PageSourceSearch

https://frontiersemi.com/ClientI18N.php?file=Globalize.js&locale=en

js frontiersemi.com collected 2026-10-10 00:31:00 UTC 66,080 bytes, 1,660 lines download raw bytes

1index.html//JS Globalize @0-2CE52E34
2/*!
3 * Globalize
4 *
5 * http://github.com/jquery/globalize
6 *
7 * Copyright Software Freedom Conservancy, Inc.
8 * Dual licensed under the MIT or GPL Version 2 licenses.
9 * http://jquery.org/license
10 */
11
12(function (window, undefined) {
13
14var arrayLocaleInfo = "en|en|US|Yes;No;|2|.|,|January;February;March;April;May;June;July;August;September;October;November;December|Jan;Feb;Mar;Apr;May;Jun;Jul;Aug;Sep;Oct;Nov;Dec|Sunday;Monday;Tuesday;Wednesday;Thursday;Friday;Saturday|Sun;Mon;Tue;Wed;Thu;Fri;Sat|m/d/yyyy|dddd, mmmm dd, yyyy|h:nn tt|h:nn:ss tt|0|AM|PM".split("|");
15    function convertTojQueryDateFormat(srcFormat, expand) {
16       expand = !expand ? false : true;
17       switch (srcFormat) {
18           case "":
19           case "ShortDate":
20               return expand ? Globalize.culture().calendars.standard.patterns[srcFormat] : srcFormat;
21               // return "d"; // "M/d/yyyy"
22           case "GeneralDate":
23               return expand ? Globalize.culture().calendars.standard.patterns[srcFormat] : srcFormat;
24               // return "f"; // "dddd, MMMM dd, yyyy h:mm tt"
25           case "LongDate":
26               return expand ? Globalize.culture().calendars.standard.patterns[srcFormat] : srcFormat;
27               // return "D"; // "dddd, MMMM dd, yyyy"
28           case "ShortTime":
29               return expand ? Globalize.culture().calendars.standard.patterns[srcFormat] : srcFormat;
30               // return "t"; // "h:mm tt"
31           case "LongTime":
32               return expand ? Globalize.culture().calendars.standard.patterns[srcFormat] : srcFormat;
33               // return "T"; // "h:mm:ss tt";
34       }
35       srcFormat = srcFormat.replace("AM/PM", "tt");
36       srcFormat = srcFormat.replace("am/pm", "tt");
37       srcFormat = srcFormat.replace("M/P", "t");
38       srcFormat = srcFormat.replace("a/p", "t");
39
40       srcFormat = srcFormat.replace(/w/g, "");
41       srcFormat = srcFormat.replace(/m/g, "M");
42       srcFormat = srcFormat.replace(/n/g, "m");
43       return srcFormat;
44   } 
45
46    function getLocaleInfo(id)
47    {
48        switch (id)
49        {
50            case "LanguageAndCountry":	return arrayLocaleInfo[0];
51            case "language":			return arrayLocaleInfo[1];
52            case "country":				return arrayLocaleInfo[2];
53            case "booleanFormat":		return arrayLocaleInfo[3];
54            case "decimalDigits":		return parseInt(arrayLocaleInfo[4]);
55            case "decimalSeparator":	return arrayLocaleInfo[5];
56            case "groupSeparator":		return arrayLocaleInfo[6];
57            case "monthNames":			return arrayLocaleInfo[7];
58            case "monthShortNames":		return arrayLocaleInfo[8];
59            case "weekdayNames":		return arrayLocaleInfo[9];
60            case "weekdayShortNames":	return arrayLocaleInfo[10];
61            case "shortDate":			return convertTojQueryDateFormat(arrayLocaleInfo[11], true);
62            case "longDate":			return convertTojQueryDateFormat(arrayLocaleInfo[12], true);
63            case "shortTime":			return convertTojQueryDateFormat(arrayLocaleInfo[13], true);
64            case "longTime":			return convertTojQueryDateFormat(arrayLocaleInfo[14], true);
65            case "firstWeekDay":		return parseInt(arrayLocaleInfo[15]);
66            case "AMDesignator":		return arrayLocaleInfo[16];
67            case "PMDesignator":		return arrayLocaleInfo[17];
68        }
69        return "";
70    }
71
72    var listMonths = getLocaleInfo("monthNames").split(";");
73    listMonths.push("");
74    var listShortMonths = getLocaleInfo("monthShortNames").split(";");
75    listShortMonths.push("");
76    var firstWeekDay = getLocaleInfo("firstWeekDay");
77    var listWeekdays = getLocaleInfo("weekdayNames").split(";");
78    var listShortWeekdays = getLocaleInfo("weekdayShortNames").split(";");
79    var amDesignator = getLocaleInfo("AMDesignator");
80    var pmDesignator = getLocaleInfo("PMDesignator");
81
82
83
84
85    var Globalize,
86    // private variables
87	regexHex,
88	regexInfinity,
89	regexParseFloat,
90	regexTrim,
91    // private JavaScript utility functions
92	arrayIndexOf,
93	endsWith,
94	extend,
95	isArray,
96	isFunction,
97	isObject,
98	startsWith,
99	trim,
100	truncate,
101	zeroPad,
102    // private Globalization utility functions
103	appendPreOrPostMatch,
104	expandFormat,
105	formatDate,
106	formatNumber,
107	getTokenRegExp,
108	getEra,
109	getEraYear,
110	parseExact,
111	parseNegativePattern;
112
113    // Global variable (Globalize) or CommonJS module (globalize)
114    Globalize = function (cultureSelector) {
115        return new Globalize.prototype.init(cultureSelector);
116    };
117
118    if (typeof require !== "undefined"
119	&& typeof exports !== "undefined"
120	&& typeof module !== "undefined") {
121        // Assume CommonJS
122        module.exports = Globalize;
123    } else {
124        // Export as global variable
125        window.Globalize = Globalize;
126    }
127
128    Globalize.cultures = {};
129
130    Globalize.prototype = {
131        constructor: Globalize,
132        init: function (cultureSelector) {
133            this.cultures = Globalize.cultures;
134            this.cultureSelector = cultureSelector;
135
136            return this;
137        }
138    };
139    Globalize.prototype.init.prototype = Globalize.prototype;
140
141    // 1.	 When defining a culture, all fields are required except the ones stated as optional.
142    // 2.	 Each culture should have a ".calendars" object with at least one calendar named "standard"
143    //		 which serves as the default calendar in use by that culture.
144    // 3.	 Each culture should have a ".calendar" object which is the current calendar being used,
145    //		 it may be dynamically changed at any time to one of the calendars in ".calendars".
146    Globalize.cultures["default"] = {
147        // A unique name for the culture in the form <language code>-<country/region code>
148        name: getLocaleInfo("LanguageAndCountry"),
149        // the name of the culture in the english language
150        englishName: getLocaleInfo("language"),
151        // the name of the culture in its own language
152        nativeName: getLocaleInfo("language"),
153        // whether the culture uses right-to-left text
154        isRTL: false,
155        // "language" is used for so-called "specific" cultures.
156        // For example, the culture "es-CL" means "Spanish, in Chili".
157        // It represents the Spanish-speaking culture as it is in Chili,
158        // which might have different formatting rules or even translations
159        // than Spanish in Spain. A "neutral" culture is one that is not
160        // specific to a region. For example, the culture "es" is the generic
161        // Spanish culture, which may be a more generalized version of the language
162        // that may or may not be what a specific culture expects.
163        // For a specific culture like "es-CL", the "language" field refers to the
164        // neutral, generic culture information for the language it is using.
165        // This is not always a simple matter of the string before the dash.
166        // For example, the "zh-Hans" culture is netural (Simplified Chinese).
167        // And the "zh-SG" culture is Simplified Chinese in Singapore, whose lanugage
168        // field is "zh-CHS", not "zh".
169        // This field should be used to navigate from a specific culture to it's
170        // more general, neutral culture. If a culture is already as general as it
171        // can get, the language may refer to itself.
172        language: getLocaleInfo("language"),
173        // numberFormat defines general number formatting rules, like the digits in
174        // each grouping, the group separator, and how negative numbers are displayed.
175        numberFormat: {
176            // [negativePattern]
177            // Note, numberFormat.pattern has no "positivePattern" unlike percent and currency,
178            // but is still defined as an array for consistency with them.
179            //   negativePattern: one of "(n)|-n|- n|n-|n -"
180            pattern: ["-n"],
181            // number of decimal places normally shown
182            decimals: getLocaleInfo("decimalDigits"),
183            // string that separates number groups, as in 1,000,000
184            ",": getLocaleInfo("groupSeparator"),
185            // string that separates a number from the fractional portion, as in 1.99
186            ".": getLocaleInfo("decimalSeparator"),
187            // array of numbers indicating the size of each number group.
188            // TODO: more detailed description and example
189            groupSizes: [3],
190            // symbol used for positive numbers
191            "+": "+",
192            // symbol used for negative numbers
193            "-": "-",
194            // symbol used for NaN (Not-A-Number)
195            NaN: "NaN",
196            // symbol used for Negative Infinity
197            negativeInfinity: "-Infinity",
198            // symbol used for Positive Infinity
199            positiveInfinity: "Infinity",
200            percent: {
201                // [negativePattern, positivePattern]
202                //   negativePattern: one of "-n %|-n%|-%n|%-n|%n-|n-%|n%-|-% n|n %-|% n-|% -n|n- %"
203                //   positivePattern: one of "n %|n%|%n|% n"
204                pattern: ["-n %", "n %"],
205                // number of decimal places normally shown
206                decimals: getLocaleInfo("decimalDigits"),
207                // array of numbers indicating the size of each number group.
208                // TODO: more detailed description and example
209                groupSizes: [3],
210                // string that separates number groups, as in 1,000,000
211                ",": getLocaleInfo("groupSeparator"),
212                // string that separates a number from the fractional portion, as in 1.99
213                ".": getLocaleInfo("decimalSeparator"),
214                // symbol used to represent a percentage
215                symbol: "%"
216            },
217            currency: {
218                // [negativePattern, positivePattern]
219                //   negativePattern: one of "($n)|-$n|$-n|$n-|(n$)|-n$|n-$|n$-|-n $|-$ n|n $-|$ n-|$ -n|n- $|($ n)|(n $)"
220                //   positivePattern: one of "$n|n$|$ n|n $"
221                pattern: ["($n)", "$n"],
222                // number of decimal places normally shown
223                decimals: getLocaleInfo("decimalDigits"),
224                // array of numbers indicating the size of each number group.
225                // TODO: more detailed description and example
226                groupSizes: [3],
227                // string that separates number groups, as in 1,000,000
228                ",": getLocaleInfo("groupSeparator"),
229                // string that separates a number from the fractional portion, as in 1.99
230                ".": getLocaleInfo("decimalSeparator"),
231                // symbol used to represent currency
232                symbol: "$"
233            }
234        },
235        // calendars defines all the possible calendars used by this culture.
236        // There should be at least one defined with name "standard", and is the default
237        // calendar used by the culture.
238        // A calendar contains information about how dates are formatted, information about
239        // the calendar's eras, a standard set of the date formats,
240        // translations for day and month names, and if the calendar is not based on the Gregorian
241        // calendar, conversion functions to and from the Gregorian calendar.
242        calendars: {
243            standard: {
244                // name that identifies the type of calendar this is
245                name: "Gregorian_CCSStandart",
246                // separator of parts of a date (e.g. "/" in 11/05/1955)
247                "/": "/",
248                // separator of parts of a time (e.g. ":" in 05:44 PM)
249                ":": ":",
250                // the first day of the week (0 = Sunday, 1 = Monday, etc)
251                firstDay: firstWeekDay,
252                days: {
253                    // full day names
254                    names: listWeekdays,
255                    // abbreviated day names
256                    namesAbbr: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
257                    // shortest day names
258                    namesShort: listShortWeekdays
259                },
260                months: {
261                    // full month names (13 months for lunar calendards -- 13th month should be "" if not lunar)
262                    names: listMonths,
263                    // abbreviated month names
264                    namesAbbr: listShortMonths
265                },
266                // AM and PM designators in one of these forms:
267                // The usual view, and the upper and lower case versions
268                //   [ standard, lowercase, uppercase ]
269                // The culture does not use AM or PM (likely all standard date formats use 24 hour time)
270                //   null
271                AM: amDesignator == "" ? null : [amDesignator, amDesignator.toLowerCase(), amDesignator.toUpperCase()],
272                PM: pmDesignator == "" ? null : [pmDesignator, pmDesignator.toLowerCase(), pmDesignator.toUpperCase()],
273                eras: [
274                // eras in reverse chronological order.
275                // name: the name of the era in this culture (e.g. A.D., C.E.)
276                // start: when the era starts in ticks (gregorian, gmt), null if it is the earliest supported era.
277                // offset: offset in years from gregorian calendar
278				{
279				"name": "A.D.",
280				"start": null,
281				"offset": 0
282}
283			],
284                // when a two digit year is given, it will never be parsed as a four digit
285                // year greater than this year (in the appropriate era for the culture)
286                // Set it as a full year (e.g. 2029) or use an offset format starting from
287                // the current year: "+19" would correspond to 2029 if the current year 2010.
288                twoDigitYearMax: 2029,
289                // set of predefined date and time patterns used by the culture
290                // these represent the format someone in this culture would expect
291                // to see given the portions of the date that are shown.
292                patterns: {
293                    // short date pattern
294                    d: getLocaleInfo("shortDate"),
295                    "ShortDate": getLocaleInfo("shortDate"),
296                    // long date pattern
297                    D: getLocaleInfo("longDate"),
298                    "LongDate": getLocaleInfo("longDate"),
299                    // short time pattern
300                    t: getLocaleInfo("shortTime"),
301                    "ShortTime": getLocaleInfo("shortTime"),
302                    // long time pattern
303                    T: getLocaleInfo("longTime"),
304                    "LongTime": getLocaleInfo("longTime"),
305                    // long date, short time pattern
306                    f: "dddd, MMMM dd, yyyy h:mm tt",
307                    // long date, long time pattern
308                    F: "dddd, MMMM dd, yyyy h:mm:ss tt",
309                    "GeneralDate": getLocaleInfo("shortDate") + ", " + getLocaleInfo("longTime"),
310                    // month/day pattern
311                    M: "MMMM dd",
312                    // month/year pattern
313                    Y: "yyyy MMMM",
314                    // S is a sortable format that does not vary by culture
315                    S: "yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss"
316                }
317                // optional fields for each calendar:
318                /*
319                monthsGenitive:
320                Same as months but used when the day preceeds the month.
321                Omit if the culture has no genitive distinction in month names.
322                For an explaination of genitive months, see http://blogs.msdn.com/michkap/archive/2004/12/25/332259.aspx
323                convert:
324                Allows for the support of non-gregorian based calendars. This convert object is used to
325                to convert a date to and from a gregorian calendar date to handle parsing and formatting.
326                The two functions:
327                fromGregorian( date )
328                Given the date as a parameter, return an array with parts [ year, month, day ]
329                corresponding to the non-gregorian based year, month, and day for the calendar.
330                toGregorian( year, month, day )
331                Given the non-gregorian year, month, and day, return a new Date() object
332                set to the corresponding date in the gregorian calendar.
333                */
334            }
335        },
336        // For localized strings
337        messages: {
338          CCS_Now: "Now",
339          CCS_RequiredField: "The value in field {0} is required.",
340          CCS_MinimumLength: "The number of symbols in field {0} can't be less than {1}.",
341          CCS_MaximumLength: "The number of symbols in field {0} can't be greater than {1}.",
342          CCS_IncorrectFormat: "The value in field {0} is not valid. Use the following format: {1}.",
343          CCS_IncorrectValue: "The value in field {0} is not valid."
344        }
345    };
346
347    Globalize.cultures["default"].calendar = Globalize.cultures["default"].calendars.standard;
348
349    Globalize.cultures[getLocaleInfo("LanguageAndCountry")] = Globalize.cultures["default"];
350
351    Globalize.cultureSelector = getLocaleInfo("LanguageAndCountry");
352
353    //
354    // private variables
355    //
356
357    regexHex = /^0x[a-f0-9]+$/i;
358    regexInfinity = /^[+-]?infinity$/i;
359    regexParseFloat = /^[+-]?\d*\.?\d*(e[+-]?\d+)?$/;
360    regexTrim = /^\s+|\s+$/g;
361
362    //
363    // private JavaScript utility functions
364    //
365
366    arrayIndexOf = function (array, item) {
367        if (array.indexOf) {
368            return array.indexOf(item);
369        }
370        for (var i = 0, length = array.length; i < length; i++) {
371            if (array[i] === item) {
372                return i;
373            }
374        }
375        return -1;
376    };
377
378    endsWith = function (value, pattern) {
379        return value.substr(value.length - pattern.length) === pattern;
380    };
381
382    extend = function (deep) {
383        var options, name, src, copy, copyIsArray, clone,
384		target = arguments[0] || {},
385		i = 1,
386		length = arguments.length,
387		deep = false;
388
389        // Handle a deep copy situation
390        if (typeof target === "boolean") {
391            deep = target;
392            target = arguments[1] || {};
393            // skip the boolean and the target
394            i = 2;
395        }
396
397        // Handle case when target is a string or something (possible in deep copy)
398        if (typeof target !== "object" && !isFunction(target)) {
399            target = {};
400        }
401
402        for (; i < length; i++) {
403            // Only deal with non-null/undefined values
404            if ((options = arguments[i]) != null) {
405                // Extend the base object
406                for (name in options) {
407                    src = target[name];
408                    copy = options[name];
409
410                    // Prevent never-ending loop
411                    if (target === copy) {
412                        continue;
413                    }
414
415                    // Recurse if we're merging plain objects or arrays
416                    if (deep && copy && (isObject(copy) || (copyIsArray = isArray(copy)))) {
417                        if (copyIsArray) {
418                            copyIsArray = false;
419                            clone = src && isArray(src) ? src : [];
420
421                        } else {
422                            clone = src && isObject(src) ? src : {};
423                        }
424
425                        // Never move original objects, clone them
426                        target[name] = extend(deep, clone, copy);
427
428                        // Don't bring in undefined values
429                    } else if (copy !== undefined) {
430                        target[name] = copy;
431                    }
432                }
433            }
434        }
435
436        // Return the modified object
437        return target;
438    };
439
440    isArray = Array.isArray || function (obj) {
441        return Object.prototype.toString.call(obj) === "[object Array]";
442    };
443
444    isFunction = function (obj) {
445        return Object.prototype.toString.call(obj) === "[object Function]"
446    }
447
448    isObject = function (obj) {
449        return Object.prototype.toString.call(obj) === "[object Object]";
450    };
451
452    startsWith = function (value, pattern) {
453        return value.indexOf(pattern) === 0;
454    };
455
456    trim = function (value) {
457        return (value + "").replace(regexTrim, "");
458    };
459
460    truncate = function (value) {
461        return value | 0;
462    };
463
464    zeroPad = function (str, count, left) {
465        var l;
466        for (l = str.length; l < count; l += 1) {
467            str = (left ? ("0" + str) : (str + "0"));
468        }
469        return str;
470    };
471
472    //
473    // private Globalization utility functions
474    //
475
476    appendPreOrPostMatch = function (preMatch, strings) {
477        // appends pre- and post- token match strings while removing escaped characters.
478        // Returns a single quote count which is used to determine if the token occurs
479        // in a string literal.
480        var quoteCount = 0,
481		escaped = false;
482        for (var i = 0, il = preMatch.length; i < il; i++) {
483            var c = preMatch.charAt(i);
484            switch (c) {
485                case "\'":
486                    if (escaped) {
487                        strings.push("\'");
488                    }
489                    else {
490                        quoteCount++;
491                    }
492                    escaped = false;
493                    break;
494                case "\\":
495                    if (escaped) {
496                        strings.push("\\");
497                    }
498                    escaped = !escaped;
499                    break;
500                default:
501                    strings.push(c);
502                    escaped = false;
503                    break;
504            }
505        }
506        return quoteCount;
507    };
508
509    expandFormat = function (cal, format) {
510        // expands unspecified or single character date formats into the full pattern.
511        format = format || "F";
512        var pattern,
513		patterns = cal.patterns,
514		len = format.length;
515        if (len === 1) {
516            pattern = patterns[format];
517            if (!pattern) {
518                throw "Invalid date format string \'" + format + "\'.";
519            }
520            format = pattern;
521        }
522        else if (len === 2 && format.charAt(0) === "%") {
523            // %X escape format -- intended as a custom format string that is only one character, not a built-in format.
524            format = format.charAt(1);
525        }
526        return format;
527    };
528
529    formatDate = function (value, format, culture) {
530        var cal = culture.calendar,
531		convert = cal.convert;
532
533        if (!format || !format.length || format === "i") {
534            var ret;
535            if (culture && culture.name.length) {
536                if (convert) {
537                    // non-gregorian calendar, so we cannot use built-in toLocaleString()
538                    ret = formatDate(value, cal.patterns.F, culture);
539                }
540                else {
541                    var eraDate = new Date(value.getTime()),
542					era = getEra(value, cal.eras);
543                    eraDate.setFullYear(getEraYear(value, cal, era));
544                    ret = eraDate.toLocaleString();
545                }
546            }
547            else {
548                ret = value.toString();
549            }
550            return ret;
551        }
552
553        var eras = cal.eras,
554		sortable = format === "s";
555        format = expandFormat(cal, format);
556
557        // Start with an empty string
558        ret = [];
559        var hour,
560		zeros = ["0", "00", "000"],
561		foundDay,
562		checkedDay,
563		dayPartRegExp = /([^d]|^)(d|dd)([^d]|$)/g,
564		quoteCount = 0,
565		tokenRegExp = getTokenRegExp(),
566		converted;
567
568        function padZeros(num, c) {
569            var r, s = num + "";
570            if (c > 1 && s.length < c) {
571                r = (zeros[c - 2] + s);
572                return r.substr(r.length - c, c);
573            }
574            else {
575                r = s;
576            }
577            return r;
578        }
579
580        function hasDay() {
581            if (foundDay || checkedDay) {
582                return foundDay;
583            }
584            foundDay = dayPartRegExp.test(format);
585            checkedDay = true;
586            return foundDay;
587        }
588
589        function getPart(date, part) {
590            if (converted) {
591                return converted[part];
592            }
593            switch (part) {
594                case 0: return date.getFullYear();
595                case 1: return date.getMonth();
596                case 2: return date.getDate();
597            }
598        }
599
600        if (!sortable && convert) {
601            converted = convert.fromGregorian(value);
602        }
603
604        for (; ; ) {
605            // Save the current index
606            var index = tokenRegExp.lastIndex,
607            // Look for the next pattern
608			ar = tokenRegExp.exec(format);
609
610            // Append the text before the pattern (or the end of the string if not found)
611            var preMatch = format.slice(index, ar ? ar.index : format.length);
612            quoteCount += appendPreOrPostMatch(preMatch, ret);
613
614            if (!ar) {
615                break;
616            }
617
618            // do not replace any matches that occur inside a string literal.
619            if (quoteCount % 2) {
620                ret.push(ar[0]);
621                continue;
622            }
623
624            var current = ar[0],
625			clength = current.length;
626
627            switch (current) {
628                case "ddd":
629                    //Day of the week, as a three-letter abbreviation
630                case "dddd":
631                    // Day of the week, using the full name
632                    var names = (clength === 3) ? cal.days.namesAbbr : cal.days.names;
633                    ret.push(names[value.getDay()]);
634                    break;
635                case "d":
636                    // Day of month, without leading zero for single-digit days
637                case "dd":
638                    // Day of month, with leading zero for single-digit days
639                    foundDay = true;
640                    ret.push(
641					padZeros(getPart(value, 2), clength)
642				);
643                    break;
644                case "MMM":
645                    // Month, as a three-letter abbreviation
646                case "MMMM":
647                    // Month, using the full name
648                    var part = getPart(value, 1);
649                    ret.push(
650					(cal.monthsGenitive && hasDay())
651					?
652					cal.monthsGenitive[clength === 3 ? "namesAbbr" : "names"][part]
653					:
654					cal.months[clength === 3 ? "namesAbbr" : "names"][part]
655				);
656                    break;
657                case "M":
658                    // Month, as digits, with no leading zero for single-digit months
659                case "MM":
660                    // Month, as digits, with leading zero for single-digit months
661                    ret.push(
662					padZeros(getPart(value, 1) + 1, clength)
663				);
664                    break;
665                case "y":
666                    // Year, as two digits, but with no leading zero for years less than 10
667                case "yy":
668                    // Year, as two digits, with leading zero for years less than 10
669                case "yyyy":
670                    // Year represented by four full digits
671                    part = converted ? converted[0] : getEraYear(value, cal, getEra(value, eras), sortable);
672                    if (clength < 4) {
673                        part = part % 100;
674                    }
675                    ret.push(
676					padZeros(part, clength)
677				);
678                    break;
679                case "h":
680                    // Hours with no leading zero for single-digit hours, using 12-hour clock
681                case "hh":
682                    // Hours with leading zero for single-digit hours, using 12-hour clock
683                    hour = value.getHours() % 12;
684                    if (hour === 0) hour = 12;
685                    ret.push(
686					padZeros(hour, clength)
687				);
688                    break;
689                case "H":
690                    // Hours with no leading zero for single-digit hours, using 24-hour clock
691                case "HH":
692                    // Hours with leading zero for single-digit hours, using 24-hour clock
693                    ret.push(
694					padZeros(value.getHours(), clength)
695				);
696                    break;
697                case "m":
698                    // Minutes with no leading zero for single-digit minutes
699                case "mm":
700                    // Minutes with leading zero for single-digit minutes
701                    ret.push(
702					padZeros(value.getMinutes(), clength)
703				);
704                    break;
705                case "s":
706                    // Seconds with no leading zero for single-digit seconds
707                case "ss":
708                    // Seconds with leading zero for single-digit seconds
709                    ret.push(
710					padZeros(value.getSeconds(), clength)
711				);
712                    break;
713                case "t":
714                    // One character am/pm indicator ("a" or "p")
715                case "tt":
716                    // Multicharacter am/pm indicator
717                    part = value.getHours() < 12 ? (cal.AM ? cal.AM[0] : " ") : (cal.PM ? cal.PM[0] : " ");
718                    ret.push(clength === 1 ? part.charAt(0) : part);
719                    break;
720                case "f":
721                    // Deciseconds
722                case "ff":
723                    // Centiseconds
724                case "fff":
725                    // Milliseconds
726                    ret.push(
727					padZeros(value.getMilliseconds(), 3).substr(0, clength)
728				);
729                    break;
730                case "z":
731                    // Time zone offset, no leading zero
732                case "zz":
733                    // Time zone offset with leading zero
734                    hour = value.getTimezoneOffset() / 60;
735                    ret.push(
736					(hour <= 0 ? "+" : "-") + padZeros(Math.floor(Math.abs(hour)), clength)
737				);
738                    break;
739                case "zzz":
740                    // Time zone offset with leading zero
741                    hour = value.getTimezoneOffset() / 60;
742                    ret.push(
743					(hour <= 0 ? "+" : "-") + padZeros(Math.floor(Math.abs(hour)), 2)
744                    // Hard coded ":" separator, rather than using cal.TimeSeparator
745                    // Repeated here for consistency, plus ":" was already assumed in date parsing.
746					+ ":" + padZeros(Math.abs(value.getTimezoneOffset() % 60), 2)
747				);
748                    break;
749                case "g":
750                case "gg":
751                    if (cal.eras) {
752                        ret.push(
753						cal.eras[getEra(value, eras)].name
754					);
755                    }
756                    break;
757                case "/":
758                    ret.push(cal["/"]);
759                    break;
760                default:
761                    throw "Invalid date format pattern \'" + current + "\'.";
762                    break;
763            }
764        }
765        return ret.join("");
766    };
767
768    // formatNumber
769    (function () {
770        var expandNumber;
771
772        expandNumber = function (number, precision, formatInfo) {
773            var groupSizes = formatInfo.groupSizes,
774			curSize = groupSizes[0],
775			curGroupIndex = 1,
776			factor = Math.pow(10, precision),
777			rounded = Math.round(number * factor) / factor;
778
779            if (!isFinite(rounded)) {
780                rounded = number;
781            }
782            number = rounded;
783
784            var numberString = number + "",
785			right = "",
786			split = numberString.split(/e/i),
787			exponent = split.length > 1 ? parseInt(split[1], 10) : 0;
788            numberString = split[0];
789            split = numberString.split(".");
790            numberString = split[0];
791            right = split.length > 1 ? split[1] : "";
792
793            var l;
794            if (exponent > 0) {
795                right = zeroPad(right, exponent, false);
796                numberString += right.slice(0, exponent);
797                right = right.substr(exponent);
798            }
799            else if (exponent < 0) {
800                exponent = -exponent;
801                numberString = zeroPad(numberString, exponent + 1);
802                right = numberString.slice(-exponent, numberString.length) + right;
803                numberString = numberString.slice(0, -exponent);
804            }
805
806            if (precision > 0) {
807                right = formatInfo["."] +
808				((right.length > precision) ? right.slice(0, precision) : zeroPad(right, precision));
809            }
810            else {
811                right = "";
812            }
813
814            var stringIndex = numberString.length - 1,
815			sep = formatInfo[","],
816			ret = "";
817
818            while (stringIndex >= 0) {
819                if (curSize === 0 || curSize > stringIndex) {
820                    return numberString.slice(0, stringIndex + 1) + (ret.length ? (sep + ret + right) : right);
821                }
822                ret = numberString.slice(stringIndex - curSize + 1, stringIndex + 1) + (ret.length ? (sep + ret) : "");
823
824                stringIndex -= curSize;
825
826                if (curGroupIndex < groupSizes.length) {
827                    curSize = groupSizes[curGroupIndex];
828                    curGroupIndex++;
829                }
830            }
831
832            return numberString.slice(0, stringIndex + 1) + sep + ret + right;
833        };
834
835        formatNumber = function (value, format, culture) {
836            if (!isFinite(value)) {
837                if (value === Infinity) {
838                    return culture.numberFormat.positiveInfinity;
839                }
840                if (value === -Infinity) {
841                    return culture.numberFormat.negativeInfinity;
842                }
843                return culture.numberFormat.NaN;
844            }
845            if (!format || format === "i") {
846                return culture.name.length ? value.toLocaleString() : value.toString();
847            }
848            format = format || "D";
849
850            var nf = culture.numberFormat,
851			number = Math.abs(value),
852			precision = -1,
853			pattern;
854            if (format.length > 1) precision = parseInt(format.slice(1), 10);
855
856            var current = format.charAt(0).toUpperCase(),
857			formatInfo;
858
859            switch (current) {
860                case "D":
861                    pattern = "n";
862                    number = truncate(number);
863                    if (precision !== -1) {
864                        number = zeroPad("" + number, precision, true);
865                    }
866                    if (value < 0) number = "-" + number;
867                    break;
868                case "N":
869                    formatInfo = nf;
870                    // fall through
871                case "C":
872                    formatInfo = formatInfo || nf.currency;
873                    // fall through
874                case "P":
875                    formatInfo = formatInfo || nf.percent;
876                    pattern = value < 0 ? formatInfo.pattern[0] : (formatInfo.pattern[1] || "n");
877                    if (precision === -1) precision = formatInfo.decimals;
878                    number = expandNumber(number * (current === "P" ? 100 : 1), precision, formatInfo);
879                    break;
880                default:
881                    throw "Bad number format specifier: " + current;
882            }
883
884            var patternParts = /n|\$|-|%/g,
885			ret = "";
886            for (; ; ) {
887                var index = patternParts.lastIndex,
888				ar = patternParts.exec(pattern);
889
890                ret += pattern.slice(index, ar ? ar.index : pattern.length);
891
892                if (!ar) {
893                    break;
894                }
895
896                switch (ar[0]) {
897                    case "n":
898                        ret += number;
899                        break;
900                    case "$":
901                        ret += nf.currency.symbol;
902                        break;
903                    case "-":
904                        // don't make 0 negative
905                        if (/[1-9]/.test(number)) {
906                            ret += nf["-"];
907                        }
908                        break;
909                    case "%":
910                        ret += nf.percent.symbol;
911                        break;
912                }
913            }
914
915            return ret;
916        };
917
918    } ());
919
920    getTokenRegExp = function () {
921        // regular expression for matching date and time tokens in format strings.
922        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;
923    };
924
925    getEra = function (date, eras) {
926        if (!eras) return 0;
927        var start, ticks = date.getTime();
928        for (var i = 0, l = eras.length; i < l; i++) {
929            start = eras[i].start;
930            if (start === null || ticks >= start) {
931                return i;
932            }
933        }
934        return 0;
935    };
936
937    getEraYear = function (date, cal, era, sortable) {
938        var year = date.getFullYear();
939        if (!sortable && cal.eras) {
940            // convert normal gregorian year to era-shifted gregorian
941            // year by subtracting the era offset
942            year -= cal.eras[era].offset;
943        }
944        return year;
945    };
946
947    // parseExact
948    (function () {
949        var expandYear,
950		getDayIndex,
951		getMonthIndex,
952		getParseRegExp,
953		outOfRange,
954		toUpper,
955		toUpperArray;
956
957        expandYear = function (cal, year) {
958            // expands 2-digit year into 4 digits.
959            var now = new Date(),
960			era = getEra(now);
961            if (year < 100) {
962                var twoDigitYearMax = cal.twoDigitYearMax;
963                twoDigitYearMax = typeof twoDigitYearMax === "string" ? new Date().getFullYear() % 100 + parseInt(twoDigitYearMax, 10) : twoDigitYearMax;
964                var curr = getEraYear(now, cal, era);
965                year += curr - (curr % 100);
966                if (year > twoDigitYearMax) {
967                    year -= 100;
968                }
969            }
970            return year;
971        };
972
973        getDayIndex = function (cal, value, abbr) {
974            var ret,
975			days = cal.days,
976			upperDays = cal._upperDays;
977            if (!upperDays) {
978                cal._upperDays = upperDays = [
979				toUpperArray(days.names),
980				toUpperArray(days.namesAbbr),
981				toUpperArray(days.namesShort)
982			];
983            }
984            value = toUpper(value);
985            if (abbr) {
986                ret = arrayIndexOf(upperDays[1], value);
987                if (ret === -1) {
988                    ret = arrayIndexOf(upperDays[2], value);
989                }
990            }
991            else {
992                ret = arrayIndexOf(upperDays[0], value);
993            }
994            return ret;
995        };
996
997        getMonthIndex = function (cal, value, abbr) {
998            var months = cal.months,
999			monthsGen = cal.monthsGenitive || cal.months,
1000			upperMonths = cal._upperMonths,
1001			upperMonthsGen = cal._upperMonthsGen;
1002            if (!upperMonths) {
1003                cal._upperMonths = upperMonths = [
1004				toUpperArray(months.names),
1005				toUpperArray(months.namesAbbr)
1006			];
1007                cal._upperMonthsGen = upperMonthsGen = [
1008				toUpperArray(monthsGen.names),
1009				toUpperArray(monthsGen.namesAbbr)
1010			];
1011            }
1012            value = toUpper(value);
1013            var i = arrayIndexOf(abbr ? upperMonths[1] : upperMonths[0], value);
1014            if (i < 0) {
1015                i = arrayIndexOf(abbr ? upperMonthsGen[1] : upperMonthsGen[0], value);
1016            }
1017            return i;
1018        };
1019
1020        getParseRegExp = function (cal, format) {
1021            // converts a format string into a regular expression with groups that
1022            // can be used to extract date fields from a date string.
1023            // check for a cached parse regex.
1024            var re = cal._parseRegExp;
1025            if (!re) {
1026                cal._parseRegExp = re = {};
1027            }
1028            else {
1029                var reFormat = re[format];
1030                if (reFormat) {
1031                    return reFormat;
1032                }
1033            }
1034
1035            // expand single digit formats, then escape regular expression characters.
1036            var expFormat = expandFormat(cal, format).replace(/([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g, "\\\\$1"),
1037			regexp = ["^"],
1038			groups = [],
1039			index = 0,
1040			quoteCount = 0,
1041			tokenRegExp = getTokenRegExp(),
1042			match;
1043
1044            // iterate through each date token found.
1045            while ((match = tokenRegExp.exec(expFormat)) !== null) {
1046                var preMatch = expFormat.slice(index, match.index);
1047                index = tokenRegExp.lastIndex;
1048
1049                // don't replace any matches that occur inside a string literal.
1050                quoteCount += appendPreOrPostMatch(preMatch, regexp);
1051                if (quoteCount % 2) {
1052                    regexp.push(match[0]);
1053                    continue;
1054                }
1055
1056                // add a regex group for the token.
1057                var m = match[0],
1058				len = m.length,
1059				add;
1060                switch (m) {
1061                    case "dddd": case "ddd":
1062                    case "MMMM": case "MMM":
1063                    case "gg": case "g":
1064                        add = "(\\D+)";
1065                        break;
1066                    case "tt": case "t":
1067                        add = "(\\D*)";
1068                        break;
1069                    case "yyyy":
1070                    case "fff":
1071                    case "ff":
1072                    case "f":
1073                        add = "(\\d{" + len + "})";
1074                        break;
1075                    case "dd": case "d":
1076                    case "MM": case "M":
1077                    case "yy": case "y":
1078                    case "HH": case "H":
1079                    case "hh": case "h":
1080                    case "mm": case "m":
1081                    case "ss": case "s":
1082                        add = "(\\d\\d?)";
1083                        break;
1084                    case "zzz":
1085                        add = "([+-]?\\d\\d?:\\d{2})";
1086                        break;
1087                    case "zz": case "z":
1088                        add = "([+-]?\\d\\d?)";
1089                        break;
1090                    case "/":
1091                        add = "(\\" + cal["/"] + ")";
1092                        break;
1093                    default:
1094                        throw "Invalid date format pattern \'" + m + "\'.";
1095                        break;
1096                }
1097                if (add) {
1098                    regexp.push(add);
1099                }
1100                groups.push(match[0]);
1101            }
1102            appendPreOrPostMatch(expFormat.slice(index), regexp);
1103            regexp.push("$");
1104
1105            // allow whitespace to differ when matching formats.
1106            var regexpStr = regexp.join("").replace(/\s+/g, "\\s+"),
1107			parseRegExp = { "regExp": regexpStr, "groups": groups };
1108
1109            // cache the regex for this format.
1110            return re[format] = parseRegExp;
1111        };
1112
1113        outOfRange = function (value, low, high) {
1114            return value < low || value > high;
1115        };
1116
1117        toUpper = function (value) {
1118            // "he-IL" has non-breaking space in weekday names.
1119            return value.split("\u00A0").join(" ").toUpperCase();
1120        };
1121
1122        toUpperArray = function (arr) {
1123            var results = [];
1124            for (var i = 0, l = arr.length; i < l; i++) {
1125                results[i] = toUpper(arr[i]);
1126            }
1127            return results;
1128        };
1129
1130        parseExact = function (value, format, culture) {
1131            // try to parse the date string by matching against the format str
1131ing
1132            // while using the specified culture for date field names.
1133            value = trim(value);
1134            var cal = culture.calendar,
1135            // convert date formats into regular expressions with groupings.
1136            // use the regexp to determine the input format and extract the date fields.
1137			parseInfo = getParseRegExp(cal, format),
1138			match = new RegExp(parseInfo.regExp).exec(value);
1139            if (match === null) {
1140                return null;
1141            }
1142            // found a date format that matches the input.
1143            var groups = parseInfo.groups,
1144			era = null, year = null, month = null, date = null, weekDay = null,
1145			hour = 0, hourOffset, min = 0, sec = 0, msec = 0, tzMinOffset = null,
1146			pmHour = false;
1147            // iterate the format groups to extract and set the date fields.
1148            for (var j = 0, jl = groups.length; j < jl; j++) {
1149                var matchGroup = match[j + 1];
1150                if (matchGroup) {
1151                    var current = groups[j],
1152					clength = current.length,
1153					matchInt = parseInt(matchGroup, 10);
1154                    switch (current) {
1155                        case "dd": case "d":
1156                            // Day of month.
1157                            date = matchInt;
1158                            // check that date is generally in valid range, also checking overflow below.
1159                            if (outOfRange(date, 1, 31)) return null;
1160                            break;
1161                        case "MMM": case "MMMM":
1162                            month = getMonthIndex(cal, matchGroup, clength === 3);
1163                            if (outOfRange(month, 0, 11)) return null;
1164                            break;
1165                        case "M": case "MM":
1166                            // Month.
1167                            month = matchInt - 1;
1168                            if (outOfRange(month, 0, 11)) return null;
1169                            break;
1170                        case "y": case "yy":
1171                        case "yyyy":
1172                            year = clength < 4 ? expandYear(cal, matchInt) : matchInt;
1173                            if (outOfRange(year, 0, 9999)) return null;
1174                            break;
1175                        case "h": case "hh":
1176                            // Hours (12-hour clock).
1177                            hour = matchInt;
1178                            if (hour === 12) hour = 0;
1179                            if (outOfRange(hour, 0, 11)) return null;
1180                            break;
1181                        case "H": case "HH":
1182                            // Hours (24-hour clock).
1183                            hour = matchInt;
1184                            if (outOfRange(hour, 0, 23)) return null;
1185                            break;
1186                        case "m": case "mm":
1187                            // Minutes.
1188                            min = matchInt;
1189                            if (outOfRange(min, 0, 59)) return null;
1190                            break;
1191                        case "s": case "ss":
1192                            // Seconds.
1193                            sec = matchInt;
1194                            if (outOfRange(sec, 0, 59)) return null;
1195                            break;
1196                        case "tt": case "t":
1197                            // AM/PM designator.
1198                            // see if it is standard, upper, or lower case PM. If not, ensure it is at least one of
1199                            // the AM tokens. If not, fail the parse for this format.
1200                            pmHour = cal.PM && (matchGroup === cal.PM[0] || matchGroup === cal.PM[1] || matchGroup === cal.PM[2]);
1201                            if (
1202							!pmHour && (
1203								!cal.AM || (matchGroup !== cal.AM[0] && matchGroup !== cal.AM[1] && matchGroup !== cal.AM[2])
1204							)
1205						) return null;
1206                            break;
1207                        case "f":
1208                            // Deciseconds.
1209                        case "ff":
1210                            // Centiseconds.
1211                        case "fff":
1212                            // Milliseconds.
1213                            msec = matchInt * Math.pow(10, 3 - clength);
1214                            if (outOfRange(msec, 0, 999)) return null;
1215                            break;
1216                        case "ddd":
1217                            // Day of week.
1218                        case "dddd":
1219                            // Day of week.
1220                            weekDay = getDayIndex(cal, matchGroup, clength === 3);
1221                            if (outOfRange(weekDay, 0, 6)) return null;
1222                            break;
1223                        case "zzz":
1224                            // Time zone offset in +/- hours:min.
1225                            var offsets = matchGroup.split(/:/);
1226                            if (offsets.length !== 2) return null;
1227                            hourOffset = parseInt(offsets[0], 10);
1228                            if (outOfRange(hourOffset, -12, 13)) return null;
1229                            var minOffset = parseInt(offsets[1], 10);
1230                            if (outOfRange(minOffset, 0, 59)) return null;
1231                            tzMinOffset = (hourOffset * 60) + (startsWith(matchGroup, "-") ? -minOffset : minOffset);
1232                            break;
1233                        case "z": case "zz":
1234                            // Time zone offset in +/- hours.
1235                            hourOffset = matchInt;
1236                            if (outOfRange(hourOffset, -12, 13)) return null;
1237                            tzMinOffset = hourOffset * 60;
1238                            break;
1239                        case "g": case "gg":
1240                            var eraName = matchGroup;
1241                            if (!eraName || !cal.eras) return null;
1242                            eraName = trim(eraName.toLowerCase());
1243                            for (var i = 0, l = cal.eras.length; i < l; i++) {
1244                                if (eraName === cal.eras[i].name.toLowerCase()) {
1245                                    era = i;
1246                                    break;
1247                                }
1248                            }
1249                            // could not find an era with that name
1250                            if (era === null) return null;
1251                            break;
1252                    }
1253                }
1254            }
1255            var result = new Date(), defaultYear, convert = cal.convert;
1256            defaultYear = convert ? convert.fromGregorian(result)[0] : result.getFullYear();
1257            if (year === null) {
1258                year = defaultYear;
1259            }
1260            else if (cal.eras) {
1261                // year must be shifted to normal gregorian year
1262                // but not if year was not specified, its already normal gregorian
1263                // per the main if clause above.
1264                year += cal.eras[(era || 0)].offset;
1265            }
1266            // set default day and month to 1 and January, so if unspecified, these are the defaults
1267            // instead of the current day/month.
1268            if (month === null) {
1269                month = 0;
1270            }
1271            if (date === null) {
1272                date = 1;
1273            }
1274            // now have year, month, and date, but in the culture's calendar.
1275            // convert to gregorian if necessary
1276            if (convert) {
1277                result = convert.toGregorian(year, month, date);
1278                // conversion failed, must be an invalid match
1279                if (result === null) return null;
1280            }
1281            else {
1282                // have to set year, month and date together to avoid overflow based on current date.
1283                result.setFullYear(year, month, date);
1284                // check to see if date overflowed for specified month (only checked 1-31 above).
1285                if (result.getDate() !== date) return null;
1286                // invalid day of week.
1287                if (weekDay !== null && result.getDay() !== weekDay) {
1288                    return null;
1289                }
1290            }
1291            // if pm designator token was found make sure the hours fit the 24-hour clock.
1292            if (pmHour && hour < 12) {
1293                hour += 12;
1294            }
1295            result.setHours(hour, min, sec, msec);
1296            if (tzMinOffset !== null) {
1297                // adjust timezone to utc before applying local offset.
1298                var adjustedMin = result.getMinutes() - (tzMinOffset + result.getTimezoneOffset());
1299                // Safari limits hours and minutes to the range of -127 to 127.	 We need to use setHours
1300                // to ensure both these fields will not exceed this range.	adjustedMin will range
1301                // somewhere between -1440 and 1500, so we only need to split this into hours.
1302                result.setHours(result.getHours() + parseInt(adjustedMin / 60, 10), adjustedMin % 60);
1303            }
1304            return result;
1305        };
1306    } ());
1307
1308    parseNegativePattern = function (value, nf, negativePattern) {
1309        var neg = nf["-"],
1310		pos = nf["+"],
1311		ret;
1312        switch (negativePattern) {
1313            case "n -":
1314                neg = " " + neg;
1315                pos = " " + pos;
1316                // fall through
1317            case "n-":
1318                if (endsWith(value, neg)) {
1319                    ret = ["-", value.substr(0, value.length - neg.length)];
1320                }
1321                else if (endsWith(value, pos)) {
1322                    ret = ["+", value.substr(0, value.length - pos.length)];
1323                }
1324                break;
1325            case "- n":
1326                neg += " ";
1327                pos += " ";
1328                // fall through
1329            case "-n":
1330                if (startsWith(value, neg)) {
1331                    ret = ["-", value.substr(neg.length)];
1332                }
1333                else if (startsWith(value, pos)) {
1334                    ret = ["+", value.substr(pos.length)];
1335                }
1336                break;
1337            case "(n)":
1338                if (startsWith(value, "(") && endsWith(value, ")")) {
1339                    ret = ["-", value.substr(1, value.length - 2)];
1340                }
1341                break;
1342        }
1343        return ret || ["", value];
1344    };
1345
1346    //
1347    // public instance functions
1348    //
1349
1350    Globalize.prototype.findClosestCulture = function (cultureSelector) {
1351        return Globalize.findClosestCulture.call(this, cultureSelector);
1352    };
1353
1354    Globalize.prototype.format = function (value, format, cultureSelector) {
1355        return Globalize.format.call(this, value, format, cultureSelector);
1356    };
1357
1358    Globalize.prototype.localize = function (key, cultureSelector) {
1359        return Globalize.localize.call(this, key, cultureSelector);
1360    };
1361
1362    Globalize.prototype.parseInt = function (value, radix, cultureSelector) {
1363        return Globalize.parseInt.call(this, value, radix, cultureSelector);
1364    };
1365
1366    Globalize.prototype.parseFloat = function (value, radix, cultureSelector) {
1367        return Globalize.parseFloat.call(this, value, radix, cultureSelector);
1368    };
1369
1370    Globalize.prototype.culture = function (cultureSelector) {
1371        return Globalize.culture.call(this, cultureSelector);
1372    };
1373
1374    //
1375    // public singleton functions
1376    //
1377
1378    Globalize.addCultureInfo = function (cultureName, baseCultureName, info) {
1379
1380        var base = {},
1381		isNew = false;
1382
1383        if (typeof cultureName !== "string") {
1384            // cultureName argument is optional string. If not specified, assume info is first
1385            // and only argument. Specified info deep-extends current culture.
1386            info = cultureName;
1387            cultureName = this.culture().name;
1388            base = this.cultures[cultureName];
1389        } else if (typeof baseCultureName !== "string") {
1390            // baseCultureName argument is optional string. If not specified, assume info is second
1391            // argument. Specified info deep-extends specified culture.
1392            // If specified culture does not exist, create by deep-extending default
1393            info = baseCultureName;
1394            isNew = (this.cultures[cultureName] == null);
1395            base = this.cultures[cultureName] || this.cultures["default"];
1396        } else {
1397            // cultureName and baseCultureName specified. Assume a new culture is being created
1398            // by deep-extending an specified base culture
1399            isNew = true;
1400            base = this.cultures[baseCultureName];
1401        }
1402
1403        this.cultures[cultureName] = extend(true, {},
1404		base,
1405		info
1406	);
1407        // Make the standard calendar the current culture if it's a new culture
1408        if (isNew) {
1409            this.cultures[cultureName].calendar = this.cultures[cultureName].calendars.standard;
1410        }
1411    };
1412
1413    Globalize.findClosestCulture = function (name) {
1414        var match;
1415        if (!name) {
1416            return this.cultures[this.cultureSelector] || this.cultures["default"];
1417        }
1418        if (typeof name === "string") {
1419            name = name.split(",");
1420        }
1421        if (isArray(name)) {
1422            var lang,
1423			cultures = this.cultures,
1424			list = name,
1425			i, l = list.length,
1426			prioritized = [];
1427            for (i = 0; i < l; i++) {
1428                name = trim(list[i]);
1429                var pri, parts = name.split(";");
1430                lang = trim(parts[0]);
1431                if (parts.length === 1) {
1432                    pri = 1;
1433                }
1434                else {
1435                    name = trim(parts[1]);
1436                    if (name.indexOf("q=") === 0) {
1437                        name = name.substr(2);
1438                        pri = parseFloat(name);
1439                        pri = isNaN(pri) ? 0 : pri;
1440                    }
1441                    else {
1442                        pri = 1;
1443                    }
1444                }
1445                prioritized.push({ lang: lang, pri: pri });
1446            }
1447            prioritized.sort(function (a, b) {
1448                return a.pri < b.pri ? 1 : -1;
1449            });
1450
1451            // exact match
1452            for (i = 0; i < l; i++) {
1453                lang = prioritized[i].lang;
1454                match = cultures[lang];
1455                if (match) {
1456                    return match;
1457                }
1458            }
1459
1460            // neutral language match
1461            for (i = 0; i < l; i++) {
1462                lang = prioritized[i].lang;
1463                do {
1464                    var index = lang.lastIndexOf("-");
1465                    if (index === -1) {
1466                        break;
1467                    }
1468                    // strip off the last part. e.g. en-US => en
1469                    lang = lang.substr(0, index);
1470                    match = cultures[lang];
1471                    if (match) {
1472                        return match;
1473                    }
1474                }
1475                while (1);
1476            }
1477
1478            // last resort: match first culture using that language
1479            for (i = 0; i < l; i++) {
1480                lang = prioritized[i].lang;
1481                for (var cultureKey in cultures) {
1482                    var culture = cultures[cultureKey];
1483                    if (culture.language == lang) {
1484                        return culture;
1485                    }
1486                }
1487            }
1488        }
1489        else if (typeof name === "object") {
1490            return name;
1491        }
1492        return match || null;
1493    };
1494
1495    Globalize.format = function (value, format, cultureSelector) {
1496        culture = this.findClosestCulture(cultureSelector);
1497        if (value instanceof Date) {
1498            value = formatDate(value, format, culture);
1499        }
1500        else if (typeof value === "number") {
1501            value = formatNumber(value, format, culture);
1502        }
1503        return value;
1504    };
1505
1506    Globalize.localize = function (key, cultureSelector) {
1507        return this.findClosestCulture(cultureSelector).messages[key] ||
1508		this.cultures["default"].messages[key];
1509    };
1510
1511    Globalize.parseDate = function (value, formats, culture) {
1512        culture = this.findClosestCulture(culture);
1513
1514        var date, prop, patterns;
1515        if (formats) {
1516            if (typeof formats === "string") {
1517                formats = [formats];
1518            }
1519            if (formats.length) {
1520                for (var i = 0, l = formats.length; i < l; i++) {
1521                    var format = formats[i];
1522                    if (format) {
1523                        date = parseExact(value, format, culture);
1524                        if (date) {
1525                            break;
1526                        }
1527                    }
1528                }
1529            }
1530        } else {
1531            patterns = culture.calendar.patterns;
1532            for (prop in patterns) {
1533                date = parseExact(value, patterns[prop], culture);
1534                if (date) {
1535                    break;
1536                }
1537            }
1538        }
1539
1540        return date || null;
1541    };
1542
1543    Globalize.parseInt = function (value, radix, cultureSelector) {
1544        return truncate(Globalize.parseFloat(value, radix, cultureSelector));
1545    };
1546
1547    Globalize.parseFloat = function (value, radix, cultureSelector) {
1548        // radix argument is optional
1549        if (typeof radix !== "number") {
1550            cultureSelector = radix;
1551            radix = 10;
1552        }
1553
1554        var culture = this.findClosestCulture(cultureSelector);
1555        var ret = NaN,
1556		nf = culture.numberFormat;
1557
1558        if (value.indexOf(culture.numberFormat.currency.symbol) > -1) {
1559            // remove currency symbol
1560            value = value.replace(culture.numberFormat.currency.symbol, "");
1561            // replace decimal seperator
1562            value = value.replace(culture.numberFormat.currency["."], culture.numberFormat["."]);
1563        }
1564
1565        // trim leading and trailing whitespace
1566        value = trim(value);
1567
1568        // allow infinity or hexidecimal
1569        if (regexInfinity.test(value)) {
1570            ret = parseFloat(value);
1571        }
1572        else if (!radix && regexHex.test(value)) {
1573            ret = parseInt(value, 16);
1574        }
1575        else {
1576
1577            // determine sign and number
1578            var signInfo = parseNegativePattern(value, nf, nf.pattern[0]),
1579			sign = signInfo[0],
1580			num = signInfo[1];
1581
1582            // #44 - try parsing as "(n)"
1583            if (sign === "" && nf.pattern[0] !== "(n)") {
1584                signInfo = parseNegativePattern(value, nf, "(n)");
1585                sign = signInfo[0];
1586                num = signInfo[1];
1587            }
1588
1589            // try parsing as "-n"
1590            if (sign === "" && nf.pattern[0] !== "-n") {
1591                signInfo = parseNegativePattern(value, nf, "-n");
1592                sign = signInfo[0];
1593                num = signInfo[1];
1594            }
1595
1596            sign = sign || "+";
1597
1598            // determine exponent and number
1599            var exponent,
1600			intAndFraction,
1601			exponentPos = num.indexOf("e");
1602            if (exponentPos < 0) exponentPos = num.indexOf("E");
1603            if (exponentPos < 0) {
1604                intAndFraction = num;
1605                exponent = null;
1606            }
1607            else {
1608                intAndFraction = num.substr(0, exponentPos);
1609                exponent = num.substr(exponentPos + 1);
1610            }
1611            // determine decimal position
1612            var integer,
1613			fraction,
1614			decSep = nf["."],
1615			decimalPos = intAndFraction.indexOf(decSep);
1616            if (decimalPos < 0) {
1617                integer = intAndFraction;
1618                fraction = null;
1619            }
1620            else {
1621                integer = intAndFraction.substr(0, decimalPos);
1622                fraction = intAndFraction.substr(decimalPos + decSep.length);
1623            }
1624            // handle groups (e.g. 1,000,000)
1625            var groupSep = nf[","];
1626            integer = integer.split(groupSep).join("");
1627            var altGroupSep = groupSep.replace(/\u00A0/g, " ");
1628            if (groupSep !== altGroupSep) {
1629                integer = integer.split(altGroupSep).join("");
1630            }
1631            // build a natively parsable number string
1632            var p = sign + integer;
1633            if (fraction !== null) {
1634                p += "." + fraction;
1635            }
1636            if (exponent !== null) {
1637                // exponent itself may have a number patternd
1638                var expSignInfo = parseNegativePattern(exponent, nf, "-n");
1639                p += "e" + (expSignInfo[0] || "+") + expSignInfo[1];
1640            }
1641            if (regexParseFloat.test(p)) {
1642                ret = parseFloat(p);
1643            }
1644        }
1645        return ret;
1646    };
1647
1648    Globalize.culture = function (cultureSelector) {
1649        // setter
1650        if (typeof cultureSelector !== "undefined") {
1651            this.cultureSelector = cultureSelector;
1652        }
1653        // getter
1654        return this.findClosestCulture(cultureSelector) || this.culture["default"];
1655    };
1656
1657} (this));
1658
1659//End JS Globalize
1660

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.