var years = '2004:2005:2006:2007:2008';
var selparam = '';
var alertct = 0;
var micro = '<font face="Symbol">m</font>';
var seldata = new Array();

function dumpprops(obj, parent, recursion) {
	if (recursion <= 0)
		return('');
	var msg = '';

	if (parent)
		msg = 'Properties of ' + parent + '<p>\n';
	else
		msg = 'Properties<p>\n';
	for (var i in obj) {
		if (parent) { 
			msg += '<b>' + parent + '.' + i + '</b> (' + recursion + ')<br>\n' + obj[i] + '<p>\n'; 
		} else { 
			msg += '<b>' + i + '</b> (' + recursion + ')<br>\n' + obj[i] + '<p>\n'; 
		}
		if (typeof obj[i] == 'object') {
			if (parent) {
				msg += dumpprops(obj[i], parent + '.' + i, recursion - 1); 
			} else { 
				msg += dumpprops(obj[i], i, recursion - 1); 
			}
		}
	}

	return(msg);
}

function listformfields(form, field) {
	answer = '';
	eval ('myelements = document.' + form + '.elements');
	for (var i = 0; i<myelements.length; i++) {
		if (myelements[i].name == 'answer') {
			answer += 'skipped textarea field: \'answer\'\n';
			continue;
		}
		answer += myelements[i].type;
		if (myelements[i].type == 'text' || myelements[i].type == 'textarea' || myelements[i].type == 'button' || myelements[i].type == 'submit' || 
			myelements[i].type == 'reset' || myelements[i].type == 'password' || myelements[i].type == 'hidden' || myelements[i].type == 'file') {
			answer += ': \'' + myelements[i].name + '\' value: \'' + myelements[i].value + '\'\n';
		}
		if (myelements[i].type == 'select-one' || myelements[i].type == 'select-multiple') {
			answer += ': \'' + myelements[i].name + '\'\n';
			for (var j = 0; j < myelements[i].length; j++) {
				answer += '   option: \'' + myelements[i].options[j].value + '\'';
				if (myelements[i].options[j].selected) {
					answer += ' selected';
				}
				answer += '\n';
			}
		}
		if (myelements[i].type == 'radio') {
			answer += ': \'' + myelements[i].name + '\' option: \'' + myelements[i].value + '\'';
			if (myelements[i].checked) {
				answer += ' checked';
			}
			answer += '\n';
		}
		if (myelements[i].type == 'checkbox') {
			answer += ': \'' + myelements[i].name + '\' option: \'' + myelements[i].value + '\'';
			if (myelements[i].checked) {
				answer += ' checked';
			}
			answer += '\n';
		}
	}
	eval ('document.' + form + '.' + field + '.value = answer');
}

function OpenWindow(script, param, height, width) {
	window.open(script + param,'openWindow','scrollbars=yes,resizable=yes,status=yes,left=200,top=100,width=' + width + ',height=' + height);
	return false;
}

function OpenHelpWindow(script, param, height, width) {
	window.open(script + param,'HelpWindow','scrollbars=yes,resizable=yes,menubar=0,status=yes,left=200,top=100,width=' + width + ',height=' + height);
	return false;
}

function Confirm_delete(type) {
	return(confirm('Are you sure that you want to delete this ' + type + ' ?'));
}

if(document.all && !document.getElementById) {
	document.getElementById = function(id) {
		return document.all[id];
	}
} 

function fill_string(form, fld, type, options, editp, cssclass, onchange) {
	loptions = options.replace(/\|/g, "','");
	eval("var options_arr = new Array('" + loptions + "')");
	var lvalue = '';
	var v = 0;
	if (type == 'checkbox') {
// alert('fill_string ' + fld + ' ' + options + ' ' + editp);
		for (c=flag=0; c < options_arr.length; c++) {
			var opt_arr = options_arr[c].split('=');
			eval ('var cellname = document.' + form + '.' + fld + '_' + opt_arr[0]);
			if (!cellname) {
				alert('Failed to update field ' + fld + '.\nPlease save data or reload the page');
				return (-1);
			}
			if (cellname.checked) {
				if (lvalue)
					lvalue = lvalue + '|';
				lvalue = lvalue + cellname.value;
			}
		}
	} else if (type == 'multiple_select') {
		for (v = 0; ; v++) {
			eval ('var cellname = document.' + form + '.' + fld + '_' + v);
			if (!cellname)
				break;
// alert('fill_string ' + fld + ' ' + cellname.value);
			if (lvalue)
				lvalue = lvalue + '|';
			lvalue = lvalue + cellname.value;
		}
	} else if (type == 'options') {
		for (v = 0; ; v++) {
			eval ('var cellopt = document.' + form + '.' + fld + '_opt_' + v);
			eval ('var celldesc = document.' + form + '.' + fld + '_desc_' + v);
			if (!cellopt)
				break;
//			if (v && !cellopt.value)
//				continue;
// alert("'" + cellopt.value + "'");
// alert('fill_string ' + fld + ' ' + cellopt.value);
			if (lvalue)
				lvalue = lvalue + '|';
			lvalue = lvalue + cellopt.value + '=' + celldesc.value;
		}
// alert(lvalue);
	} else if (type == 'radio') {
// alert('fill_string ' + fld + ' ' + options + ' ' + editp);
		for (c=flag=0; c < options_arr.length; c++) {
			var opt_arr = options_arr[c].split('=');
			eval ('var cellname = document.' + form + '.' + fld + '[' + c + ']');
			if (!cellname) {
				alert('Failed to update field ' + fld + '.\nPlease save data or reload the page');
				return (-1);
			}
			if (cellname.checked) {
				lvalue = cellname.value;
			}
// alert(fld + '[' + c + ']' + ' ' + cellname.checked + ' ' + cellname.value);
		}
	} else if (type == 'date') {
		eval ('var yearcell = document.' + form + '.' + fld + '_year');
		eval ('var monthcell = document.' + form + '.' + fld + '_month');
		eval ('var daycell = document.' + form + '.' + fld + '_day');
		if (yearcell.value || monthcell.value || daycell.value)
			lvalue = yearcell.value + '/' + monthcell.value + '/' + daycell.value;
		else
			lvalue = '';
	} else {
		eval ('var cellname = document.' + form + '.' + fld);
		if (!cellname) {
			alert('Failed to update field ' + fld + '.\nPlease save data or reload the page');
			return (-1);
		}
		lvalue = cellname.value;
// alert(lvalue);
	}

	reset_string(form, fld, lvalue, type, options, editp, cssclass, onchange);

	return(0);
}

function fill_form(form, fld, type, options, editp, cssclass, onchange) {
// alert('fill_form ' + form + ', ' + fld + ', type ' + type + ', options ' + options + ', editp ' + editp + ', cssclass ' + cssclass + ', onchange ' + onchange);
	restore_cell();

	eval ("mydiv = document.getElementById('div_" + fld + "')");

	if (!mydiv) {
		if (++alertct < 5)
			alert('failed to access field ' + fld);
		return;
	}

	if (type != 'checkbox' && type != 'date' && type != 'multiple_select' && type != 'options') {
		eval ('cellname = document.' + form + '.' + fld);
		if (!cellname) {
			alert('Failed to update field ' + fld + '.\nPlease save data or reload the page');
			return;
		}
		if (type != 'textarea')
			cellname.value = cellname.value.replace(/"/g, "&quot;");
	}

	loptions = options.replace(/\|/g, "','");
	eval("var options_arr = new Array('" + loptions + "')");

	var output = '';
	var v = 0;
	if (onchange)
		onchange = 'onChange="' + onchange + '"';

	if (type == 'text')
		output = '<input name="' + fld + '" value="' + cellname.value + '" size=30 style="width:250;" class="' + cssclass + '" ' + onchange + ' type="text"> ';
	else if (type == 'password')
		output = '<input name="' + fld + '" value="' + cellname.value + '" size=30 style="width:250;" class="' + cssclass + '" ' + onchange + ' type="password"> ';
	else if (type == 'textarea')
		output = '<textarea name="' + fld + '" cols=80 rows=10 ' + onchange + ' class="' + cssclass + '">' + cellname.value + '</textarea>';
	else if (type == 'select') {
// alert('fill_form ' + form + ', ' + fld + ', type ' + type + ', options ' + options + ', editp ' + editp + ', cssclass ' + cssclass + ', onchange ' + onchange);
		output = '<select class=item ' + onchange + ' name="' + fld + '">';
		for (c=0; c < options_arr.length; c++) {
			opt_arr = options_arr[c].split('=');
			if (!opt_arr[1])
				opt_arr[1] = opt_arr[0];
			if (cellname.value == opt_arr[0])
				selected = 'selected';
			else
				selected = '';
			output += '<option ' + selected + ' value="' + opt_arr[0] + '">' + opt_arr[1] + '</option>\n';
		}
		output += '</select>';
	} else if (type == 'multiple_select') {
		for (v = 0; ; v++) {
			eval ('var cellname = document.' + form + '.' + fld + '_' + v);
			if (!cellname)
				break;
			output += '<select class="' + cssclass + '" ' + onchange + ' name="' + fld + '_' + v + '">';
// alert(fld + ' ' + cellname.value);
			for (c=0; c < options_arr.length; c++) {
				opt_arr = options_arr[c].split('=');
				if (!opt_arr[1])
					opt_arr[1] = opt_arr[0];
				if (cellname.value == opt_arr[0])
					selected = 'selected';
				else
					selected = '';
				output += '<option ' + selected + ' value="' + opt_arr[0] + '">' + opt_arr[1] + '</option>\n';
			}
			output += '</select>';
		}
	} else if (type == 'options') {
		var nopt = 0;
		for (v = 0; ; v++) {
			eval ('var cellopt = document.' + form + '.' + fld + '_opt_' + v);
			eval ('var celldesc = document.' + form + '.' + fld + '_desc_' + v);
			if (!cellopt)
				break;
			if (!cellopt.value && v && nopt)
				break;
			output += '<input class="' + cssclass + '" ' + onchange + ' size=5 name="' + fld + '_opt_' + v + '" value="' + cellopt.value + '"> ';
			output += '<input class="' + cssclass + '" ' + onchange + ' size=20 name="' + fld + '_desc_' + v + '" value="' + celldesc.value + '">';
			output += '<br>';
			if (cellopt.value)
				nopt = 0;
			else
				nopt++;
// alert(fld + ' ' + cellname.value);
		}

		output += '<input class="' + cssclass + '" ' + onchange + ' size=5 name="' + fld + '_opt_' + v + '" value=""> ';
		output += '<input class="' + cssclass + '" ' + onchange + ' size=20 name="' + fld + '_desc_' + v + '" value="">';
		output += '<br>';
	} else if (type == 'checkbox') {
		for (c=0; c < options_arr.length; c++) {
			var opt_arr = options_arr[c].split('=');
			if (!opt_arr[1]) opt_arr[1] = opt_arr[0];
			eval ('var cellname = document.' + form + '.' + fld + '_' + opt_arr[0]);
			if (cellname.checked)
				checked = 'checked';
			else
				checked = '';
// alert(cellname.value + ' --- ' + opt_arr[0] + ' --- ' + cellname.checked);
			output += opt_arr[1] + '<input type="checkbox" ' + checked + ' value="' + opt_arr[0] + '" class="' + cssclass + '" onClick="' + onchange + '" name="' + fld + '_' + opt_arr[0] + '"><br>\n';
		}
// alert(output);
	} else if (type == 'radio') {
		var focus_on = 0;
		for (c=0; c < options_arr.length; c++) {
			var opt_arr = options_arr[c].split('=');
			if (!opt_arr[1]) opt_arr[1] = opt_arr[0];
// eval ('var tmp = document.' + form + '.' + fld + '[' + c + ']');
// alert('document.' + form + '.' + fld + '[' + c + ']' + ': ' + tmp);
// alert(options + ' ' + fld + ' ' + cellname + ' ' + cellname.value);
			if (cellname.value == opt_arr[0]) {
				checked = 'checked';
				var focus_on = c;
			} else
				checked = '';
// alert('document.' + form + '.' + fld + '.value' + ': ' + cellname.value + ' - ' + opt_arr[0] + ' - ' + checked);
			output += opt_arr[1] + '<input type="radio" ' + checked + ' value="' + opt_arr[0] + '" class="' + cssclass + '" onClick="' + onchange + '" name="' + fld + '">\n';
		}
// alert(output);
	} else if (type == 'date') {
		yearopts = years.split(':');
		eval ('var cellname = document.' + form + '.' + fld + '_year');
		output = '<select class="' + cssclass + '" ' + onchange + ' name="' + fld + '_year"><option></option>';
		for (c=0; c < yearopts.length; c++) {
			if (yearopts[c] == cellname.value) 
				selected = 'selected'; 
			else
				selected = '';
			output += '<option value="' + yearopts[c] + '" name="' + fld + '_year" ' + selected + '>' + yearopts[c] + '</option>\n';
		}
		output += '</select>';
		eval ('var cellname = document.' + form + '.' + fld + '_month');
		output += '<select class="' + cssclass + '" ' + onchange + ' name="' + fld + '_month"><option></option>';
		for (c=1; c <= 12; c++) {
			if (c == cellname.value) 
				selected = 'selected';
			else
				selected = '';
			c = String(c);
			cform = c.replace(/\b(\d)\b/g, '0$1');
			output += '<option value="' + cform + '" name="' + fld + '_month" ' + selected + '>' + cform + '</option>\n';
		}
		output += '</select>';
		eval ('var cellname = document.' + form + '.' + fld + '_day');
		output += '<select class="' + cssclass + '" ' + onchange + ' name="' + fld + '_day"><option></option>';
		for (c=1; c <= 31; c++) {
			if (c == cellname.value)
				selected = 'selected';
			else
				selected = '';
			c = String(c);
			cform = c.replace(/\b(\d)\b/g, '0$1');
			output += '<option value="' + cform + '" name="' + fld + '_day" ' + selected + '>' + cform + '</option>\n';
		}
		output += '</select>';
	}

	output = output + '<input type="reset" class="' + cssclass + '" onClick="restore_cell(); return false" value="restore">';
	mydiv.innerHTML = output;
// alert(output);

	if (type == 'text' || type == 'textarea' || type == 'select')
		eval ('document.' + form + '.' + fld + '.focus()');
	else if (type == 'multiple_select')
		eval ('document.' + form + '.' + fld + '_0.focus()');
	else if (type == 'radio')
		eval ('document.' + form + '.' + fld + '[' + focus_on + '].focus()');
	else if (type == 'date')
		eval ('document.' + form + '.' + fld + '_year.focus()');

	seldata = new Array(form, fld, type, options, editp, cssclass, onchange);
}

function restore_cell() {
// alert('restore_cell ' + seldata[0] + ', ' + seldata[1] + ', type ' + seldata[2] + ', options ' + seldata[3] + ', editp ' + seldata[4] + ', onchange ' + seldata[5]);
	if (seldata[0]) {
		fill_string(seldata[0], seldata[1], seldata[2], seldata[3], seldata[4], seldata[5], seldata[6]);
		seldata[0] = "";
	}
}

function reset_string(form, fld, value, type, options, editp, cssclass, onchange) {
	var output = '';
	eval ("mydiv = document.getElementById('div_" + fld + "')");

	if (!mydiv) {
		if (++alertct < 5)
			alert('failed to access div box div_' + fld);
		return;
	}

	if (type == 'file') {
		mydiv.innerHTML = 'new file: <input name="' + fld + '" type="file" value="' + value + '" size=30 style="width:250;" class="' + cssclass + '" ' + onchange + '> ';
		return;
	}

	if (editp)
		output = "<a href=\"javascript:void(0)\" onClick=\"fill_form('" + form + "', '" + fld + "', '" + type + "', '" + options + "', '" + editp + "', '" + cssclass + "', '" + onchange + "'); return(false)\">";

	loptions = options.replace(/\|/g, "','");
	eval("var options_arr = new Array('" + loptions + "')");

	if (type == 'checkbox') {
// alert(fld + ': ' + options + ' - ' + loptions);
		var evalme = '';
		for (c=flag=0; c < options_arr.length; c++) {
			var opt_arr = options_arr[c].split('=');
			if (!opt_arr[1]) opt_arr[1] = opt_arr[0];
// alert('reset_string: ' + value + ' - ' + opt_arr[0]);
			if (value.match("(^|\\|)" + opt_arr[0] + "(\\||$)")) {
				checked = 'checked';
				lvalue = opt_arr[0];
			} else {
				checked = '';
				lvalue = '';
			}
			if (checked) {
				if (flag)
					output += ',<br>';
				output += opt_arr[1];
				flag = 1;
			}
			output += '<input type="checkbox" ' + checked + ' value="' + lvalue + '" name="' + fld + '_' + opt_arr[0] + '">';
			evalme = evalme + "document." + form + "." + fld + "_" + opt_arr[0] + ".style.display = 'none'; ";
		}
		if (!flag && editp)
			output += 'edit';
// alert('reset_string: ' + output);

	} else if (type == 'select') {
// alert('reset_string ' + form + ', ' + fld + ', value ' + value + ', type ' + type + ', options ' + options + ', editp ' + editp + ', onchange ' + onchange);
		for (c=flag=0; c < options_arr.length; c++) {
			var opt_arr = options_arr[c].split('=');
			if (!opt_arr[1]) opt_arr[1] = opt_arr[0];
			if (value == opt_arr[0]) {
				if (opt_arr[1])
					lvalue = opt_arr[1];
				else
					if (editp) lvalue = 'edit'; else lvalue = '&nbsp;';
				output += lvalue;
				flag = 1;
				break;
			}
		}
		if (!flag && editp)
			output += 'edit';
		output += '<input name="' + fld + '" value="' + value + '" type="hidden">';
// alert('reset_string: ' + output);

	} else if (type == 'radio') {
		for (c=flag=0; c < options_arr.length; c++) {
			var opt_arr = options_arr[c].split('=');
			if (!opt_arr[1]) opt_arr[1] = opt_arr[0];
			if (value == opt_arr[0]) {
				if (opt_arr[1])
					lvalue = opt_arr[1];
				else
					if (editp) lvalue = 'edit'; else lvalue = '$nbsp;';
				output += lvalue;
				flag = 1;
				break;
			}
		}

		if (!flag && editp)
			output += 'edit';

		output += '<input name="' + fld + '" value="' + value + '" type="hidden">';
// alert(fld + ', ' + value + ', ' + type + ', ' + options + ', ' + editp + ', ' + output);

	} else if (type == 'multiple_select') {
// alert(value + ' ' + editp);
		var val_arr = value.split('|');
		var liststart = 1;
		var listend = 0;
		var lvalue;
		for (v = 0; v <= val_arr.length; v++) {
			lvalue = '';
			if (listend)
				break;
			for (c = 0; c < options_arr.length; c++) {
				var opt_arr = options_arr[c].split('=');
				if (!opt_arr[1]) opt_arr[1] = opt_arr[0];
				if (val_arr[v] == opt_arr[0]) {
					if (opt_arr[1]) {
						lvalue = lvalue + opt_arr[1];
					}
					break;
				}
			}
			if(!lvalue) {
				if (val_arr[v]) {
					lvalue = lvalue + val_arr[v];
					lvalue = lvalue + ' <font color=red>(not presently in stock list)</font>';
				} else if (editp && liststart) {
					lvalue = 'edit';
				}
			}
			if (!val_arr[v])
				listend = 1;
			if (lvalue && !liststart) output += ', ';
			lvalue = lvalue + '<input name="' + fld + '_' + v + '" value="' + val_arr[v] + '" type="hidden">';
// alert('reset_string: ' + '<input name="' + fld + '_' + v + '" value="' + val_arr[v] + '" type="hidden">');
// alert(lvalue);
			output += lvalue;
			liststart = 0;
		}
// alert(output);

	} else if (type == 'options') {
		var flag = 1;
		if (value) {
			var val_arr = value.split('|');
			for (v = 0; v < val_arr.length; v++) {
// alert(val_arr[v]);
				var lvalue = '';
				var opt_arr = val_arr[v].split('=');
				if (v && (opt_arr[0] || opt_arr[1])) lvalue += ', ';
				if (opt_arr[0]) {
					lvalue += '"' + opt_arr[0] + '"';
					flag = 0;
				}
				lvalue += '<input name="' + fld + '_opt_' + v + '" value="' + opt_arr[0] + '" type="hidden">';
				if (opt_arr[1]) {
					lvalue += ' ('+ opt_arr[1] + ')';
					flag = 0;
				}
				lvalue += '<input name="' + fld + '_desc_' + v + '" value="' + opt_arr[1] + '" type="hidden">';
				output += lvalue;
// alert('reset_string: ' + '<input name="' + fld + '_' + v + '" value="' + val_arr[v] + '" type="hidden">');
// alert(lvalue);
			}
		}

		if (flag)
			output += 'edit';
// alert(output);

	} else if (type == 'date') {
		yearopts = years.split(':');
		if (value) {
			matches = value.split('/');
			lvalue = value;
		} else {
			matches = new Array('', '', '');
			if (editp) lvalue = 'edit'; else lvalue = '&nbsp;';
		}

		output += lvalue;
		output += '<input type="hidden" value="' + matches[0] + '" name="' + fld + '_year" selected>\n';
		output += '<input type="hidden" value="' + matches[1] + '" name="' + fld + '_month" selected>\n';
		output += '<input type="hidden" value="' + matches[2] + '" name="' + fld + '_day" selected>\n';
	} else if (type == 'password') {
		value = value.replace(/%2e+/g, '\r');
		value = value.replace(/%27/g, "'");
		value = value.replace(/%22/g, '"');
		value = value.replace(/"/g, "&quot;");
		if (value)
			lvalue = '********';
		else
			if (editp) lvalue = 'edit'; else lvalue = '&nbsp;';
		lvalue = lvalue.replace(/(\n|\r)+/g, '<br>');
		output += lvalue;
		output += '<input name="' + fld + '" value="' + value + '" type="hidden">';
	} else if (type == 'textarea') {
		value = value.replace(/%2e+/g, '\r');
		value = value.replace(/%27/g, "'");
		value = value.replace(/%22/g, '"');
		if (editp) lvalue = 'edit<p>'; else lvalue = '&nbsp;';
		output += lvalue;
// alert(output);
		var text = value.replace(/(\n|\r)+/g, '<br>');
		text += '<textarea name="' + fld + '">' + value + '</textarea>';
		var evalme = "document." + form + "." + fld + ".style.display = 'none'; ";
// alert(fld + ', ' + value + ', ' + type + ', ' + options + ', ' + editp);
	} else {
		value = value.replace(/%2e+/g, '\r');
		value = value.replace(/%27/g, "'");
		value = value.replace(/%22/g, '"');
		value = value.replace(/"/g, "&quot;");
		if (value)
			lvalue = value;
		else
			if (editp) lvalue = 'edit'; else lvalue = '&nbsp;';
		lvalue = lvalue.replace(/(\n|\r)+/g, '<br>');
		if (fld.match(/MolMass/) && parseFloat(lvalue))
			output += fmtF(lvalue, 2);
		else
			output += lvalue;
		output += '<input name="' + fld + '" value="' + value + '" type="hidden">';
// alert(fld + ', ' + value + ', ' + type + ', ' + options + ', ' + editp);
	}

	if (editp)
		output += '</a>';
	mydiv.innerHTML = output;

	if (type == 'textarea')
		mydiv.innerHTML += text;

//if(type=='select')
//alert('reset_string: ' + mydiv + ' ' + mydiv.innerHTML);

//if (fld == 'Options_28') {
//	alert(output);
//}

	if (type == 'checkbox' || type == 'textarea')
		eval(evalme);
}

function calc_recipe(field, conc, stockconc, unit, name, volume, formula, molmass) {
	eval ('mydiv_recipe = document.getElementById(\"' + field + '\")');

	if (!name || !conc) {
		mydiv_recipe.innerHTML = '&nbsp;';
		return;
	}

	if (!unit) {
		output += '<font color=red>Need stock unit for ' + name + '</font> ';
	}

	if (!volume && !(conc == '100' && (unit == '%w/v' || unit == '%v/v'))) {
		mydiv_recipe.innerHTML = '<font color=red>Need volume to calculate recipe</font> ';
		return;
	}

	var output = '';
	if (parseFloat(conc) < stockconc)
		output += compose_value(conc / stockconc * volume, 'ml') + ' ' + stockconc + ' ' + unit + ' ' + name + ' / ' + compose_value(volume, 'ml') + '<br>';
	else if (parseFloat(conc) > stockconc)
		output += '<font color=red>concentration ' + conc + ' exceeds stock concentration (' + stockconc + ' ' + unit + ')</font><br>';

	if ((unit == '%w/v' || unit == '%v/v') && conc < 100.0) {
		if (unit == '%w/v') {
			output += compose_value(conc * volume * 10, 'mg') + ' ' + name + ' / ' + compose_value(volume, 'ml');
		} else if (unit == '%v/v') {
			output += compose_value(conc * volume * 10, 'ul') + ' ' + name + ' / ' + compose_value(volume, 'ml');
		}
	} else if (unit == 'M') {
		if (molmass) {
			output += compose_value(conc * molmass * volume, 'mg') + ' ' + formula + ' / ' + compose_value(volume, 'ml');
		} else {
			output += '<font color=red>Need molecular weight for ' + name + '</font> ';
		}
	} else if (unit == 'mg/ml') {
		output += compose_value(conc * volume, 'mg') + ' / ' + compose_value(volume, 'ml');
	}

	if (output)
		mydiv_recipe.innerHTML = output;
	else
		mydiv_recipe.innerHTML = '&nbsp;';
}

function compose_value(value, unit) {
	if (unit == '%v/v' || unit == '%w/v' || unit == '%')
		return (fmtF(value, 2) + ' ' + unit);
	if (!unit)
		return (value);

	var ct;
	var fmtvalue;

	if (unit.match(/^\w\S+$/)) {
		var modifier = unit.substring(0,1);
		var SI_unit = unit.substring(1);
	} else {
		var modifier = '';
		var SI_unit = unit;
	}

	if (SI_unit != 'M' && SI_unit != 'l' && SI_unit != 'g' && SI_unit != 'B' && SI_unit != 'g/ml')
		return (value + ' ' + unit);

	var modif_arr = {'-4':'p', '-3':'n', '-2':'u', '-1':'m', '0':'', '1':'k', '2':'M', '3':'G', '4':'T'};
	var prec = 9;
	if (SI_unit == 'l') var prec = 6;
	if (SI_unit == 'g') var prec = 4;
	if (SI_unit == 'B') var prec = 0;
	if (SI_unit == 'M') var prec = 7;
	if (SI_unit == 'g/ml') var prec = 9;

	for (ct = -4; ct <= 4; ct++)
		if (modifier == modif_arr[ct])
			break;

	var orig_ct = ct;
	prec += ct * 3;

	modif_arr['-2'] = micro;

	if (value == 0)
		return ('0 ' + modif_arr[ct] + SI_unit);

	fmtvalue = value;

	while (fmtvalue < 1.0) {
		if (--ct == -4) break;
		fmtvalue *= 1000.0;
		prec -= 3;
	}

	while (fmtvalue >= 1000.0) {
		if (++ct == 4) break;
		fmtvalue /= 1000.0;
		prec += 3;
	}

	fmtvalue = fmtF(fmtvalue, prec);

	if (fmtvalue == 0)
		return ('0 ' + modif_arr[orig_ct] + SI_unit);
	else
		return (fmtvalue + ' ' + modif_arr[ct] + SI_unit);
}

function fmtF(value, prec) {
	var s;
	var zeros = '';
	var i = parseFloat(value);
	var factor = Math.pow(10, prec);
	for (x = 0; x < prec; x++)
		zeros = zeros + '0';
	if(isNaN(i)) { i = 0; }
	var minus = '';
	if(i < 0) { minus = '-'; }
	i = Math.abs(i);
	i = parseInt((i + 0.5/factor) * factor);
	i = i / factor;
	s = new String(i);
	if(s.indexOf('.') < 0 && zeros) { s += '.' + zeros; }
	if(s.indexOf('.') == (s.length - prec)) { s += '0'; }
	while(s.indexOf('.') >= 0 && s.lastIndexOf('0') == s.length - 1) { s = s.substr(0, s.length-1);}
	if(s.indexOf('.') == (s.length - 1)) { s = s.substr(0, s.length-1); }
	s = minus + s;
	return s;
}

function construct_selector(name, value, options, myclass, onchange, omit) {
// alert(name + ' / ' + value + ' / ' + options + ' / ' + myclass + ' / ' + onchange + ' / ' + omit);
	output = "<select class=\"" + myclass + "\" name=\"" + name + "\" onChange=\"" + onchange + "\">";
	var flag = 0;
	var opt;
	for (opt=0; opt < options.length; opt++) {
// alert(options[opt]);
		if (options[opt] == omit)
			continue;
		if (options[opt] == value) {
			selected = "selected";
			flag = 1;
		} else
			selected = "";
		output += "<option " + selected + " value=\"" + options[opt] + "\">" + options[opt] + "</option>\n";
	}
	if (!flag)
		output += "<option selected value=\"" + value + "\">" + value + "</option>\n";
	output += "</select>";
// alert(output);
	return(output);
}

function construct_named_selector(name, value, options, myclass, onchange, omit) {
// alert(name + ' / ' + value + ' / ' + options + ' / ' + myclass + ' / ' + onchange + ' / ' + omit);
	output = "<select class=\"" + myclass + "\" name=\"" + name + "\" onChange=\"" + onchange + "\">";
	var flag = 0;
	var opt;
	for (opt in options) {
// alert(options[opt]);
		if (opt == omit)
			continue;
		if (opt == value) {
			selected = "selected";
			flag = 1;
		} else
			selected = "";
		output += "<option " + selected + " value=\"" + opt + "\">" + options[opt] + "</option>\n";
	}
	output += "</select>";
// alert(output);
	return(output);
}

function validate(form, row, key, type, options, valid, str, regexdesc) {
// alert(form + ' / ' + row + ' / ' + key + ' / ' + type + ' / ' + options + ' / ' + valid + ' / ' + str + ' / ' + regexdesc);
	var valid = valid.replace('/\\\\\|/', '%5c%7c');
	var conds = valid.split('|');
	for (c=flag=0; c < conds.length; c++) {
		conds[c] = conds[c].replace('/%5c%7c/', '|');
	}
	eval("var opts_r = new Array('" + options.replace(/\|/g, "','") + "')");

	if (row)
		row = '_' + row;

	if (type == 'select') {
		eval("fld = form." + key + row);
		if (!select_check_selected(fld, str)) 
			return(false);

	} else if (type == 'radio') {
		eval("fld = form." + key + row);
		if (!radio_check_selected(fld, str))
			return(false);

	} else if (type == 'checkbox') {
		if (valid == 'ne') {
			var isset=0;
			for (c=flag=0; c < opts_r.length; c++) {
				var opt = opts_r[c].split('=');
				opt[0] = opt[0].replace('/%5c%7c/', '|');
				eval("fld = form." + key + row + "_" + opt[0]);
				if (!fld) {
					isset = 1;
				} else {
					if (fld.checked)
						isset = 1;
				}
			}
			if (!isset) {
				alert("Please enter a value for the " + str + " field.");
				return (false);
			} 
		}

	} else {
		eval("fld = form." + key + row);
		for (c=flag=0; c < conds.length; c++) {
			var cond = conds[c].split('=');
// alert(conds[c] + ' ' + key + ' ' + row + ' ' + fld.value);
			if (conds[c] == 'ne') {
				if (!is_defined(fld, str))
					return(false); 
			}
			if (conds[c] == 'email') {
				if (!is_email(fld, str))
					return(false); 
			}
			if (conds[c] == 'date') {
				if (!is_date(fld, str))
					return(false); 
			}
			if (conds[c] == 'num') {
				if (!is_num(fld, str))
					return(false); 
			}
			if (cond[0] == 'min') {
				if (!equal_greater_than(fld, str, cond[1]))
					return(false); 
			}
			if (cond[0] == 'max') {
				if (!equal_lower_than(fld, str, cond[1]))
					return(false); 
			}
			if (cond[0] == 'maxl') {
				if (!within_maxsize(fld, str, cond[1]))
					return(false); 
			}
			if (cond[0] == 'regex') {
				if (!does_match(fld, str, cond[1], regexdesc))
					return(false); 
			}
			if (cond[0] == 'invregex') {
				if (!does_not_match(fld, str, cond[1], regexdesc))
					return(false); 
			}
		}
	}

	return(true);
}

function select_check_selected(fld, desc) {
	if (!fld)
		return(true);

	var isset = 0;
	if (fld.options) {
		if (fld[fld.selectedIndex].value)
			isset = 1;
	} else
		if (fld.value != '')
			isset = 1;

	if (!isset) {
		alert('Please enter a value for the "' + desc + '" field.');
//		fld[0].focus();
		return(false);
	}
	return(true);
}

function radio_check_selected(fld, desc) {
	if (!fld)
		return(true);

	var isset=0;
	if (fld.length) {
		for (var i=0; i < fld.length; i++)  { 
			if (fld[i].checked)  {
				isset = 1;
				break;
			} 
		} 
	} else {
		if (fld.value != '')
			isset = 1;
	}

	if (!isset) {
		alert('Please enter a value for the "' + desc + '" field.');
//		fld[0].focus();
		return(false);
	}
	return(true);
}

function radio_selectedIndex(fld) {
	var i = 0;
	if (fld.length) {
		for (var i=0; i < fld.length; i++)  { 
			if (fld[i].checked)  {
				break;
			} 
		} 
	} else {
		if (fld.value != '')
			i = 0;
	}

	if (i == fld.length)
		return(-1);
	else
		return(i);
}

function is_defined(fld, desc) {
	if (fld && fld.value == '') {
		alert('Please enter a value for the "' + desc + '" field.');
//		fld.focus();
		return (false);
	}
	return(true);
}

function equal_greater_than(fld, desc, min) {
	if (fld && fld.value != '' && Number(fld.value) < min) {
		alert('"' + desc + '" must be at least ' + min + '.');
//		fld.focus();
		return (false);
	}
	return(true);
}

function equal_lower_than(fld, desc, max) {
	if (fld && fld.value != '' && Number(fld.value) > max) {
		alert('"' + desc + '" must not exceed ' + max + '.');
//		fld.focus();
		return (false);
	}
	return(true);
}

function within_maxsize(fld, desc, max) {
	if (fld && fld.value.length > max) {
		alert('field "' + desc + '" contains too many letters (max. ' + max + ')');
//		fld.focus();
		return (false);
	}
	return(true);
}

function is_email(fld, desc) {
	if (fld && fld.value && 
		(fld.value.match(/(\@.*\@)|(\.\.)|(\@\.)|(\.\@)|(^\.)/) || 
		!(fld.value.match(/^\s*\S+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,}|[0-9]{1,3})(\]?)\s*$/)))) {
		alert(fld.value + ' is not a valid E-mail address');
//		fld.focus();
		return (false);
	}
	return(true);
}

function is_date(fld, desc) {
	if (fld && fld.value && 
		!(fld.value.match(/^[12][09][09][0-9]\/[01][0-9]\/[0-3][0-9]( [012][0-9]:[0-6][0-9]:[0-6][0-9])?$/))) {
		alert('The field "' + desc + '" must have the form YYYY/MM/DD');
//		fld.focus();
		return (false);
	}
	return(true);
}

function is_num(fld, desc) {
	if (fld && fld.value && !(fld.value.match(/^[0-9.]+$/))) {
		alert('The field "' + desc + '" must be a number');
//		fld.focus();
		return (false);
	}
	return(true);
}

function does_match(fld, desc, expr, regexdesc) {
	if (!fld)
		return(true);

	if (fld.value == '')
		return(true);

	eval('str = fld.value.match(/^' + expr + '$/i)');
	if (!str) {
		if (regexdesc) { 
			alert(regexdesc);
		} else { 
			alert('field "' + desc + '" must match the expression ' + expr);
		} 
//		fld.focus();
		return (false);
	}
	return(true);
}

function does_not_match(fld, desc, expr, regexdesc) {
	if (!fld)
		return(true);

	if (fld.value == '')
		return(true);

	eval('str = fld.value.match(/' + expr + '/i)');

	if (str) {
		if (regexdesc) { 
			alert(regexdesc);
		} else { 
			alert('field "' + desc + '" must not contain ' + expr);
		} 
//		fld.focus();
		return (false);
	}
	return(true);
}

