www-thermferm/jqwidgets/globalization/globalize.js

changeset 617
b216f9d4b917
parent 511
2d1d43c3a2c2
--- a/www-thermferm/jqwidgets/globalization/globalize.js	Sun Jul 10 16:58:40 2022 +0200
+++ b/www-thermferm/jqwidgets/globalization/globalize.js	Mon Aug 08 10:54:27 2022 +0200
@@ -1,1 +1,1607 @@
-!function(a,b){var c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;c=function(a){return new c.prototype.init(a)},"undefined"!=typeof require&&"undefined"!=typeof exports&&"undefined"!=typeof module?module.exports=c:a.Globalize=c,c.cultures={},c.prototype={constructor:c,init:function(a){return this.cultures=c.cultures,this.cultureSelector=a,this}},c.prototype.init.prototype=c.prototype,c.cultures.default={name:"en",englishName:"English",nativeName:"English",isRTL:!1,language:"en",numberFormat:{pattern:["-n"],decimals:2,",":",",".":".",groupSizes:[3],"+":"+","-":"-",NaN:"NaN",negativeInfinity:"-Infinity",positiveInfinity:"Infinity",percent:{pattern:["-n %","n %"],decimals:2,groupSizes:[3],",":",",".":".",symbol:"%"},currency:{pattern:["($n)","$n"],decimals:2,groupSizes:[3],",":",",".":".",symbol:"$"}},calendars:{standard:{name:"Gregorian_USEnglish","/":"/",":":":",firstDay:0,days:{names:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],namesAbbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],namesShort:["Su","Mo","Tu","We","Th","Fr","Sa"]},months:{names:["January","February","March","April","May","June","July","August","September","October","November","December",""],namesAbbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""]},AM:["AM","am","AM"],PM:["PM","pm","PM"],eras:[{name:"A.D.",start:null,offset:0}],twoDigitYearMax:2029,patterns:{d:"M/d/yyyy",D:"dddd, MMMM dd, yyyy",t:"h:mm tt",T:"h:mm:ss tt",f:"dddd, MMMM dd, yyyy h:mm tt",F:"dddd, MMMM dd, yyyy h:mm:ss tt",M:"MMMM dd",Y:"yyyy MMMM",S:"yyyy'-'MM'-'dd'T'HH':'mm':'ss"}}},messages:{}},c.cultures.default.calendar=c.cultures.default.calendars.standard,c.cultures.en=c.cultures.default,c.cultureSelector="en",d=/^0x[a-f0-9]+$/i,e=/^[+\-]?infinity$/i,f=/^[+\-]?\d*\.?\d*(e[+\-]?\d+)?$/,g=/^\s+|\s+$/g,h=function(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},i=function(a,b){return a.substr(a.length-b.length)===b},j=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,n=arguments.length,o=!1;for("boolean"==typeof h&&(o=h,h=arguments[1]||{},i=2),"object"==typeof h||l(h)||(h={});i<n;i++)if(null!=(a=arguments[i]))for(c in a)d=h[c],e=a[c],h!==e&&(o&&e&&(m(e)||(f=k(e)))?(f?(f=!1,g=d&&k(d)?d:[]):g=d&&m(d)?d:{},h[c]=j(o,g,e)):e!==b&&(h[c]=e));return h},k=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)},l=function(a){return"[object Function]"===Object.prototype.toString.call(a)},m=function(a){return"[object Object]"===Object.prototype.toString.call(a)},n=function(a,b){return 0===a.indexOf(b)},o=function(a){return(a+"").replace(g,"")},p=function(a){return isNaN(a)?NaN:Math[a<0?"ceil":"floor"](a)},q=function(a,b,c){var d;for(d=a.length;d<b;d+=1)a=c?"0"+a:a+"0";return a},r=function(a,b){for(var c=0,d=!1,e=0,f=a.length;e<f;e++){var g=a.charAt(e);switch(g){case"'":d?b.push("'"):c++,d=!1;break;case"\\":d&&b.push("\\"),d=!d;break;default:b.push(g),d=!1}}return c},s=function(a,b){b=b||"F";var c,d=a.patterns,e=b.length;if(1===e){if(c=d[b],!c)throw"Invalid date format string '"+b+"'.";b=c}else 2===e&&"%"===b.charAt(0)&&(b=b.charAt(1));return b},t=function(a,b,c){function d(a,b){if(a<0)return"-"+d(-a,b);var c,e=a+"";return b>1&&e.length<b?(c=u[b-2]+e,c.substr(c.length-b,b)):c=e}function e(){return o||p?o:(o=y.test(b),p=!0,o)}function f(a,b){if(q)return q[b];switch(b){case 0:return a.getFullYear();case 1:return a.getMonth();case 2:return a.getDate();default:throw"Invalid part value "+b}}var g,h=c.calendar,i=h.convert;if(!b||!b.length||"i"===b){if(c&&c.name.length)if(i)g=t(a,h.patterns.F,c);else{var j=new Date(a.getTime()),k=w(a,h.eras);j.setFullYear(x(a,h,k)),g=j.toLocaleString()}else g=a.toString();return g}var l=h.eras,m="s"===b;b=s(h,b),g=[];var n,o,p,q,u=["0","00","000"],y=/([^d]|^)(d|dd)([^d]|$)/g,z=0,A=v();for(!m&&i&&(q=i.fromGregorian(a));;){var B=A.lastIndex,C=A.exec(b),D=b.slice(B,C?C.index:b.length);if(z+=r(D,g),!C)break;if(z%2)g.push(C[0]);else{var E=C[0],F=E.length;switch(E){case"ddd":case"dddd":var G=3===F?h.days.namesAbbr:h.days.names;g.push(G[a.getDay()]);break;case"d":case"dd":o=!0,g.push(d(f(a,2),F));break;case"MMM":case"MMMM":var H=f(a,1);g.push(h.monthsGenitive&&e()?h.monthsGenitive[3===F?"namesAbbr":"names"][H]:h.months[3===F?"namesAbbr":"names"][H]);break;case"M":case"MM":g.push(d(f(a,1)+1,F));break;case"y":case"yy":case"yyyy":H=q?q[0]:x(a,h,w(a,l),m),F<4&&(H%=100),g.push(d(H,F));break;case"h":case"hh":n=a.getHours()%12,0===n&&(n=12),g.push(d(n,F));break;case"H":case"HH":g.push(d(a.getHours(),F));break;case"m":case"mm":g.push(d(a.getMinutes(),F));break;case"s":case"ss":g.push(d(a.getSeconds(),F));break;case"t":case"tt":H=a.getHours()<12?h.AM?h.AM[0]:" ":h.PM?h.PM[0]:" ",g.push(1===F?H.charAt(0):H);break;case"f":case"ff":case"fff":g.push(d(a.getMilliseconds(),3).substr(0,F));break;case"z":case"zz":n=a.getTimezoneOffset()/60,g.push((n<=0?"+":"-")+d(Math.floor(Math.abs(n)),F));break;case"zzz":n=a.getTimezoneOffset()/60,g.push((n<=0?"+":"-")+d(Math.floor(Math.abs(n)),2)+":"+d(Math.abs(a.getTimezoneOffset()%60),2));break;case"g":case"gg":h.eras&&g.push(h.eras[w(a,l)].name);break;case"/":g.push(h["/"]);break;default:throw"Invalid date format pattern '"+E+"'."}}}return g.join("")},function(){var a;a=function(a,b,c){var d=c.groupSizes,e=d[0],f=1,g=Math.pow(10,b),h=Math.round(a*g)/g;isFinite(h)||(h=a),a=h;var i=a+"",j="",k=i.split(/e/i),l=k.length>1?parseInt(k[1],10):0;i=k[0],k=i.split("."),i=k[0],j=k.length>1?k[1]:"";l>0?(j=q(j,l,!1),i+=j.slice(0,l),j=j.substr(l)):l<0&&(l=-l,i=q(i,l+1,!0),j=i.slice(-l,i.length)+j,i=i.slice(0,-l)),j=b>0?c["."]+(j.length>b?j.slice(0,b):q(j,b)):"";for(var m=i.length-1,n=c[","],o="";m>=0;){if(0===e||e>m)return i.slice(0,m+1)+(o.length?n+o+j:j);o=i.slice(m-e+1,m+1)+(o.length?n+o:""),m-=e,f<d.length&&(e=d[f],f++)}return i.slice(0,m+1)+n+o+j},u=function(b,c,d){if(!isFinite(b))return b===1/0?d.numberFormat.positiveInfinity:b===-(1/0)?d.numberFormat.negativeInfinity:d.numberFormat.NaN;if(!c||"i"===c)return d.name.length?b.toLocaleString():b.toString();c=c||"D";var e,f=d.numberFormat,g=Math.abs(b),h=-1;c.length>1&&(h=parseInt(c.slice(1),10));var i,j=c.charAt(0).toUpperCase();switch(j){case"D":e="n",g=p(g),h!==-1&&(g=q(""+g,h,!0)),b<0&&(g="-"+g);break;case"N":i=f;case"C":i=i||f.currency;case"P":i=i||f.percent,e=b<0?i.pattern[0]:i.pattern[1]||"n",h===-1&&(h=i.decimals),g=a(g*("P"===j?100:1),h,i);break;default:throw"Bad number format specifier: "+j}for(var k=/n|\$|-|%/g,l="";;){var m=k.lastIndex,n=k.exec(e);if(l+=e.slice(m,n?n.index:e.length),!n)break;switch(n[0]){case"n":l+=g;break;case"$":l+=f.currency.symbol;break;case"-":/[1-9]/.test(g)&&(l+=f["-"]);break;case"%":l+=f.percent.symbol}}return l}}(),v=function(){return/\/|dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z|gg|g/g},w=function(a,b){if(!b)return 0;for(var c,d=a.getTime(),e=0,f=b.length;e<f;e++)if(c=b[e].start,null===c||d>=c)return e;return 0},x=function(a,b,c,d){var e=a.getFullYear();return!d&&b.eras&&(e-=b.eras[c].offset),e},function(){var a,b,c,d,e,f,g;a=function(a,b){if(b<100){var c=new Date,d=w(c),e=x(c,a,d),f=a.twoDigitYearMax;f="string"==typeof f?(new Date).getFullYear()%100+parseInt(f,10):f,b+=e-e%100,b>f&&(b-=100)}return b},b=function(a,b,c){var d,e=a.days,i=a._upperDays;return i||(a._upperDays=i=[g(e.names),g(e.namesAbbr),g(e.namesShort)]),b=f(b),c?(d=h(i[1],b),d===-1&&(d=h(i[2],b))):d=h(i[0],b),d},c=function(a,b,c){var d=a.months,e=a.monthsGenitive||a.months,i=a._upperMonths,j=a._upperMonthsGen;i||(a._upperMonths=i=[g(d.names),g(d.namesAbbr)],a._upperMonthsGen=j=[g(e.names),g(e.namesAbbr)]),b=f(b);var k=h(c?i[1]:i[0],b);return k<0&&(k=h(c?j[1]:j[0],b)),k},d=function(a,b){var c=a._parseRegExp;if(c){var d=c[b];if(d)return d}else a._parseRegExp=c={};for(var e,f=s(a,b).replace(/([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g,"\\\\$1"),g=["^"],h=[],i=0,j=0,k=v();null!==(e=k.exec(f));){var l=f.slice(i,e.index);if(i=k.lastIndex,j+=r(l,g),j%2)g.push(e[0]);else{var m,n=e[0],o=n.length;switch(n){case"dddd":case"ddd":case"MMMM":case"MMM":case"gg":case"g":m="(\\D+)";break;case"tt":case"t":m="(\\D*)";break;case"yyyy":case"fff":case"ff":case"f":m="(\\d{"+o+"})";break;case"dd":case"d":case"MM":case"M":case"yy":case"y":case"HH":case"H":case"hh":case"h":case"mm":case"m":case"ss":case"s":m="(\\d\\d?)";break;case"zzz":m="([+-]?\\d\\d?:\\d{2})";break;case"zz":case"z":m="([+-]?\\d\\d?)";break;case"/":m="(\\/)";break;default:throw"Invalid date format pattern '"+n+"'."}m&&g.push(m),h.push(e[0])}}r(f.slice(i),g),g.push("$");var p=g.join("").replace(/\s+/g,"\\s+"),q={regExp:p,groups:h};return c[b]=q},e=function(a,b,c){return a<b||a>c},f=function(a){return a.split(" ").join(" ").toUpperCase()},g=function(a){for(var b=[],c=0,d=a.length;c<d;c++)b[c]=f(a[c]);return b},y=function(f,g,h){f=o(f);var i=h.calendar,j=d(i,g),k=new RegExp(j.regExp).exec(f);if(null===k)return null;for(var l,m=j.groups,p=null,q=null,r=null,s=null,t=null,u=0,v=0,w=0,x=0,y=null,z=!1,A=0,B=m.length;A<B;A++){var C=k[A+1];if(C){var D=m[A],E=D.length,F=parseInt(C,10);switch(D){case"dd":case"d":if(s=F,e(s,1,31))return null;break;case"MMM":case"MMMM":if(r=c(i,C,3===E),e(r,0,11))return null;break;case"M":case"MM":if(r=F-1,e(r,0,11))return null;break;case"y":case"yy":case"yyyy":if(q=E<4?a(i,F):F,e(q,0,9999))return null;break;case"h":case"hh":if(u=F,12===u&&(u=0),e(u,0,11))return null;break;case"H":case"HH":if(u=F,e(u,0,23))return null;break;case"m":case"mm":if(v=F,e(v,0,59))return null;break;case"s":case"ss":if(w=F,e(w,0,59))return null;break;case"tt":case"t":if(z=i.PM&&(C===i.PM[0]||C===i.PM[1]||C===i.PM[2]),!z&&(!i.AM||C!==i.AM[0]&&C!==i.AM[1]&&C!==i.AM[2]))return null;break;case"f":case"ff":case"fff":if(x=F*Math.pow(10,3-E),e(x,0,999))return null;break;case"ddd":case"dddd":if(t=b(i,C,3===E),e(t,0,6))return null;break;case"zzz":var G=C.split(/:/);if(2!==G.length)return null;if(l=parseInt(G[0],10),e(l,-12,13))return null;var H=parseInt(G[1],10);if(e(H,0,59))return null;y=60*l+(n(C,"-")?-H:H);break;case"z":case"zz":if(l=F,e(l,-12,13))return null;y=60*l;break;case"g":case"gg":var I=C;if(!I||!i.eras)return null;I=o(I.toLowerCase());for(var J=0,K=i.eras.length;J<K;J++)if(I===i.eras[J].name.toLowerCase()){p=J;break}if(null===p)return null}}}var L,M=new Date,N=i.convert;if(L=N?N.fromGregorian(M)[0]:M.getFullYear(),null===q?q=L:i.eras&&(q+=i.eras[p||0].offset),null===r&&(r=0),null===s&&(s=1),N){if(M=N.toGregorian(q,r,s),null===M)return null}else{if(M.setFullYear(q,r,s),M.getDate()!==s)return null;if(null!==t&&M.getDay()!==t)return null}if(z&&u<12&&(u+=12),M.setHours(u,v,w,x),null!==y){var O=M.getMinutes()-(y+M.getTimezoneOffset());M.setHours(M.getHours()+parseInt(O/60,10),O%60)}return M}}(),z=function(a,b,c){var d,e=b["-"],f=b["+"];switch(c){case"n -":e=" "+e,f=" "+f;case"n-":i(a,e)?d=["-",a.substr(0,a.length-e.length)]:i(a,f)&&(d=["+",a.substr(0,a.length-f.length)]);break;case"- n":e+=" ",f+=" ";case"-n":n(a,e)?d=["-",a.substr(e.length)]:n(a,f)&&(d=["+",a.substr(f.length)]);break;case"(n)":n(a,"(")&&i(a,")")&&(d=["-",a.substr(1,a.length-2)])}return d||["",a]},c.prototype.findClosestCulture=function(a){return c.findClosestCulture.call(this,a)},c.prototype.format=function(a,b,d){return c.format.call(this,a,b,d)},c.prototype.localize=function(a,b){return c.localize.call(this,a,b)},c.prototype.parseInt=function(a,b,d){return c.parseInt.call(this,a,b,d)},c.prototype.parseFloat=function(a,b,d){return c.parseFloat.call(this,a,b,d)},c.prototype.culture=function(a){return c.culture.call(this,a)},c.addCultureInfo=function(a,b,c){var d={},e=!1;"string"!=typeof a?(c=a,a=this.culture().name,d=this.cultures[a]):"string"!=typeof b?(c=b,e=null==this.cultures[a],d=this.cultures[a]||this.cultures.default):(e=!0,d=this.cultures[b]),this.cultures[a]=j(!0,{},d,c),e&&(this.cultures[a].calendar=this.cultures[a].calendars.standard)},c.findClosestCulture=function(a){var b;if(!a)return this.findClosestCulture(this.cultureSelector)||this.cultures.default;if("string"==typeof a&&(a=a.split(",")),k(a)){var c,d,e=this.cultures,f=a,g=f.length,h=[];for(d=0;d<g;d++){a=o(f[d]);var i,j=a.split(";");c=o(j[0]),1===j.length?i=1:(a=o(j[1]),0===a.indexOf("q=")?(a=a.substr(2),i=parseFloat(a),i=isNaN(i)?0:i):i=1),h.push({lang:c,pri:i})}for(h.sort(function(a,b){return a.pri<b.pri?1:a.pri>b.pri?-1:0}),d=0;d<g;d++)if(c=h[d].lang,b=e[c])return b;for(d=0;d<g;d++)for(c=h[d].lang;;){var l=c.lastIndexOf("-");if(l===-1)break;if(c=c.substr(0,l),b=e[c])return b}for(d=0;d<g;d++){c=h[d].lang;for(var m in e){var n=e[m];if(n.language==c)return n}}}else if("object"==typeof a)return a;return b||null},c.format=function(a,b,c){var d=this.findClosestCulture(c);return a instanceof Date?a=t(a,b,d):"number"==typeof a&&(a=u(a,b,d)),a},c.localize=function(a,b){return this.findClosestCulture(b).messages[a]||this.cultures.default.messages[a]},c.parseDate=function(a,b,c){c=this.findClosestCulture(c);var d,e,f;if(b){if("string"==typeof b&&(b=[b]),b.length)for(var g=0,h=b.length;g<h;g++){var i=b[g];if(i&&(d=y(a,i,c)))break}}else{f=c.calendar.patterns;for(e in f)if(d=y(a,f[e],c))break}return d||null},c.parseInt=function(a,b,d){return p(c.parseFloat(a,b,d))},c.parseFloat=function(a,b,c){"number"!=typeof b&&(c=b,b=10);var g=this.findClosestCulture(c),h=NaN,i=g.numberFormat;if(a.indexOf(g.numberFormat.currency.symbol)>-1&&(a=a.replace(g.numberFormat.currency.symbol,""),a=a.replace(g.numberFormat.currency["."],g.numberFormat["."])),a.indexOf(g.numberFormat.percent.symbol)>-1&&(a=a.replace(g.numberFormat.percent.symbol,"")),a=a.replace(/ /g,""),e.test(a))h=parseFloat(a);else if(!b&&d.test(a))h=parseInt(a,16);else{var j=z(a,i,i.pattern[0]),k=j[0],l=j[1];""===k&&"(n)"!==i.pattern[0]&&(j=z(a,i,"(n)"),k=j[0],l=j[1]),""===k&&"-n"!==i.pattern[0]&&(j=z(a,i,"-n"),k=j[0],l=j[1]),k=k||"+";var m,n,o=l.indexOf("e");o<0&&(o=l.indexOf("E")),o<0?(n=l,m=null):(n=l.substr(0,o),m=l.substr(o+1));var p,q,r=i["."],s=n.indexOf(r);s<0?(p=n,q=null):(p=n.substr(0,s),q=n.substr(s+r.length));var t=i[","];p=p.split(t).join("");var u=t.replace(/\u00A0/g," ");t!==u&&(p=p.split(u).join(""));var v=k+p;if(null!==q&&(v+="."+q),null!==m){var w=z(m,i,"-n");v+="e"+(w[0]||"+")+w[1]}f.test(v)&&(h=parseFloat(v))}return h},c.culture=function(a){return"undefined"!=typeof a&&(this.cultureSelector=a),this.findClosestCulture(a)||this.cultures.default}}(this);
\ No newline at end of file
+/* tslint:disable */
+/* eslint-disable */
+/*!
+ * Globalize
+ *
+ * http://github.com/jquery/globalize
+ *
+ * Copyright Software Freedom Conservancy, Inc.
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+
+(function( window, undefined ) {
+if (document.Globalize) {
+    return;
+}
+
+var Globalize,
+	// private variables
+	regexHex,
+	regexInfinity,
+	regexParseFloat,
+	regexTrim,
+	// private JavaScript utility functions
+	arrayIndexOf,
+	endsWith,
+	extend,
+	isArray,
+	isFunction,
+	isObject,
+	startsWith,
+	trim,
+	truncate,
+	zeroPad,
+	// private Globalization utility functions
+	appendPreOrPostMatch,
+	expandFormat,
+	formatDate,
+	formatNumber,
+	getTokenRegExp,
+	getEra,
+	getEraYear,
+	parseExact,
+	parseNegativePattern;
+
+// Global variable (Globalize) or CommonJS module (globalize)
+Globalize = function( cultureSelector ) {
+	return new Globalize.prototype.init( cultureSelector );
+};
+
+if ( typeof require !== "undefined" &&
+	typeof exports !== "undefined" &&
+	typeof module !== "undefined" ) {
+	// Assume CommonJS
+	module.exports = Globalize;
+} else {
+	// Export as global variable
+	window.Globalize = Globalize;
+}
+
+Globalize.cultures = {};
+
+Globalize.prototype = {
+	constructor: Globalize,
+	init: function( cultureSelector ) {
+		this.cultures = Globalize.cultures;
+		this.cultureSelector = cultureSelector;
+
+		return this;
+	}
+};
+Globalize.prototype.init.prototype = Globalize.prototype;
+
+// 1. When defining a culture, all fields are required except the ones stated as optional.
+// 2. Each culture should have a ".calendars" object with at least one calendar named "standard"
+//    which serves as the default calendar in use by that culture.
+// 3. Each culture should have a ".calendar" object which is the current calendar being used,
+//    it may be dynamically changed at any time to one of the calendars in ".calendars".
+Globalize.cultures[ "default" ] = {
+	// A unique name for the culture in the form <language code>-<country/region code>
+	name: "en",
+	// the name of the culture in the english language
+	englishName: "English",
+	// the name of the culture in its own language
+	nativeName: "English",
+	// whether the culture uses right-to-left text
+	isRTL: false,
+	// "language" is used for so-called "specific" cultures.
+	// For example, the culture "es-CL" means "Spanish, in Chili".
+	// It represents the Spanish-speaking culture as it is in Chili,
+	// which might have different formatting rules or even translations
+	// than Spanish in Spain. A "neutral" culture is one that is not
+	// specific to a region. For example, the culture "es" is the generic
+	// Spanish culture, which may be a more generalized version of the language
+	// that may or may not be what a specific culture expects.
+	// For a specific culture like "es-CL", the "language" field refers to the
+	// neutral, generic culture information for the language it is using.
+	// This is not always a simple matter of the string before the dash.
+	// For example, the "zh-Hans" culture is netural (Simplified Chinese).
+	// And the "zh-SG" culture is Simplified Chinese in Singapore, whose lanugage
+	// field is "zh-CHS", not "zh".
+	// This field should be used to navigate from a specific culture to it's
+	// more general, neutral culture. If a culture is already as general as it
+	// can get, the language may refer to itself.
+	language: "en",
+	// numberFormat defines general number formatting rules, like the digits in
+	// each grouping, the group separator, and how negative numbers are displayed.
+	numberFormat: {
+		// [negativePattern]
+		// Note, numberFormat.pattern has no "positivePattern" unlike percent and currency,
+		// but is still defined as an array for consistency with them.
+		//   negativePattern: one of "(n)|-n|- n|n-|n -"
+		pattern: [ "-n" ],
+		// number of decimal places normally shown
+		decimals: 2,
+		// string that separates number groups, as in 1,000,000
+		",": ",",
+		// string that separates a number from the fractional portion, as in 1.99
+		".": ".",
+		// array of numbers indicating the size of each number group.
+		// TODO: more detailed description and example
+		groupSizes: [ 3 ],
+		// symbol used for positive numbers
+		"+": "+",
+		// symbol used for negative numbers
+		"-": "-",
+		// symbol used for NaN (Not-A-Number)
+		"NaN": "NaN",
+		// symbol used for Negative Infinity
+		negativeInfinity: "-Infinity",
+		// symbol used for Positive Infinity
+		positiveInfinity: "Infinity",
+		percent: {
+			// [negativePattern, positivePattern]
+			//   negativePattern: one of "-n %|-n%|-%n|%-n|%n-|n-%|n%-|-% n|n %-|% n-|% -n|n- %"
+			//   positivePattern: one of "n %|n%|%n|% n"
+			pattern: [ "-n %", "n %" ],
+			// number of decimal places normally shown
+			decimals: 2,
+			// array of numbers indicating the size of each number group.
+			// TODO: more detailed description and example
+			groupSizes: [ 3 ],
+			// string that separates number groups, as in 1,000,000
+			",": ",",
+			// string that separates a number from the fractional portion, as in 1.99
+			".": ".",
+			// symbol used to represent a percentage
+			symbol: "%"
+		},
+		currency: {
+			// [negativePattern, positivePattern]
+			//   negativePattern: one of "($n)|-$n|$-n|$n-|(n$)|-n$|n-$|n$-|-n $|-$ n|n $-|$ n-|$ -n|n- $|($ n)|(n $)"
+			//   positivePattern: one of "$n|n$|$ n|n $"
+			pattern: [ "($n)", "$n" ],
+			// number of decimal places normally shown
+			decimals: 2,
+			// array of numbers indicating the size of each number group.
+			// TODO: more detailed description and example
+			groupSizes: [ 3 ],
+			// string that separates number groups, as in 1,000,000
+			",": ",",
+			// string that separates a number from the fractional portion, as in 1.99
+			".": ".",
+			// symbol used to represent currency
+			symbol: "$"
+		}
+	},
+	// calendars defines all the possible calendars used by this culture.
+	// There should be at least one defined with name "standard", and is the default
+	// calendar used by the culture.
+	// A calendar contains information about how dates are formatted, information about
+	// the calendar's eras, a standard set of the date formats,
+	// translations for day and month names, and if the calendar is not based on the Gregorian
+	// calendar, conversion functions to and from the Gregorian calendar.
+	calendars: {
+		standard: {
+			// name that identifies the type of calendar this is
+			name: "Gregorian_USEnglish",
+			// separator of parts of a date (e.g. "/" in 11/05/1955)
+			"/": "/",
+			// separator of parts of a time (e.g. ":" in 05:44 PM)
+			":": ":",
+			// the first day of the week (0 = Sunday, 1 = Monday, etc)
+			firstDay: 0,
+			days: {
+				// full day names
+				names: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
+				// abbreviated day names
+				namesAbbr: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
+				// shortest day names
+				namesShort: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ]
+			},
+			months: {
+				// full month names (13 months for lunar calendards -- 13th month should be "" if not lunar)
+				names: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "" ],
+				// abbreviated month names
+				namesAbbr: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" ]
+			},
+			// AM and PM designators in one of these forms:
+			// The usual view, and the upper and lower case versions
+			//   [ standard, lowercase, uppercase ]
+			// The culture does not use AM or PM (likely all standard date formats use 24 hour time)
+			//   null
+			AM: [ "AM", "am", "AM" ],
+			PM: [ "PM", "pm", "PM" ],
+			eras: [
+				// eras in reverse chronological order.
+				// name: the name of the era in this culture (e.g. A.D., C.E.)
+				// start: when the era starts in ticks (gregorian, gmt), null if it is the earliest supported era.
+				// offset: offset in years from gregorian calendar
+				{
+					"name": "A.D.",
+					"start": null,
+					"offset": 0
+				}
+			],
+			// when a two digit year is given, it will never be parsed as a four digit
+			// year greater than this year (in the appropriate era for the culture)
+			// Set it as a full year (e.g. 2029) or use an offset format starting from
+			// the current year: "+19" would correspond to 2029 if the current year 2010.
+			twoDigitYearMax: 2029,
+			// set of predefined date and time patterns used by the culture
+			// these represent the format someone in this culture would expect
+			// to see given the portions of the date that are shown.
+			patterns: {
+				// short date pattern
+				d: "M/d/yyyy",
+				// long date pattern
+				D: "dddd, MMMM dd, yyyy",
+				// short time pattern
+				t: "h:mm tt",
+				// long time pattern
+				T: "h:mm:ss tt",
+				// long date, short time pattern
+				f: "dddd, MMMM dd, yyyy h:mm tt",
+				// long date, long time pattern
+				F: "dddd, MMMM dd, yyyy h:mm:ss tt",
+				// month/day pattern
+				M: "MMMM dd",
+				// month/year pattern
+				Y: "yyyy MMMM",
+				// S is a sortable format that does not vary by culture
+				S: "yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss"
+			}
+			// optional fields for each calendar:
+			/*
+			monthsGenitive:
+				Same as months but used when the day preceeds the month.
+				Omit if the culture has no genitive distinction in month names.
+				For an explaination of genitive months, see http://blogs.msdn.com/michkap/archive/2004/12/25/332259.aspx
+			convert:
+				Allows for the support of non-gregorian based calendars. This convert object is used to
+				to convert a date to and from a gregorian calendar date to handle parsing and formatting.
+				The two functions:
+					fromGregorian( date )
+						Given the date as a parameter, return an array with parts [ year, month, day ]
+						corresponding to the non-gregorian based year, month, and day for the calendar.
+					toGregorian( year, month, day )
+						Given the non-gregorian year, month, and day, return a new Date() object
+						set to the corresponding date in the gregorian calendar.
+			*/
+		}
+	},
+	// For localized strings
+	messages: {}
+};
+
+Globalize.cultures[ "default" ].calendar = Globalize.cultures[ "default" ].calendars.standard;
+
+Globalize.cultures.en = Globalize.cultures[ "default" ];
+
+Globalize.cultureSelector = "en";
+
+//
+// private variables
+//
+
+regexHex = /^0x[a-f0-9]+$/i;
+regexInfinity = /^[+\-]?infinity$/i;
+regexParseFloat = /^[+\-]?\d*\.?\d*(e[+\-]?\d+)?$/;
+regexTrim = /^\s+|\s+$/g;
+
+//
+// private JavaScript utility functions
+//
+
+arrayIndexOf = function( array, item ) {
+	if ( array.indexOf ) {
+		return array.indexOf( item );
+	}
+	for ( var i = 0, length = array.length; i < length; i++ ) {
+		if ( array[i] === item ) {
+			return i;
+		}
+	}
+	return -1;
+};
+
+endsWith = function( value, pattern ) {
+	return value.substr( value.length - pattern.length ) === pattern;
+};
+
+extend = function() {
+	var options, name, src, copy, copyIsArray, clone,
+		target = arguments[0] || {},
+		i = 1,
+		length = arguments.length,
+		deep = false;
+
+	// Handle a deep copy situation
+	if ( typeof target === "boolean" ) {
+		deep = target;
+		target = arguments[1] || {};
+		// skip the boolean and the target
+		i = 2;
+	}
+
+	// Handle case when target is a string or something (possible in deep copy)
+	if ( typeof target !== "object" && !isFunction(target) ) {
+		target = {};
+	}
+
+	for ( ; i < length; i++ ) {
+		// Only deal with non-null/undefined values
+		if ( (options = arguments[ i ]) != null ) {
+			// Extend the base object
+			for ( name in options ) {
+				src = target[ name ];
+				copy = options[ name ];
+
+				// Prevent never-ending loop
+				if ( target === copy ) {
+					continue;
+				}
+
+				// Recurse if we're merging plain objects or arrays
+				if ( deep && copy && ( isObject(copy) || (copyIsArray = isArray(copy)) ) ) {
+					if ( copyIsArray ) {
+						copyIsArray = false;
+						clone = src && isArray(src) ? src : [];
+
+					} else {
+						clone = src && isObject(src) ? src : {};
+					}
+
+					// Never move original objects, clone them
+					target[ name ] = extend( deep, clone, copy );
+
+				// Don't bring in undefined values
+				} else if ( copy !== undefined ) {
+					target[ name ] = copy;
+				}
+			}
+		}
+	}
+
+	// Return the modified object
+	return target;
+};
+
+isArray = Array.isArray || function( obj ) {
+	return Object.prototype.toString.call( obj ) === "[object Array]";
+};
+
+isFunction = function( obj ) {
+	return Object.prototype.toString.call( obj ) === "[object Function]";
+};
+
+isObject = function( obj ) {
+	return Object.prototype.toString.call( obj ) === "[object Object]";
+};
+
+startsWith = function( value, pattern ) {
+	return value.indexOf( pattern ) === 0;
+};
+
+trim = function( value ) {
+	return ( value + "" ).replace( regexTrim, "" );
+};
+
+truncate = function( value ) {
+	if ( isNaN( value ) ) {
+		return NaN;
+	}
+	return Math[ value < 0 ? "ceil" : "floor" ]( value );
+};
+
+zeroPad = function( str, count, left ) {
+	var l;
+	for ( l = str.length; l < count; l += 1 ) {
+		str = ( left ? ("0" + str) : (str + "0") );
+	}
+	return str;
+};
+
+//
+// private Globalization utility functions
+//
+
+appendPreOrPostMatch = function( preMatch, strings ) {
+	// appends pre- and post- token match strings while removing escaped characters.
+	// Returns a single quote count which is used to determine if the token occurs
+	// in a string literal.
+	var quoteCount = 0,
+		escaped = false;
+	for ( var i = 0, il = preMatch.length; i < il; i++ ) {
+		var c = preMatch.charAt( i );
+		switch ( c ) {
+			case "\'":
+				if ( escaped ) {
+					strings.push( "\'" );
+				}
+				else {
+					quoteCount++;
+				}
+				escaped = false;
+				break;
+			case "\\":
+				if ( escaped ) {
+					strings.push( "\\" );
+				}
+				escaped = !escaped;
+				break;
+			default:
+				strings.push( c );
+				escaped = false;
+				break;
+		}
+	}
+	return quoteCount;
+};
+
+expandFormat = function( cal, format ) {
+	// expands unspecified or single character date formats into the full pattern.
+	format = format || "F";
+	var pattern,
+		patterns = cal.patterns,
+		len = format.length;
+	if ( len === 1 ) {
+		pattern = patterns[ format ];
+		if ( !pattern ) {
+			throw "Invalid date format string \'" + format + "\'.";
+		}
+		format = pattern;
+	}
+	else if ( len === 2 && format.charAt(0) === "%" ) {
+		// %X escape format -- intended as a custom format string that is only one character, not a built-in format.
+		format = format.charAt( 1 );
+	}
+	return format;
+};
+
+formatDate = function( value, format, culture ) {
+	var cal = culture.calendar,
+		convert = cal.convert,
+		ret;
+
+	if ( !format || !format.length || format === "i" ) {
+		if ( culture && culture.name.length ) {
+			if ( convert ) {
+				// non-gregorian calendar, so we cannot use built-in toLocaleString()
+				ret = formatDate( value, cal.patterns.F, culture );
+			}
+			else {
+				var eraDate = new Date( value.getTime() ),
+					era = getEra( value, cal.eras );
+				eraDate.setFullYear( getEraYear(value, cal, era) );
+				ret = eraDate.toLocaleString();
+			}
+		}
+		else {
+			ret = value.toString();
+		}
+		return ret;
+	}
+
+	var eras = cal.eras,
+		sortable = format === "s";
+	format = expandFormat( cal, format );
+
+	// Start with an empty string
+	ret = [];
+	var hour,
+		zeros = [ "0", "00", "000" ],
+		foundDay,
+		checkedDay,
+		dayPartRegExp = /([^d]|^)(d|dd)([^d]|$)/g,
+		quoteCount = 0,
+		tokenRegExp = getTokenRegExp(),
+		converted;
+
+	//function padZeros( num, c ) {
+	//	var r, s = num + "";
+	//	if ( c > 1 && s.length < c ) {
+	//		r = ( zeros[c - 2] + s);
+	//		return r.substr( r.length - c, c );
+	//	}
+	//	else {
+	//		r = s;
+	//	}
+	//	return r;
+	//}
+
+	function padZeros(num, c) {
+	    if (num < 0) {
+	        return "-" + padZeros(-num, c);
+	    }
+	    var r, s = num + "";
+	    if (c > 1 && s.length < c) {
+	        r = (zeros[c - 2] + s);
+	        return r.substr(r.length - c, c);
+	    }
+	    else {
+	        r = s;
+	    }
+	    return r;
+	}
+
+	function hasDay() {
+		if ( foundDay || checkedDay ) {
+			return foundDay;
+		}
+		foundDay = dayPartRegExp.test( format );
+		checkedDay = true;
+		return foundDay;
+	}
+
+	function getPart( date, part ) {
+		if ( converted ) {
+			return converted[ part ];
+		}
+		switch ( part ) {
+			case 0:
+				return date.getFullYear();
+			case 1:
+				return date.getMonth();
+			case 2:
+				return date.getDate();
+			default:
+				throw "Invalid part value " + part;
+		}
+	}
+
+	if ( !sortable && convert ) {
+		converted = convert.fromGregorian( value );
+	}
+
+	for ( ; ; ) {
+		// Save the current index
+		var index = tokenRegExp.lastIndex,
+			// Look for the next pattern
+			ar = tokenRegExp.exec( format );
+
+		// Append the text before the pattern (or the end of the string if not found)
+		var preMatch = format.slice( index, ar ? ar.index : format.length );
+		quoteCount += appendPreOrPostMatch( preMatch, ret );
+
+		if ( !ar ) {
+			break;
+		}
+
+		// do not replace any matches that occur inside a string literal.
+		if ( quoteCount % 2 ) {
+			ret.push( ar[0] );
+			continue;
+		}
+
+		var current = ar[ 0 ],
+			clength = current.length;
+
+		switch ( current ) {
+			case "ddd":
+				//Day of the week, as a three-letter abbreviation
+			case "dddd":
+				// Day of the week, using the full name
+				var names = ( clength === 3 ) ? cal.days.namesAbbr : cal.days.names;
+				ret.push( names[value.getDay()] );
+				break;
+			case "d":
+				// Day of month, without leading zero for single-digit days
+			case "dd":
+				// Day of month, with leading zero for single-digit days
+				foundDay = true;
+				ret.push(
+					padZeros( getPart(value, 2), clength )
+				);
+				break;
+			case "MMM":
+				// Month, as a three-letter abbreviation
+			case "MMMM":
+				// Month, using the full name
+				var part = getPart( value, 1 );
+				ret.push(
+					( cal.monthsGenitive && hasDay() ) ?
+					( cal.monthsGenitive[ clength === 3 ? "namesAbbr" : "names" ][ part ] ) :
+					( cal.months[ clength === 3 ? "namesAbbr" : "names" ][ part ] )
+				);
+				break;
+			case "M":
+				// Month, as digits, with no leading zero for single-digit months
+			case "MM":
+				// Month, as digits, with leading zero for single-digit months
+				ret.push(
+					padZeros( getPart(value, 1) + 1, clength )
+				);
+				break;
+			case "y":
+				// Year, as two digits, but with no leading zero for years less than 10
+			case "yy":
+				// Year, as two digits, with leading zero for years less than 10
+			case "yyyy":
+				// Year represented by four full digits
+				part = converted ? converted[ 0 ] : getEraYear( value, cal, getEra(value, eras), sortable );
+				if ( clength < 4 ) {
+					part = part % 100;
+				}
+				ret.push(
+					padZeros( part, clength )
+				);
+				break;
+			case "h":
+				// Hours with no leading zero for single-digit hours, using 12-hour clock
+			case "hh":
+				// Hours with leading zero for single-digit hours, using 12-hour clock
+				hour = value.getHours() % 12;
+				if ( hour === 0 ) hour = 12;
+				ret.push(
+					padZeros( hour, clength )
+				);
+				break;
+			case "H":
+				// Hours with no leading zero for single-digit hours, using 24-hour clock
+			case "HH":
+				// Hours with leading zero for single-digit hours, using 24-hour clock
+				ret.push(
+					padZeros( value.getHours(), clength )
+				);
+				break;
+			case "m":
+				// Minutes with no leading zero for single-digit minutes
+			case "mm":
+				// Minutes with leading zero for single-digit minutes
+				ret.push(
+					padZeros( value.getMinutes(), clength )
+				);
+				break;
+			case "s":
+				// Seconds with no leading zero for single-digit seconds
+			case "ss":
+				// Seconds with leading zero for single-digit seconds
+				ret.push(
+					padZeros( value.getSeconds(), clength )
+				);
+				break;
+			case "t":
+				// One character am/pm indicator ("a" or "p")
+			case "tt":
+				// Multicharacter am/pm indicator
+				part = value.getHours() < 12 ? ( cal.AM ? cal.AM[0] : " " ) : ( cal.PM ? cal.PM[0] : " " );
+				ret.push( clength === 1 ? part.charAt(0) : part );
+				break;
+			case "f":
+				// Deciseconds
+			case "ff":
+				// Centiseconds
+			case "fff":
+				// Milliseconds
+				ret.push(
+					padZeros( value.getMilliseconds(), 3 ).substr( 0, clength )
+				);
+				break;
+			case "z":
+				// Time zone offset, no leading zero
+			case "zz":
+				// Time zone offset with leading zero
+				hour = value.getTimezoneOffset() / 60;
+				ret.push(
+					( hour <= 0 ? "+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), clength )
+				);
+				break;
+			case "zzz":
+				// Time zone offset with leading zero
+				hour = value.getTimezoneOffset() / 60;
+				ret.push(
+					( hour <= 0 ? "+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), 2 ) +
+					// Hard coded ":" separator, rather than using cal.TimeSeparator
+					// Repeated here for consistency, plus ":" was already assumed in date parsing.
+					":" + padZeros( Math.abs(value.getTimezoneOffset() % 60), 2 )
+				);
+				break;
+			case "g":
+			case "gg":
+				if ( cal.eras ) {
+					ret.push(
+						cal.eras[ getEra(value, eras) ].name
+					);
+				}
+				break;
+		case "/":
+			ret.push( cal["/"] );
+			break;
+		default:
+			throw "Invalid date format pattern \'" + current + "\'.";
+		}
+	}
+	return ret.join( "" );
+};
+
+// formatNumber
+(function() {
+	var expandNumber;
+
+	expandNumber = function( number, precision, formatInfo ) {
+		var groupSizes = formatInfo.groupSizes,
+			curSize = groupSizes[ 0 ],
+			curGroupIndex = 1,
+			factor = Math.pow( 10, precision ),
+			rounded = Math.round( number * factor ) / factor;
+
+		if ( !isFinite(rounded) ) {
+			rounded = number;
+		}
+		number = rounded;
+
+		var numberString = number+"",
+			right = "",
+			split = numberString.split( /e/i ),
+			exponent = split.length > 1 ? parseInt( split[1], 10 ) : 0;
+		numberString = split[ 0 ];
+		split = numberString.split( "." );
+		numberString = split[ 0 ];
+		right = split.length > 1 ? split[ 1 ] : "";
+
+		var l;
+		if ( exponent > 0 ) {
+			right = zeroPad( right, exponent, false );
+			numberString += right.slice( 0, exponent );
+			right = right.substr( exponent );
+		}
+		else if ( exponent < 0 ) {
+			exponent = -exponent;
+			numberString = zeroPad( numberString, exponent + 1, true );
+			right = numberString.slice( -exponent, numberString.length ) + right;
+			numberString = numberString.slice( 0, -exponent );
+		}
+
+		if ( precision > 0 ) {
+			right = formatInfo[ "." ] +
+				( (right.length > precision) ? right.slice(0, precision) : zeroPad(right, precision) );
+		}
+		else {
+			right = "";
+		}
+
+		var stringIndex = numberString.length - 1,
+			sep = formatInfo[ "," ],
+			ret = "";
+
+		while ( stringIndex >= 0 ) {
+			if ( curSize === 0 || curSize > stringIndex ) {
+				return numberString.slice( 0, stringIndex + 1 ) + ( ret.length ? (sep + ret + right) : right );
+			}
+			ret = numberString.slice( stringIndex - curSize + 1, stringIndex + 1 ) + ( ret.length ? (sep + ret) : "" );
+
+			stringIndex -= curSize;
+
+			if ( curGroupIndex < groupSizes.length ) {
+				curSize = groupSizes[ curGroupIndex ];
+				curGroupIndex++;
+			}
+		}
+
+		return numberString.slice( 0, stringIndex + 1 ) + sep + ret + right;
+	};
+
+	formatNumber = function( value, format, culture ) {
+		if ( !isFinite(value) ) {
+			if ( value === Infinity ) {
+				return culture.numberFormat.positiveInfinity;
+			}
+			if ( value === -Infinity ) {
+				return culture.numberFormat.negativeInfinity;
+			}
+			return culture.numberFormat.NaN;
+		}
+		if ( !format || format === "i" ) {
+			return culture.name.length ? value.toLocaleString() : value.toString();
+		}
+		format = format || "D";
+
+		var nf = culture.numberFormat,
+			number = Math.abs( value ),
+			precision = -1,
+			pattern;
+		if ( format.length > 1 ) precision = parseInt( format.slice(1), 10 );
+
+		var current = format.charAt( 0 ).toUpperCase(),
+			formatInfo;
+
+		switch ( current ) {
+			case "D":
+				pattern = "n";
+				number = truncate( number );
+				if ( precision !== -1 ) {
+					number = zeroPad( "" + number, precision, true );
+				}
+				if ( value < 0 ) number = "-" + number;
+				break;
+			case "N":
+				formatInfo = nf;
+				/* falls through */
+			case "C":
+				formatInfo = formatInfo || nf.currency;
+				/* falls through */
+			case "P":
+				formatInfo = formatInfo || nf.percent;
+				pattern = value < 0 ? formatInfo.pattern[ 0 ] : ( formatInfo.pattern[1] || "n" );
+				if ( precision === -1 ) precision = formatInfo.decimals;
+				number = expandNumber( number * (current === "P" ? 100 : 1), precision, formatInfo );
+				break;
+			default:
+				throw "Bad number format specifier: " + current;
+		}
+
+		var patternParts = /n|\$|-|%/g,
+			ret = "";
+		for ( ; ; ) {
+			var index = patternParts.lastIndex,
+				ar = patternParts.exec( pattern );
+
+			ret += pattern.slice( index, ar ? ar.index : pattern.length );
+
+			if ( !ar ) {
+				break;
+			}
+
+			switch ( ar[0] ) {
+				case "n":
+					ret += number;
+					break;
+				case "$":
+					ret += nf.currency.symbol;
+					break;
+				case "-":
+					// don't make 0 negative
+					if ( /[1-9]/.test(number) ) {
+						ret += nf[ "-" ];
+					}
+					break;
+				case "%":
+					ret += nf.percent.symbol;
+					break;
+			}
+		}
+
+		return ret;
+	};
+
+}());
+
+getTokenRegExp = function() {
+	// regular expression for matching date and time tokens in format strings.
+	return (/\/|dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z|gg|g/g);
+};
+
+getEra = function( date, eras ) {
+	if ( !eras ) return 0;
+	var start, ticks = date.getTime();
+	for ( var i = 0, l = eras.length; i < l; i++ ) {
+		start = eras[ i ].start;
+		if ( start === null || ticks >= start ) {
+			return i;
+		}
+	}
+	return 0;
+};
+
+getEraYear = function( date, cal, era, sortable ) {
+	var year = date.getFullYear();
+	if ( !sortable && cal.eras ) {
+		// convert normal gregorian year to era-shifted gregorian
+		// year by subtracting the era offset
+		year -= cal.eras[ era ].offset;
+	}
+	return year;
+};
+
+// parseExact
+(function() {
+	var expandYear,
+		getDayIndex,
+		getMonthIndex,
+		getParseRegExp,
+		outOfRange,
+		toUpper,
+		toUpperArray;
+
+	expandYear = function( cal, year ) {
+		// expands 2-digit year into 4 digits.
+		if ( year < 100 ) {
+			var now = new Date(),
+				era = getEra( now ),
+				curr = getEraYear( now, cal, era ),
+				twoDigitYearMax = cal.twoDigitYearMax;
+			twoDigitYearMax = typeof twoDigitYearMax === "string" ? new Date().getFullYear() % 100 + parseInt( twoDigitYearMax, 10 ) : twoDigitYearMax;
+			year += curr - ( curr % 100 );
+			if ( year > twoDigitYearMax ) {
+				year -= 100;
+			}
+		}
+		return year;
+	};
+
+	getDayIndex = function	( cal, value, abbr ) {
+		var ret,
+			days = cal.days,
+			upperDays = cal._upperDays;
+		if ( !upperDays ) {
+			cal._upperDays = upperDays = [
+				toUpperArray( days.names ),
+				toUpperArray( days.namesAbbr ),
+				toUpperArray( days.namesShort )
+			];
+		}
+		value = toUpper( value );
+		if ( abbr ) {
+			ret = arrayIndexOf( upperDays[1], value );
+			if ( ret === -1 ) {
+				ret = arrayIndexOf( upperDays[2], value );
+			}
+		}
+		else {
+			ret = arrayIndexOf( upperDays[0], value );
+		}
+		return ret;
+	};
+
+	getMonthIndex = function( cal, value, abbr ) {
+		var months = cal.months,
+			monthsGen = cal.monthsGenitive || cal.months,
+			upperMonths = cal._upperMonths,
+			upperMonthsGen = cal._upperMonthsGen;
+		if ( !upperMonths ) {
+			cal._upperMonths = upperMonths = [
+				toUpperArray( months.names ),
+				toUpperArray( months.namesAbbr )
+			];
+			cal._upperMonthsGen = upperMonthsGen = [
+				toUpperArray( monthsGen.names ),
+				toUpperArray( monthsGen.namesAbbr )
+			];
+		}
+		value = toUpper( value );
+		var i = arrayIndexOf( abbr ? upperMonths[1] : upperMonths[0], value );
+		if ( i < 0 ) {
+			i = arrayIndexOf( abbr ? upperMonthsGen[1] : upperMonthsGen[0], value );
+		}
+		return i;
+	};
+
+	getParseRegExp = function( cal, format ) {
+		// converts a format string into a regular expression with groups that
+		// can be used to extract date fields from a date string.
+		// check for a cached parse regex.
+		var re = cal._parseRegExp;
+		if ( !re ) {
+			cal._parseRegExp = re = {};
+		}
+		else {
+			var reFormat = re[ format ];
+			if ( reFormat ) {
+				return reFormat;
+			}
+		}
+
+		// expand single digit formats, then escape regular expression characters.
+		var expFormat = expandFormat( cal, format ).replace( /([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g, "\\\\$1" ),
+			regexp = [ "^" ],
+			groups = [],
+			index = 0,
+			quoteCount = 0,
+			tokenRegExp = getTokenRegExp(),
+			match;
+
+		// iterate through each date token found.
+		while ( (match = tokenRegExp.exec(expFormat)) !== null ) {
+			var preMatch = expFormat.slice( index, match.index );
+			index = tokenRegExp.lastIndex;
+
+			// don't replace any matches that occur inside a string literal.
+			quoteCount += appendPreOrPostMatch( preMatch, regexp );
+			if ( quoteCount % 2 ) {
+				regexp.push( match[0] );
+				continue;
+			}
+
+			// add a regex group for the token.
+			var m = match[ 0 ],
+				len = m.length,
+				add;
+			switch ( m ) {
+				case "dddd": case "ddd":
+				case "MMMM": case "MMM":
+				case "gg": case "g":
+					add = "(\\D+)";
+					break;
+				case "tt": case "t":
+					add = "(\\D*)";
+					break;
+				case "yyyy":
+				case "fff":
+				case "ff":
+				case "f":
+					add = "(\\d{" + len + "})";
+					break;
+				case "dd": case "d":
+				case "MM": case "M":
+				case "yy": case "y":
+				case "HH": case "H":
+				case "hh": case "h":
+				case "mm": case "m":
+				case "ss": case "s":
+					add = "(\\d\\d?)";
+					break;
+				case "zzz":
+					add = "([+-]?\\d\\d?:\\d{2})";
+					break;
+				case "zz": case "z":
+					add = "([+-]?\\d\\d?)";
+					break;
+				case "/":
+					add = "(\\/)";
+					break;
+				default:
+					throw "Invalid date format pattern \'" + m + "\'.";
+			}
+			if ( add ) {
+				regexp.push( add );
+			}
+			groups.push( match[0] );
+		}
+		appendPreOrPostMatch( expFormat.slice(index), regexp );
+		regexp.push( "$" );
+
+		// allow whitespace to differ when matching formats.
+		var regexpStr = regexp.join( "" ).replace( /\s+/g, "\\s+" ),
+			parseRegExp = { "regExp": regexpStr, "groups": groups };
+
+		// cache the regex for this format.
+		return re[ format ] = parseRegExp;
+	};
+
+	outOfRange = function( value, low, high ) {
+		return value < low || value > high;
+	};
+
+	toUpper = function( value ) {
+		// "he-IL" has non-breaking space in weekday names.
+		return value.split( "\u00A0" ).join( " " ).toUpperCase();
+	};
+
+	toUpperArray = function( arr ) {
+		var results = [];
+		for ( var i = 0, l = arr.length; i < l; i++ ) {
+			results[ i ] = toUpper( arr[i] );
+		}
+		return results;
+	};
+
+	parseExact = function( value, format, culture ) {
+		// try to parse the date string by matching against the format string
+		// while using the specified culture for date field names.
+		value = trim( value );
+		var cal = culture.calendar,
+			// convert date formats into regular expressions with groupings.
+			// use the regexp to determine the input format and extract the date fields.
+			parseInfo = getParseRegExp( cal, format ),
+			match = new RegExp( parseInfo.regExp ).exec( value );
+		if ( match === null ) {
+			return null;
+		}
+		// found a date format that matches the input.
+		var groups = parseInfo.groups,
+			era = null, year = null, month = null, date = null, weekDay = null,
+			hour = 0, hourOffset, min = 0, sec = 0, msec = 0, tzMinOffset = null,
+			pmHour = false;
+		// iterate the format groups to extract and set the date fields.
+		for ( var j = 0, jl = groups.length; j < jl; j++ ) {
+			var matchGroup = match[ j + 1 ];
+			if ( matchGroup ) {
+				var current = groups[ j ],
+					clength = current.length,
+					matchInt = parseInt( matchGroup, 10 );
+				switch ( current ) {
+					case "dd": case "d":
+						// Day of month.
+						date = matchInt;
+						// check that date is generally in valid range, also checking overflow below.
+						if ( outOfRange(date, 1, 31) ) return null;
+						break;
+					case "MMM": case "MMMM":
+						month = getMonthIndex( cal, matchGroup, clength === 3 );
+						if ( outOfRange(month, 0, 11) ) return null;
+						break;
+					case "M": case "MM":
+						// Month.
+						month = matchInt - 1;
+						if ( outOfRange(month, 0, 11) ) return null;
+						break;
+					case "y": case "yy":
+					case "yyyy":
+						year = clength < 4 ? expandYear( cal, matchInt ) : matchInt;
+						if ( outOfRange(year, 0, 9999) ) return null;
+						break;
+					case "h": case "hh":
+						// Hours (12-hour clock).
+						hour = matchInt;
+						if ( hour === 12 ) hour = 0;
+						if ( outOfRange(hour, 0, 11) ) return null;
+						break;
+					case "H": case "HH":
+						// Hours (24-hour clock).
+						hour = matchInt;
+						if ( outOfRange(hour, 0, 23) ) return null;
+						break;
+					case "m": case "mm":
+						// Minutes.
+						min = matchInt;
+						if ( outOfRange(min, 0, 59) ) return null;
+						break;
+					case "s": case "ss":
+						// Seconds.
+						sec = matchInt;
+						if ( outOfRange(sec, 0, 59) ) return null;
+						break;
+					case "tt": case "t":
+						// AM/PM designator.
+						// see if it is standard, upper, or lower case PM. If not, ensure it is at least one of
+						// the AM tokens. If not, fail the parse for this format.
+						pmHour = cal.PM && ( matchGroup === cal.PM[0] || matchGroup === cal.PM[1] || matchGroup === cal.PM[2] );
+						if (
+							!pmHour && (
+								!cal.AM || ( matchGroup !== cal.AM[0] && matchGroup !== cal.AM[1] && matchGroup !== cal.AM[2] )
+							)
+						) return null;
+						break;
+					case "f":
+						// Deciseconds.
+					case "ff":
+						// Centiseconds.
+					case "fff":
+						// Milliseconds.
+						msec = matchInt * Math.pow( 10, 3 - clength );
+						if ( outOfRange(msec, 0, 999) ) return null;
+						break;
+					case "ddd":
+						// Day of week.
+					case "dddd":
+						// Day of week.
+						weekDay = getDayIndex( cal, matchGroup, clength === 3 );
+						if ( outOfRange(weekDay, 0, 6) ) return null;
+						break;
+					case "zzz":
+						// Time zone offset in +/- hours:min.
+						var offsets = matchGroup.split( /:/ );
+						if ( offsets.length !== 2 ) return null;
+						hourOffset = parseInt( offsets[0], 10 );
+						if ( outOfRange(hourOffset, -12, 13) ) return null;
+						var minOffset = parseInt( offsets[1], 10 );
+						if ( outOfRange(minOffset, 0, 59) ) return null;
+						tzMinOffset = ( hourOffset * 60 ) + ( startsWith(matchGroup, "-") ? -minOffset : minOffset );
+						break;
+					case "z": case "zz":
+						// Time zone offset in +/- hours.
+						hourOffset = matchInt;
+						if ( outOfRange(hourOffset, -12, 13) ) return null;
+						tzMinOffset = hourOffset * 60;
+						break;
+					case "g": case "gg":
+						var eraName = matchGroup;
+						if ( !eraName || !cal.eras ) return null;
+						eraName = trim( eraName.toLowerCase() );
+						for ( var i = 0, l = cal.eras.length; i < l; i++ ) {
+							if ( eraName === cal.eras[i].name.toLowerCase() ) {
+								era = i;
+								break;
+							}
+						}
+						// could not find an era with that name
+						if ( era === null ) return null;
+						break;
+				}
+			}
+		}
+		var result = new Date(), defaultYear, convert = cal.convert;
+		defaultYear = convert ? convert.fromGregorian( result )[ 0 ] : result.getFullYear();
+		if ( year === null ) {
+			year = defaultYear;
+		}
+		else if ( cal.eras ) {
+			// year must be shifted to normal gregorian year
+			// but not if year was not specified, its already normal gregorian
+			// per the main if clause above.
+			year += cal.eras[( era || 0 )].offset;
+		}
+		// set default day and month to 1 and January, so if unspecified, these are the defaults
+		// instead of the current day/month.
+		if ( month === null ) {
+			month = 0;
+		}
+		if ( date === null ) {
+			date = 1;
+		}
+		// now have year, month, and date, but in the culture's calendar.
+		// convert to gregorian if necessary
+		if ( convert ) {
+			result = convert.toGregorian( year, month, date );
+			// conversion failed, must be an invalid match
+			if ( result === null ) return null;
+		}
+		else {
+			// have to set year, month and date together to avoid overflow based on current date.
+			result.setFullYear( year, month, date );
+			// check to see if date overflowed for specified month (only checked 1-31 above).
+			if ( result.getDate() !== date ) return null;
+			// invalid day of week.
+			if ( weekDay !== null && result.getDay() !== weekDay ) {
+				return null;
+			}
+		}
+		// if pm designator token was found make sure the hours fit the 24-hour clock.
+		if ( pmHour && hour < 12 ) {
+			hour += 12;
+		}
+		result.setHours( hour, min, sec, msec );
+		if ( tzMinOffset !== null ) {
+			// adjust timezone to utc before applying local offset.
+			var adjustedMin = result.getMinutes() - ( tzMinOffset + result.getTimezoneOffset() );
+			// Safari limits hours and minutes to the range of -127 to 127.  We need to use setHours
+			// to ensure both these fields will not exceed this range.	adjustedMin will range
+			// somewhere between -1440 and 1500, so we only need to split this into hours.
+			result.setHours( result.getHours() + parseInt(adjustedMin / 60, 10), adjustedMin % 60 );
+		}
+		return result;
+	};
+}());
+
+parseNegativePattern = function( value, nf, negativePattern ) {
+	var neg = nf[ "-" ],
+		pos = nf[ "+" ],
+		ret;
+	switch ( negativePattern ) {
+		case "n -":
+			neg = " " + neg;
+			pos = " " + pos;
+			/* falls through */
+		case "n-":
+			if ( endsWith(value, neg) ) {
+				ret = [ "-", value.substr(0, value.length - neg.length) ];
+			}
+			else if ( endsWith(value, pos) ) {
+				ret = [ "+", value.substr(0, value.length - pos.length) ];
+			}
+			break;
+		case "- n":
+			neg += " ";
+			pos += " ";
+			/* falls through */
+		case "-n":
+			if ( startsWith(value, neg) ) {
+				ret = [ "-", value.substr(neg.length) ];
+			}
+			else if ( startsWith(value, pos) ) {
+				ret = [ "+", value.substr(pos.length) ];
+			}
+			break;
+		case "(n)":
+			if ( startsWith(value, "(") && endsWith(value, ")") ) {
+				ret = [ "-", value.substr(1, value.length - 2) ];
+			}
+			break;
+	}
+	return ret || [ "", value ];
+};
+
+//
+// public instance functions
+//
+
+Globalize.prototype.findClosestCulture = function( cultureSelector ) {
+	return Globalize.findClosestCulture.call( this, cultureSelector );
+};
+
+Globalize.prototype.format = function( value, format, cultureSelector ) {
+	return Globalize.format.call( this, value, format, cultureSelector );
+};
+
+Globalize.prototype.localize = function( key, cultureSelector ) {
+	return Globalize.localize.call( this, key, cultureSelector );
+};
+
+Globalize.prototype.parseInt = function( value, radix, cultureSelector ) {
+	return Globalize.parseInt.call( this, value, radix, cultureSelector );
+};
+
+Globalize.prototype.parseFloat = function( value, radix, cultureSelector ) {
+	return Globalize.parseFloat.call( this, value, radix, cultureSelector );
+};
+
+Globalize.prototype.culture = function( cultureSelector ) {
+	return Globalize.culture.call( this, cultureSelector );
+};
+
+//
+// public singleton functions
+//
+
+Globalize.addCultureInfo = function( cultureName, baseCultureName, info ) {
+
+	var base = {},
+		isNew = false;
+
+	if ( typeof cultureName !== "string" ) {
+		// cultureName argument is optional string. If not specified, assume info is first
+		// and only argument. Specified info deep-extends current culture.
+		info = cultureName;
+		cultureName = this.culture().name;
+		base = this.cultures[ cultureName ];
+	} else if ( typeof baseCultureName !== "string" ) {
+		// baseCultureName argument is optional string. If not specified, assume info is second
+		// argument. Specified info deep-extends specified culture.
+		// If specified culture does not exist, create by deep-extending default
+		info = baseCultureName;
+		isNew = ( this.cultures[ cultureName ] == null );
+		base = this.cultures[ cultureName ] || this.cultures[ "default" ];
+	} else {
+		// cultureName and baseCultureName specified. Assume a new culture is being created
+		// by deep-extending an specified base culture
+		isNew = true;
+		base = this.cultures[ baseCultureName ];
+	}
+
+	this.cultures[ cultureName ] = extend(true, {},
+		base,
+		info
+	);
+	// Make the standard calendar the current culture if it's a new culture
+	if ( isNew ) {
+		this.cultures[ cultureName ].calendar = this.cultures[ cultureName ].calendars.standard;
+	}
+};
+
+Globalize.findClosestCulture = function( name ) {
+	var match;
+	if ( !name ) {
+		return this.findClosestCulture( this.cultureSelector ) || this.cultures[ "default" ];
+	}
+	if ( typeof name === "string" ) {
+		name = name.split( "," );
+	}
+	if ( isArray(name) ) {
+		var lang,
+			cultures = this.cultures,
+			list = name,
+			i, l = list.length,
+			prioritized = [];
+		for ( i = 0; i < l; i++ ) {
+			name = trim( list[i] );
+			var pri, parts = name.split( ";" );
+			lang = trim( parts[0] );
+			if ( parts.length === 1 ) {
+				pri = 1;
+			}
+			else {
+				name = trim( parts[1] );
+				if ( name.indexOf("q=") === 0 ) {
+					name = name.substr( 2 );
+					pri = parseFloat( name );
+					pri = isNaN( pri ) ? 0 : pri;
+				}
+				else {
+					pri = 1;
+				}
+			}
+			prioritized.push({ lang: lang, pri: pri });
+		}
+		prioritized.sort(function( a, b ) {
+			if ( a.pri < b.pri ) {
+				return 1;
+			} else if ( a.pri > b.pri ) {
+				return -1;
+			}
+			return 0;
+		});
+		// exact match
+		for ( i = 0; i < l; i++ ) {
+			lang = prioritized[ i ].lang;
+			match = cultures[ lang ];
+			if ( match ) {
+				return match;
+			}
+		}
+
+		// neutral language match
+		for ( i = 0; i < l; i++ ) {
+			lang = prioritized[ i ].lang;
+			do {
+				var index = lang.lastIndexOf( "-" );
+				if ( index === -1 ) {
+					break;
+				}
+				// strip off the last part. e.g. en-US => en
+				lang = lang.substr( 0, index );
+				match = cultures[ lang ];
+				if ( match ) {
+					return match;
+				}
+			}
+			while ( 1 );
+		}
+
+		// last resort: match first culture using that language
+		for ( i = 0; i < l; i++ ) {
+			lang = prioritized[ i ].lang;
+			for ( var cultureKey in cultures ) {
+				var culture = cultures[ cultureKey ];
+				if ( culture.language == lang ) {
+					return culture;
+				}
+			}
+		}
+	}
+	else if ( typeof name === "object" ) {
+		return name;
+	}
+	return match || null;
+};
+
+Globalize.format = function( value, format, cultureSelector ) {
+	var culture = this.findClosestCulture( cultureSelector );
+	if ( value instanceof Date ) {
+		value = formatDate( value, format, culture );
+	}
+	else if ( typeof value === "number" ) {
+		value = formatNumber( value, format, culture );
+	}
+	return value;
+};
+
+Globalize.localize = function( key, cultureSelector ) {
+	return this.findClosestCulture( cultureSelector ).messages[ key ] ||
+		this.cultures[ "default" ].messages[ key ];
+};
+
+Globalize.parseDate = function( value, formats, culture ) {
+	culture = this.findClosestCulture( culture );
+
+	var date, prop, patterns;
+	if ( formats ) {
+		if ( typeof formats === "string" ) {
+			formats = [ formats ];
+		}
+		if ( formats.length ) {
+			for ( var i = 0, l = formats.length; i < l; i++ ) {
+				var format = formats[ i ];
+				if ( format ) {
+					date = parseExact( value, format, culture );
+					if ( date ) {
+						break;
+					}
+				}
+			}
+		}
+	} else {
+		patterns = culture.calendar.patterns;
+		for ( prop in patterns ) {
+			date = parseExact( value, patterns[prop], culture );
+			if ( date ) {
+				break;
+			}
+		}
+	}
+
+	return date || null;
+};
+
+Globalize.parseInt = function( value, radix, cultureSelector ) {
+	return truncate( Globalize.parseFloat(value, radix, cultureSelector) );
+};
+
+Globalize.parseFloat = function( value, radix, cultureSelector ) {
+	// radix argument is optional
+	if ( typeof radix !== "number" ) {
+		cultureSelector = radix;
+		radix = 10;
+	}
+
+	var culture = this.findClosestCulture( cultureSelector );
+	var ret = NaN,
+		nf = culture.numberFormat;
+
+	if ( value.indexOf(culture.numberFormat.currency.symbol) > -1 ) {
+		// remove currency symbol
+		value = value.replace( culture.numberFormat.currency.symbol, "" );
+		// replace decimal seperator
+		value = value.replace( culture.numberFormat.currency["."], culture.numberFormat["."] );
+	}
+
+	//Remove percentage character from number string before parsing
+	if ( value.indexOf(culture.numberFormat.percent.symbol) > -1){
+		value = value.replace( culture.numberFormat.percent.symbol, "" );
+	}
+
+	// remove spaces: leading, trailing and between - and number. Used for negative currency pt-BR
+	value = value.replace( / /g, "" );
+
+	// allow infinity or hexidecimal
+	if ( regexInfinity.test(value) ) {
+		ret = parseFloat( value );
+	}
+	else if ( !radix && regexHex.test(value) ) {
+		ret = parseInt( value, 16 );
+	}
+	else {
+
+		// determine sign and number
+		var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ),
+			sign = signInfo[ 0 ],
+			num = signInfo[ 1 ];
+
+		// #44 - try parsing as "(n)"
+		if ( sign === "" && nf.pattern[0] !== "(n)" ) {
+			signInfo = parseNegativePattern( value, nf, "(n)" );
+			sign = signInfo[ 0 ];
+			num = signInfo[ 1 ];
+		}
+
+		// try parsing as "-n"
+		if ( sign === "" && nf.pattern[0] !== "-n" ) {
+			signInfo = parseNegativePattern( value, nf, "-n" );
+			sign = signInfo[ 0 ];
+			num = signInfo[ 1 ];
+		}
+
+		sign = sign || "+";
+
+		// determine exponent and number
+		var exponent,
+			intAndFraction,
+			exponentPos = num.indexOf( "e" );
+		if ( exponentPos < 0 ) exponentPos = num.indexOf( "E" );
+		if ( exponentPos < 0 ) {
+			intAndFraction = num;
+			exponent = null;
+		}
+		else {
+			intAndFraction = num.substr( 0, exponentPos );
+			exponent = num.substr( exponentPos + 1 );
+		}
+		// determine decimal position
+		var integer,
+			fraction,
+			decSep = nf[ "." ],
+			decimalPos = intAndFraction.indexOf( decSep );
+		if ( decimalPos < 0 ) {
+			integer = intAndFraction;
+			fraction = null;
+		}
+		else {
+			integer = intAndFraction.substr( 0, decimalPos );
+			fraction = intAndFraction.substr( decimalPos + decSep.length );
+		}
+		// handle groups (e.g. 1,000,000)
+		var groupSep = nf[ "," ];
+		integer = integer.split( groupSep ).join( "" );
+		var altGroupSep = groupSep.replace( /\u00A0/g, " " );
+		if ( groupSep !== altGroupSep ) {
+			integer = integer.split( altGroupSep ).join( "" );
+		}
+		// build a natively parsable number string
+		var p = sign + integer;
+		if ( fraction !== null ) {
+			p += "." + fraction;
+		}
+		if ( exponent !== null ) {
+			// exponent itself may have a number patternd
+			var expSignInfo = parseNegativePattern( exponent, nf, "-n" );
+			p += "e" + ( expSignInfo[0] || "+" ) + expSignInfo[ 1 ];
+		}
+		if ( regexParseFloat.test(p) ) {
+			ret = parseFloat( p );
+		}
+	}
+	return ret;
+};
+
+Globalize.culture = function( cultureSelector ) {
+	// setter
+	if ( typeof cultureSelector !== "undefined" ) {
+		this.cultureSelector = cultureSelector;
+	}
+	// getter
+	return this.findClosestCulture( cultureSelector ) || this.cultures[ "default" ];
+};
+
+document.Globalize = Globalize;
+}(this));
\ No newline at end of file

mercurial