// FV Validation Engine - PJF
//see https://iws.riskmetrics.com/twiki/bin/view/Main/UltimateFormValidation for details

var fv_debug=0;
var fv_value;
var _fv_errors;

function _fv_value(field) {
    if (typeof field=='string') {
	field = _fv_form.elements[field];
	if (!field.name) {
	    field = field[_fv_fld_cur[_fv_curfield.name]-1];
	}
    }
    return field.value;
}

function fv_sum(group,expr,msg,rnd) {
    var sum=0;
    if (_fv_groups[group]) {
	for (var p in _fv_groups[group]) {
	    sum += parseFloat(_fv_groups[group][p]) || 0;
	}
    } else {
	var f = _fv_form.elements[group];
	if (f) {
	    if (!f.name) {
		for (var i=0;i<f.length;i++) {
		    sum += parseFloat(f[i].value) || 0;
		}
	    } else {
		sum=parseFloat(f.value) | 0;
	    }
	}
    }

    if (!isNaN(rnd)) sum=sum.toFixed(rnd);
    try {
	var f=Function('sum',expr);
	ret=f(sum);
    } catch(e) {
	if (fv_debug) {
	    alert('eval failed: ' + e.message);
	    ret=true;
	}
    };
    if (ret==false) {
	if (msg) _fv_errors.push([msg]);
	return false;
    }
    return true;
}

function _fv_name(field) {
    if (typeof field=='string') {
	field = _fv_form.elements[field];
	if (!field.name) {
	    field = field[0];
	}
    }
    return field.fullname || field.name;
}

function _fv_field(field) {
    if (typeof field=='string') {
	field = _fv_form.elements[field];
	if (!field.name) {
	    field = field[0];
	}
    }
    return field;
}

function _fv_error(field,str,sub,etype) {
/*    if (field.type.toUpperCase()!='HIDDEN') {
      try {
	if (sub) {
	    field[sub].focus();
	} else {
	    field.focus();
	}
      } catch (e) {
      };
      }*/
    var estr = field['error_' + etype];
    return [field.errorstring || estr || str,field];
}

var _fv_last_x=0;
var _fv_last_y=0;

function _fv_beginDrag(e,event) {
    var dX = event.clientX-(parseInt(e.currentStyle.left) || event.clientX);
    var dY = event.clientY-(parseInt(e.currentStyle.top) || event.clientY);

    document.attachEvent("onmousemove",moveHandler);
    document.attachEvent("onmouseup",upHandler);
    event.cancelBubble=true;
    event.returnValue=false;

    function moveHandler(ev) {
	if (!ev) e=window.event;
	e.style.left=(ev.clientX-dX) + "px";
	e.style.top=(ev.clientY-dY) + "px";
	_fv_last_x = e.clientX-dX;
	_fv_last_y = e.clientY-dY;
    }

    function upHandler(ev) {
	if (!ev) ev=window.event;
	document.detachEvent("onmousemove",moveHandler);
	document.detachEvent("onmouseup",upHandler);
	e.cancelBubble=true;
    }
}

var _fv_cur_error;
var _fv_errorlist;

function _fv_close_errors() {
  var win = document.getElementById('_fv_error_win');
  if (win) {
    for (var i=0;i<_fv_errorlist.length;i++) {
      var v = _fv_errorlist[i][1];
      if (v) {
	v.style.borderColor='activeborder';
	v.title=_fv_errorlist[i][2];
      }
    }
    if (_fv_cur_error) {
	_fv_cur_error.style.background='white';
    }
    win.removeNode(true);
  }
}

var MillisecondsInDay=1000*60*60*24;

function _fv_show_errors(errors,form) {
  _fv_errorlist=errors;
  if (_fv_cur_error) {
    _fv_cur_error.style.background='white';
  }

  var old = document.getElementById('_fv_error_win');
  if (old) {old.removeNode(true);}

  var d=document.createElement('div');
  d.style.width='200px';
  d.style.position='absolute';
  d.style.display='none';
  d.style.top='5px';
  d.style.left=(document.body.offsetWidth-220)+'px';
  d.style.background='white';
//    d.style.top=(document.body.scrollTop || 5) + 'px';
//    d.style.left=(_fv_last_x || (document.body.offsetWidth-220))+'px';
  d.style.border='3px ridge #f3f3f3';
  d.id='_fv_error_win';

  var div=document.createElement('div');
  div.style.background='#d3d3d3';
  div.style.padding='2px';
  div.style.border='2px solid gray';
  div.style.fontWeight=800;
  div.style.width='100%';
  div.innerHTML='<table width=100%><tr><td width=100% style="cursor: move;" onMouseDown="_fv_beginDrag(document.getElementById(\'_fv_error_win\'),window.event)"><span class="message">Errors</span></td><td align=right><input type="button" value="close" onClick="_fv_close_errors()"></td></tr></table>';

  d.appendChild(div);



  var divl=document.createElement('div');
  divl.style.background='white';
  divl.overflow='scrolled';

  if (form && form.onErrorString) {
    errors.unshift([form.onErrorString]);
  }

  for (var i=0;i<errors.length;i++) {
    var div = document.createElement('div');
    div.style.background= i % 2 ? '#f3f3f3' : '#e3e3e3';
    div.style.border='2px solid white';
    div.className="text";
    div.innerHTML="<b>" + (i+1) + ".</b>&nbsp;&nbsp;" + errors[i][0];

    if (errors[i][1]) {
      div.focfield=errors[i][1];
      errors[i][1].style.borderColor='red';

      errors[i][2]=errors[i][1].title;
      var str = errors[i][0];
      str=str.replace(/<[^>]*>/g,'');
      errors[i][1].title=str;
      div.style.cursor='hand';
      div.onclick=function (evt) {
	evt = (evt) ? evt : ((window.event) ? window.event : null);
	var elem = (evt.target) ? evt.target : evt.srcElement;

	// Netscape fires on the text in the div, in this case get the
	// parent of the text (ie the div).
	if (elem.nodeType != 1) {
	  elem = elem.parentNode;
	}
	if (_fv_cur_error) {
	  _fv_cur_error.style.background='white';
	}
	elem.focfield.style.background='#A5DFAD';
	try {
	  elem.focfield.focus();
	  elem.focfield.select();
	} catch(e) {
	};
	_fv_cur_error=elem.focfield;
      }
      }
    divl.appendChild(div);
  }
  d.appendChild(divl);
  document.body.appendChild(d);
  var t = document.documentElement.scrollTop || document.body.scrollTop;
  if (t) t+= 5;
  d.style.top=(t || 5) + 'px';
  d.style.left=(_fv_last_x || (document.body.offsetWidth-220))+'px';
  document.body._fv_errwin = d;
  window.onscroll=function() {
    var d = document.body._fv_errwin;
  var t = document.documentElement.scrollTop || document.body.scrollTop;
  if (t) t+= 5;
  d.style.top=(t || 5) + 'px';
    d.style.left=(document.body.offsetWidth-220)+'px';
  }

  document.body.onresize=function() {
    var d = document.body._fv_errwin;
  var t = document.documentElement.scrollTop || document.body.scrollTop;
  if (t) t+= 5;
  d.style.top=(t || 5) + 'px';
    d.style.left=(document.body.offsetWidth-220)+'px';
  }

  d.style.display='block';
}

// should add more here
var _fv_charmap = {
  ',': 'commas',
  ' ': 'spaces',
  "'": 'apostrophes',
  ".": 'periods',
  "_": 'underscores',
  "-": 'dashes',
  "&": 'ampersands'
};

function _fv_nicelist(list,add) {
  var str;

  if (list.length==1) {
    return (add ? " or " : "") + list[0];
  }
  return (add ? ", " : "") + list.slice(0,list.length-1).join(", ") + " or " + list[list.length-1];

}

function _fv_charlist(str) {

  if (!str) return '';
  var list=[];
  for (var i=0;i<str.length;i++) {
    var ch = str.substr(i,1);
    if (ch=='\\') continue;
     list.push(_fv_charmap[ch] || ("'" +ch + "'"));
  }
  list = list.sort();
  if (list.length) return _fv_nicelist(list,true);
  return '';
}

function _fv_validatetype(field,value) {
    switch (field.datatype) {
    case 'alphanum':
    	var re = new RegExp('^[/. A-Za-z0-9' + (field.additionalchars || '') + ']+$');
    	if (!value.match(re)) {
    	    return _fv_error(field,_fv_name(field) + " must consist of letters, digits" + _fv_charlist(field.additionalchars) + ".");
    	}
    	break;
    case 'number':
	var re = /^[+-]?(\.\d+|\d+(\.\d+)?)$/;
	if (!value.match(re)) {
	    return _fv_error(field,_fv_name(field) + " must be numeric. (No symbols)");
	}
	if (field.minvalue!=null && parseFloat(value) < field.minvalue) {
	    return _fv_error(field,_fv_name(field) + ' must be at least ' + (parseFloat(field.minvalue)) + '.',null,'minvalue');
	}
	if (field.maxvalue!=null && parseFloat(value) > field.maxvalue) {
	  return _fv_error(field,_fv_name(field) + ' must be at most ' + (parseFloat(field.maxvalue)) + '.',null,'maxvalue');
	}
	break;
    case 'integer':
	var re = /^[+-]?\d+$/;
	if (!value.match(re)) {
	    return _fv_error(field,_fv_name(field) + " must be an integer.");
	}
	if (field.minvalue!=null && parseInt(value) < field.minvalue) {
	    return _fv_error(field,_fv_name(field) + ' must be at least ' + (parseInt(field.minvalue)) + '.',null,'minvalue');
	}
	if (field.maxvalue!=null && parseInt(value) > field.maxvalue) {
	    return _fv_error(field,_fv_name(field) + ' must be at most ' + (parseInt(field.maxvalue)) + '.',null,'maxvalue');
	}
	break;
    case 'percent':
	var re = field.intpct ? /^([+-]?\d+)%?$/: /^([+-]?(\.\d+|\d+(\.\d+)?))%?$/;
	if (!value.match(re)) {
	    return _fv_error(field,_fv_name(field) + " must be a percentage.");
	}
	var value1=RegExp.$1;
	if (value != value1) {field.value=value1;}
	if (field.minvalue!=null && parseFloat(value1) < parseFloat(field.minvalue)) {
	  return _fv_error(field,_fv_name(field) + ' must be at least ' + field.minvalue + '.');
	}
	if (field.maxvalue!=null && parseFloat(value1) > parseFloat(field.maxvalue)) {
	  return _fv_error(field,_fv_name(field) + ' must be at most ' + field.maxvalue + '.');
	}
	if (field.negpct) {
	    if (parseFloat(value1) < -100) {
		return _fv_error(field,_fv_name(field) + ' must be at least -100%.');
	    }
	    if (parseFloat(value1) > 100) {
		return _fv_error(field,_fv_name(field) + ' must be at most 100%.');
	    }
	} else {
	    if (parseFloat(value1) < 0) {
		return _fv_error(field,_fv_name(field) + ' must be at least 0%.');
	    }
	    if (parseFloat(value1) > 100) {
		return _fv_error(field,_fv_name(field) + ' must be at most 100%.');
	    }
	}
	break;

    case 'amount':
	var re1 = /^\d+$/;
	var re2 = /^\d+\s\d+\/\d+$/;
	var re3 = /^\d+\/\d+$/;
	if (!value.match(re1) && !value.match(re2) && !value.match(re3)) {
	    return _fv_error(field,_fv_name(field) + " must be a fractional number like '1 1/2'  No words or other text are allowed.");
	}
	break;


    case 'recipeAmount':
	//var re = /^[\d\s\/]+$/;
	var re1 = /^\d+$/;
	var re2 = /^\d+\s\d+\/\d+$/;
	var re3 = /^\d+\/\d+$/;
	if (!value.match(re1) && !value.match(re2) && !value.match(re3)) {
	    return _fv_error(field,_fv_name(field) + " must be a fractional number like '1 1/2'  No words or other text are allowed.  If you need to have two measurements (cups/tbsps) enter them on separate lines.");
	}
	break;

    case 'phone':
	var re = /^(1\s*-?\s*)?(\(?\s*\d\d\d\s*\)?[ -]?\s*)?\d\d\d\s*-?\s*\d\d\d(\s*x\s*\d+\s*)?$/;
	if (!value.match(re)) {
	    return _fv_error(field,_fv_name(field) + " must be an phone number.");
	}
	break;
    case 'zipcode':
	var re = /^\d\d\d\d\d(-\d\d\d\d)?$/;
	if (!value.match(re)) {
	    return _fv_error(field,_fv_name(field) + " must be an integer.");
	}
	break;
    case 'year':
      var re=/\d\d\d\d/;
      if (!value.match(re)) {
	return _fv_error(field,_fv_name(field) + " must be a year.");
      }
	if (field.minvalue!=null && parseInt(value) < parseInt(field.minvalue)) {
	    return _fv_error(field,_fv_name(field) + ' must be at least ' + (parseInt(field.minvalue)) + '.');
	}
	if (field.maxvalue!=null && parseInt(value) > parseInt(field.maxvalue)) {
	    return _fv_error(field,_fv_name(field) + ' must be at most ' + (parseInt(field.maxvalue)) + '.');
	}
	if (parseInt(value) < 1900) {
	    return _fv_error(field,_fv_name(field) + ' must be at least 1900');
	}
	if (parseInt(value) > 2200) {
	    return _fv_error(field,_fv_name(field) + ' must be at most 2200.');
	}

      break;

    case 'date':

      if (!chkdate(value)) {
	return _fv_error(field,_fv_name(field) + " must be a valid date.");
      }
	var d = new Date(value);
	var t = new Date();
	d.setHours(0);
	d.setMinutes(0);
	d.setSeconds(0);
	t.setHours(0);
	t.setMinutes(0);
	t.setSeconds(0);
//      var d = Math.floor(new Date(value).valueOf()/MillisecondsInDay);
//      var t = Math.floor(new Date().valueOf()/MillisecondsInDay);
      if (field.past) {
	if (d >= t) {
	  return _fv_error(field,_fv_name(field) + " must be in the past.");
	}
      }
      if (field.future) {
	if (d <= t) {
	  return _fv_error(field,_fv_name(field) + " must be in the future.");
	}
      }

      if (field.notpast) {
	if (d < t) {
	  return _fv_error(field,_fv_name(field) + " must not be in the past.");
	}
      }
      if (field.notfuture) {
	if (d > t) {
	  return _fv_error(field,_fv_name(field) + " must not be in the future.");
	}
      }
      break;
    case 'currency':
	var re = /^\$?([+-]?(\d*(\.\d\d?)?|\d+))$/;
	if (!value.match(re)) {
	    return _fv_error(field,_fv_name(field) + " must be currency.");
	}
	var value1=RegExp.$1;
	if (value != value1) {field.value=value1;}
	if (field.minvalue!=null && parseFloat(value1) < field.minvalue) {
	    return _fv_error(field,_fv_name(field) + ' must be at least ' + field.minvalue + '.');
	}
	if (field.maxvalue!=null && parseFloat(value1) > field.maxvalue) {
	    return _fv_error(field,_fv_name(field) + ' must be at most  ' + field.maxvalue + '.');
	}
	break;
    case 'choices':
	if (!field._fv_choices) {
	    field._fv_choices=field.choices.split(";");
	}
	var match=0;
	for (var j=0;j<field._fv_choices.length;j++) {
	    if (value == field._fv_choices[j]) {
	        match=1;
	        break;
	    }
	}
	if (!match) {
	    return _fv_error(field,_fv_name(field) + "  must be one of " + field._fv_choices.join(", ")  + ".");
	}
	break;
    }
    return null;
}

function _fv_date_compare(d1,d2) {
      var dd1 = d1 ? Math.floor(new Date(d1).valueOf()/MillisecondsInDay) : 0;
      var dd2 = d2 ? Math.floor(new Date(d2).valueOf()/MillisecondsInDay) : 0;
      return dd1-dd2;
}

var _fv_form;
var _fv_fields;
var _fv_groups;
var _fv_rgroups;
var _fv_rgroupflds;
var _fv_curfield;

function _fv_validatefield(field,value) {

  if (field.skipval) return null;

    value = value.replace(/^\s*(.*?)\s*/,"$1");

    if (value==null || value.length==0 || !value.match(/\S/)) {
	if (field.required) {
	    return _fv_error(field,'You must enter a value for ' + (field.fullname || field.name) + '.');
        }
	if (field.requiredif) {
	  var reqif=field.requiredif;
	  var reqifval=null;
	  if (field.requiredif.match(/=/)) {
	    reqif = field.requiredif.split(/=/)[0];
	    reqifval = field.requiredif.split(/=/)[1];
	  }
	  if (_fv_fld_ctr[reqif]>1) {
		var ind=_fv_fld_cur[field.name];
		var val=_fv_form.elements[reqif][ind-1].value;
		if (val && val.length && val.match(/\S/)) {
		  if (reqifval!=null) {
		    if (val == reqifval) {
		      return _fv_error(field,_fv_name(field) + ' must be entered when ' + _fv_name(reqif) + ' is ' + reqifval + '.');
		    }
		  } else {
		    return _fv_error(field,_fv_name(field) + ' must be entered when ' + _fv_name(reqif) + ' is filled in.');
		  }
		}
	    } else {
		var val=_fv_form.elements[reqif].value;
		if (val && val.length && val.match(/\S/)) {
		  if (reqifval!=null) {
		    if (val == reqifval) {
		      return _fv_error(field,_fv_name(field) + ' must be entered when ' + _fv_name(reqif) + ' is ' + reqifval + '.');
		    }
                  } else {
		    return _fv_error(field,_fv_name(field) + ' must be entered when ' + _fv_name(reqif) + ' is filled in.');
		  }
		}
	    }
        }
    } else {
	if (field.disallowedunless) {
	    if (_fv_fld_ctr[field.disallowedunless]>1) {
		var ind=_fv_fld_cur[field.name];
		var val=_fv_form.elements[field.disallowedunless][ind-1].value;
		if (!val || !val.length || !val.match(/\S/)) {
		    return _fv_error(field,_fv_name(field) + ' may not be entered unless ' + _fv_name(field.disallowedunless) + ' is filled in.');
		}
	    } else {
		var val=_fv_form.elements[field.disallowedunless].value;
		if (!val || !val.length || !val.match(/\S/)) {
		  return _fv_error(field,_fv_name(field) + ' may not be entered unless ' + _fv_name(field.disallowedunless) + ' is filled in.');
		}
	    }
        }
	if (field.reqgroup) _fv_rgroups[field.reqgroup]++;
    }

    if (field.datatype && field.value.length) {
    	var ret = _fv_validatetype(field,value);
    	if (ret) {return ret}
    	if (field.minlength) {
    	    if (value.length < field.minlength) {
    		return _fv_error(field,_fv_name(field) + " must be longer than " + (field.minlength-1) + " characters.");
    	    }
    	}
    	if (field.maxlength) {
    	    if (value.length > field.maxlength) {
    		return _fv_error(field,_fv_name(field) + " must be shorter than " + (field.maxlength-1) + " characters.");
    	    }
    	}
    	if (field.nodecimals) {
    	    if (value.match('\\.')) {
        		return _fv_error(field,"Please use fractions like '1 1/2' rather than decimals like '1.5'");
        		return false;
    	    }
    	}    
    	if (field.pattern) {
    	    var p = '^' + field.pattern + '$';
    	    if (!value.match(p)) {
    		return _fv_error(field,field.patternfail || (_fv_name(field) + " is incorrect."));
    		return false;
    	    }
    	}
    }

    if (field.jsvalidation) {
	fv_value = value;
	_fv_curfield = field;
	var ret=true;
	try {
	    ret=eval(field.jsvalidation);
	} catch( e) {
	    if (fv_debug) {
		alert("eval failed: js [" + field.jsvalidation + "]" + e.message);
	    }
	    ret=true;
	};
	if (ret==false) {
	    return _fv_error(field,field.jsvalidationfail || (_fv_name(field) + "  is incorrect."));
	}
    }

    for (var f in field) {
      if (f.match(/^jsvalidation_(\w+)$/)) {
	var val = RegExp.$1;
	var fail = field['jsvalidationfail_' + val];
	var ret=true;
	try {
	  var expr = Function('value',field['jsvalidation_' + val]);

	  ret = expr(value);
	} catch (e) {
	  if (fv_debug) {
	    alert(e.message);
	  }
	};
	if (ret==false) {
	  if (fail.match(/^javascript:(.*)$/)) {
	    try {
	      var ffail = Function('value',RegExp.$1);
	      fail = ffail(value);
	    } catch (e) {
	      if (fv_debug) {
		alert(e.message);
	      }
	    };
	  }
	  return _fv_error(field,fail || field.jsvalidationfail || (_fv_name(field) + "  is incorrect."));
	}
      }
    }

    return null;
}

var _fv_fld_ctr;
var _fv_fld_cur;

function _fv_exists(v) {
  return v!= null && v.length;
}

function _fv_grpnames(list) {
    var list2=[]
    for (var i=0;i<list.length;i++) {
	list2[i] = _fv_name(list[i]);
    }
    return list2;
}

function fv_validate(form) {

  _fv_close_errors();
  form = _fv_form = form || document.forms[0];

  _fv_errors=[];

  _fv_fields=[];
  _fv_rgroups=[];
  _fv_rgroupflds=[];
  _fv_groups=[];
  _fv_fld_ctr={};
  _fv_fld_cur={};

  var fldinfo={};
  for (var i=0;i<form.elements.length;i++) {
    var field = form.elements[i];

    if (_fv_fld_ctr[field.name]==null) {
	_fv_fld_ctr[field.name]=1;
    } else {
	_fv_fld_ctr[field.name]++;
    }
  }
  for (var i=0;i<form.elements.length;i++) {
    var field = form.elements[i];

    if (_fv_fld_cur[field.name]==null) {
	_fv_fld_cur[field.name]=1;
    } else {
	_fv_fld_cur[field.name]++;
    }
    if (_fv_fields[field.name]) {
      if (_fv_fields[field] instanceof Array) {
        _fv_fields[field.name].push(field.value);
      } else {
        _fv_fields[field.name]=[_fv_fields[field.name],field.value];
      }
    } else {
      _fv_fields[field.name]=field.value;
    }
    if (field.reqgroup) {
	if (_fv_rgroups[field.reqgroup]==null) {
           _fv_rgroups[field.reqgroup]=0;
           _fv_rgroupflds[field.reqgroup]=[];
        }
        _fv_rgroupflds[field.reqgroup].push(field.name);
    }

    if (field.groups) {
      var grps=field.groups.split(/,/);
      for (var j=0;j<grps.length;j++) {
        if (_fv_groups[grps[j]]==null) {
           _fv_groups[grps[j]]={};
        }
        _fv_groups[grps[j]][field.name]=field.value;
      }
    }
    var ret=_fv_validatefield(field,field.value);
    if (ret) _fv_errors.push(ret);
  }

  for (var g in _fv_rgroups) {
    if (!_fv_rgroups[g]) {
      _fv_errors.push(["One or more of " + _fv_grpnames(_fv_rgroupflds[g]).join(", ") + " must be filled in.",_fv_field(_fv_rgroupflds[g][0])]);
    }
  }

  if (_fv_errors.length) {
     _fv_show_errors(_fv_errors,form);
     return false;
  }

  var err=false;
  if (form.jsvalidation) {
    var ret=true;
    try {
      var f= Function('fields','groups',form.jsvalidation);
      ret=f(_fv_fields,_fv_groups);
    } catch(e) {
	if (fv_debug) {
	  alert("form eval failed: " + e.message);
	}
	ret=true;
    };
    if (ret==false) {
	if (form.jsvalidationfail) {_fv_errors.push([form.jsvalidationfail])}
        err=true;
    }
  }

  if (form.aggregateval) {
    var ret=true;
    try {
      var f=Function(form.aggregateval);
      ret=f();
    } catch(e) {
	if (fv_debug) {
	  alert("form eval failed: " + e.message);
	}
	ret=true;
    };
    if (ret==false) {
        err=true;
    }
  }

  if (_fv_errors.length) {
     _fv_show_errors(_fv_errors,form);
     return false;
  }
  return !err;
}

function fv_submit(form) {
  form = form || document.forms[0];
  if (fv_validate(form)) {
     form.submit();
  }
  disableButtons = false;
  return false;
}

var _fv_init_alerts=[];

function _fv_set_init_errors() {
  if (_fv_init_alerts.length) {
    var errors=[];
    for (var i=0;i<_fv_init_alerts.length;i++) {
      var e = _fv_init_alerts[i];

      if (e[1]) {
	var fld;
	for (var j=0;j<document.forms.length;j++) {
	  var done=0;
	  for (var k=0;k<document.forms[j].elements.length;k++) {
	    if (document.forms[j].elements[k].name==e[1]) {
	      fld=document.forms[j].elements[k];
	      done=1;
	      break;
	    }
	  }
	  if (done==1) break;
	}
	errors.push([e[0],fld]);
      } else {
	errors.push([e[0]]);
      }
    }
    _fv_show_errors(errors);
  }
}

fv_debug=1;
// END of FV
