self.AJAX = function()
{
	// PRIVATE and PRIVATE STATIC properties
	var IE = (window.ActiveXObject !== undefined);
	var _request;
	var _requests;
	var _state;

	// PRIVATE methods
	var init = function()
	{
		_requests = [];
		_state = 4;
	};
	
	var create = function()
	{
		try
		{
			_request = new XMLHttpRequest();
		}
		catch (excGeneral)
		{
			try
			{
				_request = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (excMicrosoft)
			{
				try
				{
					_request = new ActiveXObject("Msxml2.XMLHTTP");
				}
				catch (excMicrosoft2)
				{
					_request = null;

					alert("Não foi possível criar o objeto \"XMLHttpRequest\"!\nAtualize seu navegador:\n\n" + excMicrosoft2 + "\n" + excMicrosoft + "\n" + excGeneral);
				}
			}
		}
	};
	
	var toXML = function(str) // Converte uma String para XML
	{
		var xmlObject, xml;

		xml = null;
		//str = str.split("\n").join(""); // Remove as quebras de linha
		
		if (str.match(/^<\?\s*xml/) !== null)
		{
			if (IE)
			{
				xml = new ActiveXObject("Microsoft.XMLDOM");
				xml.async = "false";
				xml.loadXML(str);
	
				if (xml.parseError.errorCode !== 0) xml = xml.parseError.reason;
			}
			else
			{
				xmlObject = new DOMParser();
				xml = xmlObject.parseFromString(str, "text/xml"); // Executa incondicionalmente.
			}
		}
	
		return xml;
	};
	
	var execute = function(params)
	{
		var url, method, postData, async, onComplete, onProcess;
		
		url = params.url;
		method = (params.postData !== undefined) ? "post" : ((params.method !== undefined) ? params.method.toLowerCase() : "get");
		postData = (params.postData !== undefined) ? params.postData : "";
		async = (params.async !== undefined) ? params.async : true;
		onComplete = (params.onComplete !== undefined) ? params.onComplete : function(){};
		onProcess = (params.onProcess !== undefined) ? params.onProcess : function(){};

		create();
		
		_request.onreadystatechange = function()
		{
			var text;

			_state = _request.readyState;

			onProcess({state: _state});

			if (_state === 4)
			{
				text = _request.responseText;
				onComplete({text: text, xml: toXML(text), state: _state});

				if (_requests.length > 0)
				{
					execute(_requests[0]);
					_requests.shift()
				}
			}
		};

		try
		{
			_request.open(method, url, async);

			if (postData !== "") _request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

			_request.send(postData);
		}
		catch (exception)
		{
			var o;

			if (IE)
			{
				o = "";
				
				for (var i in exception) o += i + ": " + exception[i] + "\n";
			}
			else o = exception;
			
			alert("ERRO:\n\n" + o);
		}
	};
	
	// PUBLIC methods
	this.execute = function(params)
	{
		if (_state < 4) _requests.push(params);
			else execute(params);
	};

	// Construct
	init();
};