/* javascript library for dSurvey
  This contains procedures used to implement the <value> and <radio> special elements.

  <Value> is used to set up an <input type="text"> box, with a number of fancy features.
  <Radio> is used to set up group of <input type="radio"> radio buttons

   These features are specified in seperate elements between <value> and </value>, or between <radio> and </radio>

   Note that <value> and <radio> can contain other attributes  (such as  "id", "name", "size", "style", "class", "accesskey", and "maxlength")
   which will be added to the <input> that is created.
      However, you should NOT specify a "value" or a "type"  attribute: they will ignored.            

   ID and NAME can be used to find the attribute. In particular, you can use ID or NAME to assign attributes in the <attributes> section of the
   spec file.  In fact, you can set all of the "special features" usings <attributes> -- use the (attribute_name) instead of the <tagName>

   Syntax:
     <value attributes="..." >
        <tagname> ... </tagname>                        // specify fancy features using special tagnames
     </value>

     <radio attributes="..." >
        <tagname> ... </tagname>                        // specify fancy features using special tagnames
     </radio>

   There are several general features, and several "fancy numeric entry" features
            
 VALUE notes:
  
   The general features:
           <isNumber show="1"> flag </isNumber> (isNumber and isNumber_show )
                       Accept non-numeric entry? In all cases,  if a number is enter, then "min/max/confirm_min/confirm_max" may be checked
                       The value of flag can be:
                             "0" or "N" : anything can be entered.
                             "1" or "Y" : the default. MUST be a numeric entry, or a ''. If a non-number is entered, it is converted to prior value
                             "2" or "R" : number is required. Non-numeric entries (including '') are converted to the prior value value. 
               show="1" means show an error message if a non-number is entered (ignored if "0" or "N" is used)

            <submitName>varname </submitName>  (submitName)          // submit this value to server (when submit happens) using this name
            <submitVar>varname</submitVar>     (submitVar)        //   save this value to this dSurvey variable (when submit happens)
            <changeVar>varname</changeVar>     (changeVar)        //   change  value to this dSurvey variable (whenever value is changed)
            <title>a title </title>            (title)        // mouseover title 
            <start varname="avar">value </start>  (start)    // the value first displayed (this is the default value). 
                                                               If not specified, '' is used
                                                               If type="2": if not specified, "0" is used.
                                                                            if non-numeric specified, an error occurs
                                                               If varname="avar" specified, avalue is ignored. Instead, the value of the
                                                               avar dSurvey variable is used (or a '' if no such variable exists)

            <allowed> is used to specify permitted 1 word entries. It also overrids isNumber.
                 <allowed show="1"> word list </allowed>    (allowed)       // a space delimited list of permitted values.  If the stripped entry does not
                                                             match a word in this list, the value is not saved; the prior value is used.
                                                             Note that case insensitive comparision is used
                                                             Note that the comparison occurs onChange (NOT while keyboard entry is occurring)
                                                           (allowed_show)  if show="1", then display allowed values if not a match
         These next 4 are ignored if <allowed> is specified. They are used only if the value entered is a number
                  <min show="1" >avalue </min>            (min and min_show)         // minimum value  (default is no min)
                  <max show="1" >avalue </max>            (max and max_show )         // maximum value (default is no max)
                     If show="1", then if below min (or above max), display an error message
                  <confirm_min value="avalue" > a message </confirm_min>  (confirm_min_value and confirm_min_message)
                                                             // ask if value below avalue, using a message.
                                                               If a message not specified, then use a default message
                  <confirm_max value="avalue" > a message </confirm_max>     (confirm_max_value and confirm_max_message) 
                                                            // ask if value above avalue, using a message.
                                                            If a message not specified, then use a default message
             
       The 3 "fancy numeric entry" elements, which can have "sub-specs" specified (as nested elements)
            <key>   : specify if cursor keys can be used to increase numeric values
            <arrow>  : specify if graphic arrows (displayed next to the input box) can be used to change numeric values
            <scroll>  : specify if a scroll bar (displayed next to the input box) can be used to change numeric values
         
            <key>   (key="1")
                  <increment> value </increment>  (key_inc)                   // increment/decrement when arrow hit (up/right increase, down/left decrease). default is 1
                  <increment_page> value </increment_page> (key_inc_page)        // increment/decrment when pgup/pgdn is used. Default is 10
                  <esc> value </esc>    (key_esc)                 // value filled in when esc hit. If not specified, <start> value is used.  
                                                            If esc hit with and this is the value, change value to ''.
                                                            Exception: if type="2", on this "2nd esc" value is changed to <start> value
                                                            <esc> augments <start> -- for example:
                                                                         <start></start>
                                                                         <key><esc>10</esc></key>
                                                               Then '' is displayed at first, hitting ESC yields a 10, hitting ESC again goes back to ''.
            <arrow size="nn">    (arrow="1")   (arrows_size)    
               <name>arrowName</name>   (arrow_name)  // If specified, the "base name" of the arrow-gif files to use
                                           The currently supported names are: : "Arrow", "ArrowGreen", "Chevron", "ChevronGreen", and "FairytaleBlue"
                                            The default value is Arrow. 

                <where>idName</where>  (arrow_where)   // The location to put the arrows (say, the ID of a <DIV>). 
                                            If not specified, a table is created with the box on the left, and arrows on the right

                 size="nn"  : optional. Size of the arrow image. If not specified, 20 is used
               Note:
                        <arrow /> or <arrow> </arrow> mean "use the default arrow, in the default location

            <scroll show="1" titleOnly="1">       (scroll="1")
                show="1"              (scroll_show)  Show value while scrolling (in a box next to scroll bar)
                titleOnly="1"         (scroll_titleOnly)  Show value as a floating title. Do NOT update colors.
                                      This might be quicker on cpu constrained machines (hence might support more divisions)
                                      If show is NOT specified, do not show values while scrolling.
                                      Note that titleOnly="2"' suppresses show="1"
                <where>idName</where>  (scroll_where)  // The location to put the scrollbar (say, the ID of a <DIV>). 
                                            If not specified, a table is created with the box on the left, and arrows on the right (if specified)
                                            and the arrows in 2nd row (underneath both box and arrows)
                <min>     (scroll_min)               Minimum (left) value of bar. Can be greater than min, but not less. Default is  <min>
                <max>     (scroll_max)                Maximum (left) value of bar. Can be less than max, but not less. Default is  <max>
                <width>npx</width>    (scroll_width)    The width of the scroll bar, in pixels
                <cells>ncells</cells>   (scroll_cells) The resolution of the scroll bar.  Ncells large means higher resolution, but takes more CPU resources.
                                        The default value is 33.  
                                         Example: If width is 300, and ncells is 50, and min and max value are 1 and 20
                                             then 
                                                each "cell" is 6 pixels wide, where a "cell" is matched to a value.  
                                                the resolution is 4 (left most is 1,5,..., right most is 200)
                <leftColor>rgb</leftColor> (scroll_leftcolor) The leftmost (small) color. The scroll bar color will be a linear trend between
                                            the leftColor and rightColor. rgb should be in  rrggbb "hex" format (you do not need the leading #).
                                            Default color is #839db8
                <rightColor>rgb</rightColor> (scroll_rightcolor)  The rightmost (large) color. 
                                            Default color is #abcdf0
                <fmt>ndec</fmt>       (scroll_fmt)   Number of decimal points to use when displaying number. Default is 2.
                                         Thus, ndec of 2 means display 10.152 as 10.15

               Note:
                        <scroll /> or <scroll> </scroll> mean "use the default scrollBar, in the default location"


======== */


// =---------------------- Useful functions
// multiple value version of tagSpecsFind: elemname an attname can be space delimited list
// (each word yields seperate call to tagSpecsFind0
// eg: (tagSpecsFind(anode,'default#var default#varname start#var start#varname','start_var start default_var start_varname default_varname','');

function tagSpecsFind(anode,elemname,attname,defval,idebug) {

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

var enames,attnames,i,j,aval;

elemname=strip(elemname).toUpperCase() ;
if (elemname!=='') {
  enames=getWord(elemname);
  for (var i=0;i<enames.length;i++) {
    aval=tagSpecsFind0(anode,enames[i],'',defval);
    if (aval!==defval) return aval;
  }
}

attname=strip(attname).toUpperCase() ;
if (attname!=='') {
  enames=getWord(attname);
  for (var i=0;i<enames.length;i++) {
     aval= getAttributes(anode,enames[i],defval) ;
     if (aval!=='') return aval;
  }
}
return defval ;

}

// ==========
function tagSpecsFind0(anode,elemname,attname,defval) {

// return spec for a <value> node. Its either in a <elemname> udner anode, or in an attname=".." attribute of anode.
// special case: if elemname is elemname.elemname2, then find elemname2 under elemname.
// special case: if elemname is elemname#anAtt, instead of returning node value, return the "anAtt" attribute value 
// (of the node with elemname). This can also be used with elemname.elemname2#anAtt
// return defval if no match

if (arguments.length<4) defval='';
var elemname0=elemname;
var elematt,vv,vval,code,cnodeval,elematt='',elemname2='' ;  

if (elemname.indexOf('#')>0) {
   vv=parseAt(elemname,'#'); 
   elemname=vv[0];
   elematt=vv[1];
}

if (elemname.indexOf('.')>0) {
   vv=parseAt(elemname,'.');
   elemname=vv[0];
   elemname2=vv[1];
}
cnode=E2_getNodes(anode,elemname);                      // check for first level node
if (cnode.length==0) {                          // no match. Check attribute
   if (attname=='') return defval ;
   vval= getAttributes(anode,attname,defval) ;
   return vval;
}

// got element. But need to get element under this?
if (elemname2!=='') {
   cnode=E2_getNodes(cnode[0],elemname2);
   if (cnode.length==0) {                               // no 2nd element match
       if (attname=='') return defval ;
       vval= getAttributes(anode,attname,defval) ;
       return vval;
   }
}

// got element (possibly a 2nd level element). Is an attribute of this element wanted?
if (elematt!=='') {
   vval= getAttributes(cnode[0],elematt,'.-.-a') ;                 // get attribute of element
   if (vval==='.-.-a') vval=getAttributes(anode,attname,defval) ;  // if no such attribute, look for alternative attribute in <value>
   return vval;
}


// else, use element's contents
if (cnode.length==0) return defval ;
vval= E2_getNodeText(cnode[0],0,'') ;
return vval;
}

//======================
// take a string of the time foo[ivar] and return foo[1] (if ivar=1)
function resolveArrayVar(vv,amess) {
var vv,vindx,goo;

if (arguments.length<2) amess='';
vv=strip(vv);
if (vv=='') return vv;
if (vv.indexOf('[')<0) return vv ;

goo=parseUsing(vv,'[',']',1);
vindx=strip(svy_getVal(goo[1],''));
if (vindx==='') {
      alert('Error: '+amess+' : in '+vv+': an array index is not specified ');
      return -1 ;
 }
 vv=strip(goo[0])+'['+vindx+']';
 return vv;
}


//======================================= BEGIN <RADIO> functions  --------------------------

// ----------  Parse a <radio .. > special tagname, save to radioSpecs array object
// set ith row of radioSpecs. Uses <elements> inside of the <radio>...</radio>
// to find specifications, or attributes inside of the <radio>.
// <elements> takes precedence over attributes
function setRadioSpecs(anode) {
var vv,ith,foo,vv2,goo,vindx,agroup,ifoo,aword,rval,newvv,vvlist,ifoo;


var ith=radioSpecs.length ;

radioSpecs[ith]={};

vv=tagSpecsFind(anode,' group name group#name group#group group#groupname','name group groupName ',''); vv=strip(vv).toUpperCase();  

if (vv==='') {
  alert(ith+' Error in setRadioSpecs: no group (or name) specified ');
  return -1; 
}
vv2=tagSpecsFind(anode,'group#append','group_append','');               // append a number to the groupname ?
if (strip(vv2)!=='') {   
  vv2=svy_getVal(vv2,'');
  vv=vv+strip(vv2);
}
agroup=strip(vv).toUpperCase() ;
radioSpecs[ith]['group']=agroup ;
radioSpecs[ith]['chosen']=0 ;


// look for a submit class. If found, error
goo=getAttributes(anode,'class','');
if (goo!=='') {
      goo=' '+goo.toUpperCase()+' ';
      if (goo.indexOf(' CLASS ')>-1) {
              alert('Error: RADIO must not have a SUBMIT class: '+ agroup);
              return 1;
       }
}

// note: radioSpecs[ith]['useValue'] is created on first button push, or if an IF is satisfied (below) ;

if (typeof(radioSpecs[0]['grouplist'])=='undefined') radioSpecs[0]['grouplist']='';
if (radioSpecs[0]['grouplist'].indexOf(' '+agroup+' ')<0) {                         // add this group to grouplist
     radioSpecs[0]['grouplist']=radioSpecs[0]['grouplist']+' '+agroup+ '  '
     radioSpecs[0][agroup]={} ;
     radioSpecs[0][agroup]['chosen']='x' ;               // points to ith radio button (the selected one). If 'x', signal that nothing in this group has been chosen yet
     radioSpecs[0][agroup]['list']=[] ;
//    if (debugOn(2)) E2_writeStatus('Adding radio group: '+agroup);
};
radioSpecs[0][agroup]['list']=radioSpecs[0][agroup]['list'].concat(ith);

vv=tagSpecsFind(anode,'value value#value ','value',''); vv=strip(vv) ;
if (vv==='')  {                                                          // support <value var="xx" />
    vv=tagSpecsFind(anode,'value#var var ','var','');  
    vv=strip(vv) ; 
    if (vv!=='')   vv=svy_getVal(vv,'');
}
radioSpecs[ith]['value']=vv ;

vv=tagSpecsFind(anode,'default value#default ','default',''); vv=strip(vv) ;   // check this button by default? 
if (vv!=='') {
    vv2=E2_doMath(vv,'');  
    if (vv2==1) {
       if (radioSpecs[0][agroup]['chosen']==='x') {                      // x signals "not yet set"
           radioSpecs[ith]['chosen']=1 ;
           radioSpecs[0][agroup]['useValue']=radioSpecs[ith]['value'] ;
           radioSpecs[0][agroup]['chosen']=ith;
        } else {
           E2_writeStatus('RADIO warning: more than one default for this group ('+agroup+'): only the first one is used ');
       }
    }
}


// note: radioSpecs[0][agroup]['useValue'] and ['chosen'] are changed on button pushes in this group
vv=tagSpecsFind(anode,'submitName submitName#value submitName#name submitName#var','submitName',''); vv=strip(vv.toUpperCase());
vv=resolveArrayVar(vv); 
radioSpecs[ith]['submitname']=vv ;


vv=tagSpecsFind(anode,'submitVar submitVar#name submitVar#value ','submitVar',''); vv=strip(vv.toUpperCase());
vv=resolveArrayVar(vv);
radioSpecs[ith]['submitvar']=vv ;

vv=tagSpecsFind(anode,'confirm','confirm',null); vv=strip(vv) ;
if (vv!==null) {     // subsitute ' %xx% ' with the value of the xx variable (must be space % varname % space)
                     // could use regex, as in a="this is %real %silly% too" ; b=a.search(/\%\S+\%/,'arf'). but naah
   vvlist=getWord(vv);
   newvv='';
   vvlist=getWord(vv);
   for (var ifoo=0;ifoo<vvlist.length;ifoo++) {
     aword=strip(vvlist[ifoo]) ;
     if (aword.substr(0,1)=='%' && aword.substr(aword.length-1,1)=='%') {  
         aword=aword.substr(1,aword.length-2);
         newvv=newvv+' '+svy_getVal(aword,'')+' ';
     } else {
         newvv=newvv+' '+aword+' ';
     }
  }
  vv=newvv;
  radioSpecs[0][agroup]['confirm']=vv ;            // later confirm message overwrite earlier 
}

vv=tagSpecsFind(anode,'box box.styleChosen box#styleChosen','box box_styleChosen',null);

if (vv==null) {                                // no <box>, so don't make box
  radioSpecs[ith]['box']='' ;
} else {
  vv=strip(vv);
  if (vv==='') vv='border:1px #adacab solid;background-color:#efefef';
   radioSpecs[ith]['box']=vv ;
   vv=tagSpecsFind(anode,'box#class','box_class',''); vv=strip(vv) ;
   radioSpecs[ith]['box_class']=vv ;
   vv=tagSpecsFind(anode,'box#style','box_style',''); vv=strip(vv) ;
   radioSpecs[ith]['box_style']=vv ;
}

vv=E2_getNodes(anode,'label');
radioSpecs[ith]['label_node']='' ;
if (vv.length==0) {                             // no <label>, check for attribute
   vv=getAttributes(anode,'label','');
   radioSpecs[ith]['label_text']=vv ;
   if (vv!=='') {
      vv=getAttributes(anode,'label_after','');
      radioSpecs[ith]['label_after']=vv ;
   }
} else {                                // got a label element
   radioSpecs[ith]['label_node']=vv[0] ;
   vv=tagSpecsFind(anode,'label#after','label_after',''); vv=strip(vv) ;
   radioSpecs[ith]['label_after']=vv ;
}

radioSpecs[ith]['click']='' ;
vv=E2_getNodes(anode,'click');
if (vv.length>0) {
   radioSpecs[ith]['click']=vv[0] ;
} else {                                // look for attribute
  vv=getAttributes(anode,'click','');
  if (vv!='') {
     var foo=document.createElement('clickStuff') ;
     foo.innerHTML=vv ;
     radioSpecs[ith]['click']=foo ;
  }
}   


return ith ;
}



//  ------------- create an <input type="radiOo" ...

// create an input type="radio" node using radioSpecs[ith], replace anode with this input node

function setRadioSpecsInsert(ith,anode,loopvs,anode1) {

var ainput,atable,atbody,atext,atr,atd,aspan,aspan2;
var tmp,tmpid,agroup,alabel,ainputID,lnode,lnodeT ;
agroup=radioSpecs[ith]['group'] ;

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

ainput=document.createElement('input');

E2_copyAttributes(anode,ainput,'type value submit use submitName submitVar  ');

ainput.setAttribute('type','radio');
if (radioSpecs[ith]['chosen']==1) {
        ainput.setAttribute('checked',1);                           // this is the default?
}
ainput.setAttribute('onClick','var vv=setRadioClick('+ith+'); ');

ainput.setAttribute('loopVarsAll',loopvs);              // used by event handlers (current value of  all loopvariables 
radioSpecs[ith]['loopVarsAll']=loopvs ;  


ainputID=getAttributes(anode,'ID','');
if (ainputID==='') {
   ainputID='ID_'+Math.random(); ainputID=ainputID.replace('.','_');
   ainput.setAttribute('ID',ainputID);
}

radioSpecs[ith]['ID']=ainputID ;

ainput.setAttribute('isRadio','1');             // used to suppress submitNAME matching (in do_submit)

ainput.value=radioSpecs[ith]['value'];  
ainput.setAttribute('value',radioSpecs[ith]['value']);

// create a box to hold <input>. and the span-with-label-stuff
boxspan=document.createElement('span');         // always put in a span, possibly make this span a "box"  

// is there a "box"
if (radioSpecs[ith]['box']!=='') {
 if (radioSpecs[ith]['box_class']!=='') boxspan.className=radioSpecs[ith]['box_class'];
  if (radioSpecs[ith]['chosen']==1) {                           // this is the default?
      boxspan.style.cssText=radioSpecs[ith]['box'];                  // the "checked" style
   } else {
      boxspan.style.cssText=radioSpecs[ith]['box_style'];                 // the derault (non-checked) style
   }
   boxspan.setAttribute('ID','BOX_'+ainputID);          // used to change styles 
}

if (radioSpecs[ith]['label']!=='') {
  labelNode=document.createElement('label');
  labelNode.setAttribute('for',ainputID);
  
 if (radioSpecs[ith]['label_node']!=='') {
     lnodeT=E2_xmlToDom(radioSpecs[ith]['label_node'],'span','label') ;                       //  dom nodes with content 
  } else {
       lnodeT=document.createElement('span');
       vv=document.createTextNode(radioSpecs[ith]['label_text']);
       lnodeT.appendChild(vv);
  }
}     
 // order is <label><span>pretext<input/>postText</span></label>
// pretext and posttext are in lnode; only one is used (depending o value of label_after
// or, if no label, pretext and posttext not added

if (radioSpecs[ith]['label']==='')  {             // no label, no text
     boxspan.appendChild(ainput);
     anode1.parentNode.insertBefore(boxspan,anode1);
     anode1.parentNode.removeChild(anode1);    
} else {                                                // use a <label>
  if (radioSpecs[ith]['label_after']==1) {                // label after radio
     boxspan.appendChild(ainput);
     boxspan.appendChild(lnodeT);
   } else {
     boxspan.appendChild(lnodeT);
     boxspan.appendChild(ainput);
   }
   labelNode.appendChild(boxspan);    


   anode1.parentNode.insertBefore(labelNode,anode1);
   anode1.parentNode.removeChild(anode1);    
}        

radioSpecs[ith]['input']=ainput ;

return 1;

}

//==========
// This is called when a radio button is hit. Iat is a pointer into global arrays that store stuff for this radio button
function setRadioClick(iat) {  
 var agroup,aval,oldiat,aid,ares;

 agroup=radioSpecs[iat]['group'] ;
 oldiat=radioSpecs[0][agroup]['chosen'];

// do a click event?
aclick=radioSpecs[iat]['click'];
if (aclick!=='') {                      // do a click event. Substitute this.value with this button's value
  ares=setRadioOnClick(iat);
  if (strip(ares)==='0') {
       aid=document.getElementById(radioSpecs[iat]['ID']);      // forcibly uncheck this button
       aid.checked=0 ;
       aid.setAttribute("checked",0);
       return 0;
  }
}

// set values for this group
 radioSpecs[0][agroup]['chosen']=iat ;
 radioSpecs[0][agroup]['useValue']= agroup=radioSpecs[iat]['value'] ;

// reset prior checked button, in this group, to non checked (if there was prior chosen)
 if (oldiat!=='x') {
   radioSpecs[oldiat]['chosen']='' ;
   aid=document.getElementById(radioSpecs[oldiat]['ID']);
   aid.setAttribute("checked",0);
   aid.checked=0 ;
   aid=document.getElementById('BOX_'+radioSpecs[oldiat]['ID']);
   if (aid) aid.style.cssText=radioSpecs[oldiat]['box_style'];                 // the derault (non-checked) style
 }


// change stuff for this radio button
 radioSpecs[iat]['chosen']=1 ;
 aid=document.getElementById(radioSpecs[iat]['ID']);
 aid.setAttribute("checked",1);
   aid.checked=1 ;
   aid=document.getElementById('BOX_'+radioSpecs[iat]['ID']);
   if (aid) aid.style.cssText=radioSpecs[iat]['box'];                 // the derault (non-checked) style

 

return 1;
}

//=======================
// ==== click hanlder for <RADIO>
// when doing click, temporarily set variables in tthe loopvarsall attribute 

function setRadioOnClick(ith) {

var notNum,amess,zz,callow=0;
var loopvs,ires;
var lnames=[],lvals,jj,tt,ii ;
// temporary save of vars listed in loopvars
   loopvs=radioSpecs[ith]['loopVarsAll'];
   if (loopvs!=='') {
     lnames=[];
     lvals=[];
     loopvs=getWord(loopvs);
     for (var jj=0;jj<loopvs.length;jj++) {
         tt=parseAt(loopvs[jj],'=');
         ii=lnames.length;
         lnames[ii]=strip(tt[0]).toUpperCase() ;
         lvals[ii]=svy_getVal(lnames[ii]) ;                     // prior values (restore when change is done
         svy_setVal(lnames[ii],tt[1]); 
      }
    }

// if here, do the <change> stuff
radioSpecs[ith]['input'].setAttribute('chosen',1);                      // radio buttons can NOT be unclicked
ires= E2_doEquations(radioSpecs[ith]['input'],radioSpecs[ith]['click'],0,1)      ;  

// reset loopvars to prior values
  for (var jj=0;jj<lnames.length;jj++) {
         svy_setVal(lnames[jj],lvals[jj]); 
  }
 return ires ;
 
}


//======================================= BEGIN <DOIT> functions  --------------------------
// ----------  Parse a <doit.. > special tagname, save to doitSpecs array object
// set ith row of doitSpecs. Uses <element> to find specifications, or attribute names. <element> takes precedence

function setDoitSpecs(anode0) {
var goo,vv,anode,mm,bnode;
var ahow,anid;
var alink='',ahide='',atext='' ;
var ith=doitSpecs.length ;                   
doitSpecs[ith]={};

anode=E2_xmlToDom(anode0);

// look for a submit class. If found, error
goo=getAttributes(anode,'class','');
if (goo!=='') {
      goo=' '+goo.toUpperCase()+' ';
      if (goo.indexOf(' SUBMIT ')>-1) {
              alert('Error: doit must not have a SUBMIT class: '+ agroup);
              return 1;
       }
}

alink=getAttributes(anode,'type','');
if (alink=='') {
  vv=E2_getNodes(anode,'link');
  if (vv.length>0) {
     alink='link';         // no arguments needed
     removeNodes(vv);
  }
}

ahide=getAttributes(anode,'hide','');
if (ahide=='') {
  vv=E2_getNodes(anode,'hide');
  if (vv.length>0) {
        ahide='1';         // no arguments needed
        removeNodes(vv);
  }       
}

atext=getAttributes(anode,'text','');
if (atext=='') {
  vv=E2_getNodes(anode,'text');
  if (vv.length>0) {
      iok=E2_procSection_actionTags(vv[0],'Processing a <text>: '+ith,'SHOW') ;
      atext=E2_xmlToString(vv[0]);
      removeNodes(vv);
  }
}
doitSpecs[ith]['link']=alink;
doitSpecs[ith]['text']=atext;
doitSpecs[ith]['hide']=ahide;

// replace content in anode
vv=E2_getNodes(anode,'content') ;
for (var mm=0;mm<vv.length;mm++) {
  inn=doitSpecsContent.length;
  doitSpecsContent[inn]=vv[mm];
  afunc='svy_getDoitContents('+inn+','+ith+')';
  atext=document.createTextNode(afunc);
  vv[mm].parentNode.insertBefore(atext,vv[mm]);
}
removeNodes(vv);


// transform <display> to displayDiv(anid,how)
vv=E2_getNodes(anode,'display') ;
for (var mm=0;mm<vv.length;mm++) {
  anid=getAttributes(vv[mm],'where target','');
  if (anid=='') {
        alert('Error: no TARGET in a <DOIT><DISPLAY> ');
        return 0;
  }
  ahow=getAttributes(vv[mm],'how','toggle');
  afunc='displayDiv("'+anid+'","'+ahow+'");' ;
  atext=document.createTextNode(afunc);
  vv[mm].parentNode.insertBefore(atext,vv[mm]);
}
removeNodes(vv);


doitSpecs[ith]['anode']=anode;

return ith ;
}



//  ------------- create an button, or link, for DOIT

// create an input type="button" node using doitSpecs[ith], replace anode with this input node

function setDoitSpecsInsert(ith,anode,loopvs,anode1) {

var ainput,atable,atbody,atext,atr,atd,aspan,aspan2;
var tmp,tmpid,agroup,alabel,ainputID,lnode,lnodeT ;

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

if (doitSpecs[ith]['link']=='link') {
  ainput=document.createElement('span');
   E2_copyAttributes(anode,ainput,'type onClick hide link text value submitName submitVar submit ');
  ainput.style.padding='1px'
  ainput.style.color='blue';
  ainput.style.textDecoration='underline';
} else {
  ainput=document.createElement('input');
  ainput.setAttribute('type','button');
  E2_copyAttributes(anode,ainput,'type onClick hide link text value submitName submitVar submit ');
}

ainput.setAttribute('onClick','var vv=setDoitClick('+ith+');  ');

ainput.setAttribute('loopVarsAll',loopvs);              // used by event handlers (current value of  all loopvariables 
doitSpecs[ith]['loopVarsAll']=loopvs ;  


ainputID=getAttributes(anode,'ID','');
if (ainputID==='') {
   ainputID='ID_'+Math.random(); ainputID=ainputID.replace('.','_');
   ainput.setAttribute('ID',ainputID);
}

doitSpecs[ith]['ID']=ainputID ;

if (doitSpecs[ith]['link']=='link') {
   ainput.innerHTML=doitSpecs[ith]['text'];
} else {
  ainput.value=doitSpecs[ith]['text'];
  ainput.setAttribute('value',doitSpecs[ith]['text']);
}

ainput.setAttribute('hide',doitSpecs[ith]['hide']);

doitSpecs[ith]['input']=ainput ;

anode1.parentNode.insertBefore(ainput,anode1);
anode1.parentNode.removeChild(anode1);     


return 0;
}

//=================
// a doit is clicked
function setDoitClick(ith) {

var loopvs,ires,bnode,ok;
var lnames=[],lvals,jj,tt,ii ;

// temporary save of vars listed in loopvars
   loopvs=doitSpecs[ith]['loopVarsAll'];
   if (loopvs!=='') {
     lnames=[];
     lvals=[];
     loopvs=getWord(loopvs);
     for (var jj=0;jj<loopvs.length;jj++) {
         tt=parseAt(loopvs[jj],'=');
         ii=lnames.length;
         lnames[ii]=strip(tt[0]).toUpperCase() ;
         lvals[ii]=svy_getVal(lnames[ii]) ;                     // prior values (restore when change is done
         svy_setVal(lnames[ii],tt[1]); 
      }
    }

bnode=E2_copyNode(doitSpecs[ith]['anode']);
//alert('clicked '+E2_xmlToString(bnode));
//ok=E2_procSection_actionTags(bnode,'Processing a doit (for IF): '+ith,'IF') ;
//alert('clicked2 '+E2_xmlToString(bnode));
ires= E2_doEquations(doitSpecs[ith]['input'],bnode,0,1)      ;  
if (doitSpecs[ith]['hide']=='1')  displayDiv(doitSpecs[ith]['ID'],'none');

// reset loopvars to prior values
for (var jj=0;jj<lnames.length;jj++) {
     svy_setVal(lnames[jj],lvals[jj]); 
}


return ires ;
}



//==========================
// display contents of a <content>
function svy_getDoitContents(inn,ith) {
var idlist,m,idd,iok,tmp1,tmp2,vif,anode,astyle;
var isinput=0;
var anew,aid,isAppend ;

var dnode=doitSpecs[ith];

// look for an IF. If found and false, skip this

vif=E2_node_doIf(doitSpecsContent[inn],3) ;
if (!vif) return 0;

anode=E2_copyNode(doitSpecsContent[inn]);
astyle=getAttributes(doitSpecsContent[inn],'style','');'';

isAppend=getAttributes(doitSpecsContent[inn],'append',0);

iok=E2_procSection_actionTags(anode,'Processing a <content>: '+inn) ;

if (iok==0) return 0;

idlist=getAttributes(anode,'for to','');
if (idlist=='' ) idlist=doitSpecs[ith]['ID'];

if (idlist!=='') {
  idlist=getWord(idlist);
  for (var m=0;m<idlist.length;m++) {
     aid=idlist[m];
     taid=strip(aid).toUpperCase();
     idd=document.getElementById(aid);
     if (aid=='#') {
         aid=doitSpecs[ith]['ID'];
         idd=document.getElementById(aid);
     }
     if (taid=='#BEFORE') {                      // insert in sibling node before CONTENT node
        tmp1=whichSibling(doitSpecs[ith]['ID'],1) ;  // is this the first (element node)? 
        if (tmp1==1) {
           alert('Error: #BEFORE, but no earlier siblings ('+doitSpecs[ith]['ID']);
           return 0;
        }
        idd=getSibling(doitSpecs[ith]['ID'],tmp1-1,1);
     }       
     if (taid=='#AFTER') {                      // insert before CONTENT node
        tmp2=numSibling(doitSpecs[ith]['ID'],1) ;    // how many (element node)
        tmp1=whichSibling(doitSpecs[ith]['ID'],1) ;  // is this the last (element node) ?  
        if (tmp1>=tmp2) {
           alert('Error: #AFTERE, but no later siblings ('+doitSpecs[ith]['ID']);
           return 0;
        }
        idd=getSibling(doitSpecs[ith]['ID'],tmp1+1,1);   
     }       


     if (!idd) {
        alert('Error in processing <CONTENTS>: no such ID in the FOR: '+idlist[m]);
        return 0;
     }
     isinput=0;
     if (strip(idd.tagName).toUpperCase()=='INPUT') isinput=1;

     if (isinput==1) {
        if (isAppend==1) {
           idd.value=idd.value+' '+strip(E2_xmlToString(anode,1));
        } else {
           idd.value=strip(E2_xmlToString(anode,1));
        }
        if (astyle!=='') {
          if (isAppend==1) {
            idd.style.cssText=idd.style.cssText+';'+astyle;
          } else {
            idd.style.cssText=astyle;
          }
        }

     } else {

        if (isAppend==1) {
           idd.innerHTML=idd.innerHTML+' '+E2_xmlToString(anode,1);
        } else {
           idd.innerHTML=E2_xmlToString(anode,1);
        }
        if (astyle!=='') {
          if (isAppend==1) {
            idd.style.cssText=idd.style.cssText+';'+astyle;
          } else {
            idd.style.cssText=astyle;
          }
        }
     }
  }
}
return 0;
} //aid

//==================================
/* 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

 NOW IN SVYINPUTS2.JS

function removeHTMLTags(strinputCode){

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

*/


//======================================= BEGIN <CHECKBOX> functions  --------------------------

// ----------  Parse a <checkbox.. > special tagname, save to checkBoxSpecs array object
// set ith row of checkboxSpecs. Uses <element> to find specifications, or attribute names. <element> takes precedence
function setCheckboxSpecs(anode) {
var vv,ith,foo,vv2,goo,vindx,agroup,ifoo,aword,rval,newvv,vvlist,ifoo,vv2;

var ith=checkboxSpecs.length ;

checkboxSpecs[ith]={};

checkboxSpecs[ith]['chosen']=0 ;

// look for a submit class. If found, error
goo=getAttributes(anode,'class','');
if (goo!=='') {
      goo=' '+goo.toUpperCase()+' ';
      if (goo.indexOf(' SUBMIT ')>-1) {
              alert('Error: checkbox must not have a SUBMIT class: '+ agroup);
              return 1;
       }
}

// note: checkboxSpecs[ith]['useValue'] is created on first button push, or if an IF is satisfied (below) ;

vv=tagSpecsFind(anode,'value value#value ','value',''); vv=strip(vv) ;
if (vv==='')  {                                                          // support <value var="xx" />
    vv=tagSpecsFind(anode,'value#var var ','var','');  
    vv=strip(vv) ; 
    if (vv!=='')   vv=svy_getVal(vv,'');
}
checkboxSpecs[ith]['value']=vv ;
checkboxSpecs[ith]['yesValue']=vv ;

checkboxSpecs[ith]['gotNoValue']=0 ;      // default is noValue (if noValue is specified) (0 means not chosen, and noValue not specified

vv=tagSpecsFind(anode,'novalue#value ','novalue',null); 
if (vv===null)  {                                                          // support <novalue var="xx" />
    vv=tagSpecsFind(anode,'novalue#var ','novar',null);  
    if (vv!==null)  {                                        
       vv2=strip(vv) ; 
       if (vv2!=='')   vv=svy_getVal(vv2,'');
   }
}
if (vv===null) vv=tagSpecsFind(anode,'novalue ','novalue',null); 
checkboxSpecs[ith]['novalue']=vv ;                      // if vv=null, there is not a novalue spec
if (vv!==null)   checkboxSpecs[ith]['gotNoValue']=1 ;      // 1 to signal that a noValue is specified

vv=tagSpecsFind(anode,'default value#default ','default',''); vv=strip(vv) ;   // check this button by default? 
if (vv!=='') {
    vv2=E2_doMath(vv,'');  
    if (vv2==1)   checkboxSpecs[ith]['chosen']=1 ;
}


// note: checkboxSpecs[ith]['chosen'] is changed on button pushes
vv=tagSpecsFind(anode,'submitName submitName#value submitName#name submitName#var','submitName',''); vv=strip(vv.toUpperCase());
vv=resolveArrayVar(vv);
checkboxSpecs[ith]['submitname']=vv ;

vv=tagSpecsFind(anode,'title','title',''); 
checkboxSpecs[ith]['title']=vv;

vv=tagSpecsFind(anode,'submitVar submitVar#name submitVar#value ','submitVar',''); vv=strip(vv.toUpperCase());
vv=resolveArrayVar(vv);
checkboxSpecs[ith]['submitvar']=vv ;

vv=tagSpecsFind(anode,'box box.styleChosen box#styleChosen','box box_styleChosen',null);
if (vv==null) {                                // no <box>, so don't make box
  checkboxSpecs[ith]['box']='' ;
} else {
  vv=strip(vv);
  if (vv==='') vv='border:1px #adacab solid;background-color:#efefef';
   checkboxSpecs[ith]['box']=vv ;
   vv=tagSpecsFind(anode,'box#class','box_class',''); vv=strip(vv) ;
   checkboxSpecs[ith]['box_class']=vv ;
   vv=tagSpecsFind(anode,'box#style','box_style',''); vv=strip(vv) ;
   checkboxSpecs[ith]['box_style']=vv ;
}


vv=E2_getNodes(anode,'label');
checkboxSpecs[ith]['label_node']='' ;
if (vv.length==0) {                             // no <label>, check for attribute
   vv=getAttributes(anode,'label','');
   checkboxSpecs[ith]['label_text']=vv ;
   if (vv!=='') {
      vv=getAttributes(anode,'label_after','');
      checkboxSpecs[ith]['label_after']=vv ;
   }
} else {                                // got a label element
   checkboxSpecs[ith]['label_node']=vv[0] ;
   vv=tagSpecsFind(anode,'label#after','label_after',''); vv=strip(vv) ;
   checkboxSpecs[ith]['label_after']=vv ;
}

checkboxSpecs[ith]['click']='' ;
vv=E2_getNodes(anode,'click');
if (vv.length>0) {
   checkboxSpecs[ith]['click']=vv[0] ;
} else {                                // look for attribute
  vv=getAttributes(anode,'click','');
  if (vv!='') {
     var foo=document.createElement('clickStuff') ;
     foo.innerHTML=vv ;
     checkboxSpecs[ith]['click']=foo ;
  }
}   


return ith ;
}



//  ------------- create an <input type="checkboxo" ...

// create an input type="checkbox" node using checkboxSpecs[ith], replace anode with this input node

function setCheckboxSpecsInsert(ith,anode,loopvs,anode1) {

var ainput,atable,atbody,atext,atr,atd,aspan,aspan2;
var tmp,tmpid,agroup,alabel,ainputID,lnode,lnodeT ;
agroup=checkboxSpecs[ith]['group'] ;

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

ainput=document.createElement('input');

E2_copyAttributes(anode,ainput,'type value  submitName submitVar submit ');

ainput.setAttribute('type','checkbox');
if (checkboxSpecs[ith]['chosen']==1) {
        ainput.setAttribute('checked',1);                           // this is the selected
}
ainput.setAttribute('onClick','var vv=setcheckboxClick('+ith+');  ');


ainput.setAttribute('title',checkboxSpecs[ith]['title']);

ainput.setAttribute('loopVarsAll',loopvs);              // used by event handlers (current value of  all loopvariables 
checkboxSpecs[ith]['loopVarsAll']=loopvs ;  


ainputID=getAttributes(anode,'ID','');
if (ainputID==='') {
   ainputID='ID_'+Math.random(); ainputID=ainputID.replace('.','_');
   ainput.setAttribute('ID',ainputID);
}

checkboxSpecs[ith]['ID']=ainputID ;

ainput.setAttribute('ischeckbox','1');             // used to suppress submitNAME matching (in do_submit)

ainput.value=checkboxSpecs[ith]['value'];  
ainput.setAttribute('value',checkboxSpecs[ith]['value']);

if (checkboxSpecs[ith]['gotNoValue']==1)   ainput.setAttribute('novalue',checkboxSpecs[ith]['novalue']);

// create a box to hold <input>. and the span-with-label-stuff
boxspan=document.createElement('span');         // always put in a span, possibly make this span a "box"  

// is there a "box"
if (checkboxSpecs[ith]['box']!=='') {
 if (checkboxSpecs[ith]['box_class']!=='') boxspan.className=checkboxSpecs[ith]['box_class'];
  if (checkboxSpecs[ith]['chosen']==1) {                           // this is the default?
      boxspan.style.cssText=checkboxSpecs[ith]['box'];                  // the "checked" style
   } else {
      boxspan.style.cssText=checkboxSpecs[ith]['box_style'];                 // the derault (non-checked) style
   }
   boxspan.setAttribute('ID','BOX_'+ainputID);          // used to change styles 
}

if (checkboxSpecs[ith]['label']!=='') {
  labelNode=document.createElement('label');
  labelNode.setAttribute('for',ainputID);
  
 if (checkboxSpecs[ith]['label_node']!=='') {
     lnodeT=E2_xmlToDom(checkboxSpecs[ith]['label_node'],'span','label') ;                       //  dom nodes with content 
  } else {
       lnodeT=document.createElement('span');
       vv=document.createTextNode(checkboxSpecs[ith]['label_text']);
       lnodeT.appendChild(vv);
  }
}     
 // order is <label><span>pretext<input/>postText</span></label>
// pretext and posttext are in lnode; only one is used (depending o value of label_after
// or, if no label, pretext and posttext not added

if (checkboxSpecs[ith]['label']==='')  {             // no label, no text
     boxspan.appendChild(ainput);
     anode.parentNode.insertBefore(boxspan,anode);
     anode1.parentNode.removeChild(anode1);    
} else {                                                // use a <label>
  if (checkboxSpecs[ith]['label_after']==1) {                // label after checkbox
     boxspan.appendChild(ainput);
     boxspan.appendChild(lnodeT);
   } else {
     boxspan.appendChild(lnodeT);
     boxspan.appendChild(ainput);
   }
   labelNode.appendChild(boxspan);    
   anode1.parentNode.insertBefore(labelNode,anode1);
   anode1.parentNode.removeChild(anode1);    
}        

checkboxSpecs[ith]['input']=ainput ;

return 1;

}

//==========
// This is called when a checkbox button is hit. Iat is a pointer into global arrays that store stuff for this checkbox button
function setcheckboxClick(iat) {  
 var agroup,aval,aid,ares;

// do a click event?
aclick=checkboxSpecs[iat]['click'];
if (aclick!=='') {                      // do a click event. Substitute this.value with this button's value
  ares=setcheckboxOnClick(iat);
  if (strip(ares)==='0') { 
       ischecked=checkboxSpecs[iat]['chosen'];
       aid=document.getElementById(checkboxSpecs[iat]['ID']);      // do not permit change of this checkbox
       aid.checked=ischecked ;
       aid.setAttribute("checked",ischecked);
       return 0;
  }
}

ischecked=checkboxSpecs[iat]['chosen'];
if (ischecked) {                               // was checked, so now not checked
   checkboxSpecs[iat]['chosen']=0 ;
   aid=document.getElementById(checkboxSpecs[iat]['ID']);
   aid=document.getElementById('BOX_'+checkboxSpecs[iat]['ID']);
   if (aid) aid.style.cssText=checkboxSpecs[iat]['box_style'];                 // the derault (non-checked) style
 } else {                                       // is checked now
     checkboxSpecs[iat]['chosen']=1 ;
     aid=document.getElementById(checkboxSpecs[iat]['ID']);
     aid=document.getElementById('BOX_'+checkboxSpecs[iat]['ID']);
     if (aid) aid.style.cssText=checkboxSpecs[iat]['box'];                 // the derault (non-checked) style
 }
 

return 1;
}               

//=======================
// ==== click hanlder for <checkbox>
// when doing click, temporarily set variables in tthe loopvarsall attribute 

function setcheckboxOnClick(ith) {

var notNum,amess,zz,callow=0;
var loopvs,ires;
var lnames=[],lvals,jj,tt,ii ;
// temporary save of vars listed in loopvars
   loopvs=checkboxSpecs[ith]['loopVarsAll'];
   if (loopvs!=='') {
     lnames=[];
     lvals=[];
     loopvs=getWord(loopvs);
     for (var jj=0;jj<loopvs.length;jj++) {
         tt=parseAt(loopvs[jj],'=');
         ii=lnames.length;
         lnames[ii]=strip(tt[0]).toUpperCase() ;
         lvals[ii]=svy_getVal(lnames[ii]) ;                     // prior values (restore when change is done
         svy_setVal(lnames[ii],tt[1]); 
      }
    }

// if here, do the <change> stuff

checkboxSpecs[ith]['input'].setAttribute('chosen',1-checkboxSpecs[ith]['chosen']);
ires= E2_doEquations(checkboxSpecs[ith]['input'],checkboxSpecs[ith]['click'],0,1)      ;  

// reset loopvars to prior values
  for (var jj=0;jj<lnames.length;jj++) {
         svy_setVal(lnames[jj],lvals[jj]); 
  }
 return ires ;
 
}



//======================================= BEGIN VALUE functions  -------------------------- 


// ---------- 
// Read a <value> node and save its options to the ith row of valueSpecs. Uses <element> to find specifications, or attribute names. <element> takes precedence
function setValueSpecs(anode0) {

var goo,vindx;
var vv,ith,foo,isnum ;
var ith=valueSpecs.length ;
var ainclude,snode;
var anode ;
anode=anode0;

valueSpecs[ith]={};

vv=tagSpecsFind(anode,'isNumber','isNumber','1'); vv=strip(vv).toUpperCase();  
if (vv.substr(0,1)=='N')  vv=0 ;
if (vv.substr(0,1)=='Y')  vv=1 ;
if (vv.substr(0,1)=='R')  vv=2 ;
isnum=vv;
valueSpecs[ith]['isNumber']=vv ;
valueSpecs[ith]['isnumber_show']=tagSpecsFind(anode,'isNumber#show','isNumber_show','');


// read specs

vv=tagSpecsFind(anode,'submit','submit',''); vv=strip(vv.toUpperCase());
valueSpecs[ith]['submit']=vv ;

vv=tagSpecsFind(anode,'name name#value ','name',''); vv=strip(vv.toUpperCase());
vv=resolveArrayVar(vv);
valueSpecs[ith]['name']=vv ;

vv=tagSpecsFind(anode,'submitName submitName#value submitName#var submitName#name','submitName',''); vv=strip(vv.toUpperCase());
vv=resolveArrayVar(vv);
valueSpecs[ith]['submitName']=vv ;

vv=tagSpecsFind(anode,'submitVar submitVar#value submitVar#var submitVar#name','submitVar',''); vv=strip(vv.toUpperCase());
vv=resolveArrayVar(vv);
valueSpecs[ith]['submitVar']=vv ;

vv=tagSpecsFind(anode,'title','title','');
valueSpecs[ith]['title']=strip(vv) ;

vv=strip(tagSpecsFind(anode,'default#var start default#varname start#var start#varname','start_var  default_var start_varname default_varname',''));
if (vv=='') {
   vv=strip(tagSpecsFind(anode,'start default start#value start#val','start default',''));
} else {
   vv=strip(svy_getVal(vv,''));
}

if (isnum==2 && isNaN(vv)) {
  alert('setValueSpecs error: isNumber=2, but START is not a number  = '+vv);
  return -1;
}

if (isnum==1 && isNaN(vv) && vv!=='') {
  alert('setValueSpecs error: isNumber=1, but START is not a number and not an empty string  = '+vv);
  return -1;
}

valueSpecs[ith]['start']=strip(vv) ;

vv=tagSpecsFind(anode,'changeVar','changeVar','');
//alert('changvevar vv = '+vv);
valueSpecs[ith]['changeVar']=strip(vv).toUpperCase();

vv=tagSpecsFind(anode,'allowed','allowed','');
if (vv!='') {
   valueSpecs[ith]['allowed']=' '+strip(vv).toUpperCase()+' ' ;
   valueSpecs[ith]['allowed_show']= strip(tagSpecsFind(anode,'allowed#show','allowed_show',''));
} else {
   valueSpecs[ith]['allowed']='';
}


var vmin=tagSpecsFind(anode,'min','min','');
vmin=svy_getVal(vmin);
valueSpecs[ith]['min']=strip(vmin) ;

var vmax=tagSpecsFind(anode,'max','max','');
vmax=svy_getVal(vmax);
valueSpecs[ith]['max']=strip(vmax) ;

valueSpecs[ith]['max_show']=strip(tagSpecsFind(anode,'max#show','max_show','')) ;
valueSpecs[ith]['min_show']=strip(tagSpecsFind(anode,'min#show','min_show','')) ;

vv=tagSpecsFind(anode,'confirm_min#value','confirm_min_value','');
valueSpecs[ith]['confirm_min_value']=strip(vv) ;

vv=tagSpecsFind(anode,'confirm_min','confirm_min_message','');
valueSpecs[ith]['confirm_min_message']=strip(vv) ;

vv=tagSpecsFind(anode,'confirm_max#value','confirm_max_value','');
valueSpecs[ith]['confirm_max_value']=strip(vv) ;

vv=tagSpecsFind(anode,'confirm_max','confirm_max_message','');
valueSpecs[ith]['confirm_max_message']=strip(vv) ;

vv=tagSpecsFind(anode,'change','change','');
valueSpecs[ith]['change']=vv ;


valueSpecs[ith]['change']='' ;
vv=E2_getNodes(anode,'change');
if (vv.length>0) {
   valueSpecs[ith]['change']=vv[0] ;
} else {                                // look for attribute
  vv=getAttributes(anode,'change','');
  if (vv!='') {
     var foo=document.createElement('changeStuff') ;
     foo.innerHTML=vv ;
     valueSpecs[ith]['change']=foo ;
  }
}   

valueSpecs[ith]['click']='' ;
vv=E2_getNodes(anode,'click');
if (vv.length>0) {
   valueSpecs[ith]['click']=vv[0] ;
} else {                                // look for attribute
  vv=getAttributes(anode,'click','');
  if (vv!='') {
     var foo=document.createElement('clickStuff') ;
     foo.innerHTML=vv ;
     valueSpecs[ith]['click']=foo ;
  }
}   

// ===== KEY 
vv=tagSpecsFind(anode,'key','key',null);
valueSpecs[ith]['key']=-1;
if (vv!==null) {
   valueSpecs[ith]['key']=1;
   vv=tagSpecsFind(anode,'key.increment key.inc ','key_inc','1');
   valueSpecs[ith]['key_inc']=vv ;

   vv=tagSpecsFind(anode,'key.increment_page key.inc_page','key_inc_page','10');
   valueSpecs[ith]['key_inc_page']=vv ;

   vv=tagSpecsFind(anode,'key.esc','key_esc',valueSpecs[ith]['start']);
   vv=svy_getVal(vv);
   valueSpecs[ith]['key_esc']=vv ;
}


// ===== ARROW
vv=tagSpecsFind(anode,'arrow','arrow',null);
valueSpecs[ith]['arrow']=-1 ;
if (vv!==null) {
    valueSpecs[ith]['arrow']=1 ;
   valueSpecs[ith]['arrow_name']=tagSpecsFind(anode,'arrow.name','arrow_name','arrow'); ;

   vv=strip(tagSpecsFind(anode,'arrow.where','arrow_where','')) ;   
   valueSpecs[ith]['arrow_where']=vv ;

   vv=strip(tagSpecsFind(anode,'arrow#size','arrow_size','20')) ;
   if (isNaN(vv)) {
        alert('setValueSpecs error: <arrow size> is not a number: '+vv);
        return -1 ;
    }
   valueSpecs[ith]['arrows_size']=vv ;

   valueSpecs[ith]['arrows_node']=setValueSpecsArrows(ith)  ;           // the node containing a table of arrows 

}                                               // end of <arrow>

// ===== SCROLL
vv=tagSpecsFind(anode,'scroll','scroll',null);                     // start of <Scroll>
valueSpecs[ith]['scroll']=-1 ;
if (vv!==null) {                                                 // there is a <scroll>
   valueSpecs[ith]['scroll']=1 ;
  vv=tagSpecsFind(anode,'scroll.where','scroll_where','');
  valueSpecs[ith]['scroll_where']=vv ;

  vv=tagSpecsFind(anode,'scroll#show','scroll_show','');
  valueSpecs[ith]['scroll_show']=strip(vv) ;

  vv=strip(tagSpecsFind(anode,'scroll#titleOnly','scroll_titleOnly',''));
  if (vv=='1') valueSpecs[ith]['scroll_show']='2' ;

  if (vmin==='' || isNaN(vmin)) vmin=0;
  vv=tagSpecsFind(anode,'scroll.min','scroll_min',vmin);
  if (isNaN(vv)) {
        alert('setValueSpecs error: bad scrollMin ='+vv);
        return 0;
  }
  valueSpecs[ith]['scroll_min']=vv ;

  if (vmax==='' || isNaN(vmax) ) vmax=100;
  vv=tagSpecsFind(anode,'scroll.max','scroll_max',vmax);  
  if (isNaN(vv)) {
        alert('setValueSpecs error: bad scrollMax ='+vv);
        return 0;
  }
  valueSpecs[ith]['scroll_max']=vv ;

  vv=tagSpecsFind(anode,'scroll.width','scroll_width','100');
  valueSpecs[ith]['scroll_width']=vv ;

  vv=tagSpecsFind(anode,'scroll.cells','scroll_cells','33');
  if (isNaN(vv)) {
        alert('setValueSpecs error: bad scroll cells ='+vv);
        return 0;
  }
  valueSpecs[ith]['scroll_cells']=vv ;
  var nDiv=vv ;

  vv=tagSpecsFind(anode,'scroll.leftColor','scroll_leftColor','22aa88');
  if (vv.substr(0,1)=='#') vv=vv.substr(1);
  valueSpecs[ith]['scroll_leftColor']=vv ;
  valueSpecs[ith]['scroll_red0']=parseInt(vv.substr(0,2),16);
  valueSpecs[ith]['scroll_green0']=parseInt(vv.substr(2,2),16);
  valueSpecs[ith]['scroll_blue0']=parseInt(vv.substr(4,2),16);

  vv=tagSpecsFind(anode,'scroll.rightColor','scroll_rightColor','55ff99');
  if (vv.substr(0,1)=='#') vv=vv.substr(1);
  valueSpecs[ith]['scroll_rightColor']=vv ;
  valueSpecs[ith]['scroll_red1']=parseInt(vv.substr(0,2),16);
  valueSpecs[ith]['scroll_green1']=parseInt(vv.substr(2,2),16);
  valueSpecs[ith]['scroll_blue1']=parseInt(vv.substr(4,2),16);

  var rdiff=(  valueSpecs[ith]['scroll_red1']- valueSpecs[ith]['scroll_red0'])/nDiv; 
  var bdiff=(  valueSpecs[ith]['scroll_blue1'] -  valueSpecs[ith]['scroll_blue0'])/nDiv ; 
  var gdiff=(  valueSpecs[ith]['scroll_green1'] -  valueSpecs[ith]['scroll_green0'])/nDiv ; 

 valueSpecs[ith]['scroll_rdiff']=rdiff;                         // these are used to specify the colors of each cell
 valueSpecs[ith]['scroll_gdiff']=gdiff;
 valueSpecs[ith]['scroll_bdiff']=bdiff;

  vv=tagSpecsFind(anode,'scroll.fmt scroll#fmt scroll#format ','fmt format scroll_fmt','') ;  
  valueSpecs[ith]['scroll_fmt']=vv ;

   setValueSpecsScroll(-1,ith)  ;           // the node containing a table of arrows 

}

valueSpecs[ith]['node']=anode ;

return ith ;


}                               // end of spec read


//===================================
// create an input node using valueSpecs[ith], replace anode with this input node
// create <input>, add attributes

function setValueSpecsInsert(ith,anode,loopvs,anode1) {

var ainput,atable,atbody,atext,atr,atd,arrowTd=0,scrollTd=0;
var tmp,tmpid;

if (arguments.length<3) loopvs='';
if (arguments.length<4) anode1=anode;

ainput=document.createElement('input');

E2_copyAttributes(anode,ainput,'type value  submitName submitVar submit name ');

ainput.setAttribute('type','text');

tmp=getAttributes(anode,'ID','');
if (tmp==='') {
   tmp='ID_'+Math.random(); tmp=tmp.replace('.','_');
   ainput.setAttribute('ID',tmp);
}
valueSpecs[ith]['ID']=tmp ;
set_elemValue(ainput,valueSpecs[ith]['start']); 
ainput.setAttribute('start',valueSpecs[ith]['start']);      // this is added so that #start can be used in equations
ainput.setAttribute('priorVal',valueSpecs[ith]['start']);      // this is added so that #priorVal can be used in equations
valueSpecs[ith]['priorVal']=valueSpecs[ith]['start'];  

valueSpecs[ith]['useValue']=valueSpecs[ith]['start'];  

ainput.setAttribute('isValue','1');

if (valueSpecs[ith]['name']!=='') ainput.setAttribute('name',valueSpecs[ith]['name']);

ainput.setAttribute('loopVarsAll',loopvs);              // used by event handlers (current value of all loopvariables 
valueSpecs[ith]['loopVarsAll']=loopvs ;  

ainput.setAttribute('onClick','var thisvaluenow=setValueSpecsClick('+ith+',this.value); ; this.value=thisvaluenow') ;


if (document.createEventObject) {               // stupid ie hack
  ainput.setAttribute('onBlur',' var thisvaluenow=setValueSpecsChange('+ith+',this.value);; this.value=thisvaluenow ;'); 
} else {                                // not ie
  ainput.setAttribute('onChange','var thisvaluenow=setValueSpecsChange('+ith+',this.value); this.value=thisvaluenow ;'); 
}


// Key?
if (valueSpecs[ith]['key']!=-1) {  
   ainput.setAttribute('onKeyup','var thisvaluenow=setValueSpecsKey('+ith+',event,this);  this.value=thisvaluenow ;') ;
}

if (valueSpecs[ith]['title']!='') ainput.setAttribute('title',valueSpecs[ith]['title']);

// create table to contain input, and arrows or scroll?

if (valueSpecs[ith]['arrow']!=-1 || valueSpecs[ith]['scroll']!=-1 ) {
  atable=document.createElement('table');
  atbody=document.createElement('tbody');
  atr=document.createElement('tr');                     // first cell first row has the <input>
  atd=document.createElement('td');
  atd.style.textAlign='center';
  atd.appendChild(ainput);
  atr.appendChild(atd);

  if (valueSpecs[ith]['arrow']!=-1) {                           // 2nd cell first row is default location for the <arrow> -- but check for <where>
     if (valueSpecs[ith]['arrow_where']=='') {
          atd=document.createElement('td');
          atd.appendChild(valueSpecs[ith]['arrows_node']);
          atr.appendChild(atd);
          arrowTd=1;
      } else {
          idiv=document.getElementById(valueSpecs[ith]['arrow_where']);
          if (!idiv) {
                alert('Error in <VALUE>: unknown ID for arrow= ' +valueSpecs[ith]['arrow_where']);
                return 0;
           }
           idiv.innerHTML='';
           idiv.appendChild(valueSpecs[ith]['darrows_node']);
      }
  }
  atbody.appendChild(atr);
 
  if (valueSpecs[ith]['scroll']!=-1) {                  // 2nd row has the <scroll> (possibly over two columns) -- but check for <where>
     if (valueSpecs[ith]['scroll_where']=='') {
          atr=document.createElement('tr');
          atd=document.createElement('td');
          if (arrowTd==1)  atd.setAttribute('colspan','2');
          atd.appendChild(valueSpecs[ith]['scroll_node']);
          atr.appendChild(atd);
          atbody.appendChild(atr);
          scrollTd=1 ;
     } else {
          idiv=document.getElementById(valueSpecs[ith]['scroll_where']);
          if (!idiv) {
                alert('Error in <VALUE>: unknown ID for scroll= ' +valueSpecs[ith]['scroll_where']);
                return 0;
           }
           idiv.innerHTML='';
           idiv.appendChild(valueSpecs[ith]['scroll_node']);
     }
  }

  if (arrowTd==1 || scrollTd==1) {
     atable.appendChild(atbody);
     anode1.parentNode.insertBefore(atable,anode1);
     anode1.parentNode.removeChild(anode1);    
  } else  {                                             // arrow and scroll in explicit location, so don't bother with a table
          anode1.parentNode.insertBefore(ainput,anode1);    // (kind of a hack, cause table created above is never used. but wtf)
          anode1.parentNode.removeChild(anode1);    
  }


} else {                                                // no arrow or scroll, so no need to use table 
  anode1.parentNode.insertBefore(ainput,anode1);
  anode1.parentNode.removeChild(anode1);    
}

valueSpecs[ith]['input']=ainput ;

return  1 ;


}


// ========================================================== submit change





//=======================
// ==== key handler for <VALUE>
// does nothing except for the following keycodes (that seem to work on the major browsers)
// arrows: left=37,  up=38, right=39, down=40, pgup=33, pgdn=34, esc=27, backspace=8, del-46


function setValueSpecsKey(ith,ae,athis) { 

var ielem,foo,acode,akey,avalue,newval,dochange=0;
var vinc,vincPage,vEsc,dainc,didesc=0 ;
var vv,nfmt;

  var actCodes=' 38 40 33 34 27 ';   // uparrow downarrow pgup pgdn esc

  avalue=athis.value ;
  newval=avalue ;

  if (!ae) ae=window.event ;
  ielem= (ae.srcElement) ? ae.srcElement : ae.target ;
  var acode=ae.keyCode ;
  var akey=ae.which ;
  if (document.all) {akey=acode; acode=0}                // ie is too stupid to support

  if (actCodes.indexOf(' '+akey+' ')<0) return avalue ;              // not an actCode, do nothing

   vinc=valueSpecs[ith]['key_inc'] ;
   vincPage=valueSpecs[ith]['key_inc_page'] ;

  if (akey==27) {                       // escape
        vEsc=valueSpecs[ith]['key_esc']; 
        if (strip(avalue)==strip(vEsc)) {
              avalue='' ;
         } else {
               avalue=vEsc ;
               didesc=1;
        }
  } 


  if (akey==38 && !isNaN(avalue) ) {     
        if (avalue==='') avalue=vEsc ; dainc=vinc ;
        if (!isNaN(avalue)) avalue=1*avalue+ 1*vinc  ;                  // up
  } 

  if (akey==40 && !isNaN(avalue) ) {     
        if (avalue==='') avalue=vEsc  ; dainc=vinc ;
        if (!isNaN(avalue))  avalue=1*avalue - 1*vinc  ;                  // udown
  } 


  if (akey==33 && !isNaN(avalue) ) {                       // pgup
        if (avalue==='') avalue=vEsc ;  dainc=vincPage  ;
         if (!isNaN(avalue))  avalue=1*avalue+ 1*vincPage  ;                  // up
  } 

  if (akey==34 && !isNaN(avalue)  ) {                       // pgdn
        if (avalue==='') avalue=vEsc ;  dainc=vincPage  ;
        if (!isNaN(avalue))  avalue=1*avalue - 1*vincPage  ;                  // up
  } 

  if (didesc==0) {
      if (!isNaN(avalue)) {
         dainc=strip(dainc);
         vv=parseAt(dainc,'.');
         dainc=vv[1];
         nfmt=dainc.length;
         newval=setValueSpecsCheckNumber(avalue,ith,nfmt);           // check against max,min, etc
     }
  } else {
       newval=setValueSpecsCheckNumber(avalue,ith);           // check against max,min, etc
  }

  set_elemValue(valueSpecs[ith]['input'],newval)
  valueSpecs[ith]['priorVal']=newval;
  valueSpecs[ith]['input'].setAttribute('priorVal',newval);
  setValueSpecsScroll(0,ith,newval) ;                          // move scroll bar? 

  return newval ;

}

//======================= 
// ==== click hanlder for <VALUE>

function setValueSpecsClick(ith,nowval) {

var lnames=[],lvals,loopvs,tt,jj,ii;
 if (valueSpecs[ith]['click']=='') return nowval ;

   loopvs=valueSpecs[ith]['loopVarsAll'];
   if (loopvs!=='') {
     lnames=[];
     lvals=[];
     loopvs=getWord(loopvs);
     for (var jj=0;jj<loopvs.length;jj++) {
         tt=parseAt(loopvs[jj],'=');
         ii=lnames.length;
         lnames[ii]=strip(tt[0]).toUpperCase() ;
         lvals[ii]=svy_getVal(lnames[ii]) ;                     // prior values (restore when change is done
         svy_setVal(lnames[ii],tt[1]); 
      }
    }

  set_elemValue(valueSpecs[ith]['input'],nowval)
  E2_doEquations(valueSpecs[ith]['input'],valueSpecs[ith]['click'],0)      ;  

// reset loopvars to prior values
  for (var jj=0;jj<lnames.length;jj++) {
         svy_setVal(lnames[jj],lvals[jj]); 
  }

  nowval=get_elemValue(valueSpecs[ith]['input']);                       // if you explicitily set the value, it will set the value of the input box
  valueSpecs[ith]['useValue']=nowval;
  return nowval ;

}

//=====
// display busy message;
function displayBusyAlert(ido) { 

var iccs,balert=-1 ;
iccs=document.getElementById('_busyAlert');
if (!iccs) return 0;

if (ido==2) alert(' ... close this box to resume computing ');

if (ido==1) iccs.style.display='inline';
if (ido==0) iccs.style.display='none';

}


//=======================
// ==== <change> handler for <VALUE>
// first do max, min, etc tests
// then do <changeVar> stuff
// then do <change> stuff
// when doing change, temporarily set variables in tthe loopvarsall attribute 

function setValueSpecsChange(ith,nowval) {


var notNum,amess,zz,callow=0,tisnum;
var loopvs;
var ii;
var lnames=[],lvals,jj,tt,ii ;

displayBusyAlert(1);

if (strip(valueSpecs[ith]['allowed'])!='') {                           // check answer against "words" in <allowed>
   callow=1 ;
   goo=' '+strip(nowval)+' ';
   if (valueSpecs[ith]['allowed'].indexOf(goo)==-1) {
          nowval= valueSpecs[ith]['priorVal'] ;
          if (valueSpecs[ith]['allowed_show']==1) alert('You must enter one of the following values: '+valueSpecs[ith]['allowed']);
      }          
}


notNum=isNaN(nowval);
if (strip(nowval)==='') notNum=1 ;

// check numeric value for bounds (max,min,confirm_min,confirm_max)
if (!notNum && callow==0) {                   // is a number (and not a '') -- check max, etc
   nowval=setValueSpecsCheckNumber(nowval,ith);
}


var tisnum=valueSpecs[ith]['isNumber'] ;
if (callow==0) {                                // don't check if allow was already checked
  if (notNum && tisnum!='0') {                   // not a number, and perahsp number required? Than check for isNumber  
   if (tisnum==2) {                // must be a number. If not, set to priorval
     nowval=valueSpecs[ith]['priorVal'] ;
     if (valueSpecs[ith]['isnumber_show']=='1') alert('You must enter a number, or a space ');
    }
    if (tisnum==1 && strip(nowval)!=='') {
       nowval= valueSpecs[ith]['priorVal'] ;
       if (valueSpecs[ith]['isnumber_show']=='1') alert('You must enter a number, or a space ');
    }
  }                                     // notnum and tisnum 
}                                       // callow

 setValueSpecsScroll(0,ith,nowval) ;                          // move scroll bar?

 if (valueSpecs[ith]['change']=='') {
      if (strip(valueSpecs[ith]['changeVar'])!=='') {                // change a variable (to be current value)
         svy_setVal(valueSpecs[ith]['changeVar'],nowval) ;                 
     }
      valueSpecs[ith]['priorVal']=nowval;                            // save current value to use as prior value
      valueSpecs[ith]['input'].setAttribute('priorVal',nowval);    
      valueSpecs[ith]['useValue']=nowval;

     displayBusyAlert(0);

      return nowval ;
 }


// temporary save of vars listed in loopvars
   loopvs=valueSpecs[ith]['loopVarsAll'];
   if (loopvs!=='') {
     lnames=[];
     lvals=[];
     loopvs=getWord(loopvs);
     for (var jj=0;jj<loopvs.length;jj++) {
         tt=parseAt(loopvs[jj],'=');
         ii=lnames.length;
         lnames[ii]=strip(tt[0]).toUpperCase() ;
         lvals[ii]=svy_getVal(lnames[ii]) ;                     // prior values (restore when change is done
         svy_setVal(lnames[ii],tt[1]); 
      }
    }


// if here, do the <change> stuff
  set_elemValue(valueSpecs[ith]['input'],nowval) ;           // a hack that (contents of input textbox is fussy about changing

  ares=E2_doEquations(valueSpecs[ith]['input'],valueSpecs[ith]['change'],0)      ;  

  nowval=get_elemValue(valueSpecs[ith]['input']);          // priorVal becomes the current value

  valueSpecs[ith]['priorVal']=nowval;
  valueSpecs[ith]['input'].setAttribute('priorVal',nowval);  // and save it in the element's attributes

  for (var jj=0;jj<lnames.length;jj++) {                        // reset loopvars to prior values
         svy_setVal(lnames[jj],lvals[jj]); 
  }

// set the ChangeVar variable (after all other change processing 


if (strip(valueSpecs[ith]['changeVar'])!=='') {                          // change a variable (to be current value)
  svy_setVal(valueSpecs[ith]['changeVar'],nowval) ;                 
}

valueSpecs[ith]['useValue']=nowval;

 displayBusyAlert(0);



return  nowval ;                                // returned value is used to set input textbox

}               // return

//===================
//  check numeric values for max,min,confirm_max, and confirm_min
  
function setValueSpecsCheckNumber(nowval,ith,afmt,iquiet) {
 var zz,amess ;
 if (arguments.length<3) afmt='';
 if (arguments.length<4) iquiet=0 ;

 afmt=strip(afmt);
 iquiet=strip(iquiet);

  nowval=strip(nowval);
  if (typeof(nowval)=='undefined' || isNaN(nowval) || nowval==='' )  return nowval ;


  if (afmt!=='' && !isNaN(nowval)) {
     nowval=strip(nowval);
     nowval=parseFloat(nowval);
     nowval=nowval.toFixed(parseInt(afmt)) ;
  }

        
   if (valueSpecs[ith]['max']!=='') {                           // <max> in a <value>
       if (1*nowval> 1*valueSpecs[ith]['max']) {
           nowval=valueSpecs[ith]['max'] ;
           if (valueSpecs[ith]['max_show']=='1' && iquiet!=1 )  alert(' Warning: You can not enter a value larger than '+nowval);
           if (valueSpecs[ith]['max_show']=='2' && iquiet!=1 ) {
                 writeAlert('Warning: You can not enter a value larger than '+nowval,5);
            }
       }
   }

   if (valueSpecs[ith]['min']!=='') {
       if (1*nowval<1*valueSpecs[ith]['min'])  { 
          nowval=valueSpecs[ith]['min'];
          if (valueSpecs[ith]['min_show']=='1' && iquiet!=1 )  alert(' You can not enter a value smaller than '+nowval);
        }
   }


   if (valueSpecs[ith]['confirm_max_value']!=='' && iquiet!=1   ) {
       if (1*nowval>1*valueSpecs[ith]['confirm_max_value'] ) {
          amess=valueSpecs[ith]['confirm_max_message'] ; 
          if (amess=='') amess='Your value ('+nowval+') is greater than '+ valueSpecs[ith]['confirm_max_value']+'. Are you sure? ';  
          zz=confirm(amess);
          if (zz==0) {
                 nowval= valueSpecs[ith]['priorVal'] ;
           }
        
       } 
   }
   if (valueSpecs[ith]['confirm_min_value']!=='' && iquiet!=1   ) {
       if (1*nowval<1*valueSpecs[ith]['confirm_min_value']) { 
          amess=valueSpecs[ith]['confirm_min_message'] ;
          if (amess=='') amess='Your value ('+nowval+') is less than '+ valueSpecs[ith]['confirm_min_value']+'. Are you sure? ';
          zz=confirm(amess);
          if (zz==0) {
                 nowval= valueSpecs[ith]['priorVal'] ;
           }
       }
   }


  if (afmt!=='' && !isNaN(nowval)) {
     nowval=strip(nowval);
     nowval=parseFloat(nowval);
      nowval=nowval.toFixed(parseInt(afmt)) ;
  }
  return nowval ;

}                               // notnum


//================
// create a table node with arrows in it
function setValueSpecsArrows(ith)  {

 var atable,atbody,atr,ath,atd,aimg,imgsize;
 var abase ;
abase=valueSpecs[ith]['arrow_name'] ;
imgsize=valueSpecs[ith]['arrows_size'] ;
 atable=document.createElement('table');
 atbody=document.createElement('tbody');
  atr=document.createElement('tr');
  atd=document.createElement('td');
    aimg=document.createElement('img');
         aimg.setAttribute('src','/dsurvey/docs/icons/'+abase+'Up.gif');
         aimg.setAttribute('title','click here to increment value');
         aimg.setAttribute('alt','up');
         aimg.setAttribute('height',imgsize);
         aimg.setAttribute('width',imgsize);
         aimg.setAttribute('onClick','setValueSpecsArrowIncrement(1,'+ith+')'); 
         atd.appendChild(aimg);
      atr.appendChild(aimg);
    atbody.appendChild(atr);
      atr=document.createElement('tr');
         atd=document.createElement('td');
         aimg=document.createElement('img');
         aimg.setAttribute('src','/dsurvey/docs/icons/'+abase+'Down.gif');
         aimg.setAttribute('title','click here to decrement value');
         aimg.setAttribute('alt','down');
         aimg.setAttribute('onClick','setValueSpecsArrowIncrement(-1,'+ith+')'); 
         aimg.setAttribute('height',imgsize);
         aimg.setAttribute('width',imgsize);
         atd.appendChild(aimg);
      atr.appendChild(aimg);
    atbody.appendChild(atr);
  atable.appendChild(atbody);
  return atable ;

 }

//================
// onclick of an arrow 
function setValueSpecsArrowIncrement(iadd,ith)  {
var idd,myid,myvalue,vv,newval,aid;
aid=valueSpecs[ith]['ID'];
idd=document.getElementById(aid);
vv=get_elemValue(idd,0);
newval=(1*vv)+(1*iadd);

var dainc=strip(iadd);
var  vv=parseAt(dainc,'.');
dainc=vv[1];
var nfmt=dainc.length;

newval=setValueSpecsCheckNumber(newval,ith,nfmt);           // check against max,min, etc

vv=set_elemValue(idd,newval);
idd.setAttribute('value',newval);

valueSpecs[ith]['priorVal']=newval;
valueSpecs[ith]['input'].setAttribute('priorVal',newval);

setValueSpecsScroll(0,ith,newval) ;                          // move scroll bar? 

return 1;
}



//==============
// Create a "scroll value" bar. Mouseover the bar and the bar fills in from left edge to mouse location.
// Click on the bar and a value, that depends on the mouse location within the bar, will be written to an input field.
 
function setValueSpecsScroll(ido,iat,athis,canshow) {
var m,goo,astyle;
var red0,blue0,green0,ruse,buse,guse,rdiff,bdiff,gdiff,vv;
var scrollValueId,ac16,aaval,useTitle=0 ;
var aadd='';
var barWidth,maxVal,minVal,iDivs,ipad;
var fillY,fillN,tmp,tmp2,aid,iid;
var initdo=0;
var atitle='';

if (arguments.length<4) canshow=0;
canshow=strip(canshow);

if (arguments.length<1) ido=0 ;                                 // if no argument, start with "empty" scroll bar
if (arguments.length<2) iat=0 ;                                 // use first scroll bar
if (ido==-1) {
        ido=0; initdo=1;                        // initdo controls what to do with scroll bar code
}

// make sure there is a scroll bar
if (valueSpecs[iat]['scroll']=='-1') return 0 ;         // no scroll, do nothing

vv=valueSpecs[iat]['scroll_show'] ;
if (vv=='2') {
        useTitle=1;
        canshow=0;
}

red0=valueSpecs[iat]['scroll_red0'] ;
green0=valueSpecs[iat]['scroll_green0'] ;
blue0=valueSpecs[iat]['scroll_blue0'] ;

rdiff=valueSpecs[iat]['scroll_rdiff'] ;
gdiff=valueSpecs[iat]['scroll_gdiff'] ;
bdiff=valueSpecs[iat]['scroll_bdiff'] ;

barWidth=valueSpecs[iat]['scroll_width'] ;

maxVal=valueSpecs[iat]['scroll_max'] ;           // max and min values
minVal=valueSpecs[iat]['scroll_min'] ;
iDivs=valueSpecs[iat]['scroll_cells'];                    // # of divisions

if (arguments.length>2 && canshow==0 ) {                      // typed in value to scroll bar conversion
  if (typeof(athis)!='object') {
        aaval=athis*1;
  } else {
       aaval=athis.value*1 ;
  }
  if (isNaN(aaval)) {
      ido=0 ;
  } else { 
      if (aaval<=minVal) {
         ido=0;
      } else if (aaval>=maxVal) {
         ido=iDivs ;
      } else {
         ido=Math.ceil(iDivs*(aaval-minVal)/(maxVal-minVal));
      }
  }
}

ipad=Math.ceil(barWidth/iDivs) ;    // width of each division in the scroll bar

fillY='padding-left:'+ipad+'px;     ' ;             // color of divisions in the left-of-cursor portion of scroll bar (modified below to be a color ramp)
fillN='padding-left:'+ipad+'px ; border-left:1px #aaaaaa dotted;  background-color:#8899aa ';            // color of divisions in the right-of-cursor portion of scroll bar

// left border (minval)
  var sBLeft='padding-left:8x; margin:0px;background-color:white;color:white ';
  var sBRight='padding-right:8px;background-color:white;color:white; border-left:1px gray dotted ';     

  goo='<span style="'+sBLeft+'" onClick="setValueSpecsScroll(0,'+iat+'); setValueSpecsSetScrollValue(0,'+iat+')"  title="'+minVal+'"  >.</span>  \n';
  aadd=aadd+goo ;

// Blocks < current value (to the left of the cursor). Note use of color-ramp
for  (var m=0;m<ido;m++) {
    ruse=Math.ceil(red0+(m*rdiff));  guse=Math.ceil(green0+(m*gdiff)); buse=Math.ceil(blue0+(m*bdiff));
    ac16='#'+ruse.toString(16)+guse.toString(16)+buse.toString(16);
    astyle=' style="' +fillY+ ' border-left:1px '+ac16+' dotted; background-color:'+ac16+'   " ';
    if (useTitle==1) {
        atitle=' title="'+setValueSpecsComputeScrollValue(m,iat,1)+'" ' ;
        goo='<span  '+astyle+' '+atitle+' onClick="setValueSpecsSetScrollValue('+m+','+iat+')"    > </span>  \n';
    } else {
       goo='<span  '+astyle+'  onClick="setValueSpecsSetScrollValue('+m+','+iat+')"    onMouseOver="setValueSpecsScroll('+m+','+iat+',0,1)"    > </span>  \n';
    }
    aadd=aadd+goo ;
}

// Blocks > current value (to the right of the curso)

for  (var m=ido;m<iDivs;m++) {
     astyle=' style="'+fillN+';   " ' ;
     if (useTitle==1) {
        atitle=' title="'+setValueSpecsComputeScrollValue(m,iat,1)+'" ' ;
        goo='<span  ' + astyle+' '+atitle+' onClick="setValueSpecsSetScrollValue('+m+','+iat+')"    > </span>  \n';
      } else {
           goo='<span  ' + astyle+'  onClick="setValueSpecsSetScrollValue('+m+','+iat+')"  onMouseOver="setValueSpecsScroll('+m+','+iat+',0,1)" > </span>  \n';
      }
     aadd=aadd+goo ;
}

// right border (max)
   goo='<span style="'+sBRight+'"  onClick="setValueSpecsScroll('+iDivs+','+iat+');setValueSpecsSetScrollValue('+iDivs+','+iat+')"    title="'+maxVal+'"  >.</span>  \n';


aadd=aadd+goo ;

if (canshow==1) {
    if (valueSpecs[iat]['scroll_show']==1) {
        vv=setValueSpecsComputeScrollValue(ido,iat,1) ;
        if (valueSpecs[iat]['priorVal']!=vv) {
           m=document.createElement('span');
           m.style.backgroundColor='#cdcdcd'; 
           goo='<span  style="color: #282928;background-color:#cddecd">'+vv+'</span> ';
           aadd=aadd+goo ;
        }
    }
 }

if (initdo==1) {
   goo=document.createElement('span');
   tmp='ID_'+Math.random(); tmp=tmp.replace('.','_');
   goo.setAttribute('ID',tmp);
   goo.innerHTML=aadd;
   valueSpecs[iat]['scroll_node']=goo;
   valueSpecs[iat]['scroll_node_ID']=tmp;
} else {
   idd=document.getElementById(valueSpecs[iat]['scroll_node_ID']);;
   idd.innerHTML=aadd;
}


   return 1 ;


}                               // end of setValueSpecsScroll  

// ============
// compute value at cell m in scroll bar
function setValueSpecsComputeScrollValue(im,iat,iquiet) {
var vv0,vv1,ddiv,afmt,vdif,afrac,newval,iid ;

vv0=valueSpecs[iat]['scroll_min'] ;
vv1=valueSpecs[iat]['scroll_max'] ;
ddiv=valueSpecs[iat]['scroll_cells'] ;
afmt=valueSpecs[iat]['scroll_fmt'] ;

vdiff=vv1-vv0 ;  
afrac=im/ddiv ;  
newval=(1*vv0)+(vdiff*afrac) ;

newval=setValueSpecsCheckNumber(newval,iat,afmt,iquiet);           // check against max,min, etc

if (iquiet!=1) {
 setValueSpecsScroll(0,iat,newval) ;
 iid=valueSpecs[iat]['ID'];
  vv0=document.getElementById(iid);
  vv0.focus();
}

return newval ;
}

// ============
// set value when click on 
function setValueSpecsSetScrollValue(im,iat) {

var vv0,vv1,afrac,vdiff,afmt,newval,valueBoxID,ddiv;
var aid,idd ;

aid=valueSpecs[iat]['ID'];
idd=document.getElementById(aid);


newval=setValueSpecsComputeScrollValue(im,iat,0) 

vv=set_elemValue(idd,newval);
idd.setAttribute('value',newval);

valueSpecs[iat]['priorVal']=newval;
valueSpecs[iat]['input'].setAttribute('priorVal',newval);

return 1;



}




