diff --git a/Makefile b/Makefile
index f490d39..a6f56d2 100755
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,7 @@ travis: ## Run test suite with minimal output
 
 .PHONY: ctest
 ctest:
-	browserify -t brfs test/{dateNF,exp,fraction,general,implied,oddities,utilities,comma}.js > ctest/test.js
+	browserify -t brfs test/{dateNF,exp,fraction,general,implied,oddities,utilities,comma,valid}.js > ctest/test.js
 
 .PHONY: ctestserv
 ctestserv: ## Start a test server on port 8000
diff --git a/bits/01_version.js b/bits/01_version.js
index e54e7fd..7528349 100644
--- a/bits/01_version.js
+++ b/bits/01_version.js
@@ -1 +1 @@
-SSF.version = '0.9.1';
+SSF.version = '0.9.2';
diff --git a/bits/60_number.js b/bits/60_number.js
index 093568c..c14a2ec 100644
--- a/bits/60_number.js
+++ b/bits/60_number.js
@@ -7,12 +7,14 @@ function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{
 	var o/*:string*/;
 	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
 	if(fmt.match(/^#+0.0E\+0$/)) {
+		if(val == 0) return "0.0E+0";
+		else if(val < 0) return "-" + write_num_exp(fmt, -val);
 		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
-		var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
+		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
 		if(ee < 0) ee += period;
 		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
 		if(o.indexOf("e") === -1) {
-			var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
+			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
 			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
 			else o += "E+" + (fakee - ee);
 			while(o.substr(0,2) === "0.") {
diff --git a/bits/63_numflt.js b/bits/63_numflt.js
index f907f11..6644977 100644
--- a/bits/63_numflt.js
+++ b/bits/63_numflt.js
@@ -25,7 +25,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 	if((r = fmt.match(/^(0*)\.(#*)$/))) {
 		return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
 	}
-	if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
+	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
 	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
 		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
 	}
@@ -73,7 +73,12 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
 	}
 	switch(fmt) {
+		case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
+		case "###,###":
+		case "##,###":
 		case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
+		case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
+		case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
 		default:
 	}
 	throw new Error("unsupported format |" + fmt + "|");
diff --git a/bits/65_numinth.js b/bits/65_numinth.js
index 4a653e5..e86a5ef 100644
--- a/bits/65_numinth.js
+++ b/bits/65_numinth.js
@@ -11,12 +11,14 @@ function write_num_exp2(fmt/*:string*/, val/*:number*/)/*:string*/{
 	var o/*:string*/;
 	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
 	if(fmt.match(/^#+0.0E\+0$/)) {
+		if(val == 0) return "0.0E+0";
+		else if(val < 0) return "-" + write_num_exp2(fmt, -val);
 		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
-		var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
+		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
 		if(ee < 0) ee += period;
 		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
 		if(!o.match(/[Ee]/)) {
-			var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
+			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
 			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
 			else o += "E+" + (fakee - ee);
 			o = o.replace(/\+-/,"-");
diff --git a/bits/66_numint.js b/bits/66_numint.js
index 69399f2..21bfb9a 100644
--- a/bits/66_numint.js
+++ b/bits/66_numint.js
@@ -9,7 +9,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 	if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
 	if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
 	var o;
-	var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
+	var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
 	if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
 	if(fmt.match(/^[#?]+$/)) {
 		o = (""+val); if(val === 0) o = "";
@@ -29,7 +29,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 	if((r = fmt.match(/^(0*)\.(#*)$/))) {
 		return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
 	}
-	if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify((""+aval));
+	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
 	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
 		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
 	}
@@ -45,12 +45,12 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 	}
 	var oa = "";
 	if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
-		ri = Math.min(r[4].length,7);
+		ri = Math.min(/*::String(*/r[4]/*::)*/.length,7);
 		ff = frac(aval, Math.pow(10,ri)-1, false);
 		o = "" + sign;
-		oa = write_num("n", r[1], ff[1]);
+		oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
 		if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
-		o += oa + r[2] + "/" + r[3];
+		o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
 		oa = rpad_(ff[2],ri);
 		if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
 		o += oa;
@@ -76,8 +76,12 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
 	}
 	switch(fmt) {
+		case "###,###":
+		case "##,###":
 		case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
 		default:
+			if(fmt.slice(-3) == ".00") return write_num_int(type, fmt.slice(0,-3), val) + ".00";
+			if(fmt.slice(-2) == ".0") return write_num_int(type, fmt.slice(0,-2), val) + ".0";
 	}
 	throw new Error("unsupported format |" + fmt + "|");
 }
diff --git a/bits/82_eval.js b/bits/82_eval.js
index 764f39f..8fc4efa 100644
--- a/bits/82_eval.js
+++ b/bits/82_eval.js
@@ -28,7 +28,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
 				if(v < 0) return "";
 				if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
 				o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
-				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; /* m = minute */
+				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
 				if(c === 'h') c = hr;
 				out[out.length] = {t:c, v:o}; lst = c; break;
 			case 'A':
@@ -46,6 +46,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
 				if(o.match(abstime)) {
 					if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
 					out[out.length] = {t:'Z', v:o.toLowerCase()};
+					lst = o.charAt(1);
 				} else if(o.indexOf("$") > -1) {
 					o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
 					if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
@@ -59,7 +60,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
 				}
 				/* falls through */
 			case '0': case '#':
-				o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
+				o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
 				out[out.length] = {t:'n', v:o}; break;
 			case '?':
 				o = c; while(fmt.charAt(++i) === c) o+=c;
@@ -123,7 +124,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
 					(c=out[jj].t) === "?" || c === "D" ||
 					(c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/') ||
 					out[i].t === '(' && (c === ' ' || c === 'n' || c === ')') ||
-					c === 't' && (out[jj].v === '/' || '$€'.indexOf(out[jj].v) > -1 || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
+					c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
 				)) {
 					out[i].v += out[jj].v;
 					out[jj] = {v:"", t:";"}; ++jj;
diff --git a/bits/90_main.js b/bits/90_main.js
index d06a839..a1c7b72 100644
--- a/bits/90_main.js
+++ b/bits/90_main.js
@@ -21,7 +21,6 @@ function choose_fmt(f/*:string*/, v) {
 }
 function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
 	if(o == null) o = {};
-	//fixopts(o != null ? o : (o=[]));
 	var sfmt = "";
 	switch(typeof fmt) {
 		case "string":
diff --git a/package.json b/package.json
index 0840ec0..cc9ae5d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "ssf",
-	"version": "0.9.1",
+	"version": "0.9.2",
 	"author": "SheetJS",
 	"description": "Format data using ECMA-376 spreadsheet Format Codes",
 	"keywords": [ "format", "sprintf", "spreadsheet" ],
diff --git a/ssf.flow.js b/ssf.flow.js
index ae9e124..822a125 100644
--- a/ssf.flow.js
+++ b/ssf.flow.js
@@ -2,7 +2,7 @@
 /*jshint -W041 */
 var SSF = {};
 var make_ssf = function make_ssf(SSF){
-SSF.version = '0.9.1';
+SSF.version = '0.9.2';
 function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
 function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
 function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
@@ -270,12 +270,14 @@ function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{
 	var o/*:string*/;
 	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
 	if(fmt.match(/^#+0.0E\+0$/)) {
+		if(val == 0) return "0.0E+0";
+		else if(val < 0) return "-" + write_num_exp(fmt, -val);
 		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
-		var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
+		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
 		if(ee < 0) ee += period;
 		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
 		if(o.indexOf("e") === -1) {
-			var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
+			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
 			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
 			else o += "E+" + (fakee - ee);
 			while(o.substr(0,2) === "0.") {
@@ -353,7 +355,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 	if((r = fmt.match(/^(0*)\.(#*)$/))) {
 		return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
 	}
-	if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
+	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
 	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
 		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
 	}
@@ -401,7 +403,12 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
 	}
 	switch(fmt) {
+		case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
+		case "###,###":
+		case "##,###":
 		case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
+		case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
+		case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
 		default:
 	}
 	throw new Error("unsupported format |" + fmt + "|");
@@ -419,12 +426,14 @@ function write_num_exp2(fmt/*:string*/, val/*:number*/)/*:string*/{
 	var o/*:string*/;
 	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
 	if(fmt.match(/^#+0.0E\+0$/)) {
+		if(val == 0) return "0.0E+0";
+		else if(val < 0) return "-" + write_num_exp2(fmt, -val);
 		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
-		var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
+		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
 		if(ee < 0) ee += period;
 		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
 		if(!o.match(/[Ee]/)) {
-			var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
+			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
 			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
 			else o += "E+" + (fakee - ee);
 			o = o.replace(/\+-/,"-");
@@ -446,7 +455,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 	if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
 	if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
 	var o;
-	var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
+	var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
 	if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
 	if(fmt.match(/^[#?]+$/)) {
 		o = (""+val); if(val === 0) o = "";
@@ -466,7 +475,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 	if((r = fmt.match(/^(0*)\.(#*)$/))) {
 		return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
 	}
-	if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify((""+aval));
+	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
 	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
 		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
 	}
@@ -482,12 +491,12 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 	}
 	var oa = "";
 	if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
-		ri = Math.min(r[4].length,7);
+		ri = Math.min(/*::String(*/r[4]/*::)*/.length,7);
 		ff = frac(aval, Math.pow(10,ri)-1, false);
 		o = "" + sign;
-		oa = write_num("n", r[1], ff[1]);
+		oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
 		if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
-		o += oa + r[2] + "/" + r[3];
+		o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
 		oa = rpad_(ff[2],ri);
 		if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
 		o += oa;
@@ -513,8 +522,12 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
 		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
 	}
 	switch(fmt) {
+		case "###,###":
+		case "##,###":
 		case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
 		default:
+			if(fmt.slice(-3) == ".00") return write_num_int(type, fmt.slice(0,-3), val) + ".00";
+			if(fmt.slice(-2) == ".0") return write_num_int(type, fmt.slice(0,-2), val) + ".0";
 	}
 	throw new Error("unsupported format |" + fmt + "|");
 }
@@ -610,7 +623,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
 				if(v < 0) return "";
 				if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
 				o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
-				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; /* m = minute */
+				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
 				if(c === 'h') c = hr;
 				out[out.length] = {t:c, v:o}; lst = c; break;
 			case 'A':
@@ -628,6 +641,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
 				if(o.match(abstime)) {
 					if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
 					out[out.length] = {t:'Z', v:o.toLowerCase()};
+					lst = o.charAt(1);
 				} else if(o.indexOf("$") > -1) {
 					o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
 					if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
@@ -641,7 +655,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
 				}
 				/* falls through */
 			case '0': case '#':
-				o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
+				o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
 				out[out.length] = {t:'n', v:o}; break;
 			case '?':
 				o = c; while(fmt.charAt(++i) === c) o+=c;
@@ -705,7 +719,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
 					(c=out[jj].t) === "?" || c === "D" ||
 					(c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/') ||
 					out[i].t === '(' && (c === ' ' || c === 'n' || c === ')') ||
-					c === 't' && (out[jj].v === '/' || '$€'.indexOf(out[jj].v) > -1 || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
+					c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
 				)) {
 					out[i].v += out[jj].v;
 					out[jj] = {v:"", t:";"}; ++jj;
@@ -819,7 +833,6 @@ function choose_fmt(f/*:string*/, v) {
 }
 function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
 	if(o == null) o = {};
-	//fixopts(o != null ? o : (o=[]));
 	var sfmt = "";
 	switch(typeof fmt) {
 		case "string":
diff --git a/ssf.js b/ssf.js
index 080f88e..f770131 100644
--- a/ssf.js
+++ b/ssf.js
@@ -2,7 +2,7 @@
 /*jshint -W041 */
 var SSF = {};
 var make_ssf = function make_ssf(SSF){
-SSF.version = '0.9.1';
+SSF.version = '0.9.2';
 function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
 function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
 function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
@@ -269,12 +269,14 @@ function write_num_exp(fmt, val){
 	var o;
 	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
 	if(fmt.match(/^#+0.0E\+0$/)) {
+		if(val == 0) return "0.0E+0";
+		else if(val < 0) return "-" + write_num_exp(fmt, -val);
 		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
-		var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
+		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
 		if(ee < 0) ee += period;
 		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
 		if(o.indexOf("e") === -1) {
-			var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
+			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
 			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
 			else o += "E+" + (fakee - ee);
 			while(o.substr(0,2) === "0.") {
@@ -352,7 +354,7 @@ function write_num_flt(type, fmt, val) {
 	if((r = fmt.match(/^(0*)\.(#*)$/))) {
 		return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
 	}
-	if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
+	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
 	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
 		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
 	}
@@ -400,7 +402,12 @@ function write_num_flt(type, fmt, val) {
 		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
 	}
 	switch(fmt) {
+		case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
+		case "###,###":
+		case "##,###":
 		case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
+		case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
+		case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
 		default:
 	}
 	throw new Error("unsupported format |" + fmt + "|");
@@ -418,12 +425,14 @@ function write_num_exp2(fmt, val){
 	var o;
 	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
 	if(fmt.match(/^#+0.0E\+0$/)) {
+		if(val == 0) return "0.0E+0";
+		else if(val < 0) return "-" + write_num_exp2(fmt, -val);
 		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
-		var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
+		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
 		if(ee < 0) ee += period;
 		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
 		if(!o.match(/[Ee]/)) {
-			var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
+			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
 			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
 			else o += "E+" + (fakee - ee);
 			o = o.replace(/\+-/,"-");
@@ -463,7 +472,7 @@ return "." + $1 + fill("0", r[1].length-$1.length); });
 	if((r = fmt.match(/^(0*)\.(#*)$/))) {
 		return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
 	}
-	if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify((""+aval));
+	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
 	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
 		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
 	}
@@ -510,8 +519,12 @@ return "." + $1 + fill("0", r[1].length-$1.length); });
 		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
 	}
 	switch(fmt) {
+		case "###,###":
+		case "##,###":
 		case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
 		default:
+			if(fmt.slice(-3) == ".00") return write_num_int(type, fmt.slice(0,-3), val) + ".00";
+			if(fmt.slice(-2) == ".0") return write_num_int(type, fmt.slice(0,-2), val) + ".0";
 	}
 	throw new Error("unsupported format |" + fmt + "|");
 }
@@ -607,7 +620,7 @@ function eval_fmt(fmt, v, opts, flen) {
 				if(v < 0) return "";
 				if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
 				o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
-				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; /* m = minute */
+				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
 				if(c === 'h') c = hr;
 				out[out.length] = {t:c, v:o}; lst = c; break;
 			case 'A':
@@ -625,6 +638,7 @@ function eval_fmt(fmt, v, opts, flen) {
 				if(o.match(abstime)) {
 					if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
 					out[out.length] = {t:'Z', v:o.toLowerCase()};
+					lst = o.charAt(1);
 				} else if(o.indexOf("$") > -1) {
 					o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
 					if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
@@ -638,7 +652,7 @@ function eval_fmt(fmt, v, opts, flen) {
 				}
 				/* falls through */
 			case '0': case '#':
-				o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
+				o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
 				out[out.length] = {t:'n', v:o}; break;
 			case '?':
 				o = c; while(fmt.charAt(++i) === c) o+=c;
@@ -699,7 +713,7 @@ out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
 					(c=out[jj].t) === "?" || c === "D" ||
 					(c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/') ||
 					out[i].t === '(' && (c === ' ' || c === 'n' || c === ')') ||
-					c === 't' && (out[jj].v === '/' || '$€'.indexOf(out[jj].v) > -1 || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
+					c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
 				)) {
 					out[i].v += out[jj].v;
 					out[jj] = {v:"", t:";"}; ++jj;
@@ -813,7 +827,6 @@ function choose_fmt(f, v) {
 }
 function format(fmt,v,o) {
 	if(o == null) o = {};
-	//fixopts(o != null ? o : (o=[]));
 	var sfmt = "";
 	switch(typeof fmt) {
 		case "string":
diff --git a/test/comma.tsv b/test/comma.tsv
index 85ee283..dee043e 100644
--- a/test/comma.tsv
+++ b/test/comma.tsv
@@ -1,16 +1,16 @@
-value	#.0000,,,	#.0000,,	#.0000,	#,##0.0
-0.99	.0000	.0000	.0010	1.0
-1.2345	.0000	.0000	.0012	1.2
-12.345	.0000	.0000	.0123	12.3
-123.456	.0000	.0001	.1235	123.5
-1234	.0000	.0012	1.2340	1,234.0
-12345	.0000	.0123	12.3450	12,345.0
-123456	.0001	.1235	123.4560	123,456.0
-1234567	.0012	1.2346	1234.5670	1,234,567.0
-12345678	.0123	12.3457	12345.6780	12,345,678.0
-123456789	.1235	123.4568	123456.7890	123,456,789.0
-1234567890	1.2346	1234.5679	1234567.8900	1,234,567,890.0
-12345678901	12.3457	12345.6789	12345678.9010	12,345,678,901.0
-123456789012	123.4568	123456.7890	123456789.0120	123,456,789,012.0
-4321	.0000	.0043	4.3210	4,321.0
-4321234	.0043	4.3212	4321.2340	4,321,234.0
+value	#.0000,,,	#.0000,,	#.0000,	#,##0.0	###,##0	###,###	#,###.00
+0.99	.0000	.0000	.0010	1.0	1	1	.99
+1.2345	.0000	.0000	.0012	1.2	1	1	1.23
+12.345	.0000	.0000	.0123	12.3	12	12	12.35
+123.456	.0000	.0001	.1235	123.5	123	123	123.46
+1234	.0000	.0012	1.2340	1,234.0	1,234	1,234	1,234.00
+12345	.0000	.0123	12.3450	12,345.0	12,345	12,345	12,345.00
+123456	.0001	.1235	123.4560	123,456.0	123,456	123,456	123,456.00
+1234567	.0012	1.2346	1234.5670	1,234,567.0	1,234,567	1,234,567	1,234,567.00
+12345678	.0123	12.3457	12345.6780	12,345,678.0	12,345,678	12,345,678	12,345,678.00
+123456789	.1235	123.4568	123456.7890	123,456,789.0	123,456,789	123,456,789	123,456,789.00
+1234567890	1.2346	1234.5679	1234567.8900	1,234,567,890.0	1,234,567,890	1,234,567,890	1,234,567,890.00
+12345678901	12.3457	12345.6789	12345678.9010	12,345,678,901.0	12,345,678,901	12,345,678,901	12,345,678,901.00
+123456789012	123.4568	123456.7890	123456789.0120	123,456,789,012.0	123,456,789,012	123,456,789,012	123,456,789,012.00
+4321	.0000	.0043	4.3210	4,321.0	4,321	4,321	4,321.00
+4321234	.0043	4.3212	4321.2340	4,321,234.0	4,321,234	4,321,234	4,321,234.00
diff --git a/test/valid.js b/test/valid.js
new file mode 100644
index 0000000..3afbb70
--- /dev/null
+++ b/test/valid.js
@@ -0,0 +1,19 @@
+/* vim: set ts=2: */
+/*jshint loopfunc:true, mocha:true, node:true */
+var SSF = require('../');
+var fs = require('fs');
+var data = fs.readFileSync('./test/valid.tsv','utf8').split("\n");
+var _data = [0, 1, -2, 3.45, -67.89, "foo"];
+function doit(d) {
+  it(d[0], function() {
+    for(var w = 0; w < _data.length; ++w) {
+      SSF.format(d[0], _data[w]);
+    }
+  });
+}
+describe('valid formats', function() {
+  for(var j=0;j<data.length;++j) {
+    if(!data[j]) return;
+    doit(data[j].replace(/#{255}/g,"").split("\t"));
+  }
+});
diff --git a/test/valid.tsv b/test/valid.tsv
new file mode 100644
index 0000000..9cb45b9
--- /dev/null
+++ b/test/valid.tsv
@@ -0,0 +1,442 @@
+" Excellent"
+" Fair"
+" Good"
+" Poor"
+" Very Good"
+"$"#,##0
+"$"#,##0.00
+"$"#,##0.00_);[Red]\("$"#,##0.00\)
+"$"#,##0.00_);\("$"#,##0.00\)
+"$"#,##0;[Red]\-"$"#,##0
+"$"#,##0_);[Red]\("$"#,##0\)
+"$"#,##0_);\("$"#,##0\)
+"Haha!"\ @\ "Yeah!"
+"TRUE";"TRUE";"FALSE"
+"True";"True";"False";@
+"Years: "0
+"Yes";"Yes";"No";@
+"kl "hh:mm:ss;@
+"£"#,##0.00
+"£"#,##0;[Red]\-"£"#,##0
+"€"#,##0.00
+"€"\ #,##0.00_-
+"上午/下午 "hh"時"mm"分"ss"秒 "
+"¥"#,##0.00;"¥"\-#,##0.00
+#
+# ?/?
+# ??/??
+#" "?/?
+#" "??/??
+#"abded"\ ??/??
+###0.00;-###0.00
+###0;-###0
+##0.0E+0
+#,##0
+#,##0 ;(#,##0)
+#,##0 ;[Red](#,##0)
+#,##0"р.";[Red]\-#,##0"р."
+#,##0.0
+#,##0.00
+#,##0.00 "�"
+#,##0.00 €;-#,##0.00 €
+#,##0.00"р.";[Red]\-#,##0.00"р."
+#,##0.000
+#,##0.0000
+#,##0.00000
+#,##0.000000
+#,##0.0000000
+#,##0.00000000
+#,##0.000000000
+#,##0.00000000;[Red]#,##0.00000000
+#,##0.0000_ 
+#,##0.000_ 
+#,##0.000_);\(#,##0.000\)
+#,##0.00;(#,##0.00)
+#,##0.00;(#,##0.00);0.00
+#,##0.00;[Red](#,##0.00)
+#,##0.00;[Red]\(#,##0.00\)
+#,##0.00;\(#,##0.00\)
+#,##0.00[$₹-449]_);\(#,##0.00[$₹-449]\)
+#,##0.00\ "р."
+#,##0.00\ "р.";[Red]\-#,##0.00\ "р."
+#,##0.00\ [$€-407]
+#,##0.00\ [$€-40C]
+#,##0.00_);\(#,##0.00\)
+#,##0.00_р_.;[Red]\-#,##0.00_р_.
+#,##0.00_р_.;\-#,##0.00_р_.
+#,##0.0;[Red]#,##0.0
+#,##0.0_ ;\-#,##0.0\ 
+#,##0.0_);[Red]\(#,##0.0\)
+#,##0.0_);\(#,##0.0\)
+#,##0;\-#,##0;0
+#,##0\ "р.";[Red]\-#,##0\ "р."
+#,##0\ "р.";\-#,##0\ "р."
+#,##0\ ;[Red]\(#,##0\)
+#,##0\ ;\(#,##0\)
+#,##0_ 
+#,##0_ ;[Red]\-#,##0\ 
+#,##0_);[Red]\(#,##0\)
+#,##0_р_.;[Red]\-#,##0_р_.
+#,##0_р_.;\-#,##0_р_.
+#.0000,,
+#0
+#0.00
+#0.0000
+#\ ?/10
+#\ ?/2
+#\ ?/4
+#\ ?/8
+#\ ?/?
+#\ ??/100
+#\ ??/100;[Red]\(#\ ??/16\)
+#\ ??/16
+#\ ??/??
+#\ ??/?????????
+#\ ???/???
+**\ #,###,#00,000.00,**
+0
+0"abde".0"??"000E+00
+0%
+0.0
+0.0%
+0.00
+0.00"°"
+0.00%
+0.000
+0.000%
+0.0000
+0.000000
+0.00000000
+0.000000000
+0.000000000%
+0.00000000000
+0.000000000000000
+0.00000000E+00
+0.0000E+00
+0.00;[Red]0.00
+0.00E+00
+0.00_);[Red]\(0.00\)
+0.00_);\(0.00\)
+0.0_ 
+00.00.00.000
+00.000%
+0000
+00000
+00000000
+000000000
+00000\-0000
+00000\-00000
+000\-00\-0000
+0;[Red]0
+0\-00000\-00000\-0
+0_);[Red]\(0\)
+0_);\(0\)
+@
+A/P
+AM/PM
+AM/PMh"時"mm"分"ss"秒";@
+D
+DD
+DD/MM/YY;@
+DD/MM/YYYY
+DD/MM/YYYY;@
+DDD
+DDDD
+DDDD", "MMMM\ DD", "YYYY
+GENERAL
+General
+H
+H:MM:SS\ AM/PM
+HH:MM
+HH:MM:SS\ AM/PM
+HHM
+HHMM
+HH[MM]
+HH[M]
+M/D/YYYY
+M/D/YYYY\ H:MM
+MM/DD/YY
+S
+SS
+YY
+YYM
+YYMM
+YYMMM
+YYMMMM
+YYMMMMM
+YYYY
+YYYY-MM-DD HH:MM:SS
+YYYY\-MM\-DD
+[$$-409]#,##0
+[$$-409]#,##0.00
+[$$-409]#,##0.00_);[Red]\([$$-409]#,##0.00\)
+[$$-C09]#,##0.00
+[$-100042A]h:mm:ss\ AM/PM;@
+[$-1010409]0.000%
+[$-1010409]General
+[$-1010409]d/m/yyyy\ h:mm\ AM/PM;@
+[$-1010409]dddd, mmmm dd, yyyy
+[$-1010409]m/d/yyyy
+[$-1409]h:mm:ss\ AM/PM;@
+[$-2000000]h:mm:ss;@
+[$-2010401]d/mm/yyyy\ h:mm\ AM/PM;@
+[$-4000439]h:mm:ss\ AM/PM;@
+[$-4010439]d/m/yyyy\ h:mm\ AM/PM;@
+[$-409]AM/PM\ hh:mm:ss;@
+[$-409]d/m/yyyy\ hh:mm;@
+[$-409]d\-mmm;@
+[$-409]d\-mmm\-yy;@
+[$-409]d\-mmm\-yyyy;@
+[$-409]dd/mm/yyyy\ hh:mm;@
+[$-409]dd\-mmm\-yy;@
+[$-409]h:mm:ss\ AM/PM;@
+[$-409]h:mm\ AM/PM;@
+[$-409]m/d/yy\ h:mm\ AM/PM;@
+[$-409]mmm\-yy;@
+[$-409]mmmm\ d\,\ yyyy;@
+[$-409]mmmm\-yy;@
+[$-409]mmmmm;@
+[$-409]mmmmm\-yy;@
+[$-40E]h\ "óra"\ m\ "perckor"\ AM/PM;@
+[$-412]AM/PM\ h"시"\ mm"분"\ ss"초";@
+[$-41C]h:mm:ss\.AM/PM;@
+[$-449]hh:mm:ss\ AM/PM;@
+[$-44E]hh:mm:ss\ AM/PM;@
+[$-44F]hh:mm:ss\ AM/PM;@
+[$-D000409]h:mm\ AM/PM;@
+[$-D010000]d/mm/yyyy\ h:mm\ "น.";@
+[$-F400]h:mm:ss\ AM/PM
+[$-F800]dddd\,\ mmmm\ dd\,\ yyyy
+[$AUD]\ #,##0.00
+[$RD$-1C0A]#,##0.00;[Red]\-[$RD$-1C0A]#,##0.00
+[$SFr.-810]\ #,##0.00_);[Red]\([$SFr.-810]\ #,##0.00\)
+[$£-809]#,##0.00;[Red][$£-809]#,##0.00
+[$¥-411]#,##0.00
+[$¥-804]#,##0.00
+[<0]"";0%
+[<=9999999]###\-####;\(###\)\ ###\-####
+[=0]?;#,##0.00
+[=0]?;0%
+[=0]?;[<4.16666666666667][hh]:mm:ss;[hh]:mm
+[>999999]#,,"M";[>999]#,"K";#
+[>999999]#.000,,"M";[>999]#.000,"K";#.000
+[>=100000]0.000\ \";[Red]0.000\ \<\ \>\ \"\ \&\ \'\ 
+[>=100000]0.000\ \<;[Red]0.000\ \>
+[BLACK]@
+[BLUE]GENERAL
+[Black]@
+[Blue]General
+[CYAN]@
+[Cyan]@
+[DBNum1][$-804]AM/PMh"时"mm"分";@
+[DBNum1][$-804]General
+[DBNum1][$-804]h"时"mm"分";@
+[ENG][$-1004]dddd\,\ d\ mmmm\,\ yyyy;@
+[ENG][$-101040D]d\ mmmm\ yyyy;@
+[ENG][$-101042A]d\ mmmm\ yyyy;@
+[ENG][$-140C]dddd\ "YeahWoo!"\ ddd\ mmmm\ yyyy;@
+[ENG][$-2C0A]dddd\ d" de "mmmm" de "yyyy;@
+[ENG][$-402]dd\ mmmm\ yyyy\ "г.";@
+[ENG][$-403]dddd\,\ d" / "mmmm" / "yyyy;@
+[ENG][$-405]d\.\ mmmm\ yyyy;@
+[ENG][$-408]d\ mmmm\ yyyy;@
+[ENG][$-409]d\-mmm;@
+[ENG][$-409]d\-mmm\-yy;@
+[ENG][$-409]d\-mmm\-yyyy;@
+[ENG][$-409]dd\-mmm\-yy;@
+[ENG][$-409]mmm\-yy;@
+[ENG][$-409]mmmm\ d\,\ yyyy;@
+[ENG][$-409]mmmm\-yy;@
+[ENG][$-40B]d\.\ mmmm\t\a\ yyyy;@
+[ENG][$-40C]d/mmm/yyyy;@
+[ENG][$-40E]yyyy/\ mmmm\ d\.;@
+[ENG][$-40F]dd\.\ mmmm\ yyyy;@
+[ENG][$-410]d\ mmmm\ yyyy;@
+[ENG][$-415]d\ mmmm\ yyyy;@
+[ENG][$-416]d\ \ mmmm\,\ yyyy;@
+[ENG][$-418]d\ mmmm\ yyyy;@
+[ENG][$-41A]d\.\ mmmm\ yyyy\.;@
+[ENG][$-41B]d\.\ mmmm\ yyyy;@
+[ENG][$-41D]"den "\ d\ mmmm\ yyyy;@
+[ENG][$-420]dddd\,\ dd\ mmmm\,\ yyyy;@
+[ENG][$-421]dd\ mmmm\ yyyy;@
+[ENG][$-424]dddd\,\ d\.\ mmmm\ yyyy;@
+[ENG][$-425]dddd\,\ d\.\ mmmm\ yyyy;@
+[ENG][$-426]dddd\,\ yyyy". gada "d\.\ mmmm;@
+[ENG][$-427]yyyy\ "m."\ mmmm\ d\ "d.";@
+[ENG][$-42B]dddd\,\ d\ mmmm\ yyyy;@
+[ENG][$-42C]d\ mmmm\ yyyy;@
+[ENG][$-42D]yyyy"(e)ko"\ mmmm"ren"\ d"a";@
+[ENG][$-42F]dddd\,\ dd\ mmmm\ yyyy;@
+[ENG][$-437]yyyy\ \წ\ლ\ი\ს\ dd\ mm\,\ dddd;@
+[ENG][$-438]d\.\ mmmm\ yyyy;@
+[ENG][$-43F]d\ mmmm\ yyyy\ "ж.";@
+[ENG][$-444]d\ mmmm\ yyyy;@
+[ENG][$-449]dd\ mmmm\ yyyy;@
+[ENG][$-44E]d\ mmmm\ yyyy;@
+[ENG][$-44F]dd\ mmmm\ yyyy\ dddd;@
+[ENG][$-457]dd\ mmmm\ yyyy;@
+[ENG][$-813]dddd\ d\ mmmm\ yyyy;@
+[ENG][$-81A]dddd\,\ d\.\ mmmm\ yyyy;@
+[ENG][$-82C]d\ mmmm\ yyyy;@
+[ENG][$-843]yyyy\ "й""и""л"\ d/mmmm;@
+[ENG][$-C07]dddd\,\ dd\.\ mmmm\ yyyy;@
+[ENG][$-FC19]yyyy\,\ dd\ mmmm;@
+[ENG][$-FC22]d\ mmmm\ yyyy" р.";@
+[ENG][$-FC23]d\ mmmm\ yyyy;@
+[GREEN]#,###
+[Green]#,###
+[HH]
+[HIJ][$-2060401]d/mm/yyyy\ h:mm\ AM/PM;@
+[HIJ][$-2060401]d\ mmmm\ yyyy;@
+[H]
+[JPN][$-411]gggyy"年"m"月"d"日"\ dddd;@
+[MAGENTA]0.00
+[Magenta]0.00
+[RED]#.##
+[Red]#.##
+[Red][<-25]General;[Blue][>25]General;[Green]General;[Yellow]General\ 
+[Red][<=-25]General;[Blue][>=25]General;[Green]General;[Yellow]General
+[Red][<>50]General;[Blue]000
+[Red][=50]General;[Blue]000
+[SS]
+[S]
+[TWN][DBNum1][$-404]y"年"m"月"d"日";@
+[WHITE]0.0
+[White]0.0
+[YELLOW]@
+[Yellow]@
+[h]
+[h]:mm:ss
+[h]:mm:ss;@
+[h]\.mm" Uhr ";@
+[hh]
+[s]
+[ss]
+\#\r\e\c
+\$#,##0_);[Red]"($"#,##0\)
+\$0.00
+\C\O\B\ \o\n\ @
+\C\R\O\N\T\A\B\ \o\n\ @
+\R\e\s\u\l\t\ \o\n\ @
+\S\Q\L\ \:\ @
+\S\Q\L\ \R\e\q\u\e\s\t\ \f\o\r\ @
+\c\c\c?????0"aaaa"0"bbbb"000000.00%
+\u\n\t\i\l\ h:mm;@
+_ "¥"* #,##0.00_ "Positive";_ "¥"* \-#,##0.00_ ;_ "¥"* "-"??_ "Negtive";_ @_ \ "Zero"
+_ * #,##0.00_)[$﷼-429]_ ;_ * \(#,##0.00\)[$﷼-429]_ ;_ * "-"??_)[$﷼-429]_ ;_ @_ 
+_ * #,##0_ ;_ * \-#,##0_ ;[Red]_ * "-"_ ;_ @_ 
+_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)
+_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"??_);_(@_)
+_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)
+_(* #,##0.0000_);_(* \(#,##0.0000\);_(* "-"??_);_(@_)
+_(* #,##0.000_);_(* \(#,##0.000\);_(* "-"??_);_(@_)
+_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)
+_(* #,##0.0_);_(* \(#,##0.0\);_(* "-"??_);_(@_)
+_(* #,##0_);_(* \(#,##0\);_(* "-"??_);_(@_)
+_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)
+_([$ANG]\ * #,##0.0_);_([$ANG]\ * \(#,##0.0\);_([$ANG]\ * "-"?_);_(@_)
+_-"€"\ * #,##0.00_-;_-"€"\ * #,##0.00\-;_-"€"\ * "-"??_-;_-@_-
+_-* #,##0.00" TL"_-;\-* #,##0.00" TL"_-;_-* \-??" TL"_-;_-@_-
+_-* #,##0.00" €"_-;\-* #,##0.00" €"_-;_-* \-??" €"_-;_-@_-
+_-* #,##0.00\ "р."_-;\-* #,##0.00\ "р."_-;_-* "-"??\ "р."_-;_-@_-
+_-* #,##0.00\ "€"_-;\-* #,##0.00\ "€"_-;_-* "-"??\ "€"_-;_-@_-
+_-* #,##0.00\ [$€-407]_-;\-* #,##0.00\ [$€-407]_-;_-* \-??\ [$€-407]_-;_-@_-
+_-* #,##0.0\ _F_-;\-* #,##0.0\ _F_-;_-* "-"??\ _F_-;_-@_-
+_-* #,##0\ "€"_-;\-* #,##0\ "€"_-;_-* "-"\ "€"_-;_-@_-
+_-* #,##0_-;\-* #,##0_-;_-* "-"??_-;_-@_-
+_-\$* #,##0.0_ ;_-\$* \-#,##0.0\ ;_-\$* "-"?_ ;_-@_ 
+d
+d-mmm
+d-mmm-yy
+d/m
+d/m/yy;@
+d/m/yyyy;@
+d/mm/yy;@
+d/mm/yyyy;@
+d\-mmm
+d\-mmm\-yyyy
+dd
+dd"-"mmm"-"yyyy
+dd/m/yyyy
+dd/mm/yy
+dd/mm/yy;@
+dd/mm/yy\ hh:mm
+dd/mm/yyyy
+dd/mm/yyyy\ hh:mm:ss
+dd/mmm
+dd\-mm\-yy
+dd\-mmm\-yy
+dd\-mmm\-yyyy\ hh:mm:ss.000
+dd\/mm\/yy
+dd\/mm\/yyyy
+ddd
+dddd
+dddd, mmmm dd, yyyy
+h
+h"时"mm"分"ss"秒";@
+h"時"mm"分"ss"秒";@
+h:mm
+h:mm AM/PM
+h:mm:ss
+h:mm:ss AM/PM
+h:mm:ss;@
+h:mm;@
+h\.mm" Uhr ";@
+h\.mm" h";@
+h\.mm" u.";@
+hh":"mm AM/PM
+hh:mm:ss
+hh:mm:ss\ AM/PM
+hh\.mm" h";@
+hhm
+hhmm
+m"月"d"日"
+m/d/yy
+m/d/yy h:mm
+m/d/yy;@
+m/d/yy\ h:mm
+m/d/yy\ h:mm;@
+m/d/yyyy
+m/d/yyyy;@
+m/d/yyyy\ h:mm:ss;@
+m/d;@
+m\/d\/yyyy
+mm/dd
+mm/dd/yy
+mm/dd/yy;@
+mm/dd/yyyy
+mm:ss
+mm:ss.0;@
+mmm d, yyyy
+mmm" "d", "yyyy
+mmm-yy
+mmm-yy;@
+mmm/yy
+mmm\-yy
+mmm\-yy;@
+mmm\-yyyy
+mmmm\ d\,\ yyyy
+mmmm\ yyyy
+mmss.0
+s
+ss
+yy
+yy/mm/dd
+yy\.mm\.dd
+yym
+yymm
+yymmm
+yymmmm
+yymmmmm
+yyyy
+yyyy"년"\ m"월"\ d"일";@
+yyyy-m-d h:mm AM/PM
+yyyy-mm-dd
+yyyy/mm/dd
+yyyy\-m\-d\ hh:mm:ss
+yyyy\-mm\-dd
+yyyy\-mm\-dd;@
+yyyy\-mm\-dd\ h:mm
+yyyy\-mm\-dd\Thh:mm
+yyyy\-mm\-dd\Thhmmss.000