					var statesCache = {};
					statesCache.US = {"AL":"Alabama","AK":"Alaska","AS":"American Samoa","AZ":"Arizona","AR":"Arkansas","CA":"California","CO":"Colorado","CT":"Connecticut","DE":"Delaware","DC":"District of Columbia","FL":"Florida","GA":"Georgia","GU":"Guam","HI":"Hawaii","ID":"Idaho","IL":"Illinois","IN":"Indiana","IA":"Iowa","KS":"Kansas","KY":"Kentucky","LA":"Louisiana","ME":"Maine","MD":"Maryland","MA":"Massachusetts","MI":"Michigan","MN":"Minnesota","MS":"Mississippi","MO":"Missouri","MT":"Montana","NE":"Nebraska","NV":"Nevada","NH":"New Hampshire","NJ":"New Jersey","NM":"New Mexico","NY":"New York","NC":"North Carolina","ND":"North Dakota","MP":"Northern Mariana Islands","OH":"Ohio","OK":"Oklahoma","OR":"Oregon","PA":"Pennsylvania","PR":"Puerto Rico","RI":"Rhode Island","SC":"South Carolina","SD":"South Dakota","TN":"Tennessee","TX":"Texas","UM":"U.S. Minor Outlying Islands","UT":"Utah","VT":"Vermont","VI":"Virgin Islands of the U.S.","VA":"Virginia","WA":"Washington","WV":"West Virginia","WI":"Wisconsin","WY":"Wyoming"};
					statesCache.CA = {"AB":"Alberta","BC":"British Columbia","MB":"Manitoba","NB":"New Brunswick","NL":"Newfoundland and Labrador","NT":"Northwest Territories","NS":"Nova Scotia","NU":"Nunavut","ON":"Ontario","PE":"Prince Edward Island","QC":"Quebec","SK":"Saskatchewan","YT":"Yukon Territory"};
					function changeStates(obj) {
					        var country = obj.options[obj.selectedIndex].value;
					        var nm = (obj.name == 'cc_country') ? '#f_cc_state' : '#f_state';
					        $(nm).removeOption(/.|^$/).
					        addOption('', '[Select state]');
					        if (statesCache[country]){
					            $(nm).addOption(statesCache[country]).selectOptions('', true);
					            onStatesLoaded();
					        } else {
					            onStatesLoaded();
					            $(nm).attr('selectedIndex', -1);
					            $(nm).ajaxAddOption("ajax.php", 
					                {"do" : "get_states", "country" : country}, false, onStatesLoaded);
					        }
					}
					//select states in drop down list
					function selectStates(obj) {
					        var nm = (obj.name == 'cc_country') ? '#f_cc_state' : '#f_state';
					        var nmt = (obj.name == 'cc_country') ? '#t_cc_state' : '#t_state';
					        var selected=$(nmt)[0].value;
					        if (selected!='') {       
					            tmp=nm+" > option[@value='"+selected+"']";
					            $(tmp).attr("selected", "selected");
					        }
					}
					$(document).ready(function(){
					    $("#f_country, #f_cc_country").change(function(){
					        changeStates(this);
					    });
					    onStatesLoaded();
					    $("#f_country, #f_cc_country").each(function(){
					        changeStates(this);
					    });
					});
					function onStatesLoaded(){
					    // this function called after completion of Ajax or after changing 
					    // state list options
					    // we will display text box instead of selectBox if no states found
					    selObj = $("#f_state")[0];
					    if (selObj){
					        if (selObj.options.length <= 1){
					            $("#f_state").hide().attr("disabled", true).attr('_required', false);
					            $("#t_state").show().attr("disabled", false).attr('_required', true);
					        } else {
					            $("#f_state").show().attr("disabled", false).attr('_required', true);;
					            $("#t_state").hide().attr("disabled", true).attr('_required', false);;
					        }
					    }
					    selObj = $("#f_cc_state")[0];
					    if (selObj){
					        if (selObj.options.length <= 1){
					            $("#f_cc_state").hide().attr("disabled", true);
					            $("#t_cc_state").show().attr("disabled", false);

					        } else {
					            $("#f_cc_state").show().attr("disabled", false);
					            $("#t_cc_state").hide().attr("disabled", true);
					        }
					    }  
					    $("#f_country, #f_cc_country").each(function(){
					        selectStates(this);
					    });     
					}				
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------					
					jQuery.validator.addMethod("remoteUniqLogin", function(value, element, params) { 
					  	var previous = this.previousValue(element);
					  	if (!this.settings.messages[element.name] )
					  		this.settings.messages[element.name] = {};
					  	this.settings.messages[element.name].remoteUniqLogin = 
					      	this.settings.messages[element.name].remote = 
					        typeof previous.message == "function" ? previous.message(value) : previous.message;
					  	if ( previous.old !== value ) {
					  		previous.old = value;
					  		var validator = this;
					  		this.startRequest(element);
					  		var data = {
					            'do'    : "check_uniq_login",
					            'login' : $("#f_login").val(),
					            'email' : $("#f_email").val(),
					            'pass'  : $("#f_pass0").val()
					        };
					  		jQuery.ajax({
					            type: "POST",
					  			url: params,
					  			mode: "abort",
					  			port: "validate" + element.name,
					  			dataType: "json",
					  			data: data,
					  			success: function(response) {
					        		if ( !response || response.errorCode>0 ) {
					    				var errors = {};
					                    validator.settings.messages[element.name]['remote'] = 
					                    validator.settings.messages[element.name]['remoteUniqLogin'] = 
					                            response.msg;
					  					errors[element.name] =  response.msg || validator.defaultMessage( element, "remoteUniqLogin" );
					                    previous.message = response.msg;
					                    jQuery.data(element, "previousValue", previous);
					  					validator.showErrors(errors);

					  				} else {
					  					var submitted = validator.formSubmitted;
					  					validator.prepareElement(element);
					  					validator.formSubmitted = submitted;
					  					validator.successList.push(element);
					  					validator.showErrors();
					  				}
					  				previous.valid = response && (response.errorCode == 0);
					  				validator.stopRequest(element, response);
					  			}
					  		});
					  		return "pending";
					  	} else if( this.pending[element.name] ) {
					  		return "pending";
					  	}
					  	return previous.valid;
					  }, "Incorect value"); 
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
					  jQuery.validator.addMethod("remoteCoupon", function(value, element, params) { 
					  	var previous = this.previousValue(element);
					  	if (!this.settings.messages[element.name] )
					  		this.settings.messages[element.name] = {};
					  	this.settings.messages[element.name].remoteCoupon = 
					        typeof previous.message == "function" ? previous.message(value) : previous.message;
					    if (value == "")
					        return true;
					  	if ( previous.old !== value ) {
					  		previous.old = value;
					  		var validator = this;
					  		this.startRequest(element);
					  		var data = {
					            'do'    : "check_coupon",
					            'coupon' : $("#f_coupon").val()
					        };
					  		jQuery.ajax({
					            type: "POST",
					  			url: params,
					  			mode: "abort",
					  			port: "validate" + element.name,
					  			dataType: "json",
					  			data: data,
					  			success: function(response) {
					        		if ( !response || response.errorCode>0 ) {
					    				var errors = {};
					                    validator.settings.messages[element.name]['remoteCoupon'] = 
					                            response.msg;
					  					errors[element.name] =  response.msg || validator.defaultMessage( element, "remoteCoupon" );
					                    previous.message = response.msg;
					                    jQuery.data(element, "previousValue", previous);
					  					validator.showErrors(errors);
					  				} else {
					  					var submitted = validator.formSubmitted;
					  					validator.prepareElement(element);
					  					validator.formSubmitted = submitted;
					  					validator.successList.push(element);
					  					validator.showErrors();
					  				}
					  				previous.valid = response && (response.errorCode == 0);
					  				validator.stopRequest(element, response);
					  			}
					  		});
					  		return "pending";
					  	} else if( this.pending[element.name] ) {
					  		return "pending";
					  	}
					  	return previous.valid;
					  }, "Incorect value"); 
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------					  
					  // TODO: coupon, uniq_login ajax check, additional fields
					function checkLogin(){
					    $("#signup").validate().element("#f_login");
					}
					function checkCoupon(){
					    $("#signup").validate().element("#f_coupon");
					}
					$(document).ready(function(){
					    var prevLogin = "";   
					    var prevCoupon = ""; 
					    var timeout = null;
					    $("#signup").validate({
					   	onkeyup: function(element) {
					   		if ( element.name in this.submitted || element == this.lastElement ) {
					            if (element.id == 'f_login'){
					                var l = element.value;
					                if (l == prevLogin) return;
					                clearTimeout(timeout);
					                timeout = setTimeout(checkLogin, 1*1000);
					                prevLogin = l;
					            } else if (element.id == 'f_coupon'){
					                var c = element.value;
					                if (c == prevCoupon) return; 
					                clearTimeout(timeout);
					                timeout = setTimeout(checkCoupon, 1*1000);
					                prevCoupon = c;
					            } else
					       			this.element(element);
					   		}
					   	},
					    rules: {
						    "_notexisting_": "required" // for the following comma
						},
					  	errorPlacement: function(error, element) {
							error.appendTo( element.parent());
						}
					    });
					});
