function sajx(vr,frm,cb) {
	var me = this; //Para referencias dentro de event handlers
	this._xmlHttp = null; //Objeto xmlHTTP
	this.sa = frm; //Ponteiro para o form em que estamos dando submit AJAX

	//CONFIGURAR
	this.vr = vr; //Nome da variável que contém ponteiro para instância de objeto AJAX
	this._actajx = null; //Armazenará action que implementa AJAX no servidor
	this._pdata = ''; //Armazenara corpo do post no submit AJAX
	this.cb = cb; //Armazena função de callback que tem a assinatura: (msg, f_erro, elname)

	//CONSTANTES
	this.appFullURL=appFullURL; //URL raiz para a pesquisa AJAX
	this.appCookies=appCookies; //Dump dos cookies do usuário

	//Instancia e retorna um objeto XMLHTTP
	this.getXmlHttp = function(){
		var A=null;
		try {
			A=new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch(e) {
			try {
				A=new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (oc) {
				A=null;
			}
		}
		if (!A && typeof XMLHttpRequest != "undefined") {
	    	A=new XMLHttpRequest();
		}
		return A;
	}

	//Pesquisa o token na pagina pg
	this.qc = function() {
		if (this._xmlHttp && this._xmlHttp.readyState!=0) {
			this._xmlHttp.abort();
		}
		this._xmlHttp=this.getXmlHttp();
		if (this._xmlHttp) {
			this._xmlHttp.open("POST",this.appFullURL+'?a='+this._actajx+'&vr='+this.vr,true);
            if (this.appCookies) {
    			this._xmlHttp.setRequestHeader("Cookie", this.appCookies);
            }
			this._xmlHttp.setRequestHeader("Accept-Language", "pt-br");
			this._xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			this._xmlHttp.setRequestHeader("Content-length", this._pdata.length);
			this._xmlHttp.onreadystatechange= function() {
				if (me._xmlHttp.readyState==4 && me._xmlHttp.responseText) {
					eval(me.url_decode(me._xmlHttp.responseText));
				}
			}
			this._xmlHttp.send(this._pdata);
		}
		else {
			alert('_xmlHttp eh null...>_<');
		}
	}

	// url_decode version 1.0
	this.url_encode = function(str) {
	    var hex_chars = "0123456789ABCDEF";
	    var noEncode = /^([a-zA-Z0-9\_\-\.])$/;
	    var n, strCode, hex1, hex2, strEncode = "";

	    for(n = 0; n < str.length; n++) {
	        if (noEncode.test(str.charAt(n))) {
	            strEncode += str.charAt(n);
	        }
			else {
	            strCode = str.charCodeAt(n);
	            hex1 = hex_chars.charAt(Math.floor(strCode / 16));
	            hex2 = hex_chars.charAt(strCode % 16);
	            strEncode += "%" + (hex1 + hex2);
	        }
	    }
	    return strEncode;
	}

	// url_decode version 1.0
	this.url_decode = function(str) {
	    var n, strCode, strDecode = "";

	    for (n = 0; n < str.length; n++) {
	        if (str.charAt(n) == "%") {
	            strCode = str.charAt(n + 1) + str.charAt(n + 2);
	            strDecode += String.fromCharCode(parseInt(strCode, 16));
	            n += 2;
	        }
			else {
	            strDecode += str.charAt(n);
	        }
	    }
	    return strDecode;
	}

	//Extrai o tipo do elemento de formulário
	this.extractTipo = function(o) {
		try {
			var tipo;
			if (typeof(o.options)!='undefined') tipo= o.type.toLowerCase();
			else if (o.length) tipo = o[0].type.toLowerCase();
			else tipo = o.type.toLowerCase();
			return tipo;
		}
		catch (e) {
			return '';
		}
	}

	//Dump de um post para AJAX
	this.getPostValue = function(frm) {
		var out = '';
		var tipo;
		//Varremos todo o form
		for (var i=0; i<frm.elements.length; i++) {
			//Extraindo o elemento atual
			var o = frm.elements[i];

			//Extraindo o tipo do elemento de formulário
			tipo = this.extractTipo(o);

			//Se o elemento não estiver escondido, será enviado
			if (o.style.visibility!='hidden')
			switch (tipo) {
				case 'hidden':
				case 'text':
				case 'textarea':
					//UPDATE 05/05/07
					//Se prefixo indicar que é valor decimal (vlr)
					//Entao substituo virgula por ponto.
					if (o.name.substring(0,3)=='vlr')
						out += '&' + o.name + '=' + this.url_encode(o.value.replace(",","."));
					else
						out += '&' + o.name + '=' + this.url_encode(o.value);
				break;
				case 'select-one':
					out += '&' + o.name + '=' + this.url_encode(o.options[o.selectedIndex].value);
				break;
				case 'checkbox':
				case 'radio':
					if (o.length)
						for (var j=0; j<o.length; j++) {
							if (o[j].checked) {
								out += '&' + o[j].name + '=' + this.url_encode(o[j].value);
							}
						}
					else {
						if (o.checked) {
							out += '&' + o.name + '=' + this.url_encode(o.value);
						}
					}
				break;
			}
		}
		return out.substr(1);
	}

	//trata onsubmit
	this.Qa = function(){
		return false;
	}

	//Popula o corpo do post
	this.cy = function()  {
		this._pdata = this.getPostValue(this.sa);
	}

	//Instala o submit AJAX no form
	this.doPost = function() {
		me.sa.onsubmit = me.Qa;
		me._actajx = me.sa.a.value;
		me.cy();
		me.qc();
	}
	//OBS: Responsabilidade de chamar o doPost é do botão de submit em cada página!
	//OBS2: SEMPRE chamar o construtor com 'new'
}
