//***************************************************//
//         Text sizing version .9                    //
//***************************************************//

var sizesArray = new Array("96%", "97%", "98%", "99%", "100%", "101%", "102%", "103%", "104%")
var sizePointer;
var ruleCounter;
// ruleCounter is used for Mozilla due to the necessity to write the new CSS rule in the last position so that it is applied.


if (getCookie("sizePref") != "") {
	sizePointer = Number(getCookie("sizePref"))
	// now apply the font
	if (document.styleSheets[0].cssRules) {
		ruleCounter = document.styleSheets[0].cssRules.length
	// Mozilla
	document.styleSheets[0].insertRule("* {font-size: " + sizesArray[sizePointer] + ";}", ruleCounter)
		//ruleCounter = ruleCounter + 1
	}
	else {
	//IE
	document.styleSheets[0].addRule("*", "{font-size: " + sizesArray[sizePointer] + ";}")
	}
}
else {
	sizePointer = 4;
}
var ie=false;
if (navigator.appName.indexOf("Microsoft") != -1){
	ie=true;
}
	


function getCookie(c_name)
{
if (document.cookie.length>0)
  {
  c_start=document.cookie.indexOf(c_name + "=")
  if (c_start!=-1)
    { 
    c_start=c_start + c_name.length+1 
    c_end=document.cookie.indexOf(";",c_start)
    if (c_end==-1) c_end=document.cookie.length
    return unescape(document.cookie.substring(c_start,c_end))
    } 
  }
return "";
}

function largerFont () {
	
	if (document.styleSheets[0].cssRules) {
	// Mozilla
		if (document.styleSheets[0].cssRules[0]) {
			if (sizePointer != 8) {
				ruleCounter = document.styleSheets[0].cssRules.length;
				sizePointer = sizePointer + 1;
				document.styleSheets[0].insertRule("* {font-size: " + sizesArray[sizePointer] + ";}", ruleCounter)
				//document.write('<style>* {font-size: ' + sizesArray[sizePointer] + ';}</style>');
				document.cookie = 'sizePref='+ sizePointer + '; path=/; domain=.hhs.gov';
			}
		}	
	}
	
	else if (document.styleSheets[0].rules) {
	// IE
		if (sizePointer < 8) {
			sizePointer = sizePointer + 1;
			document.cookie = 'sizePref='+ sizePointer + '; path=/; domain=.hhs.gov';
			document.styleSheets[0].addRule("*", "{font-size: " + sizesArray[sizePointer] + ";}")
			}
		}		
	}

function smallerFont () {	
	if (document.styleSheets[0].cssRules) {
		
	// Mozilla
		if (document.styleSheets[0].cssRules[0]) {	
			if (sizePointer != 0) {
				sizePointer = sizePointer - 1;
				ruleCounter = document.styleSheets[0].cssRules.length;
				document.styleSheets[0].insertRule("* {font-size: " + sizesArray[sizePointer] + ";}", ruleCounter)
				document.cookie = 'sizePref='+ sizePointer + '; path=/; domain=.hhs.gov';
			}
		}	
	}
	
	else if (document.styleSheets[0].rules) {
	// IE		
		if (sizePointer > 0) {
			sizePointer = sizePointer - 1;
			document.cookie = 'sizePref='+ sizePointer + '; path=/; domain=.hhs.gov';
			document.styleSheets[0].addRule("*", "{font-size: " + sizesArray[sizePointer] + ";}")
		}
	}
	
}


/******* SHOW/HIDE CONTENT **********/


function showHide(content) {
  if (document.getElementById(content).style.display == "none")
    document.getElementById(content).style.display = "block"
  else
    document.getElementById(content).style.display = "none"
}

/*** sortable tables *****/

function SortableTable (tableEl) {
 
	this.tbody = tableEl.getElementsByTagName('tbody');
	this.thead = tableEl.getElementsByTagName('thead');
	this.tfoot = tableEl.getElementsByTagName('tfoot');
 
	this.getInnerText = function (el) {
		if (typeof(el.textContent) != 'undefined') return el.textContent;
		if (typeof(el.innerText) != 'undefined') return el.innerText;
		if (typeof(el.innerHTML) == 'string') return el.innerHTML.replace(/<[^<>]+>/g,'');
	}
 
	this.getParent = function (el, pTagName) {
		if (el == null) return null;
		else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
			return el;
		else
			return this.getParent(el.parentNode, pTagName);
	}
 
	this.sort = function (cell) {
 
	    var column = cell.cellIndex;
	    var itm = this.getInnerText(this.tbody[0].rows[1].cells[column]);
		var sortfn = this.sortCaseInsensitive;
 
		if (itm.match(/\d\d[-]+\d\d[-]+\d\d\d\d/)) sortfn = this.sortDate; // date format mm-dd-yyyy
		if (itm.replace(/^\s+|\s+$/g,"").match(/^[\d\.]+$/)) sortfn = this.sortNumeric;
 
		this.sortColumnIndex = column;
 
	    var newRows = new Array();
	    for (j = 0; j < this.tbody[0].rows.length; j++) {
			newRows[j] = this.tbody[0].rows[j];
		}
 
		newRows.sort(sortfn);
 
		if (cell.getAttribute("sortdir") == 'down') {
			newRows.reverse();
			cell.setAttribute('sortdir','up');
		} else {
			cell.setAttribute('sortdir','down');
		}
 
		for (i=0;i<newRows.length;i++) {
			this.tbody[0].appendChild(newRows[i]);
		}
 
	}
 
	this.sortCaseInsensitive = function(a,b) {
		aa = thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]).toLowerCase();
		bb = thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]).toLowerCase();
		if (aa==bb) return 0;
		if (aa<bb) return -1;
		return 1;
	}
 
	this.sortDate = function(a,b) {
		aa = thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]);
		bb = thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]);
		date1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
		date2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
		if (date1==date2) return 0;
		if (date1<date2) return -1;
		return 1;
	}
 
	this.sortNumeric = function(a,b) {
		aa = parseFloat(thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]));
		if (isNaN(aa)) aa = 0;
		bb = parseFloat(thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]));
		if (isNaN(bb)) bb = 0;
		return aa-bb;
	}
 
	// define variables
	var thisObject = this;
	var sortSection = this.thead;
 
	// constructor actions
	if (!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length > 0)) return;
 
	if (sortSection && sortSection[0].rows && sortSection[0].rows.length > 0) {
		var sortRow = sortSection[0].rows[0];
	} else {
		return;
	}
 
	for (var i=0; i<sortRow.cells.length; i++) {
		sortRow.cells[i].sTable = this;
		sortRow.cells[i].onclick = function () {
			this.sTable.sort(this);
			return false;
		}
	}
 
}

//***************************************************//
//        JUMP TO SPECIFIC PAGE                      //
//***************************************************//

function jumpToPageAction(sel){
window.location = sel.options[sel.selectedIndex].value;
}


//***************************************************//
//        TABLE STRIPING                             //
//***************************************************//

 // this function is needed to work around 
  // a bug in IE related to element attributes
  function hasClass(obj) {
     var result = false;
     if (obj.getAttributeNode("class") != null) {
         result = obj.getAttributeNode("class").value;
     }
     return result;
  }   

 function stripeTables(id) {

    // the flag we'll use to keep track of 
    // whether the current row is odd or even
    var even = false;
  
	// Set the alternate color in the method call arguments
	var evenColor; 

	// hard coded here and applies to all tables.
	/*
	*********
	*********
	*/
	
    var oddColor = "rgb(255, 255, 255)";
	
    /*
	*********
	*********
	*/ 
	// hard coded here and applies to all tables.
 
	 // Populate 2 arrays with the arguments,
	 // separating the colors from the ID's.
	 var colorArray = new Array();
	 var cArrayCount = 0;
	 
	 var IdArray = new Array();
	 var IdArrayCount = 0;
	 
	 // This script assumes that the arguements always
	 // come in pairs: ID / evenColor. So the first
	 // argument will always be the ID.
	 for (i_id = 0; i_id < arguments.length; i_id++) {
	 	
		// Since the function arguments are formatted in ID/color pairs,
		// and the first argument is an ID, when %2 == 0 
		// it will be a element ID and not a color.
		if (i_id%2 == 0) {
			IdArray[IdArrayCount] = arguments[i_id];
			IdArrayCount++;
		}
		else {
			colorArray[cArrayCount] = arguments[i_id];
			cArrayCount++;			
		}
	 }
	 // Populate 2 arrays with arguments
	 
	 
	 
	 
	 /*
	 // Testing code for the arrays
	 alert("Color Array has: "+ colorArray.length);
	 alert("ID Array has: "+IdArray.length);
	 
	 for (a = 0; a < colorArray.length; a++) {
	 	alert(colorArray[a]);	 	
	 }
	 
	  for (a = 0; a < IdArray.length; a++) {
	 	alert(IdArray[a]);	 	
	 }
	 // Testing code for the arrays
	 */
	 
	
	
	 // color the rows for each table as defined in the function arguments
	 for (a = 0; a < IdArray.length; a++) {	 	 
		  		 
		 	     evenColor = colorArray[a]; 		
		 			 
		 		// obtain a reference to the desired table
				// if no such table exists, abort
				var table = document.getElementById(IdArray[a]);
				if (! table) { return; }		 
				
				
				// by definition, tables can have more than one tbody
				// element, so we'll have to get the list of child
				// &lt;tbody&gt;s 
				var tbodies = table.getElementsByTagName("tbody");
			
				// and iterate through them...
				for (var h = 0; h < tbodies.length; h++) {
				
				 // find all the &lt;tr&gt; elements... 
				  var trs = tbodies[h].getElementsByTagName("tr");
				  
				  // ... and iterate through them
				  for (var i = 0; i < trs.length; i++) {
			
					// avoid rows that have a class attribute
					// or backgroundColor style
					if (! hasClass(trs[i]) &&
						! trs[i].style.backgroundColor) {
					  
					  // get all the cells in this row...
					  var tds = trs[i].getElementsByTagName("td");
					
					  // and iterate through them...
					  for (var j = 0; j < tds.length; j++) {
					
						var mytd = tds[j];
			
						// avoid cells that have a class attribute
						// or backgroundColor style
						if (! hasClass(mytd) &&
							! mytd.style.backgroundColor) {
					
						  mytd.style.backgroundColor =
							even ? evenColor : oddColor;
						
						}
					  }
					}
					// flip from odd to even, or vice-versa
					even =  ! even;
				  }
				}
		} // for loop		
  }


//***************************************************//
//        SORTABLE TABLES                            //
//***************************************************//

/*
License:
 You can do whatever you want with the script, but at any time (whether for your
 own usage or if you modify it and redistribute your modified version), you must
 include the "Authors" and this "License" sections in your copy (modified or not)
 of this script. You may delete any other comment section or modify the script.
 BTW, also note that no warranty is provided and as with most freewares - use it
 at your own risk! ;)

Authors:
 Mingyi Liu (http://mingyi.org) wrote this script initially based upon an
 excellent script by Stuart Langridge. But now this script is so much beyond
 what that original script offered.  I made very significant improvements not
 only to vastly improve the features, but also fixed/improved the sorting
 algorithms to develope it into by far the most advanced and feature-rich table
 sorting script on the net (and even created a firefox extension out of it!).

*/

var ts_version = "1.25";
var ts_browser_agt = navigator.userAgent.toLowerCase();   
var ts_browser_is_ie = ((ts_browser_agt.indexOf("msie") != -1) && (ts_browser_agt.indexOf("opera") == -1));

var ml_tsort = {
  ///////////////////////////////////////////////////
  // configurable constants, modify as needed!
  sort_col_title : "Click here to sort.",
  sort_col_class : "", // whichever class you want the heading to be
  sort_col_style : "text-decoration:none; font-weight:bold; color:black", // whichever style you want the link to look like
  sort_col_mouseover : "this.style.color='blue'", // what style the link should use onmouseover?
  sort_col_mouseout : "this.style.color='black'", // what style the link should use onmouseover?
  use_ctrl_alt_click : true, // allow ctrl-alt-click anywhere in table to activate sorting?
  sort_only_sortable : true, // make all tables sortable by default or just make the tables with "sortable" class sortable?
  
  //////////////////////////////////////////////////
  // speed related constants, modify as needed!
  table_content_might_change : false, // table content could be changed by other JS on-the-fly? if so, some speed improvements cannot be used.
  preserve_style : "", // (row, cell) preserves style for row or cell e.g., row is useful when the table highlights rows alternatively. cell is much slower while no preservation's the fastest by far!
  tell_me_time_consumption : false, // give stats about time consumed during sorting and table update/redrawing.
  
  //////////////////////////////////////////////////////////
  // anything below this line, modify at your own risk! ;)
  smallest_int : -2147483648000, // date parse is in milliseconds, hence the 000
  set_vars : function(event)
  {
    var e = (event)? event : window.event;
    var element = (event)? ((event.target)? event.target : event.srcElement) : window.event.srcElement;
    var clicked_td = ml_tsort.getParent(element,'TD') || ml_tsort.getParent(element,'TH');
    var table = ml_tsort.getParent(element,'TABLE');
    if(!table || table.rows.length < 1 || !clicked_td) return;
    var column = clicked_td.cellIndex;
    if (e.altKey && e.ctrlKey && ml_tsort.use_ctrl_alt_click) ml_tsort.resortTable(table.rows[0].cells[column]);
  },

  makeSortable: function(table) 
  {
      if (table.rows && table.rows.length > 0) {
          var rowidx = table.getAttribute("ts_linkrow") || 0;
          var firstRow = table.rows[rowidx];
      }
      if (!firstRow) return;
      var sortCell;
      // We have a first row: assume it's the header (it works for <thead> too), 
      // and make its contents clickable links
      for (var i=0;i<firstRow.cells.length;i++) {
          var cell = firstRow.cells[i];
//           var txt = this.getInnerText(cell);
          var txt = cell.innerHTML;
          if(cell.getAttribute("sortdir")) sortCell = cell;
          cell.innerHTML = '<a style="'+this.sort_col_style+'" onMouseOver="'+this.sort_col_mouseover+'" onMouseOut="'+this.sort_col_mouseout+'" class="'+this.sort_col_class+'" href="#" title="'+this.sort_col_title+'" onclick="javascript:ml_tsort.resortTable(this.parentNode);return false">'+txt+'</a>';
      }
      if(sortCell) this.resortTable(sortCell);
  },
  
  sortables_init : function() 
  {
      // Find all tables with class sortable and make them sortable
      if (!document.getElementsByTagName) return;
      var tbls = document.getElementsByTagName("table");
      for (var ti=0;ti<tbls.length;ti++) {
          thisTbl = tbls[ti];
          if(!ml_tsort.sort_only_sortable || thisTbl.className.match(/sortable/i))
            ml_tsort.makeSortable(thisTbl);
      }
  },
  
  getParent : function(el, pTagName) 
  {
  	if (el == null) return null;
  	else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())	// Gecko bug, supposed to be uppercase
  		return el;
  	else
  		return this.getParent(el.parentNode, pTagName);
  },
  
  getInnerText : function(el) 
  {
  	if (typeof el == "string") return el;
  	if (typeof el == "undefined") { return el };
  	if (el.innerText) return el.innerText;	//Not needed but it is faster
  	var str = "";
  	
  	var cs = el.childNodes;
  	var l = cs.length;
  	for (var i = 0; i < l; i++) {
  		switch (cs[i].nodeType) {
  			case 1: //ELEMENT_NODE
  				str += this.getInnerText(cs[i]);
  				break;
  			case 3:	//TEXT_NODE
  				str += cs[i].nodeValue;
  				break;
  		}
  	}
  	return str;
  },
  
  match_date_format : function(value, format)
  {
    var v = this.getInnerText(value.cells[this.sort_column_index]);
    this.set_date_array(format);
    if(format == 'M/D/Y' && !isNaN(Date.parse(v)))
      return true;
    else if(!isNaN(this.convert_date(v))) return true;
    this.set_date_array(format.replace(/\//g, '-'));
    if(!isNaN(this.convert_date(v))) return true;
    this.set_date_array(format.replace(/\//g, '.'));
    if(!isNaN(this.convert_date(v))) return true;
    this.set_date_array(format.replace(/\//g, ' '));
    if(!isNaN(this.convert_date(v))) return true;
    return false;
  },
    
  resortTable : function(td) 
  {
    if(td == null) return;
    var column = td.cellIndex;
    var table = this.getParent(td,'TABLE');
    this.sort_column_index = column;
    if(table == null || table.rows.length <= 2) return;

    // now let's do a lot just to save a little time, if possible at all. ;)
    var lastSortCell = table.getAttribute("ts_sortcell") || 0;
    lastSortCell--; // the processing is used for IE, which treats no attribute as 0, while FF treats 0 as still true.
    var lastSortDir = (table == this.last_sorted_table && column == lastSortCell)? table.getAttribute("ts_sortdir") : 'desc';

    var newRows = new Array();
    var headcount = 1;
    for (var i=0,j=1;j<table.rows.length;j++)
    {
      var t = table.rows[j].parentNode.tagName.toLowerCase();
      if(t == 'tbody' && table.rows[j].cells.length >= column + 1) newRows[i++] = table.rows[j];
      else if(t == 'thead') headcount++;
    }
    if(newRows.length == 0) return;
    var time2 = new Date();
  
    // check if we really need to sort
    if(!this.table_content_might_change && table == this.last_sorted_table && column == lastSortCell)
      newRows.reverse();
    else
    {
      // Work out a type for the column
      var sortfn, type = td.getAttribute("ts_type");
      this.replace_pattern = '';
      var itm, i;
      for(i = 0; i < newRows.length; i++)
      {
        itm = this.getInnerText(newRows[i].cells[column]);
        if(itm.match(/\S/)) break;
      }
      if(i == newRows.length) return;
      itm = ml_trim(itm);
      if(!type)
      {
        sortfn = this.sort_caseinsensitive;

        if (this.match_date_format(newRows[i], 'M/D/Y')) sortfn = this.sort_date;
        else if (itm.match(/^[???$]/)) sortfn = this.sort_currency;
        else if (itm.match(/^\d{1,3}(\.\d{1,3}){3}$/)) sortfn = this.sort_ip;
        else if (itm.match(/^[+-]?\s*[0-9]+(?:\.[0-9]+)?(?:\s*[eE]\s*[+-]?\s*\d+)?$/))
          sortfn = this.sort_numeric;
      }
      else if(type == 'date' && this.match_date_format(newRows[i], 'M/D/Y')) sortfn = this.sort_date;
      else if(type == 'euro_date' && this.match_date_format(newRows[i], 'D/M/Y')) sortfn = this.sort_date;
      else if(type == 'other_date' && this.match_date_format(newRows[i], td.getAttribute("ts_date_format"))) sortfn = this.sort_date; 
      else if(type == 'number') sortfn = this.sort_numeric;
      else if(type == 'ip') sortfn = this.sort_ip;
      else if(type == 'money') sortfn = this.sort_currency;
  //       else if(type == 'custom') sortfn = function(aa,bb) { a = this.getInnerText(aa.cells[this.sort_column_index]); b = this.getInnerText(bb.cells[this.sort_column_index]); eval(td.getAttribute("ts_sortfn")) }; // the coding here is shorter but interestingly it's also slower
      else if(type == 'custom') { this.custom_code = td.getAttribute("ts_sortfn"); sortfn = this.custom_sortfn }
      else { alert("unsupported sorting type or data not matching indicated type!"); return; }
  
      table.setAttribute("ts_sortcell", column+1);
      newRows.sort(sortfn);
      if (lastSortDir == 'asc') newRows.reverse();
    }
    if (lastSortDir == 'desc') table.setAttribute('ts_sortdir','asc');
    else table.setAttribute('ts_sortdir','desc');
  
    this.last_sorted_table = table;
       
    var time3 = new Date();
    
    var ps = table.getAttribute("preserve_style") || this.preserve_style;
    if(ps == 'row' && !ts_browser_is_ie) 
    {
      var tmp = new Array(newRows.length);
      for (var i = 0; i < newRows.length; i++) tmp[i] = newRows[i].innerHTML;
      for (var i = 0; i < newRows.length; i++) table.rows[i+headcount].innerHTML = tmp[i];
    }
    else if(ps == 'cell' || (ps == 'row' && ts_browser_is_ie)) 
    {
      var tmp = new Array(newRows.length);
      for (var i = 0; i < newRows.length; i++)
        for (var j = 0; j < newRows[i].cells.length; j++)
        {
          if(!tmp[i]) tmp[i] = new Array(newRows[i].cells.length);
          tmp[i][j] = newRows[i].cells[j].innerHTML;
        }
      for (var i = 0; i < newRows.length; i++)
        for (var j = 0; j < newRows[i].cells.length; j++)
          table.rows[i+headcount].cells[j].innerHTML = tmp[i][j];
    }
    else
    {
      for (var i=0;i<newRows.length;i++) // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
        table.tBodies[0].appendChild(newRows[i]);
    } 
    var time4 = new Date();
    if(this.tell_me_time_consumption)
    {
      alert('it took ' + this.diff_time(time3, time2) + ' seconds to do sorting!');
      alert('it took ' + this.diff_time(time4, time3) + ' seconds to do redrawing!');
    }
    return false;
  },
  
  diff_time : function(time2, time1) 
  {
    return (time2.getTime() - time1.getTime())/1000;
  },
  
  // Mingyi Note: it seems ridiculous to do so much processing for
  // customizable date conversion, should try to find a zbetter way
  // of doing it.
  set_date_array : function(f) 
  {
    var tmp = [['D', f.indexOf('D')], ['M', f.indexOf('M')], ['Y', f.indexOf('Y')]];
    tmp.sort(function(a,b){ return a[1] - b[1]});
    this.date_order_array = new Array(3);
    for(var i = 0; i < 3; i++) this.date_order_array[tmp[i][0]] = '$' + (i + 2);
    this.replace_pattern = f.replace(/[DMY]([^DMY]+)[DMY]([^DMY]+)[DMY]/, '^(.*?)(\\d+)\\$1(\\d+)\\$2(\\d+)(.*)$');
  },
  
  process_year : function(y) 
  {
    var tmp = parseInt(y);
    if(tmp < 32) return '20' + y; 
  	else if(tmp < 100) return '19' + y;
  	else return y;
  },
  
  // convert to MM/DD/YYYY (or M/D/YYYY) format
  convert_date : function(a) 
  {
    var re = 'RegExp.$1+RegExp.'+this.date_order_array['M']+'+\'/\'+RegExp.'+this.date_order_array['D']+'+\'/\'+this.process_year(RegExp.'+this.date_order_array['Y']+')+RegExp.$5';
    var code = 'if(a.match(/'+this.replace_pattern+'/)) (' + re + ')';
    return Date.parse(eval(code));
  },
  
  sort_date : function(a,b) 
  {
    var atext = ml_tsort.getInnerText(a.cells[ml_tsort.sort_column_index]);
    var btext = ml_tsort.getInnerText(b.cells[ml_tsort.sort_column_index]);
    var aa, bb;
    // basically I have to do the conversion due to the potential usage of double digit years
    if(atext && atext.match(/\S/))
    {
      aa = ml_tsort.convert_date(atext);
      if(isNaN(aa)) aa = Date.parse(atext);
      if(isNaN(aa)) aa = 0;
    }
    else aa = ml_tsort.smallest_int;
    if(btext && btext.match(/\S/))
    {
      bb = ml_tsort.convert_date(btext);
      if(isNaN(bb)) bb = Date.parse(btext);
      if(isNaN(bb)) bb = 0;
    }
    else bb = ml_tsort.smallest_int;
    return aa - bb;
  },
  
  // assume no scientific number in currency (if assumption incorrect, just use
  // same code for this.sort_numeric will do)
  sort_currency : function(a,b) 
  { 
      return ml_tsort.sort_num(ml_tsort.getInnerText(a.cells[ml_tsort.sort_column_index]).replace(/[^-0-9.+]/g,''),
                         ml_tsort.getInnerText(b.cells[ml_tsort.sort_column_index]).replace(/[^-0-9.+]/g,''));
  },
  
  // let's allow scientific notation but also be strict on number format
  sort_num : function(a, b) 

  {
      var aa, bb;
      if(a && a.match(/\S/))
      {
        if(!isNaN(a)) aa = a;
        else if(a && a.match(/^[^0-9.+-]*([+-]?\s*[0-9]+(?:\.[0-9]+)?(?:\s*[eE]\s*[+-]?\s*\d+)?)/))
          aa = parseFloat(RegExp.$1.replace(/\s+/g, ''));
        else aa = 0;
      }
      else aa = ml_tsort.smallest_int;
      if(b && b.match(/\S/))
      {
        if(!isNaN(b)) bb = b;
        else if(b && b.match(/^[^0-9.+-]*([+-]?\s*[0-9]+(?:\.[0-9]+)?(?:\s*[eE]\s*[+-]?\s*\d+)?)/))
          bb = parseFloat(RegExp.$1.replace(/\s+/g, ''));
        else bb = 0;
      }
      else bb = ml_tsort.smallest_int;
      return aa - bb;
  },
  
  sort_numeric : function(a,b) 
  {
      return ml_tsort.sort_num(ml_tsort.getInnerText(a.cells[ml_tsort.sort_column_index]),
                         ml_tsort.getInnerText(b.cells[ml_tsort.sort_column_index])); 
  },
  
  sort_ip : function(a,b) 
  {
      var aa = ml_tsort.getInnerText(a.cells[ml_tsort.sort_column_index]).split('.');
      var bb = ml_tsort.getInnerText(b.cells[ml_tsort.sort_column_index]).split('.');
      return ml_tsort.sort_num(aa[0], bb[0]) || ml_tsort.sort_num(aa[1], bb[1]) || 
             ml_tsort.sort_num(aa[2], bb[2]) || ml_tsort.sort_num(aa[3], bb[3]);
  },
   
  sort_caseinsensitive : function(a,b) 
  {
      var aa = ml_tsort.getInnerText(a.cells[ml_tsort.sort_column_index]).toLowerCase();
      var bb = ml_tsort.getInnerText(b.cells[ml_tsort.sort_column_index]).toLowerCase();
      if (aa==bb) return 0;
      if (aa<bb) return -1;
      return 1;
  },
  
  custom_sortfn : function(aa,bb) 
  {
    var a = ml_tsort.getInnerText(aa.cells[ml_tsort.sort_column_index]);
    var b = ml_tsort.getInnerText(bb.cells[ml_tsort.sort_column_index]);
    return eval(ml_tsort.custom_code);
  }
};

function ml_trim(text)
{
  if(!text) return text;
  var tmp = text.replace(/^\s+/, '');
  return tmp.replace(/\s+$/, '');
}

function ts_addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
{
  if (elm.addEventListener){
    elm.addEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.attachEvent){
    var r = elm.attachEvent("on"+evType, fn);
    return r;
  } else {
    alert("Handler could not be removed");
  }
}
ts_addEvent(document, "click", ml_tsort.set_vars);
ts_addEvent(window, "load", ml_tsort.sortables_init);



//GOOGLE ANALYTICS CODE

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-18143375-1']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();


