// Library of common functions mostly taken from Pro Javascript Techniques written by John Resig

var DOM = {
	trim: function(str) {
		return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
	},
	
	getTag: function(elem,name) { // Returns array of elements
		name = name || ((elem && elem.constructor == String) ? elem : "*");
		elem = (elem && elem.constructor != String) ? elem : document;
		return (elem.getElementsByTagName) ? elem.getElementsByTagName(name) : [];
	},
	
	getId: function(elem,type,name) { // Returns element
		name = name || type || elem;
		if (!name || name.constructor != String) {return null;}
		if (document.getElementById) {return document.getElementById(name);}
		
		type = (type && type != name) ? type : ((elem && elem.constructor == String && elem != name) ? elem : "*");
		elem = (elem && elem.constructor != String) ? elem : document;
		var e = this.getTag(elem, type);
		for (var j = 0; j < e.length; j++) {
			if (e[j].id == name) {return e[j];}
		}
		return null;
	},
	
	hasClass: function(elem,name) { // Returns boolean
		var re = new RegExp("(^|\\s)" + name + "(\\s|$)");
		return re.test(elem.className);
	},
	
	getClass: function(elem,type,name) { // Returns array of elements
		var r = [];
		name = name || type || elem;
		if (!name || name.constructor != String) {return null;}
		
		type = (type && type != name) ? type : ((elem && elem.constructor == String && elem != name) ? elem : "*");
		elem = (elem && elem.constructor != String) ? elem : document;
		var e = this.getTag(elem, type);
		for (var j = 0; j < e.length; j++) {
			if (this.hasClass(e[j],name)) {r.push(e[j]);}
		}
		return (r.length > 0) ? r : [null];
	},
	
	// A function for finding the previous sibling element in relation to an element
	prev: function(elem) {
		do {
			elem = elem.previousSibling;
		} while (elem && elem.nodeType != 1);
		return elem;
	},
	
	// A function for finding the next sibling element in relation to an element
	next: function(elem) {
		do {
			elem = elem.nextSibling;
		} while (elem && elem.nodeType != 1);
		return elem;
	},
	
	// A function for finding the first child element of an element
	first: function(elem,num) {
		num = num || 1;
		for (var i = 0; i < num; i++) {
			elem = elem.firstChild;
			elem = elem && elem.nodeType != 1 ? this.next(elem) : elem;
		}
		return elem;
	},
	
	// A function for finding the last child element of an element
	last: function(elem) {
		elem = elem.lastChild;
		return elem && elem.nodeType != 1 ? this.prev(elem) : elem;
	},
	
	// A function for finding the parent of an element
	parent: function(elem,num) {
		num = num || 1;
		for (var i = 0; i < num; i++) {
			if (elem != null) {elem = elem.parentNode;}
		}
		return elem;
	},
	
	// A function for finding the children of an element
	children: function(elem) {
		var r = [];
		var e = elem.childNodes;
		for (var j = 0; j < e.length; j++) {
			if (e[j].nodeType == 1) {r.push(e[j]);}
		}
		return r;
	},
	
	attr: function(elem,name,value) {
		// Make sure that a valid name was provided
		if (!elem || !name || name.constructor != String) return '';
		
		// Figure out if the name is one of the weird naming cases
		name = {'for': 'htmlFor', 'class': 'className'}[name] || name;
		
		// If the user is setting a value, also
		if (typeof value != 'undefined') {
			// Set the quick way first
			elem[name] = value;
			
			// If we can, use setAttribute
			if (elem.setAttribute) {elem.setAttribute(name,value);}
		}
		
		// Return the value of the attribute
		return elem[name] || elem.getAttribute(name) || '';
	},
	
	addClass: function(elem,name) {
		// Get the old value
		var old = this.attr(elem,"class");
		
		// Make sure that a valid name was provided
		if (!name || name.constructor != String) return old;
		
		// Return the new value
		return this.attr(elem,"class",(typeof old == 'string') ? (old + " " + name) : name);
	},
	
	removeClass: function(elem,name) {
		// Get the old value
		var old = this.attr(elem,"class");
		
		// Make sure that a valid name was provided
		if (!name || name.constructor != String || typeof old != 'string') return old;
		
		// Remove the space if more then one class name is present
		if (old.indexOf(" ") != -1) {name = (old.indexOf(name) == 0) ? (name + " ") : (" " + name);}
		
		// Return the new value
		return this.attr(elem,"class",old.replace(name,''));
	},
	
	css: function(elem,name,value) {
		// Make sure that a valid name was provided
		if (!elem || !name || name.constructor != String) {return '';}
		
		// Figure out if the name is one of the weird naming cases
		name = {'float': 'cssFloat', 'text': 'cssText'}[name] || name;
		
		if (typeof value != 'undefined') {
			// Set the value
			return elem.style[name] = value;
		}
		
		// If the property exists in style[], then it's been set recently (and is correct)
		if (elem.style[name]) {return elem.style[name];}
		
		// Otherwise, try to use IE's method
		else if (elem.currentStyle) {return elem.currentStyle[name];}
		
		// Or the W3C's method, if it exists
		else if (document.defaultView && document.defaultView.getComputedStyle) {
			// It uses the traditional 'text-align' style of rule writing
			name = name.replace(/([A-Z])/g,"-$1");
			name = name.toLowerCase();
			
			// Get the style object and get the value of the property (if it exists)
			var s = document.defaultView.getComputedStyle(elem,"");
			return s && s.getPropertyValue(name);
		
		// Otherwise, we're using some other browser
		} else {return null;}
	},
	
	fullWidth: function(elem) {
		if (!elem) {return;}
		if (DOM.css(elem, 'display') != 'none') {
			return elem.offsetWidth || parseInt(DOM.css(elem, 'width'));
		}
		
		var old = DOM.resetCss(elem, {display: '', visibility: 'hidden', position: 'absolute'});
		var w = elem.clientWidth || parseInt(DOM.css(elem, 'width'));
		DOM.restoreCss(elem, old);
		
		return w;
	},
	
	fullHeight: function(elem) {
		if (!elem) {return;}
		if (DOM.css(elem, 'display') != 'none') {
			return elem.offsetHeight || parseInt(DOM.css(elem, 'height'));
		}
		
		var old = DOM.resetCss(elem, {display: '', visibility: 'hidden', position: 'absolute'});
		var h = elem.clientHeight || parseInt(DOM.css(elem, 'height'));
		DOM.restoreCss(elem, old);
		
		return h;
	},
	
	resetCss: function(elem,prop) {
		if (!elem) {return;}
		
		var old = {};
		for (var i in prop) {
			old[i] = elem.style[i];
			elem.style[i] = prop[i];
		}
		
		return old;
	},
	
	restoreCss: function(elem,prop) {
		for (var i in prop) {
			elem.style[i] = prop[i];
		}
	},
	
	setOpacity: function(elem,level) {
		if (!elem) {return;}
		// If filters exist, then this is IE, so set the Alpha filter
		if (elem.filters) {elem.style.filter = 'alpha(opacity=' + level + ')';}
		
		// Otherwise use the W3C opacity property
		else {elem.style.opacity = level / 100;}
		return;
	},
	
	innerHTML: function(elem, html) {
		if (!elem) {return '';}
		if (html) {elem.innerHTML = html;}
		return elem.innerHTML;
	},
	
	create: function(name,attr,html) {
		var elem = document.createElementNS ? document.createElementNS('http://www.w3.org/1999/xhtml',name) : document.createElement(name);
		if (!attr) {return elem;}
		if (attr.constructor == String) {html = attr;}
		else {
			for (i in attr) {this.attr(elem, i, attr[i]);}
		}
		if (html != '') {this.innerHTML(elem, html);}
		return elem;
	},
	
	convertDiv: function(html,start,end) {
		if (start) {html = html.substring(html.indexOf(start) + start.length, html.lastIndexOf(end || ''));}
		var div = this.create("div", html);
		return div;
	},
	
	pageX: function(elem) {
		if (!elem) {return null;}
		return elem.offsetParent ?
			
			// If we can still go up, add the current offset and recurse upwards
			elem.offsetLeft + DOM.pageX(elem.offsetParent) :
			
			// Otherwise, just get the current offset
			elem.offsetLeft;
	},
	
	pageY: function(elem) {
		if (!elem) {return null;}
		return elem.offsetParent ?
			
			// If we can still go up, add the current offset and recurse upwards
			elem.offsetTop + DOM.pageY(elem.offsetParent) :
			
			// Otherwise, just get the current offset
			elem.offsetTop;
	},
	
	pageWidth: function() {
		return Math.max(document.body.scrollWidth, document.body.offsetWidth);
	},
	
	pageHeight: function() {
		return Math.max(document.body.scrollHeight, document.body.offsetHeight);
	},
	
	windowWidth: function() {
		// A shortcut, in case we're using Internet Explorer 6 in Strict Mode
		var de = document.documentElement;
		
		// If the innerWidth of the browser is available, use that
		return self.innerWidth ||
			
			// Otherwise, try to get the width off of the root node
			(de && de.clientWidth) ||
			
			// Finally, try to get the width off of the body element
			document.body.clientWidth;
	},
	
	windowHeight: function() {
		// A shortcut, in case we're using Internet Explorer 6 in Strict Mode
		var de = document.documentElement;
		
		// If the innerHeight of the browser is available, use that
		return self.innerHeight ||
			
			// Otherwise, try to get the height off of the root node
			(de && de.clientHeight) ||
			
			// Finally, try to get the height off of the body element
			document.body.clientHeight;
	},
	
	scrollX: function() {
		// A shortcut, in case we're using Internet Explorer 6 in Strict Mode
		var de = document.documentElement;
		
		// If the pageXOffset of the browser is available, use that
		return self.pageXOffset ||
			
			// Otherwise, try to get the scroll left off of the root node
			(de && de.scrollLeft) ||
			
			// Finally, try to get the scroll left off of the body element
			document.body.scrollLeft;
	},
	
	scrollY: function() {
		// A shortcut, in case we're using Internet Explorer 6 in Strict Mode
		var de = document.documentElement;
		
		// If the pageYOffset of the browser is available, use that
		return self.pageYOffset ||
			
			// Otherwise, try to get the scroll top off of the root node
			(de && de.scrollTop) ||
			
			// Finally, try to get the scroll top off of the body element
			document.body.scrollTop;
	}
};

var Effect = {
	slide: function(elem,prop,time,rate,start,end,delay) {
		if (!elem) {return;}
		
		var change = end - start;
		var frames = Math.floor(time * rate);
		for (var i = 1; i <= frames; i++) {
			(function(){
				var frame = i;
				setTimeout(function(){
					DOM.css(elem, prop, start + Math.floor(change * frame / frames) + 'px');
					if (frame == frames && elem.onSlideFinish) {elem.onSlideFinish();}
				}, Math.floor(((delay || 0) + frame / rate) * 1000));
			})();
		}
		return;
	},
	
	fade: function(elem,time,rate,start,end,delay) {
		if (!elem) {return;}
		start = Math.max(start, 0);
		end = Math.min(end, 100);
		
		var change = end - start;
		var frames = Math.floor(time * rate);
		for (var i = 1; i <= frames; i++) {
			(function(){
				var frame = i;
				setTimeout(function(){
					DOM.setOpacity(elem, start + Math.floor(change * frame / frames));
					if (frame == frames && elem.onFadeFinish) {elem.onFadeFinish();}
				}, Math.floor(((delay || 0) + frame / rate) * 1000));
			})();
		}
		return;
	}
};

var Drag = {
	// The current element being dragged
	obj: null,
	
	// Initialize the function for the drag object
	// o = The element to act as the drag handle
	// oRoot = The element to be dragged, if not specified,
	// 				the handle will be the element dragged
	// minX, maxX, minY, maxY = The min and max coordinates allowed for the element
	// bSwapHorzRef = Toggle the horizontal coordinate system
	// bSwapVertRef = Toggle the vertical coordinate system
	// fxMapper, fyMapper = Functions for mapping x and y coordinates to others
	init: function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fxMapper, fyMapper) {
		// Watch for the drag event to start
		Evnt.add(o, 'mousedown', Drag.start);
		
		// Figure out which coordinate system is being used
		o.hmode = bSwapHorzRef ? false : true;
		o.vmode = bSwapVertRef ? false : true;
		
		// Figure out which element is acting as the draggable 'handle'
		o.root = oRoot && oRoot != null ? oRoot : o;
		
		// Initalize the specified coordinate system
		if (o.hmode && isNaN(parseInt(DOM.css(o.root, 'left'))))	{DOM.css(o.root, 'left', '0px');}
		if (o.vmode && isNaN(parseInt(DOM.css(o.root, 'top'))))		{DOM.css(o.root, 'top', '0px');}
		if (!o.hmode && isNaN(parseInt(DOM.css(o.root, 'right'))))	{DOM.css(o.root, 'right', '0px');}
		if (!o.vmode && isNaN(parseInt(DOM.css(o.root, 'bottom'))))	{DOM.css(o.root, 'bottom', '0px');}
		
		// Look to see if the user provided min/max x/y coordinates
		o.minX = typeof minX != 'undefined' ? minX : null;
		o.minY = typeof minY != 'undefined' ? minY : null;
		o.maxX = typeof maxX != 'undefined' ? maxX : null;
		o.maxY = typeof maxY != 'undefined' ? maxY : null;
		
		// Check for any specified x and y coordinate mappers
		o.xMapper = fxMapper ? fxMapper : null;
		o.yMapper = fyMapper ? fyMapper : null;
		
		// Add shells for all the user-defined functions
		o.root.onDragStart = new Function();
		o.root.onDragEnd = new Function();
		o.root.onDrag = new Function();
		
	},
	
	start: function(et) {
		// Figure out the object that's being dragged
		var o = Drag.obj = this;
		
		// Get the current x and y coordinates
		var x = parseInt(o.hmode ? DOM.css(o.root, 'left') : DOM.css(o.root, 'right'));
		var y = parseInt(o.vmode ? DOM.css(o.root, 'top') : DOM.css(o.root, 'bottom'));
		
		// Call the user's function with the current x and y coordinates
		o.root.onDragStart(x, y);
		
		// Remember the starting mouse position
		o.lastMouseX = et.clientX;
		o.lastMouseY = et.clientY;
		
		// If we're using the css coordinate system
		if (o.hmode) {
			// set the min and max coordinates, where applicable
			if (o.minX != null)	{o.minMouseX = et.clientX - x + o.minX;}
			if (o.maxX != null)	{o.maxMouseX = o.minMouseX + o.maxX - o.minX;}
		
		// Otherwise, we're using a traditional mathematical coordinate system
		} else {
			if (o.minX != null) {o.maxMouseX = -o.minX + et.clientX + x;}
			if (o.maxX != null) {o.minMouseX = -o.maxX + et.clientX + x;}
		}
		
		// If we're using the css coordinate system
		if (o.vmode) {
			// set the min and max coordinates, where applicable
			if (o.minY != null) {o.minMouseY = et.clientY - y + o.minY;}
			if (o.maxY != null) {o.maxMouseY = o.minMouseY + o.maxY - o.minY;}
		
		// Otherwise, we're using a traditional mathematical coordinate system
		} else {
			if (o.minY != null) {o.maxMouseY = -o.minY + et.clientY + y;}
			if (o.maxY != null) {o.minMouseY = -o.maxY + et.clientY + y;}
		}
		
		// Watch for 'dragging' and 'drag end' events
		Evnt.add(document, 'mousemove', Drag.drag);
		Evnt.add(document, 'mouseup', Drag.end);
		
		return false;
	},
	
	// A function to watch for all movements of the mouse druing the drag event
	drag: function(et) {
		// Get our reference to the element being dragged
		var o = Drag.obj;
		
		// Get the position of the mouse within the window
		var ey = et.clientY;
		var ex = et.clientX;
		
		// Get the current x and y coordinates
		var x = parseInt(o.hmode ? DOM.css(o.root, 'left') : DOM.css(o.root, 'right'));
		var y = parseInt(o.vmode ? DOM.css(o.root, 'top') : DOM.css(o.root, 'bottom'));
		var nx, ny;
		
		// If a minimum X position was set, make sure it doesn't go past that
		if (o.minX != null) {ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);}
		
		// If a maximum X position was set, make sure it doesn't go past that
		if (o.maxX != null) {ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);}
		
		// If a minimum Y postion was set, make sure it doesn't go past that
		if (o.minY != null) {ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);}
		
		// If a maximum Y postion was set, make sure it doesn't go past that
		if (o.maxY != null) {ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);}
		
		// Figure out the newly translated x and y coordinates
		nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
		ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));
		
		// and translate them using an x and y mapper function (if provided)
		if (o.xMapper) {nx = o.xMapper(y);}
		else if (o.yMapper) {ny = o.yMapper(x);}
		
		// Set the new x and y coordinates onto the element
		Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
		Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
		
		// and remember the last position of the mouse
		Drag.obj.lastMouseX = ex;
		Drag.obj.lastMouseY = ey;
		
		// Call the user's onDrag function with the current x and y coordinates
		Drag.obj.root.onDrag(nx, ny);
		
		return false;
	},
	
	// A function that handles the end of a drag event
	end: function() {
		// No longer watch for mouse events (as the drag is done)
		Evnt.remove(document, 'mousemove', Drag.drag);
		Evnt.remove(document, 'mouseup', Drag.end);
		
		// Call the user's onDragEnd function with the x and y coordinates
		// of the element at the end of the drag event
		Drag.obj.root.onDragEnd(
			parseInt(DOM.css(Drag.obj.root, Drag.obj.hmode ? "left" : "right")),
			parseInt(DOM.css(Drag.obj.root, Drag.obj.vmode ? "top" : "bottom")));
		// No longer watch the object for drags
		Drag.obj = null;
	}
};

// Reorder a list of elements by dragging
var Reorder = {
	obj: null,
	size: 0,
	ref: 0,
	
	start: function() {
			Reorder.obj = this;
			Reorder.size = DOM.fullHeight(this);
			Reorder.ref = DOM.pageY(this) - DOM.scrollY();
			
			Evnt.add(document, 'mousemove', Reorder.move);
			Evnt.add(document, 'mouseup', Reorder.end);
			return false;
	},
	
	move: function(et) {
		var o = Reorder.obj;
		var h = Reorder.size;
		var dy = et.clientY - Reorder.ref;
		
		var p = DOM.prev(o);
		var n = DOM.next(o);
		
		if (dy < 0 && p != null) {
			DOM.parent(o).insertBefore(o, p);
			o.onReorder && o.onReorder(o, p);
			Reorder.ref -= DOM.fullHeight(p);
		}
		
		else if (dy > h && n != null) {
			var nn = DOM.next(n);
			if (nn != null) {
				DOM.parent(o).insertBefore(o, nn);}
			else {
				DOM.parent(o).appendChild(o);}
			o.onReorder && o.onReorder(o, n);
			Reorder.ref += h;
		}
		
		return false;
	},
	
	end: function() {
		Evnt.remove(document, 'mousemove', Reorder.move);
		Evnt.remove(document, 'mouseup', Reorder.end);
		Reorder.obj = null;
		return false;
	}
};

/*--------------------------------------------------------------------------------*/
// addEvent/removeEvent written by Dean Edwards, 2005
// with input from Tino Zijdel
// http://dean.edwards.name/weblog/2005/10/add-event/

var Evnt = {
	guid: 1,
	
	add: function(elem,type,handler) {
		if (!elem) {return;}
		// assign each event handeler a unique ID
		if (!handler.$$guid) {handler.$$guid = this.guid++;}
		
		// create a hash table of event types for the element
		if (!elem.events) {elem.events = {};}
		
		// create a hash table of event handlers for each element/event pair
		var handlers = elem.events[type];
		if (!handlers) {
			handlers = elem.events[type] = {};
			
			// store the existing event handler (if there is one)
			if (elem["on" + type]) {handlers[0] = elem["on" + type];}
		}
		
		// store the event handler in the hash table
		handlers[handler.$$guid] = handler;
		
		// assign a global event handler to do all the work
		elem["on" + type] = this.handle;
	},
	
	remove: function(elem,type,handler) {
		// delete the event handler from the hash table
		if (elem.events && elem.events[type]) {delete elem.events[type][handler.$$guid];}
	},
	
	handle: function(et) {
		var returnValue = true;
		
		// grab the event object (IE uses global event object)
		et = Evnt.fixEvent(et);
		
		// get a reference to the hash table of event handlers
		var handlers = this.events[et.type];
		
		// execute each event handler
		for (var i in handlers) {
			this.$$handleEvent = handlers[i];
			if (this.$$handleEvent(et) === false) {returnValue = false;}
		}
		
		return returnValue;
	},
	
	// Add some "missing" methods to IE's event object
	fixEvent: function(et) {
		// If no event object exists, then this is IE, so provide IE's event object
		if (typeof et == 'undefined') {et = window.event;}
		
		// If the layer properties aren't set, get the values from the equivalent
		// offset properties
		if (typeof et.layerX == 'undefined') {et.layerX = et.offsetX;}
		if (typeof et.layerY == 'undefined') {et.layerY = et.offsetY;}
		if (typeof et.target == 'undefined') {et.target = et.srcElement;}
		
		// add W3C standard event methods
		if (typeof et.preventDefault == 'undefined') {
			et.preventDefault = function() {this.returnValue = false;};}
		if (typeof et.stopPropagation == 'undefined') {
			et.stopPropagation = function() {this.cancleBubble = true;};}
		
		return et;
	}
};

/*--------------------------------------------------------------------------------*/
// Internet Explorer fix for XMLHttpRequest support
if (typeof XMLHttpRequest == "undefined") {
	XMLHttpRequest = function() {
		try {
			// Internet Explorer uses an ActiveXObject to create a new XMLHttpRequest object
			return new ActiveXObject(
				// IE 5 uses a different XMLHTTP object from IE 6
				navigator.userAgent.indexOf("MSIE 5") >= 0 ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP"
			);
		} catch (ex) {
			return null;
		}
	};
}

// A generic function for performming Ajax requests
function ajax(options) {
	// Load the options with defaults, if no values were provided by the user
	options = {
		// The type of HTTP Request
		req: options.req || "GET",
		
		// The URL the request will be made to
		url: options.url || "",
		
		// How long to wait before considering the request to be a timeout
		timeout: options.timeout || 5000,
		
		// Functions to call when the request fails, succeeds, or complelets (either fails or succeed)
		onComplete: options.onComplete || function(){},
		onError: options.onError || function(){},
		onSuccess: options.onSuccess || function(){},
		
		// The data type that'll be returned from the server
		// the default is simply to determine what data was returned from the server and act accordingly
		type: options.type || ""
	};
	
	// Create the request object
	var xml = new XMLHttpRequest();
	
	// Open the asynchronous request
	//alert(options.url);
	xml.open(options.req,options.url,true);
	//xml.open("get","/illustrate.html",true);
	
	// Keep track of when the request has been successfully completed
	var requestDone = false;
	
	// Initialize a callback that will cancel the request (if it has not already occurred)
	setTimeout(function() {requestDone = true;}, options.timeout);
	
	// Watch for when the state of the document gets updated
	xml.onreadystatechange = function() {
		// Wait until the data is fully loaded and hasn't already timed out
		if (xml.readyState == 4 && !requestDone) {
			// Check to see if the request was successful
			if (httpSuccess(xml)) {
				// Execute the success callback with the data returned
				options.onSuccess(httpData(xml,options.type));
			} else {
				// Otherwise, an error occurred, so execute the error callback
				options.onError();
			}
			
			// Call the completion callback
			options.onComplete();
			
			// Clean up after ourselves, to avoid memory leaks
			xml = null;
		}
	};
	
	// Establish the connection to the server
	xml.send(null);
	
	// Determine the success of the Http response
	function httpSuccess(r) {
		try {
			// If no server status is provided, and we're actually requesting a local file, then it was successful
			return (!r.status && location.protocol == "file:") ||
			
				// Any status in the 200 range is good
				(r.status >= 200 && r.status < 300) ||
				
				// Successful if the document has not been modified
				(r.status == 304) ||
				
				// Safari returns an empty status if the file has not been modified
				(navigator.userAgent.indexOf("Safari") >= 0 && typeof r.status == "undefined");
		} catch(e){}
		
		// If checking the status failed, then assume that the request failed too
		return false;
	};
	
	// Extract the correct data from the HTTP response
	function httpData(r,type) {
		// Get the content-type header
		var ct = r.getResponseHeader("content-type");
		
		// If no default type was provided, determine if some form of XML was returned from the server
		var data = !type && ct && (ct.indexOf("xml") >= 0);
		
		// Get the XML Document object if XML was returned from the server, otherwise return the text contents returned by the server
		data = (type == "xml" || data) ? r.responseXML : r.responseText;
		
		// If teh specified type is "script", execute teh returned text response as if it was javascript
		if (type == "script") {eval.call(window,data);}
		
		// Return teh response data (either an XML Document of a text string)
		return data;
	};
};
		
		
		



