text: define([
  	"dojo/_base/declare", // declare
  	"dojo/_base/lang", // lang.hitch lang.mixin
  	"dojo/number", // number._realNumberRegexp number.format number.parse number.regexp
  	"./RangeBoundTextBox"
  ], function(declare, lang, number, RangeBoundTextBox){
  
  	// module:
  	//		dijit/form/NumberTextBox
  
  
  	var NumberTextBoxMixin = declare("dijit.form.NumberTextBoxMixin", null, {
  		// summary:
  		//		A mixin for all number textboxes
  		// tags:
  		//		protected
  
  		// Override ValidationTextBox.pattern.... we use a reg-ex generating function rather
  		// than a straight regexp to deal with locale (plus formatting options too?)
  		pattern: function(constraints){
  			// if focused, accept either currency data or NumberTextBox format
  			return '(' + (this.focused && this.editOptions ? this._regExpGenerator(lang.delegate(constraints, this.editOptions)) + '|' : '')
  				+ this._regExpGenerator(constraints) + ')';
  		},
  
  		/*=====
  		// constraints: NumberTextBox.__Constraints
  		//		Despite the name, this parameter specifies both constraints on the input
  		//		(including minimum/maximum allowed values) as well as
  		//		formatting options like places (the number of digits to display after
  		//		the decimal point).
  		constraints: {},
  		======*/
  
  		// value: Number
  		//		The value of this NumberTextBox as a Javascript Number (i.e., not a String).
  		//		If the displayed value is blank, the value is NaN, and if the user types in
  		//		an gibberish value (like "hello world"), the value is undefined
  		//		(i.e. get('value') returns undefined).
  		//
  		//		Symmetrically, set('value', NaN) will clear the displayed value,
  		//		whereas set('value', undefined) will have no effect.
  		value: NaN,
  
  		// editOptions: [protected] Object
  		//		Properties to mix into constraints when the value is being edited.
  		//		This is here because we edit the number in the format "12345", which is
  		//		different than the display value (ex: "12,345")
  		editOptions: { pattern: '#.######' },
  
  		/*=====
  		_formatter: function(value, options){
  			// summary:
  			//		_formatter() is called by format().  It's the base routine for formatting a number,
  			//		as a string, for example converting 12345 into "12,345".
  			// value: Number
  			//		The number to be converted into a string.
  			// options: number.__FormatOptions?
  			//		Formatting options
  			// tags:
  			//		protected extension
  
  			return "12345";		// String
  		},
  		 =====*/
  		_formatter: number.format,
  
  		/*=====
  		_regExpGenerator: function(constraints){
  			// summary:
  			//		Generate a localized regular expression as a string, according to constraints.
  			// constraints: number.__ParseOptions
  			//		Formatting options
  			// tags:
  			//		protected
  
  			return "(\d*).(\d*)";	// string
  		},
  		=====*/
  		_regExpGenerator: number.regexp,
  
  		postMixInProperties: function(){
  			this.inherited(arguments);
  			this._set("type", "text"); // in case type="number" was specified which messes up parse/format
  		},
  
  		_setConstraintsAttr: function(/*Object*/ constraints){
  			var places = typeof constraints.places == "number"? constraints.places : 0;
  			if(places){ places++; } // decimal rounding errors take away another digit of precision
  			if(typeof constraints.max != "number"){
  				constraints.max = 9 * Math.pow(10, 15-places);
  			}
  			if(typeof constraints.min != "number"){
  				constraints.min = -9 * Math.pow(10, 15-places);
  			}
  			this.inherited(arguments, [ constraints ]);
  			if(this.focusNode && this.focusNode.value && !isNaN(this.value)){
  				this.set('value', this.value);
  			}
  		},
  
  		_onFocus: function(){
  			if(this.disabled || this.readOnly){ return; }
  			var val = this.get('value');
  			if(typeof val == "number" && !isNaN(val)){
  				var formattedValue = this.format(val, this.constraints);
  				if(formattedValue !== undefined){
  					this.textbox.value = formattedValue;
  				}
  			}
  			this.inherited(arguments);
  		},
  
  		format: function(/*Number*/ value, /*number.__FormatOptions*/ constraints){
  			// summary:
  			//		Formats the value as a Number, according to constraints.
  			// tags:
  			//		protected
  
  			var formattedValue = String(value);
  			if(typeof value != "number"){ return formattedValue; }
  			if(isNaN(value)){ return ""; }
  			// check for exponential notation that dojo/number.format() chokes on
  			if(!("rangeCheck" in this && this.rangeCheck(value, constraints)) && constraints.exponent !== false && /\de[-+]?\d/i.test(formattedValue)){
  				return formattedValue;
  			}
  			//AR added disabled and readOnly to condition
  			if(this.editOptions && this.focused && !this.readOnly && !this.disabled){
  				constraints = lang.mixin({}, constraints, this.editOptions);
  			}
  			return this._formatter(value, constraints);
  		},
  
  		/*=====
  		_parser: function(value, constraints){
  			// summary:
  			//		Parses the string value as a Number, according to constraints.
  			// value: String
  			//		String representing a number
  			// constraints: number.__ParseOptions
  			//		Formatting options
  			// tags:
  			//		protected
  
  			return 123.45;		// Number
  		},
  		=====*/
  		_parser: number.parse,
  
  		parse: function(/*String*/ value, /*number.__FormatOptions*/ constraints){
  			// summary:
  			//		Replaceable function to convert a formatted string to a number value
  			// tags:
  			//		protected extension
  
  			var v = this._parser(value, lang.mixin({}, constraints, (this.editOptions && this.focused) ? this.editOptions : {}));
  			if(this.editOptions && this.focused && isNaN(v)){
  				v = this._parser(value, constraints); // parse w/o editOptions: not technically needed but is nice for the user
  			}
  			return v;
  		},
  
  		_getDisplayedValueAttr: function(){
  			var v = this.inherited(arguments);
  			return isNaN(v) ? this.textbox.value : v;
  		},
  
  		filter: function(/*Number*/ value){
  			// summary:
  			//		This is called with both the display value (string), and the actual value (a number).
  			//		When called with the actual value it does corrections so that '' etc. are represented as NaN.
  			//		Otherwise it dispatches to the superclass's filter() method.
  			//
  			//		See `dijit/form/TextBox.filter()` for more details.
  			return (value == null /* or undefined */ || value === '') ? NaN : this.inherited(arguments); // set('value', null||''||undefined) should fire onChange(NaN)
  		},
  
  		serialize: function(/*Number*/ value, /*Object?*/ options){
  			// summary:
  			//		Convert value (a Number) into a canonical string (ie, how the number literal is written in javascript/java/C/etc.)
  			// tags:
  			//		protected
  			return (typeof value != "number" || isNaN(value)) ? '' : this.inherited(arguments);
  		},
  
  		_setBlurValue: function(){
  			var val = lang.hitch(lang.delegate(this, { focused: true }), "get")('value'); // parse with editOptions
  			this._setValueAttr(val, true);
  		},
  
  		_setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
  			// summary:
  			//		Hook so set('value', ...) works.
  			if(value !== undefined && formattedValue === undefined){
  				formattedValue = String(value);
  				if(typeof value == "number"){
  					if(isNaN(value)){ formattedValue = ''; }
  					// check for exponential notation that number.format chokes on
  					else if(("rangeCheck" in this && this.rangeCheck(value, this.constraints)) || this.constraints.exponent === false || !/\de[-+]?\d/i.test(formattedValue)){
  						formattedValue = undefined; // lets format compute a real string value
  					}
  				}else if(!value){ // 0 processed in if branch above, ''|null|undefined flows through here
  					formattedValue = '';
  					value = NaN;
  				}else{ // non-numeric values
  					value = undefined;
  				}
  			}
  			this.inherited(arguments, [value, priorityChange, formattedValue]);
  		},
  
  		_getValueAttr: function(){
  			// summary:
  			//		Hook so get('value') works.
  			//		Returns Number, NaN for '', or undefined for unparseable text
  			var v = this.inherited(arguments); // returns Number for all values accepted by parse() or NaN for all other displayed values
  
  			// If the displayed value of the textbox is gibberish (ex: "hello world"), this.inherited() above
  			// returns NaN; this if() branch converts the return value to undefined.
  			// Returning undefined prevents user text from being overwritten when doing _setValueAttr(_getValueAttr()).
  			// A blank displayed value is still returned as NaN.
  			if(isNaN(v) && this.textbox.value !== ''){
  				if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value) && (new RegExp("^"+number._realNumberRegexp(lang.delegate(this.constraints))+"$").test(this.textbox.value))){	// check for exponential notation that parse() rejected (erroneously?)
  					var n = Number(this.textbox.value);
  					return isNaN(n) ? undefined : n; // return exponential Number or undefined for random text (may not be possible to do with the above RegExp check)
  				}else{
  					return undefined; // gibberish
  				}
  			}else{
  				return v; // Number or NaN for ''
  			}
  		},
  
  		isValid: function(/*Boolean*/ isFocused){
  			// Overrides dijit/form/RangeBoundTextBox.isValid() to check that the editing-mode value is valid since
  			// it may not be formatted according to the regExp validation rules
  			if(!this.focused || this._isEmpty(this.textbox.value)){
  				return this.inherited(arguments);
  			}else{
  				var v = this.get('value');
  				if(!isNaN(v) && this.rangeCheck(v, this.constraints)){
  					if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value)){ // exponential, parse doesn't like it
  						return true; // valid exponential number in range
  					}else{
  						return this.inherited(arguments);
  					}
  				}else{
  					return false;
  				}
  			}
  		}
  	});
  
  	var NumberTextBox = declare("dijit.form.NumberTextBox", [RangeBoundTextBox, NumberTextBoxMixin], {
  		// summary:
  		//		A TextBox for entering numbers, with formatting and range checking
  		// description:
  		//		NumberTextBox is a textbox for entering and displaying numbers, supporting
  		//		the following main features:
  		//
  		//		1. Enforce minimum/maximum allowed values (as well as enforcing that the user types
  		//			a number rather than a random string)
  		//		2. NLS support (altering roles of comma and dot as "thousands-separator" and "decimal-point"
  		//			depending on locale).
  		//		3. Separate modes for editing the value and displaying it, specifically that
  		//			the thousands separator character (typically comma) disappears when editing
  		//			but reappears after the field is blurred.
  		//		4. Formatting and constraints regarding the number of places (digits after the decimal point)
  		//			allowed on input, and number of places displayed when blurred (see `constraints` parameter).
  
  		baseClass: "dijitTextBox dijitNumberTextBox"
  	});
  
  	NumberTextBox.Mixin = NumberTextBoxMixin;	// for monkey patching
  
  	/*=====
  	 NumberTextBox.__Constraints = declare([RangeBoundTextBox.__Constraints, number.__FormatOptions, number.__ParseOptions], {
  		 // summary:
  		 //		Specifies both the rules on valid/invalid values (minimum, maximum,
  		 //		number of required decimal places), and also formatting options for
  		 //		displaying the value when the field is not focused.
  		 // example:
  		 //		Minimum/maximum:
  		 //		To specify a field between 0 and 120:
  		 //	|		{min:0,max:120}
  		 //		To specify a field that must be an integer:
  		 //	|		{fractional:false}
  		 //		To specify a field where 0 to 3 decimal places are allowed on input:
  		 //	|		{places:'0,3'}
  	 });
  	 =====*/
  
  	return NumberTextBox;
  });
  