function isString(s){
	return (typeof s=="string")
}
function isCollection(a){return ((a != null && a != "undefined" && typeof(a) != "sting") ? ((!isNaN(a.length)) ? true : false) : false )}
function isArray(a){return (a instanceof Array)}
//function isHash(a){return (a instanceof Hash)}
function isObject(o){return (typeof o=="object")}
function isNumber(n){return ((typeof n=="number")&&(!isNaN(n))) }
function isFunction(f){return (typeof f=="function")}
function isBoolean(b){return (typeof b=="boolean")}
function isDefined(o){return ((typeof o!="undefined")&&(o!=null))}

var Detect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
Detect.init();

var Class = function(properties){
	// create the holding var for the new class
	var newClass = function(){
		// when the class is instantiated, fire the init function if it exists and return the new instance of the class that was created (Cat in above example)
		if (this.initialize && arguments[0] != 'noinit') return this.initialize.apply(this, arguments);
		else return this;
	};
	// copy the extended Class functions, and properties to the newClass (like extend)
	for (var property in this) newClass[property] = this[property];
	// copy the passed properties to newClass and return it
	newClass.prototype = properties;
	return newClass;
};

Class.empty = function(){};

Class.prototype = {
	extend: function(properties){
		// create a new instance of the newClass (Animal in above) this inherits all of it's attributes
		var pr0t0typ3 = new this('noinit');

		// parentize passes the initialize function from the newClass (Animal) to the child so it can be called
		var parentize = function(previous, current){
			// check if both are functions (initialize) all other functions should be set using implement
			if (!previous.apply || !current.apply) return false;
			
			return function(){
				// copy the parent's init func to "parent"
				this.parent = previous;
				// and the current init to the new Class
				return current.apply(this, arguments);
			};
		};

		for (var property in properties){
			var previous = pr0t0typ3[property];
			var current = properties[property];
			// if both properties exist and they're != then use the new one if they're both function, split them out using parentize
			if (previous && previous != current) current = parentize(previous, current) || current;
			// apply to holding Class
			pr0t0typ3[property] = current;
		}
		return new Class(pr0t0typ3);
	},

	implement: function(properties){
		// add all properties to "this"
		for (var property in properties) this.prototype[property] = properties[property];
	}

};

Object.Native = function(){
	for (var i = 0; i < arguments.length; i++) arguments[i].extend = Class.prototype.implement;
};

new Object.Native(Function, Array, String, Number, Class);
Object.inherit = function(target){
	var args = arguments;
	for(var i = 1; i < args.length; i++){
		for (var property in args[i]) target[property] = args[i][property];
	};
	return target;
};


function $(){
	if (arguments.length > 1 || isArray(arguments[0])) {
		for (var i = 0, out = []; i < arguments.length; i++){
			if ( isArray(arguments[i]) ){
				arguments[i].each(function(e){
					out.push($(e));
				});
			}else{
				out.push( $(arguments[i]) );
			}
		}
		return out;
	}
	if (typeof(arguments[0]) == 'string') return document.getElementById(arguments[0]);
	return null;
}
function $v(){
	var temp = $.apply(this,arguments);
	if (isArray(temp)) {
		var out = [];
		temp.each(function(e){
			if(!isDefined(e)){
				out.push( null );
			}else{
				out.push( e.value || e.innerHTML );
			}
		});
		return out;
	}
	if(!isDefined(temp)) return null;
	return temp.value || temp.innerHTML || null;
}


var Try = {
	these: function() {
		var o;
		for ( var i = 0; i < arguments.length; i++) {
			try {
				o = arguments[i]();
				break;
			} catch (e) {}
		};
		return o;
	}
};

function fireActions(obj){
	var args = arguments;
	for ( var i = 1; i < args.length; i++ ) {
		if(isArray(args[i])){
			args[i].each(function(e){
				e.apply(obj);
			});
		}else if( isFunction(args[i]) ){
			args[i].apply(obj);
		}
	}
};

String.extend({
	trim: function(){
		return this.replace(/^\s+|\s+$/g,"");
	}
});

Array.extend({
	first: function(){
		return this[0];
	},
	last: function(){
		return this[this.length-1];
	},
	each: function(func, inReverse){
		var output = [].concat(this);
		inReverse = inReverse == true;
		if(inReverse) output.reverse();
		for ( var i = 0; i < output.length; i++ ){
			var out = func(output[i], i);
			if ( out != null ) output[i] = out;
		}
		if(inReverse) output.reverse();
		return output;
	},
	find: function(func, numToReturn, fromRight){
		var out = [];
		numToReturn = ( numToReturn != null ) ?
			( numToReturn > 0 ) ? numToReturn : this.length
			: this.length;
		fromRight = fromRight == true;
		this.each(function(value, index){
			if ( func(value, index) ) out.push(value);
		}, fromRight);
		return (fromRight) ? out.slice(0,numToReturn).reverse() : out.slice(0,numToReturn);
	},
	compact: function(){
		return this.find(function(value){
			return (value != null && value != "");
		});
	},
	contains: function(){
		var args = arguments;
		var out = this.find(function(e){
			for(var i = 0; i < args.length; i++){
				if(e == args[i]) return true;
			}
			return false;
		});
		return out.length != 0;
	}
});

var QueryString = function(){
	var out = {};
	var qs = document.location.toString().split("?");
	if(!qs[1]) return {};
	qs = qs[1].split("#");
	qs = qs[0].split("&");
	qs.each(
		function(e){
			var e = e.split("=");
			out[e[0]] = unescape(e[1]);
		}
	);
	return out;
}();
