www/js/prod_edit.js

changeset 236
4b8e5478d08f
parent 223
0de4455bd2a1
child 237
9337b5ff8698
--- a/www/js/prod_edit.js	Sat Feb 02 21:35:54 2019 +0100
+++ b/www/js/prod_edit.js	Sun Feb 03 17:44:14 2019 +0100
@@ -46,13 +46,13 @@
 
 $(document).ready(function () {
 
-	var	brewstage = 0;	// Numeric value of stage
+	var	to_100 = false;		// Fermentables adjust to 100%
 	var     preboil_sg = 0;
 	var	est_mash_sg = 0;
-	var     sugarsm = 0;    // Sugars after mash
-	var     sugarsf = 0;    // Sugars after boil
-	var     psugar = 0;     // Percentage real sugars
-	var     pcara = 0;      // Percentage cara/crystal malts
+	var     sugarsm = 0;		// Sugars after mash
+	var     sugarsf = 0;		// Sugars after boil
+	var     psugar = 0;		// Percentage real sugars
+	var     pcara = 0;		// Percentage cara/crystal malts
 	var     svg = 77;               // Default attenuation
         var     mashkg = 0;             // Malt in mash weight
         var     hop_flavour = 0;
@@ -77,6 +77,17 @@
         var     MMNaCl = 58.443;
         var     MMCaOH2 = 74.06268;
 
+	var     fermentableRow = 0;
+	var     fermentableData = {};
+	var     hopRow = 0;
+	var     hopData = {};
+	var     miscRow = 0;
+	var     miscData = {};
+	var     yeastRow = 0;
+	var     yeastData = {};
+	var     mashRow = 0;
+	var     mashData = {};
+
 	console.log("record:" + my_record + "  return:" + my_return + "  theme:" + theme);
         $("#jqxLoader").jqxLoader({
                 width: 250,
@@ -101,12 +112,12 @@
                         var row = rows[i];
                         if (row.f_adjust_to_total_100)
                                 my_100 = true;
-			if (row.f_type == "Sugar")
+			if (row.f_type == 1)	// Sugar
 				psugar += row.f_percentage;
-			if (row.f_graintype == "Crystal")
+			if (row.f_graintype == 2)	// Crystal
 				pcara += row.f_percentage;
 			var d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
-			if (row.f_added == "Mash") {
+			if (row.f_added == 0) {	// Mash
 				d = parseFloat(dataRecord.efficiency) / 100 * d;
 				sugarsm += d;
 				mashkg += row.f_amount;
@@ -115,6 +126,11 @@
 			colorw += row.f_amount * ebc_to_srm(row.f_color) / parseFloat(dataRecord.batch_size) * 8.34436;
 		}
 		to_100 = my_100;
+		if (to_100) {
+			$("#wf_amount").jqxNumberInput({ width: 90, readOnly: true, spinButtons: false  });
+		} else {
+			$("#wf_amount").jqxNumberInput({ width: 110, readOnly: false, spinButtons: true });
+		}
 		var est_og = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size));
                 $('#est_og').val(est_og);
                 $('#est_og2').val(est_og);
@@ -127,7 +143,7 @@
                 document.getElementById("bcolor").style.background= scolor;
                 document.getElementById("bcolor2").style.background= scolor;
                 pmalts = mashkg / dataRecord.eq_mash_max * 100;
-		console.log("mash kg: "+mashkg+" max: "+dataRecord.eq_mash_max+" perc: "+pmalts);
+//		console.log("mash kg: "+mashkg+" max: "+dataRecord.eq_mash_max+" perc: "+pmalts);
                 $("#perc_malts").jqxProgressBar('val', pmalts);
                 $("#perc_sugars").jqxProgressBar('val', psugar);
                 $("#perc_cara").jqxProgressBar('val', pcara);
@@ -147,7 +163,7 @@
 			var rows = $('#fermentableGrid').jqxGrid('getrows');
 			for (i = 0; i < rows.length; i++) {
 				var row = rows[i];
-				if ((row.f_added == "Fermentation") || (row.f_added == "Lagering") || (row.f_added == "Bottle")) {
+				if ((row.f_added == 2) || (row.f_added == 3) || (row.f_added == 4)) {	// Fermentation, Lagering or Bottle
 					var x = (row.f_yield / 100) * (1 - row.f_moisture / 100);
 					vol += row.f_amount / (x * sugardensity + (1 - x) * 1);
 					sug2 += row.f_amount * x;
@@ -168,7 +184,7 @@
 			for (i = 0; i < rows.length; i++) {
 				var row = rows[i];
 				d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100);
-				if (row.f_added == "Mash")
+				if (row.f_added == 0)	// Mash
 					d = efficiency / 100 * d;
 				tot += d;
 			}
@@ -189,14 +205,23 @@
 		//CalcWaterBalance;
 	};
 
+	function calcFG() {
+		var fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, parseFloat(parseFloat($("#est_og").jqxNumberInput('decimal'))));
+		dataRecord.est_fg = fg;
+		$('#est_fg').val(fg);
+		$('#est_fg2').val(fg);
+	}
+
 	function calcABV() {
-		$("#est_abv").val(abvol(parseFloat($("#est_og").jqxNumberInput('decimal')), parseFloat($("#est_fg").jqxNumberInput('decimal'))));
+		var abv = abvol(parseFloat($("#est_og").jqxNumberInput('decimal')), parseFloat($("#est_fg").jqxNumberInput('decimal')));
+		$("#est_abv").val(abv);
+		$("#est_abv2").val(abv);
 	};
 
 	function hopFlavourContribution(bt, vol, use, amount) {
 		var result;
 
-		if ((use == "First Wort") || (use == "First wort")) {
+		if (use == 1) {	// First wort
 			result = 0.15;          // assume 15% flavourcontribution for fwh
 		} else if (bt > 50) {
 			result = 0.10;          // assume 10% flavourcontribution as a minimum
@@ -217,13 +242,13 @@
 			result = 0;
 		} else if (bt > 7.5) {
 			result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) /4, 2));
-		} else if (use == "Boil") {
+		} else if (use == 2) {	// Boil
 			result = 1;
-		} else if (use == "Aroma") {
+		} else if (use == 3) {	// Aroma
 			result = 1.2;
-		} else if (use == "Whirlpool") {
+		} else if (use == 4) {	// Whirlpool
 			result = 1.2;
-		} else if ((use == "Dry Hop") || (use == "Dry hop")) {
+		} else if (use == 5) {	// Drt hop
 			result = 1.33;
 		}
 		result = (result * amount * 1000) / vol;
@@ -257,7 +282,7 @@
 		var rows = $('#yeastGrid').jqxGrid('getrows');
 		for (var i = 0; i < rows.length; i++) {
 			var row = rows[i];
-			if (row.y_use == "Primary")
+			if (row.y_use == 0)	// Primary
 				svg = parseFloat(row.y_attenuation);
 		}
 	}
@@ -271,7 +296,7 @@
 		for (var i = 0; i < rows.length; i++) {
 			var row = rows[i];
 //			console.log("step " + i + " " + row.step_name + " " + row.step_type);
-			if (row.step_type == 'Infusion')
+			if (row.step_type == 0)	// Infusion
 				mvol += parseFloat(row.step_infuse_amount);
 		}
 		if (mvol > 0) {
@@ -279,7 +304,7 @@
 			var rows = $('#fermentableGrid').jqxGrid('getrows');
 			for (var i = 0; i < rows.length; i++) {
 			        var row = rows[i];
-				if (row.f_added == "Mash") {
+				if (row.f_added == 0) {	// Mash
 					var d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
 					mvol += row.f_amount * row.f_moisture / 100;
 					gs += my_grain_absorbtion * row.f_amount;
@@ -336,7 +361,6 @@
 				var row = rows[i];
 				if (row.m_name == name) {
 					found = true;
-					$("#miscGrid").jqxGrid('setcellvalue', i, 'm_weight', amount);
 					$("#miscGrid").jqxGrid('setcellvalue', i, 'm_amount', amount / 1000);
 					break;
 				}
@@ -355,8 +379,9 @@
 								row["m_type"] = record.type;
 								row["m_use_use"] = record.use_use;
 								row["m_time"] = 0;
-								row["m_weight"] = amount;
 								row["m_amount_is_weight"] = record.amount_is_weight;
+								row["m_inventory"] = record.inventory;
+								row["m_avail"] = 1;
 								var commit = $("#miscGrid").jqxGrid('addrow', null, row);
 							}
 						}
@@ -428,25 +453,25 @@
 		var rows = $('#fermentableGrid').jqxGrid('getrows');
 		for (var i = 0; i < rows.length; i++) {
 			var row = rows[i];
-			if (row.f_added == 'Mash' && row.f_graintype != 'No malt') {
+			if (row.f_added == 0 && row.f_graintype != 6) {	// Added == Mash && graintype != No Malt
 				// Check if acid is required
 				var C1 = 0;
 				if ((row.f_di_ph != 5.7) && ((row.f_acid_to_ph_57 < - 0.1) || (row.f_acid_to_ph_57 > 0.1))) {
-						C1 = row.f_acid_to_ph_57 / (row.f_di_ph - 5.7);
+					C1 = row.f_acid_to_ph_57 / (row.f_di_ph - 5.7);
 				} else {
 					// If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid.
 					var ebc = row.f_color;
 					switch (row.f_graintype) {
-						case 'Base':
-						case 'Special':
-						case 'Kilned':  C1 = 0.014 * ebc - 34.192;
-								break;
-						case 'Crystal': C1 = -0.0597 * ebc - 32.457;
-								break;
-						case 'Roast':   C1 = 0.0107 * ebc - 54.768;
-								break;
-						case 'Sour':    C1 = -149;
-								break;
+						case 0:					// Base, Special, Kilned
+						case 3:
+						case 5: C1 = 0.014 * ebc - 34.192;
+							break;
+						case 2: C1 = -0.0597 * ebc - 32.457;	// Crystal
+							break;
+						case 1: C1 = 0.0107 * ebc - 54.768;	// Roast
+							break;
+						case 4: C1 = -149;			// Sour malt
+							break;
 					}
 				}
 				x = C1 * (pHZ - row.f_di_ph);   // AcidRequired(ZpH)
@@ -476,38 +501,38 @@
 
 	function GetAcidSpecs(AT) {
 		switch(AT) {
-			case 'Melkzuur':        return {
-							pK1: 3.08,
-							pK2: 20,
-							pK3: 20,
-							MolWt: 90.08,
-							AcidSG: 1214,
-							AcidPrc: 0.88
-						};
-			case 'Zoutzuur':        return {
-							pK1: -10,
-							pK2: 20,
-							pK3: 20,
-							MolWt: 36.46,
-							AcidSG: 1142,
-							AcidPrc: 0.28
-						};
-			case 'Fosforzuur':      return {
-							pK1: 2.12,
-							pK2: 7.20,
-							pK3: 12.44,
-							MolWt: 98.00,
-							AcidSG: 1170,
-							AcidPrc: 0.25
-						};
-			case 'Zwavelzuur':      return {
-							pK1: -10,
-							pK2: 1.92,
-							pK3: 20,
-							MolWt: 98.07,
-							AcidSG: 1700,
-							AcidPrc: 0.93
-						};
+			case 0:	return {	// Melkzuur
+					pK1: 3.08,
+					pK2: 20,
+					pK3: 20,
+					MolWt: 90.08,
+					AcidSG: 1214,
+					AcidPrc: 0.88
+				};
+			case 1:	return {	// Zoutzuur
+					pK1: -10,
+					pK2: 20,
+					pK3: 20,
+					MolWt: 36.46,
+					AcidSG: 1142,
+					AcidPrc: 0.28
+				};
+			case 2:	return {	// Fosforzuur
+					pK1: 2.12,
+					pK2: 7.20,
+					pK3: 12.44,
+					MolWt: 98.00,
+					AcidSG: 1170,
+					AcidPrc: 0.25
+				};
+			case 3:	return {	// Zwavelzuur
+					pK1: -10,
+					pK2: 1.92,
+					pK3: 20,
+					MolWt: 98.07,
+					AcidSG: 1700,
+					AcidPrc: 0.93
+				};
 		}
 	}
 
@@ -527,8 +552,6 @@
 		var RA = 0;
 		var frac = 0;
 		var TpH = 0;
-		var Acid = 0;
-		var Acidmg = 0;
 		var protonDeficit = 0;
 
 		if (dataRecord.w1_name == "") {
@@ -602,17 +625,24 @@
 		chloride += 1000 * RA / liters;
 		// Einde noot.
 
-		if ($("#wa_acid_name").val() == "") {
-			$("#wa_acid_name").val('Melkzuur');
-			last_acid = 'Melkzuur';
+		if ($("#wa_acid_name").val() < 0 || $("#wa_acid_name").val() > 3) {
+			console.log("fix wa_acid_name");
+			$("#wa_acid_name").val(0);
+			dataRecord.wa_acid_name = 0;
 		}
-		if ($("#wa_base_name").val() == "") {
-			$("#wa_base_name").val('NaHCO3');
-			last_base = 'NaHCO3';
+		if (last_acid == '')
+			last_acid = AcidTypeData[$("#wa_acid_name").val()].nl;
+
+		if ($("#wa_base_name").val() < 0 || $("#wa_base_name").val() > 3) {
+			console.log("fix wa_base_name");
+			$("#wa_base_name").val(0);
+			dataRecord.wa_base_name = 0;
 		}
+		if (last_base == '')
+			last_base = BaseTypeData[$("#wa_base_name").val()].nl;
 
-		var AT = $("#wa_acid_name").val();
-		var BT = $("#wa_base_name").val();
+		var AT = dataRecord.wa_acid_name;
+		var BT = dataRecord.wa_base_name;
 
 		var result = GetAcidSpecs(AT);
 		var pK1 = result.pK1;
@@ -640,7 +670,7 @@
 				Acid = Acid * AcidPrc / (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
 				console.log("Final ml: "+Acid);
 				$("#wa_acid").val(Math.round(Acid * 100) / 100);
-				setWaterAgent(AT, Math.round(Acid * 100) / 100);
+				setWaterAgent(AcidTypeData[AT].nl, Math.round(Acid * 100) / 100);
 
 				bicarbonate = bicarbonate - protonDeficit * frac / liters;
 				total_alkalinity = bicarbonate * 50 / 61;
@@ -653,79 +683,79 @@
 				var f2d = f1d * r1d;
 				var f3d = f2d * r2d;
 				switch (BT) {
-					case 'NaHCO3':  RA = -protonDeficit / (f1d - f3d); //mmol totaal
-							RA = RA * MMNaHCO3/1000; //gram
-							$("#wa_base").val(Math.round(RA * 100) / 100);
-							setWaterAgent(BT, Math.round(RA * 100) / 100);
-							if (liters > 0) {
-								// Na
-								RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
-								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
-								RA = 1000 * RA / liters;
-								sodium = wg_sodium + RA;
-								// HCO3
-								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
-								RA = 1000 * RA / liters;
-								bicarbonate = wg_bicarbonate + RA;
-								total_alkalinity = bicarbonate * 50 / 61;
-								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
-							}
-							break;
-					case 'Na2CO3':  RA = -protonDeficit / (2 * f1d + f2d); //mmol totaal
-							RA = RA * MMNa2CO3/1000; //gram
-							$("#wa_base").val(Math.round(RA * 100) / 100);
-							setWaterAgent(BT, Math.round(RA * 100) / 100);
-							if (liters > 0) {
-								RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
-								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
-								RA = 1000 * RA / liters;
-								sodium = wg_sodium + RA;
-								// HCO3
-								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
-								RA = 1000 * RA / liters;
-								bicarbonate = wg_bicarbonate + RA;
-								total_alkalinity = bicarbonate * 50 / 61;
-								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
-							}
-							break;
-					case 'CaCO3':   RA = -protonDeficit * (f1d - f3d); //mmol totaal
-							RA = RA * MMCaCO3/1000; //gram
-							//but only 1/3 is effective, so add 3 times as much
-							RA = 3 * RA;
-							$("#wa_base").val(Math.round(RA * 100) / 100);
-							setWaterAgent(BT, Math.round(RA * 100) / 100);
-							if (liters > 0) {
-								//Bicarbonate
-								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
-								RA = 1000 * RA / liters;
-								bicarbonate = wg_bicarbonate + RA;
-								total_alkalinity = bicarbonate * 50 / 61;
-								//Ca precipitates out as Ca10(PO4)6(OH)2
-								RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
-								     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
-								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
-								RA = 1000 * RA / liters;
-								calcium = wg_calcium + RA;
-								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
-							}
-							break;
-					case 'Ca(OH)2': RA = -protonDeficit / 19.3; // g
-							$("#wa_base").val(Math.round(RA * 100) / 100);
-							setWaterAgent(BT, Math.round(RA * 100) / 100);
-							if (liters > 0) {
-								// Bicarbonate
-								RA = -protonDeficit / liters;
-								total_alkalinity = wg_total_alkalinity + RA;
-								bicarbonate = total_alkalinity * 61 / 50;
-								// Calcium
-								RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
-								parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
-								parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaOH2;
-								RA = 1000 * RA / liters;
-								calcium = wg_calcium + RA;
-								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
-							}
-							break;
+					case 0:  RA = -protonDeficit / (f1d - f3d); // Sodiumbicarbonate, mmol totaal
+						RA = RA * MMNaHCO3/1000; //gram
+						$("#wa_base").val(Math.round(RA * 100) / 100);
+						setWaterAgent('NaHCO3', Math.round(RA * 100) / 100);
+						if (liters > 0) {
+							// Na
+							RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
+							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
+							RA = 1000 * RA / liters;
+							sodium = wg_sodium + RA;
+							// HCO3
+							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
+							RA = 1000 * RA / liters;
+							bicarbonate = wg_bicarbonate + RA;
+							total_alkalinity = bicarbonate * 50 / 61;
+							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+						}
+						break;
+					case 1:	RA = -protonDeficit / (2 * f1d + f2d); // Sodiumcarbonate, mmol totaal
+						RA = RA * MMNa2CO3/1000; //gram
+						$("#wa_base").val(Math.round(RA * 100) / 100);
+						setWaterAgent('Na2CO3', Math.round(RA * 100) / 100);
+						if (liters > 0) {
+							RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
+							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
+							RA = 1000 * RA / liters;
+							sodium = wg_sodium + RA;
+							// HCO3
+							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
+							RA = 1000 * RA / liters;
+							bicarbonate = wg_bicarbonate + RA;
+							total_alkalinity = bicarbonate * 50 / 61;
+							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+						}
+						break;
+					case 2:	RA = -protonDeficit * (f1d - f3d); // Calciumcarbonate, mmol totaal
+						RA = RA * MMCaCO3/1000; //gram
+						//but only 1/3 is effective, so add 3 times as much
+						RA = 3 * RA;
+						$("#wa_base").val(Math.round(RA * 100) / 100);
+						setWaterAgent('CaCO3', Math.round(RA * 100) / 100);
+						if (liters > 0) {
+							//Bicarbonate
+							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
+							RA = 1000 * RA / liters;
+							bicarbonate = wg_bicarbonate + RA;
+							total_alkalinity = bicarbonate * 50 / 61;
+							//Ca precipitates out as Ca10(PO4)6(OH)2
+							RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
+							     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
+							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
+							RA = 1000 * RA / liters;
+							calcium = wg_calcium + RA;
+							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+						}
+						break;
+					case 3: RA = -protonDeficit / 19.3; // Calciumhydroxide
+						$("#wa_base").val(Math.round(RA * 100) / 100);
+						setWaterAgent('Ca(OH)2', Math.round(RA * 100) / 100);
+						if (liters > 0) {
+							// Bicarbonate
+							RA = -protonDeficit / liters;
+							total_alkalinity = wg_total_alkalinity + RA;
+							bicarbonate = total_alkalinity * 61 / 50;
+							// Calcium
+							RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
+							     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
+							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaOH2;
+							RA = 1000 * RA / liters;
+							calcium = wg_calcium + RA;
+							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+						}
+						break;
 				}
 			}
 			ph = TpH;
@@ -737,42 +767,43 @@
 			if (parseFloat($("#wa_base").jqxNumberInput('decimal')) > 0) {
 				if (liters > 0) {
 					switch (BT) {
-						case 'NaHCO3':  // Na
-							        RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
-								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
-								RA = 1000 * RA / liters;
-								sodium = wg_sodium + RA;
-								// HCO3
-								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
-								RA = 1000 * RA / liters;
-								bicarbonate = wg_bicarbonate + RA;
-								total_alkalinity = bicarbonate * 50 / 61;
-								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
-								break;
-						case 'Na2CO3':  RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
-								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
-								RA = 1000 * RA / liters;
-								sodium = wg_sodium + RA;
-								// HCO3
-								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
-								RA = 1000 * RA / liters;
-								bicarbonate = wg_bicarbonate + RA;
-								total_alkalinity = bicarbonate * 50 / 61;
-								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
-								break;
-						case 'CaCO3':   // Bicarbonate
-								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
-								RA = 1000 * RA / liters;
-								bicarbonate = wg_bicarbonate + RA;
-								total_alkalinity = bicarbonate * 50 / 61;
-								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
-								// Ca
-								RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
-								     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
-								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
-								RA = 1000 * RA / liters;
-								calcium = wg_calcium + RA;
-								break;
+						case 0:  // Sodiumbicarbonate, Na
+						        RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
+							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
+							RA = 1000 * RA / liters;
+							sodium = wg_sodium + RA;
+							// HCO3
+							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
+							RA = 1000 * RA / liters;
+							bicarbonate = wg_bicarbonate + RA;
+							total_alkalinity = bicarbonate * 50 / 61;
+							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+							break;
+						case 1:	// Sodiumcarbonate
+							RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
+							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
+							RA = 1000 * RA / liters;
+							sodium = wg_sodium + RA;
+							// HCO3
+							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
+							RA = 1000 * RA / liters;
+							bicarbonate = wg_bicarbonate + RA;
+							total_alkalinity = bicarbonate * 50 / 61;
+							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+							break;
+						case 2:	// Calciumcarbonate: Bicarbonate
+							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
+							RA = 1000 * RA / liters;
+							bicarbonate = wg_bicarbonate + RA;
+							total_alkalinity = bicarbonate * 50 / 61;
+							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+							// Ca
+							RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
+							     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
+							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
+							RA = 1000 * RA / liters;
+							calcium = wg_calcium + RA;
+							break;
 					}
 				}
 			}
@@ -818,16 +849,16 @@
 			}
 		}
 
-		if ((AT == 'Zwavelzuur') && (liters > 0)) {
+		if ((AT == 3) && (liters > 0)) {	// Sulfuctic / Zwavelzuur
 			RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
 			     parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 +
 			     Acidmg / 1000 * MMSO4 / (MMSO4 + 2);
 			RA = 1000 * RA / liters;
 			sulfate = wg_sulfate + RA;      // Not add to sulfate??
-		} else if ((AT == 'Zoutzuur') && (liters > 0)) {
+		} else if ((AT == 1) && (liters > 0)) {	// Hydrochloric, Zoutzuur
 			RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
 			     parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl +
-			     Acidmg / 1000 * MMCl / (MMCL + 1);
+			     Acidmg / 1000 * MMCl / (MMCl + 1);
 			RA = 1000 * RA / liters;
 			chloride = wg_chloride + RA;
 		}
@@ -896,21 +927,21 @@
 		var Source_pH = dataRecord.w1_ph;
 		var Source_alkalinity = dataRecord.w1_total_alkalinity;
 		// Select watersource or fallback to the first source.
-		if (dataRecord.sparge_source == 'Bron 2') {
+		if (dataRecord.sparge_source == 1) {	// Source 2
 			if (dataRecord.w2_ph > 0.0) {
 				Source_pH = dataRecord.w2_ph;
 				Source_alkalinity = dataRecord.w2_total_alkalinity;
 			} else {
-				dataRecord.sparge_source = 'Bron 1';
-				$("#sparge_source").val('Bron 1');
+				dataRecord.sparge_source = 0;	// Source 1
+				$("#sparge_source").val(0);
 			}
-		} else if (dataRecord.sparge_source == 'Gemengd') {
+		} else if (dataRecord.sparge_source == 2) {	// Mixed
 			if (dataRecord.w2_ph > 0.0) {
 				Source_pH = parseFloat($("#wg_ph").jqxNumberInput('decimal'));
 				Source_alkalinity = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal'));
 			} else {
-				dataRecord.sparge_source = 'Bron 1';
-				$("#sparge_source").val('Bron 1');
+				dataRecord.sparge_source = 0;
+				$("#sparge_source").val(0);
 			}
 		}
 
@@ -947,10 +978,9 @@
 
 		//Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
 		var Acid = alkalinity * ((f1g-f1)+(f3-f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH);  //mEq/l
-
-		if ($("#sparge_acid_type").val() == "") {
-			$("#sparge_acid_type").val('Melkzuur');
-			dataRecord.sparge_acid_type = 'Melkzuur';
+		if (dataRecord.sparge_acid_type < 0 || dataRecord.sparge_acid_type > 3) {
+			dataRecord.sparge_acid_type = 0;
+			$("#sparge_acid_type").val(0);
 		}
 		var AT = dataRecord.sparge_acid_type;
 		var result = GetAcidSpecs(AT);
@@ -1013,17 +1043,6 @@
 				0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376);
 	}
 
-	function getSFactor(Sugar) {
-		switch (Sugar) {
-			case 'Kristalsuiker':		return 1;
-			case 'Glucose/dextrose':	return 1.16;
-			case 'Honing':			return 1.28;
-			case 'Moutextract':		return 1.74;
-			case 'Melasse':			return 3.83;
-		}
-		return 1;
-	}
-
 	function calcCarbonation() {
 
 		var TSec = dataRecord.secondary_temp;	// End fermentation temperature.
@@ -1038,7 +1057,7 @@
 			var ABV = abvol(dataRecord.brew_fermenter_sg, dataRecord.fg);
 
 		// Bottles
-		var SFactor = getSFactor(dataRecord.bottle_priming_sugar);
+		var SFactor = PrimingSugarData[dataRecord.bottle_priming_sugar].factor;
 		var Amount = CarbCO2toS(dataRecord.bottle_carbonation, TSec, SFactor);
 		dataRecord.bottle_priming_amount = Amount;
 		$("#bottle_priming_amount").val(Math.round(dataRecord.bottle_priming_amount * 10) / 10);
@@ -1046,7 +1065,7 @@
 		$("#bottle_abv").val(Math.round((ABV + Amount * 0.47 / 7.907) * 10) / 10);
 
 		// Kegs
-		SFactor = getSFactor(dataRecord.keg_priming_sugar);
+		SFactor = PrimingSugarData[dataRecord.keg_priming_sugar].factor;
 		Amount = CarbCO2toS(dataRecord.keg_carbonation, TSec, SFactor);
 		var Pressure = CarbCO2ToPressure(dataRecord.keg_carbonation, dataRecord.keg_carbonation_temp);
 		if (Pressure < 0)
@@ -1107,45 +1126,73 @@
 			calcWater();
 		});
 		$('#wa_cacl2').on('change', function (event) {
-			setWaterAgent('CaCl2', event.args.value);
-			calcWater();
+			if (event.args) {
+				setWaterAgent('CaCl2', 0);      // This can prevent double entries.
+				setWaterAgent('CaCl2', event.args.value);
+				calcWater();
+			}
 		});
 		$('#wa_caso4').on('change', function (event) {
-			setWaterAgent('CaSO4', event.args.value);
-			calcWater();
+			if (event.args) {
+				setWaterAgent('CaSO4', 0);
+				setWaterAgent('CaSO4', event.args.value);
+				calcWater();
+			}
 		});
 		$('#wa_mgso4').on('change', function (event) {
-			setWaterAgent('MgSO4', event.args.value);
-			calcWater();
+			if (event.args) {
+				setWaterAgent('MgSO4', 0);
+				setWaterAgent('MgSO4', event.args.value);
+				calcWater();
+			}
 		});
 		$('#wa_nacl').on('change', function (event) {
-			setWaterAgent('NaCl', event.args.value);
-			calcWater();
+			if (event.args) {
+				setWaterAgent('NaCl', 0);
+				setWaterAgent('NaCl', event.args.value);
+				calcWater();
+			}
 		});
 		$('#wa_base_name').on('change', function (event) {
-			setWaterAgent(last_base, 0);
-			last_base = event.args.item.value;
-			setWaterAgent(last_base, parseFloat($("#wa_base").jqxNumberInput('decimal')));
-			calcWater();
+			if (event.args) {
+				var index = event.args.index;
+				console.log("wa_base_name "+index);
+				setWaterAgent(last_base, 0);
+				last_base = BaseTypeData[index].nl;
+				setWaterAgent(last_base, parseFloat($("#wa_base").jqxNumberInput('decimal')));
+				dataRecord.wa_base_name = index;
+				calcWater();
+			}
 		});
 		$('#wa_base').on('change', function (event) {
-			setWaterAgent($("#wa_base_name").val(), parseFloat(event.args.value));
+			var name = BaseTypeData[$("#wa_base_name").val()].nl;
+			setWaterAgent(name, parseFloat(event.args.value));
 			calcWater();
 		});
 		$('#wa_acid_name').on('change', function (event) {
-			setWaterAgent(last_acid, 0);
-			last_acid = event.args.item.value;
-			setWaterAgent(last_acid, parseFloat($("#wa_acid").jqxNumberInput('decimal')));
-			calcWater();
+			if (event.args) {
+				var index = event.args.index;
+				console.log("wa_acid_name "+index);
+				setWaterAgent(last_acid, 0);
+				last_acid = AcidTypeData[index].nl;
+				setWaterAgent(last_acid, parseFloat($("#wa_acid").jqxNumberInput('decimal')));
+				dataRecord.wa_acid_name = index;
+				calcWater();
+			}
 		});
 		$('#wa_acid').on('change', function (event) {
-			setWaterAgent($("#wa_acid_name").val(), parseFloat(event.args.value));
+			var name = AcidTypeData[$("#wa_acid_name").val()].nl;
+			setWaterAgent(name, parseFloat(event.args.value));
 			calcWater();
 		});
 		$('#wa_acid_perc').on('change', function (event) { calcWater(); });
 
-		$('#color_method').on('change', function (event) { calcFermentables(); });
+		$('#color_method').on('change', function (event) {
+			dataRecord.color_method = event.args.index;
+			calcFermentables();
+		});
 		$('#ibu_method').on('change', function (event) {
+			dataRecord.ibu_method = event.args.index;
 			calcFermentables();
 			calcIBUs();
 		});
@@ -1159,6 +1206,7 @@
 			calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal')));     // Keep the OG
 			calcFermentables();
 			calcSVG();
+			calcFG();
 			calcABV();
 			// TODO: adjust the hops, miscs, yeast, water.
 			calcIBUs();
@@ -1173,6 +1221,7 @@
 			$("#boil_size").val(Math.round(new_boil * 100) / 100);
 			calcFermentables();
 			calcSVG();
+			calcFG();
 			calcABV();
 			// TODO: adjust the hops, miscs, yeast, water.
 			calcIBUs();
@@ -1181,6 +1230,7 @@
 			console.log("efficiency change:"+event.args.value);
 			calcFermentables();
 			calcSVG();
+			calcFG();
 			calcABV();
 			calcIBUs();
 		});
@@ -1191,6 +1241,7 @@
 			calcFermentablesFromOG(event.args.value);       // Adjust fermentables amounts
 			calcFermentables();                             // Update the recipe details
 			calcSVG();
+			calcFG();
 			calcABV();                                      // and ABV
 			calcIBUs();                                     // and the IBU's.
 		});
@@ -1208,13 +1259,19 @@
 			calcSparge();
 		});
 		$('#sparge_source').on('change', function (event) {
-			dataRecord.sparge_source= event.args.item.value;
-			calcSparge();
+			if (event.args) {
+				var index = event.args.index;
+				dataRecord.sparge_source= index;
+				calcSparge();
+			}
 		});
 		$('#sparge_acid_type').on('change', function (event) {
-			dataRecord.sparge_acid_type = event.args.item.value;
-			console.log("new sparge_acid_type: "+dataRecord.sparge_acid_type);
-			calcSparge();
+			if (event.args) {
+				var index = event.args.index;
+				dataRecord.sparge_acid_type = index;
+				console.log("new sparge_acid_type: "+dataRecord.sparge_acid_type);
+				calcSparge();
+			}
 		});
 		$('#sparge_acid_perc').on('change', function (event) {
 			dataRecord.sparge_acid_perc = parseFloat(event.args.value);
@@ -1269,8 +1326,8 @@
 		theme: theme,
 		source: styleslist,
 		displayMember: "name",
-		width: 150,
-		height: 27,
+		width: 180,
+		height: 23,
 		dropDownVerticalAlignment: 'top',
 		dropDownWidth: 500,
 		dropDownHeight: 380,
@@ -1288,7 +1345,7 @@
 			$("#st_category_number").val(datarecord.category_number);
 			$("#st_letter").val(datarecord.style_letter);
 			$("#st_guide").val(datarecord.style_guide);
-			$("#st_type").val(datarecord.type);
+			$("#st_type").val(StyleTypeData[datarecord.type].nl);
 			$("#st_og_min").val(datarecord.og_min);
 			$("#st_og_max").val(datarecord.og_max);
 			$("#st_fg_min").val(datarecord.fg_min);
@@ -1312,8 +1369,8 @@
 		theme: theme,
 		source: equipmentlist,
 		displayMember: "name",
-		width: 150,
-		height: 27,
+		width: 170,
+		height: 23,
 		dropDownWidth: 300,
 		renderer: function (index, label, value) {
 			var datarecord = equipmentlist.records[index];
@@ -1368,6 +1425,7 @@
 
 	var dataRecord = {};
 	var url = "includes/db_product.php";
+
 	// Prepare the data
 	var source = {
 		datatype: "json",
@@ -1379,25 +1437,25 @@
 			{ name: 'name', type: 'string' },
 			{ name: 'code', type: 'string' },
 			{ name: 'birth', type: 'string' },
-			{ name: 'stage', type: 'string' },
+			{ name: 'stage', type: 'int' },
 			{ name: 'notes', type: 'string' },
-			{ name: 'log_brew', type: 'bool' },
-			{ name: 'log_fermentation', type: 'bool' },
-			{ name: 'inventory_reduced', type: 'bool' },
-			{ name: 'locked', type: 'bool' },
+			{ name: 'log_brew', type: 'int' },
+			{ name: 'log_fermentation', type: 'int' },
+			{ name: 'inventory_reduced', type: 'int' },
+			{ name: 'locked', type: 'int' },
 			{ name: 'eq_name', type: 'string' },
 			{ name: 'eq_boil_size', type: 'float' },
 			{ name: 'eq_batch_size', type: 'float' },
 			{ name: 'eq_tun_volume', type: 'float' },
 			{ name: 'eq_tun_weight', type: 'float' },
 			{ name: 'eq_tun_specific_heat', type: 'float' },
-			{ name: 'eq_tun_material', type: 'string' },
+			{ name: 'eq_tun_material', type: 'int' },
 			{ name: 'eq_tun_height', type: 'float' },
 			{ name: 'eq_top_up_water', type: 'float' },
 			{ name: 'eq_trub_chiller_loss', type: 'float' },
 			{ name: 'eq_evap_rate', type: 'float' },
 			{ name: 'eq_boil_time', type: 'float' },
-			{ name: 'eq_calc_boil_volume', type: 'bool' },
+			{ name: 'eq_calc_boil_volume', type: 'int' },
 			{ name: 'eq_top_up_kettle', type: 'float' },
 			{ name: 'eq_hop_utilization', type: 'float' },
 			{ name: 'eq_notes', type: 'string' },
@@ -1422,7 +1480,7 @@
 			{ name: 'brew_aboil_sg', type: 'float' },
 			{ name: 'brew_aboil_ph', type: 'float' },
 			{ name: 'brew_aboil_efficiency', type: 'float' },
-			{ name: 'brew_cooling_method', type: 'string' },
+			{ name: 'brew_cooling_method', type: 'int' },
 			{ name: 'brew_cooling_time', type: 'float' },
 			{ name: 'brew_cooling_to', type: 'float' },
 			{ name: 'brew_whirlpool9', type: 'float' },
@@ -1433,11 +1491,11 @@
 			{ name: 'brew_fermenter_extrawater', type: 'float' },
 			{ name: 'brew_aeration_time', type: 'float' },
 			{ name: 'brew_aeration_speed', type: 'float' },
-			{ name: 'brew_aeration_type', type: 'string' },
+			{ name: 'brew_aeration_type', type: 'int' },
 			{ name: 'brew_fermenter_sg', type: 'float' },
 			{ name: 'brew_fermenter_ibu', type: 'float' },
 			{ name: 'brew_date_end', type: 'string' },
-			{ name: 'brew_log_available', type: 'bool' },
+			{ name: 'brew_log_available', type: 'int' },
 			{ name: 'og', type: 'float' },
 			{ name: 'fg', type: 'float' },
 			{ name: 'primary_start_temp', type: 'float' },
@@ -1451,15 +1509,15 @@
 			{ name: 'package_date', type: 'string' },
 			{ name: 'bottle_amount', type: 'float' },
 			{ name: 'bottle_carbonation', type: 'float' },
-			{ name: 'bottle_priming_sugar', type: 'string' },
+			{ name: 'bottle_priming_sugar', type: 'int' },
 			{ name: 'bottle_priming_amount', type: 'float' },
 			{ name: 'bottle_carbonation_temp', type: 'float' },
 			{ name: 'keg_amount', type: 'float' },
 			{ name: 'keg_carbonation', type: 'float' },
-			{ name: 'keg_priming_sugar', type: 'string' },
+			{ name: 'keg_priming_sugar', type: 'int' },
 			{ name: 'keg_priming_amount', type: 'float' },
 			{ name: 'keg_carbonation_temp', type: 'float' },
-			{ name: 'keg_forced_carb', type: 'bool' },
+			{ name: 'keg_forced_carb', type: 'int' },
 			{ name: 'keg_pressure', type: 'float' },
 			{ name: 'taste_notes', type: 'string' },
 			{ name: 'taste_rate', type: 'float' },
@@ -1476,7 +1534,7 @@
 			{ name: 'st_guide', type: 'string' },
 			{ name: 'st_category', type: 'string' },
 			{ name: 'st_category_number', type: 'float' },
-			{ name: 'st_type', type: 'string' },
+			{ name: 'st_type', type: 'int' },
 			{ name: 'st_og_min', type: 'float' },
 			{ name: 'st_og_max', type: 'float' },
 			{ name: 'st_fg_min', type: 'float' },
@@ -1489,7 +1547,7 @@
 			{ name: 'st_carb_max', type: 'float' },
 			{ name: 'st_abv_min', type: 'float' },
 			{ name: 'st_abv_max', type: 'float' },
-			{ name: 'type', type: 'string' },
+			{ name: 'type', type: 'int' },
 			{ name: 'batch_size', type: 'float' },
 			{ name: 'boil_size', type: 'float' },
 			{ name: 'boil_time', type: 'float' },
@@ -1498,20 +1556,20 @@
 			{ name: 'est_fg', type: 'float' },
 			{ name: 'est_abv', type: 'float' },
 			{ name: 'est_color', type: 'float' },
-			{ name: 'color_method', type: 'string' },
+			{ name: 'color_method', type: 'int' },
 			{ name: 'est_ibu', type: 'float' },
-			{ name: 'ibu_method', type: 'string' },
+			{ name: 'ibu_method', type: 'int' },
 			{ name: 'est_carb', type: 'float' },
 			{ name: 'sparge_temp', type: 'float' },
 			{ name: 'sparge_ph', type: 'float' },
 			{ name: 'sparge_volume', type: 'float' },
-			{ name: 'sparge_source', type: 'string' },
-			{ name: 'sparge_acid_type', type: 'string' },
+			{ name: 'sparge_source', type: 'int' },
+			{ name: 'sparge_acid_type', type: 'int' },
 			{ name: 'sparge_acid_perc', type: 'float' },
 			{ name: 'sparge_acid_amount', type: 'float' },
 			{ name: 'mash_ph', type: 'float' },
 			{ name: 'mash_name', type: 'string' },
-			{ name: 'calc_acid', type: 'bool' },
+			{ name: 'calc_acid', type: 'int' },
 			{ name: 'w1_name', type: 'string' },
 			{ name: 'w1_amount', type: 'float' },
 			{ name: 'w1_calcium', type: 'float' },
@@ -1532,11 +1590,14 @@
 			{ name: 'w2_total_alkalinity', type: 'float' },
 			{ name: 'w2_ph', type: 'float' },
 			{ name: 'w2_cost', type: 'float' },
+			{ name: 'wa_acid_name', type: 'int' },
+			{ name: 'wa_acid_perc', type: 'int' },
+			{ name: 'wa_base_name', type: 'int' },
 			{ name: 'fermentables', type: 'array' },
-			{ name: 'hops', type: 'string' },
-			{ name: 'miscs', type: 'string' },
-			{ name: 'yeasts', type: 'string' },
-			{ name: 'mashs', type: 'string' }
+			{ name: 'hops', type: 'array' },
+			{ name: 'miscs', type: 'array' },
+			{ name: 'yeasts', type: 'array' },
+			{ name: 'mashs', type: 'array' }
 		],
 		id: 'record',
 		url: url + '?record=' + my_record
@@ -1717,54 +1778,42 @@
 			$("#w2_total_alkalinity").val(dataRecord.w2_total_alkalinity);
 			$("#w2_ph").val(dataRecord.w2_ph);
 			$("#w2_cost").val(dataRecord.w2_cost);
+			$("#wa_acid_name").val(dataRecord.wa_acid_name);
+			$("#wa_acid_perc").val(dataRecord.wa_acid_perc);
+			$("#wa_base_name").val(dataRecord.wa_base_name);
 			editFermentable(dataRecord);
 			editHop(dataRecord);
                         editMisc(dataRecord);
                         editYeast(dataRecord);
                         editMash(dataRecord);
 
-			switch (dataRecord.stage) {
-				case 'Plan':		brewstage = 0;	break;
-				case 'Wait':		brewstage = 1;	break;
-				case 'Brew':		brewstage = 2;	break;
-				case 'Primary':		brewstage = 3;	break;
-				case 'Secondary':	brewstage = 4;	break;
-				case 'Tertiary':	brewstage = 5;	break;
-				case 'Package':		brewstage = 6;	break;
-				case 'Carbonation':	brewstage = 7;	break;
-				case 'Mature':		brewstage = 8;	break;
-				case 'Taste':		brewstage = 9;	break;
-				case 'Ready':		brewstage = 10;
-							$("#locked").jqxCheckBox({ disabled:false });
-							break;
-				case 'Closed':		brewstage = 11;
-							$("#locked").jqxCheckBox({ disabled:false });
-							break;
+			if (dataRecord.stage >= 10) {
+				$("#locked").jqxCheckBox({ disabled:false });
 			}
 			// Enable or Disable settings depending on the stage.
-			if (brewstage > 1)
+			if (dataRecord.stage > 1)
 				$("#equipmentSelect").jqxDropDownList({ disabled: true });
-			if (brewstage > 0) {
+			if (dataRecord.stage > 0) {
 				$("#Delete").jqxButton({ disabled: true });
 			}
-			if (brewstage < 3) {
+			if (dataRecord.stage < 3) {
 				$('#jqxTabs').jqxTabs('disableAt', 9);
 				// If recipe not complete, disable 8 too.
 			} else {
 				$('#jqxTabs').jqxTabs('enableAt', 9);
 			}
-			if (brewstage < 4) { // At least primary
+			if (dataRecord.stage < 4) { // At least primary
 				$('#jqxTabs').jqxTabs('disableAt', 10);
 			} else {
 				$('#jqxTabs').jqxTabs('enableAt', 10);
 			}
-			if (brewstage < 6) {
+			if (dataRecord.stage < 6) {
 				$("#inventory_reduced").jqxCheckBox({ disabled : true });
 			} else {
 				if ($('#inventory_reduced').jqxCheckBox('checked'))
 					$("#inventory_reduced").jqxCheckBox({ disabled : true });
 			}
-			if (brewstage < 8) { // Taste when at least Mature.
+			if (dataRecord.stage < 8) { // Taste when at least Mature.
 				$('#jqxTabs').jqxTabs('disableAt', 11);
 			} else {
 				$('#jqxTabs').jqxTabs('enableAt', 11);
@@ -1785,13 +1834,15 @@
                 var fermentableSource = {
                         localdata: data.fermentables,
                         datatype: "local",
+			cache: false,
+			async: false,
                         datafields: [
                                 { name: 'f_name', type: 'string' },
                                 { name: 'f_origin', type: 'string' },
                                 { name: 'f_supplier', type: 'string' },
                                 { name: 'f_amount', type: 'float' },
                                 { name: 'f_cost', type: 'float' },
-                                { name: 'f_type', type: 'string' },
+                                { name: 'f_type', type: 'int' },
                                 { name: 'f_yield', type: 'float' },
                                 { name: 'f_color', type: 'float' },
                                 { name: 'f_coarse_fine_diff', type: 'float' },
@@ -1799,14 +1850,17 @@
                                 { name: 'f_diastatic_power', type: 'float' },
                                 { name: 'f_protein', type: 'float' },
                                 { name: 'f_max_in_batch', type: 'float' },
-                                { name: 'f_graintype', type: 'string' },
-                                { name: 'f_added', type: 'string' },
+                                { name: 'f_graintype', type: 'int' },
+                                { name: 'f_added', type: 'int' },
                                 { name: 'f_dissolved_protein', type: 'float' },
-                                { name: 'f_recommend_mash', type: 'bool' },
-                                { name: 'f_add_after_boil', type: 'bool' },
-                                { name: 'f_adjust_to_total_100', type: 'bool' },
+                                { name: 'f_recommend_mash', type: 'int' },
+                                { name: 'f_add_after_boil', type: 'int' },
+                                { name: 'f_adjust_to_total_100', type: 'int' },
                                 { name: 'f_percentage', type: 'float' },
-                                { name: 'f_di_ph', type: 'float' }
+                                { name: 'f_di_ph', type: 'float' },
+				{ name: 'f_acid_to_ph_57', type: 'float' },
+				{ name: 'f_inventory', type: 'float' },
+				{ name: 'f_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
                                 commit(true);
@@ -1817,13 +1871,11 @@
                 };
                 var fermentableAdapter = new $.jqx.dataAdapter(fermentableSource);
                 $("#fermentableGrid").jqxGrid({
-                        width: 1150,
-                        height: 400,
+                        width: 1240,
+                        height: 450,
                         source: fermentableAdapter,
                         theme: theme,
                         selectionmode: 'singlerow',
-                        editmode: 'selectedcell',
-                        editable: true,
                         localization: getLocalization(),
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -1838,6 +1890,7 @@
                                 $("#faddrowbutton").jqxDropDownList({
                                         placeHolder: "Kies mout:",
                                         theme: theme,
+					template: "primary",
                                         source: fermentablelist,
                                         displayMember: "name",
                                         width: 150,
@@ -1870,13 +1923,13 @@
                                                 row["f_max_in_batch"] = datarecord.max_in_batch;
                                                 row["f_graintype"] = datarecord.graintype;
                                                 if (datarecord.add_after_boil) {
-                                                        row["f_added"] = "Primary";
-                                                } else if ((datarecord.type == "Sugar") || (datarecord.type == "Adjunct")) {
-                                                        row["f_added"] = "Boil";
+                                                        row["f_added"] = 2;	// Fermentation
+                                                } else if ((datarecord.type == 1) || (datarecord.type == 4)) {	// Sugar or Adjunct
+                                                        row["f_added"] = 1;	// Boil
                                                 } else {
-                                                        row["f_added"] = "Mash";
+                                                        row["f_added"] = 0;	// Mash
                                                 }
-                                                row["f_dissolved_protein"] = 0;
+                                                row["f_dissolved_protein"] = datarecord.dissolved_protein;
                                                 row["f_recommend_mash"] = datarecord.recommend_mash;
                                                 row["f_add_after_boil"] = datarecord.add_after_boil;
                                                 if (rowscount == 0) {
@@ -1888,6 +1941,8 @@
                                                         row["f_percentage"] = 0;
                                                 }
                                                 row["f_di_ph"] = datarecord.di_ph;
+						row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57;
+						row["f_inventory"] = datarecord.inventory;
                                                 var commit = $("#fermentableGrid").jqxGrid('addrow', null, row);
                                         }
                                 });
@@ -1899,7 +1954,7 @@
                                 });
 
                                 // delete selected fermentable.
-                                $("#fdeleterowbutton").jqxButton({ theme: theme, height: 27, width: 150 });
+                                $("#fdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                 $("#fdeleterowbutton").on('click', function () {
                                         var selectedrowindex = $("#fermentableGrid").jqxGrid('getselectedrowindex');
                                         var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
@@ -1936,6 +1991,7 @@
                                         }
                                         calcFermentables();
                                         calcSVG();
+					calcFG();
                                         calcABV();
                                         calcIBUs();
                                 });
@@ -1945,137 +2001,43 @@
                                 $('#jqxTabs').jqxTabs('next');
                         },
                         columns: [
-                                { text: 'Vergistbaar ingredi&euml;nt', editable: false, datafield: 'f_name',
+                                { text: 'Vergistbaar ingredi&euml;nt', datafield: 'f_name',
                                   cellsrenderer:  function (row, columnfield, value, defaulthtml, columnproperties) {
                                         var rowData = $("#fermentableGrid").jqxGrid('getrowdata', row);
                                         return "<span style='margin: 3px; margin-top: 6px; float: "+
                                                 columnproperties.cellsalign+"'>" +rowData.f_supplier+" / "+rowData.f_name+" ("+rowData.f_color+" EBC)</span>";
                                   }
                                 },
-                                { text: 'Type', editable: false, align: 'center', cellsalign: 'center', width: 100, datafield: 'f_type' },
-                                { text: 'Moment', width: 110, align: 'center', cellsalign: 'center', datafield: 'f_added', columntype: 'dropdownlist',
-                                  createeditor: function (row, column, editor) {
-                                        var srcAdded = [ "Mash", "Boil", "Fermentation", "Lagering", "Bottle" ];
-                                        editor.jqxDropDownList({ autoDropDownHeight: true, source: srcAdded });
-                                  }
-                                },
-                                { text: 'Opbrengst', editable: false, datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
-                                { text: 'Gewicht Kg', datafield: 'f_amount', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f3',
-                                  columntype: 'numberinput',
-                                  validation: function (cell, value) {
-                                        // Maximum weight is the batch_size, just a simple check.
-                                        var maxmout = parseFloat($("#batch_size").jqxNumberInput('decimal'));
-                                        if (value < 0 || value > maxmout) {
-                                                return { result: false, message: "Gewicht moet 0-"+maxmout+" zijn" };
-                                        }
-                                        return true;
-                                  },
-                                  initeditor: function (row, cellvalue, editor) {
-                                        editor.jqxNumberInput({ inputMode: 'simple', min: 0, decimalDigits: 3, spinButtons: false });
-                                  },
-                                  cellvaluechanging: function (row, column, columntype, oldvalue, newvalue) {
-                                        if (to_100) {
-                                                return oldvalue;        // When using percentages, don't allow edited results.
-                                        }
+                                { text: 'Type', width: 100, datafield: 'f_type',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + FermentableTypeData[value].nl + "</div>";
+				  }
+			       	},
+                                { text: 'Moment', width: 110, datafield: 'f_added',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + AddedData[value].nl + "</div>";
                                   }
                                 },
-                                { text: 'Percentage', datafield: 'f_percentage', width: 110, align: 'right', cellsalign: 'right', cellsformat: 'p1',
-                                  columntype: 'numberinput',
-                                  validation: function (cell, value) {
-                                        if (value < 0 || value > 100) {
-                                                return { result: false, message: "Percentage moet 0-100 zijn" };
-                                        }
-                                        return true;
-                                  },
-                                  initeditor: function (row, cellvalue, editor) {
-                                        editor.jqxNumberInput({ decimalDigits: 1, min: 0, max: 100, spinButtons: false });
-                                  },
-                                  cellvaluechanging: function (row, column, columntype, oldvalue, newvalue) {
-                                        oldvalue = Math.round(oldvalue * 10) / 10.0;
-                                        var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
-                                        if ((oldvalue != newvalue) && (rowscount > 1)) {
-                                                var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', row);
-                                                if (rowdata.f_adjust_to_total_100) {
-                                                        return oldvalue;
-                                                }
-                                                var diff = newvalue - oldvalue;
-                                                var tw = 0;     // total weight
-                                                for (i = 0; i < rowscount; i++) {
-                                                        var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-                                                        tw += rowdata.f_amount;
-                                                }
-                                                if (to_100) {
-                                                        // Adjust this row and the 100% row.
-                                                        var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', row);
-                                                        rowdata.f_amount += tw * diff / 100;
-                                                        for (i = 0; i < rowscount; i++) {
-                                                                var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-                                                                if (rowdata.f_adjust_to_total_100) {
-                                                                        rowdata.f_percentage -= diff;
-                                                                        rowdata.f_amount -= tw * diff / 100;
-                                                                }
-                                                        }
-                                                } else {
-                                                        // Adjust all the rows.
-                                                        var nw = tw * diff / 100;
-                                                        for (i = 0; i < rowscount; i++) {
-                                                                var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-                                                                if (i == row) {
-                                                                        rowdata.f_amount += nw;
-                                                                } else {
-                                                                        rowdata.f_amount -= nw / (rowscount - 1);
-                                                                        rowdata.f_percentage = Math.round((rowdata.f_amount / tw) * 1000) / 10.0;
-                                                                }
-                                                        }
-                                                }
-                                        }
-                                  }
-                                },
-                                { text: '100%', align: 'center', datafield: 'f_adjust_to_total_100', columntype: 'checkbox', width: 80,
-                                  cellvaluechanging: function (row, column, columntype, oldvalue, newvalue) {
-                                        if (to_100) {
-                                                var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
-                                                for (i = 0; i < rowscount; i++) {
-                                                        if (i != row) {
-                                                                var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-                                                                rowdata.f_adjust_to_total_100 = false;
-                                                        }
-                                                }
-                                        }
-                                  }
-                                }
+                                { text: 'Opbrengst', datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
+                                { text: 'Gewicht Kg', datafield: 'f_amount', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f3' },
+                                { text: 'Percent', datafield: 'f_percentage', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
+                                { text: '100%', align: 'center', datafield: 'f_adjust_to_total_100', columntype: 'checkbox', width: 70 },
+				{ text: 'Wijzig', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
+					return "Wijzig";
+					}, buttonclick: function (row) {
+						fermentableRow = row;
+						fermentableData = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
+						$("#wf_name").val(fermentableData.f_name);
+						$("#wf_amount").val(fermentableData.f_amount);
+						$("#wf_percentage").val(fermentableData.f_percentage);
+						$("#wf_adjust_to_total_100").val(fermentableData.f_adjust_to_total_100);
+						$("#wf_added").val(fermentableData.f_added);
+						// show the popup window.
+						$("#popupFermentable").jqxWindow('open');
+					}
+				}
                         ]
                 });
-                $("#fermentableGrid").on('cellendedit', function (event) {
-                        var args = event.args;
-                        console.log("Event Type: cellendedit, Column: " + args.datafield + ", Row: " + (args.rowindex) + ", Value: " + args.value);
-                        // Make sure the grid itself is updated.
-                        $("#fermentableGrid").jqxGrid('setcellvalue', args.rowindex, args.datafield, args.value);
-                        if ((args.datafield == 'f_amount') && (! to_100)) {
-                                // If one of the amounts is changed, recalculate the percentages.
-                                console.log("adjust percentages");
-                                var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
-                                if (rowscount > 1) {
-                                        var tw = 0;
-                                        for (i = 0; i < rowscount; i++) {
-                                                var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-                                                tw += rowdata.f_amount;
-                                        };
-                                        for (i = 0; i < rowscount; i++) {
-                                                var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-                                                var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
-                                                $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
-                                        };
-                                } else {
-                                        $("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
-                                }
-                        };
-                        $('#fermentableGrid').jqxGrid('sortby', 'f_amount', 'desc');    // TODO: not reliable
-                        calcFermentables();
-                        calcSVG();
-                        calcABV();
-                        calcIBUs();     // Depends on gravity, so recalculate.
-                });
         };
 
         // Inline hops editor
@@ -2084,14 +2046,15 @@
                         localdata: data.hops,
                         datatype: "local",
                         cache: false,
+			async: false,
                         datafields: [
                                 { name: 'h_name', type: 'string' },
                                 { name: 'h_origin', type: 'string' },
                                 { name: 'h_amount', type: 'float' },
                                 { name: 'h_cost', type: 'float' },
-                                { name: 'h_type', type: 'string' },
-                                { name: 'h_form', type: 'string' },
-                                { name: 'h_useat', type: 'string' },
+                                { name: 'h_type', type: 'int' },
+                                { name: 'h_form', type: 'int' },
+                                { name: 'h_useat', type: 'int' },
                                 { name: 'h_time', type: 'float' },
                                 { name: 'h_alpha', type: 'float' },
                                 { name: 'h_beta', type: 'float' },
@@ -2101,7 +2064,8 @@
                                 { name: 'h_cohumulone', type: 'float' },
                                 { name: 'h_myrcene', type: 'float' },
                                 { name: 'h_total_oil', type: 'float' },
-                                { name: 'h_weight', type: 'float' }
+				{ name: 'h_inventory', type: 'float' },
+				{ name: 'h_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
                                 commit(true);
@@ -2110,28 +2074,13 @@
                                 commit(true);
                         }
                 };
-                var hopAdapter = new $.jqx.dataAdapter(hopSource, {
-                        beforeLoadComplete: function (records) {
-                                var data = new Array();
-                                for (var i = 0; i < records.length; i++) {
-                                        var row = records[i];
-                                        row.h_weight = row.h_amount * 1000;
-                                        data.push(row);
-                                }
-                                return data;
-                        },
-                        loadError: function(jqXHR, status, error) {
-                                $('#err').text(status + ' ' + error);
-                        },
-                });
+                var hopAdapter = new $.jqx.dataAdapter(hopSource);
                 $("#hopGrid").jqxGrid({
-                        width: 1050,
-                        height: 400,
+                        width: 1240,
+                        height: 510,
                         source: hopAdapter,
                         theme: theme,
                         selectionmode: 'singlerow',
-                        editmode: 'selectedcell',
-                        editable: true,
                         localization: getLocalization(),
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2141,11 +2090,12 @@
                                 container.append('<div style="float: left; margin-left: 165px;" id="haddrowbutton"></div>');
                                 container.append('<div style="float: left; margin-left: 10px; margin-top: 5px;">In voorraad:</div>');
                                 container.append('<div style="float: left; margin-left: 10px;" id="hinstockbutton"></div>');
-                                container.append('<input style="float: left; margin-left: 280px;" id="hdeleterowbutton" type="button" value="Verwijder hop" />');
+                                container.append('<input style="float: left; margin-left: 400px;" id="hdeleterowbutton" type="button" value="Verwijder hop" />');
                                 // add hop from dropdownlist.
                                 $("#haddrowbutton").jqxDropDownList({
                                         placeHolder: "Kies hop:",
                                         theme: theme,
+					template: "primary",
                                         source: hoplist,
                                         displayMember: "name",
                                         width: 150,
@@ -2168,7 +2118,7 @@
                                                 row["h_cost"] = datarecord.cost;
                                                 row["h_type"] = datarecord.type;
                                                 row["h_form"] = datarecord.form;
-                                                row["h_useat"] = datarecord.useat;
+                                                row["h_useat"] = 2;	// Boil
                                                 row["h_time"] = 0;
                                                 row["h_alpha"] = datarecord.alpha;
                                                 row["h_beta"] = datarecord.beta;
@@ -2178,7 +2128,7 @@
                                                 row["h_cohumulone"] = datarecord.cohumulone;
                                                 row["h_myrcene"] = datarecord.myrcene;
                                                 row["h_total_oil"] = datarecord.total_oil;
-                                                row["h_weight"] = 0;
+						row["h_inventory"] = datarecord.inventory;
                                                 var commit = $("#hopGrid").jqxGrid('addrow', null, row);
                                         }
                                 });
@@ -2190,7 +2140,7 @@
                                 });
 
                                 // delete selected hop.
-                                $("#hdeleterowbutton").jqxButton({ theme: theme, height: 27, width: 150 });
+                                $("#hdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                 $("#hdeleterowbutton").on('click', function () {
                                         var selectedrowindex = $("#hopGrid").jqxGrid('getselectedrowindex');
                                         var rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount;
@@ -2198,80 +2148,48 @@
                                                 var id = $("#hopGrid").jqxGrid('getrowid', selectedrowindex);
                                                 var commit = $("#hopGrid").jqxGrid('deleterow', id);
                                         }
+					calcIBUs();
                                 });
                         },
                         ready: function() {
+				calcIBUs();
                                 $('#jqxTabs').jqxTabs('next');
                         },
                         columns: [
-                                { text: 'Hop', editable: false, datafield: 'h_name',
+                                { text: 'Hop', datafield: 'h_name',
                                   cellsrenderer: function (row, columnfield, value, defaulthtml, columnproperties) {
                                         var rowData = $("#hopGrid").jqxGrid('getrowdata', row);
                                         return "<span style='margin: 3px; margin-top: 6px; float: "+
                                                 columnproperties.cellsalign+"'>" +rowData.h_origin+" / "+rowData.h_name+"</span>";
                                   },
                                 },
-                                { text: 'Type', editable: false, width: 90, align: 'center', cellsalign: 'center', datafield: 'h_type' },
-                                { text: 'Vorm', editable: false, width: 90, align: 'center', cellsalign: 'center', datafield: 'h_form' },
-                                { text: 'Alpha', editable: false, datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
-                                { text: 'Amount', hidden: true, datafield: 'h_amount' },
-                                { text: 'Gewicht gr', datafield: 'h_weight', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f1',
-                                  columntype: 'numberinput',
-                                  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
-                                        return "<div style='margin: 4px;' class='jqx-right-align'>" + dataAdapter.formatNumber(value, "f1") + " gr</div>";
-                                  },
-                                  initeditor: function (row, cellvalue, editor, celltext, pressedChar) {
-                                        editor.jqxNumberInput({
-                                                inputMode: 'simple', decimalDigits: 1, min: 0, max: parseFloat(dataRecord.batch_size * 200),
-                                                spinButtons: false
-                                        });
-                                  },
-                                  validation: function (cell, value) {
-                                        var maxhops = parseFloat(dataRecord.batch_size) * 200;
-                                        if (value < 0 || value > maxhops ) {
-                                                return { result: false, message: "Gewicht moet tussen 0 en "+maxhops+" gram zijn" };
-                                        }
-                                        return true;
-                                  }
-                                },
-                                { text: 'Gebruik', width: 110, align: 'center', cellsalign: 'center', datafield: 'h_useat', columntype: 'dropdownlist',
-                                  createeditor: function (row, column, editor) {
-                                          var srcUse = [ "Boil", "Dry Hop", "Mash", "First Wort", "Aroma" ];
-                                          editor.jqxDropDownList({ autoDropDownHeight: true, source: srcUse });
-                                  },
-                                  cellvaluechanging: function (row, column, columntype, oldvalue, newvalue) {
-                                        if ((newvalue == "Mash") || (newvalue == "First Wort")) {
-                                                $("#hopGrid").jqxGrid('setcellvalue', row, "h_time", parseFloat(dataRecord.boil_time));
-                                        } else if (newvalue == "Aroma") {
-                                                $("#hopGrid").jqxGrid('setcellvalue', row, "h_time", 0);
-                                        }
-                                  }
-                                },
-                                { text: 'Tijd', datafield: 'h_time', width: 70, align: 'right', cellsalign: 'right', cellsformat: 'f0',
-                                  columntype: 'numberinput',
-                                  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
-                                        if ((rowdata.h_useat == "Boil") || (rowdata.h_useat == "Dry Hop") || (rowdata.h_useat == "Dry hop"))
-                                                return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+"</div>";
-                                        else
-                                                return "<div style='margin: 4px;' class='jqx-right-align'> </div>";
-                                  },
-                                  initeditor: function (row, cellvalue, editor, celltext, pressedChar) {
-                                        editor.jqxNumberInput({ decimalDigits: 0, digits: 3, min: 0, max: parseFloat(dataRecord.boil_time) });
-                                  },
-                                  cellvaluechanging: function (row, column, columntype, oldvalue, newvalue) {
-                                        var use = $("#hopGrid").jqxGrid('getcellvalue', row, "h_useat");
-                                        if ((use == "Mash") || (use == "First Wort") || (use == "First wort") || (use == "Aroma"))
-                                                return oldvalue;
-                                  },
-                                  validation: function (cell, value) {
-                                        var high = parseFloat(dataRecord.boil_time);
-                                        if (value < 0 || value > high ) {
-                                                return { result: false, message: "De tijd moet  0-"+high+" zijn" };
-                                        }
-                                        return true;
-                                  }
-                                },
-                                { text: 'IBU', editable: false, datafield: 'ibu', width: 80, align: 'right',
+                                { text: 'Type', width: 90, datafield: 'h_type',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + HopTypeData[value].nl + "</div>";
+				  }
+			       	},
+                                { text: 'Vorm', width: 90, datafield: 'h_form',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + HopFormData[value].nl + "</div>";
+				  }
+			       	},
+                                { text: 'Alpha', datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
+				{ text: 'Gebruik', width: 110, datafield: 'h_useat',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + HopUseData[value].nl + "</div>";
+				  }
+				},
+				{ text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4))   // Boil, Whirlpool
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" min.</div>";
+					if (rowdata.h_useat == 5)       // Dry hop
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value/1440, "f0")+" dagen</div>";
+					else
+						return "<div style='margin: 4px;'></div>";
+				  }
+				},
+                                { text: 'IBU', datafield: 'ibu', width: 80, align: 'right',
                                   cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
                                         var ibu = toIBU(rowdata.h_useat,
                                                           rowdata.h_form,
@@ -2282,20 +2200,49 @@
                                                           parseFloat(rowdata.h_alpha),
                                                           $("#ibu_method").val()
                                                          );
-                                        calcIBUs();
                                         return "<div style='margin: 4px;' class='jqx-right-align'>" + dataAdapter.formatNumber(ibu, "f1") + "</div>";
                                   }
-                                }
+                                },
+				{ text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right', cellsalign: 'right',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					if (value < 1)
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value * 1000, "f1")+" gr</div>";
+					else
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f1")+" kg</div>";
+				  }
+				},
+				{ text: 'Voorraad', datafield: 'h_inventory', width: 110, align: 'right', cellsalign: 'right',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					if (value < 1)
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value * 1000, "f1")+" gr</div>";
+					else
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f1")+" kg</div>";
+				  }
+				},
+				{ text: 'Wijzig', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
+					return "Wijzig";
+					}, buttonclick: function (row) {
+						hopRow = row;
+						hopData = $("#hopGrid").jqxGrid('getrowdata', hopRow);
+						$("#wh_name").val(hopData.h_name);
+						$("#wh_amount").val(hopData.h_amount * 1000);
+						var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg,
+							parseFloat($("#batch_size").jqxNumberInput('decimal')),
+							parseFloat(hopData.h_amount), parseFloat(hopData.h_time),
+							parseFloat(hopData.h_alpha), $("#ibu_method").val()
+						);
+						$("#wh_ibu").val(ibu);
+						if (hopData.h_useat == 5)       // Dry hop
+							$("#wh_time").val(hopData.h_time / 1440);
+						else
+							$("#wh_time").val(hopData.h_time);
+						$("#wh_useat").val(hopData.h_useat);
+						// show the popup window.
+						$("#popupHop").jqxWindow('open');
+					}
+				}
                         ]
                 });
-                $("#hopGrid").on('cellendedit', function (event) {
-                        var args = event.args;
-                        console.log("Event Type: cellendedit, Column: " + args.datafield + ", Row: " + (args.rowindex) + ", Value: " + args.value);
-                        $("#hopGrid").jqxGrid('setcellvalue', args.rowindex, args.datafield, args.value);
-                        if (args.datafield == 'h_weight')
-                                $("#hopGrid").jqxGrid('setcellvalue', args.rowindex, 'h_amount', args.value / 1000);
-                        //$('#hopGrid').jqxGrid('sortby', 'f_amount', 'desc');
-                });
         };
 
         // Inline miscs editor
@@ -2304,15 +2251,17 @@
                         localdata: data.miscs,
                         datatype: "local",
                         cache: false,
+			async: false,
                         datafields: [
                                 { name: 'm_name', type: 'string' },
                                 { name: 'm_amount', type: 'float' },
                                 { name: 'm_cost', type: 'float' },
-                                { name: 'm_type', type: 'string' },
-                                { name: 'm_use_use', type: 'string' },
+                                { name: 'm_type', type: 'int' },
+                                { name: 'm_use_use', type: 'int' },
                                 { name: 'm_time', type: 'float' },
-                                { name: 'm_amount_is_weight', type: 'bool' },
-                                { name: 'm_weight', type: 'float' }
+                                { name: 'm_amount_is_weight', type: 'int' },
+				{ name: 'm_inventory', type: 'float' },
+				{ name: 'm_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
                                 commit(true);
@@ -2326,52 +2275,51 @@
                                 var data = new Array();
                                 for (var i = 0; i < records.length; i++) {
                                         var row = records[i];
-                                        row.m_weight = row.m_amount * 1000;
                                         data.push(row);
                                         // Initial set water agent values.
                                         switch (row.m_name) {
-                                                case 'CaCl2':           $("#wa_cacl2").val(row.m_weight);
+                                                case 'CaCl2':           $("#wa_cacl2").val(row.m_amount * 1000);
                                                                         break;
-                                                case 'CaSO4':           $("#wa_caso4").val(row.m_weight);
+                                                case 'CaSO4':           $("#wa_caso4").val(row.m_amount * 1000);
                                                                         break;
-                                                case 'MgSO4':           $("#wa_mgso4").val(row.m_weight);
+                                                case 'MgSO4':           $("#wa_mgso4").val(row.m_amount * 1000);
                                                                         break;
-                                                case 'NaCl':            $("#wa_nacl").val(row.m_weight);
+                                                case 'NaCl':            $("#wa_nacl").val(row.m_amount * 1000);
                                                                         break;
-                                                case 'Melkzuur':        $("#wa_acid_name").val('Melkzuur');
-                                                                        $("#wa_acid").val(row.m_weight);
+                                                case 'Melkzuur':        $("#wa_acid_name").val(0);
+                                                                        $("#wa_acid").val(row.m_amount * 1000);
                                                                         $("#wa_acid_perc").val(80);
                                                                         last_acid = 'Melkzuur';
                                                                         break;
-                                                case 'Zoutzuur':        $("#wa_acid_name").val('Zoutzuur');
-                                                                        $("#wa_acid").val(row.m_weight);
+                                                case 'Zoutzuur':        $("#wa_acid_name").val(1);
+                                                                        $("#wa_acid").val(row.m_amount * 1000);
                                                                         $("#wa_acid_perc").val(80);
                                                                         last_acid = 'Zoutzuur';
                                                                         break;
-                                                case 'Fosforzuur':      $("#wa_acid_name").val('Fosforzuur');
-                                                                        $("#wa_acid").val(row.m_weight);
+                                                case 'Fosforzuur':      $("#wa_acid_name").val(2);
+                                                                        $("#wa_acid").val(row.m_amount * 1000);
                                                                         $("#wa_acid_perc").val(80);
                                                                         last_acid = 'Fosforzuur';
                                                                         break;
-                                                case 'Zwavelzuur':      $("#wa_acid_name").val('Zwavelzuur');
-                                                                        $("#wa_acid").val(row.m_weight);
+                                                case 'Zwavelzuur':      $("#wa_acid_name").val(3);
+                                                                        $("#wa_acid").val(row.m_amount * 1000);
                                                                         $("#wa_acid_perc").val(80);
                                                                         last_acid = 'Zwavelzuur';
                                                                         break;
-                                                case 'NaHCO3':          $("#wa_base_name").val('NaHCO3');
-                                                                        $("#wa_base").val(row.m_weight);
+                                                case 'NaHCO3':          $("#wa_base_name").val(0);
+                                                                        $("#wa_base").val(row.m_amount * 1000);
                                                                         last_base = 'NaHCO3';
                                                                         break;
-                                                case 'Na2CO3':          $("#wa_base_name").val('Na2CO3');
-                                                                        $("#wa_base").val(row.m_weight);
+                                                case 'Na2CO3':          $("#wa_base_name").val(1);
+                                                                        $("#wa_base").val(row.m_amount * 1000);
                                                                         last_base = 'Na2CO3';
                                                                         break;
-                                                case 'CaCO3':           $("#wa_base_name").val('CaCO3');
-                                                                        $("#wa_base").val(row.m_weight);
+                                                case 'CaCO3':           $("#wa_base_name").val(2);
+                                                                        $("#wa_base").val(row.m_amount * 1000);
                                                                         last_base = 'CaCO3';
                                                                         break;
-                                                case 'Ca(OH)2':         $("#wa_base_name").val('Ca(OH)2');
-                                                                        $("#wa_base").val(row.m_weight);
+                                                case 'Ca(OH)2':         $("#wa_base_name").val(3);
+                                                                        $("#wa_base").val(row.m_amount * 1000);
                                                                         last_base = 'Ca(OH)2';
                                                                         break;
                                         }
@@ -2383,13 +2331,11 @@
                         },
                 });
                 $("#miscGrid").jqxGrid({
-                        width: 960,
-                        height: 400,
+                        width: 1240,
+                        height: 525,
                         source: miscAdapter,
                         theme: theme,
                         selectionmode: 'singlerow',
-                        editmode: 'selectedcell',
-                        editable: true,
                         localization: getLocalization(),
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2399,11 +2345,12 @@
                                 container.append('<div style="float: left; margin-left: 165px;" id="maddrowbutton"></div>');
                                 container.append('<div style="float: left; margin-left: 10px; margin-top: 5px;">In voorraad:</div>');
                                 container.append('<div style="float: left; margin-left: 10px;" id="minstockbutton"></div>');
-                                container.append('<input style="float: left; margin-left: 200px;" id="mdeleterowbutton" type="button" value="Verwijder ingredient" />');
+                                container.append('<input style="float: left; margin-left: 400px;" id="mdeleterowbutton" type="button" value="Verwijder ingredient" />');
                                 // add misc from dropdownlist.
                                 $("#maddrowbutton").jqxDropDownList({
-                                        placeHolder: "Kies ingredient:",
+                                        placeHolder: "Kies ingredi&euml;nt:",
                                         theme: theme,
+					template: "primary",
                                         source: misclist,
                                         displayMember: "name",
                                         width: 150,
@@ -2422,8 +2369,8 @@
                                                 row["m_type"] = datarecord.type;
                                                 row["m_use_use"] = datarecord.use_use;
                                                 row["m_time"] = 0;
-                                                row["m_weight"] = 0;
                                                 row["m_amount_is_weight"] = datarecord.amount_is_weight;
+						row["m_inventory"] = datarecord.inventory;
                                                 var commit = $("#miscGrid").jqxGrid('addrow', null, row);
                                         }
                                 });
@@ -2433,12 +2380,12 @@
                                         misclist.dataBind();
                                 });
                                 // delete selected misc.
-                                $("#mdeleterowbutton").jqxButton({ theme: theme, height: 27, width: 150 });
+                                $("#mdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                 $("#mdeleterowbutton").on('click', function () {
                                         var selectedrowindex = $("#miscGrid").jqxGrid('getselectedrowindex');
                                         var rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount;
                                         var type = $("#miscGrid").jqxGrid('getcellvalue', selectedrowindex, "m_type");
-                                        if (selectedrowindex >= 0 && selectedrowindex < rowscount && type != "Water agent")  {
+                                        if (selectedrowindex >= 0 && selectedrowindex < rowscount && type != 4)  {	// Water agent
                                                 var id = $("#miscGrid").jqxGrid('getrowid', selectedrowindex);
                                                 var commit = $("#miscGrid").jqxGrid('deleterow', id);
                                         }
@@ -2448,84 +2395,64 @@
                                 $('#jqxTabs').jqxTabs('next');
                         },
                         columns: [
-                                { text: 'Ingredient', editable: false, datafield: 'm_name' },
-                                { text: 'Type', editable: false, width: 120, align: 'center', cellsalign: 'center', datafield: 'm_type' },
-                                { text: 'Gebruik', width: 110, align: 'center', cellsalign: 'center', datafield: 'm_use_use', columntype: 'dropdownlist',
-                                  createeditor: function (row, column, editor) {
-                                        var srcUseUse = [ "Mash", "Boil", "Primary", "Secondary", "Bottling" ];
-                                        editor.jqxDropDownList({ autoDropDownHeight: true, source: srcUseUse });
-                                  },
-                                  cellvaluechanging: function (row, column, columntype, oldvalue, newvalue) {
-                                        var type = $("#miscGrid").jqxGrid('getcellvalue', row, "m_type");
-                                        if (type == "Water agent")
-                                                return oldvalue;
-                                  }
-                                },
-                                { datafield: 'm_amount_is_weight', hidden: true },      // We need to declare this column
-                                { datafield: 'm_amount', hidden: true },                // We need to declare this column
-                                { text: 'Hoeveelheid', datafield: 'm_weight', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f2',
-                                  columntype: 'numberinput',
-                                  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
-                                        var vstr = rowdata.m_amount_is_weight ? "gr":"ml";
-                                        return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value,"f2")+" "+vstr+"</div>";
-                                  },
-                                  validation: function (cell, value) {
-                                        var high = parseFloat(dataRecord.boil_size) * 1000;
-                                        if (value < 0 || value > high) {
-                                                return { result: false, message: "Hoeveelheid moet tussen 0 en "+high+" zijn" };
-                                        }
-                                        return true;
-                                  },
-                                  initeditor: function (row, cellvalue, editor) {
-                                        editor.jqxNumberInput({
-                                                inputMode: 'simple', min: 0, max: parseFloat(dataRecord.boil_size) * 1000,
-                                                decimalDigits: 2, spinButtons: false
-                                        });
-                                  },
-                                  cellvaluechanging: function (row, column, columntype, oldvalue, newvalue) {
-                                        var type = $("#miscGrid").jqxGrid('getcellvalue', row, "m_type");
-                                        if (type == "Water agent")
-                                                return oldvalue;
+                                { text: 'Ingredient', datafield: 'm_name' },
+                                { text: 'Type', width: 140, datafield: 'm_type',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + MiscTypeData[value].nl + "</div>";
+				  }
+			       	},
+                                { text: 'Gebruik', width: 140, datafield: 'm_use_use',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + MiscUseData[value].nl + "</div>";
                                   }
+                               	},
+                               	{ text: 'Tijd', datafield: 'm_time', width: 90, align: 'right',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					if (rowdata.m_use_use == 2) {   // Boil
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" min.</div>";
+					} else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) {      // Primary or Secondary
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value/1440, "f0")+" dagen</div>";
+					} else {
+						var tijd = 0;
+						return "<div style='margin: 4px;'> </div>";
+					}
+				  },
                                 },
-                               { text: 'Tijd', datafield: 'm_time', width: 70, align: 'right', cellsalign: 'right', cellsformat: 'f0',
-                                  columntype: 'numberinput',
-                                  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
-                                        if (rowdata.m_use_use == 'Boil') {
-                                                return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" m</div>";
-                                        } else if (rowdata.m_use_use == 'Secondary') {
-                                                return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" d</div>";
-                                        } else {
-                                                var tijd = 0;
-                                                return "<div style='margin: 4px;' class='jqx-right-align'> </div>";
-                                        }
-                                  },
-                                  initeditor: function (row, cellvalue, editor, celltext, pressedChar) {
-                                        editor.jqxNumberInput({ decimalDigits: 0, digits: 3, min: 0, max: parseFloat(dataRecord.boil_time) });
-                                  },
-                                  cellvaluechanging: function (row, column, columntype, oldvalue, newvalue) {
-                                        var use = $("#miscGrid").jqxGrid('getcellvalue', row, "m_use_use");
-                                        if ((use != "Boil") && (use != "Secondary"))
-                                                return oldvalue;
-                                  },
-                                  validation: function (cell, value) {
-                                        var high = parseFloat(dataRecord.boil_time);
-                                        if (value < 0 || value > high ) {
-                                                return { result: false, message: "De tijd moet 0-"+high+" zijn" };
-                                        }
-                                        return true;
-                                  }
-                                }
+				{ text: 'Hoeveel', datafield: 'm_amount', width: 110, align: 'right',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					var vstr = rowdata.m_amount_is_weight ? "gr":"ml";
+					return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr+"</div>";
+				  }
+				},
+				{ text: 'Voorraad', datafield: 'm_inventory', width: 110, align: 'right',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					var vstr = rowdata.m_amount_is_weight ? "gr":"ml";
+					return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr+"</div>";
+				  }
+				},
+				{ text: 'Wijzig', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
+					return "Wijzig";
+					}, buttonclick: function (row) {
+						miscRow = row;
+						miscData = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+						if (miscData.m_amount_is_weight)
+							$("#wm_pmpt_amount").html("Gewicht gram:");
+						else
+							$("#wm_pmpt_amount").html("Volume ml:");
+						$("#wm_name").val(miscData.m_name);
+						$("#wm_amount").val(miscData.m_amount * 1000);
+						if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4))     // Primary or Secondary
+							$("#wm_time").val(miscData.m_time / 1440);
+						else
+							$("#wm_time").val(miscData.m_time);
+						$("#wm_use_use").val(miscData.m_use_use);
+						// show the popup window.
+						if (miscData.m_type != 4)
+							$("#popupMisc").jqxWindow('open');
+					}
+				}
                         ]
                 });
-                $("#miscGrid").on('cellendedit', function (event) {
-                        var args = event.args;
-                        console.log("Event Type: cellendedit, Column: " + args.datafield + ", Row: " + (args.rowindex) + ", Value: " + args.value);
-                        $("#miscGrid").jqxGrid('setcellvalue', args.rowindex, args.datafield, args.value);
-                        if (args.datafield == 'm_weight') {
-                                $("#miscGrid").jqxGrid('setcellvalue', args.rowindex, 'm_amount', parseFloat(args.value) / 1000);
-                        }
-                });
         };
 
         // Inline yeasts editor
@@ -2534,21 +2461,23 @@
                         localdata: data.yeasts,
                         datatype: "local",
                         cache: false,
+			async: false,
                         datafields: [
                                 { name: 'y_name', type: 'string' },
                                 { name: 'y_laboratory', type: 'string' },
                                 { name: 'y_product_id', type: 'string' },
                                 { name: 'y_amount', type: 'float' },
                                 { name: 'y_cost', type: 'float' },
-                                { name: 'y_type', type: 'string' },
-                                { name: 'y_form', type: 'string' },
-                                { name: 'y_time', type: 'float' },
+                                { name: 'y_type', type: 'int' },
+                                { name: 'y_form', type: 'int' },
+				{ name: 'y_flocculation', type: 'int' },
                                 { name: 'y_min_temperature', type: 'float' },
                                 { name: 'y_max_temperature', type: 'float' },
                                 { name: 'y_attenuation', type: 'float' },
-                                { name: 'y_amount_is_weight', type: 'bool' },
-                                { name: 'y_use', type: 'string' },
-                                { name: 'y_weight', type: 'float' }
+                                { name: 'y_use', type: 'int' },
+				{ name: 'y_cells', type: 'float' },
+				{ name: 'y_inventory', type: 'float' },
+				{ name: 'y_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
                                 commit(true);
@@ -2557,31 +2486,13 @@
                                 commit(true);
                         }
                 };
-                var yeastAdapter = new $.jqx.dataAdapter(yeastSource, {
-                         beforeLoadComplete: function (records) {
-                                var data = new Array();
-                                for (var i = 0; i < records.length; i++) {
-                                        var row = records[i];
-                                        if (row.y_form == 'Liquid')
-                                                row.y_weight = Math.round(row.y_amount * 17);
-                                        else
-                                                row.y_weight = row.y_amount * 1000;
-                                        data.push(row);
-                                }
-                                return data;
-                        },
-                        loadError: function(jqXHR, status, error) {
-                                $('#err').text(status + ' ' + error);
-                        },
-                });
+                var yeastAdapter = new $.jqx.dataAdapter(yeastSource);
                 $("#yeastGrid").jqxGrid({
-                        width: 1050,
-                        height: 300,
+                        width: 1240,
+                        height: 400,
                         source: yeastAdapter,
                         theme: theme,
                         selectionmode: 'singlerow',
-                        editmode: 'selectedcell',
-                        editable: true,
                         localization: getLocalization(),
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2591,12 +2502,13 @@
                                 container.append('<div style="float: left; margin-left: 165px;" id="yaddrowbutton"></div>');
                                 container.append('<div style="float: left; margin-left: 10px; margin-top: 5px;">In voorraad:</div>');
                                 container.append('<div style="float: left; margin-left: 10px;" id="yinstockbutton"></div>');
-                                container.append('<input style="float: left; margin-left: 230px;" id="ydeleterowbutton" type="button" value="Verwijder gist" />');
+                                container.append('<input style="float: left; margin-left: 400px;" id="ydeleterowbutton" type="button" value="Verwijder gist" />');
                                 // add yeast from dropdownlist.
                                 $("#yaddrowbutton").jqxDropDownList({
                                         placeHolder: "Kies gist:",
                                         theme: theme,
                                         source: yeastlist,
+					template: "primary",
                                         displayMember: "name",
                                         width: 150,
                                         height: 27,
@@ -2619,17 +2531,13 @@
                                                 row["y_form"] = datarecord.form;
                                                 row["y_amount"] = 0;
                                                 row["y_cost"] = datarecord.cost;
-                                                row["y_use"] = "Primary";
-                                                row["y_time"] = 0;
-                                                if (datarecord.form == "Dry") {
-                                                        row["y_amount_is_weight"] = 1;
-                                                } else {
-                                                        row["y_amount_is_weight"] = 0;
-                                                }
+                                                row["y_use"] = 0;
                                                 row["y_min_temperature"] = datarecord.min_temperature;
                                                 row["y_max_temperature"] = datarecord.max_temperature;
                                                 row["y_attenuation"] = datarecord.attenuation;
-                                                row["y_weight"] = 0;
+						row["y_flocculation"] = datarecord.flocculation;
+						row["y_cells"] = datarecord.cells;
+						row["y_inventory"] = datarecord.inventory;
                                                 var commit = $("#yeastGrid").jqxGrid('addrow', null, row);
                                         }
                                 });
@@ -2639,7 +2547,7 @@
                                         yeastlist.dataBind();
                                 });
                                 // delete selected yeast.
-                                $("#ydeleterowbutton").jqxButton({ theme: theme, height: 27, width: 150 });
+                                $("#ydeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                 $("#ydeleterowbutton").on('click', function () {
                                         var selectedrowindex = $("#yeastGrid").jqxGrid('getselectedrowindex');
                                         var rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount;
@@ -2654,60 +2562,72 @@
                                 $('#jqxTabs').jqxTabs('next');
                         },
                         columns: [
-                                { text: 'Gist', editable: false, datafield: 'y_name' },
-                                { text: 'Laboratorium', editable: false, width: 150, datafield: 'y_laboratory' },
-                                { text: 'Code', editable: false, width: 90, datafield: 'y_product_id' },
-                                { text: 'Soort', editable: false, width: 80, align: 'center', cellsalign: 'center', datafield: 'y_form' },
-                                { text: 'Min.', editable: false, width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' },
-                                { text: 'Max.', editable: false, width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' },
-                                { text: 'Attn.', editable: false, width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' },
-                                { text: 'Voor', width: 100, align: 'center', cellsalign: 'center', datafield: 'y_use', columntype: 'dropdownlist',
-                                  createeditor: function (row, column, editor) {
-                                        var srcYUse = [ "Primary", "Secondary", "Bottle" ];
-                                        editor.jqxDropDownList({ autoDropDownHeight: true, source: srcYUse });
+                                { text: 'Gist', datafield: 'y_name' },
+                                { text: 'Laboratorium', width: 150, datafield: 'y_laboratory' },
+                                { text: 'Code', width: 90, datafield: 'y_product_id' },
+                                { text: 'Soort', width: 100, datafield: 'y_form',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + YeastFormData[value].nl + "</div>";
+				  }
+			       	},
+                                { text: 'Min. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' },
+                                { text: 'Max. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' },
+                                { text: 'Attn. %', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' },
+                                { text: 'Voor', width: 120, datafield: 'y_use',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + YeastUseData[value].nl + "</div>";
                                   }
                                 },
-                                { datafield: 'y_amount', width: 90 },
-                                { text: 'Hoeveel', datafield: 'y_weight', width: 110, align: 'right', cellsalign: 'right',
-                                  cellsformat: 'f1', columntype: 'numberinput',
-                                  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
-                                        if (rowdata.y_form == 'Liquid') {
-                                                return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" pk</div>";
-                                        } else if (rowdata.y_form == 'Dry') {
-                                                return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f1")+" gr</div>";
-                                        } else {
-                                                return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" ml</div>";
-                                        }
-                                  },
-                                  initeditor: function (row, cellvalue, editor, celltext, pressedChar) {
-                                        var form = $("#yeastGrid").jqxGrid('getcellvalue', args.rowindex, 'y_form');
-                                        if (form == 'Dry') {
-                                                editor.jqxNumberInput({ decimalDigits: 1, min: 0, spinButtons: false });
-                                        } else {
-                                                editor.jqxNumberInput({ decimalDigits: 0, min: 0, spinButtons: false });
-                                        }
-                                  },
-                                  validation: function (cell, value) {
-                                        if (value < 0 || value > 100000000000 ) {
-                                                return { result: false, message: "Hoeveelheid moet 0-~ zijn" };
-                                        }
-                                        return true;
-                                  }
-                                }
+				{ text: 'Hoeveel', datafield: 'y_amount', width: 100, align: 'right',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					if (rowdata.y_form == 0) {      // Liquid
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" pk</div>";
+					} else if (rowdata.y_form == 1) {       // Dry
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value*1000, "f1")+" gr</div>";
+					} else {
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value*1000, "f0")+" ml</div>";
+					}
+				  }
+				},
+				{ text: 'Voorraad', datafield: 'y_inventory', width: 100, align: 'right',
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					if (rowdata.y_form == 0) {      // Liquid
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" pk</div>";
+					} else if (rowdata.y_form == 1) {       // Dry
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value*1000, "f1")+" gr</div>";
+					} else {
+						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value*1000, "f0")+" ml</div>";
+					}
+				  }
+				},
+				{ text: 'Wijzig', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
+					return "Wijzig";
+					}, buttonclick: function (row) {
+						yeastRow = row;
+						yeastData = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
+						if (yeastData.y_form == 0) {
+							$("#wy_pmpt_amount").html("Pak(ken):");
+							$("#wy_amount").val(yeastData.y_amount);
+							$("#wy_amount").jqxNumberInput({ decimalDigits: 0, spinButtonsStep: 1 });
+						} else if (yeastData.y_form == 1) {
+							$("#wy_pmpt_amount").html("Gewicht gram:");
+							$("#wy_amount").val(yeastData.y_amount * 1000);
+							$("#wy_amount").jqxNumberInput({ decimalDigits: 1, spinButtonsStep: 0.5 });
+						} else {
+							$("#wy_pmpt_amount").html("Volume ml:");
+							$("#wy_amount").val(yeastData.y_amount * 1000);
+							$("#wy_amount").jqxNumberInput({ decimalDigits: 0, spinButtonsStep: 1 });
+						}
+						$("#wy_name").val(yeastData.y_name);
+						$("#wy_laboratory").val(yeastData.y_laboratory);
+						$("#wy_product_id").val(yeastData.y_product_id);
+						$("#wy_use").val(yeastData.y_use);
+						// show the popup window.
+						$("#popupYeast").jqxWindow('open');
+					}
+				}
                         ]
                 });
-                $("#yeastGrid").on('cellendedit', function (event) {
-                        var args = event.args;
-                        console.log("Event Type: cellendedit, Column: " + args.datafield + ", Row: " + (args.rowindex) + ", Value: " + args.value);
-                        $("#yeastGrid").jqxGrid('setcellvalue', args.rowindex, args.datafield, args.value);
-                        if (args.datafield == 'y_weight') {
-                                var form = $("#yeastGrid").jqxGrid('getcellvalue', args.rowindex, 'y_form');
-                                if (form == 'Liquid')
-                                        $("#yeastGrid").jqxGrid('setcellvalue', args.rowindex, 'y_amount', parseFloat(args.value * 0.0588));
-                                else
-                                        $("#yeastGrid").jqxGrid('setcellvalue', args.rowindex, 'y_amount', parseFloat(args.value / 1000));
-                        }
-                });
         };
 
         // inline mash editor
@@ -2727,9 +2647,10 @@
                         localdata: data.mashs,
                         datatype: "local",
                         cache: false,
+			async: false,
                         datafields: [
                                 { name: 'step_name', type: 'string' },
-                                { name: 'step_type', type: 'string' },
+                                { name: 'step_type', type: 'int' },
                                 { name: 'step_infuse_amount', type: 'float' },
                                 { name: 'step_temp', type: 'float' },
                                 { name: 'step_time', type: 'float' },
@@ -2749,19 +2670,17 @@
                                 var data = new Array();
                                 for (var i = 0; i < records.length; i++) {
                                         var row = records[i];
-                                        if (row.step_type == 'Infusion')
+                                        if (row.step_type == 0)	// Infusion
                                                 mash_infuse += parseFloat(row.step_infuse_amount);
                                 }
                         },
                 });
                 $("#mashGrid").jqxGrid({
-                        width: 960,
+                        width: 1240,
                         height: 400,
                         source: mashAdapter,
                         theme: theme,
                         selectionmode: 'singlerow',
-                        editmode: 'selectedcell',
-                        editable: true,
                         localization: getLocalization(),
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2769,14 +2688,14 @@
                                 var container = $("<div style='overflow: hidden; position: relative; margin: 5px;'></div>");
                                 toolbar.append(container);
                                 container.append('<input style="float: left; margin-left: 165px;" id="saddrowbutton" type="button" value="Nieuwe stap" />');
-                                container.append('<input style="float: left; margin-left: 230px;" id="sdeleterowbutton" type="button" value="Verwijder stap" />');
-                                $("#saddrowbutton").jqxButton({ theme: theme, height: 27, width: 150 });
+                                container.append('<input style="float: left; margin-left: 565px;" id="sdeleterowbutton" type="button" value="Verwijder stap" />');
+                                $("#saddrowbutton").jqxButton({ template: "primary", theme: theme, height: 27, width: 150 });
                                 $("#saddrowbutton").on('click', function () {
                                         var datarow = generaterow();
                                         var commit = $("#mashGrid").jqxGrid('addrow', null, datarow);
                                 });
-                                // delete selected yeast.
-                                $("#sdeleterowbutton").jqxButton({ theme: theme, height: 27, width: 150 });
+                                // delete selected step.
+                                $("#sdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                 $("#sdeleterowbutton").on('click', function () {
                                         var selectedrowindex = $("#mashGrid").jqxGrid('getselectedrowindex');
                                         var rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount;
@@ -2787,71 +2706,52 @@
                                 });
                         },
                         ready: function() {
-                                var fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, parseFloat(parseFloat($("#est_og").jqxNumberInput('decimal'))));
-                                dataRecord.est_fg = fg;
-                                $('#est_fg').val(fg);
-				$('#est_fg2').val(fg);
+				calcFG();
                                 calcInit();
                                 $('#jqxLoader').jqxLoader('close');
                                 $('#jqxTabs').jqxTabs('first');
                         },
                         columns: [
                                 { text: 'Stap naam', datafield: 'step_name' },
-                                { text: 'Stap type', datafield: 'step_type', width: 110, columntype: 'dropdownlist',
-                                  createeditor: function (row, cellvalue, editor, celltext, cellwidth, cellheight) {
-                                        var dataSource = [ "Infusion", "Temperature", "Decoction" ];
-                                        editor.jqxDropDownList({ source: dataSource, dropDownHeight: 105 });
-                                  }
-                                },
-                                { text: 'Temperatuur', datafield: 'step_temp', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f1',
-                                  validation: function (cell, value) {
-                                        if (value < 35 || value > 80) {
-                                                return { result: false, message: "De temperatuur moet tussen 35 en 80 zijn." };
-                                        }
-                                        return true;
-                                  }
-                                },
-                                { text: 'Eind', datafield: 'end_temp', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f1',
-                                  validation: function (cell, value) {
-                                        if (value < 35 || value > 80) {
-                                                return { result: false, message: "De temperatuur moet tussen 35 en 80 zijn." };
-                                        }
-                                        return true;
+                                { text: 'Stap type', datafield: 'step_type', width: 175,
+				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
+					return "<div style='margin: 4px;'>" + MashStepTypeData[value].nl + "</div>";
                                   }
                                 },
-                                { text: 'Tijd', datafield: 'step_time', width: 70, align: 'right', cellsalign: 'right',
-                                  validation: function (cell, value) {
-                                        if (value < 1 || value > 360) {
-                                                return { result: false, message: "De tijd moet tussen 1 en 360 zijn." };
-                                        }
-                                        return true;
-                                  }
-                                },
-                                { text: 'Stap', datafield: 'ramp_time', width: 70, align: 'right', cellsalign: 'right',
-                                  validation: function (cell, value) {
-                                        if (value < 1 || value > 60) {
-                                                return { result: false, message: "De tijd moet tussen 1 en 60 zijn." };
-                                        }
-                                        return true;
-                                  }
-                                },
-                                { text: 'Infuse', datafield: 'step_infuse_amount', width: 70, align: 'right', cellsalign: 'right',
-                                  validation: function (cell, value) {
-                                        if (value < 0 || value > 60) {
-                                                return { result: false, message: "De waarde moet tussen 0 en 60 zijn." };
-                                        }
-                                        return true;
-                                  }
-                                }
+                                { text: 'Start &deg;C', datafield: 'step_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' },
+                                { text: 'Eind &deg;C', datafield: 'end_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' },
+                                { text: 'Tijd', datafield: 'step_time', width: 90, align: 'right', cellsalign: 'right' },
+                                { text: 'Stap', datafield: 'ramp_time', width: 90, align: 'right', cellsalign: 'right' },
+                                { text: 'Infuse', datafield: 'step_infuse_amount', width: 90, align: 'right', cellsalign: 'right' },
+				{ text: 'Wijzig', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
+					return "Wijzig";
+					}, buttonclick: function (row) {
+						mashRow = row;
+						mashData = $("#mashGrid").jqxGrid('getrowdata', mashRow);
+						$("#wstep_name").val(mashData.step_name);
+						$("#wstep_type").val(mashData.step_type);
+						$("#wstep_infuse_amount").val(mashData.step_infuse_amount);
+						$("#wstep_temp").val(mashData.step_temp);
+						$("#wend_temp").val(mashData.end_temp);
+						$("#wstep_time").val(mashData.step_time);
+						$("#wramp_time").val(mashData.ramp_time);
+						if (mashData.step_type == 0) {
+							$("#wstep_infuse_amount").show();
+							$("#wstep_pmpt").show();
+						} else {
+							$("#wstep_infuse_amount").hide();
+							$("#wstep_pmpt").hide();
+						}
+						// show the popup window.
+						$("#popupMash").jqxWindow('open');
+					}
+				}
                         ]
                 });
-                $("#mashGrid").on('cellendedit', function (event) {
-                        $('#mashGrid').jqxGrid('sortby', 'step_temp', 'asc');
-                });
         };
 
 	// initialize the input fields.
-        var srcType = [ "All Grain", "Partial Mash", "Extract" ];
+//        var srcType = [ "All Grain", "Partial Mash", "Extract" ];
         var srcColor = [ "Morey", "Mosher", "Daniels" ];
         var srcIBU = [ "Tinseth", "Rager", "Daniels" ]; // Only these are supported at this time.
         var srcBase = [ "NaHCO3", "Na2CO3", "CaCO3", "Ca(OH)2" ];
@@ -2894,16 +2794,26 @@
 	$("#notes").jqxTooltip({ content: 'De uitgebreide opmerkingen over dit product.' });
 	$("#notes").jqxInput({ theme: theme, width: 960, height: 100 });
 	$("#type").jqxTooltip({ content: 'Het brouw type van dit recept.' });
-	$("#type").jqxDropDownList({ theme: theme, source: srcType, width: 125, height: 23, dropDownHeight: 95 });
+	$("#type").jqxDropDownList({
+		theme: theme,
+		source: RecipeTypeAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true
+	});
 	$("#efficiency").jqxTooltip({ content: 'Het rendement van maischen en koken.' });
-	$("#efficiency").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 40, max: 100, decimalDigits: 0, spinButtons: true, symbol: '%', symbolPosition: 'right'  });
-
+	$("#efficiency").jqxNumberInput( Perc1dec5 );
 	$("#batch_size").jqxTooltip({ content: 'Het volume van het gekoelde wort na het koken.' });
-	$("#batch_size").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 4, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: 'L', symbolPosition: 'right' });
+	$("#batch_size").jqxNumberInput( Spin1dec5 );
+	$("#batch_size").jqxNumberInput({ min: 4 });
 	$("#boil_time").jqxTooltip({ content: 'De kooktijd in minuten.' });
-	$("#boil_time").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 4, max: 360, decimalDigits: 0, spinButtons: true });
+	$("#boil_time").jqxNumberInput( PosInt );
+	$("#boil_time").jqxNumberInput({ min: 4, max: 360 });
 	$("#boil_size").jqxTooltip({ content: 'Het volume van het wort voor het koken.' });
-	$("#boil_size").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 2, readOnly: true, symbol: 'L', symbolPosition: 'right' });
+	$("#boil_size").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 2, readOnly: true });
+
 	$("#st_guide").jqxTooltip({ content: 'De bierstijl gids voor dit recept.'});
 	$("#st_guide").jqxInput({ theme: theme, width: 250, height: 23 });
 	$("#st_name").jqxTooltip({ content: 'De bierstijl naam voor dit recept.'});
@@ -2918,38 +2828,59 @@
 	$("#st_category_number").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
 
 	$("#est_og").jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' });
-	$("#est_og").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 1.000, max: 1.200, decimalDigits: 3, spinButtons: true, spinButtonsStep: 0.001 });
+	$("#est_og").jqxNumberInput( SGopts );
 	$("#st_og_min").jqxTooltip({ content: 'Het minimum begin SG voor deze bierstijl.'});
 	$("#st_og_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
 	$("#st_og_max").jqxTooltip({ content: 'Het maximum begin SG voor deze bierstijl.'});
 	$("#st_og_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
+
 	$("#est_fg").jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' });
-	$("#est_fg").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 3, readOnly: true });
-	$("#est_fg2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 70, height: 23, decimalDigits: 3, readOnly: true });
+	$("#est_fg").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 3, readOnly: true });
 	$("#st_fg_min").jqxTooltip({ content: 'Het minimum eind SG voor deze bierstijl.'});
 	$("#st_fg_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
 	$("#st_fg_max").jqxTooltip({ content: 'Het maximum eind SG voor deze bierstijl.'});
 	$("#st_fg_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
+
 	$("#est_abv").jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' });
 	$("#est_abv").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
 	$("#st_abv_min").jqxTooltip({ content: 'Het minimum alcohol volume % voor deze bierstijl.'});
 	$("#st_abv_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
 	$("#st_abv_max").jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'});
 	$("#st_abv_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
+
 	$("#est_color").jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' });
-	$("#est_color").jqxNumberInput({ inputMode: 'simple', theme: theme, symbol: ' EBC', symbolPosition: 'right', width: 100, height: 23, decimalDigits: 0, readOnly: true });
+	$("#est_color").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 0, readOnly: true });
 	$("#st_color_min").jqxTooltip({ content: 'De minimum kleur voor deze bierstijl.'});
 	$("#st_color_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
 	$("#st_color_max").jqxTooltip({ content: 'De maximum kleur voor deze bierstijl.'});
 	$("#st_color_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
-	$("#color_method").jqxDropDownList({ theme: theme, source: srcColor, width: 125, height: 23, dropDownHeight: 95 });
+	$("#color_method").jqxDropDownList({
+		theme: theme,
+		source: ColorMethodAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true
+	});
+
 	$("#est_ibu").jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' });
-	$("#est_ibu").jqxNumberInput({ inputMode: 'simple', theme: theme, symbol: ' IBU', symbolPosition: 'right', width: 100, height: 23, decimalDigits: 0, readOnly: true });
+	$("#est_ibu").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 0, readOnly: true });
 	$("#st_ibu_min").jqxTooltip({ content: 'De minimum bitterheid voor deze bierstijl.'});
 	$("#st_ibu_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
 	$("#st_ibu_max").jqxTooltip({ content: 'De maximum bitterheid voor deze bierstijl.'});
 	$("#st_ibu_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
-	$("#ibu_method").jqxDropDownList({ theme: theme, source: srcIBU, width: 125, height: 23, dropDownHeight: 95, dropDownVerticalAlignment: 'top' });
+	$("#ibu_method").jqxDropDownList({
+		theme: theme,
+		source: IBUmethodAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true,
+		dropDownVerticalAlignment: 'top'
+	});
+
 	$("#est_carb").jqxTooltip({ content: 'Koolzuur volume. Dit wordt automatisch berekend.' });
 	$("#est_carb").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
 	$("#st_carb_min").jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'});
@@ -2995,30 +2926,678 @@
 
 	// Tab 3, Fermentables
 	$("#est_color2").jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' });
-	$("#est_color2").jqxNumberInput({ inputMode: 'simple', theme: theme, symbol: ' EBC', symbolPosition: 'right', width: 100, height: 23, decimalDigits: 0, readOnly: true });
+	$("#est_color2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 0, readOnly: true });
+	$("#est_og2").jqxTooltip({ content: 'Het geschatte begin SG van dit product.' });
+	$("#est_og2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 3, readOnly: true });
 	$("#perc_malts").jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true });
-	$("#est_og2").jqxTooltip({ content: 'Het geschatte begin SG van dit product.' });
-	$("#est_og2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 3, readOnly: true });
 	$("#perc_sugars").jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true });
 	$("#perc_cara").jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true });
+	$("#popupFermentable").jqxWindow({
+		width: 800,
+		height: 300,
+		position: { x: 230, y: 100 },
+		resizable: false,
+		theme: theme,
+		isModal: true,
+		autoOpen: false,
+		cancelButton: $("#FermentableReady"),
+		modalOpacity: 0.40
+	});
+	$("#FermentableReady").jqxButton({ template: "success", width: '90px', theme: theme });
+	$("#FermentableReady").click(function () {
+		$("#fermentableGrid").jqxGrid('sortby', 'f_amount', 'desc');
+		// Recalc percentages
+		calcFermentables();
+		calcSVG();
+		calcFG();
+		calcABV();
+		calcIBUs();
+		// Waters: yes there is impact.
+	});
+	$("#wf_name").jqxInput({ theme: theme, width: 320, height: 23 });
+	$("#wf_instock").jqxCheckBox({ theme: theme, height: 23 });
+	$("#wf_instock").on('change', function (event) {
+		fermentableinstock = event.args.checked;
+		fermentablelist.dataBind();
+	});
+	$("#wf_select").jqxDropDownList({
+		placeHolder: "Kies mout:",
+		theme: theme,
+		source: fermentablelist,
+		displayMember: "name",
+		width: 150,
+		height: 23,
+		dropDownWidth: 500,
+		dropDownHeight: 500,
+		renderer: function (index, label, value) {
+			var datarecord = fermentablelist.records[index];
+			return datarecord.supplier+ " / " + datarecord.name + " (" + datarecord.color + " EBC)";
+		}
+	});
+	$("#wf_select").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var datarecord = fermentablelist.records[index];
+			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
+			$("#wf_name").val(datarecord.name);
+			rowdata.f_name = datarecord.name;
+			rowdata.f_origin = datarecord.origin;
+			rowdata.f_supplier = datarecord.supplier;
+			rowdata.f_type = datarecord.type;
+			rowdata.f_cost = datarecord.cost;
+			rowdata.f_yield = datarecord.yield;
+			rowdata.f_color = datarecord.color;
+			rowdata.f_coarse_fine_diff = datarecord.coarse_fine_diff;
+			rowdata.f_moisture = datarecord.moisture;
+			rowdata.f_diastatic_power = datarecord.diastatic_power;
+			rowdata.f_protein = datarecord.protein;
+			rowdata.f_max_in_batch = datarecord.max_in_batch;
+			rowdata.f_graintype = datarecord.graintype;
+			rowdata.f_dissolved_protein = datarecord.dissolved_protein;
+			rowdata.f_recommend_mash = datarecord.recommend_mash;
+			rowdata.f_add_after_boil = datarecord.add_after_boil;
+			rowdata.f_di_ph = datarecord.di_ph;
+			rowdata.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
+			rowdata.f_inventory = datarecord.inventory;
+		}
+	});
+	$("#wf_amount").jqxNumberInput( Spin3dec5 );
+	$('#wf_amount').on('change', function (event) {
+		console.log("amount changed: "+event.args.value);
+		$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', event.args.value);
+		if (! to_100) {
+			// Recalculate percentages
+			console.log("adjust percentages");
+			var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
+			if (rowscount > 1) {
+				var tw = 0;
+				for (i = 0; i < rowscount; i++) {
+					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+					tw += rowdata.f_amount;
+				};
+				for (i = 0; i < rowscount; i++) {
+					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+					var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
+					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
+		//                      if (i == fermentableRow) // Will crash the script.
+		//                              $("#wf_percentage").val(percentage);
+				};
+			} else {
+				$("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
+			}
+			calcFermentables();
+		};
+	});
+	$("#wf_percentage").jqxNumberInput( Perc1dec1 );
+	$("#wf_percentage").on('change', function (event) {
+		var oldvalue = Math.round(fermentableData.f_percentage * 10) / 10.0;
+		var newvalue = event.args.value;
+		console.log("percentage changed: "+newvalue+" old: "+oldvalue);
+		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
+		if ((oldvalue != newvalue) && (rowscount > 1)) {
+			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
+			if (rowdata.f_adjust_to_total_100) {
+				$("#wf_percentage").val(oldvalue);
+			} else {
+				var diff = newvalue - oldvalue;
+				var tw = 0;     // total weight
+				for (i = 0; i < rowscount; i++) {
+					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+					tw += rowdata.f_amount;
+				}
+				if (to_100) {
+					// Adjust this row and the 100% row.
+					var damount = tw * diff / 100;
+					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
+					var namount = rowdata.f_amount + damount;
+					$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', namount);
+					$("#wf_amount").val(namount);
+					$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_percentage', rowdata.f_percentage + diff);
+					for (i = 0; i < rowscount; i++) {
+						var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+						if (rowdata.f_adjust_to_total_100) {
+							namount = rowdata.f_amount - damount;
+							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', rowdata.f_percentage - diff);
+							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
+						}
+					}
+					calcFermentables();
+				} else {
+					// Adjust all the rows.
+					var nw = tw * diff / 100;
+					for (i = 0; i < rowscount; i++) {
+						var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+						if (i == fermentableRow) {
+							var namount = rowdata.f_amount + nw;
+							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
+		//                                      $("#wf_amount").val(namount); // Will crash the script.
+							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newvalue);
+						} else {
+							var namount = rowdata.f_amount - (nw / (rowscount - 1));
+							var newperc = Math.round((namount / tw) * 1000) / 10.0;
+							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
+							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newperc);
+						}
+					}
+					calcFermentables();
+				}
+			}
+		}
+	});
+	$("#wf_adjust_to_total_100").jqxCheckBox({ theme: theme, width: 120, height: 23 });
+	$("#wf_adjust_to_total_100").on('checked', function (event) {
+		if (fermentableData.f_adjust_to_total_100 == 0) {
+			if (to_100) {
+				// Reset other flag first.
+				var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
+				for (var i = 0; i < rowscount; i++) {
+					if (i != fermentableRow) {
+						$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_adjust_to_total_100', 0);
+					}
+				}
+			}
+			$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_adjust_to_total_100', 1);
+			calcFermentables();
+		}
+	});
+	$("#wf_adjust_to_total_100").on('unchecked', function (event) {
+		if (fermentableData.f_adjust_to_total_100 != 0) {
+			$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_adjust_to_total_100', 0);
+			calcFermentables();
+		}
+	});
+	$("#wf_added").jqxDropDownList({
+		theme: theme,
+		source: AddedAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true,
+		dropDownVerticalAlignment: 'top'
+	});
 
 	// Tab 4, Hops
 	$("#est_ibu2").jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' });
 	$("#est_ibu2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
 	$("#hop_flavour").jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true });
 	$("#hop_aroma").jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true });
+	$("#popupHop").jqxWindow({
+		width: 800,
+		height: 300,
+		position: { x: 230, y: 100 },
+		resizable: false,
+		theme: theme,
+		isModal: true,
+		autoOpen: false,
+		cancelButton: $("#HopReady"),
+		modalOpacity: 0.40
+	});
+	$("#HopReady").jqxButton({ template: "success", width: '90px', theme: theme });
+	$("#HopReady").click(function () {
+		$("#hopGrid").jqxGrid('sortby', 'h_amount', 'asc');
+		calcIBUs();
+	});
+	$("#wh_name").jqxInput({ theme: theme, width: 320, height: 23 });
+	$("#wh_instock").jqxCheckBox({ theme: theme, height: 23 });
+	$("#wh_instock").on('change', function (event) {
+		hopinstock = event.args.checked;
+		hoplist.dataBind();
+	});
+	$("#wh_select").jqxDropDownList({
+		placeHolder: "Kies hop:",
+		theme: theme,
+		source: hoplist,
+		displayMember: "name",
+		width: 150,
+		height: 23,
+		dropDownWidth: 500,
+		dropDownHeight: 500,
+		renderer: function (index, label, value) {
+			var datarecord = hoplist.records[index];
+			return datarecord.origin+ " / " + datarecord.name + " (" + datarecord.alpha + " % &alpha;)";
+		}
+	});
+	$("#wh_select").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var datarecord = hoplist.records[index];
+			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
+			$("#wh_name").val(datarecord.name);
+			rowdata.h_name = datarecord.name;
+			rowdata.h_origin = datarecord.origin;
+			rowdata.h_cost = datarecord.cost;
+			rowdata.h_type = datarecord.type;
+			rowdata.h_form = datarecord.form;
+			rowdata.h_alpha = datarecord.alpha;
+			rowdata.h_beta = datarecord.beta;
+			rowdata.h_hsi = datarecord.hsi;
+			rowdata.h_humulene = datarecord.humulene;
+			rowdata.h_caryophyllene = datarecord.caryophyllene;
+			rowdata.h_cohumulone = datarecord.cohumulone;
+			rowdata.h_myrcene = datarecord.myrcene;
+			rowdata.h_total_oil = datarecord.total_oil;
+			rowdata.h_inventory = datarecord.inventory;
+		}
+	});
+	$("#wh_amount").jqxNumberInput( Spin1dec1 );
+	$('#wh_amount').on('change', function (event) {
+		console.log("amount changed: "+event.args.value);
+		var amount = parseFloat(event.args.value) / 1000;
+		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
+		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg,
+			parseFloat($("#batch_size").jqxNumberInput('decimal')),
+			amount, parseFloat(rowdata.h_time),
+			parseFloat(rowdata.h_alpha), $("#ibu_method").val()
+		);
+		rowdata.h_amount = amount;
+		calcIBUs();
+	});
+	$("#wh_ibu").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 1, readOnly: true });
+	$("#wh_time").jqxNumberInput( PosInt );
+	$("#wh_time").on('change', function (event) {
+		console.log("time changed: "+event.args.value);
+		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
+		var newtime = parseFloat(event.args.value);
+		// Check limits and correct
+		if (rowdata.h_useat == 2) {     // Boil
+			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
+				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
+				$("#wh_time").val(newtime);
+			}
+			rowdata.h_time = newtime;
+		} else if (rowdata.h_useat == 4) {      // Whirlpool
+			if (newtime > 120) {
+				newtime = 120;
+				$("#wh_time").val(newtime);
+			}
+			rowdata.h_time = newtime;
+		} else if (rowdata.h_useat == 5) {      // Dry hop
+			if (newtime > 21) {
+				newtime = 21;
+				$("#wh_time").val(newtime);
+			}
+			rowdata.h_time = newtime * 1440;
+		}
+		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
+				parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		$("#wh_ibu").val(ibu);
+		calcIBUs();
+	});
+	$("#wh_useat").jqxDropDownList({
+		theme: theme,
+		source: HopUseAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true,
+		dropDownVerticalAlignment: 'top'
+	});
+	$("#wh_useat").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
+			rowdata.h_useat = index;
+			if ((index == 0) || (index == 1)) {     // Mashhop or First wort hop
+				rowdata.h_time = parseFloat(dataRecord.boil_time);
+				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
+				$("#wh_time").val(rowdata.h_time);
+			} else if (index == 3) {        // Aroma
+				rowdata.h_time = 0;
+				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
+				$("#wh_time").val(0);
+			} else {        // Boil, Whirlpool or Dry hop
+				$("#wh_time").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
+			}
+			if (index == 5) // Dry hop
+				$("#wh_pmpt_time").html("Tijd in dagen");
+			else
+				$("#wh_pmpt_time").html("Tijd in minuten");
+		}
+	});
 
 	// Tab 5, Miscs
+	$("#popupMisc").jqxWindow({
+		width: 800,
+		height: 275,
+		position: { x: 230, y: 100 },
+		resizable: false,
+		theme: theme,
+		isModal: true,
+		autoOpen: false,
+		cancelButton: $("#MiscReady"),
+		modalOpacity: 0.40
+	});
+	$("#MiscReady").jqxButton({ template: "success", width: '90px', theme: theme });
+	$("#MiscReady").click(function () {
+		$("#miscGrid").jqxGrid('sortby', 'm_use_use', 'asc');
+	});
+	$("#wm_name").jqxInput({ theme: theme, width: 320, height: 23 });
+	$("#wm_instock").jqxCheckBox({ theme: theme, height: 23 });
+	$("#wm_instock").on('change', function (event) {
+		miscinstock = event.args.checked;
+		misclist.dataBind();
+	});
+	$("#wm_select").jqxDropDownList({
+		placeHolder: "Kies ingredi&euml;nt:",
+		theme: theme,
+		source: misclist,
+		displayMember: "name",
+		width: 150,
+		height: 23,
+		dropDownWidth: 500,
+		dropDownHeight: 500
+	});
+	$("#wm_select").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var datarecord = misclist.records[index];
+			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+			$("#wm_name").val(datarecord.name);
+			rowdata.m_name = datarecord.name;
+			rowdata.m_cost = datarecord.cost;
+			rowdata.m_type = datarecord.type;
+			rowdata.m_use_use = datarecord.use_use;
+			rowdata.m_amount_is_weight = datarecord.amount_is_weight;
+			rowdata.m_inventory = datarecord.inventory;
+		}
+	});
+	$("#wm_amount").jqxNumberInput( Spin1dec1 );
+	$('#wm_amount').on('change', function (event) {
+		console.log("amount changed: "+event.args.value);
+		var amount = parseFloat(event.args.value) / 1000;
+		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+		rowdata.m_amount = amount;
+	});
+	$("#wm_time").jqxNumberInput( PosInt );
+	$("#wm_time").on('change', function (event) {
+		console.log("time changed: "+event.args.value);
+		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+		var newtime = parseFloat(event.args.value);
+
+		if (rowdata.m_use_use == 2) {   // Boil
+			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
+				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
+				$("#wm_time").val(newtime);
+			}
+			rowdata.m_time = newtime;
+		} else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) {      // Primary or Secondary
+			if (newtime > 21) {
+				newtime = 21;
+				$("#wm_time").val(newtime);
+			}
+			rowdata.m_time = newtime * 1440;
+		}
+	});
+	$("#wm_use_use").jqxDropDownList({
+		theme: theme,
+		source: MiscUseAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true,
+		dropDownVerticalAlignment: 'top'
+	});
+	$("#wm_use_use").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+			rowdata.m_use_use = index;
+			if ((index == 2) || (index == 3) || (index == 4)) {     // Boil, Primary or Secondary
+				$("#wm_time").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
+			} else {
+				rowdata.m_time = 0;
+				$("#wm_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
+				$("#wm_time").val(0);
+			}
+		}
+	});
 
 	// Tab 6, Yeasts
+	$("#est_fg2").jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' });
+	$("#est_fg2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 3, readOnly: true });
+	$("#est_abv2").jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' });
+	$("#est_abv2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
+	$("#popupYeast").jqxWindow({
+		width: 800,
+		height: 300,
+		position: { x: 230, y: 100 },
+		resizable: false,
+		theme: theme,
+		isModal: true,
+		autoOpen: false,
+		cancelButton: $("#YeastReady"),
+		modalOpacity: 0.40
+	});
+	$("#YeastReady").jqxButton({ template: "success", width: '90px', theme: theme });
+	$("#YeastReady").click(function () {
+		calcSVG();
+		calcFG();
+		calcABV();
+		$("#yeastGrid").jqxGrid('sortby', 'y_use', 'asc');
+	});
+	$("#wy_name").jqxInput({ theme: theme, width: 320, height: 23 });
+	$("#wy_laboratory").jqxInput({ theme: theme, width: 320, height: 23 });
+	$("#wy_product_id").jqxInput({ theme: theme, width: 320, height: 23 });
+	$("#wy_instock").jqxCheckBox({ theme: theme, height: 23 });
+	$("#wy_instock").on('change', function (event) {
+		yeastinstock = event.args.checked;
+		yeastlist.dataBind();
+	});
+	$("#wy_select").jqxDropDownList({
+		placeHolder: "Kies gist:",
+		theme: theme,
+		source: yeastlist,
+		displayMember: "name",
+		width: 150,
+		height: 23,
+		dropDownWidth: 500,
+		dropDownHeight: 500,
+		renderer: function (index, label, value) {
+			var datarecord = yeastlist.records[index];
+			return datarecord.laboratory+" "+datarecord.product_id+" "+datarecord.name;
+		}
+	});
+	$("#wy_select").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var datarecord = yeastlist.records[index];
+			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
+			$("#wy_name").val(datarecord.name);
+			$("#wy_laboratory").val(datarecord.laboratory);
+			$("#wy_product_id").val(datarecord.product_id);
+			rowdata.y_name = datarecord.name;
+			rowdata.y_cost = datarecord.cost;
+			rowdata.y_type = datarecord.type;
+			rowdata.y_form = datarecord.form;
+			rowdata.y_laboratory = datarecord.laboratory;
+			rowdata.y_product_id = datarecord.product_id;
+			rowdata.y_min_temperature = datarecord.min_temperature;
+			rowdata.y_max_temperature = datarecord.max_temperature;
+			rowdata.y_flocculation = datarecord.flocculation;
+			rowdata.y_attenuation = datarecord.attenuation;
+			rowdata.y_cells = datarecord.cells;
+			rowdata.y_inventory = datarecord.inventory;
+			if (rowdata.y_form == 0) {
+				$("#wy_pmpt_amount").html("Pak(ken):");
+			} else if (rowdata.y_form == 1) {
+				$("#wy_pmpt_amount").html("Gewicht gram:");
+			} else {
+				$("#wy_pmpt_amount").html("Volume ml:");
+			}
+			calcSVG();
+			calcFG();
+			calcABV();
+		}
+	});
+	$("#wy_amount").jqxNumberInput( Spin1dec5 );
+	$('#wy_amount').on('change', function (event) {
+		console.log("amount changed: "+event.args.value);
+		var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
+		if (rowdata.y_form == 0)        // Liquid
+			var amount = parseFloat(event.args.value);
+		else
+			var amount = parseFloat(event.args.value) / 1000;
+		rowdata.y_amount = amount;
+		calcSVG();
+		calcFG();
+		calcABV();
+	});
+	$("#wy_use").jqxDropDownList({
+		theme: theme,
+		source: YeastUseAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true,
+		dropDownVerticalAlignment: 'top'
+	});
+	$("#wy_use").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
+			rowdata.y_use = index;
+			calcSVG();
+			calcFG();
+			calcABV();
+		}
+	});
 
 	// Tab 7, Mashing
 	$("#mash_name").jqxTooltip({ content: 'De omschrijving van dit maisch profiel.' });
 	$("#mash_name").jqxInput({ theme: theme, width: 320, height: 23 });
+	$("#mash_select").jqxDropDownList({
+		placeHolder: "Kies schema:",
+		theme: theme,
+		source: mashlist,
+		displayMember: "name",
+		width: 250,
+		height: 23,
+		dropDownWidth: 500,
+		dropDownHeight: 500,
+		dropDownHorizontalAlignment: 'right'
+	});
+	$("#mash_select").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			// First delete all current steps
+			var rowIDs = new Array();
+			var rows = $("#mashGrid").jqxGrid('getdisplayrows');
+			for (var i = 0; i < rows.length; i++) {
+				var row = rows[i];
+				rowIDs.push(row.uid);
+			}
+			$("#mashGrid").jqxGrid('deleterow', rowIDs);
+			// Then add the new steps
+			$("#mash_name").val(datarecord.name);
+			for (var i = 0; i < datarecord.steps.length; i++) {
+				var data = datarecord.steps[i];
+				var row = {};
+				row["step_name"] = data.step_name;
+				row["step_type"] = data.step_type;
+				// For now, but this must be smarter.
+				if (mash_infuse == 0 && dataRecord.w1_amount > 0)
+					mash_infuse = dataRecord.w1_amount;
+				if (i == 0)
+					row["step_infuse_amount"] = mash_infuse;
+				else
+					row["step_infuse_amount"] = 0;
+				row["step_temp"] = data.step_temp;
+				row["end_temp"] = data.end_temp;
+				row["step_time"] = data.step_time;
+				row["ramp_time"] = data.ramp_time;
+				var commit = $("#mashGrid").jqxGrid('addrow', null, row);
+			}
+		}
+	});
+	$("#popupMash").jqxWindow({
+		width: 800,
+		height: 350,
+		position: { x: 230, y: 100 },
+		resizable: false,
+		theme: theme,
+		isModal: true,
+		autoOpen: false,
+		cancelButton: $("#MashReady"),
+		modalOpacity: 0.40
+	});
+	$("#MashReady").jqxButton({ template: "success", width: '90px', theme: theme });
+	$("#MashReady").click(function () {
+		$("#mashGrid").jqxGrid('sortby', 'step_temp', 'asc');
+	});
+	$("#wstep_name").jqxInput({ theme: theme, width: 320, height: 23 });
+	$("#wstep_type").jqxDropDownList({
+		theme: theme,
+		source: MashStepTypeAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true
+	});
+	$("#wstep_type").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
+			rowdata.step_type = index;
+			if (index == 0) {
+				$("#wstep_infuse_amount").show();
+				$("#wstep_pmpt").show();
+			} else {
+				rowdata.step_infuse_amount = 0;
+				$("#wstep_infuse_amount").hide();
+				$("#wstep_pmpt").hide();
+			}
+			mash_infuse = 0;
+			var rows = $('#mashGrid').jqxGrid('getrows');
+			for (var i = 0; i < rows.length; i++) {
+				var row = rows[i];
+				if (row.step_type == 0) // Infusion
+					mash_infuse += parseFloat(row.step_infuse_amount);
+			}
+		}
+	});
+	$("#wstep_temp").jqxNumberInput( Spin1dec5 );
+	$('#wstep_temp').on('change', function (event) {
+		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
+		rowdata.step_temp = parseFloat(event.args.value);
+	});
+	$("#wend_temp").jqxNumberInput( Spin1dec5 );
+	$('#wend_temp').on('change', function (event) {
+		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
+		rowdata.end_temp = parseFloat(event.args.value);
+	});
+	$("#wstep_time").jqxNumberInput( PosInt );
+	$('#wstep_time').on('change', function (event) {
+		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
+		rowdata.step_time = parseFloat(event.args.value);
+	});
+	$("#wramp_time").jqxNumberInput( PosInt );
+	$('#wramp_time').on('change', function (event) {
+		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
+		rowdata.ramp_time = parseFloat(event.args.value);
+	});
+	$("#wstep_infuse_amount").jqxNumberInput( Spin1dec5 );
+	$('#wstep_infuse_amount').on('change', function (event) {
+		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
+		rowdata.step_infuse_amount = parseFloat(event.args.value);
+		mash_infuse = 0;
+		var rows = $('#mashGrid').jqxGrid('getrows');
+		for (var i = 0; i < rows.length; i++) {
+			var row = rows[i];
+			if (row.step_type == 0) // Infusion
+				mash_infuse += parseFloat(row.step_infuse_amount);
+		}
+	});
 
 	// Tab 8, Water
 	$("#tgt_bu").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 2, readOnly: true });
 	$("#tgt_cl_so4").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
+
+	// Water source 1
 	$("#w1_name").jqxDropDownList({
 		placeHolder: "Kies hoofd water:",
 		theme: theme,
@@ -3061,6 +3640,7 @@
 	$("#w1_chloride").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#w1_sulfate").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#w1_ph").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
+	// Water source 2
 	$("#w2_name").jqxDropDownList({
 		placeHolder: "Kies meng water:",
 		theme: theme,
@@ -3105,7 +3685,7 @@
 	$("#w2_chloride").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#w2_sulfate").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#w2_ph").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
-
+	// Water mixed
 	$("#wg_amount").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#wg_calcium").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#wg_magnesium").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
@@ -3114,7 +3694,7 @@
 	$("#wg_chloride").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#wg_sulfate").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#wg_ph").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
-
+	// Water treated
 	$("#wb_calcium").jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'});
 	$("#wb_calcium").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#wb_magnesium").jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is lager dan 30.'});
@@ -3129,7 +3709,7 @@
 	$("#wb_sulfate").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 
 	$("#wb_ph").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
-
+	// Water target profile
 	$("#pr_name").jqxDropDownList({
 		placeHolder: "Kies doel profiel:",
 		theme: theme,
@@ -3159,70 +3739,132 @@
 	$("#pr_chloride").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 	$("#pr_sulfate").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
 
+	// Water agents
 	$("#wa_cacl2").jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.' });
-	$("#wa_cacl2").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, max: 1000, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
-	$("#mash_ph").jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'});
-	$("#mash_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 4, max: 8, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#sparge_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
+	$("#wa_cacl2").jqxNumberInput( Spin1dec1 );
 	$("#wa_caso4").jqxTooltip({ content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.' });
-	$("#wa_caso4").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, max: 1000, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
-	$("#calc_acid").jqxCheckBox({ theme: theme, width: 120, height: 23 });
-	$("#sparge_temp").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 70, max: 98, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
+	$("#wa_caso4").jqxNumberInput( Spin1dec1 );
 	$("#wa_mgso4").jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!' });
-	$("#wa_mgso4").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, max: 1000, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
-	$("#wa_base_name").jqxDropDownList({ theme: theme, source: srcBase, width: 100, height: 23, dropDownHeight: 128 });
-	$("#wa_base").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, decimalDigits: 2, spinButtons: true, spinButtonsStep: 0.05, symbol: ' gr', symbolPosition: 'right' });
-	$("#sparge_source").jqxDropDownList({ theme: theme, source: srcSource, width: 100, height: 23, dropDownHeight: 95 });
+	$("#wa_mgso4").jqxNumberInput( Spin1dec1 );
 	$("#wa_nacl").jqxTooltip({ content: 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.' });
-	$("#wa_nacl").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, max: 1000, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
-	$("#wa_acid_name").jqxDropDownList({ theme: theme, source: srcAcid, width: 100, height: 23, dropDownHeight: 128 })
-	$("#wa_acid").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, decimalDigits: 2, spinButtons: true, spinButtonsStep: 0.05, symbol: ' ml', symbolPosition: 'right' });
-	$("#wa_acid_perc").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 80, height: 23, min: 0, max: 100, decimalDigits: 0, spinButtons: true, symbol: '%', symbolPosition: 'right' });
-	$("#sparge_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 4.5, max: 6.5, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#sparge_acid_type").jqxDropDownList({ theme: theme, source: srcAcid, width: 100, height: 23, dropDownHeight: 128 });
-	$("#sparge_acid_perc").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, spinButtons: true, decimalDigits: 0, symbol: '%', symbolPosition: 'right' });
-	$("#sparge_acid_amount").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 2, readOnly: true, symbol: ' ml', symbolPosition: 'right' });
+	$("#wa_nacl").jqxNumberInput( Spin1dec1 );
+	$("#mash_ph").jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'});
+	$("#mash_ph").jqxNumberInput( SpinpH );
+	$("#calc_acid").jqxCheckBox({ theme: theme, width: 120, height: 23 });
+	$("#wa_base_name").jqxDropDownList({
+		theme: theme,
+		source: BaseTypeAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 170,
+		height: 23,
+		autoDropDownHeight: true
+	});
+	$("#wa_base").jqxNumberInput( Spin2dec5 );
+	$("#wa_base").jqxNumberInput({ symbol: ' gr', symbolPosition: 'right' });
+	$("#wa_acid_name").jqxDropDownList({
+		theme: theme,
+		source: AcidTypeAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 170,
+		height: 23,
+		autoDropDownHeight: true
+	})
+	$("#wa_acid").jqxNumberInput( Spin2dec5 );
+	$("#wa_acid").jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' });
+	$("#wa_acid_perc").jqxNumberInput( Perc0 );
+	$("#wa_acid_perc").jqxNumberInput({ width: 70, symbol: '%', symbolPosition: 'right' });
+	// Sparge water
+	$("#sparge_temp").jqxNumberInput( Spin1dec5 );
+	$("#sparge_volume").jqxNumberInput( Spin1dec5 );
+	$("#sparge_ph").jqxNumberInput( SpinpH );
+	$("#sparge_source").jqxDropDownList({
+		theme: theme,
+		source: SpargeSourceAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 110,
+		height: 23,
+		autoDropDownHeight: true
+	});
+	$("#sparge_acid_amount").jqxNumberInput( Spin2dec1 );
+	$("#sparge_acid_amount").jqxNumberInput({ spinButtons: false, readOnly: true, symbol: ' ml', symbolPosition: 'right' });
+	$("#sparge_acid_type").jqxDropDownList({
+		theme: theme,
+		source: AcidTypeAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 110,
+		height: 23,
+		autoDropDownHeight: true
+	});
+	$("#sparge_acid_perc").jqxNumberInput( Perc0 );
+	$("#sparge_acid_perc").jqxNumberInput({ symbol: '%', symbolPosition: 'right' });
 
 	// Tab 9, Brewday
 	$("#brew_date_start").jqxDateTimeInput({ theme: theme, width: 230, height: 23, formatString: 'yyyy-MM-dd HH:mm:ss', showTimeButton: true });
 	$("#brew_date_end").jqxDateTimeInput({ theme: theme, width: 230, height: 23, formatString: 'yyyy-MM-dd HH:mm:ss', showTimeButton: true });
-	$("#brew_mash_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
+	$("#brew_mash_ph").jqxNumberInput( SpinpH );
 	$("#est_mash_ph").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
-	$("#brew_preboil_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
+	$("#brew_preboil_ph").jqxNumberInput( SpinpH );
 	// est_preboil_ph
-	$("#brew_aboil_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
+	$("#brew_aboil_ph").jqxNumberInput( SpinpH );
 	// est_aboil_ph
-	$("#brew_mash_sg").jqxNumberInput({ inputMode: 'simple',  spinMode: 'simple', theme: theme, width: 90, height: 23, min: 1.000, max: 1.200, decimalDigits: 3, spinButtons: true, spinButtonsStep: 0.001 });
+	$("#brew_mash_sg").jqxNumberInput( SGopts );
 	$("#brew_mash_sg").on('valueChanged', function () { calcMashEfficiency(); });
 	$("#est_mash_sg").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 3 });
-	$("#brew_preboil_sg").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 3, spinButtons: true, spinButtonsStep: 0.001 });
-	$("#brew_aboil_sg").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 3, spinButtons: true, spinButtonsStep: 0.001 });
+	$("#brew_preboil_sg").jqxNumberInput( SGopts );
+	$("#brew_aboil_sg").jqxNumberInput( SGopts );
 	$("#est_og3").jqxTooltip({ content: 'Het geschatte begin SG van dit product.' });
 	$("#est_og3").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 70, height: 23, decimalDigits: 3, readOnly: true });
-	$("#brew_mash_efficiency").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
-	$("#brew_preboil_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_aboil_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_preboil_efficiency").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
-	$("#brew_aboil_efficiency").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
-	$("#brew_sparge_temperature").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_sparge_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_whirlpool9").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, max: 120, decimalDigits: 0, spinButtons: true });
-	$("#brew_cooling_to").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_sparge_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, max: 14, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_whirlpool7").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, max: 120, decimalDigits: 0, spinButtons: true });
-	$("#brew_cooling_method").jqxDropDownList({ theme: theme, source: srcCooling, width: 170, height: 23, dropDownHeight: 153 });
-	$("#brew_whirlpool6").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, max: 120, decimalDigits: 0, spinButtons: true });
-	$("#brew_cooling_time").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, max: 1440, decimalDigits: 0, spinButtons: true });
-	$("#brew_whirlpool2").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, max: 120, decimalDigits: 0, spinButtons: true });
-	$("#brew_aeration_type").jqxDropDownList({ theme: theme, source: srcAeration, width: 100, height: 23, dropDownHeight: 95 });
-	$("#brew_aeration_time").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, max: 1440, decimalDigits: 0, spinButtons: true });
-	$("#brew_aeration_speed").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, max: 1440, decimalDigits: 0, spinButtons: true });
-	$("#brew_fermenter_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_fermenter_extrawater").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_fermenter_sg").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 3 });
-	$("#brew_fermenter_extrasugar").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#brew_fermenter_ibu").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 0 });
-	$("#brew_fermenter_color").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 0 });
+	$("#brew_mash_efficiency").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 90, height: 23, decimalDigits: 1 });
+	$("#brew_preboil_volume").jqxNumberInput( Spin1dec5 );
+	$("#brew_aboil_volume").jqxNumberInput( Spin1dec5 );
+	$("#brew_preboil_efficiency").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 90, height: 23, decimalDigits: 1 });
+	$("#brew_aboil_efficiency").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 90, height: 23, decimalDigits: 1 });
+	$("#brew_sparge_temperature").jqxNumberInput( Spin1dec5 );
+	$("#brew_sparge_volume").jqxNumberInput( Spin1dec5 );
+	$("#brew_whirlpool9").jqxNumberInput( PosInt );
+	$("#brew_whirlpool9").jqxNumberInput({ max: 120 });
+	$("#brew_cooling_to").jqxNumberInput( Spin1dec5 );
+	$("#brew_sparge_ph").jqxNumberInput( SpinpH );
+	$("#brew_whirlpool7").jqxNumberInput( PosInt );
+	$("#brew_whirlpool7").jqxNumberInput({ max: 120 });
+	$("#brew_cooling_method").jqxDropDownList({
+		theme: theme,
+		source: CoolingTypeAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true
+	});
+	$("#brew_whirlpool6").jqxNumberInput( PosInt );
+	$("#brew_whirlpool6").jqxNumberInput({ max: 120 });
+	$("#brew_cooling_time").jqxNumberInput( PosInt );
+	$("#brew_cooling_time").jqxNumberInput({ max: 1440 });
+	$("#brew_whirlpool2").jqxNumberInput( PosInt );
+	$("#brew_whirlpool2").jqxNumberInput({ max: 120 });
+	$("#brew_aeration_type").jqxDropDownList({
+		theme: theme,
+		source: AerationTypeAdapter,
+		valueMember: 'id',
+		displayMember: 'nl',
+		width: 180,
+		height: 23,
+		autoDropDownHeight: true
+	});
+	$("#brew_aeration_time").jqxNumberInput( PosInt );
+	$("#brew_aeration_time").jqxNumberInput({ max: 1440 });
+	$("#brew_aeration_speed").jqxNumberInput( PosInt );
+	$("#brew_aeration_speed").jqxNumberInput({ max: 1440 });
+	$("#brew_fermenter_volume").jqxNumberInput( Spin1dec5 );
+	$("#brew_fermenter_extrawater").jqxNumberInput( Spin1dec1 );
+	$("#brew_fermenter_sg").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 90, height: 23, decimalDigits: 3 });
+	$("#brew_fermenter_extrasugar").jqxNumberInput( Spin1dec1 );
+	$("#brew_fermenter_ibu").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 90, height: 23, decimalDigits: 0 });
+	$("#brew_fermenter_color").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 90, height: 23, decimalDigits: 0 });
 	$("#BLog").jqxButton({ template: "info", width: '150px', theme: theme });
 	$("#BLog").click(function () {
 		// Open log in a new tab.
@@ -3273,6 +3915,7 @@
 	});
 
 	// Tab 11, Packaging
+	// TODO: high gravity packaging, extra water and recalc abv, color and ibu.
 	$("#package_date").jqxTooltip({ content: 'De verpakkings datum van dit bier.' });
 	$("#package_date").jqxDateTimeInput({
 		theme: theme,
@@ -3404,7 +4047,7 @@
 			name: $("#name").val(),
 			code: $("#code").val(),
 			birth: $("#birth").val(),
-			stage: $("#stage").val(),
+			stage: dataRecord.stage,
 			notes: $("#notes").val(),
 			log_brew: dataRecord.log_brew,
 			log_fermentation: dataRecord.log_fermentation,
@@ -3499,7 +4142,7 @@
 			st_name: $('#st_name').val(),
 			st_letter: $('#st_letter').val(),
 			st_guide: $('#st_guide').val(),
-			st_type: $('#st_type').val(),
+			st_type: dataRecord.st_type,
 			st_category: $('#st_category').val(),
 			st_category_number: parseFloat($("#st_category_number").jqxNumberInput('decimal')),
 			st_og_min: parseFloat($("#st_og_min").jqxNumberInput('decimal')),
@@ -3557,6 +4200,9 @@
 			w2_total_alkalinity: parseFloat($("#w2_total_alkalinity").jqxNumberInput('decimal')),
 			w2_ph: parseFloat($("#w2_ph").jqxNumberInput('decimal')),
 			w2_cost: dataRecord.w2_cost,
+			wa_acid_name: $("#wa_acid_name").val(),
+			wa_acid_perc: parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')),
+			wa_base_name: $("#wa_base_name").val(),
 			fermentables: fermentablerow,
 			hops: hoprow,
 			miscs: miscrow,

mercurial