text: /**
   * jQuery number plug-in 2.1.5
   * Copyright 2012, Digital Fusion
   * Licensed under the MIT license.
   * http://opensource.teamdf.com/license/
   *
   * A jQuery plugin which implements a permutation of phpjs.org's number_format to provide
   * simple number formatting, insertion, and as-you-type masking of a number.
   *
   * @author	Sam Sehnert
   * @docs	http://www.teamdf.com/web/jquery-number-format-redux/196/
   */
  (function($){
  
  	"use strict";
  
  	/**
  	 * Method for selecting a range of characters in an input/textarea.
  	 *
  	 * @param int rangeStart			: Where we want the selection to start.
  	 * @param int rangeEnd				: Where we want the selection to end.
  	 *
  	 * @return void;
  	 */
  	function setSelectionRange( rangeStart, rangeEnd )
  	{
  		// Check which way we need to define the text range.
  		if( this.createTextRange )
  		{
  			var range = this.createTextRange();
  				range.collapse( true );
  				range.moveStart( 'character',	rangeStart );
  				range.moveEnd( 'character',		rangeEnd-rangeStart );
  				range.select();
  		}
  
  		// Alternate setSelectionRange method for supporting browsers.
  		else if( this.setSelectionRange )
  		{
  			this.focus();
  			this.setSelectionRange( rangeStart, rangeEnd );
  		}
  	}
  
  	/**
  	 * Get the selection position for the given part.
  	 *
  	 * @param string part			: Options, 'Start' or 'End'. The selection position to get.
  	 *
  	 * @return int : The index position of the selection part.
  	 */
  	function getSelection( part )
  	{
  		var pos	= this.value.length;
  
  		// Work out the selection part.
  		part = ( part.toLowerCase() == 'start' ? 'Start' : 'End' );
  
  		if( document.selection ){
  			// The current selection
  			var range = document.selection.createRange(), stored_range, selectionStart, selectionEnd;
  			// We'll use this as a 'dummy'
  			stored_range = range.duplicate();
  			// Select all text
  			//stored_range.moveToElementText( this );
  			stored_range.expand('textedit');
  			// Now move 'dummy' end point to end point of original range
  			stored_range.setEndPoint( 'EndToEnd', range );
  			// Now we can calculate start and end points
  			selectionStart = stored_range.text.length - range.text.length;
  			selectionEnd = selectionStart + range.text.length;
  			return part == 'Start' ? selectionStart : selectionEnd;
  		}
  
  		else if(typeof(this['selection'+part])!="undefined")
  		{
  			pos = this['selection'+part];
  		}
  		return pos;
  	}
  
  	/**
  	 * Substitutions for keydown keycodes.
  	 * Allows conversion from e.which to ascii characters.
  	 */
  	var _keydown = {
  		codes : {
  			46 : 127,
  			188 : 44,
  			109 : 45,
  			190 : 46,
  			191 : 47,
  			192 : 96,
  			220 : 92,
  			222 : 39,
  			221 : 93,
  			219 : 91,
  			173 : 45,
  			187 : 61, //IE Key codes
  			186 : 59, //IE Key codes
  			189 : 45, //IE Key codes
  			110 : 46  //IE Key codes
  		},
  		shifts : {
  			96 : "~",
  			49 : "!",
  			50 : "@",
  			51 : "#",
  			52 : "$",
  			53 : "%",
  			54 : "^",
  			55 : "&",
  			56 : "*",
  			57 : "(",
  			48 : ")",
  			45 : "_",
  			61 : "+",
  			91 : "{",
  			93 : "}",
  			92 : "|",
  			59 : ":",
  			39 : "\"",
  			44 : "<",
  			46 : ">",
  			47 : "?"
  		}
  	};
  
  	/**
  	 * jQuery number formatter plugin. This will allow you to format numbers on an element.
  	 *
  	 * @params proxied for format_number method.
  	 *
  	 * @return : The jQuery collection the method was called with.
  	 */
  	$.fn.number = function( number, decimals, dec_point, thousands_sep ){
  
  		// Enter the default thousands separator, and the decimal placeholder.
  		thousands_sep	= (typeof thousands_sep === 'undefined') ? ',' : thousands_sep;
  		dec_point		= (typeof dec_point === 'undefined') ? '.' : dec_point;
  		decimals		= (typeof decimals === 'undefined' ) ? 0 : decimals;
  
  		// Work out the unicode character for the decimal placeholder.
  		var u_dec			= ('\\u'+('0000'+(dec_point.charCodeAt(0).toString(16))).slice(-4)),
  			regex_dec_num	= new RegExp('[^'+u_dec+'0-9]','g'),
  			regex_dec		= new RegExp(u_dec,'g');
  
  		// If we've specified to take the number from the target element,
  		// we loop over the collection, and get the number.
  		if( number === true )
  		{
  			// If this element is a number, then we add a keyup
  			if( this.is('input:text') )
  			{
  				// Return the jquery collection.
  				return this.on({
  
  					/**
  					 * Handles keyup events, re-formatting numbers.
  					 *
  					 * Uses 'data' object to keep track of important information.
  					 *
  					 * data.c
  					 * This variable keeps track of where the caret *should* be. It works out the position as
  					 * the number of characters from the end of the string. E.g., '1^,234.56' where ^ denotes the caret,
  					 * would be index -7 (e.g., 7 characters from the end of the string). At the end of both the key down
  					 * and key up events, we'll re-position the caret to wherever data.c tells us the cursor should be.
  					 * This gives us a mechanism for incrementing the cursor position when we come across decimals, commas
  					 * etc. This figure typically doesn't increment for each keypress when to the left of the decimal,
  					 * but does when to the right of the decimal.
  					 *
  					 * @param object e			: the keyup event object.s
  					 *
  					 * @return void;
  					 */
  					'keydown.format' : function(e){
  
  						// Define variables used in the code below.
  						var $this	= $(this),
  							data	= $this.data('numFormat'),
  							code	= (e.keyCode ? e.keyCode : e.which),
  							chara	= '', //unescape(e.originalEvent.keyIdentifier.replace('U+','%u')),
  							start	= getSelection.apply(this,['start']),
  							end		= getSelection.apply(this,['end']),
  							val		= '',
  							setPos	= false;
  
  						// Webkit (Chrome & Safari) on windows screws up the keyIdentifier detection
  						// for numpad characters. I've disabled this for now, because while keyCode munging
  						// below is hackish and ugly, it actually works cross browser & platform.
  
  //						if( typeof e.originalEvent.keyIdentifier !== 'undefined' )
  //						{
  //							chara = unescape(e.originalEvent.keyIdentifier.replace('U+','%u'));
  //						}
  //						else
  //						{
  							if (_keydown.codes.hasOwnProperty(code)) {
  								code = _keydown.codes[code];
  							}
  							if (!e.shiftKey && (code >= 65 && code <= 90)){
  								code += 32;
  							} else if (!e.shiftKey && (code >= 69 && code <= 105)){
  								code -= 48;
  							} else if (e.shiftKey && _keydown.shifts.hasOwnProperty(code)){
  								//get shifted keyCode value
  								chara = _keydown.shifts[code];
  							}
  
  							if( chara == '' ) chara = String.fromCharCode(code);
  //						}
  
  
  
  
  						// Stop executing if the user didn't type a number key, a decimal character, backspace, or delete.
  						if( code != 8 && code != 45 && code != 127 && chara != dec_point && !chara.match(/[0-9]/) )
  						{
  							// We need the original keycode now...
  							var key = (e.keyCode ? e.keyCode : e.which);
  							if( // Allow control keys to go through... (delete, backspace, tab, enter, escape etc)
  								key == 46 || key == 8 || key == 127 || key == 9 || key == 27 || key == 13 ||
  								// Allow: Ctrl+A, Ctrl+R, Ctrl+P, Ctrl+S, Ctrl+F, Ctrl+H, Ctrl+B, Ctrl+J, Ctrl+T, Ctrl+Z, Ctrl++, Ctrl+-, Ctrl+0
  								( (key == 65 || key == 82 || key == 80 || key == 83 || key == 70 || key == 72 || key == 66 || key == 74 || key == 84 || key == 90|| key == 61 || key == 173 || key == 48) && ( e.ctrlKey || e.metaKey ) === true ) ||
  								// Allow: Ctrl+V, Ctrl+C, Ctrl+X
  								( (key == 86 || key == 67 || key == 88) && ( e.ctrlKey || e.metaKey ) === true ) ||
  								// Allow: home, end, left, right
  								( (key >= 35 && key <= 39) ) ||
  								// Allow: F1-F12
  								( (key >= 112 && key <= 123) )
  							){
  								return;
  							}
  							// But prevent all other keys.
  							e.preventDefault();
  							return false;
  						}
  
  						// The whole lot has been selected, or if the field is empty...
  						if( start == 0 && end == this.value.length ) //|| $this.val() == 0 )
  						{
  							if( code == 8 )		// Backspace
  							{
  								// Blank out the field, but only if the data object has already been instantiated.
  								start = end = 1;
  								this.value = '';
  
  								// Reset the cursor position.
  								data.init = (decimals>0?-1:0);
  								data.c = (decimals>0?-(decimals+1):0);
  								setSelectionRange.apply(this, [0,0]);
  							}
  							else if( chara == dec_point )
  							{
  								start = end = 1;
  								this.value = '0'+ dec_point + (new Array(decimals+1).join('0'));
  
  								// Reset the cursor position.
  								data.init = (decimals>0?1:0);
  								data.c = (decimals>0?-(decimals+1):0);
  							}
  							else if( code == 45 )	// Negative sign
  							{
  								start = end = 2;
  								this.value = '-0'+dec_point + (new Array(decimals+1).join('0'));
  
  								// Reset the cursor position.
  								data.init = (decimals>0?1:0);
  								data.c = (decimals>0?-(decimals+1):0);
  
  								setSelectionRange.apply(this, [2,2]);
  							}
  							else
  							{
  								// Reset the cursor position.
  								data.init = (decimals>0?-1:0);
  								data.c = (decimals>0?-(decimals):0);
  							}
  						}
  
  						// Otherwise, we need to reset the caret position
  						// based on the users selection.
  						else
  						{
  							data.c = end-this.value.length;
  						}
  
  						// Track if partial selection was used
  						data.isPartialSelection = start == end ? false : true;
  
  						// If the start position is before the decimal point,
  						// and the user has typed a decimal point, we need to move the caret
  						// past the decimal place.
  						if( decimals > 0 && chara == dec_point && start == this.value.length-decimals-1 )
  						{
  							data.c++;
  							data.init = Math.max(0,data.init);
  							e.preventDefault();
  
  							// Set the selection position.
  							setPos = this.value.length+data.c;
  						}
  
  						// Ignore negative sign unless at beginning of number (and it's not already present)
  						else if( code == 45 && (start != 0 || this.value.indexOf('-') == 0) )
  						{
  							e.preventDefault();
  						}
  
  						// If the user is just typing the decimal place,
  						// we simply ignore it.
  						else if( chara == dec_point )
  						{
  							data.init = Math.max(0,data.init);
  							e.preventDefault();
  						}
  
  						// If hitting the delete key, and the cursor is before a decimal place,
  						// we simply move the cursor to the other side of the decimal place.
  						else if( decimals > 0 && code == 127 && start == this.value.length-decimals-1 )
  						{
  							// Just prevent default but don't actually move the caret here because it's done in the keyup event
  							e.preventDefault();
  						}
  
  						// If hitting the backspace key, and the cursor is behind a decimal place,
  						// we simply move the cursor to the other side of the decimal place.
  						else if( decimals > 0 && code == 8 && start == this.value.length-decimals )
  						{
  							e.preventDefault();
  							data.c--;
  
  							// Set the selection position.
  							setPos = this.value.length+data.c;
  						}
  
  						// If hitting the delete key, and the cursor is to the right of the decimal
  						// we replace the character after the caret with a 0.
  						else if( decimals > 0 && code == 127 && start > this.value.length-decimals-1 )
  						{
  							if( this.value === '' ) return;
  
  							// If the character following is not already a 0,
  							// replace it with one.
  							if( this.value.slice(start, start+1) != '0' )
  							{
  								val = this.value.slice(0, start) + '0' + this.value.slice(start+1);
  								// The regex replacement below removes negative sign from numbers...
  								// not sure why they're necessary here when none of the other cases use them
  								//$this.val(val.replace(regex_dec_num,'').replace(regex_dec,dec_point));
  								$this.val(val);
  							}
  
  							e.preventDefault();
  
  							// Set the selection position.
  							setPos = this.value.length+data.c;
  						}
  
  						// If hitting the backspace key, and the cursor is to the right of the decimal
  						// (but not directly to the right) we replace the character preceding the
  						// caret with a 0.
  						else if( decimals > 0 && code == 8 && start > this.value.length-decimals )
  						{
  							if( this.value === '' ) return;
  
  							// If the character preceding is not already a 0,
  							// replace it with one.
  							if( this.value.slice(start-1, start) != '0' )
  							{
  								val = this.value.slice(0, start-1) + '0' + this.value.slice(start);
  								// The regex replacement below removes negative sign from numbers...
  								// not sure why they're necessary here when none of the other cases use them
  								//$this.val(val.replace(regex_dec_num,'').replace(regex_dec,dec_point));
  								$this.val(val);
  							}
  
  							e.preventDefault();
  							data.c--;
  
  							// Set the selection position.
  							setPos = this.value.length+data.c;
  						}
  
  						// If the delete key was pressed, and the character immediately
  						// after the caret is a thousands_separator character, simply
  						// step over it.
  						else if( code == 127 && this.value.slice(start, start+1) == thousands_sep )
  						{
  							// Just prevent default but don't actually move the caret here because it's done in the keyup event
  							e.preventDefault();
  						}
  
  						// If the backspace key was pressed, and the character immediately
  						// before the caret is a thousands_separator character, simply
  						// step over it.
  						else if( code == 8 && this.value.slice(start-1, start) == thousands_sep )
  						{
  							e.preventDefault();
  							data.c--;
  
  							// Set the selection position.
  							setPos = this.value.length+data.c;
  						}
  
  						// If the caret is to the right of the decimal place, and the user is entering a
  						// number, remove the following character before putting in the new one.
  						else if(
  							decimals > 0 &&
  							start == end &&
  							this.value.length > decimals+1 &&
  							start > this.value.length-decimals-1 && isFinite(+chara) &&
  							!e.metaKey && !e.ctrlKey && !e.altKey && chara.length === 1
  						)
  						{
  							// If the character preceding is not already a 0,
  							// replace it with one.
  							if( end === this.value.length )
  							{
  								val = this.value.slice(0, start-1);
  							}
  							else
  							{
  								val = this.value.slice(0, start)+this.value.slice(start+1);
  							}
  
  							// Reset the position.
  							this.value = val;
  							setPos = start;
  						}
  
  						// If we need to re-position the characters.
  						if( setPos !== false )
  						{
  							//console.log('Setpos keydown: ', setPos );
  							setSelectionRange.apply(this, [setPos, setPos]);
  						}
  
  						// Store the data on the element.
  						$this.data('numFormat', data);
  
  					},
  
  					/**
  					 * Handles keyup events, re-formatting numbers.
  					 *
  					 * @param object e			: the keyup event object.s
  					 *
  					 * @return void;
  					 */
  					'keyup.format' : function(e){
  
  						// Store these variables for use below.
  						var $this	= $(this),
  							data	= $this.data('numFormat'),
  							code	= (e.keyCode ? e.keyCode : e.which),
  							start	= getSelection.apply(this,['start']),
  							end		= getSelection.apply(this,['end']),
  							setPos;
  
  
  						// Check for negative characters being entered at the start of the string.
  						// If there's any kind of selection, just ignore the input.
  						if( start === 0 && end === 0 && ( code === 189 || code === 109 ) )
  						{
  							$this.val('-'+$this.val());
  
  							start		= 1;
  							data.c		= 1-this.value.length;
  							data.init	= 1;
  
  							$this.data('numFormat', data);
  
  							setPos = this.value.length+data.c;
  							setSelectionRange.apply(this, [setPos, setPos]);
  						}
  
  						// Stop executing if the user didn't type a number key, a decimal, or a comma.
  						if( this.value === '' || (code < 48 || code > 57) && (code < 96 || code > 105 ) && code !== 8 && code !== 46 && code !== 110 ) return;
  
  						// Re-format the textarea.
  						$this.val($this.val());
  
  						if( decimals > 0 )
  						{
  							// If we haven't marked this item as 'initialized'
  							// then do so now. It means we should place the caret just
  							// before the decimal. This will never be un-initialized before
  							// the decimal character itself is entered.
  							if( data.init < 1 )
  							{
  								start		= this.value.length-decimals-( data.init < 0 ? 1 : 0 );
  								data.c		= start-this.value.length;
  								data.init	= 1;
  
  								$this.data('numFormat', data);
  							}
  
  							// Increase the cursor position if the caret is to the right
  							// of the decimal place, and the character pressed isn't the backspace key.
  							else if( start > this.value.length-decimals && code != 8 )
  							{
  								data.c++;
  
  								// Store the data, now that it's changed.
  								$this.data('numFormat', data);
  							}
  						}
  
  						// Move caret to the right after delete key pressed
  						if (code == 46 && !data.isPartialSelection)
  						{
  							data.c++;
  
  							// Store the data, now that it's changed.
  							$this.data('numFormat', data);
  						}
  
  						//console.log( 'Setting pos: ', start, decimals, this.value.length + data.c, this.value.length, data.c );
  
  						// Set the selection position.
  						setPos = this.value.length+data.c;
  						setSelectionRange.apply(this, [setPos, setPos]);
  					},
  
  					/**
  					 * Reformat when pasting into the field.
  					 *
  					 * @param object e 		: jQuery event object.
  					 *
  					 * @return false : prevent default action.
  					 */
  					'paste.format' : function(e){
  
  						// Defint $this. It's used twice!.
  						var $this		= $(this),
  							original	= e.originalEvent,
  							val		= null;
  
  						// Get the text content stream.
  						if (window.clipboardData && window.clipboardData.getData) { // IE
  							val = window.clipboardData.getData('Text');
  						} else if (original.clipboardData && original.clipboardData.getData) {
  							val = original.clipboardData.getData('text/plain');
  						}
  
  						// Do the reformat operation.
  						$this.val(val);
  
  						// Stop the actual content from being pasted.
  						e.preventDefault();
  						return false;
  					}
  
  				})
  
  				// Loop each element (which isn't blank) and do the format.
  				.each(function(){
  
  					var $this = $(this).data('numFormat',{
  						c				: -(decimals+1),
  						decimals		: decimals,
  						thousands_sep	: thousands_sep,
  						dec_point		: dec_point,
  						regex_dec_num	: regex_dec_num,
  						regex_dec		: regex_dec,
  						init			: this.value.indexOf('.') ? true : false
  					});
  
  					// Return if the element is empty.
  					if( this.value === '' ) return;
  
  					// Otherwise... format!!
  					$this.val($this.val());
  				});
  			}
  			else
  			{
  				// return the collection.
  				return this.each(function(){
  					var $this = $(this), num = +$this.text().replace(regex_dec_num,'').replace(regex_dec,'.');
  					$this.number( !isFinite(num) ? 0 : +num, decimals, dec_point, thousands_sep );
  				});
  			}
  		}
  
  		// Add this number to the element as text.
  		return this.text( $.number.apply(window,arguments) );
  	};
  
  	//
  	// Create .val() hooks to get and set formatted numbers in inputs.
  	//
  
  	// We check if any hooks already exist, and cache
  	// them in case we need to re-use them later on.
  	var origHookGet = null, origHookSet = null;
  
  	// Check if a text valHook already exists.
  	if( $.isPlainObject( $.valHooks.text ) )
  	{
  		// Preserve the original valhook function
  		// we'll call this for values we're not
  		// explicitly handling.
  		if( $.isFunction( $.valHooks.text.get ) ) origHookGet = $.valHooks.text.get;
  		if( $.isFunction( $.valHooks.text.set ) ) origHookSet = $.valHooks.text.set;
  	}
  	else
  	{
  		// Define an object for the new valhook.
  		$.valHooks.text = {};
  	}
  
  	/**
  	* Define the valHook to return normalised field data against an input
  	* which has been tagged by the number formatter.
  	*
  	* @param object el			: The raw DOM element that we're getting the value from.
  	*
  	* @return mixed : Returns the value that was written to the element as a
  	*				  javascript number, or undefined to let jQuery handle it normally.
  	*/
  	$.valHooks.text.get = function( el ){
  
  		// Get the element, and its data.
  		var $this	= $(el), num, negative,
  			data	= $this.data('numFormat');
  
  		// Does this element have our data field?
  		if( !data )
  		{
  			// Check if the valhook function already existed
  			if( $.isFunction( origHookGet ) )
  			{
  				// There was, so go ahead and call it
  				return origHookGet(el);
  			}
  			else
  			{
  				// No previous function, return undefined to have jQuery
  				// take care of retrieving the value
  				return undefined;
  			}
  		}
  		else
  		{
  			// Remove formatting, and return as number.
  			if( el.value === '' ) return '';
  
  
  			// Convert to a number.
  			num = +(el.value
  				.replace( data.regex_dec_num, '' )
  				.replace( data.regex_dec, '.' ));
  
  			// If we've got a finite number, return it.
  			// Otherwise, simply return 0.
  			// Return as a string... thats what we're
  			// used to with .val()
  			return (el.value.indexOf('-') === 0 ? '-' : '')+( isFinite( num ) ? num : 0 );
  		}
  	};
  
  	/**
  	* A valhook which formats a number when run against an input
  	* which has been tagged by the number formatter.
  	*
  	* @param object el		: The raw DOM element (input element).
  	* @param float			: The number to set into the value field.
  	*
  	* @return mixed : Returns the value that was written to the element,
  	*				  or undefined to let jQuery handle it normally.
  	*/
  	$.valHooks.text.set = function( el, val )
  	{
  		// Get the element, and its data.
  		var $this	= $(el),
  			data	= $this.data('numFormat');
  
  		// Does this element have our data field?
  		if( !data )
  		{
  
  			// Check if the valhook function already exists
  			if( $.isFunction( origHookSet ) )
  			{
  				// There was, so go ahead and call it
  				return origHookSet(el,val);
  			}
  			else
  			{
  				// No previous function, return undefined to have jQuery
  				// take care of retrieving the value
  				return undefined;
  			}
  		}
  		else
  		{
  			var num = $.number( val, data.decimals, data.dec_point, data.thousands_sep );
  
  			// Make sure empties are set with correct signs.
  //			if(val.indexOf('-') === 0 && +num === 0)
  //			{
  //				num = '-'+num;
  //			}
  
  			return $.isFunction(origHookSet) ? origHookSet(el, num) : el.value = num;
  		}
  	};
  
  	/**
  	 * The (modified) excellent number formatting method from PHPJS.org.
  	 * http://phpjs.org/functions/number_format/
  	 *
  	 * @modified by Sam Sehnert (teamdf.com)
  	 *	- don't redefine dec_point, thousands_sep... just overwrite with defaults.
  	 *	- don't redefine decimals, just overwrite as numeric.
  	 *	- Generate regex for normalizing pre-formatted numbers.
  	 *
  	 * @param float number			: The number you wish to format, or TRUE to use the text contents
  	 *								  of the element as the number. Please note that this won't work for
  	 *								  elements which have child nodes with text content.
  	 * @param int decimals			: The number of decimal places that should be displayed. Defaults to 0.
  	 * @param string dec_point		: The character to use as a decimal point. Defaults to '.'.
  	 * @param string thousands_sep	: The character to use as a thousands separator. Defaults to ','.
  	 *
  	 * @return string : The formatted number as a string.
  	 */
  	$.number = function( number, decimals, dec_point, thousands_sep ){
  		// Set the default values here, instead so we can use them in the replace below.
  		thousands_sep	= (typeof thousands_sep === 'undefined') ? ( new Number(1000).toLocaleString() !== '1000' ? new Number(1000).toLocaleString().charAt(1) : '' ) : thousands_sep;
  		dec_point		= (typeof dec_point === 'undefined') ? new Number(0.1).toLocaleString().charAt(1) : dec_point;
  		decimals		= !isFinite(+decimals) ? 0 : Math.abs(decimals);
  
  		// Work out the unicode representation for the decimal place and thousand sep.
  		var u_dec = ('\\u'+('0000'+(dec_point.charCodeAt(0).toString(16))).slice(-4));
  		var u_sep = ('\\u'+('0000'+(thousands_sep.charCodeAt(0).toString(16))).slice(-4));
  
  		// Fix the number, so that it's an actual number.
  		number = (number + '')
  			.replace('\.', dec_point) // because the number if passed in as a float (having . as decimal point per definition) we need to replace this with the passed in decimal point character
  			.replace(new RegExp(u_sep,'g'),'')
  			.replace(new RegExp(u_dec,'g'),'.')
  			.replace(new RegExp('[^0-9+\-Ee.]','g'),'');
  
  		var n = !isFinite(+number) ? 0 : +number,
  			s = '',
  			toFixedFix = function (n, decimals) {
  				return '' + (+(Math.round(('' + n).indexOf('e') > 0 ? n : n + 'e+' + decimals) + 'e-' + decimals));
  			};
  
  		// Fix for IE parseFloat(0.55).toFixed(0) = 0;
  		s = (decimals ? toFixedFix(n, decimals) : '' + Math.round(n)).split('.');
  		if (s[0].length > 3) {
  			s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, thousands_sep);
  		}
  		if ((s[1] || '').length < decimals) {
  			s[1] = s[1] || '';
  			s[1] += new Array(decimals - s[1].length + 1).join('0');
  		}
  		return s.join(dec_point);
  	}
  
  })(jQuery);