/**
 * jquery.meio.mask.js
 * @author: fabiomcosta
 * @version: 1.1.3
 *
 * Created by Fabio M. Costa on 2008-09-16. Please report any bug at http://www.meiocodigo.com
 *
 * Copyright (c) 2008 Fabio M. Costa http://www.meiocodigo.com
 *
 * The MIT License (http://www.opensource.org/licenses/mit-license.php)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

(function($){
		
    var isIphone = (window.orientation != undefined),
	    // browsers like firefox2 and before and opera doenst have the onPaste event, but the paste feature can be done with the onInput event.
	    pasteEvent = (($.browser.opera || ($.browser.mozilla && parseFloat($.browser.version.substr(0,3)) < 1.9 ))? 'input': 'paste');
		
    $.event.special.paste = {
	    setup: function() {
    	    if(this.addEventListener)
        	    this.addEventListener(pasteEvent, pasteHandler, false);
		    else if (this.attachEvent)
			    this.attachEvent(pasteEvent, pasteHandler);
	    },

	    teardown: function() {
		    if(this.removeEventListener)
        	    this.removeEventListener(pasteEvent, pasteHandler, false);
		    else if (this.detachEvent)
			    this.detachEvent(pasteEvent, pasteHandler);
	    }
    };
	
    // the timeout is set because we can't get the value from the input without it
    function pasteHandler(e){
	    var self = this;
	    e = $.event.fix(e || window.e);
	    e.type = 'paste';
	    // Execute the right handlers by setting the event type to paste
	    setTimeout(function(){ $.event.handle.call(self, e); }, 1);
    };

    $.extend({
	    mask : {
			
		    // the mask rules. You may add yours!
		    // number rules will be overwritten
		    rules : {
			    'z': /[a-z]/,
			    'Z': /[A-Z]/,
			    'a': /[a-zA-Z]/,
			    '*': /[0-9a-zA-Z]/,
			    '@': /[0-9a-zA-ZçÇáàãâéèêíìóòôõúùü]/
		    },
			
		    // these keys will be ignored by the mask.
		    // all these numbers where obtained on the keydown event
		    keyRepresentation : {
			    8	: 'backspace',
			    9	: 'tab',
			    16	: 'shift',
			    17	: 'control',
			    18	: 'alt',
			    27	: 'esc',
			    33	: 'page up',
			    34	: 'page down',
			    35	: 'end',
			    36	: 'home',
			    37	: 'left',
			    38	: 'up',
			    39	: 'right',
			    40	: 'down',
			    45	: 'insert',
			    46	: 'delete',
			    116	: 'f5',
			    123 : 'f12',
			    224	: 'command'
		    },
			
		    iphoneKeyRepresentation : {
			    10	: 'go',
			    127	: 'delete'
		    },
			
		    signals : {
			    '+' : '',
			    '-' : '-'
		    },
			
		    // default settings for the plugin
		    options : {
			    attr: 'alt', // an attr to look for the mask name or the mask itself
			    mask: null, // the mask to be used on the input
			    type: 'fixed', // the mask of this mask
			    maxLength: -1, // the maxLength of the mask
			    defaultValue: '', // the default value for this input
			    signal: false, // this should not be set, to use signal at masks put the signal you want ('-' or '+') at the default value of this mask.
						       // See the defined masks for a better understanding.
				
			    textAlign: true, // use false to not use text-align on any mask (at least not by the plugin, you may apply it using css)
			    selectCharsOnFocus: true, // select all chars from input on its focus
			    autoTab: false, // auto focus the next form element when you type the mask completely
			    setSize: false, // sets the input size based on the length of the mask (work with fixed and reverse masks only)
			    fixedChars : '[(),.:/ -]', // fixed chars to be used on the masks. You may change it for your needs!
				
			    onInvalid : function(){},
			    onValid : function(){},
			    onOverflow : function(){}
		    },
			
		    // masks. You may add yours!
		    // Ex: $.fn.setMask.masks.msk = {mask: '999'}
		    // and then if the 'attr' options value is 'alt', your input should look like:
		    // <input type="text" name="some_name" id="some_name" alt="msk" />
		    masks : {
			    'phone'				: { mask : ' 99  9999-9999' },
			    'phone-us'			: { mask : '(99) 9999-9999' },
			    'cpf'				: { mask : '999.999.999-99' }, // cadastro nacional de pessoa fisica
			    'cnpj'				: { mask : '99.999.999/9999-99' },
			    'date'				: { mask : '39/19/9999' }, //uk date
			    'date-us'			: { mask : '19/39/9999' },
			    'cep'				: { mask : '99999-999' },
			    'time'				: { mask : '29:59' },
			    'cc'				: { mask : '9999 9999 9999 9999' }, //credit card mask
			    'integer'			: { mask : '999.999.999.999', type : 'reverse', defaultValue: '0' },				
			    'decimal'			: { mask : '99,999.999.999.999', type : 'reverse', defaultValue : '000' },
			    'decimal-us'		: { mask : '99.999,999,999,999', type : 'reverse', defaultValue : '000' },
			    'signed-decimal'	: { mask : '99,999.999.999.999', type : 'reverse', defaultValue : '+000' },
			    'signed-decimal-us' : { mask : '99,999.999.999.999', type : 'reverse', defaultValue : '+000' },
			    'signed-decimal-resultado'	: { mask : '99,999.999.9', type : 'reverse', defaultValue : '+θθθ' }
		    },
			
		    init : function(){
			    // if has not inited...
			    if( !this.hasInit ){

				    var self = this, i,
					    keyRep = (isIphone)? this.iphoneKeyRepresentation: this.keyRepresentation;
						
				    this.ignore = false;
			
				    // constructs number rules
				    for(i=0; i<=9; i++) this.rules[i] = new RegExp('[0-'+i+']');
				
				    this.keyRep = keyRep;
				    // ignore keys array creation for iphone or the normal ones
				    this.ignoreKeys = [];
				    $.each(keyRep,function(key){
					    self.ignoreKeys.push( parseInt(key) );
				    });
					
				    this.hasInit = true;
			    }
		    },
			
		    set: function(el,options){
				
			    var maskObj = this,
				    $el = $(el),
				    mlStr = 'maxLength';
				
			    options = options || {};
			    this.init();

			    return $el.each(function(){
					
                    

				    if(options.attr) maskObj.options.attr = options.attr;
					
				    var $this = $(this),
					    o = $.extend({}, maskObj.options),
					    attrValue = $this.attr(o.attr),
					    tmpMask = '';
						
				    // then we look for the 'attr' option
				    tmpMask = (typeof options == 'string')? options: (attrValue != '')? attrValue: null;
				    if(tmpMask) o.mask = tmpMask;
					
				    // then we see if it's a defined mask
				    if(maskObj.masks[tmpMask]) o = $.extend(o, maskObj.masks[tmpMask]);
					
				    // then it looks if the options is an object, if it is we will overwrite the actual options
				    if(typeof options == 'object' && options.constructor != Array) o = $.extend(o, options);
					
				    //then we look for some metadata on the input
				    if($.metadata) o = $.extend(o, $this.metadata());
					
				    if(o.mask != null){
						
					    if($this.data('mask')) maskObj.unset($this);
						
					    var defaultValue = o.defaultValue,
						    reverse = (o.type=='reverse'),
						    fixedCharsRegG = new RegExp(o.fixedChars, 'g');
						
					    if(o.maxLength == -1) o.maxLength = $this.attr(mlStr);
						
					    o = $.extend({}, o,{
						    fixedCharsReg: new RegExp(o.fixedChars),
						    fixedCharsRegG: fixedCharsRegG,
						    maskArray: o.mask.split(''),
						    maskNonFixedCharsArray: o.mask.replace(fixedCharsRegG, '').split('')
					    });
						
					    //setSize option (this is not removed from the input (while removing the mask) since this would be kind of funky)
					    if((o.type=='fixed' || reverse) && o.setSize && !$this.attr('size')) $this.attr('size', o.mask.length);
						
					    //sets text-align right for reverse masks
					    if(reverse && o.textAlign) $this.css('text-align', 'right');
						
					    if(this.value!='' || defaultValue!=''){

						    // apply mask to the current value of the input or to the default value
						    var val = maskObj.string((this.value!='')? this.value: defaultValue, o);
						    //setting defaultValue fixes the reset button from the form
						    this.defaultValue = val;
						    $this.val(val);
					    }
						
					    // compatibility patch for infinite mask, that is now repeat
					    if(o.type=='infinite') o.type = 'repeat';
						
					    $this.data('mask', o);
						
					    // removes the maxLength attribute (it will be set again if you use the unset method)
					    $this.removeAttr(mlStr);
                        
                        var funcaox = null;
                        if(this.onkeyup!=null){
                            funcaox = this.onkeyup;
                        }    
                        this.onkeyup="";
					    
					    // setting the input events
					    
					    $this.bind('keydown.mask', {func:maskObj._onKeyDown, thisObj:maskObj}, maskObj._onMask)
						    .bind('keypress.mask', {func:maskObj._onKeyPress, thisObj:maskObj}, maskObj._onMask)
						    .bind('keyup.mask', {func:maskObj._onKeyUp, thisObj:maskObj}, maskObj._onMask)
						   
						    .bind('paste.mask', {func:maskObj._onPaste, thisObj:maskObj}, maskObj._onMask)
						    .bind('focus.mask', maskObj._onFocus)
						    .bind('blur.mask', maskObj._onBlur)
						    .bind('change.mask', maskObj._onChange);
						
					     if(funcaox!=null){
			                $this.bind('keyup.mask',funcaox)
			             }    
						    
				    }
			    });
		    },
			
		    //unsets the mask from el
		    unset : function(el){
			    var $el = $(el);
				
			    return $el.each(function(){
				    var $this = $(this);
				    if($this.data('mask')){
					    var maxLength = $this.data('mask').maxLength;
					    if(maxLength != -1) $this.attr('maxLength', maxLength);
					    $this.unbind('.mask')
						    .removeData('mask');
				    }
			    });
		    },
			
		    //masks a string
		    string : function(str, options){
			    this.init();
			    var o={};
			    if(typeof str != 'string') str = String(str);
			    switch(typeof options){
				    case 'string':
					    // then we see if it's a defined mask	
					    if(this.masks[options]) o = $.extend(o, this.masks[options]);
					    else o.mask = options;
					    break;
				    case 'object':
					    o = options;
			    }
			    if(!o.fixedChars) o.fixedChars = this.options.fixedChars;

			    var fixedCharsReg = new RegExp(o.fixedChars),
				    fixedCharsRegG = new RegExp(o.fixedChars, 'g');
					
			    // insert signal if any
			    if( (o.type=='reverse') && o.defaultValue ){
				    if( typeof this.signals[o.defaultValue.charAt(0)] != 'undefined' ){
					    var maybeASignal = str.charAt(0);
					    o.signal = (typeof this.signals[maybeASignal] != 'undefined') ? this.signals[maybeASignal] : this.signals[o.defaultValue.charAt(0)];
					    o.defaultValue = o.defaultValue.substring(1);
				    }
			    }
				
			    return this.__maskArray(str.split(''),
						    o.mask.replace(fixedCharsRegG, '').split(''),
						    o.mask.split(''),
						    o.type,
						    o.maxLength,
						    o.defaultValue,
						    fixedCharsReg,
						    o.signal);
		    },
			
		    // all the 3 events below are here just to fix the change event on reversed masks.
		    // It isn't fired in cases that the keypress event returns false (needed).
		    _onFocus: function(e){
			    var $this = $(this), dataObj = $this.data('mask');
			    dataObj.inputFocusValue = $this.val();
			    dataObj.changed = false;
			    if(dataObj.selectCharsOnFocus) $this.select();
		    },
			
		    _onBlur: function(e){
			    var $this = $(this), dataObj = $this.data('mask');
			    if(dataObj.inputFocusValue != $this.val() && !dataObj.changed)
				    $this.trigger('change');
		    },
			
		    _onChange: function(e){
			    $(this).data('mask').changed = true;
		    },
			
		    _onMask : function(e){
			    var thisObj = e.data.thisObj,
				    o = {};
			    o._this = e.target;
			    o.$this = $(o._this);
			    // if the input is readonly it does nothing
			    if(o.$this.attr('readonly')) return true;
			    o.data = o.$this.data('mask');
			    o[o.data.type] = true;
			    o.value = o.$this.val();
			    o.nKey = thisObj.__getKeyNumber(e);
			    o.range = thisObj.__getRange(o._this);
			    o.valueArray = o.value.split('');
			    return e.data.func.call(thisObj, e, o);
		    },
			
		    _onKeyDown : function(e,o){
			    // lets say keypress at desktop == keydown at iphone (theres no keypress at iphone)
			    this.ignore = $.inArray(o.nKey, this.ignoreKeys) > -1 || e.ctrlKey || e.metaKey || e.altKey;
			    if(this.ignore){
				    var rep = this.keyRep[o.nKey];
				    o.data.onValid.call(o._this, rep? rep: '', o.nKey);
			    }
			    return isIphone ? this._keyPress(e, o) : true;
		    },
			
		    _onKeyUp : function(e, o){
			    //9=TAB_KEY 16=SHIFT_KEY
			    //this is a little bug, when you go to an input with tab key
			    //it would remove the range selected by default, and that's not a desired behavior
			    if(o.nKey==9 || o.nKey==16) return true;
				
			    if(o.data.type=='repeat'){
				    this.__autoTab(o);
				    return true;
			    }

			    return this._onPaste(e, o);
		    },
			
		    _onPaste : function(e,o){
			    // changes the signal at the data obj from the input
			    if(o.reverse) this.__changeSignal(e.type, o);
				
			    var $thisVal = this.__maskArray(
				    o.valueArray,
				    o.data.maskNonFixedCharsArray,
				    o.data.maskArray,
				    o.data.type,
				    o.data.maxLength,
				    o.data.defaultValue,
				    o.data.fixedCharsReg,
				    o.data.signal
			    );
				
			    o.$this.val( $thisVal );
			    // this makes the caret stay at first position when 
			    // the user removes all values in an input and the plugin adds the default value to it (if it haves one).
			    if( !o.reverse && o.data.defaultValue.length && (o.range.start==o.range.end) )
				    this.__setRange(o._this, o.range.start, o.range.end);
					
			    //fix so ie's and safari's caret won't go to the end of the input value.
			    if( ($.browser.msie || $.browser.safari) && !o.reverse)
				    this.__setRange(o._this,o.range.start,o.range.end);
				
			    if(this.ignore) return true;
				
			    this.__autoTab(o);
			    return true;
		    },
			
		    _onKeyPress: function(e, o){
				
			    if(this.ignore) return true;
				
			    // changes the signal at the data obj from the input
			    if(o.reverse) this.__changeSignal(e.type, o);
				
			    var c = String.fromCharCode(o.nKey),
				    rangeStart = o.range.start,
				    rawValue = o.value,
				    maskArray = o.data.maskArray;
				
			    if(o.reverse){
				 	    // the input value from the range start to the value start
				    var valueStart = rawValue.substr(0, rangeStart),
					    // the input value from the range end to the value end
					    valueEnd = rawValue.substr(o.range.end, rawValue.length);
					
				    rawValue = valueStart+c+valueEnd;
				    //necessary, if not decremented you will be able to input just the mask.length-1 if signal!=''
				    //ex: mask:99,999.999.999 you will be able to input 99,999.999.99
				    if(o.data.signal && (rangeStart-o.data.signal.length > 0)) rangeStart-=o.data.signal.length;
			    }

			    var valueArray = rawValue.replace(o.data.fixedCharsRegG, '').split(''),
				    // searches for fixed chars begining from the range start position, till it finds a non fixed
				    extraPos = this.__extraPositionsTill(rangeStart, maskArray, o.data.fixedCharsReg);
				
			    o.rsEp = rangeStart+extraPos;
				
			    if(o.repeat) o.rsEp = 0;
				
			    // if the rule for this character doesnt exist (value.length is bigger than mask.length)
			    // added a verification for maxLength in the case of the repeat type mask
			    if( !this.rules[maskArray[o.rsEp]] || (o.data.maxLength != -1 && valueArray.length >= o.data.maxLength && o.repeat)){
				    // auto focus on the next input of the current form
				    o.data.onOverflow.call(o._this, c, o.nKey);
				    return false;
			    }
				
			    // if the new character is not obeying the law... :P
			    else if( !this.rules[maskArray[o.rsEp]].test( c ) ){
				    o.data.onInvalid.call(o._this, c, o.nKey);
				    return false;
			    }
				
			    else o.data.onValid.call(o._this, c, o.nKey);
				
			    var $thisVal = this.__maskArray(
				    valueArray,
				    o.data.maskNonFixedCharsArray,
				    maskArray,
				    o.data.type,
				    o.data.maxLength,
				    o.data.defaultValue,
				    o.data.fixedCharsReg,
				    o.data.signal,
				    extraPos
			    );
				
			    o.$this.val( $thisVal );
				
			    return (o.reverse)? this._keyPressReverse(e, o): (o.fixed)? this._keyPressFixed(e, o): true;
		    },
			
		    _keyPressFixed: function(e, o){

			    if(o.range.start==o.range.end){
				    // the 0 thing is cause theres a particular behavior i wasnt liking when you put a default
				    // value on a fixed mask and you select the value from the input the range would go to the
				    // end of the string when you enter a char. with this it will overwrite the first char wich is a better behavior.
				    // opera fix, cant have range value bigger than value length, i think it loops thought the input value...
				    if((o.rsEp==0 && o.value.length==0) || o.rsEp < o.value.length)
					    this.__setRange(o._this, o.rsEp, o.rsEp+1);	
			    }
			    else
				    this.__setRange(o._this, o.range.start, o.range.end);
					
			    return true;
		    },
			
		    _keyPressReverse: function(e, o){
			    //fix for ie
			    //this bug was pointed by Pedro Martins
			    //it fixes a strange behavior that ie was having after a char was inputted in a text input that
			    //had its content selected by any range 
			    if($.browser.msie && ((o.range.start==0 && o.range.end==0) || o.range.start != o.range.end ))
				    this.__setRange(o._this, o.value.length);
			    return false;
		    },
			
		    __autoTab: function(o){
			    if(o.data.autoTab
				    && (
					    (
						    o.$this.val().length >= o.data.maskArray.length 
						    && !o.repeat 
					    ) || (
						    o.data.maxLength != -1
						    && o.valueArray.length >= o.data.maxLength
						    && o.repeat
					    )
				    )
			    ){
				    var nextEl = this.__getNextInput(o._this, o.data.autoTab);
				    if(nextEl){
					    o.$this.trigger('blur');
					    nextEl.focus().select();
				    }
			    }
		    },
			
		    // changes the signal at the data obj from the input			
		    __changeSignal : function(eventType,o){
			    if(o.data.signal!==false){
				    var inputChar = (eventType=='paste')? o.value.charAt(0): String.fromCharCode(o.nKey);
				    if( this.signals && (typeof this.signals[inputChar] != 'undefined') ){
					    o.data.signal = this.signals[inputChar];
				    }
			    }
		    },
			
		    __getKeyNumber : function(e){
			    return (e.charCode||e.keyCode||e.which);
		    },
			
		    // this function is totaly specific to be used with this plugin, youll never need it
		    // it gets the array representing an unmasked string and masks it depending on the type of the mask
		    __maskArray : function(valueArray, maskNonFixedCharsArray, maskArray, type, maxlength, defaultValue, fixedCharsReg, signal, extraPos){
			    if(type == 'reverse') valueArray.reverse();
			    valueArray = this.__removeInvalidChars(valueArray, maskNonFixedCharsArray, type=='repeat'||type=='infinite');
			    if(defaultValue) valueArray = this.__applyDefaultValue.call(valueArray, defaultValue);
			    valueArray = this.__applyMask(valueArray, maskArray, extraPos, fixedCharsReg);
			    switch(type){
				    case 'reverse':
					    valueArray.reverse();
					    return (signal || '')+valueArray.join('').substring(valueArray.length-maskArray.length);
				    case 'infinite': case 'repeat':
					    var joinedValue = valueArray.join('');
					    return (maxlength != -1 && valueArray.length >= maxlength)? joinedValue.substring(0, maxlength): joinedValue;
				    default:
					    return valueArray.join('').substring(0, maskArray.length);
			    }
			    return '';
		    },
			
		    // applyes the default value to the result string
		    __applyDefaultValue : function(defaultValue){
			    var defLen = defaultValue.length,thisLen = this.length,i;
			    //removes the leading chars
			    for(i=thisLen-1;i>=0;i--){
				    if(this[i]==defaultValue.charAt(0)) this.pop();
				    else break;
			    }
			    // apply the default value
			    for(i=0;i<defLen;i++) if(!this[i])
				    this[i] = defaultValue.charAt(i);
					
			    return this;
		    },
			
		    // Removes values that doesnt match the mask from the valueArray
		    // Returns the array without the invalid chars.
		    __removeInvalidChars : function(valueArray, maskNonFixedCharsArray, repeatType){
			    // removes invalid chars
			    for(var i=0, y=0; i<valueArray.length; i++ ){
				    if( maskNonFixedCharsArray[y] &&
					    this.rules[maskNonFixedCharsArray[y]] &&
					    !this.rules[maskNonFixedCharsArray[y]].test(valueArray[i]) ){
						    valueArray.splice(i,1);
						    if(!repeatType) y--;
						    i--;
				    }
				    if(!repeatType) y++;
			    }
			    return valueArray;
		    },
			
		    // Apply the current input mask to the valueArray and returns it. 
		    __applyMask : function(valueArray, maskArray, plus, fixedCharsReg){
			    if( typeof plus == 'undefined' ) plus = 0;
			    // apply the current mask to the array of chars
			    for(var i=0; i<valueArray.length+plus; i++ ){
				    if( maskArray[i] && fixedCharsReg.test(maskArray[i]) )
					    valueArray.splice(i, 0, maskArray[i]);
			    }
			    return valueArray;
		    },
			
		    // searches for fixed chars begining from the range start position, till it finds a non fixed
		    __extraPositionsTill : function(rangeStart, maskArray, fixedCharsReg){
			    var extraPos = 0;
			    while(fixedCharsReg.test(maskArray[rangeStart++])){
				    extraPos++;
			    }
			    return extraPos;
		    },
			
		    __getNextInput: function(input, selector){
			    var formEls = input.form.elements,
				    initialInputIndex = $.inArray(input, formEls) + 1,
				    $input = null,
				    i;
			    // look for next input on the form of the pased input
			    for(i = initialInputIndex; i < formEls.length; i++){
				    $input = $(formEls[i]);
				    if(this.__isNextInput($input, selector))
					    return $input;
			    }
					
			    var forms = document.forms,
				    initialFormIndex = $.inArray(input.form, forms) + 1,
				    y, tmpFormEls = null;
			    // look for the next forms for the next input
			    for(y = initialFormIndex; y < forms.length; y++){
				    tmpFormEls = forms[y].elements;
				    for(i = 0; i < tmpFormEls.length; i++){
					    $input = $(tmpFormEls[i]);
					    if(this.__isNextInput($input, selector))
						    return $input;
				    }
			    }
			    return null;
		    },
			
		    __isNextInput: function($formEl, selector){
			    var formEl = $formEl.get(0);
			    return formEl
				    && (formEl.offsetWidth > 0 || formEl.offsetHeight > 0)
				    && formEl.nodeName != 'FIELDSET'
				    && (selector === true || (typeof selector == 'string' && $formEl.is(selector)));
		    },
			
		    // http://www.bazon.net/mishoo/articles.epl?art_id=1292
		    __setRange : function(input, start, end) {
			    if(typeof end == 'undefined') end = start;
			    if (input.setSelectionRange){
				    input.setSelectionRange(start, end);
			    }
			    else{
				    // assumed IE
				    var range = input.createTextRange();
				    range.collapse();
				    range.moveStart('character', start);
				    range.moveEnd('character', end - start);
				    range.select();
			    }
		    },
			
		    // adaptation from http://digitarald.de/project/autocompleter/
		    __getRange : function(input){
			    if (!$.browser.msie) return {start: input.selectionStart, end: input.selectionEnd};
			    var pos = {start: 0, end: 0},
				    range = document.selection.createRange();
			    pos.start = 0 - range.duplicate().moveStart('character', -100000);
			    pos.end = pos.start + range.text.length;
			    return pos;
		    },
			
		    //deprecated
		    unmaskedVal : function(el){
			    return $(el).val().replace($.mask.fixedCharsRegG, '');
		    }
			
	    }
    });
	
    $.fn.extend({
	    setMask : function(options){
		    return $.mask.set(this, options);
	    },
	    unsetMask : function(){
		    return $.mask.unset(this);
	    },
	    //deprecated
	    unmaskedVal : function(){
		    return $.mask.unmaskedVal(this[0]);
	    }
    });
})(jQuery);



