    // ********************* EFC version ******************************************
    //global strings that can be set by external validation routine;
    //  non-empty value for errors2 will print & return false (fail);
    //  non-empty value for warnings2 will print but not fail alone
var errmsg = "";
var errors2 = "";
var warnings2 = "";

function fldname(f) {
    var re = /_/g;
    var fname = (f.label==null ? f.name.replace(re," ") : f.label);
    return fname;
}

function getval(s) {
    if (isNaN(s.value) || s.value == null || parseInt(s.value) == 0) {
	return 0;
    } else {
	return parseInt(s.value);
    }
}

    //return value of SINGLE selected option
function getselectval(s) {
    for (var i=0; i<s.length; ++i) {
	if (s[i].selected) return s[i].value;
    }
    return (-1);
}

    //return value of MULTIPLE selected option(s), delimited by char d
function getmselectval(s,d) {
    var t = "";
    for (var i=0; i<s.length; ++i) {
	if (s[i].selected) {
	    if (t != "")
		t += d;
	    t += s[i].value;
	}
    }
    return (t);		//caller must check for empty string
}

    //return value of checked radio button
function getradioval(s) {
    for (var i=0; i<s.length; ++i) {
	if (s[i].checked) return s[i].value;
    }
    return (-1);
}

    //return how many boxes were checked in a checkbox object
function getchkboxcnt(s) {
    var n=0;
    for (var i=0; i<s.length; ++i) {
	if (s[i].checked) ++n;
    }
    return (n);
}

function iszero(s) {
    return (isNaN(s.value) || s.value == null || s.value+0 == 0);
}

    // A utility function that returns true if a string contains only 
    // whitespace characters.
function isblank(s) {
    for (var i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if ((c != ' ') && (c != '\n') && (c != '\t')) return false;
    }
    return true;
}

    // Do some rudimentary checking on an email address
function checkemail(s) {
    disallowed = "()<>,;:\\\"[ ]"
    txt = s.value;
    if (txt.indexOf("@") < 3) {
	return false;
    }
    for (i=0; i<12; ++i)
	if (txt.indexOf(disallowed.substring(i,i+1)) != -1)
	    return false;
    if ((txt.indexOf(".com") < 5)
	    && (txt.indexOf(".org") < 5)
	    && (txt.indexOf(".gov") < 5)
	    && (txt.indexOf(".net") < 5)
	    && (txt.indexOf(".mil") < 5)
	    && (txt.indexOf(".int") < 5)
	    && (txt.indexOf(".edu") < 5)) {
	return false;
    }
    return true;
}   //checkemail

    // Validation for a birthdate; set s.bdate=true to trigger this check
    // Set var.minage and var.maxage to control range of acceptable dates
function checkbdate(s) {
    var minage = s.minage;
    var maxage = s.maxage;
    var err = 0;
    var age = 0;
    var re = /\//;
    var sdate = s.value.split(re);
    var nflds = sdate.length
    var m = sdate[0];
    var d = sdate[1];
    var y = sdate[2];
    if (y < 1000) {
      if (y > 10)
	y += 1900;
      else
	y += 2000;
    }
    var ymd = Number(y*10000) + Number(m*100) + Number(d);
    var today = new Date();
    var thisyy = today.getFullYear();	//browser-dep - returns 2 or 4-digit yr
    var thismm = today.getMonth()+1;	//getMonth returns 0-11
    var thisdd = today.getDate();
    if (thisyy < 1000) {
      if (thisyy > 10)
	thisyy += 1900;
      else
	thisyy += 2000;
    }
    var thisymd = Number(thisyy*10000) + Number(thismm*100) + Number(thisdd);
    var isfuture = (ymd > thisymd);

    errmsg = "";
    if (isNaN(maxage)) maxage = 99;
    if (isNaN(minage)) {
	if (s.future)		//a future date is OK
	    minage = -99
	else
	    minage = 0
    }

    if (nflds == 2 && s.nodayok) {
	d = 1		//value doesn't matter
	y = sdate[1]
	nflds = 3;
    }

    if (nflds != 3) {
	err = 1
	errmsg = "format must be mm/dd/yyyy"
	if (s.nodayok) errmsg += " or mm/yyyy"
    } else if (m<1 || m>12) {
	err = 2
	errmsg = "month must be 1-12"
    } else if (d<1 || d>31) {
	err = 3 
	errmsg = "day of month must be 1-31"
    } else if (m==4 || m==6 || m==9 || m==11) {	//check months with 30 days
	if (d > 30) {
	    err=5
	    errmsg = "day of month not valid"
	}
    } else if (m==2) {	// check february for leap year
	if (d > 29) {
	    err=7
	    errmsg = "day of month for February not valid"
	} else if (d==29 && ! (y%4 == 0 && (y%100 != 0 || y%400 == 0))) {
	    err=8	//not a leap year
	    errmsg = y + " is not a leap year"
	}
    }

    age = thisyy - y
    if (thismm < m || (thismm == m && thisdd < d)) age--
    if (err == 0
	    && (age < minage || age > maxage || (maxage == 0 && !isfuture))) {
	err = 4
	if (minage < 0) {
	    var x = thisyy-minage
	    var y = thisyy-maxage
	    errmsg = "year must be on/after " + (maxage==0 ? "today" : y);
	    errmsg += " and before " + x;
	} else {
	    errmsg = "age must be greater than/equal to " + minage;
	    errmsg += " and less than/equal to " + maxage;
	}
    }
    if (err>0)
	return false
    else
	return true
}  //checkbdate

    // Validation for any date; set s.anydate=true to trigger this check
    // can set s.mindate, s.maxdate, s.nodayok, s.futureonly (for today+ only)
function checkdate(s) {
    var mindate = s.mindate;	// yyyymmdd or 0
    var maxdate = s.maxdate;	// yyyymmdd or 0
    var err = 0;
    var re = /\//;
    var sdate = s.value.split(re);
    var nflds = sdate.length
    var m = sdate[0];
    var d = sdate[1];
    var y = sdate[2];
    var ymd = Number(y*10000) + Number(m*100) + Number(d);
    var today = new Date();
    var thisyy = today.getYear();	//browser-dep - returns 2 or 4-digit yr
    var thismm = today.getMonth()+1;	//getMonth returns 0-11
    var thisdd = today.getDate();
    if (thisyy < 1000) thisyy += 2000;
    var thisymd = Number(thisyy*10000) + Number(thismm*100) + Number(thisdd);
    var isfuture = (ymd > thisymd);

    errmsg = "";
    if (nflds == 2 && s.nodayok) {	// mm/yyyy is OK
	d = 1;		//value doesn't matter
	y = sdate[1];
	nflds = 3;
    }

    if (nflds != 3) {
	err = 1;
	errmsg = "format must be mm/dd/yyyy";
	if (s.nodayok) errmsg += " or mm/yyyy";
    } else if (m<1 || m>12) {
	err = 2;
	errmsg = "month must be 1-12";
    } else if (d<1 || d>31) {
	err = 3;
	errmsg = "day of month must be 1-31";
    } else if (m==4 || m==6 || m==9 || m==11) {	//check months with 30 days
	if (d > 30) {
	    err = 5;
	    errmsg = "day of month not valid";
	}
    } else if (m==2) {	// check february for leap year
	if (d > 29) {
	    err = 7;
	    errmsg = "day of month for February not valid";
	} else if (d==29 && ! (y%4 == 0 && (y%100 != 0 || y%400 == 0))) {
	    err = 8;
	    errmsg = y + " is not a leap year";
	}
    } else if (y < 1900) {
	err = 9;
	errmsg = "year must be after 1900";
    }

    if (err == 0 && mindate > 0 && ymd < mindate) {
	err = 4;
	errmsg = "date must be on/after "
	    + Math.floor((mindate%10000)/100) + "/"
	    + Math.floor(mindate%100) + "/"
	    + Math.floor(mindate/10000);
    }
    if (err == 0 && maxdate > 0 && ymd > maxdate) {
	err = 4;
	errmsg = "date must be on/before "
	    + Math.floor((maxdate%10000)/100) + "/"
	    + Math.floor(maxdate%100) + "/"
	    + Math.floor(maxdate/10000);
    }
    if (err == 0 && ymd < thisymd && s.futuredateonly) {
	err = 4;
	errmsg = "date must be on/after today";
    }
    if (err>0)
	return false;
    else
	return true;
}  //checkdate

    // This is the function that performs form verification. It will be invoked
    // from the onSubmit() event handler. The handler should return whatever
    // value this function returns.
function verify(f)
{ 
    var msg;
    var empty_fields = "";
    var errors = "";

    // Loop through the elements of the form, looking for all test and
    // textarea elements that have a "required" property defined.  Then,
    // check for fields that are empty and make a list of them.  Also,
    // if any of these elements have a "min" or a "max" property defined,
    // verify that if they are numbers they are in the right range, or if
    // they are strings that their lengths are within the right range.
    // Catenate an error message string for fields that are wrong.
    for (var i = 0; i < f.length; i++) {
        var e = f.elements[i];
	var fname = fldname(e);
        if (e.type == "text" || e.type == "textarea") {
            // first check for empty field
	    if (e.value == null || e.valolue == "" || isblank(e.value)) {
		if (e.required)		//report error if it can't be empty
		    empty_fields += fname +" must include a value, even if that value is zero\n";
		    if(fname == "Family Members in College" || fname == "Family Size") {empty_fields = fname +" must include a value that is greater than or equal to " + e.min + " and " + " that is less than or equal to " + c(e.max) + "\n";}
		    else if(fname == "Number of Parents") {empty_fields = fname +" must be either 1 or 2.\n";}
		    else if(fname == "Parent Adjusted Gross Income") {empty_fields = fname +" must be greater than zero.\n";}
                continue;		//proceed regardless
        }
	    if (e.Number_parents) {
                var v = parseFloat(e.value);
                if (isNaN(v) || (e.min != null && v < e.min) || (e.max != null && v > e.max)) {
                    errors += fname + " must be either 1 or 2\n";
		}
        } else if (e.numeric && (e.min != null || e.max != null)) { 
                var v = parseFloat(e.value);
                if (isNaN(v) || (e.min != null && v < e.min) || 
			(e.max != null && v > e.max)) {
                    errors += fname + " must be a number";
                    if (e.min != null) 
                        errors += " that is greater than or equal to " + e.min;
                    if (e.max != null && e.min != null) 
                        errors += " and less than or equal to " + c(e.max);
                    else if (e.max != null)
                        errors += " that is less than or equal to " + c(e.max);
                    errors += ".\n";
		      }
        } else if (!e.numeric && (e.min != null || e.max != null)) { 
			if (e.min != null && e.value.length < e.min) {
	                    errors += fname + " must be at least "
				+ e.min + " characters long.\n";
			} else if (e.max != null && e.value.length > e.max) {
	                    errors += fname + " must be no more than "
				+ e.max + " characters long.\n";
			}
	    } else if (e.bdate) {
			if (checkbdate(e) == false) {
			   errors += fname + " is invalid - " + errmsg + ".\n";
			} 
	    } else if (e.anydate) {
			if (checkdate(e) == false) {
			   errors += fname + " is invalid - " + errmsg + ".\n";
			} 
	    } else if (e.email) {
			if (checkemail(e) == false) {
			    errors += fname + " is invalid.\n";
			}
	    }
	}//end text check
    }//end loop   

    // Include "errors2" string in check, which contains cross-field
    //    error messages from other product-specific validation functions.
    errors += errors2;

    // Now, if there were any errors, display the messages, and
    //    return false to prevent the form from being submitted. 
    // Otherwise, print warnings2 string (if non-null) and return true.
    if (!empty_fields && !errors) {
	if (warnings2)
	    alert("WARNING:\n\n"
		+ "Your data will be processed, but the following items may\n"
		+ "impact your results:\n\n"
		+ warnings2);
    	return true;
    }
    msg = "Please correct the following error(s) and re-submit:\n\n";

    if (empty_fields) {
        msg += empty_fields;
        if (errors) msg += "\n";
    }
    msg += errors;
    if (warnings2)
	msg += "\nWarning:\n" + warnings2;
    alert(msg);
    return false;
}  //verify


//////////////////////////////////////////////////////////////////////////////


    //Get a value for a subscripted form element
    //Note:  Since JavaScript cannot handle "<INPUT NAME=myfield[1] ...>"
    //	explicitly (you cannot reference myfield[1] in JS validation code),
    //	we have to write a get() & set() function pair to access the fields
    //	using the document.forms[0].elements[] array
    //Usage:
    //	x = getaval("myfield",1)	--retrieves myfield[1].value
    //	setaval("myfield",1,0);		--sets it to 0
function getaval (f, ndx) {
    var i, s;
    s = f + "[" + ndx + "]";
    for (i=0; i<document.forms[0].elements.length; ++i) {
	if (document.forms[0].elements[i].name == s) {
	    if (document.forms[0].elements[i].type == "select-one")
		return getselectval(document.forms[0].elements[i]);
	    else
		return document.forms[0].elements[i].value;
	}
    }
    return null;
}

    //Note:  Will not work as is for a SELECT field
    //  (val would need to be select index value, & would need loop to look
    //  for that value & set .selected attribute)
function setaval (f, ndx, val) {
    var i, s;
    s = f + "[" + ndx + "]";
    for (i=0; i<document.forms[0].elements.length; ++i) {
	if (document.forms[0].elements[i].name == s) {
	    document.forms[0].elements[i].value = val;
	    return true;
	}
    }
    return false;
}

    //Add commas to a number
function c(n) {
    var arr = new Array('0');
    for (var i=0; n>0; i++) {
	arr[i] = '' + n%1000;
	n = Math.floor(n/1000);
    }
    arr = arr.reverse();
    for (var i in arr)
	if (i>0)	//padding zeros
	    while (arr[i].length < 3)
		arr[i] = '0' + arr[i];
    return arr.join();
}  //c
