PageSourceSearch

https://dietologinutrizionisti.it/js/devextreme/globalize/number.js

js dietologinutrizionisti.it collected 2026-10-06 02:42:34 UTC 46,097 bytes, 1,727 lines download raw bytes

1/**
2 * Globalize v1.7.0
3 *
4 * https://github.com/globalizejs/globalize
5 *
6 * Copyright OpenJS Foundation and other contributors
7 * Released under the MIT license
8 * https://jquery.org/license
9 *
10 * Date: 2021-08-02T11:53Z
11 */
12/*!
13 * Globalize v1.7.0 2021-08-02T11:53Z Released under the MIT license
14 * http://git.io/TrdQbw
vendor: 38,525 bytes, lines 14-1454
14
15 */
16(function( root, factory ) {
17
18	// UMD returnExports
19	if ( typeof define === "function" && define.amd ) {
20
21		// AMD
22		define([
23			"cldr",
24			"../globalize",
25			"cldr/event",
26			"cldr/supplemental"
27		], factory );
28	} else if ( typeof exports === "object" ) {
29
30		// Node, CommonJS
31		module.exports = factory( require( "cldrjs" ), require( "../globalize" ) );
32	} else {
33
34		// Global
35		factory( root.Cldr, root.Globalize );
36	}
37}(this, function( Cldr, Globalize ) {
38
39var createError = Globalize._createError,
40	partsJoin = Globalize._partsJoin,
41	partsPush = Globalize._partsPush,
42	regexpEscape = Globalize._regexpEscape,
43	runtimeBind = Globalize._runtimeBind,
44	stringPad = Globalize._stringPad,
45	validateCldr = Globalize._validateCldr,
46	validateDefaultLocale = Globalize._validateDefaultLocale,
47	validateParameterPresence = Globalize._validateParameterPresence,
48	validateParameterRange = Globalize._validateParameterRange,
49	validateParameterType = Globalize._validateParameterType,
50	validateParameterTypePlainObject = Globalize._validateParameterTypePlainObject;
51
52
53var createErrorUnsupportedFeature = function( feature ) {
54	return createError( "E_UNSUPPORTED", "Unsupported {feature}.", {
55		feature: feature
56	});
57};
58
59
60
61
62var validateParameterTypeNumber = function( value, name ) {
63	validateParameterType(
64		value,
65		name,
66		value === undefined || typeof value === "number",
67		"Number"
68	);
69};
70
71
72
73
74var validateParameterTypeString = function( value, name ) {
75	validateParameterType(
76		value,
77		name,
78		value === undefined || typeof value === "string",
79		"a string"
80	);
81};
82
83
84
85
86var numberFormatterFn = function( numberToPartsFormatter ) {
87	return function numberFormatter( value ) {
88		return partsJoin( numberToPartsFormatter( value ));
89	};
90};
91
92
93
94
95/**
96 * NumberingSystem( cldr )
97 *
98 * - http://www.unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems
99 * - http://cldr.unicode.org/index/bcp47-extension
100 * - http://www.unicode.org/reports/tr35/#u_Extension
101 */
102var numberNumberingSystem = function( cldr ) {
103	var nu = cldr.attributes[ "u-nu" ];
104
105	if ( nu ) {
106		if ( nu === "traditio" ) {
107			nu = "traditional";
108		}
109		if ( [ "native", "traditional", "finance" ].indexOf( nu ) !== -1 ) {
110
111			// Unicode locale extension `u-nu` is set using either (native, traditional or
112			// finance). So, lookup the respective locale's numberingSystem and return it.
113			return cldr.main([ "numbers/otherNumberingSystems", nu ]);
114		}
115
116		// Unicode locale extension `u-nu` is set with an explicit numberingSystem. Return it.
117		return nu;
118	}
119
120	// Return the default numberingSystem.
121	return cldr.main( "numbers/defaultNumberingSystem" );
122};
123
124
125
126
127/**
128 * Compact( name, cldr )
129 *
130 * @compactType [String] Compact mode, `short` or `long`.
131 *
132 * @cldr [Cldr instance].
133 *
134 * Return the localized compact map for the given compact mode.
135 */
136var numberCompact = function( compactType, cldr ) {
137	var maxExponent = 0;
138
139	var object = cldr.main([
140		"numbers/decimalFormats-numberSystem-" + numberNumberingSystem( cldr ),
141		compactType,
142		"decimalFormat"
143	]);
144
145	object = Object.keys( object ).reduce(function( newObject, compactKey ) {
146		var numberExponent = compactKey.split( "0" ).length - 1;
147		var pluralForm = compactKey.split( "-" )[ 2 ];
148		newObject[ numberExponent ] = newObject[ numberExponent ] || {};
149		newObject[ numberExponent ][ pluralForm ] = object[ compactKey ];
150		maxExponent = Math.max( numberExponent, maxExponent );
151		return newObject;
152	}, {});
153
154	object.maxExponent = maxExponent;
155
156	return object;
157};
158
159
160
161
162/**
163 * nuMap( cldr )
164 *
165 * @cldr [Cldr instance].
166 *
167 * Return digits map if numbering system is different than `latn`.
168 */
169var numberNumberingSystemDigitsMap = function( cldr ) {
170	var aux,
171		nu = numberNumberingSystem( cldr );
172
173	if ( nu === "latn" ) {
174		return;
175	}
176
177	aux = cldr.supplemental([ "numberingSystems", nu ]);
178
179	if ( aux._type !== "numeric" ) {
180		throw createErrorUnsupportedFeature( "`" + aux._type + "` numbering system" );
181	}
182
183	return aux._digits;
184};
185
186
187
188
189/**
190 * EBNF representation:
191 *
192 * number_pattern_re =        prefix?
193 *                            padding?
194 *                            (integer_fraction_pattern | significant_pattern)
195 *                            scientific_notation?
196 *                            suffix?
197 *
198 * prefix =                   non_number_stuff
199 *
200 * padding =                  "*" regexp(.)
201 *
202 * integer_fraction_pattern = integer_pattern
203 *                            fraction_pattern?
204 *
205 * integer_pattern =          regexp([#,]*[0,]*0+)
206 *
207 * fraction_pattern =         "." regexp(0*[0-9]*#*)
208 *
209 * significant_pattern =      regexp([#,]*@+#*)
210 *
211 * scientific_notation =      regexp(E\+?0+)
212 *
213 * suffix =                   non_number_stuff
214 *
215 * non_number_stuff =         regexp(('[^']+'|''|[^*#@0,.E])*)
216 *
217 *
218 * Regexp groups:
219 *
220 *  0: number_pattern_re
221 *  1: prefix
222 *  2: -
223 *  3: -
224 *  4: padding
225 *  5: (integer_fraction_pattern | significant_pattern)
226 *  6: integer_fraction_pattern
227 *  7: integer_pattern
228 *  8: fraction_pattern
229 *  9: significant_pattern
230 * 10: scientific_notation
231 * 11: suffix
232 * 12: -
233 */
234var numberPatternRe = ( /^(('([^']|'')*'|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(('[^']+'|''|[^*#@0,.E])*)$/ );
235
236
237
238
239/**
240 * format( number, pattern )
241 *
242 * @number [Number].
243 *
244 * @pattern [String] raw pattern for numbers.
245 *
246 * Return the formatted number.
247 * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
248 */
249var numberPatternProperties = function( pattern ) {
250	var aux1, aux2, fractionPattern, integerFractionOrSignificantPattern, integerPattern,
251		maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
252		minimumIntegerDigits, minimumSignificantDigits, padding, prefix, primaryGroupingSize,
253		roundIncrement, scientificNotation, secondaryGroupingSize, significantPattern, suffix;
254
255	pattern = pattern.match( numberPatternRe );
256	if ( !pattern ) {
257		throw new Error( "Invalid pattern: " + pattern );
258	}
259
260	prefix = pattern[ 1 ];
261	padding = pattern[ 4 ];
262	integerFractionOrSignificantPattern = pattern[ 5 ];
263	significantPattern = pattern[ 9 ];
264	scientificNotation = pattern[ 10 ];
265	suffix = pattern[ 11 ];
266
267	// Significant digit format
268	if ( significantPattern ) {
269		significantPattern.replace( /(@+)(#*)/, function( _match, minimumSignificantDigitsMatch, maximumSignificantDigitsMatch ) {
270			minimumSignificantDigits = minimumSignificantDigitsMatch.length;
271			maximumSignificantDigits = minimumSignificantDigits +
272				maximumSignificantDigitsMatch.length;
273		});
274
275	// Integer and fractional format
276	} else {
277		fractionPattern = pattern[ 8 ];
278		integerPattern = pattern[ 7 ];
279
280		if ( fractionPattern ) {
281
282			// Minimum fraction digits, and rounding.
283			fractionPattern.replace( /[0-9]+/, function( match ) {
284				minimumFractionDigits = match;
285			});
286			if ( minimumFractionDigits ) {
287				roundIncrement = +( "0." + minimumFractionDigits );
288				minimumFractionDigits = minimumFractionDigits.length;
289			} else {
290				minimumFractionDigits = 0;
291			}
292
293			// Maximum fraction digits
294			// 1: ignore decimal character
295			maximumFractionDigits = fractionPattern.length - 1; /* 1 */
296		} else {
297			minimumFractionDigits = 0;
298			maximumFractionDigits = 0;
299		}
300
301		// Minimum integer digits
302		integerPattern.replace( /0+$/, function( match ) {
303			minimumIntegerDigits = match.length;
304		});
305	}
306
307	// Scientific notation
308	if ( scientificNotation ) {
309		throw createErrorUnsupportedFeature({
310			feature: "scientific notation (not implemented)"
311		});
312	}
313
314	// Padding
315	if ( padding ) {
316		throw createErrorUnsupportedFeature({
317			feature: "padding (not implemented)"
318		});
319	}
320
321	// Grouping
322	if ( ( aux1 = integerFractionOrSignificantPattern.lastIndexOf( "," ) ) !== -1 ) {
323
324		// Primary grouping size is the interval between the last group separator and the end of
325		// the integer (or the end of the significant pattern).
326		aux2 = integerFractionOrSignificantPattern.split( "." )[ 0 ];
327		primaryGroupingSize = aux2.length - aux1 - 1;
328
329		// Secondary grouping size is the interval between the last two group separators.
330		if ( ( aux2 = integerFractionOrSignificantPattern.lastIndexOf( ",", aux1 - 1 ) ) !== -1 ) {
331			secondaryGroupingSize = aux1 - 1 - aux2;
332		}
333	}
334
335	// Return:
336	//  0: @prefix String
337	//  1: @padding Array [ <character>, <count> ] TODO
338	//  2: @minimumIntegerDigits non-negative integer Number value indicating the minimum integer
339	//        digits to be used. Numbers will be padded with leading zeroes if necessary.
340	//  3: @minimumFractionDigits and
341	//  4: @maximumFractionDigits are non-negative integer Number values indicating the minimum and
342	//        maximum fraction digits to be used. Numbers will be rounded or padded with trailing
343	//        zeroes if necessary.
344	//  5: @minimumSignificantDigits and
345	//  6: @maximumSignificantDigits are positive integer Number values indicating the minimum and
346	//        maximum fraction digits to be shown. Either none or both of these properties are
347	//        present; if they are, they override minimum and maximum integer and fraction digits
348	//        – the formatter uses however many integer and fraction digits are required to display
349	//        the specified number of significant digits.
350	//  7: @roundIncrement Decimal round increment or null
351	//  8: @primaryGroupingSize
352	//  9: @secondaryGroupingSize
353	// 10: @suffix String
354	return [
355		prefix,
356		padding,
357		minimumIntegerDigits,
358		minimumFractionDigits,
359		maximumFractionDigits,
360		minimumSignificantDigits,
361		maximumSignificantDigits,
362		roundIncrement,
363		primaryGroupingSize,
364		secondaryGroupingSize,
365		suffix
366	];
367};
368
369
370
371
372/**
373 * Symbol( name, cldr )
374 *
375 * @name [String] Symbol name.
376 *
377 * @cldr [Cldr instance].
378 *
379 * Return the localized symbol given its name.
380 */
381var numberSymbol = function( name, cldr ) {
382	return cldr.main([
383		"numbers/symbols-numberSystem-" + numberNumberingSystem( cldr ),
384		name
385	]);
386};
387
388
389
390
391var numberSymbolName = {
392	".": "decimal",
393	",": "group",
394	"%": "percentSign",
395	"+": "plusSign",
396	"-": "minusSign",
397	"E": "exponential",
398	"\u2030": "perMille"
399};
400
401
402
403
404/**
405 * symbolMap( cldr )
406 *
407 * @cldr [Cldr instance].
408 *
409 * Return the (localized symbol, pattern symbol) key value pair, eg. {
410 *   ".": "Ù«",
411 *   ",": "Ù¬",
412 *   "%": "Ùª",
413 *   ...
414 * };
415 */
416var numberSymbolMap = function( cldr ) {
417	var symbol,
418		symbolMap = {};
419
420	for ( symbol in numberSymbolName ) {
421		symbolMap[ symbol ] = numberSymbol( numberSymbolName[ symbol ], cldr );
422	}
423
424	return symbolMap;
425};
426
427
428
429
430var numberTruncate = function( value ) {
431	if ( isNaN( value ) ) {
432		return NaN;
433	}
434	return Math[ value < 0 ? "ceil" : "floor" ]( value );
435};
436
437
438
439
440/**
441 * round( method )
442 *
443 * @method [String] with either "round", "ceil", "floor", or "truncate".
444 *
445 * Return function( value, incrementOrExp ):
446 *
447 *   @value [Number] eg. 123.45.
448 *
449 *   @incrementOrExp [Number] optional, eg. 0.1; or
450 *     [Object] Either { increment: <value> } or { exponent: <value> }
451 *
452 *   Return the rounded number, eg:
453 *   - round( "round" )( 123.45 ): 123;
454 *   - round( "ceil" )( 123.45 ): 124;
455 *   - round( "floor" )( 123.45 ): 123;
456 *   - round( "truncate" )( 123.45 ): 123;
457 *   - round( "round" )( 123.45, 0.1 ): 123.5;
458 *   - round( "round" )( 123.45, 10 ): 120;
459 *
460 *   Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
461 *   Ref: #376
462 */
463var numberRound = function( method ) {
464	method = method || "round";
465	method = method === "truncate" ? numberTruncate : Math[ method ];
466
467	return function( value, incrementOrExp ) {
468		var exp, increment;
469
470		value = +value;
471
472		// If the value is not a number, return NaN.
473		if ( isNaN( value ) ) {
474			return NaN;
475		}
476
477		// Exponent given.
478		if ( typeof incrementOrExp === "object" && incrementOrExp.exponent ) {
479			exp = +incrementOrExp.exponent;
480			increment = 1;
481
482			if ( exp === 0 ) {
483				return method( value );
484			}
485
486			// If the exp is not an integer, return NaN.
487			if ( !( typeof exp === "number" && exp % 1 === 0 ) ) {
488				return NaN;
489			}
490
491		// Increment given.
492		} else {
493			increment = +incrementOrExp || 1;
494
495			if ( increment === 1 ) {
496				return method( value );
497			}
498
499			// If the increment is not a number, return NaN.
500			if ( isNaN( increment ) ) {
501				return NaN;
502			}
503
504			increment = increment.toExponential().split( "e" );
505			exp = +increment[ 1 ];
506			increment = +increment[ 0 ];
507		}
508
509		// Shift & Round
510		value = value.toString().split( "e" );
511		value[ 0 ] = +value[ 0 ] / increment;
512		value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] - exp ) : -exp;
513		value = method( +( value[ 0 ] + "e" + value[ 1 ] ) );
514
515		// Shift back
516		value = value.toString().split( "e" );
517		value[ 0 ] = +value[ 0 ] * increment;
518		value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] + exp ) : exp;
519		return +( value[ 0 ] + "e" + value[ 1 ] );
520	};
521};
522
523
524
525
526/**
527 * formatProperties( pattern, cldr [, options] )
528 *
529 * @pattern [String] raw pattern for numbers.
530 *
531 * @cldr [Cldr instance].
532 *
533 * @options [Object]:
534 * - minimumIntegerDigits [Number]
535 * - minimumFractionDigits, maximumFractionDigits [Number]
536 * - minimumSignificantDigits, maximumSignificantDigits [Number]
537 * - round [String] "ceil", "floor", "round" (default), or "truncate".
538 * - useGrouping [Boolean] default true.
539 *
540 * Return the processed properties that will be used in number/format.
541 * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
542 */
543var numberFormatProperties = function( pattern, cldr, options ) {
544	var negativePattern, negativePrefix, negativeProperties, negativeSuffix, positivePattern,
545		roundFn, properties;
546
547	function getOptions( attribute, propertyIndex ) {
548		if ( attribute in options ) {
549			properties[ propertyIndex ] = options[ attribute ];
550		}
551	}
552
553	options = options || {};
554	pattern = pattern.split( ";" );
555
556	positivePattern = pattern[ 0 ];
557
558	negativePattern = pattern[ 1 ] || "-" + positivePattern;
559	negativeProperties = numberPatternProperties( negativePattern );
560	negativePrefix = negativeProperties[ 0 ];
561	negativeSuffix = negativeProperties[ 10 ];
562
563	// Have runtime code to refer to numberRound() instead of including it explicitly.
564	roundFn = numberRound( options.round );
565	roundFn.generatorString = function() {
566		return "numberRound(" + ( options.round ? "\"" + options.round + "\"" : "" ) + ")";
567	};
568
569	properties = numberPatternProperties( positivePattern ).concat([
570		positivePattern,
571		negativePrefix + positivePattern + negativeSuffix,
572		negativePrefix,
573		negativeSuffix,
574		roundFn,
575		numberSymbol( "infinity", cldr ),
576		numberSymbol( "nan", cldr ),
577		numberSymbolMap( cldr ),
578		numberNumberingSystemDigitsMap( cldr )
579	]);
580
581	if ( options.compact ) {
582
583		// The compact digits number pattern is always `0+`, so override the following properties.
584		// Note: minimumIntegerDigits would actually range from `0` to `000` based on the scale of
585		// the value to be formatted, though we're always using 1 as a simplification, because the
586		// number won't be zero-padded since we chose the right format based on the scale, i.e.,
587		// we'd never see something like `003M` anyway.
588		properties[ 2 ] = 1; // minimumIntegerDigits
589		properties[ 3 ] = 0; // minimumFractionDigits
590		properties[ 4 ] = 0; // maximumFractionDigits
591		properties[ 5 ] = // minimumSignificantDigits &
592			properties[ 6 ] = undefined; // maximumSignificantDigits
593
594		properties[ 20 ] = numberCompact( options.compact, cldr );
595	}
596
597	getOptions( "minimumIntegerDigits", 2 );
598	getOptions( "minimumFractionDigits", 3 );
599	getOptions( "maximumFractionDigits", 4 );
600	getOptions( "minimumSignificantDigits", 5 );
601	getOptions( "maximumSignificantDigits", 6 );
602
603	// Grouping separators
604	if ( options.useGrouping === false ) {
605		properties[ 8 ] = null;
606	}
607
608	// Normalize number of digits if only one of either minimumFractionDigits or
609	// maximumFractionDigits is passed in as an option
610	if ( "minimumFractionDigits" in options && !( "maximumFractionDigits" in options ) ) {
611
612		// maximumFractionDigits = Math.max( minimumFractionDigits, maximumFractionDigits );
613		properties[ 4 ] = Math.max( properties[ 3 ], properties[ 4 ] );
614	} else if ( !( "minimumFractionDigits" in options ) &&
615			"maximumFractionDigits" in options ) {
616
617		// minimumFractionDigits = Math.min( minimumFractionDigits, maximumFractionDigits );
618		properties[ 3 ] = Math.min( properties[ 3 ], properties[ 4 ] );
619	}
620
621	// Return:
622	// 0-10: see number/pattern-properties.
623	// 11: @positivePattern [String] Positive pattern.
624	// 12: @negativePattern [String] Negative pattern.
625	// 13: @negativePrefix [String] Negative prefix.
626	// 14: @negativeSuffix [String] Negative suffix.
627	// 15: @round [Function] Round function.
628	// 16: @infinitySymbol [String] Infinity symbol.
629	// 17: @nanSymbol [String] NaN symbol.
630	// 18: @symbolMap [Object] A bunch of other symbols.
631	// 19: @nuDigitsMap [Array] Digits map if numbering system is different than `latn`.
632	// 20: @compactMap [Object] Map of per-digit-count format patterns for specified compact mode.
633	return properties;
634};
635
636
637
638
639/**
640 * Generated by:
641 *
642 * var regenerate = require( "regenerate" );
643 * var formatSymbols = require( "@unicode/unicode-13.0.0/General_Category/Format/symbols" );
644 * regenerate().add( formatSymbols ).toString();
645 *
646 * https://github.com/mathiasbynens/regenerate
647 * https://github.com/node-unicode/unicode-13.0.0
648 */
649var regexpCfG = /[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD80D[\uDC30-\uDC38]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/g;
650
651
652
653
654/**
655 * Generated by:
656 *
657 * var regenerate = require( "regenerate" );
658 * var dashSymbols = require( "https://github.com/node-unicode/unicode-13.0.0/General_Category/Dash_Punctuation/symbols" );
659 * regenerate().add( dashSymbols ).toString();
660 *
661 * https://github.com/mathiasbynens/regenerate
662 * https://github.com/node-unicode/unicode-13.0.0
663 *
664 * NOTE: In addition to [:dash:],  the below includes MINUS SIGN U+2212.
665 */
666var regexpDashG = /[\x2D\u058A\u05BE\u1400\u1806\u2010-\u2015\u2E17\u2E1A\u2E3A\u2E3B\u2E40\u301C\u3030\u30A0\uFE31\uFE32\uFE58\uFE63\uFF0D\u2212]|\uD803\uDEAD/g;
667
668
669
670
671/**
672 * Generated by:
673 *
674 * var regenerate = require( "regenerate" );
675 * var spaceSeparatorSymbols = require( "@unicode/unicode-13.0.0/General_Category/Space_Separator/symbols" );
676 * regenerate().add( spaceSeparatorSymbols ).toString();
677 *
678 * https://github.com/mathiasbynens/regenerate
679 * https://github.com/node-unicode/unicode-13.0.0
680 */
681var regexpZsG = /[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
682
683
684
685
686/**
687 * Loose Matching:
688 * - Ignore all format characters, which includes RLM, LRM or ALM used to control BIDI
689 *   formatting.
690 * - Map all characters in [:Zs:] to U+0020 SPACE;
691 * - Map all characters in [:Dash:] to U+002D HYPHEN-MINUS;
692 */
693var looseMatching = function( value ) {
694	return value
695		.replace( regexpCfG, "" )
696		.replace( regexpDashG, "-" )
697		.replace( regexpZsG, " " );
698};
699
700
701
702
703/**
704 * parse( value, properties )
705 *
706 * @value [String].
707 *
708 * @properties [Object] Parser properties is a reduced pre-processed cldr
709 * data set returned by numberParserProperties().
710 *
711 * Return the parsed Number (including Infinity) or NaN when value is invalid.
712 * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
713 */
714var numberParse = function( value, properties ) {
715	var grammar, invertedNuDigitsMap, invertedSymbolMap, negative, number, prefix, prefixNSuffix,
716		suffix, tokenizer, valid;
717
718	// Grammar:
719	// - Value <=           NaN | PositiveNumber | NegativeNumber
720	// - PositiveNumber <=  PositivePrefix NumberOrInf PositiveSufix
721	// - NegativeNumber <=  NegativePrefix NumberOrInf
722	// - NumberOrInf <=     Number | Inf
723	grammar = [
724		[ "nan" ],
725		[ "prefix", "infinity", "suffix" ],
726		[ "prefix", "number", "suffix" ],
727		[ "negativePrefix", "infinity", "negativeSuffix" ],
728		[ "negativePrefix", "number", "negativeSuffix" ]
729	];
730
731	invertedSymbolMap = properties[ 0 ];
732	invertedNuDigitsMap = properties[ 1 ] || {};
733	tokenizer = properties[ 2 ];
734
735	value = looseMatching( value );
736
737	function parse( type ) {
738		return function( lexeme ) {
739
740			// Reverse localized symbols and numbering system.
741			lexeme = lexeme.split( "" ).map(function( character ) {
742				return invertedSymbolMap[ character ] ||
743					invertedNuDigitsMap[ character ] ||
744					character;
745			}).join( "" );
746
747			switch ( type ) {
748				case "infinity":
749					number = Infinity;
750					break;
751
752				case "nan":
753					number = NaN;
754					break;
755
756				case "number":
757
758					// Remove grouping separators.
759					lexeme = lexeme.replace( /,/g, "" );
760
761					number = +lexeme;
762					break;
763
764				case "prefix":
765				case "negativePrefix":
766					prefix = lexeme;
767					break;
768
769				case "suffix":
770					suffix = lexeme;
771					break;
772
773				case "negativeSuffix":
774					suffix = lexeme;
775					negative = true;
776					break;
777
778				// This should never be reached.
779				default:
780					throw new Error( "Internal error" );
781			}
782			return "";
783		};
784	}
785
786	function tokenizeNParse( _value, grammar ) {
787		return grammar.some(function( statement ) {
788			var value = _value;
789
790			// The whole grammar statement should be used (i.e., .every() return true) and value be
791			// entirely consumed (i.e., !value.length).
792			return statement.every(function( type ) {
793				if ( value.match( tokenizer[ type ] ) === null ) {
794					return false;
795				}
796
797				// Consume and parse it.
798				value = value.replace( tokenizer[ type ], parse( type ) );
799				return true;
800			}) && !value.length;
801		});
802	}
803
804	valid = tokenizeNParse( value, grammar );
805
806	// NaN
807	if ( !valid || isNaN( number ) ) {
808		return NaN;
809	}
810
811	prefixNSuffix = "" + prefix + suffix;
812
813	// Percent
814	if ( prefixNSuffix.indexOf( "%" ) !== -1 ) {
815		number /= 100;
816
817	// Per mille
818	} else if ( prefixNSuffix.indexOf( "\u2030" ) !== -1 ) {
819		number /= 1000;
820	}
821
822	// Negative number
823	if ( negative ) {
824		number *= -1;
825	}
826
827	return number;
828};
829
830
831
832
833var numberParserFn = function( properties ) {
834	return function numberParser( value ) {
835		validateParameterPresence( value, "value" );
836		validateParameterTypeString( value, "value" );
837
838		return numberParse( value, properties );
839	};
840
841};
842
843
844
845
846/**
847 * symbolMap( cldr )
848 *
849 * @cldr [Cldr instance].
850 *
851 * Return the (localized symbol, pattern symbol) key value pair, eg. {
852 *   "Ù«": ".",
853 *   "Ù¬": ",",
854 *   "Ùª": "%",
855 *   ...
856 * };
857 */
858var numberSymbolInvertedMap = function( cldr ) {
859	var symbol,
860		symbolMap = {};
861
862	for ( symbol in numberSymbolName ) {
863		symbolMap[ numberSymbol( numberSymbolName[ symbol ], cldr ) ] = symbol;
864	}
865
866	return symbolMap;
867};
868
869
870
871
872/**
873 * objectMap( object, fn)
874 *
875 * - object
876 *
877 * - fn( pair ) => pair
878 */
879var objectMap = function( object, fn ) {
880	return Object.keys( object ).map(function( key ) {
881		return fn([ key, object[ key ] ]);
882	}).reduce(function( object, pair ) {
883		object[ pair[ 0 ] ] = pair[ 1 ];
884		return object;
885	}, {});
886};
887
888
889
890
891/**
892 * removeLiteralQuotes( string )
893 *
894 * Return:
895 * - `'` if input string is `''`.
896 * - `o'clock` if input string is `'o''clock'`.
897 * - `foo` if input string is `foo`, i.e., return the same value in case it isn't a single-quoted
898 *   string.
899 */
900var removeLiteralQuotes = function( string ) {
901	if ( string[ 0 ] + string[ string.length - 1 ] !== "''" ) {
902		return string;
903	}
904	if ( string === "''" ) {
905		return "'";
906	}
907	return string.replace( /''/g, "'" ).slice( 1, -1 );
908};
909
910
911
912
913/**
914 * parseProperties( pattern, cldr )
915 *
916 * @pattern [String] raw pattern for numbers.
917 *
918 * @cldr [Cldr instance].
919 *
920 * Return parser properties, used to feed parser function.
921 *
922 * TODO:
923 * - Scientific_notation;
924 * - Padding;
925 */
926var numberParseProperties = function( pattern, cldr, options ) {
927	var aux, decimalSymbolRe, digitsRe, groupingSeparatorRe, infinitySymbol, invertedNuDigitsMap,
928		invertedSymbolMap, maximumFractionDigits, maximumSignificantDigits,
929		minimumSignificantDigits, nanSymbol, negativePrefix, negativeSuffix, nuDigitsMap,
930		numberTokenizer, prefix, primaryGroupingSize, secondaryGroupingSize, suffix, symbolMap,
931		formatProperties = numberFormatProperties( pattern, cldr, options );
932
933	prefix = looseMatching( formatProperties[ 0 ] );
934	maximumFractionDigits = formatProperties[ 4 ];
935	minimumSignificantDigits = formatProperties[ 5 ];
936	maximumSignificantDigits = formatProperties[ 6 ];
937	primaryGroupingSize = formatProperties[ 8 ];
938	secondaryGroupingSize = formatProperties[ 9 ];
939	suffix = looseMatching( formatProperties[ 10 ] );
940	negativePrefix = looseMatching( formatProperties[ 13 ] );
941	negativeSuffix = looseMatching( formatProperties[ 14 ] );
942	infinitySymbol = looseMatching( formatProperties[ 16 ] );
943	nanSymbol = looseMatching( formatProperties[ 17 ] );
944	symbolMap = objectMap( formatProperties[ 18 ], function( pair ) {
945		return [ pair[ 0 ], looseMatching( pair[ 1 ] ) ];
946	});
947	nuDigitsMap = formatProperties[ 19 ];
948
949	invertedSymbolMap = objectMap( numberSymbolInvertedMap( cldr ), function( pair ) {
950		return [ looseMatching( pair[ 0 ] ), pair[ 1 ] ];
951	});
952
953	digitsRe = nuDigitsMap ? "[" + nuDigitsMap + "]" : "\\d";
954	groupingSeparatorRe = regexpEscape( symbolMap[ "," ] );
955	decimalSymbolRe = regexpEscape( symbolMap[ "." ] );
956
957	if ( nuDigitsMap ) {
958		invertedNuDigitsMap = nuDigitsMap.split( "" ).reduce(function( object, localizedDigit, i ) {
959			object[ localizedDigit ] = String( i );
960			return object;
961		}, {} );
962	}
963
964	aux = [ prefix, suffix, negativePrefix, negativeSuffix ].map(function( value ) {
965		return value.replace( /('([^']|'')+'|'')|./g, function( character, literal ) {
966
967			// Literals
968			if ( literal ) {
969				return removeLiteralQuotes( literal );
970			}
971
972			// Symbols
973			character = character.replace( /[\-+E%\u2030]/, function( symbol ) {
974				return symbolMap[ symbol ];
975			});
976
977			return character;
978		});
979	});
980
981	prefix = aux[ 0 ];
982	suffix = aux[ 1 ];
983	negativePrefix = aux[ 2 ];
984	negativeSuffix = aux[ 3 ];
985
986	// Number
987	//
988	// number_re =                       integer fraction?
989	//
990	// integer =                         digits | digits_using_grouping_separators
991	//
992	// fraction =                        regexp((.\d+)?)
993	//
994	// digits =                          regexp(\d+)
995	//
996	// digits_w_grouping_separators =    digits_w_1_grouping_separators |
997	//                                   digits_w_2_grouping_separators
998	//
999	// digits_w_1_grouping_separators =  regexp(\d{1,3}(,\d{3})+)
1000	//
1001	// digits_w_2_grouping_separators =  regexp(\d{1,2}((,\d{2})*(,\d{3})))
1002
1003	// Integer part
1004	numberTokenizer = digitsRe + "+";
1005
1006	// Grouping separators
1007	if ( primaryGroupingSize ) {
1008		if ( secondaryGroupingSize ) {
1009			aux = digitsRe + "{1," + secondaryGroupingSize + "}((" + groupingSeparatorRe +
1010				digitsRe + "{" + secondaryGroupingSize + "})*(" + groupingSeparatorRe +
1011				digitsRe + "{" + primaryGroupingSize + "}))";
1012		} else {
1013			aux = digitsRe + "{1," + primaryGroupingSize + "}(" + groupingSeparatorRe +
1014				digitsRe + "{" + primaryGroupingSize + "})+";
1015		}
1016		numberTokenizer = "(" + aux + "|" + numberTokenizer + ")";
1017	}
1018
1019	// Fraction part? Only included if 1 or 2.
1020	// 1: Using significant digit format.
1021	// 2: Using integer and fractional format && it has a maximumFractionDigits.
1022	if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) || /* 1 */
1023				maximumFractionDigits /* 2 */ ) {
1024
1025		// 1: Handle trailing decimal separator, e.g., `"1." => `1``.
1026		aux = decimalSymbolRe + digitsRe + "+";
1027		numberTokenizer = numberTokenizer + "(" + aux + "|" + decimalSymbolRe /* 1 */ + ")?" +
1028
1029			// Handle non-padded decimals, e.g., `".12"` => `0.12` by making the integer part
1030			// optional.
1031			"|(" + numberTokenizer + ")?" + aux;
1032
1033		numberTokenizer = "(" + numberTokenizer + ")";
1034	}
1035
1036	// 0: @invertedSymbolMap [Object] Inverted symbol map.
1037	// 1: @invertedNuDigitsMap [Object] Inverted digits map if numbering system is different than
1038	//    `latn`.
1039	// 2: @tokenizer [Object] Tokenizer map, used by parser to consume input.
1040	return [
1041		invertedSymbolMap,
1042		invertedNuDigitsMap,
1043		{
1044			infinity: new RegExp( "^" + regexpEscape( infinitySymbol ) ),
1045			nan: new RegExp( "^" + regexpEscape( nanSymbol ) ),
1046			negativePrefix: new RegExp( "^" + regexpEscape( negativePrefix ) ),
1047			negativeSuffix: new RegExp( "^" + regexpEscape( negativeSuffix ) ),
1048			number: new RegExp( "^" + numberTokenizer ),
1049			prefix: new RegExp( "^" + regexpEscape( prefix ) ),
1050			suffix: new RegExp( "^" + regexpEscape( suffix ) )
1051		}
1052	];
1053
1054};
1055
1056
1057
1058
1059/**
1060 * Pattern( style )
1061 *
1062 * @style [String] "decimal" (default) or "percent".
1063 *
1064 * @cldr [Cldr instance].
1065 */
1066var numberPattern = function( style, cldr ) {
1067	if ( style !== "decimal" && style !== "percent" ) {
1068		throw new Error( "Invalid style" );
1069	}
1070
1071	return cldr.main([
1072		"numbers",
1073		style + "Formats-numberSystem-" + numberNumberingSystem( cldr ),
1074		"standard"
1075	]);
1076};
1077
1078
1079
1080
1081/**
1082 * EBNF representation:
1083 *
1084 * compact_pattern_re =       prefix?
1085 *                            number_pattern_re
1086 *                            suffix?
1087 *
1088 * number_pattern_re =        0+
1089 *
1090 * Regexp groups:
1091 *
1092 *  0: compact_pattern_re
1093 *  1: prefix
1094 *  2: number_pattern_re (the number pattern to use in compact mode)
1095 *  3: suffix
1096 */
1097var numberCompactPatternRe = ( /^([^0]*)(0+)([^0]*)$/ );
1098
1099
1100
1101
1102/**
1103 * goupingSeparator( number, primaryGroupingSize, secondaryGroupingSize )
1104 *
1105 * @number [Number].
1106 *
1107 * @primaryGroupingSize [Number]
1108 *
1109 * @secondaryGroupingSize [Number]
1110 *
1111 * Return the formatted number with group separator.
1112 */
1113var numberFormatGroupingSeparator = function( number, primaryGroupingSize, secondaryGroupingSize ) {
1114	var index,
1115		currentGroupingSize = primaryGroupingSize,
1116		ret = "",
1117		sep = ",",
1118		switchToSecondary = secondaryGroupingSize ? true : false;
1119
1120	number = String( number ).split( "." );
1121	index = number[ 0 ].length;
1122
1123	while ( index > currentGroupingSize ) {
1124		ret = number[ 0 ].slice( index - currentGroupingSize, index ) +
1125			( ret.length ? sep : "" ) + ret;
1126		index -= currentGroupingSize;
1127		if ( switchToSecondary ) {
1128			currentGroupingSize = secondaryGroupingSize;
1129			switchToSecondary = false;
1130		}
1131	}
1132
1133	number[ 0 ] = number[ 0 ].slice( 0, index ) + ( ret.length ? sep : "" ) + ret;
1134	return number.join( "." );
1135};
1136
1137
1138
1139
1140/**
1141 * integerFractionDigits( number, minimumIntegerDigits, minimumFractionDigits,
1142 * maximumFractionDigits, round, roundIncrement )
1143 *
1144 * @number [Number]
1145 *
1146 * @minimumIntegerDigits [Number]
1147 *
1148 * @minimumFractionDigits [Number]
1149 *
1150 * @maximumFractionDigits [Number]
1151 *
1152 * @round [Function]
1153 *
1154 * @roundIncrement [Function]
1155 *
1156 * Return the formatted integer and fraction digits.
1157 */
1158var numberFormatIntegerFractionDigits = function( number, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, round,
1159	roundIncrement ) {
1160
1161	// Fraction
1162	if ( maximumFractionDigits ) {
1163
1164		// Rounding
1165		if ( roundIncrement ) {
1166			number = round( number, roundIncrement );
1167
1168		// Maximum fraction digits
1169		} else {
1170			number = round( number, { exponent: -maximumFractionDigits } );
1171		}
1172
1173	} else {
1174		number = round( number );
1175	}
1176
1177	number = String( number );
1178
1179	// Maximum integer digits (post string phase)
1180	if ( maximumFractionDigits && /e-/.test( number ) ) {
1181
1182		// Use toFixed( maximumFractionDigits ) to make sure small numbers like 1e-7 are
1183		// displayed using plain digits instead of scientific notation.
1184		// 1: Remove leading decimal zeros.
1185		// 2: Remove leading decimal separator.
1186		// Note: String() is still preferred so it doesn't mess up with a number precision
1187		// unnecessarily, e.g., (123456789.123).toFixed(10) === "123456789.1229999959",
1188		// String(123456789.123) === "123456789.123".
1189		number = ( +number ).toFixed( maximumFractionDigits )
1190			.replace( /0+$/, "" ) /* 1 */
1191			.replace( /\.$/, "" ); /* 2 */
1192	}
1193
1194	// Minimum fraction digits (post string phase)
1195	if ( minimumFractionDigits ) {
1196		number = number.split( "." );
1197		number[ 1 ] = stringPad( number[ 1 ] || "", minimumFractionDigits, true );
1198		number = number.join( "." );
1199	}
1200
1201	// Minimum integer digits
1202	if ( minimumIntegerDigits ) {
1203		number = number.split( "." );
1204		number[ 0 ] = stringPad( number[ 0 ], minimumIntegerDigits );
1205		number = number.join( "." );
1206	}
1207
1208	return number;
1209};
1210
1211
1212
1213
1214/**
1215 * toPrecision( number, precision, round )
1216 *
1217 * @number (Number)
1218 *
1219 * @precision (Number) significant figures precision (not decimal precision).
1220 *
1221 * @round (Function)
1222 *
1223 * Return number.toPrecision( precision ) using the given round function.
1224 */
1225var numberToPrecision = function( number, precision, round ) {
1226	var roundOrder;
1227
1228	if ( number === 0 ) {  // Fix #706
1229		return number;
1230	}
1231
1232	roundOrder = Math.ceil( Math.log( Math.abs( number ) ) / Math.log( 10 ) );
1233	roundOrder -= precision;
1234
1235	return round( number, { exponent: roundOrder } );
1236};
1237
1238
1239
1240
1241/**
1242 * toPrecision( number, minimumSignificantDigits, maximumSignificantDigits, round )
1243 *
1244 * @number [Number]
1245 *
1246 * @minimumSignificantDigits [Number]
1247 *
1248 * @maximumSignificantDigits [Number]
1249 *
1250 * @round [Function]
1251 *
1252 * Return the formatted significant digits number.
1253 */
1254var numberFormatSignificantDigits = function( number, minimumSignificantDigits, maximumSignificantDigits, round ) {
1255	var atMinimum, atMaximum;
1256
1257	// Sanity check.
1258	if ( minimumSignificantDigits > maximumSignificantDigits ) {
1259		maximumSignificantDigits = minimumSignificantDigits;
1260	}
1261
1262	atMinimum = numberToPrecision( number, minimumSignificantDigits, round );
1263	atMaximum = numberToPrecision( number, maximumSignificantDigits, round );
1264
1265	// Use atMaximum only if it has more significant digits than atMinimum.
1266	number = +atMinimum === +atMaximum ? atMinimum : atMaximum;
1267
1268	// Expand integer numbers, eg. 123e5 to 12300.
1269	number = ( +number ).toString( 10 );
1270
1271	if ( ( /e/ ).test( number ) ) {
1272		throw createErrorUnsupportedFeature({
1273			feature: "integers out of (1e21, 1e-7)"
1274		});
1275	}
1276
1277	// Add trailing zeros if necessary.
1278	if ( minimumSignificantDigits - number.replace( /^0+|\./g, "" ).length > 0 ) {
1279		number = number.split( "." );
1280		number[ 1 ] = stringPad( number[ 1 ] || "", minimumSignificantDigits - number[ 0 ].replace( /^0+/, "" ).length, true );
1281		number = number.join( "." );
1282	}
1283
1284	return number;
1285};
1286
1287
1288
1289
1290/**
1291 * format( number, properties )
1292 *
1293 * @number [Number].
1294 *
1295 * @properties [Object] Output of number/format-properties.
1296 *
1297 * Return the formatted number.
1298 * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
1299 */
1300var numberFormat = function( number, properties, pluralGenerator ) {
1301	var aux, compactMap, infinitySymbol, maximumFractionDigits, maximumSignificantDigits,
1302		minimumFractionDigits, minimumIntegerDigits, minimumSignificantDigits, nanSymbol,
1303		nuDigitsMap, prefix, primaryGroupingSize, pattern, round, roundIncrement,
1304		secondaryGroupingSize, stringToParts, suffix, symbolMap;
1305
1306	minimumIntegerDigits = properties[ 2 ];
1307	minimumFractionDigits = properties[ 3 ];
1308	maximumFractionDigits = properties[ 4 ];
1309	minimumSignificantDigits = properties[ 5 ];
1310	maximumSignificantDigits = properties[ 6 ];
1311	roundIncrement = properties[ 7 ];
1312	primaryGroupingSize = properties[ 8 ];
1313	secondaryGroupingSize = properties[ 9 ];
1314	round = properties[ 15 ];
1315	infinitySymbol = properties[ 16 ];
1316	nanSymbol = properties[ 17 ];
1317	symbolMap = properties[ 18 ];
1318	nuDigitsMap = properties[ 19 ];
1319	compactMap = properties[ 20 ];
1320
1321	// NaN
1322	if ( isNaN( number ) ) {
1323		return [ { type: "nan", value: nanSymbol } ];
1324	}
1325
1326	if ( number < 0 ) {
1327		pattern = properties[ 12 ];
1328		prefix = properties[ 13 ];
1329		suffix = properties[ 14 ];
1330	} else {
1331		pattern = properties[ 11 ];
1332		prefix = properties[ 0 ];
1333		suffix = properties[ 10 ];
1334	}
1335
1336	// For prefix, suffix, and number parts.
1337	stringToParts = function( string ) {
1338		var numberType = "integer",
1339			parts = [];
1340
1341		// TODO Move the tokenization of all parts that don't depend on number into
1342		// format-properties.
1343		string.replace( /('([^']|'')+'|'')|./g, function( character, literal ) {
1344
1345			// Literals
1346			if ( literal ) {
1347				partsPush( parts, "literal", removeLiteralQuotes( literal ) );
1348				return;
1349			}
1350
1351			// Currency symbol
1352			if ( character === "\u00A4" ) {
1353				partsPush( parts, "currency", character );
1354				return;
1355			}
1356
1357			// Symbols
1358			character = character.replace( /[.,\-+E%\u2030]/, function( symbol ) {
1359				if ( symbol === "." ) {
1360					numberType = "fraction";
1361				}
1362				partsPush( parts, numberSymbolName[ symbol ], symbolMap[ symbol ] );
1363
1364				// "Erase" handled character.
1365				return "";
1366			});
1367
1368			// Number
1369			character = character.replace( /[0-9]/, function( digit ) {
1370
1371				// Numbering system
1372				if ( nuDigitsMap ) {
1373					digit = nuDigitsMap[ +digit ];
1374				}
1375				partsPush( parts, numberType, digit );
1376
1377				// "Erase" handled character.
1378				return "";
1379			});
1380
1381			// Etc
1382			character.replace( /./, function( etc ) {
1383				partsPush( parts, "literal", etc );
1384			});
1385		});
1386		return parts;
1387	};
1388
1389	prefix = stringToParts( prefix );
1390	suffix = stringToParts( suffix );
1391
1392	// Infinity
1393	if ( !isFinite( number ) ) {
1394		return prefix.concat(
1395			{ type: "infinity", value: infinitySymbol },
1396			suffix
1397		);
1398	}
1399
1400	// Percent
1401	if ( pattern.indexOf( "%" ) !== -1 ) {
1402		number *= 100;
1403
1404	// Per mille
1405	} else if ( pattern.indexOf( "\u2030" ) !== -1 ) {
1406		number *= 1000;
1407	}
1408
1409	var compactPattern, compactDigits, compactProperties, divisor, numberExponent, pluralForm;
1410
1411	// Compact mode: initial number digit processing
1412	if ( compactMap ) {
1413		numberExponent = Math.abs( Math.floor( number ) ).toString().length - 1;
1414		numberExponent = Math.min( numberExponent, compactMap.maxExponent );
1415
1416		// Use default plural form to perform initial decimal shift
1417		if ( numberExponent >= 3 ) {
1418			compactPattern = compactMap[ numberExponent ] && compactMap[ numberExponent ].other;
1419		}
1420
1421		if ( compactPattern === "0" ) {
1422			compactPattern = null;
1423		} else if ( compactPattern ) {
1424			compactDigits = compactPattern.split( "0" ).length - 1;
1425			divisor = numberExponent - ( compactDigits - 1 );
1426			number = number / Math.pow( 10, divisor );
1427		}
1428	}
1429
1430	// Significant digit format
1431	if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
1432		number = numberFormatSignificantDigits( number, minimumSignificantDigits,
1433			maximumSignificantDigits, round );
1434
1435	// Integer and fractional format
1436	} else {
1437		number = numberFormatIntegerFractionDigits( number, minimumIntegerDigits,
1438			minimumFractionDigits, maximumFractionDigits, round, roundIncrement );
1439	}
1440
1441	// Compact mode: apply formatting
1442	if ( compactMap && compactPattern ) {
1443
1444		// Get plural form after possible roundings
1445		pluralForm = pluralGenerator ? pluralGenerator( +number ) : "other";
1446
1447		compactPattern = compactMap[ numberExponent ][ pluralForm ] || compactPattern;
1448		compactProperties = compactPattern.match( numberCompactPatternRe );
1449
1450		// TODO Move the tokenization of all parts that don't depend on number into
1451		// format-properties.
1452		aux = function( string ) {
1453			var parts = [];
1454			string.replace( /(
1454\s+)|([^\s0]+)/g, function( _garbage, space, compact ) {
1455
1456				// Literals
1457				if ( space ) {
1458					partsPush( parts, "literal", space
vendor: 7,118 bytes, lines 1458-1727
1458 );
1459					return;
1460				}
1461
1462				// Compact value
1463				if ( compact ) {
1464					partsPush( parts, "compact", compact );
1465					return;
1466				}
1467			});
1468			return parts;
1469		};
1470
1471		// update prefix/suffix with compact prefix/suffix
1472		prefix = prefix.concat( aux( compactProperties[ 1 ] ) );
1473		suffix = aux( compactProperties[ 3 ] ).concat( suffix );
1474	}
1475
1476	// Remove the possible number minus sign
1477	number = number.replace( /^-/, "" );
1478
1479	// Grouping separators
1480	if ( primaryGroupingSize ) {
1481		number = numberFormatGroupingSeparator( number, primaryGroupingSize,
1482			secondaryGroupingSize );
1483	}
1484
1485	// Scientific notation
1486	// TODO implement here
1487
1488	// Padding/'([^']|'')+'|''|[.,\-+E%\u2030]/g
1489	// TODO implement here
1490
1491	return prefix.concat(
1492		stringToParts( number ),
1493		suffix
1494	);
1495};
1496
1497
1498
1499
1500var numberToPartsFormatterFn = function( properties, pluralGenerator ) {
1501	return function numberToPartsFormatter( value ) {
1502		validateParameterPresence( value, "value" );
1503		validateParameterTypeNumber( value, "value" );
1504
1505		return numberFormat( value, properties, pluralGenerator );
1506	};
1507};
1508
1509
1510
1511
1512function validateDigits( properties ) {
1513	var minimumIntegerDigits = properties[ 2 ],
1514		minimumFractionDigits = properties[ 3 ],
1515		maximumFractionDigits = properties[ 4 ],
1516		minimumSignificantDigits = properties[ 5 ],
1517		maximumSignificantDigits = properties[ 6 ];
1518
1519	// Validate significant digit format properties
1520	if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
1521		validateParameterRange( minimumSignificantDigits, "minimumSignificantDigits", 1, 21 );
1522		validateParameterRange( maximumSignificantDigits, "maximumSignificantDigits",
1523			minimumSignificantDigits, 21 );
1524
1525	} else if ( !isNaN( minimumSignificantDigits ) || !isNaN( maximumSignificantDigits ) ) {
1526		throw new Error( "Neither or both the minimum and maximum significant digits must be " +
1527			"present" );
1528
1529	// Validate integer and fractional format
1530	} else {
1531		validateParameterRange( minimumIntegerDigits, "minimumIntegerDigits", 1, 21 );
1532		validateParameterRange( minimumFractionDigits, "minimumFractionDigits", 0, 20 );
1533		validateParameterRange( maximumFractionDigits, "maximumFractionDigits",
1534			minimumFractionDigits, 20 );
1535	}
1536}
1537
1538/**
1539 * .numberFormatter( [options] )
1540 *
1541 * @options [Object]:
1542 * - style: [String] "decimal" (default) or "percent".
1543 * - see also number/format options.
1544 *
1545 * Return a function that formats a number according to the given options and default/instance
1546 * locale.
1547 */
1548Globalize.numberFormatter =
1549Globalize.prototype.numberFormatter = function( options ) {
1550	var args, numberToPartsFormatter, returnFn;
1551
1552	validateParameterTypePlainObject( options, "options" );
1553
1554	options = options || {};
1555	args = [ options ];
1556
1557	numberToPartsFormatter = this.numberToPartsFormatter( options );
1558	returnFn = numberFormatterFn( numberToPartsFormatter );
1559	runtimeBind( args, this.cldr, returnFn, [ numberToPartsFormatter ] );
1560
1561	return returnFn;
1562};
1563
1564/**
1565 * .numberToPartsFormatter( [options] )
1566 *
1567 * @options [Object]:
1568 * - style: [String] "symbol" (default), "accounting", "code" or "name".
1569 * - see also number/format options.
1570 *
1571 * Return a function that formats a number to parts according to the given options and
1572 * default/instance locale.
1573 */
1574Globalize.numberToPartsFormatter =
1575Globalize.prototype.numberToPartsFormatter = function( options ) {
1576	var args, cldr, fnArgs, pattern, properties, returnFn;
1577
1578	validateParameterTypePlainObject( options, "options" );
1579
1580	options = options || {};
1581	cldr = this.cldr;
1582
1583	args = [ options ];
1584
1585	validateDefaultLocale( cldr );
1586
1587	cldr.on( "get", validateCldr );
1588	try {
1589		if ( options.raw ) {
1590			pattern = options.raw;
1591		} else {
1592			pattern = numberPattern( options.style || "decimal", cldr );
1593		}
1594
1595		properties = numberFormatProperties( pattern, cldr, options );
1596		fnArgs = [ properties ];
1597	} finally {
1598		cldr.off( "get", validateCldr );
1599	}
1600
1601	validateDigits( properties );
1602
1603	if ( options.compact ) {
1604		fnArgs.push( this.pluralGenerator() );
1605	}
1606	returnFn = numberToPartsFormatterFn.apply( null, fnArgs );
1607	runtimeBind( args, cldr, returnFn, fnArgs );
1608
1609	return returnFn;
1610};
1611
1612/**
1613 * .numberParser( [options] )
1614 *
1615 * @options [Object]:
1616 * - style: [String] "decimal" (default) or "percent".
1617 *
1618 * Return the number parser according to the default/instance locale.
1619 */
1620Globalize.numberParser =
1621Globalize.prototype.numberParser = function( options ) {
1622	var args, cldr, pattern, properties, returnFn;
1623
1624	validateParameterTypePlainObject( options, "options" );
1625
1626	options = options || {};
1627	cldr = this.cldr;
1628
1629	args = [ options ];
1630
1631	validateDefaultLocale( cldr );
1632	if ( options.compact ) {
1633		throw createErrorUnsupportedFeature({
1634			feature: "compact number parsing (not implemented)"
1635		});
1636	}
1637
1638	cldr.on( "get", validateCldr );
1639
1640	if ( options.raw ) {
1641		pattern = options.raw;
1642	} else {
1643		pattern = numberPattern( options.style || "decimal", cldr );
1644	}
1645
1646	properties = numberParseProperties( pattern, cldr, options );
1647
1648	cldr.off( "get", validateCldr );
1649
1650	returnFn = numberParserFn( properties );
1651
1652	runtimeBind( args, cldr, returnFn, [ properties ] );
1653
1654	return returnFn;
1655};
1656
1657/**
1658 * .formatNumber( value [, options] )
1659 *
1660 * @value [Number] number to be formatted.
1661 *
1662 * @options [Object]: see number/format-properties.
1663 *
1664 * Format a number according to the given options and default/instance locale.
1665 */
1666Globalize.formatNumber =
1667Globalize.prototype.formatNumber = function( value, options ) {
1668	validateParameterPresence( value, "value" );
1669	validateParameterTypeNumber( value, "value" );
1670
1671	return this.numberFormatter( options )( value );
1672};
1673
1674/**
1675 * .formatNumberToParts( value [, options] )
1676 *
1677 * @value [Number] number to be formatted.
1678 *
1679 * @options [Object]: see number/format-properties.
1680 *
1681 * Format a number to pars according to the given options and default/instance locale.
1682 */
1683Globalize.formatNumberToParts =
1684Globalize.prototype.formatNumberToParts = function( value, options ) {
1685	validateParameterPresence( value, "value" );
1686	validateParameterTypeNumber( value, "value" );
1687
1688	return this.numberToPartsFormatter( options )( value );
1689};
1690
1691/**
1692 * .parseNumber( value [, options] )
1693 *
1694 * @value [String]
1695 *
1696 * @options [Object]: See numberParser().
1697 *
1698 * Return the parsed Number (including Infinity) or NaN when value is invalid.
1699 */
1700Globalize.parseNumber =
1701Globalize.prototype.parseNumber = function( value, options ) {
1702	validateParameterPresence( value, "value" );
1703	validateParameterTypeString( value, "value" );
1704
1705	return this.numberParser( options )( value );
1706};
1707
1708/**
1709 * Optimization to avoid duplicating some internal functions across modules.
1710 */
1711Globalize._createErrorUnsupportedFeature = createErrorUnsupportedFeature;
1712Globalize._numberNumberingSystem = numberNumberingSystem;
1713Globalize._numberNumberingSystemDigitsMap = numberNumberingSystemDigitsMap;
1714Globalize._numberPattern = numberPattern;
1715Globalize._numberSymbol = numberSymbol;
1716Globalize._looseMatching = looseMatching;
1717Globalize._removeLiteralQuotes = removeLiteralQuotes;
1718Globalize._stringPad = stringPad;
1719Globalize._validateParameterTypeNumber = validateParameterTypeNumber;
1720Globalize._validateParameterTypeString = validateParameterTypeString;
1721
1722return Globalize;
1723
1724
1725
1726
1727}));

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.