function CASTransport( url, owner, callback, timeoutCallback ) {
	this.url = url;
	this.query = new Array();
	this.owner = owner;
	this.callback = callback;
	this.timeoutCallback = timeoutCallback;
	this.busy = false;
	this.timer = null;
	
	var self = this; // Private access.

	this.processReq = function() {
    	// only if req shows 'complete'
   		if (self.xmlHTTP.readyState == 4) {
       		// only if 'OK'
        	if ( self.xmlHTTP.status == 200) {
				if ( self.timer ) clearTimeout( self.timer );
        		self.owner[self.callback]( self.xmlHTTP );
				self.xmlHTTP.abort();
				self.busy = false;
       		}
			else {
				//window.status = 'There was a problem retrieving the XML data: ' + self.xmlHTTP.status + '-' + self.xmlHTTP.statusText;
       		}
    	}
	}

	this.xmlHTTP = null;
	try {
		this.xmlHTTP = new XMLHttpRequest();
	} 
	catch (e) {
		try {
			this.xmlHTTP = new ActiveXObject('Msxml2.XMLHTTP')
		} 
		catch(e) {
			var success = false;
			var MSXML_XMLHTTP_PROGIDS = new Array(
				'Microsoft.XMLHTTP',
				'MSXML2.XMLHTTP',
				'MSXML2.XMLHTTP.5.0',
				'MSXML2.XMLHTTP.4.0',
				'MSXML2.XMLHTTP.3.0'
			);
			for (var i=0;i < MSXML_XMLHTTP_PROGIDS.length && !success; i++) {
				try {
					this.xmlHTTP = new ActiveXObject(MSXML_XMLHTTP_PROGIDS[i]);
					success = true;
				} 
				catch (e) {
					this.xmlHTTP = null;
				}
			}
		}
	}
	
	this.clearQuery = function() {
		this.query.length = 0;
	}
	
	this.abort = function() {
		self.xmlHTTP.abort();
		self.busy = false;
   		//if (self.owner[timeoutCallback]) self.owner[timeoutCallback]( self.xmlHTTP );
		if ( self.timer ) clearTimeout( self.timer );
	}
	
	this.triggerTimeout = function() {
		self.abort();
   		if (self.owner[timeoutCallback]) self.owner[timeoutCallback]( self );
	}
   	
	this.send = function() {
		var timeout = this.timeout;
		if ( !this.timeout ) {
			var timeout = 2000;
		}
		if ( arguments[0] ) timeout = arguments[0];
		if ( this.xmlHTTP !== null ) {
			var query = "?";
			var prefix = "";
			for( p in this.query ) {
				if ( typeof( this.query[p] ) != "function" && typeof( this.query[p] ) != "object" ) {
					if ( this.query[p] == "undefined" ) this.query[p] = "";
					query += prefix + p+"="+casescape(this.query[p]);
					prefix = "&";
				}
			}
			
			var url = this.url+query;
			
			if ( timeout > 0 ) {
				this.timer = setTimeout( this.triggerTimeout, timeout );
			}
			
			this.busy = true;
			this.xmlHTTP.onreadystatechange = this.processReq;
			this.xmlHTTP.open( "GET", url, true );
			this.xmlHTTP.send( "" );
		}
		else {
			throw new Error( "Could not initialte XMLHttpRequest" );
		}
	}
	
	this.post = function() {
		if ( this.xmlHTTP !== null ) {
		var timeout = this.timeout;
		if ( !this.timeout ) {
			var timeout = 2000;
		}
		
		if ( arguments[0] ) timeout = arguments[0];
			var query = "";
			var prefix = "";
			for( p in this.query ) {
				if ( typeof( this.query[p] ) != "function" && typeof( this.query[p] ) != "object" ) {
					if ( this.query[p] == "undefined" ) this.query[p] = "";
					query += prefix + p+"="+casescape(this.query[p]);
					prefix = "&";
				}
			}
			
			if ( timeout > 0 ) {
				this.timer = setTimeout( this.triggerTimeout, timeout );
			}
			
			if ( this.busy ) {
				//Debugger.alert( "Busy" );
			}
			this.busy = true;
			this.xmlHTTP.onreadystatechange = this.processReq;
			this.xmlHTTP.open( "POST", url, true );
			this.xmlHTTP.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
			this.xmlHTTP.send( query );
		}
		else {
			throw new Error( "Could not initialte XMLHttpRequest" );
		}
	}
}

function CASCmdTransport( url, owner, callback, tickCount ) {
	this.owner = owner;
	this.callback = callback;
	this.transport = new CASTransport( url, this, "onCmdCompleted", "onCmdTimeout" );
	this.commands = new Array();
	this.timeout = 2000;
	this.timer = false;
	this.isShutDown = false;
	if ( !tickCount ) tickCount = 100;
	this.tickCount = tickCount;
	this.timeoutCallback = null;
	
	var self = this;
	
	this.addCommand = function( cmdArray ) {
		this.commands.push( cmdArray );
		this.send();
	}
	
	this.send = function() {
		if ( this.isShutDown ) return;
		if ( !self.transport.busy && self.commands.length > 0 ) {
			self.transport.timeout = self.timeout;
			self.transport.clearQuery();
			
			var cmd = self.commands.shift();
			for( p in cmd ) {
				if ( typeof( cmd[p] ) != "function" && typeof( cmd[p] ) != "object" ) {
					if ( cmd[p] == "undefined" ) cmd[p] = "";
					self.transport.query[p] = cmd[p];
				}
			}
			self.transport.lastCommand = cmd;
			self.transport.post();
		}
	}
	
	this.onCmdTimeout = function( transport ){
		if ( this.isShutDown ) return;
		if ( self.timeoutCallback && self.owner && self.owner[self.timeoutCallback] ) {
			self.owner[self.timeoutCallback]( transport.lastCommand );
		}
		setTimeout( self.send, self.tickCount );
	}
	
	this.onCmdCompleted = function( transport ) {
		if ( this.isShutDown ) return;
		//Debugger.alert( transport.responseText );
		if ( self.owner && self.owner[self.callback] ) {
			self.owner[self.callback]( transport );
		}
		
		setTimeout( self.send, self.tickCount );
	}
	
	this.shutDown = function() {
		this.isShutDown = true;
	}
	
}

function casescape( str ) {
	str = escape( str );
	str = str.replace( "+", "%2B" );
	return str;
}