PageSourceSearch

https://www.marykay.cz/Content/MK/eSuite/Js/globalize/globalize.js

js marykay.cz collected 2026-09-26 02:30:27 UTC 45,719 bytes, 1,586 lines download raw bytes

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

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.