//-- table sort functions v1.2
	var g_order;
	function insAtTop(par, child, offSet){
		if(par.childNodes.length)
			par.insertBefore(child, par.childNodes[offSet]);
		else
			par.appendChild(child);
	}
	//row comparer method
	function compareRows(a,b){
		if(a.sortKey==b.sortKey)
			return 0;
		return (a.sortKey < b.sortKey) ? g_order : -g_order;
	}
	/* main function
		tableId : "ID" attribute of the table node to sort, or a node object inside that table
		colNo : 0-based number of the column to sort from, or a node object inside that column
		ord : 1 for ascending order, -1 for descending
		dataType : data type expected, can be '' 'number' or 'date'
	*/
	function sortTable(tableId, colNo, ord, dataType){
		var table, rows, nR, bs, i, j, temp, skipFirstRows, tempNodes, tempNode, tempValue;
		skipFirstRows=0;
		g_order=ord;
		//if colNo is a node, get its number in the table
		if (colNo.tagName) {
			tempNode = colNo;
			while (tempNode.tagName != 'TD' && tempNode.tagName != 'BODY')
				tempNode = tempNode.parentNode;
			if (tempNode.tagName == 'BODY') return;
			tempNodes = tempNode.parentNode.getElementsByTagName('TD');
			for (i=0; i<tempNodes.length; ++i)
				if (tempNodes[i] == tempNode) {
					colNo = i;
					break;
				}
			if (colNo.tagName) return;
		}
		g_colNo=colNo;
		// if tableId is a node, get the first parent table node, else get by id
		if (tableId.tagName) {
			table = tableId;
			while (table.tagName != 'TABLE' && table.tagName != 'BODY')
				table = table.parentNode;
			if (table.tagName == 'BODY') return;
		} else {
			table=document.getElementById(tableId);
		}
		rows=new Array();
		nR=0;
		bs=table.tBodies;
		for(i=0; i<bs.length; ++i)
			for(j=skipFirstRows; j<bs[i].rows.length; ++j){
				rows[nR]=bs[i].rows[j];
				temp=rows[nR].cells[g_colNo];
				rows[nR].sortKey='';
				if(temp) {
					if (temp.attributes.getNamedItem('sortingvalue')) {
						if (temp.attributes.item('sortingvalue'))
							rows[nR].sortKey=temp.attributes.item('sortingvalue').value;
					}
					if (rows[nR].sortKey=='') {
						rows[nR].sortKey=getFirstTextNode(temp);
					}
					if (dataType == 'number') {
    					var regExp = /[\+-]?[0-9\.,\  ]+/;
						var ms = regExp.exec(rows[nR].sortKey);
				        rows[nR].sortKey = -Infinity;
						if (ms) if (ms.length > 0)
						    rows[nR].sortKey = parseFloat(ms.join('').replace(',','.').replace(/[^0-9\.\+-]/g, ''));
					} else if (dataType == 'date') {
						var d = ParseDate(rows[nR].sortKey);
						if (d)
							rows[nR].sortKey = d
						else
							rows[nR].sortKey = new Date(100, 1, 1);
					}
				}
				++nR;
			}
		rows.sort(compareRows);
		for (i=0; i < rows.length; ++i) {
			insAtTop(table.tBodies[0], rows[i], skipFirstRows);
		}
	}
	//returns a string containing the first text found inside a node (recursively), or an empty string
	function getFirstTextNode(oNode) {
		var node, cnode, i, val;
		node = oNode
		for (i=0; i<node.childNodes.length; ++i) {
			cnode = node.childNodes[i];
			if (cnode.tagName) {
				val = getFirstTextNode(cnode);
				if (val) {return val}
			} else {
				return cnode.nodeValue;
			}
		}
		return '';
	}
	// moves a TR node up or down inside a table (first argument is any child node of the TR node)
	function SortRow(childElement, direction) {
		var trElement = childElement;
		while (trElement.tagName != 'TR' && trElement.tagName != 'BODY') trElement = trElement.parentNode;
		if (trElement.tagName != 'BODY') {
			var par = trElement;
			while (par.tagName != 'TBODY' && par.tagName != 'TABLE') par = par.parentNode;
			var trs = par.getElementsByTagName('TR');
			var i = 0;
			while (trs[i] != trElement)
				i += 1;
			if (direction == 1) {
				if (trs.length > i + 2) {
					par.insertBefore(trElement, trs[i + 2]);
				} else
					par.appendChild(trElement);
			} else if (direction == -1) {
				if (i > 1)
					par.insertBefore(trElement, trs[i - 1]);
			}
		}
	}

	function ParseDate(DateString) {
		var RegExpMatches = /[0-9]+\/[0-9]+\/[0-9]+(\ [0-9]+:[0-9]+(:[0-9]+(.[0-9]+)?)?)?/.exec(DateString);
		if (RegExpMatches.length > 0) {
			arr=RegExpMatches[0].split('/');
			var ret, arr, d, m, y, timeInfo, hr, mn, sc, ms, dt;
			hr = 0; mn = 0; sc = 0; ms = 0;
			d=parseInt(arr[0].replace(/^0/, ''));
			m=parseInt(arr[1].replace(/^0/, ''));
			if (arr[2].indexOf(' ') > 0) {
				timeInfo = arr[2].split(' ')[1];
				arr[2] = arr[2].split(' ')[0];
				if (timeInfo.indexOf(':') > 0) {
					timeInfo = timeInfo.split(':');
					hr = parseInt(timeInfo[0].replace(/^0/, ''));
					mn = parseInt(timeInfo[1].replace(/^0/, ''));
					if (timeInfo.length > 2) {
						sc = timeInfo[2];
						if (sc.indexOf('.') > 0) {
							ms = parseInt(sc.split('.')[1].replace(/^0/, ''));
							sc = sc.split('.')[0];
						}
						sc = parseInt(sc.replace(/^0/, ''));
					}
				}
			}
			y=parseInt(arr[2]);
			if (d && m && y) {
				dt=new Date(y, m-1, d, hr, mn, sc, ms);
				if (dt.getDate()==d && dt.getMonth()==(m-1) && ((dt.getYear()==y)||(dt.getFullYear()==y))) {
					return dt;
				}
			}
		}
	}
//-- /table sort functions
