function TwitterFeed( elementId, xmlrpcURL, loadingImageURL ) {
	this.elementId = elementId;
	this.element = null;
	this.xmlrpcURL = xmlrpcURL;
	this.loadingImageURL = loadingImageURL;
	
	this.Initialize = function() {
		this.element = document.getElementById( this.elementId );
		this.element.innerHTML = "<img class='loading' src='" + this.loadingImageURL + "' alt='Loading...' width='200px' />";
		this.Update();
	}
	
	this.Update = function( xmlHttp ) {
		if( xmlHttp == undefined ) {
			var job = new XMLRPCJob( this.xmlrpcURL, "", false, this );
			job.oncomplete = function() { this.callbackObject.Update( this.xmlHttp ); }
			job.Execute();
			return;
		}
		
		var xmlDocument = xmlHttp.responseXML;
		var rootElement = xmlDocument.documentElement;
		
		if( rootElement.nodeName != "tweets" ) {
			this.element.innerHTML = "[Error]";
			return;
		}
		
		// Extract data.
		var updates = new Array();
		var statusElements = rootElement.getElementsByTagName( "tweet" );
		for( var index = 0; index < statusElements.length; index++ ) {
			var statusElement = statusElements.item( index );
			
			// Timestamp elements.
			var timestampElements = statusElement.getElementsByTagName( "time" );
			if( timestampElements.length != 1 ) continue;
			var timestampElement = timestampElements.item( 0 );
			
			// Text elements.
			var textElements = statusElement.getElementsByTagName( "text" );
			if( textElements.length != 1 ) continue;
			var textElement = textElements.item( 0 );
			
			var text = ( textElement.textContent == undefined ? textElement.text : textElement.textContent );
			var timestamp = ( timestampElement.textContent == undefined ? timestampElement.text : timestampElement.textContent );
			
			updates.push( text + "' <span style='color: #9e9e9e;'>" + timestamp + "</span>" );
		}
		
		// Dump it into the site.
		if( updates.length > 0 ) {
			this.element.innerHTML = "<div class='twitterItem'>" + updates.join( "</div><div class='twitterItem'>" ) + "</div>";
		} else {
			this.element.innerHTML = "[None]";
		}
	}
}