		Array.prototype.swap=function(a, b)
		{
			var tmp=this[a];
			this[a]=this[b];
			this[b]=tmp;
		}
		 
		if(typeof Array.prototype.push != "function"){
			Array.prototype.push = ArrayPush;
			function ArrayPush(value){
				this[this.length] = value;
			}
		}
		
		String.prototype.trim = function () {
    	return this.replace(/^\s+|\s+$/g, "");
		};
		
		function partition(array, begin, end, pivot, propertyName)
		{
			var piv = (propertyName)?array[pivot][propertyName]:array[pivot];
			var piv2 = (propertyName)?array[pivot]['id']:array[pivot];
			array.swap(pivot, end-1);
			var store=begin;
			var ix;
			var other, other2;
			for(ix=begin; ix<end-1; ++ix) {
				other = ((propertyName)?array[ix][propertyName]:array[ix]);
				other2 = ((propertyName)?array[ix]['id']:array[ix]);
				if (other == piv)
				{
					if (other2 < piv2)
					{
						array.swap(store, ix);
						++store;
					}
				}
				else if((isNaN(other)||isNaN(piv))?other<piv:Number(other)<Number(piv)) {
					array.swap(store, ix);
					++store;
				}
			}
			array.swap(end-1, store);
		
			return store;
		} 

		function qsort(array, begin, end, propertyName)
		{
			if(end-1>begin) {
				var pivot=begin+Math.floor(Math.random()*(end-begin));
		
				pivot=partition(array, begin, end, pivot, propertyName);
		
				qsort(array, begin, pivot, propertyName);
				qsort(array, pivot+1, end, propertyName);
			}
		}
		
		function quick_sort(array, propertyName)
		{
			qsort(array, 0, array.length, propertyName);
		}

		Array.prototype.reverse=function()
		{
			var temp;
			for (var i = 0; i < Math.floor(this.length/2); i++)
			{
				temp = this[i];
				this[i] = this[this.length - (i + 1)];
				this[this.length - (i + 1)] = temp;
			}
		}

		Array.prototype.sort=function(propertyName, descending)
		{
			quick_sort(this, propertyName);
			if (descending) {
				this.reverse();
			}
			return this;
		}

		Array.prototype.getPropertyValues = function(propertyName) {
			var results = '';
			for (var i = 0; i < this.length; i++) {
				if (this[i][propertyName] && this[i][propertyName].trim().length != 0 ) {
					if (results.indexOf(this[i][propertyName]) == -1) {
						if (results == '') {
							results = this[i][propertyName];
						}
						else {
							results += ',' + this[i][propertyName];
						}
					}
				}
			}
			return results.split(',').sort();
		}
		
		document.getElementsByClassName = function(strClassName){
			var arrElements = (document.all) ? document.all : document.getElementsByTagName('*');
			var arrReturnElements = new Array();
			strClassName = strClassName.replace(/\-/g, "\\-");
			var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
			var oElement;
			for(var i=0; i<arrElements.length; i++){
				oElement = arrElements[i];
				if(oRegExp.test(oElement.className)){
					arrReturnElements.push(oElement);
				}
			}
			return (arrReturnElements);
		}
		
		function hasClass(node, className) {
			if (node.className && node.className.length != 0) {
				var classNames = node.className.split(' ');
				for (var i = 0; i < classNames.length; i++)
				{
					if (classNames[i] == className) {
						return true;
					}
				}
			}
			else return false;
		}
		
		function appendClass(node, newClassName) {
			if (!node.className || node.className.length == 0)
			{
				node.className = newClassName;
			}
			else
			{
				node.className = newClassName + ' ' + node.className;
			}
		}
		
		function removeClass(node, className) {
			if (node.className && node.className.length != 0) {
				var classNames = node.className.split(' ');
				node.className = '';
				for (var i = 0; i < classNames.length; i++)
				{
					if (classNames[i] != className) {
						if (node.className.length == 0)
						{
							node.className = classNames[i];
						}
						else
						{
							node.className += ' ' + classNames[i];
						}
					}
				}
			}
		}
		
		// content of your Javascript goes here
		function attachOnClicksToRows() {
			var elements = document.getElementsByTagName('th');
			for (var i = 0; i < elements.length; i++) {
				if(elements[i].parentNode.parentNode.tagName == 'THEAD')
				{
					elements[i].onclick = function() {
						if (sortCategory == this.id)
						{
							descending = !descending;
						}
						else
						{
							descending = false;
						}
						sortCategory = this.id;
						reloadTable();
					}			
				}
			}
			
			elements = document.getElementsByClassName('bikeRow');
			for (var i = 0; i < elements.length; i++) {
				if(elements[i].parentNode.tagName == 'TBODY')
				{
					elements[i].onclick = function() {
						document.getElementById('item-info-box').style.position = 'static';
						document.getElementById('item-info-box').style.visibility = 'visible';
						document.getElementById('item-info-title-text').innerHTML = database.getBike(this.id).manufacturer + ' - ' + database.getBike(this.id).name;
						if (database.getBike(this.id).image) {
							document.getElementById('item-info-pic-img').src='images/bikes/' + database.getBike(this.id).image;
						}
						else {
							document.getElementById('item-info-pic-img').src='images/question.png';
						}
						if (document.getElementById('item-info-spec')) {
							document.getElementById('item-info-spec').innerHTML = '';
							document.getElementById('item-info-spec').appendChild(database.createBikeSummary(this.id));
						}
						if (document.getElementById('item-info-spec-small')) {
							document.getElementById('item-info-spec-small').innerHTML = '';
							document.getElementById('item-info-spec-small').appendChild(database.createBikeSummary(this.id));
						}
						if (document.getElementById('item-info-tariff')) {
							document.getElementById('item-info-tariff').innerHTML = '';
							document.getElementById('item-info-tariff').appendChild(database.createBikeTariff(this.id));
						}
						if (document.getElementById('item-info-subtitle-text')) {
							document.getElementById('item-info-subtitle-text').innerHTML = '';
							if (database.getBike(this.id).price) {
								document.getElementById('item-info-subtitle-text').innerHTML = database.getBike(this.id).price;
							}
							else {
								document.getElementById('item-info-subtitle-text').innerHTML = 'Call us for a price';
							}
						}
						if (selectedBikeId && document.getElementById(selectedBikeId)) {
							removeClass(document.getElementById(selectedBikeId), 'selected-row');
						}
						selectedBikeId = this.id;
						this.className = 'bikeRow selected-row';
						pageSize = 6;
						reloadTable();
					}
				}
			}
		}
		
		function attachOnMouseOverToRows() {
			var elements = document.getElementsByClassName('bikeRow');
			for (var i = 0; i < elements.length; i++) {
				if(elements[i].parentNode.tagName == 'TBODY')
				{
					elements[i].onmouseover = function() {
						if (this.id != selectedBikeId) {
							appendClass(this, 'hover');
						}
					}
					elements[i].onmouseout = function() {
						if (this.id != selectedBikeId) {
							removeClass(this, 'hover');
						}
					}
				}
			}
		}
		
		function colourRows() {
			var elements = document.getElementsByClassName('bikeRow');
			for (var i = 1; i < elements.length; i = i+2) {
				if(elements[i].parentNode.tagName == 'TBODY' && elements[i].id != selectedBikeId)
				{
					elements[i].className = 'bikeRow even';
				}
			}
			for (var i = 0; i < elements.length; i = i+2) {
				if(elements[i].parentNode.tagName == 'TBODY' && elements[i].id != selectedBikeId)
				{
					elements[i].className = 'bikeRow odd';
				}
			}
			if (document.getElementById(selectedBikeId)) {
				document.getElementById(selectedBikeId).className = 'selected-row';
			}
		}
		
		Array.prototype.search=function(searchText, propertyName)
		{
			if (!searchText || searchText.trim().length == 0)
			{
				return this;
			}
			var results = [];
			for (var i = 0; i < this.length; i++) {
				if (propertyName) {
					if (this[i][propertyName].toUpperCase().indexOf(searchText) != -1) {
						results[results.length] = this[i];
					}
				}
				else {
					var actualPropertyName;
					for (actualPropertyName in this[i])
					{
						if (typeof this[i][actualPropertyName] == 'string')
						{
							if (this[i][actualPropertyName].toUpperCase().indexOf(searchText) != -1) {
								results[results.length] = this[i];
								break;								
							}
						}
					}
				}
			}
			return results;
		}

