Prettier JQuery tables
Prettier JQuery tables

file:a/about.php -> file:b/about.php
--- a/about.php
+++ b/about.php
@@ -1,6 +1,55 @@
+<?php

+

+

+include('./lib/common.inc.php');

+include_header("Map");

+?>

+

+<div class="msg_list">

+<p class="msg_head">Header-1 </p>

+<div class="msg_body">

+orem ipsum dolor sit amet, consectetuer adipiscing elit orem ipsum dolor sit amet, consectetuer adipiscing elit

+</div>

+<p class="msg_head">Header-2</p>

+<div class="msg_body">

+orem ipsum dolor sit amet, consectetuer adipiscing elit orem ipsum dolor sit amet, consectetuer adipiscing elit

+</div>

+<p class="msg_head">Header-3</p>

+<div class="msg_body">

+orem ipsum dolor sit amet, consectetuer adipiscing elit orem ipsum dolor sit amet, consectetuer adipiscing elit

+</div>

+</div>

+

 sourced from austender

 Government Agency Information (2009-07-10): National Archives of Australia, http://www.naa.gov.au under Creative Commons - Attribution 2.5 Australia (CC-BY)

 jpgraph for php

 ABR

 Redhat Liberation fonts

-
+

+

+<?php

+include_once("./lib/common.inc.php");

+$query = "SELECT DATE(importDate) as importday, count(*) as count, min(publishDate) as start, max(publishDate) as end 

+FROM `contractnotice` WHERE childCN = 0 AND parentCN = 0 AND DATE(importDate) in (select * from (SELECT DATE(importDate) 

+FROM `contractnotice` ORDER BY `importDate` DESC limit 1) alias)";

+$result = mysql_query($query);

+echo "<div>";

+$stats = mysql_fetch_array($result, MYSQL_BOTH);

+echo $stats["count"] . " new records in period " . $stats["start"] . "  to " . $stats["end"] ."<br>";

+

+

+$query = "SELECT DATE(importDate) as importday, count(*) as count, min(publishDate) as start, max(publishDate) as end 

+FROM `contractnotice` WHERE (childCN != 0 OR parentCN != 0) AND DATE(importDate) in (select * from (SELECT DATE(importDate) 

+FROM `contractnotice` ORDER BY `importDate` DESC limit 1) alias)";

+$result = mysql_query($query);

+echo "<div>";

+$stats = mysql_fetch_array($result, MYSQL_BOTH);

+echo $stats["count"] . " updated records in period " . $stats["start"] . "  to " . $stats["end"] ."<br>";

+

+

+echo "Last updated: ". $stats["importday"]."<br>";

+/* Check for null Procurement method and 0 ABN when not ABN exempt */

+

+

+include_footer();

+?>

--- a/admin/abr-example.php
+++ b/admin/abr-example.php

--- /dev/null
+++ b/admin/agency2portfolio.php
@@ -1,1 +1,42 @@
+<?php
 
+// Returns portfolio scraped live from directory.gov.au
+// or null if can't find a portfolio
+function agency2portfolio ($agency) {
+	static $cache = array();
+	if (isset($cache[$agency])) { return $cache[$agency]; }
+	$c = curl_init('http://www.directory.gov.au/searchres.php');
+	curl_setopt($c, CURLOPT_POST, true);
+	curl_setopt($c, CURLOPT_HEADER, false);
+	curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
+	curl_setopt($c, CURLOPT_REFERER, 'http://www.directory.gov.au/adsearch.php');
+	curl_setopt($c, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3');
+	curl_setopt($c, CURLOPT_POSTFIELDS, array(
+		'advkeywordfield' => '',
+		'advorgunitfield' => $agency,
+		'advrolefield' => '',
+		'advsection' => 'All',
+		'advsurnamefield' => '',
+		'search' => 'Submit Query'
+	));
+	$results = curl_exec($c);
+	
+	if (preg_match('#<span\s+class="standardlinks"><a\s+href="([^"]+)">#smi', $results, $m)) {
+		$nextURL = $m[1];
+	} else {
+		$cache[$agency] = false; return false;
+	}
+	
+	curl_setopt($c, CURLOPT_URL, 'http://www.directory.gov.au' . $nextURL);
+	curl_setopt($c, CURLOPT_HTTPGET, true);
+	curl_setopt($c, CURLOPT_REFERER, 'http://www.directory.gov.au/searchres.php');
+	$results = curl_exec($c);
+	if (preg_match('#portfolios:\s+([^<]+)#ims', $results, $m)) {
+		$cache[$agency] = $m[1]; return $m[1];
+	} else {
+		$cache[$agency] = false; return false;
+	}
+}
+
+?>
+

 Binary files a/admin/cmd.exe.lnk and b/admin/cmd.exe.lnk differ
--- a/admin/convertToThematicMapping.php
+++ b/admin/convertToThematicMapping.php

--- /dev/null
+++ b/admin/displayRepresentatives.php
@@ -1,1 +1,7 @@
+SELECT representative_id,firstname,surname,party,house,division_id,	portfolio
+FROM portfolio2representative
+INNER JOIN representatives
+ON portfolio2representative.representative_id=representatives.id
+INNER JOIN portfolios
+ON portfolio2representative.portfolio_id=portfolios.id
 

--- /dev/null
+++ b/admin/displayUNSPSC.php
@@ -1,1 +1,25 @@
+<?php

+error_reporting(E_ALL);

+

+$link = mysql_connect('localhost', 'team7', 'wlUsnD2xu9');

+if (!$link) {

+    die('Could not connect: ' . mysql_error());

+}

+@mysql_select_db("team7") or die("Unable to select database");

+

+$unspscresult = mysql_query ("select * from UNSPSCcategories;");

+while ($row = mysql_fetch_assoc($unspscresult)) {

+	$unspsc[$row['UNSPSC']] = $row['Title'];

+}

+$catsresult = mysql_query ("SELECT LEFT( categoryUNSPSC, 2 ) as cat , SUM( value ) as value

+FROM `contractnotice`

+GROUP BY cat ;");

+echo "<table>";

+while ($row = mysql_fetch_assoc($catsresult)) {

+	$catName = $unspsc[$row['cat']."000000"].$row['cat'];

+	if ($row['cat'] = "") $catName = "null";

+	

+	echo "<tr><td>$catName</td><td>".$row['value']."</td></tr>";

+}

+?>

 

--- a/admin/google-example.htm
+++ b/admin/google-example.htm

--- a/admin/google-example.php
+++ b/admin/google-example.php

--- a/admin/import.bat
+++ b/admin/import.bat

--- a/admin/import.php
+++ b/admin/import.php
@@ -1,119 +1,113 @@
 <?php
-include_once("../lib/common.inc.php");
-$path = '../data/';
-if ($_REQUEST["fname"] == "") {
-echo "Get files from: https://www.tenders.gov.au/?event=public.reports.list<br>";
-$dhandle = opendir($path);
-// define an array to hold the files
-$files = array();
-
-if ($dhandle) {
-   // loop through all of the files
-   while (false !== ($fname = readdir($dhandle))) {
-      if (($fname != '.') && ($fname != '..')) {
-	  echo "<a href=\"import.php?fname=$fname\">$fname</a>".filesize($path.$fname)."<br/>";
-	  }
-	}
-}
-
-} else {
-$success =0;
-$fname = $_REQUEST["fname"];
-echo " ============== $fname  ============== <br>";
-$row = 1;
-$handle = fopen($path.$fname, "r"); 
-//"t" mode string translates windows line breaks to unix
-$datamapping0709 = Array("Agency" => "agencyName", "Parent CN ID" => "parentCN", "CN ID" => "CNID", "Publish Date" => "publishDate", "Amendment Date" => "amendDate", "Status" => "", "StartDate" => "contractStart" , "EndDate" => "contractEnd", "Value" => "value", "Description" => "description",  "Agency Ref Id" => "agencyID", "Category" => "category", "Procurement Method" => "procurementMethod", "ATM ID" => "atmID", "SON ID" => "SONID","Confidentiality - Contract" => "confidentialityContract", "Confidentiality - Contract Reason(s)" => "confidentialityContractReason", "Confidentiality - Outputs" => "confidentialityOutputs", "Confidentiality - Outputs Reason(s)" => "confidentialityOutputsReason", "Consultancy" => "consultancy", "Consultancy Reason(s)" => "consultancyReason", "Amendment Reason" => "amendmentReason",  "Supplier Name" => "supplierName", "Supplier Address" => "supplierAddress", "Supplier City" => "supplierCity", "Supplier Postcode" => "supplierPostcode", "Supplier Country" => "supplierCountry" , "Supplier ABNExempt" => "supplierABNExempt", "Supplier ABN" => "supplierABN" , "Agency Branch" => "contactBranch","Agency Divison" => "contactDivision", "Agency Postcode" => "contactPostcode" , "" => "");
-$headers;
-$contractNoticeFields = Array("agencyName",  "parentCN", "CNID", "publishDate",  "amendDate", "contractStart" , "contractEnd", "value", "description",   "agencyID",  "category", "procurementMethod", "atmID", "SONID", "confidentialityContract", "confidentialityContractReason", "confidentialityOutputs", "confidentialityOutputsReason", "consultancy", "consultancyReason",  "amendmentReason",  "supplierName", "supplierAddress", "supplierCity",  "supplierPostcode",  "supplierCountry" , "supplierABNExempt",  "supplierABN", "contactBranch","contactDivision","contactPostcode" );
-$agencyFields = Array("agencyName");
-$supplierFields = Array("supplierName", "supplierAddress", "supplierCity",  "supplierPostcode",  "supplierCountry" , "supplierABNExempt",  "supplierABN" );
-
-while (($data = fgetcsv($handle, 1000, "\t")) !== FALSE) {
-    $num = count($data);
-
-	if ($row == 3)
-	{
-	$headers = $data;
-	}
-	else if ($row > 3)
-	{
-			if ($num > count($datamapping0709))
-		{
-		die ("<font color=red>Error in data import; data mapping fields out of bounds or changed</font><br>".$fname.print_r($data));
-		}
-	$firstCN= false;
-    $firstSupplier= true;
-    $firstAgency= true;
-    $contractNoticeInsert = "INSERT INTO contractnotice (importFile, ".implode(" , ",$contractNoticeFields). ") VALUES ( \"$fname\" ";
-    $supplierInsert = "INSERT INTO supplierdetails (".implode(" , ",$supplierFields). ") VALUES (";
-    $agencyInsert = "INSERT INTO agency (".implode(" , ",$agencyFields). ") VALUES (";
-	
-	$keys = array_keys($datamapping0709);
-    for ($c=0; $c < $num; $c++) {
-	$data[$c] = trim($data[$c],"=");
-	$data[$c] = trim($data[$c], "\"");
-	
-	if (in_array(($datamapping0709[$headers[$c]]),$contractNoticeFields))
-	{
-	if (($datamapping0709[$headers[$c]]) == "parentCN" || ($datamapping0709[$headers[$c]]) == "CNID")
-	{
-		$data[$c] = substr($data[$c],2);
-		if ($data[$c] >0)
-		{
-		$contractNoticeInsert .= ($firstCN ? "" : ","). mysql_real_escape_string($data[$c]);
-		} else
-		{
-		$contractNoticeInsert .= ($firstCN ? "" : ",")."''";
-		}
-	} else 	if (($datamapping0709[$headers[$c]]) == "amendDate" || ($datamapping0709[$headers[$c]]) == "publishDate" || ($datamapping0709[$headers[$c]]) == "contractStart" || ($datamapping0709[$headers[$c]]) == "contractEnd")
-	{
-		$contractNoticeInsert .= ($firstCN ? "" : ","). "'".date( 'Y-m-d H:i:s', strtotime($data[$c])). "'";
-	} else
-	{
-		if (strstr("\" =",$data[$c] > 0))
-			{
-				die ("Invalid Description field" . $contractNoticeInsert); 
-			}
-        $contractNoticeInsert .= ($firstCN ? "" : ",") .  "'". mysql_real_escape_string($data[$c])."'";
-		
-		}
-		$firstCN = false;
-    }
-		if (in_array(($datamapping0709[$headers[$c]]),$supplierFields))
-	{
-        $supplierInsert .= ($firstSupplier ? "" : ",") .  "'". mysql_real_escape_string($data[$c])."'";
-		$firstSupplier = false;
-    }
-			if (in_array(($datamapping0709[$headers[$c]]),$agencyFields))
-	{
-        $agencyInsert .= ($firstAgency ? "" : ",") .  "'". mysql_real_escape_string($data[$c])."'";
-		$firstAgency = false;
-    }
-	
-	}
-	$contractNoticeInsert .= ");";
-	$supplierInsert .= ");";
-	$agencyInsert .= ");";
-	
-$result = mysql_query($contractNoticeInsert);
-if ($result) $success++;
-else echo $data[2] . " failed CN insert.<br>". mysql_error() ." <br>  $contractNoticeInsert <br><br>\n";
-	
-	//$result = mysql_query($agencyInsert);
-if ($result) $success++;
-else echo $data[2] . " failed agency insert.<br>". mysql_error() ." <br> $agencyInsert <br><br>\n";
-	
-	$result = mysql_query($supplierInsert);
-if ($result) $success++;
-else echo $data[2] . " failed supplier insert.<br>". mysql_error() ." <br> $supplierInsert <br><br>\n";
-
-echo "<hr>\n";
-	}
-	
-    $row++;
-}
-echo "<br> $success records successfully created";
-fclose($handle);
-}
+  include_once("../lib/common.inc.php");
+  $path = 'data/';
+  if ($_REQUEST["fname"] == "") {
+      echo "Get files from: https://www.tenders.gov.au/?event=public.reports.list<br>";
+      $dhandle = opendir($path);
+      // define an array to hold the files
+      $files = array();
+      
+      if ($dhandle) {
+          // loop through all of the files
+          while (false !== ($fname = readdir($dhandle))) {
+              if (($fname != '.') && ($fname != '..')) {
+                  echo "<a href=\"import.php?fname=$fname\">$fname</a>" . filesize($path . $fname) . "<br/>";
+              }
+          }
+      }
+  } else {
+      $success = 0;
+      $fname = $_REQUEST["fname"];
+      echo " ============== $fname  ============== <br>";
+      flush();
+      $row = 1;
+      $handle = fopen($path . $fname, "r");
+      //"t" mode string translates windows line breaks to unix
+      $datamapping0709 = array("Agency" => "agencyName", "Parent CN ID" => "parentCN", "CN ID" => "CNID", "Publish Date" => "publishDate", "Amendment Date" => "amendDate", "Status" => "", "StartDate" => "contractStart", "EndDate" => "contractEnd", "Value" => "value", "Description" => "description", "Agency Ref Id" => "agencyID", "Category" => "category", "Procurement Method" => "procurementMethod", "ATM ID" => "atmID", "SON ID" => "SONID", "Confidentiality - Contract" => "confidentialityContract", "Confidentiality - Contract Reason(s)" => "confidentialityContractReason", "Confidentiality - Outputs" => "confidentialityOutputs", "Confidentiality - Outputs Reason(s)" => "confidentialityOutputsReason", "Consultancy" => "consultancy", "Consultancy Reason(s)" => "consultancyReason", "Amendment Reason" => "amendmentReason", "Supplier Name" => "supplierName", "Supplier Address" => "supplierAddress", "Supplier City" => "supplierCity", "Supplier Postcode" => "supplierPostcode", "Supplier Country" => "supplierCountry", "Supplier ABNExempt" => "supplierABNExempt", "Supplier ABN" => "supplierABN", "Agency Branch" => "contactBranch", "Agency Divison" => "contactDivision", "Agency Postcode" => "contactPostcode", "" => "");
+      $headers;
+      $contractNoticeFields = array("agencyName", "parentCN", "CNID", "publishDate", "amendDate", "contractStart", "contractEnd", "value", "description", "agencyID", "category", "procurementMethod", "atmID", "SONID", "confidentialityContract", "confidentialityContractReason", "confidentialityOutputs", "confidentialityOutputsReason", "consultancy", "consultancyReason", "amendmentReason", "supplierName", "supplierAddress", "supplierCity", "supplierPostcode", "supplierCountry", "supplierABNExempt", "supplierABN", "contactBranch", "contactDivision", "contactPostcode");
+      $agencyFields = array("agencyName");
+      $supplierFields = array("supplierName", "supplierAddress", "supplierCity", "supplierPostcode", "supplierCountry", "supplierABNExempt", "supplierABN");
+      
+      while (($data = fgetcsv($handle, 1000, "\t")) !== false) {
+          $num = count($data);
+          
+          if ($row == 3) {
+              $headers = $data;
+          } elseif ($row > 3) {
+              if ($num > count($datamapping0709)) {
+                  die("<font color=red>Error in data import; data mapping fields out of bounds or changed</font><br>" . $fname . print_r($data));
+              }
+              $firstCN = false;
+              $firstSupplier = true;
+              $firstAgency = true;
+              $contractNoticeInsert = "INSERT INTO contractnotice (importFile, " . implode(" , ", $contractNoticeFields) . ") VALUES ( \"$fname\" ";
+              $supplierInsert = "INSERT INTO supplierdetails (" . implode(" , ", $supplierFields) . ") VALUES (";
+              $agencyInsert = "INSERT INTO agency (" . implode(" , ", $agencyFields) . ") VALUES (";
+              
+              $keys = array_keys($datamapping0709);
+              for ($c = 0; $c < $num; $c++) {
+                  $data[$c] = trim($data[$c], "=");
+                  $data[$c] = trim($data[$c], "\"");
+                  
+                  if (in_array(($datamapping0709[$headers[$c]]), $contractNoticeFields)) {
+                      if (($datamapping0709[$headers[$c]]) == "parentCN" || ($datamapping0709[$headers[$c]]) == "CNID") {
+                          $data[$c] = substr($data[$c], 2);
+                          if ($data[$c] > 0) {
+                              $contractNoticeInsert .= ($firstCN ? "" : ",") . mysql_real_escape_string($data[$c]);
+                          } else {
+                              $contractNoticeInsert .= ($firstCN ? "" : ",") . "''";
+                          }
+                      } elseif (($datamapping0709[$headers[$c]]) == "amendDate" || ($datamapping0709[$headers[$c]]) == "publishDate" || ($datamapping0709[$headers[$c]]) == "contractStart" || ($datamapping0709[$headers[$c]]) == "contractEnd") {
+                          $contractNoticeInsert .= ($firstCN ? "" : ",") . "'" . date('Y-m-d H:i:s', strtotime($data[$c])) . "'";
+                      } else {
+                          if (strstr("\" =", $data[$c] > 0)) {
+                              die("Invalid Description field" . $contractNoticeInsert);
+                          }
+                          $contractNoticeInsert .= ($firstCN ? "" : ",") . "'" . mysql_real_escape_string($data[$c]) . "'";
+                      }
+                      $firstCN = false;
+                  }
+                  if (in_array(($datamapping0709[$headers[$c]]), $supplierFields)) {
+                      $supplierInsert .= ($firstSupplier ? "" : ",") . "'" . mysql_real_escape_string($data[$c]) . "'";
+                      $firstSupplier = false;
+                  }
+                  if (in_array(($datamapping0709[$headers[$c]]), $agencyFields)) {
+                      $agencyInsert .= ($firstAgency ? "" : ",") . "'" . mysql_real_escape_string($data[$c]) . "'";
+                      $firstAgency = false;
+                  }
+              }
+              flush();
+              $contractNoticeInsert .= ");";
+              $supplierInsert .= ");";
+              $agencyInsert .= ");";
+              
+              $result = mysql_query($contractNoticeInsert);
+              if ($result)
+                  $success++;
+              elseif (strpos(mysql_error(), "Duplicate entry") === false)
+                  echo $data[2] . " failed CN insert.<br>" . mysql_error() . " <br>  $contractNoticeInsert <br><br>\n";
+              
+              $result = mysql_query($agencyInsert);
+              if ($result)
+                  $success++;
+              elseif (strpos(mysql_error(), "Duplicate entry") === false)
+                  echo $data[2] . " failed agency insert.<br>" . mysql_error() . " <br> $agencyInsert <br><br>\n";
+              
+              $result = mysql_query($supplierInsert);
+              if ($result)
+                  $success++;
+              elseif (strpos(mysql_error(), "Duplicate entry") === false)
+                  echo $data[2] . " failed supplier insert.<br>" . mysql_error() . " <br> $supplierInsert <br><br>\n";
+              flush();
+              
+              //echo "<hr>\n";
+          }
+          
+          $row++;
+      }
+      echo "<br> $success records successfully created";
+      flush();
+      fclose($handle);
+  }
 ?>

--- a/admin/linkAmendments.php
+++ b/admin/linkAmendments.php

--- a/admin/recordsperweek.txt
+++ b/admin/recordsperweek.txt

--- a/admin/setAgencyStatus.php
+++ b/admin/setAgencyStatus.php
@@ -1,16 +1,24 @@
 <?php
 include_once("../lib/common.inc.php");
 
-$active = Array('Administrative Appeals Tribunal','Aged Care Standards and Accreditation Agency Ltd','Airservices Australia','Attorney-General\'s Department','Auditing and Assurance Standards Board','AusAid','Austrade','Australia Council for the Arts','Australian Accounting Standards Board','Australian Antarctic Division','Australian Broadcasting Corporation','Australian Bureau of Statistics','Australian Centre for International Agricultural Research','Australian Commission for Law Enforcement Integrity','Australian Communications and Media Authority (ACMA)','Australian Competition and Consumer Commission','Australian Crime Commission','Australian Customs Service','Australian Electoral Commission','Australian Fair Pay Commission','Australian Federal Police','Australian Film Commission','Australian Film Television and Radio School','Australian Fisheries Management Authority','Australian Hearing Services','Australian Industrial Registry','Australian Institute of Aboriginal and Torres Strait Islander Studies (AIATSIS)','Australian Institute of Criminology','Australian Institute of Family Studies','Australian Institute of Health and Welfare','Australian Institute of Marine Science','Australian Law Reform Commission','Australian Maritime Safety Authority','Australian National Audit Office (ANAO)','Australian National Maritime Museum','Australian Nuclear Science and Technology Organisation (ANSTO)','Australian Office of Financial Management','Australian Organ and Tissue Donation and Transplantation Authority','Australian Pesticides and Veterinary Medicines Authority','Australian Prudential Regulation Authority (APRA)','Australian Public Service Commission','Australian Radiation Protection and Nuclear Safety Agency (ARPANSA)','Australian Research Council','Australian Reward Investment Alliance (ARIA)','Australian Securities and Investments Commission','Australian Security Intelligence Organisation','Australian Sports Anti-Doping Authority (ASADA)','Australian Taxation Office','Australian Transaction Reports and Analysis Centre (AUSTRAC)','Australian Transport Safety Bureau','Australian War Memorial','Biosecurity Australia','Bureau of Meteorology','Cancer Australia','Centrelink','Civil Aviation Safety Authority','Comcare','Commonwealth Grants Commission','Comsuper','Corporations and Markets Advisory Committee','Crimtrac','CRS Australia','CSIRO','Defence Housing Australia','Defence Materiel Organisation','Department of Agriculture, Fisheries and Forestry','Department of Broadband, Communications and the Digital Economy','Department of Climate Change','Department of Defence','Department of Education, Employment and Workplace Relations','Department of Families, Housing, Community Services and Indigenous Affairs','Department of Finance and Deregulation','Department of Foreign Affairs and Trade','Department of Health and Ageing','Department of Human Services','Department of Immigration & Citizenship','Department of Infrastructure, Transport, Regional Development and Local Government','Department of Innovation, Industry, Science and Research','Department of Parliamentary Services','Department of Resources, Energy and Tourism','Department of the Environment, Water, Heritage and the Arts','Department of the House of Representatives','Department of the Prime Minister and Cabinet','Department of the Senate','Department of the Treasury','Department of Veterans\' Affairs','Director of National Parks','Emergency Management Australia','Equal Opportunity for Women in the Workplace Agency','Export Finance and Insurance Corporation (EFIC)','Fair Work Australia','Family Court of Australia','Federal Court of Australia','Federal Magistrates Court','Future Fund Management Agency','Geoscience Australia','Grains Research and Development Corporation','Great Barrier Reef Marine Park Authority','Human Rights and Equal Opportunity Commission','Insolvency and Trustee Service Australia (ITSA)','Inspector-General of Taxation','IP Australia','Land and Water Australia','Medicare Australia','Migration Review Tribunal and Refugee Review Tribunal (MRT-RRT)','Murray-Darling Basin Authority','National Archives of Australia','National Blood Authority','National Capital Authority','National Competition Council','National Film and Sound Archive','National Gallery of Australia','National Health and Medical Research Council','National Library of Australia','National Museum of Australia','National Native Title Tribunal','National Offshore Petroleum Safety Authority','National Water Commission','Office of National Assessments','Office of Parliamentary Counsel','Office of the Australian Building and Construction Commissioner (ABCC)','Office of the Commonwealth Ombudsman','Office of the Director of Public Prosecutions','Office of the Fair Work Ombudsman','Office of the Inspector-General of Intelligence and Security','Office of the Official Secretary to the Governor-General','Office of the Privacy Commissioner','Office of the Renewable Energy Regulator','Old Parliament House','Private Health Insurance Ombudsman','Productivity Commission','Professional Services Review','Questacon','Reserve Bank of Australia','Royal Australian Mint','Seacare','Social Security Appeals Tribunal','Sydney Harbour Federation Trust','Therapeutic Goods Administration','Tourism Australia','Workplace Authority','Workplace Ombudsman');
+$active = Array('0EC8D805-C293-3ADD-E51A93667D977314|Administrative Appeals Tribunal','0ECAA17D-9862-5309-101D94A126495C7F|Aged Care Standards and Accreditation Agency Ltd','CE45735B-F9FC-04DA-F299C730D9BE613E|Airservices Australia','0EC8DF71-ED98-8593-2D776EE93D9BA248|Attorney-General\'s Department','0ECA6B4C-DE4F-A04A-DBFB5F39B050B6D7|AusAid','0ECA6F64-F6B8-F406-E490A1479A7A717B|Austrade','D2724D99-F230-A93A-93D62A8DCC187940|Australia Council for the Arts','D26C4D0A-FF6E-612A-C6FEDB2D5E71AE4A|Australian Antarctic Division','C8E854CD-E966-9A35-078FF6702EC1ECED|Australian Broadcasting Corporation','0ECB50CF-028A-FB9D-3E5EF0F9708E4BC7|Australian Bureau of Statistics','0ECA671F-EA1F-8560-1D7C90408694B565|Australian Centre for International Agricultural Research','A861A42C-B32C-85A8-0F719005E27F4E23|Australian Commission for Law Enforcement Integrity','C8F9DAF8-9763-EA22-FA44B6BBC12B0B94|Australian Communications and Media Authority (ACMA)','0ECB2BB9-B19C-4929-87EC63542388D079|Australian Competition and Consumer Commission','0EC8E42E-EB6A-15DA-3F001AFB9C2B8D34|Australian Crime Commission','0EC8E8CE-9BCF-0651-D4362CF53DB8E4DC|Australian Customs and Border Protection Service','CD51BCA4-9DC7-9494-B7D944029D03A1F9|Australian Electoral Commission','D248626B-0BDD-B201-1A1C7C978AD973D2|Australian Fair Pay Commission','0EC8EDF3-E025-2F80-AEB39B350641C81F|Australian Federal Police','0EC8B90B-CBF5-8EC4-2C4E261041A25E16|Australian Fisheries Management Authority','0ECABD48-0388-F8AB-00BD4EB12FA44067|Australian Hearing Services','0EC920D5-CEB1-81FC-5A107A206F4A6BF3|Australian Human Rights Commission','D257B064-D245-51CC-F69A50FF4620915B|Australian Industrial Registry','0EC8F7B1-03ED-C4C3-70FBDF105ADB2FB6|Australian Institute of Criminology','D32EC07E-E22E-5805-1240CF68033C5E15|Australian Institute of Family Studies','0ECA9D77-A0B8-448A-53945B4DFACEE685|Australian Institute of Health and Welfare','D31CF0E2-B1A4-DE74-5D7B7B1DC97EA1DC|Australian Institute of Marine Science','0EC8FC41-C1BE-587A-A19920F43BA616BF|Australian Law Reform Commission','CE5DCAA3-D793-2FEE-B3C263B84AF2676C|Australian Maritime Safety Authority','0ECAED96-0B3B-1D24-56412EC3384996B0|Australian National Audit Office (ANAO)','D281D726-938C-D76D-A346348BEFC509F9|Australian National Maritime Museum','D31E738F-F139-2BC2-EBF2764D7812EA10|Australian Nuclear Science and Technology Organisation (ANSTO)','0ECB3D20-C837-FBE2-B1C32937F87CBB8F|Australian Office of Financial Management','82C5CFA1-0088-7B9E-9A3EF95987B55045|Australian Organ and Tissue Donation and Transplantation Authority','0EC8BF2B-B23F-0A07-0659BB9760EFC94E|Australian Pesticides and Veterinary Medicines Authority','0ECB5AFF-F4DC-06E3-97B3118B978F33BD|Australian Prudential Regulation Authority (APRA)','0ECAF18D-044A-0F5E-AD942B0CD5BB1ACC|Australian Public Service Commission','0ECA88C8-B803-ECE2-00F37CE4797C74BC|Australian Radiation Protection and Nuclear Safety Agency (ARPANSA)','D320882B-ED70-8061-6A5B2F8E64D6F575|Australian Research Council','CD5A2434-9592-2217-49970AF89E5956F8|Australian Reward Investment Alliance (ARIA)','0ECB44F1-BC3B-58E0-96CD33517E10E38B|Australian Securities and Investments Commission','0EC9056F-C13F-ED84-07B410D54C4A1013|Australian Security Intelligence Organisation','D303A5DD-B83B-EC45-588E3680B4E842E4|Australian Sports Anti-Doping Authority (ASADA)','0ECB54CA-EE15-8B26-3C430607E8DB3D4E|Australian Taxation Office','0EC900DB-D645-6C40-DD8BEA03CC15D392|Australian Transaction Reports and Analysis Centre (AUSTRAC)','77068F86-0A15-723A-C2FC1601C44FFCD2|Australian Transport Safety Bureau','0EC9AC89-DEB3-1441-2441891A3772863E|Australian War Memorial','D28B4F07-C2F2-2D4F-1C9229D177088373|Bureau of Meteorology','0ECA90FE-A44B-2EAA-08039CC6C43E728D|Cancer Australia','0ECAB1CF-D480-0C8B-70670DFC4FFDAC56|Centrelink','CE608086-A4DC-45F6-1179DCC148CF91F7|Civil Aviation Safety Authority','D24AFCAC-A2B2-4766-17C9A3EC3AAE4205|Comcare','166B9AD2-ACC9-B56F-4D5B47BD325DEB25|Commonwealth Grants Commission','CD5BDE89-9805-D921-0DAAFDBD5312D0D5|Comsuper','0ECB5EF6-CC7B-7C8E-32798557B78F6D98|Corporations and Markets Advisory Committee','0EC909FF-D902-5FD3-6660ADB353470F95|Crimtrac','0ECAC700-BDE8-458D-6A4E91C8B151A270|CRS Australia','D3275762-D634-4459-D33A26E1BEA05D14|CSIRO','0EC99E6C-0375-2DAF-A8338121FCBD6F7A|Defence Housing Australia','0EC9A29C-E478-AD19-3F0F29F6BE4914BF|Defence Materiel Organisation','0EC892FD-E156-BCB0-ADF5D534E584BC18|Department of Agriculture, Fisheries and Forestry','FB2B0C69-0AAF-1B2B-8186EC38772F8FC1|Department of Broadband, Communications and the Digital Economy','69368049-A8EF-0896-EA9C603C856788D9|Department of Climate Change and Energy Efficiency','0EC98EF9-E020-5DA9-DCB10135BE81BD2B|Department of Defence','D23E9B50-DAE3-6701-D90A2582EE48A4DA|Department of Education, Employment and Workplace Relations','D2FBF89C-D43D-4B3E-527132AC0D41ABBB|Department of Families, Housing, Community Services and Indigenous Affairs','CD39DC0D-D4B3-DFEC-DDDCD52E651F06EA|Department of Finance and Deregulation','0ECA5FC9-A4AD-0A3A-97A8DD3FD9D44CB1|Department of Foreign Affairs and Trade','0ECA80C0-EC9F-B5B9-0D3E8A4537C39808|Department of Health and Ageing','0ECAADBC-B488-A53B-F4F6672EC813849A|Department of Human Services','0ECB6A9B-BA91-CB7D-36C62C5C9191D403|Department of Immigration & Citizenship','047091E8-CEE4-A9FF-BF552F538D279807|Department of Infrastructure and Transport','FADB0367-F000-E0B9-8F79FD109F613AB6|Department of Innovation, Industry, Science and Research','0ECB7ED8-BB19-D108-324A8A05B1966ABF|Department of Parliamentary Services','2F03BD8D-F73D-C35C-729559C6C70C6602|Department of Regional Australia, Regional Development and Local Government','FADFD268-9BF5-97E4-2F247B92F74E82C0|Department of Resources, Energy and Tourism','62304115-AA13-68D1-592110A8021DA68E|Department of Sustainability, Environment, Water, Population and Communities','0ECB8490-9B07-1898-98170CDD42A9DFF7|Department of the House of Representatives','0ECAE795-F858-203D-FD1C9FF933EF4A37|Department of the Prime Minister and Cabinet','0ECB8A6E-B354-715B-C9DEDE4A6DA3C393|Department of the Senate','0ECB25C0-02C3-6BAA-4738951514F489A9|Department of the Treasury','0EC9A85E-BA37-0A60-47A828CD70D831FC|Department of Veterans\' Affairs','D2E272D5-DDD0-178B-F1BE5A9181D3ACAE|Director of National Parks','D2F85A2B-E563-118E-0CB302E02C74397C|Equal Opportunity for Women in the Workplace Agency','0ECA73FA-FAAD-62B5-48581DF753E57CCA|Export Finance and Insurance Corporation (EFIC)','A535F827-E58E-89FB-7F58107CBBD0D79A|Fair Work Australia','0EC91301-C770-6470-480E879920826ABD|Family Court of Australia','0EC91799-A81B-262C-CE6ACAB2622F0566|Federal Court of Australia','0EC91C3C-BB6B-97BF-76BEF63DD0905AAF|Federal Magistrates Court','08355C10-AB46-67AA-421E334D1B45E125|Food Standards Australia New Zealand','CD5E362E-A615-1102-67814B74731025AD|Future Fund Management Agency','D33926C6-BB30-4A30-3A29A5821CFB7AE6|Geoscience Australia','0EC8CA07-AE70-7EB2-5A174487D4BD6236|Grains Research and Development Corporation','D2E5D48D-08A4-5CC9-5378FEA3CD8E649C|Great Barrier Reef Marine Park Authority','0EC925CD-F184-26AF-DE8A84DE3CBA3790|Insolvency and Trustee Service Australia (ITSA)','0ECB302F-AADD-2BB1-392F50E0E94CB076|Inspector-General of Taxation','D3174EBA-F3C0-28E6-7A669C23CF0B3040|IP Australia','0ECAB5DF-B75F-EC35-92EA7821EFF77C0D|Medicare Australia','0ECB74A7-BE11-FC3C-8696F7F93D7612C0|Migration Review Tribunal and Refugee Review Tribunal (MRT-RRT)','F8E42DAB-9570-A008-97294775650CCE6E|Murray-Darling Basin Authority','0A18A552-0B56-257B-70BE077385CE2EDC|National Archives of Australia','0ECA8CEA-08C9-6D55-C57A7A102DFFBC8A|National Blood Authority','D2347B3A-F330-0317-68AB0C4F7240B9A5|National Capital Authority','0ECB3416-FEB1-F5E0-FB4760831CA2F66E|National Competition Council','7DEE189B-0A00-07D1-2D1C778EDAEFEF6D|National Film and Sound Archive','D2E7830B-9692-3124-1C2E1D74AAC8FFFF|National Gallery of Australia','0ECA957E-E479-2758-528FA4E576A27A5D|National Health and Medical Research Council','D2EA1497-0BB3-AFBD-76559FA87101FF06|National Library of Australia','D2EC2CF2-FEEE-8FB2-46193EDF8EA2F503|National Museum of Australia','0EC92A40-B2DA-D4FF-16895BCD00F9E20F|National Native Title Tribunal','D33DB6EB-FEE1-F686-7385E65E48749DD2|National Offshore Petroleum Safety Authority','D2EF702D-EF9B-B363-BDA3A4950C5ED57F|National Water Commission','0ECB00AF-04FE-735D-82D0B84D1A19F95A|Office of National Assessments','0EC93653-9FCE-12DD-DAAC73E23DCAE8CA|Office of Parliamentary Counsel','0ECB48E3-9198-6F2C-9737A69F9D15177A|Office of the Auditing and Assurance Standards Board','0ECB4CD6-A6D6-4334-D550948337CE9F56|Office of the Australian Accounting Standards Board','D25ACD14-ABA3-F69F-E1ADA4503ED97C82|Office of the Australian Building and Construction Commissioner (ABCC)','D331236A-BDE0-5CD7-24EF78F052CB2B50|Office of the Australian Information Commissioner','0ECAF6CA-ACBE-E3E7-6DCBF175E012F817|Office of the Commonwealth Ombudsman','0EC93B4D-DC77-6FA0-7E15530A7D7344CB|Office of the Director of Public Prosecutions','39DCC587-FF78-8759-E91BF5B9EC3D1904|Office of the Fair Work Ombudsman','0ECB049D-B7DC-1697-586AB4455B0DF251|Office of the Inspector-General of Intelligence and Security','0ECB0887-D30E-E490-3F16BCB7EF406D8E|Office of the Official Secretary to the Governor-General','E0EAE43E-B918-12DC-9F4E0E03811CACAD|Office of the Renewable Energy Regulator','D726F8EA-D648-B4DF-E25FF1EEE68C9700|Old Parliament House','87A575EB-E6CE-7E8B-1CB3D9B6580FAE5B|Private Health Insurance Ombudsman','0ECB380B-FC93-8003-9A1F04BD55A10F62|Productivity Commission','0ECA9978-D7C8-3F44-2D21C2827407BEF5|Professional Services Review','0ECB64C5-E6E4-3D23-B4409B18EB609B25|Reserve Bank of Australia','0ECB4106-02BC-64C6-1DF8032E549D88E4|Royal Australian Mint','4A350604-FD8E-C7BB-D6C6A14AEE6D8873|Safe Work Australia','D25D96A7-B9B7-21D2-57AA60EAC138107B|Seacare','D2FF2257-0E69-4B7C-FCF6AB672ECC341C|Social Security Appeals Tribunal','D2F16C5B-BCFB-E14D-9B62DEEDF992798B|Sydney Harbour Federation Trust','0ECA84C7-D6C3-3299-9F898B9C201D771B|Therapeutic Goods Administration','D340FD88-0AFE-B091-1F43D9EDBCE164D4|Tourism Australia','EB74EB82-AA02-F70B-DC648859ABFC28DA|Wheat Exports Australia');
 
-$suspended = Array('Airservices Australia','Australia Council for the Arts','Australia-Japan Foundation','Australian Antarctic Division','Australian Broadcasting Corporation','Australian Communications and Media Authority (ACMA)','Australian Electoral Commission','Australian Fair Pay Commission','Australian Film Commission','Australian Film Television and Radio School','Australian Industrial Registry','Australian Institute of Aboriginal and Torres Strait Islander Studies (AIATSIS)','Australian Institute of Family Studies','Australian Institute of Marine Science','Australian Maritime Safety Authority','Australian National Maritime Museum','Australian Nuclear Science and Technology Organisation (ANSTO)','Australian Research Council','Australian Reward Investment Alliance (ARIA)','Australian Sports Anti-Doping Authority (ASADA)','Bureau of Meteorology','Child Support Agency','Civil Aviation Safety Authority','Comcare','Commonwealth Grants Commission','Comsuper','CSIRO','Dairy Adjustment Authority','Department of Communications, Information Technology and the Arts','Department of Education, Science and Training','Department of Employment and Workplace Relations','Department of Families, Community Services & Indigenous Affairs','Department of Finance and Administration','Department of Industry, Tourism and Resources','Department of the Environment and Water Resources','Department of Transport and Regional Services','Director of National Parks','Equal Opportunity for Women in the Workplace Agency','Export Wheat Commission','Future Fund Management Agency','Geoscience Australia','Great Barrier Reef Marine Park Authority','IP Australia','National Archives of Australia','National Archives of Australia','National Capital Authority','National Gallery of Australia','National Library of Australia','National Museum of Australia','National Offshore Petroleum Safety Authority','National Water Commission','National Water Commission','Office of Film and Literature Classification','Office of the Australian Building and Construction Commissioner (ABCC)','Office of the Privacy Commissioner','Office of the Renewable Energy Regulator','Office of Workplace Services','Questacon','Refugee Review Tribunal','Seacare','Social Security Appeals Tribunal','Sydney Harbour Federation Trust','The National Institute of Clinical Studies Ltd','Tourism Australia','Workplace Ombudsman');
+$suspended = Array('8B346DD0-D9A5-585C-1B3174A9B6292AD1|Aboriginal and Torres Strait Islander Services','0ECB16D3-9684-471C-3FFBCCCAB63728B4|Airservices Australia','0EC975AC-F94D-B8B5-FDF5CF053D78F7EA|Australia Council for the Arts','0ECA7934-9725-0D31-1BD08C6ADFD16040|Australia-Japan Foundation','0ECA043A-C02D-1838-E994DF3EC8B0A857|Australian Antarctic Division','0EC96B6B-9A30-F9E4-892DA6860B3985B2|Australian Broadcasting Corporation','0EC9521F-C38A-2FB1-54CEF555CE76807A|Australian Communications and Media Authority (ACMA)','0ECA48E7-B536-E530-CA1F4F8A4056517F|Australian Electoral Commission','0EC9D8CD-D6F8-A695-854B714011D9B2E8|Australian Fair Pay Commission','0EC9703D-9C88-C7FF-E15390103B51CE22|Australian Film Commission','D27DB409-E5C9-15AD-635A70CEF5A8E05C|Australian Film Commission','0EC96705-AED6-462D-E1579FE99DD57511|Australian Film Television and Radio School','D27F93E1-9898-8ED5-5DF9628A1CE78BBF|Australian Film Television and Radio School','0EC9DCED-ED0B-FF25-20323EF5E93EC88E|Australian Industrial Registry','0EC9BF9B-C83C-4EC5-DDE3C845EBF3CCC0|Australian Institute of Aboriginal and Torres Strait Islander Studies (AIATSIS)','D246AE91-0DD2-193E-84F9A3E13664E58E|Australian Institute of Aboriginal and Torres Strait Islander Studies (AIATSIS)','0ECA2851-AD46-9261-B3A77D28C5CC1351|Australian Institute of Family Studies','0EC9BB58-BBA8-3F3D-AD04CBFE4FABC85D|Australian Institute of Marine Science','0ECB1ACC-FAAC-3895-9EC179BC71C3FC54|Australian Maritime Safety Authority','0EC9611A-C5D2-43B5-D4039EED991272E3|Australian National Maritime Museum','0EC9C3D2-CE1C-8C81-085ADA97E2172420|Australian Nuclear Science and Technology Organisation (ANSTO)','0EC9B71F-EDBC-5E42-E44D5595BDF7B3F4|Australian Research Council','0ECA59B7-D4C6-360D-4829CB8A5E15B664|Australian Reward Investment Alliance (ARIA)','0EC95958-08E9-4A16-A79AC1CB828B9535|Australian Sports Anti-Doping Authority (ASADA)','0EC8C3DE-B6EB-88B8-0FD9460AC543DD0C|Biosecurity Australia','0ECA1921-EA6F-1BE2-3E85DBF7BBCDE734|Bureau of Meteorology','0ECAC142-B8B8-CCE0-A4B00E4B67ED0DCB|Child Support Agency','0ECB1FED-D2C6-6214-2CEB31CE9B107ED1|Civil Aviation Safety Authority','0EC9D499-F2DE-F8D9-0239ACA17C2ABFBB|Comcare','0ECA55A3-A0B2-0D36-D383E6A113AD5749|Commonwealth Grants Commission','0ECA4CF9-9312-2F3D-637C98CF2FEEB5A4|Comsuper','0EC9C7FE-F7AC-09BD-3C498B63A9DDDDA4|CSIRO','0EC8B354-F006-A824-A43120384BE56A98|Dairy Adjustment Authority','D3328CCE-DEA4-5516-AA23F77F557454FC|Department of Climate Change','0EC94B72-AD24-B695-3C5C388FBC0C23AA|Department of Communications, Information Technology and the Arts','0EC9B2BB-D5C8-8061-8CC999143D0D291C|Department of Education, Science and Training','0EC9CE2C-A998-C45A-90697489AC42B83B|Department of Employment and Workplace Relations','0ECA21F5-F5FE-7F08-52CD6FFB54E788FE|Department of Families, Community Services & Indigenous Affairs','0ECA32E7-E860-DFD4-0FBDCE1CC8E0FC84|Department of Finance and Administration','8B3539BA-EC97-7510-AF049F389DC0497A|Department of Immigration and Multicultural Affairs','8B361B4A-EAAE-D747-134D9FA97497C70F|Department of Immigration and Multicultural and Indigenous Affairs (DIMIA)','0ECACF65-D93B-D892-1862B65F15C92A6A|Department of Industry, Tourism and Resources','CE419954-CB32-1154-9E61EDB5805C222D|Department of Infrastructure, Transport, Regional Development and Local Government','0EC9F8FB-F224-1E70-F59834C1D5CE12D5|Department of the Environment and Water Resources','D2DFCF42-A87B-181C-2F48D7EEE8849AFD|Department of the Environment, Water, Heritage and the Arts','0ECB0EE4-9D78-A341-363B0D13161C5916|Department of Transport and Regional Services','0ECA0863-0F4E-5FA8-B7C522D16CCAC9BB|Director of National Parks','0EC90E81-DAF0-F67A-7FDC1AE664FF0BEE|Emergency Management Australia','0EC9E429-9FFF-7E05-41ADCC29FE17811C|Equal Opportunity for Women in the Workplace Agency','576FCE5F-E258-4A5C-92C11639C73A0442|Export Wheat Commission','0ECA518C-EF07-86F5-ADCAA84198009116|Future Fund Management Agency','0ECAE1C5-E249-022B-DCC7D944F398E1FD|Geoscience Australia','0ECA0CF1-AEF7-5C78-23878C6A5BF93C36|Great Barrier Reef Marine Park Authority','0ECADD52-F400-97E8-25F98B9FF96FFD08|IP Australia','0EC8D025-D94D-FF1D-97130B40320BAD9A|Land and Water Australia','0EC98433-EB5E-BEB1-1EEC7CADF83918A0|National Archives of Australia','CD603E31-CD1F-AAE5-F233F954A031553E|National Archives of Australia','0ECB12DC-BF41-FF5B-CB306CF040EC3218|National Capital Authority','0EC97A03-EA2E-5AE3-EC3C2C23487ECECA|National Gallery of Australia','0EC98880-F5F1-6560-605A0250EA58D139|National Library of Australia','0EC97FE7-E894-67B2-A8CE40DEF409AC23|National Museum of Australia','0ECAD957-B214-674F-3C94DEEF52BA3F46|National Offshore Petroleum Safety Authority','0ECAFC83-0B5D-045A-EE43EA12B9953CC0|National Water Commission','48499BD1-AFE0-1093-EF06293D78B3FD65|National Water Commission','0EC92FD3-F7B3-B0E0-9A8D8D2B611BB615|Office of Film and Literature Classification','0EC9E84A-A9F7-4EEF-5DDD2FC87C1F1B55|Office of the Australian Building and Construction Commissioner (ABCC)','0EC940DD-9A7E-1ECD-B44DDA0B72B2407F|Office of the Privacy Commissioner','0ECA10FE-AC03-80D8-C8DF1069C707351E|Office of the Renewable Energy Regulator','D3362537-FE00-1892-B408CABF5E0257A7|Office of the Renewable Energy Regulator','0EC9F2EC-C778-46D0-F15FDB1A8F1552F9|Office of Workplace Services','FB2A3EA0-D6FC-DB1D-19B0B72180A8A19B|Questacon','D329A60A-E914-FB37-FBA853A4CE8558EB|Questacon','0ECB788C-CC5C-2969-4B94EFB3913B0E65|Refugee Review Tribunal','A2A6EBF4-A8F5-E60B-5C25ACD3EA0679D8|Screen Australia','0EC9EC88-9B12-CB63-56A58BE69BDF3B6F|Seacare','0ECA2CE0-CBA9-9E13-AA0FB347CF4B5FD1|Social Security Appeals Tribunal','0ECA1510-B4A2-BBA4-D6FDE37DFAAC7C12|Sydney Harbour Federation Trust','0ECAA587-C851-4038-8CDC9CCE9A28F6E6|The National Institute of Clinical Studies Ltd','0ECAD567-E1E7-F5FC-72BA34FDF72F0FC0|Tourism Australia','7A592345-0410-DF1C-4B349EA35F314D3F|Workplace Authority','003B8DE1-D09A-D72F-28CEBC19DB84E866|Workplace Ombudsman','D260B27E-9744-EF72-C065072F24B4A62A|Workplace Ombudsman');
 
 foreach ($active as $agency ) {
+	$agencyParts = explode("|",$agency);
+	$agency = $agencyParts[1];
+	$agencyInsert = "INSERT INTO agency (agencyName) VALUES ('$agency')";
+	$result = mysql_query($agencyInsert);
 	$result = mysql_query("UPDATE agency SET status = 'active' where agencyName = '".mysql_real_escape_string($agency)."';") ;
 	if ($result) echo $agency. " set to active in ". mysql_affected_rows() . " divisions/branches <br>\n";
 	else echo "error".mysql_error();
 }
 foreach ($suspended as $agency) {
+	$agencyParts = explode("|",$agency);
+	$agency = $agencyParts[1];
+	$agencyInsert = "INSERT INTO agency (agencyName) VALUES ('$agency')";
+	$result = mysql_query($agencyInsert);
 	$result = mysql_query("UPDATE agency SET status = 'suspended' where agencyName = '".mysql_real_escape_string($agency)."';") ;
 	if ($result) echo $agency. " set to suspended in ". mysql_affected_rows() . " divisions/branches <br>\n";
 	else echo "error".mysql_error();

--- a/admin/setAgencyURLABN.php
+++ b/admin/setAgencyURLABN.php
@@ -26,9 +26,10 @@
   $result = mysql_query("UPDATE agency SET website = 'http://" . $result->visibleUrl . "', abn = '{$abn[0]}' WHERE agencyName = '$agency';");
   if ($result) echo $agency . " set in " . mysql_affected_rows() . " <br>\n";
   } else {
+	
 	echo "invalid ABN";
 	$result = mysql_query("UPDATE agency SET website = 'http://" . $result->visibleUrl . "' WHERE agencyName = '$agency';");
-  if ($result) echo $agency . " set in " . mysql_affected_rows() . " <br>\n";
+	if ($result) echo $agency . " set in " . mysql_affected_rows() . " <br>\n";
   }
   // fi
   

--- /dev/null
+++ b/admin/updateReport.php
@@ -1,1 +1,30 @@
+<?php

+include_once("../lib/common.inc.php");

+$query = "SELECT DATE(importDate) as importday, count(*) as count, min(publishDate) as start, max(publishDate) as end 

+FROM `contractnotice` WHERE childCN = 0 AND parentCN = 0 AND DATE(importDate) in (select * from (SELECT DATE(importDate) 

+FROM `contractnotice` ORDER BY `importDate` DESC limit 1) alias)";

+$result = mysql_query($query);

+$stats = mysql_fetch_array($result, MYSQL_BOTH);

+echo $stats["count"] . " new records in period " . $stats["start"] . "  to " . $stats["end"] ."<br>";

+

+$query = "SELECT DATE(importDate) as importday, count(*) as count, min(publishDate) as start, max(publishDate) as end 

+FROM `contractnotice` WHERE (childCN != 0 OR parentCN != 0) AND DATE(importDate) in (select * from (SELECT DATE(importDate) 

+FROM `contractnotice` ORDER BY `importDate` DESC limit 1) alias)";

+$result = mysql_query($query);

+$stats = mysql_fetch_array($result, MYSQL_BOTH);

+echo $stats["count"] . " updated records in period " . $stats["start"] . "  to " . $stats["end"] ."<br>";

+

+$query = "SELECT count(*) as count FROM `agency` WHERE `abn` = '0'";

+$result = mysql_query($query);

+$stats = mysql_fetch_array($result, MYSQL_BOTH);

+echo $stats["count"] . " agencies with no ABN<br>";

+

+/*$query = "SELECT count(*) as count FROM `supplierdetails` WHERE `supplierABN` = '0' and supplierCountry LIKE 'Australia'";

+$result = mysql_query($query);

+$stats = mysql_fetch_array($result, MYSQL_BOTH);

+echo $stats["count"] . " Australian suppliers with no ABN<br>";*/

+

+

+echo "Last updated: ". $stats["importday"]."<br>";

+?>

 

--- /dev/null
+++ b/admin/updateUNSPSC.php
@@ -1,1 +1,34 @@
+<?php

+error_reporting(E_ALL);

+

+include_once("../lib/common.inc.php");

+

+$unspscresult = mysql_query ("select * from UNSPSCcategories;");

+while ($row = mysql_fetch_assoc($unspscresult)) {

+	$unspsc[$row['Title']] = $row['UNSPSC'];

+}

+

+$query = "SELECT CNID,category,value

+FROM `contractnotice`

+WHERE `categoryUNSPSC` IS NULL OR `categoryUNSPSC` = 0";

+$emptycatresult = mysql_query ($query);

+$missing = Array();

+if ($emptycatresult){

+	while ($record = mysql_fetch_assoc($emptycatresult)) {

+	if ($unspsc[$record['category']] == "") {

+		$missing[$record['category']]= $missing[$record['category']]+ $record['value'];

+//		echo "<br>\n Category not found for: \n";

+//		print_r($record);

+	} else {

+	$result = mysql_query("UPDATE contractnotice SET categoryUNSPSC = 

+'".mysql_real_escape_string($unspsc[$record['category']])."' where CNID = 

+'".mysql_real_escape_string($record['CNID'])."';");

+	if ($result) echo $record['CNID']. " set to ". ($unspsc[$record['category']]) . " <br>\n";

+	else echo "error".mysql_error();

+	}

+	} 

+} else echo "error".mysql_error();

+asort($missing);

+print_r($missing);

+?>

 

--- /dev/null
+++ b/autosuggest_inquisitor.css
@@ -1,1 +1,177 @@
+/* 
+================================================
+autosuggest, inquisitor style
+================================================
+*/
 
+body
+{
+	position: relative;
+}
+
+
+div.autosuggest
+{
+	position: absolute;
+	background-image: url(images/img_inquisitor/as_pointer.gif);
+	background-position: top;
+	background-repeat: no-repeat;
+	padding: 10px 0 0 0;
+}
+
+div.autosuggest div.as_header,
+div.autosuggest div.as_footer
+{
+	position: relative;
+	height: 6px;
+	padding: 0 6px;
+	background-image: url(images/img_inquisitor/ul_corner_tr.gif);
+	background-position: top right;
+	background-repeat: no-repeat;
+	overflow: hidden;
+}
+div.autosuggest div.as_footer
+{
+	background-image: url(images/img_inquisitor/ul_corner_br.gif);
+}
+
+div.autosuggest div.as_header div.as_corner,
+div.autosuggest div.as_footer div.as_corner
+{
+	position: absolute;
+	top: 0;
+	left: 0;
+	height: 6px;
+	width: 6px;
+	background-image: url(images/img_inquisitor/ul_corner_tl.gif);
+	background-position: top left;
+	background-repeat: no-repeat;
+}
+div.autosuggest div.as_footer div.as_corner
+{
+	background-image: url(images/img_inquisitor/ul_corner_bl.gif);
+}
+div.autosuggest div.as_header div.as_bar,
+div.autosuggest div.as_footer div.as_bar
+{
+	height: 6px;
+	overflow: hidden;
+	background-color: #333;
+}
+
+
+div.autosuggest ul
+{
+	list-style: none;
+	margin: 0 0 -4px 0;
+	padding: 0;
+	overflow: hidden;
+	background-color: #333;
+}
+
+div.autosuggest ul li
+{
+	color: #ccc;
+	padding: 0;
+	margin: 0 4px 4px;
+	text-align: left;
+}
+
+div.autosuggest ul li a
+{
+	color: #ccc;
+	display: block;
+	text-decoration: none;
+	background-color: transparent;
+	text-shadow: #000 0px 0px 5px;
+	position: relative;
+	padding: 0;
+	width: 100%;
+}
+div.autosuggest ul li a:hover
+{
+	background-color: #444;
+}
+div.autosuggest ul li.as_highlight a:hover
+{
+	background-color: #1B5CCD;
+}
+
+div.autosuggest ul li a span
+{
+	display: block;
+	padding: 3px 6px;
+	font-weight: bold;
+}
+
+div.autosuggest ul li a span small
+{
+	font-weight: normal;
+	color: #999;
+}
+
+div.autosuggest ul li.as_highlight a span small
+{
+	color: #ccc;
+}
+
+div.autosuggest ul li.as_highlight a
+{
+	color: #fff;
+	background-color: #1B5CCD;
+	background-image: url(images/img_inquisitor/hl_corner_br.gif);
+	background-position: bottom right;
+	background-repeat: no-repeat;
+}
+
+div.autosuggest ul li.as_highlight a span
+{
+	background-image: url(images/img_inquisitor/hl_corner_bl.gif);
+	background-position: bottom left;
+	background-repeat: no-repeat;
+}
+
+div.autosuggest ul li a .tl,
+div.autosuggest ul li a .tr
+{
+	background-image: transparent;
+	background-repeat: no-repeat;
+	width: 6px;
+	height: 6px;
+	position: absolute;
+	top: 0;
+	padding: 0;
+	margin: 0;
+}
+div.autosuggest ul li a .tr
+{
+	right: 0;
+}
+
+div.autosuggest ul li.as_highlight a .tl
+{
+	left: 0;
+	background-image: url(images/img_inquisitor/hl_corner_tl.gif);
+	background-position: bottom left;
+}
+
+div.autosuggest ul li.as_highlight a .tr
+{
+	right: 0;
+	background-image: url(images/img_inquisitor/hl_corner_tr.gif);
+	background-position: bottom right;
+}
+
+
+
+div.autosuggest ul li.as_warning
+{
+	font-weight: bold;
+	text-align: center;
+}
+
+div.autosuggest ul em
+{
+	font-style: normal;
+	color: #6EADE7;
+}

--- a/contractDashboard.kpf
+++ b/contractDashboard.kpf

--- a/cutenews/LICENSE.txt
+++ b/cutenews/LICENSE.txt

--- a/cutenews/README.htm
+++ b/cutenews/README.htm

--- a/cutenews/data/.htaccess
+++ b/cutenews/data/.htaccess

--- a/cutenews/data/Default.tpl
+++ b/cutenews/data/Default.tpl

--- a/cutenews/data/Headlines.tpl
+++ b/cutenews/data/Headlines.tpl

--- a/cutenews/data/archives/index.htm
+++ b/cutenews/data/archives/index.htm

--- a/cutenews/data/auto_archive.db.php
+++ b/cutenews/data/auto_archive.db.php

--- a/cutenews/data/backup/index.html
+++ b/cutenews/data/backup/index.html

--- a/cutenews/data/cat.num.php
+++ b/cutenews/data/cat.num.php

--- a/cutenews/data/category.db.php
+++ b/cutenews/data/category.db.php

--- a/cutenews/data/comments.txt
+++ b/cutenews/data/comments.txt

--- a/cutenews/data/config.php
+++ b/cutenews/data/config.php

--- a/cutenews/data/emoticons/.htaccess
+++ b/cutenews/data/emoticons/.htaccess

 Binary files a/cutenews/data/emoticons/angry.gif and b/cutenews/data/emoticons/angry.gif differ
 Binary files a/cutenews/data/emoticons/crying.gif and b/cutenews/data/emoticons/crying.gif differ
--- a/cutenews/data/emoticons/index.html
+++ b/cutenews/data/emoticons/index.html

 Binary files a/cutenews/data/emoticons/laughing.gif and b/cutenews/data/emoticons/laughing.gif differ
 Binary files a/cutenews/data/emoticons/sad.gif and b/cutenews/data/emoticons/sad.gif differ
 Binary files a/cutenews/data/emoticons/smile.gif and b/cutenews/data/emoticons/smile.gif differ
 Binary files a/cutenews/data/emoticons/tongue.gif and b/cutenews/data/emoticons/tongue.gif differ
 Binary files a/cutenews/data/emoticons/wassat.gif and b/cutenews/data/emoticons/wassat.gif differ
 Binary files a/cutenews/data/emoticons/wink.gif and b/cutenews/data/emoticons/wink.gif differ
--- a/cutenews/data/flood.db.php
+++ b/cutenews/data/flood.db.php

--- a/cutenews/data/index.html
+++ b/cutenews/data/index.html

--- a/cutenews/data/ipban.db.php
+++ b/cutenews/data/ipban.db.php

--- a/cutenews/data/news.txt
+++ b/cutenews/data/news.txt

--- a/cutenews/data/postponed_news.txt
+++ b/cutenews/data/postponed_news.txt

--- a/cutenews/data/rss.tpl
+++ b/cutenews/data/rss.tpl

--- a/cutenews/data/rss_config.php
+++ b/cutenews/data/rss_config.php

--- a/cutenews/data/unapproved_news.txt
+++ b/cutenews/data/unapproved_news.txt

--- a/cutenews/data/upimages/.htaccess
+++ b/cutenews/data/upimages/.htaccess

 Binary files a/cutenews/data/upimages/cutenews-banner.gif and b/cutenews/data/upimages/cutenews-banner.gif differ
--- a/cutenews/data/upimages/index.html
+++ b/cutenews/data/upimages/index.html

--- a/cutenews/data/users.db.php
+++ b/cutenews/data/users.db.php

--- a/cutenews/example1.php
+++ b/cutenews/example1.php

--- a/cutenews/example2.php
+++ b/cutenews/example2.php

--- a/cutenews/inc/.htaccess
+++ b/cutenews/inc/.htaccess

--- a/cutenews/inc/about.mdu
+++ b/cutenews/inc/about.mdu

--- a/cutenews/inc/addnews.mdu
+++ b/cutenews/inc/addnews.mdu

--- a/cutenews/inc/categories.mdu
+++ b/cutenews/inc/categories.mdu

--- a/cutenews/inc/debug.mdu
+++ b/cutenews/inc/debug.mdu

--- a/cutenews/inc/editcomments.mdu
+++ b/cutenews/inc/editcomments.mdu

--- a/cutenews/inc/editnews.mdu
+++ b/cutenews/inc/editnews.mdu

--- a/cutenews/inc/editusers.mdu
+++ b/cutenews/inc/editusers.mdu

--- a/cutenews/inc/functions.inc.php
+++ b/cutenews/inc/functions.inc.php

--- a/cutenews/inc/help.mdu
+++ b/cutenews/inc/help.mdu

--- a/cutenews/inc/images.mdu
+++ b/cutenews/inc/images.mdu

--- a/cutenews/inc/ipban.mdu
+++ b/cutenews/inc/ipban.mdu

--- a/cutenews/inc/main.mdu
+++ b/cutenews/inc/main.mdu

--- a/cutenews/inc/massactions.mdu
+++ b/cutenews/inc/massactions.mdu

--- a/cutenews/inc/options.mdu
+++ b/cutenews/inc/options.mdu

--- a/cutenews/inc/preview.mdu
+++ b/cutenews/inc/preview.mdu

--- a/cutenews/inc/shows.inc.php
+++ b/cutenews/inc/shows.inc.php

--- a/cutenews/inc/tools.mdu
+++ b/cutenews/inc/tools.mdu

--- a/cutenews/inc/wizards.mdu
+++ b/cutenews/inc/wizards.mdu

--- a/cutenews/index.php
+++ b/cutenews/index.php

--- a/cutenews/register.php
+++ b/cutenews/register.php

--- a/cutenews/remember.js
+++ b/cutenews/remember.js

--- a/cutenews/rss.php
+++ b/cutenews/rss.php

--- a/cutenews/rte/blank.htm
+++ b/cutenews/rte/blank.htm

 Binary files a/cutenews/rte/images/Thumbs.db and b/cutenews/rte/images/Thumbs.db differ
 Binary files a/cutenews/rte/images/bgcolor.gif and b/cutenews/rte/images/bgcolor.gif differ
 Binary files a/cutenews/rte/images/blackdot.gif and b/cutenews/rte/images/blackdot.gif differ
 Binary files a/cutenews/rte/images/bold.gif and b/cutenews/rte/images/bold.gif differ
 Binary files a/cutenews/rte/images/centre.gif and b/cutenews/rte/images/centre.gif differ
 Binary files a/cutenews/rte/images/copy.gif and b/cutenews/rte/images/copy.gif differ
 Binary files a/cutenews/rte/images/cut.gif and b/cutenews/rte/images/cut.gif differ
 Binary files a/cutenews/rte/images/hr.gif and b/cutenews/rte/images/hr.gif differ
 Binary files a/cutenews/rte/images/hyperlink.gif and b/cutenews/rte/images/hyperlink.gif differ
 Binary files a/cutenews/rte/images/image.gif and b/cutenews/rte/images/image.gif differ
 Binary files a/cutenews/rte/images/indent.gif and b/cutenews/rte/images/indent.gif differ
 Binary files a/cutenews/rte/images/insert_table.gif and b/cutenews/rte/images/insert_table.gif differ
 Binary files a/cutenews/rte/images/italic.gif and b/cutenews/rte/images/italic.gif differ
 Binary files a/cutenews/rte/images/justifyfull.gif and b/cutenews/rte/images/justifyfull.gif differ
 Binary files a/cutenews/rte/images/left_just.gif and b/cutenews/rte/images/left_just.gif differ
 Binary files a/cutenews/rte/images/list.gif and b/cutenews/rte/images/list.gif differ
 Binary files a/cutenews/rte/images/numbered_list.gif and b/cutenews/rte/images/numbered_list.gif differ
 Binary files a/cutenews/rte/images/outdent.gif and b/cutenews/rte/images/outdent.gif differ
 Binary files a/cutenews/rte/images/paste.gif and b/cutenews/rte/images/paste.gif differ
 Binary files a/cutenews/rte/images/redo.gif and b/cutenews/rte/images/redo.gif differ
 Binary files a/cutenews/rte/images/right_just.gif and b/cutenews/rte/images/right_just.gif differ
 Binary files a/cutenews/rte/images/smiley.gif and b/cutenews/rte/images/smiley.gif differ
 Binary files a/cutenews/rte/images/spellcheck.gif and b/cutenews/rte/images/spellcheck.gif differ
 Binary files a/cutenews/rte/images/textcolor.gif and b/cutenews/rte/images/textcolor.gif differ
 Binary files a/cutenews/rte/images/underline.gif and b/cutenews/rte/images/underline.gif differ
 Binary files a/cutenews/rte/images/undo.gif and b/cutenews/rte/images/undo.gif differ
--- a/cutenews/rte/insert_link.htm
+++ b/cutenews/rte/insert_link.htm

--- a/cutenews/rte/insert_table.htm
+++ b/cutenews/rte/insert_table.htm

--- a/cutenews/rte/palette.htm
+++ b/cutenews/rte/palette.htm

--- a/cutenews/rte/richtext.js
+++ b/cutenews/rte/richtext.js

--- a/cutenews/rte/rte.css
+++ b/cutenews/rte/rte.css

--- a/cutenews/search.php
+++ b/cutenews/search.php

--- a/cutenews/show_archives.php
+++ b/cutenews/show_archives.php

--- a/cutenews/show_news.php
+++ b/cutenews/show_news.php

--- a/cutenews/skins/compact.skin.php
+++ b/cutenews/skins/compact.skin.php

--- a/cutenews/skins/cute.js
+++ b/cutenews/skins/cute.js

--- a/cutenews/skins/default.skin.php
+++ b/cutenews/skins/default.skin.php

 Binary files a/cutenews/skins/images/Thumbs.db and b/cutenews/skins/images/Thumbs.db differ
 Binary files a/cutenews/skins/images/addnews.gif and b/cutenews/skins/images/addnews.gif differ
 Binary files a/cutenews/skins/images/archives.gif and b/cutenews/skins/images/archives.gif differ
 Binary files a/cutenews/skins/images/baloon.gif and b/cutenews/skins/images/baloon.gif differ
 Binary files a/cutenews/skins/images/blank.gif and b/cutenews/skins/images/blank.gif differ
 Binary files a/cutenews/skins/images/editnews.gif and b/cutenews/skins/images/editnews.gif differ
 Binary files a/cutenews/skins/images/error.gif and b/cutenews/skins/images/error.gif differ
 Binary files a/cutenews/skins/images/help_small.gif and b/cutenews/skins/images/help_small.gif differ
 Binary files a/cutenews/skins/images/home.gif and b/cutenews/skins/images/home.gif differ
 Binary files a/cutenews/skins/images/images.gif and b/cutenews/skins/images/images.gif differ
 Binary files a/cutenews/skins/images/info.gif and b/cutenews/skins/images/info.gif differ
 Binary files a/cutenews/skins/images/options.gif and b/cutenews/skins/images/options.gif differ
 Binary files a/cutenews/skins/images/question.gif and b/cutenews/skins/images/question.gif differ
 Binary files a/cutenews/skins/images/rss_icon.gif and b/cutenews/skins/images/rss_icon.gif differ
 Binary files a/cutenews/skins/images/user.gif and b/cutenews/skins/images/user.gif differ
 Binary files a/cutenews/skins/images/users.gif and b/cutenews/skins/images/users.gif differ
 Binary files a/cutenews/skins/images/view_image.gif and b/cutenews/skins/images/view_image.gif differ
 Binary files a/cutenews/skins/images/wizard.gif and b/cutenews/skins/images/wizard.gif differ
--- a/cutenews/skins/rss_style.css
+++ b/cutenews/skins/rss_style.css

--- a/cutenews/skins/simple.skin.php
+++ b/cutenews/skins/simple.skin.php

--- a/displayAgency.php
+++ b/displayAgency.php
@@ -19,18 +19,57 @@
   

   --- info

   website, procurement plan, annual reports

+  Breakdown of divisions/branches

   Breakdown percentage,number,value by procurement type

   Histograph, overlaying number value reported per week over X years

   Compliance statistics: amendments, delay in reporting average and number completely late*/

+  

+    $query = "SELECT CNID, description, value, agencyName, category, contractStart, supplierName

+    FROM `contractnotice`

+    WHERE agencyName = '".mysql_real_escape_string($agency)."'

+    ORDER BY value DESC";

+    echo $query;

+  $result = mysql_query($query);

+

+  echo "<table>  <thead>

+    <tr>

+      <th>Contract Notice Number</th>

+      <th>Contract Description</th>

+      <th>Total Contract Value</th>

+      <th>Agency</th>

+      <th>Contract Start Date</th>

+      <th>Supplier</th>

+    </tr>

+  </thead>";

+  while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

+    setlocale(LC_MONETARY, 'en_US');

+    $value = number_format(doubleval($row['value']) , 2);

+    echo ("<tr>

+    <td><a href=\"displayContract.php?CNID={$row['CNID']}\">{$row['CNID']}</a></td>

+    <td><b>{$row['description']}</b></a></td>

+    <td>\$$value</td><td>{$row['agencyName']}</td>

+    <td>{$row['contractStart']}</td>

+    <td>{$row['supplierName']}</td>

+    </tr>");

+  }

+  echo "</table>";

+  mysql_free_result($result);

 } else {

-    

+    /*

+     split by portfolio

+    */

 include_header("Agencies");

   $query = "SELECT SUM(value), agencyName

 FROM `contractnotice`

 WHERE childCN = 0

 GROUP BY agencyName ";

   $result = mysql_query($query);

-  echo "<table>";

+  echo "<table>  <thead>

+    <tr>

+      <th>Agency</th>

+      <th>Total Contracts Value</th>

+    </tr>

+  </thead>";

   while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

     setlocale(LC_MONETARY, 'en_US');

     $value = number_format(doubleval($row[0]) , 2);


--- /dev/null
+++ b/displayAmendments.php
@@ -1,1 +1,32 @@
+<?php

+include_once ("./lib/common.inc.php");

+    include_header("Amendments");

+$query = "select CNID, description, value, pvalue, (value - pvalue) as diff from contractnotice, (SELECT CNID as cn, childCN as ccn, value as pvalue FROM contractnotice where childCN > 0) a".

+" where ".$agencyQ.$yearQ."CNID = ccn AND (value - pvalue) <> 0 order by diff DESC";

+$result = mysql_query($query);

+  echo "<table>  <thead>

+    <tr>

+      <th>Contract</th>

+      <th>Original Value</th>

+    <th>Amended Value</th>

+    <th>Difference</th>

+    </tr>

+  </thead>";

+if ($result) {

+while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

+  setlocale(LC_MONETARY, 'en_US');

+  $value = number_format(doubleval($row['value']) , 2);

+  $pvalue = number_format(doubleval($row['pvalue']) , 2);

+  $diff = number_format(doubleval($row['diff']) , 2);

+  echo ("<tr>");

+  echo "<td><A href=\"displayContract.php?CNID={$row['CNID']}\"><b>{$row['description']}</b></a></td>";

+  echo "<td>\$$pvalue</td><td>\$$value</td><td>\$$diff</td></tr>";

+}

+} else {

+echo mysql_error();

+}

+echo "</table>";

+mysql_free_result($result);

+include_footer();

+?>

 

--- a/displayCalendar.php
+++ b/displayCalendar.php
@@ -1,25 +1,77 @@
 <?php

 include_once("./lib/common.inc.php");

 

+include_header("Months and Years");

+

+if ($_REQUEST['month']) {

+    echo "<center><h1>".$_REQUEST['month']."</h1></center>";

+$monthParts = explode("-",$_REQUEST['month']);

+  $query = "SELECT CNID, description, value, agencyName, category, contractStart, supplierName

+    FROM `contractnotice`

+    WHERE childCN = 0 

+    AND YEAR(contractStart) = {$monthParts[1]}

+    AND MONTH(contractStart)  = {$monthParts[0]}

+    ORDER BY value DESC";

+  $result = mysql_query($query);

+echo '<img src="graphs/displayMethodCountGraph.php?month=' . stripslashes($supplier) . '">';

+   echo '<img src="graphs/displayCnCGraph.php?month=' . stripslashes($supplier) . '">';

+

+  echo "<table>  <thead>

+    <tr>

+      <th>Contract Notice Number</th>

+      <th>Contract Description</th>

+      <th>Total Contract Value</th>

+      <th>Agency</th>

+      <th>Contract Start Date</th>

+      <th>Supplier</th>

+    </tr>

+  </thead>";

+  while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

+    setlocale(LC_MONETARY, 'en_US');

+    $value = number_format(doubleval($row['value']) , 2);

+    echo ("<tr>

+    <td><a href=\"displayContract.php?CNID={$row['CNID']}\">{$row['CNID']}</a></td>

+    <td><b>{$row['description']}</b></a></td>

+    <td>\$$value</td><td>{$row['agencyName']}</td>

+    <td>{$row['contractStart']}</td>

+    <td>{$row['supplierName']}</td>

+    </tr>");

+  }

+  echo "</table>";

+  mysql_free_result($result);

+} else {

 /*

+     split by year

 todo:

-Year/Month drilldown - largest contracts, agencies, suppliers*/

+Year/Month drilldown - largest contracts, agencies, suppliers

+count per month

+big picture graphs?*/

 

 

-include_header("Months and Years");

+echo '<img src="graphs/displayContractStartingGraph.php">';

+echo '<img src="graphs/displayContractPublishedGraph.php">';

+

+

 $query = "SELECT YEAR(contractStart), MONTH(contractStart),

-value FROM `contractnotice` WHERE childCN = 0 GROUP BY MONTH(contractStart), YEAR(contractStart) ORDER BY YEAR(contractStart), MONTH(contractStart) ";

+SUM(value) as val, count(1) as count FROM `contractnotice` WHERE childCN = 0 GROUP BY MONTH(contractStart), YEAR(contractStart) ORDER BY YEAR(contractStart), MONTH(contractStart) ";

 

 $result = mysql_query($query);

-echo "<table>";

+  echo "<table>  <thead>

+    <tr>

+      <th>Month/Year</th>

+      <th>Total Contracts Value</th>

+      <th>Number of Contracts</th>

+    </tr>

+  </thead>";

 while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

 setlocale(LC_MONETARY, 'en_US');

-$value = number_format(doubleval($row["value"]),2);

+$value = number_format(doubleval($row["val"]),2);

 $month_name = date( 'F', mktime(0, 0, 0, $row[1]) );

-    echo ("<tr><td><b>$month_name {$row[0]}</b></td><td>\$$value</td></tr>");

+    echo ("<tr><td><b><a href=\"?month=$row[1]-$row[0]\">$month_name {$row[0]}</a></b></td><td>\$$value</td><td>({$row['count']} contracts)</td></tr>");

 }

 echo "</table>";

 mysql_free_result($result);

-

+}

 include_footer();

-?>
+?>

+

--- a/displayCategory.php
+++ b/displayCategory.php
@@ -9,7 +9,16 @@
     AND category = '" . $_REQUEST['category'] . "'

     ORDER BY value DESC";

   $result = mysql_query($query);

-  echo "<table>";

+    echo "<table>  <thead>

+    <tr>

+      <th>Contract Notice Number</th>

+      <th>Contract Description</th>

+      <th>Total Contract Value</th>

+      <th>Agency</th>

+      <th>Contract Start Date</th>

+      <th>Supplier</th>

+    </tr>

+  </thead>";

   while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

     setlocale(LC_MONETARY, 'en_US');

     $value = number_format(doubleval($row['value']) , 2);

@@ -24,14 +33,21 @@
   echo "</table>";

   mysql_free_result($result);

 } else {

-    

+    /*

+     split by main categories

+    */

     include_header("Categories");

 $query = "SELECT sum(value), category

 FROM `contractnotice`

 WHERE childCN = 0 

 GROUP BY category ORDER BY sum(value) DESC ";

 $result = mysql_query($query);

-echo "<table>";

+  echo "<table>  <thead>

+    <tr>

+      <th>Category</th>

+      <th>Total Contracts Value</th>

+    </tr>

+  </thead>";

 while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

   setlocale(LC_MONETARY, 'en_US');

   $value = number_format(doubleval($row[0]) , 2);


--- a/displayConfidentialities.php
+++ b/displayConfidentialities.php
@@ -1,4 +1,31 @@
-agencies that use alot of consultacies
+<?php
+
+include_once("./lib/common.inc.php");
+/*
+
+
+agencies that use alot of Confidentialities
 suppliers that provide alot
 how much is spent overall per year
+*/
 
+include_header("Confidentialities");
+$query = "SELECT value, procurementMethod
+FROM `contractnotice`
+GROUP BY procurementMethod ";
+
+$result = mysql_query($query);
+
+echo "<table>";
+while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {
+setlocale(LC_MONETARY, 'en_US');
+$value = number_format(doubleval($row[0]),2);
+    echo ("<tr><td><b>{$row[1]}</b></td><td>\$$value</td></tr>");
+}
+echo "</table>";
+mysql_free_result($result);
+include_footer();
+?>
+
+
+

--- a/displayConsultancies.php
+++ b/displayConsultancies.php
@@ -1,4 +1,31 @@
+<?php
+
+include_once("./lib/common.inc.php");
+/*
+
+
 agencies that use alot of consultacies
 suppliers that provide alot
 how much is spent overall per year
+*/
 
+include_header("Consultancies");
+$query = "SELECT value, procurementMethod
+FROM `contractnotice`
+GROUP BY procurementMethod ";
+
+$result = mysql_query($query);
+
+echo "<table>";
+while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {
+setlocale(LC_MONETARY, 'en_US');
+$value = number_format(doubleval($row[0]),2);
+    echo ("<tr><td><b>{$row[1]}</b></td><td>\$$value</td></tr>");
+}
+echo "</table>";
+mysql_free_result($result);
+include_footer();
+?>
+
+
+

--- a/displayContract.php
+++ b/displayContract.php

file:a/displayLatestUpdate.php (deleted)
--- a/displayLatestUpdate.php
+++ /dev/null
@@ -1,23 +1,1 @@
-<?php

-include_once("./lib/common.inc.php");

-$query = "SELECT DATE(importDate) as importday, count(*) as count, min(publishDate) as start, max(publishDate) as end 

-FROM `contractnotice` WHERE childCN = 0 AND parentCN = 0 AND DATE(importDate) in (select * from (SELECT DATE(importDate) 

-FROM `contractnotice` ORDER BY `importDate` DESC limit 1) alias)";

-$result = mysql_query($query);

-echo "<table>";

-$stats = mysql_fetch_array($result, MYSQL_BOTH);

-echo $stats["count"] . " new records in period " . $stats["start"] . "  to " . $stats["end"] ."<br>";

-

-

-$query = "SELECT DATE(importDate) as importday, count(*) as count, min(publishDate) as start, max(publishDate) as end 

-FROM `contractnotice` WHERE (childCN != 0 OR parentCN != 0) AND DATE(importDate) in (select * from (SELECT DATE(importDate) 

-FROM `contractnotice` ORDER BY `importDate` DESC limit 1) alias)";

-$result = mysql_query($query);

-echo "<table>";

-$stats = mysql_fetch_array($result, MYSQL_BOTH);

-echo $stats["count"] . " updated records in period " . $stats["start"] . "  to " . $stats["end"] ."<br>";

-

-

-echo "Last updated: ". $stats["importday"]."<br>";

-/* Check for null Procurement method and 0 ABN when not ABN exempt */

-?>
+

--- a/displayMap.php
+++ b/displayMap.php

--- a/displayProcurementMethod.php
+++ b/displayProcurementMethod.php
@@ -10,8 +10,9 @@
 */

 

 include_header("Procurement Methods");

-$query = "SELECT value, procurementMethod

+$query = "SELECT SUM(value) as value, procurementMethod

 FROM `contractnotice`

+WHERE childCN = 0

 GROUP BY procurementMethod ";

 

 $result = mysql_query($query);


--- a/displaySupplier.php
+++ b/displaySupplier.php
@@ -3,13 +3,13 @@
 if ($_REQUEST['supplier']) {
     
 include_header("Supplier");
-  $supplier = htmlentities(strip_tags($_REQUEST['supplier']));
-  echo '<img src="graphs/displayMethodCountGraph.php?supplier=' . stripslashes($supplier) . '">';
-   echo '<img src="graphs/displayCnCGraph.php?supplier=' . stripslashes($supplier) . '">';
-   echo '<img src="graphs/displayMethodValueGraph.php?supplier=' . stripslashes($supplier) . '">';
+  $supplierS = htmlentities(strip_tags($_REQUEST['supplier']));
+  echo '<img src="graphs/displayMethodCountGraph.php?supplier=' . stripslashes($supplierS) . '">';
+   echo '<img src="graphs/displayCnCGraph.php?supplier=' . stripslashes($supplierS) . '">';
+   echo '<img src="graphs/displayMethodValueGraph.php?supplier=' . stripslashes($supplierS) . '">';
   /*lobbyist ties
   
-  
+  links to ABR/ASIC/Google News/ASX/Court records
   
   total value to various agencies (bar graph)
   
@@ -18,8 +18,42 @@
   spread of contract values
   
   spread of industries (textual?)*/
+    $query = "SELECT CNID, description, value, agencyName, category, contractStart, supplierName
+    FROM `contractnotice` WHERE
+    $supplierQ $standardQ
+    ORDER BY value DESC";
+    echo $query;
+  $result = mysql_query($query);
+echo '<img src="graphs/displayMethodCountGraph.php?month=' . stripslashes($supplier) . '">';
+   echo '<img src="graphs/displayCnCGraph.php?month=' . stripslashes($supplier) . '">';
+
+  echo "<table>  <thead>
+    <tr>
+      <th>Contract Notice Number</th>
+      <th>Contract Description</th>
+      <th>Total Contract Value</th>
+      <th>Agency</th>
+      <th>Contract Start Date</th>
+      <th>Supplier</th>
+    </tr>
+  </thead>";
+  while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {
+    setlocale(LC_MONETARY, 'en_US');
+    $value = number_format(doubleval($row['value']) , 2);
+    echo ("<tr>
+    <td><a href=\"displayContract.php?CNID={$row['CNID']}\">{$row['CNID']}</a></td>
+    <td><b>{$row['description']}</b></a></td>
+    <td>\$$value</td><td>{$row['agencyName']}</td>
+    <td>{$row['contractStart']}</td>
+    <td>{$row['supplierName']}</td>
+    </tr>");
+  }
+  echo "</table>";
+  mysql_free_result($result);
 } else {
-    
+    /*
+     histograph of supplier size/value
+    */
 include_header("Suppliers");
   $query = "SELECT SUM(value) as val, supplierName, supplierABN
 FROM `contractnotice`
@@ -28,7 +62,12 @@
 ORDER BY val DESC
 LIMIT 100";
   $result = mysql_query($query);
-  echo "<table>";
+   echo "<table>  <thead>
+    <tr>
+       <th>Supplier</th>
+      <th>Total Contract Value</th>
+    </tr>
+  </thead>";
   while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {
     setlocale(LC_MONETARY, 'en_US');
     $value = number_format(doubleval($row['val']) , 2);

--- a/futureindex.php
+++ b/futureindex.php

--- a/graphs/displayAgenciesGraph.php
+++ b/graphs/displayAgenciesGraph.php
@@ -1,7 +1,6 @@
 <?php
 include_once ("../lib/common.inc.php");
 $topX = 15;
-$startYear = 2007;
 $query = "SELECT SUM(value) as val, agencyName FROM `contractnotice` WHERE (YEAR(contractStart) >= $startYear) AND childCN = 0
 GROUP BY agencyName ORDER BY val DESC limit $topX";
 $result = mysql_query($query);

--- a/graphs/displayAgencySuppliersGraph.php
+++ b/graphs/displayAgencySuppliersGraph.php
@@ -2,7 +2,6 @@
 include_once ("../lib/common.inc.php");

 $agency = "AusAid";

 $topX = 15;

-$startYear = 2007;

 $query = "SELECT SUM(value) as val, supplierName FROM `contractnotice` WHERE (YEAR(contractStart) >= $startYear) AND childCN = 0 AND agencyName = '$agency'

 GROUP BY lower(supplierName) ORDER BY val DESC limit $topX";

 $result = mysql_query($query);


--- a/graphs/displayCnCGraph.php
+++ b/graphs/displayCnCGraph.php
@@ -3,8 +3,8 @@
 // Width and height of the graph

 $width = 800;

 $height = 300;

-$query = "select procurementMethod, count(1) as count, value, MONTH(contractStart) as month, YEAR(contractStart) as year from `contractnotice`

-where $agencyQ $supplierQ childCN = 0 AND YEAR(contractStart) >= 2007 AND YEAR(contractStart) <= 2009 group by procurementMethod,year,month order by procurementMethod,year,month";

+$query = "select procurementMethod, count(1) as count, SUM(value) as val, MONTH(contractStart) as month, YEAR(contractStart) as year from `contractnotice`

+where $agencyQ $supplierQ $standardQ group by procurementMethod,year,month order by procurementMethod,year,month";

 $result = mysql_query($query);

 $methods = Array("Direct","Open","Select");

 $dates = Array();

@@ -13,7 +13,7 @@
 $maxValue = 0;

 while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {

   setlocale(LC_MONETARY, 'en_US');

-  if ($row['value'] > $maxValue) $maxValue = $row['value'];

+  if ($row['val'] > $maxValue) $maxValue = $row['val'];

   $date = date( 'F ', mktime(0, 0, 0, $row["month"]) ). $row["year"];

   if (array_search($date,$dates) === false ) {

     $dates[$row["year"]*100 + $row["month"]] = $date;

@@ -57,7 +57,7 @@
 $graph2->Set90AndMargin(105, 45, 45, 45);

 // Setup a title for the graph

 $graph2->title->Set($agency);

-$graph2->SetUserFont("ttf-liberation/LiberationSans-Regular.ttf");

+$graph2->SetUserFont("liberation/LiberationSans-Regular.ttf");

 $graph2->title->SetFont(FF_USERFONT, FS_NORMAL, 12);

 // Setup font for axis

 $graph2->xaxis->SetFont(FF_USERFONT, FS_NORMAL, 10);


--- a/graphs/displayContractPublishedGraph.php
+++ b/graphs/displayContractPublishedGraph.php
@@ -1,7 +1,7 @@
 <?php

 include_once("../lib/common.inc.php");

 $query = "SELECT YEAR(publishDate), MONTH(publishDate),

-value, count(1) as count FROM `contractnotice`

+SUM(value) as val, count(1) as count FROM `contractnotice`

 WHERE (YEAR(publishDate) >= 2008)

 AND childCN = 0

 GROUP BY MONTH(publishDate), YEAR(publishDate) 

@@ -12,11 +12,11 @@
 $values = Array();

 while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

 setlocale(LC_MONETARY, 'en_US');

-$value = number_format(doubleval($row["value"]),2);

+$value = number_format(doubleval($row["val"]),2);

 $month_name = date( 'F', mktime(0, 0, 0, $row[1]) );

 	$dates[] = $month_name." {$row[0]}";

 	$counts[] = doubleval($row["count"]);

-	$values[] = doubleval($row["value"]);

+	$values[] = doubleval($row["val"]);

 }

 mysql_free_result($result);

 

@@ -31,8 +31,8 @@
 $graph->SetScale('textlog');

  

 // Setup a title for the graph

-$graph->title->Set('Contracts Starting - All Agencies since July 2008');

-$graph->SetUserFont("ttf-liberation/LiberationSans-Regular.ttf");

+$graph->title->Set('Contracts Published - All Agencies since July 2008');

+$graph->SetUserFont("liberation/LiberationSans-Regular.ttf");

 $graph->title->SetFont(FF_USERFONT,FS_NORMAL,12);

 

 // Setup font for axis


--- a/graphs/displayContractStartingGraph.php
+++ b/graphs/displayContractStartingGraph.php
@@ -1,7 +1,7 @@
 <?php

 include_once("../lib/common.inc.php");

 $query = "SELECT YEAR(contractStart), MONTH(contractStart),

-value, count(1) as count FROM `contractnotice`

+SUM(value) as val, count(1) as count FROM `contractnotice`

 WHERE (YEAR(contractStart) >= 2008)

 AND childCN = 0

 GROUP BY MONTH(contractStart), YEAR(contractStart) 

@@ -12,11 +12,11 @@
 $values = Array();

 while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {

 setlocale(LC_MONETARY, 'en_US');

-$value = number_format(doubleval($row["value"]),2);

+$value = number_format(doubleval($row["val"]),2);

 $month_name = date( 'F', mktime(0, 0, 0, $row[1]) );

 	$dates[] = $month_name." {$row[0]}";

 	$counts[] = doubleval($row["count"]);

-	$values[] = doubleval($row["value"]);

+	$values[] = doubleval($row["val"]);

 }

 mysql_free_result($result);

 

@@ -32,7 +32,7 @@
  

 // Setup a title for the graph

 $graph->title->Set('Contracts Starting - All Agencies since July 2008');

-$graph->SetUserFont("ttf-liberation/LiberationSans-Regular.ttf");

+$graph->SetUserFont("liberation/LiberationSans-Regular.ttf");

 $graph->title->SetFont(FF_USERFONT,FS_NORMAL,12);

 

 // Setup font for axis


--- a/graphs/displayHeatmap.php
+++ b/graphs/displayHeatmap.php

--- a/graphs/displayMethodCountGraph.php
+++ b/graphs/displayMethodCountGraph.php
@@ -3,8 +3,8 @@
 // Width and height of the graph

 $width = 800;

 $height = 300;

-$query = "select procurementMethod, count(1) as count, value, MONTH(contractStart) as month, YEAR(contractStart) as year from `contractnotice`

-where $agencyQ $supplierQ childCN = 0 AND YEAR(contractStart) >= 2007 AND YEAR(contractStart) <= 2009 group by procurementMethod,year,month order by procurementMethod,year,month";

+$query = "select procurementMethod, count(1) as count, SUM(value) as value, MONTH(contractStart) as month, YEAR(contractStart) as year from `contractnotice`

+where $agencyQ $supplierQ $standardQ group by procurementMethod,year,month order by procurementMethod,year,month";

 $result = mysql_query($query);

 $methods = Array("Direct","Open","Select");

 $dates = Array();

@@ -37,7 +37,7 @@
 $graph->SetMargin(95, 145, 45, 100);

 // Setup a title for the graph

 $graph->title->Set($agencyQ.$supplierQ);

-$graph->SetUserFont("ttf-liberation/LiberationSans-Regular.ttf");

+$graph->SetUserFont("liberation/LiberationSans-Regular.ttf");

 $graph->title->SetFont(FF_USERFONT, FS_NORMAL, 12);

 // Setup font for axis

 $graph->xaxis->SetFont(FF_USERFONT, FS_NORMAL, 10);

@@ -80,7 +80,7 @@
 $graph2->Set90AndMargin(105, 45, 45, 45);

 // Setup a title for the graph

 $graph2->title->Set($agency);

-$graph2->SetUserFont("ttf-liberation/LiberationSans-Regular.ttf");

+$graph2->SetUserFont("liberation/LiberationSans-Regular.ttf");

 $graph2->title->SetFont(FF_USERFONT, FS_NORMAL, 12);

 // Setup font for axis

 $graph2->xaxis->SetFont(FF_USERFONT, FS_NORMAL, 10);


--- a/graphs/displayMethodValueGraph.php
+++ b/graphs/displayMethodValueGraph.php
@@ -3,8 +3,8 @@
 // Width and height of the graph

 $width = 800;

 $height = 300;

-$query = "select procurementMethod, value, MONTH(contractStart) as month, YEAR(contractStart) as year from `contractnotice`

-where $agencyQ $supplierQ childCN = 0 AND YEAR(contractStart) >= 2007 AND YEAR(contractStart) <= 2009 group by procurementMethod,year,month order by procurementMethod,year,month";

+$query = "select procurementMethod, SUM(value) as value, MONTH(contractStart) as month, YEAR(contractStart) as year from `contractnotice`

+where $agencyQ $supplierQ $standardQ group by procurementMethod,year,month order by procurementMethod,year,month";

 $result = mysql_query($query);

 $methods = Array("Direct","Open","Select");

 $dates = Array();

@@ -37,7 +37,7 @@
 $graph->SetMargin(95, 145, 45, 100);

 // Setup a title for the graph

 $graph->title->Set($agencyQ.$supplierQ);

-$graph->SetUserFont("ttf-liberation/LiberationSans-Regular.ttf");

+$graph->SetUserFont("liberation/LiberationSans-Regular.ttf");

 $graph->title->SetFont(FF_USERFONT, FS_NORMAL, 12);

 // Setup font for axis

 $graph->xaxis->SetFont(FF_USERFONT, FS_NORMAL, 10);


--- a/graphs/displaySuppliersGraph.php
+++ b/graphs/displaySuppliersGraph.php

 Binary files a/images/australia.png and b/images/australia.png differ
 Binary files /dev/null and b/images/img_inquisitor/.DS_Store differ
 Binary files /dev/null and b/images/img_inquisitor/._.DS_Store differ
 Binary files /dev/null and b/images/img_inquisitor/._as_pointer.gif differ
 Binary files /dev/null and b/images/img_inquisitor/._hl_corner_bl.gif differ
 Binary files /dev/null and b/images/img_inquisitor/._hl_corner_br.gif differ
 Binary files /dev/null and b/images/img_inquisitor/._hl_corner_tl.gif differ
 Binary files /dev/null and b/images/img_inquisitor/._hl_corner_tr.gif differ
 Binary files /dev/null and b/images/img_inquisitor/._ul_corner_bl.gif differ
 Binary files /dev/null and b/images/img_inquisitor/._ul_corner_br.gif differ
 Binary files /dev/null and b/images/img_inquisitor/._ul_corner_tl.gif differ
 Binary files /dev/null and b/images/img_inquisitor/._ul_corner_tr.gif differ
 Binary files /dev/null and b/images/img_inquisitor/_source/.DS_Store differ
 Binary files /dev/null and b/images/img_inquisitor/_source/._.DS_Store differ
 Binary files /dev/null and b/images/img_inquisitor/_source/._as_pointer.png differ
 Binary files /dev/null and b/images/img_inquisitor/_source/._li_corner.png differ
 Binary files /dev/null and b/images/img_inquisitor/_source/._ul_corner.png differ
 Binary files /dev/null and b/images/img_inquisitor/_source/as_pointer.png differ
 Binary files /dev/null and b/images/img_inquisitor/_source/li_corner.png differ
 Binary files /dev/null and b/images/img_inquisitor/_source/ul_corner.png differ
 Binary files /dev/null and b/images/img_inquisitor/as_pointer.gif differ
 Binary files /dev/null and b/images/img_inquisitor/hl_corner_bl.gif differ
 Binary files /dev/null and b/images/img_inquisitor/hl_corner_br.gif differ
 Binary files /dev/null and b/images/img_inquisitor/hl_corner_tl.gif differ
 Binary files /dev/null and b/images/img_inquisitor/hl_corner_tr.gif differ
 Binary files /dev/null and b/images/img_inquisitor/ul_corner_bl.gif differ
 Binary files /dev/null and b/images/img_inquisitor/ul_corner_br.gif differ
 Binary files /dev/null and b/images/img_inquisitor/ul_corner_tl.gif differ
 Binary files /dev/null and b/images/img_inquisitor/ul_corner_tr.gif differ
--- /dev/null
+++ b/lib/bsn.AutoSuggest_2.1.3_comp.js
@@ -1,1 +1,1 @@
-
+if(typeof(bsn)=="undefined")_b=bsn={};if(typeof(_b.Autosuggest)=="undefined")_b.Autosuggest={};else alert("Autosuggest is already set!");_b.AutoSuggest=function(b,c){if(!document.getElementById)return 0;this.fld=_b.DOM.gE(b);if(!this.fld)return 0;this.sInp="";this.nInpC=0;this.aSug=[];this.iHigh=0;this.oP=c?c:{};var k,def={minchars:1,meth:"get",varname:"input",className:"autosuggest",timeout:2500,delay:500,offsety:-5,shownoresults:true,noresults:"No results!",maxheight:250,cache:true,maxentries:25};for(k in def){if(typeof(this.oP[k])!=typeof(def[k]))this.oP[k]=def[k]}var p=this;this.fld.onkeypress=function(a){return p.onKeyPress(a)};this.fld.onkeyup=function(a){return p.onKeyUp(a)};this.fld.setAttribute("autocomplete","off")};_b.AutoSuggest.prototype.onKeyPress=function(a){var b=(window.event)?window.event.keyCode:a.keyCode;var c=13;var d=9;var e=27;var f=1;switch(b){case c:this.setHighlightedValue();f=0;break;case e:this.clearSuggestions();break}return f};_b.AutoSuggest.prototype.onKeyUp=function(a){var b=(window.event)?window.event.keyCode:a.keyCode;var c=38;var d=40;var e=1;switch(b){case c:this.changeHighlight(b);e=0;break;case d:this.changeHighlight(b);e=0;break;default:this.getSuggestions(this.fld.value)}return e};_b.AutoSuggest.prototype.getSuggestions=function(a){if(a==this.sInp)return 0;_b.DOM.remE(this.idAs);this.sInp=a;if(a.length<this.oP.minchars){this.aSug=[];this.nInpC=a.length;return 0}var b=this.nInpC;this.nInpC=a.length?a.length:0;var l=this.aSug.length;if(this.nInpC>b&&l&&l<this.oP.maxentries&&this.oP.cache){var c=[];for(var i=0;i<l;i++){if(this.aSug[i].value.substr(0,a.length).toLowerCase()==a.toLowerCase())c.push(this.aSug[i])}this.aSug=c;this.createList(this.aSug);return false}else{var d=this;var e=this.sInp;clearTimeout(this.ajID);this.ajID=setTimeout(function(){d.doAjaxRequest(e)},this.oP.delay)}return false};_b.AutoSuggest.prototype.doAjaxRequest=function(b){if(b!=this.fld.value)return false;var c=this;if(typeof(this.oP.script)=="function")var d=this.oP.script(encodeURIComponent(this.sInp));else var d=this.oP.script+this.oP.varname+"="+encodeURIComponent(this.sInp);if(!d)return false;var e=this.oP.meth;var b=this.sInp;var f=function(a){c.setSuggestions(a,b)};var g=function(a){alert("AJAX error: "+a)};var h=new _b.Ajax();h.makeRequest(d,e,f,g)};_b.AutoSuggest.prototype.setSuggestions=function(a,b){if(b!=this.fld.value)return false;this.aSug=[];if(this.oP.json){var c=eval('('+a.responseText+')');for(var i=0;i<c.results.length;i++){this.aSug.push({'id':c.results[i].id,'value':c.results[i].value,'info':c.results[i].info})}}else{var d=a.responseXML;var e=d.getElementsByTagName('results')[0].childNodes;for(var i=0;i<e.length;i++){if(e[i].hasChildNodes())this.aSug.push({'id':e[i].getAttribute('id'),'value':e[i].childNodes[0].nodeValue,'info':e[i].getAttribute('info')})}}this.idAs="as_"+this.fld.id;this.createList(this.aSug)};_b.AutoSuggest.prototype.createList=function(b){var c=this;_b.DOM.remE(this.idAs);this.killTimeout();if(b.length==0&&!this.oP.shownoresults)return false;var d=_b.DOM.cE("div",{id:this.idAs,className:this.oP.className});var e=_b.DOM.cE("div",{className:"as_corner"});var f=_b.DOM.cE("div",{className:"as_bar"});var g=_b.DOM.cE("div",{className:"as_header"});g.appendChild(e);g.appendChild(f);d.appendChild(g);var h=_b.DOM.cE("ul",{id:"as_ul"});for(var i=0;i<b.length;i++){var j=b[i].value;var k=j.toLowerCase().indexOf(this.sInp.toLowerCase());var l=j.substring(0,k)+"<em>"+j.substring(k,k+this.sInp.length)+"</em>"+j.substring(k+this.sInp.length);var m=_b.DOM.cE("span",{},l,true);if(b[i].info!=""){var n=_b.DOM.cE("br",{});m.appendChild(n);var o=_b.DOM.cE("small",{},b[i].info);m.appendChild(o)}var a=_b.DOM.cE("a",{href:"#"});var p=_b.DOM.cE("span",{className:"tl"}," ");var q=_b.DOM.cE("span",{className:"tr"}," ");a.appendChild(p);a.appendChild(q);a.appendChild(m);a.name=i+1;a.onclick=function(){c.setHighlightedValue();return false};a.onmouseover=function(){c.setHighlight(this.name)};var r=_b.DOM.cE("li",{},a);h.appendChild(r)}if(b.length==0&&this.oP.shownoresults){var r=_b.DOM.cE("li",{className:"as_warning"},this.oP.noresults);h.appendChild(r)}d.appendChild(h);var s=_b.DOM.cE("div",{className:"as_corner"});var t=_b.DOM.cE("div",{className:"as_bar"});var u=_b.DOM.cE("div",{className:"as_footer"});u.appendChild(s);u.appendChild(t);d.appendChild(u);var v=_b.DOM.getPos(this.fld);d.style.left=v.x+"px";d.style.top=(v.y+this.fld.offsetHeight+this.oP.offsety)+"px";d.style.width=this.fld.offsetWidth+"px";d.onmouseover=function(){c.killTimeout()};d.onmouseout=function(){c.resetTimeout()};document.getElementsByTagName("body")[0].appendChild(d);this.iHigh=0;var c=this;this.toID=setTimeout(function(){c.clearSuggestions()},this.oP.timeout)};_b.AutoSuggest.prototype.changeHighlight=function(a){var b=_b.DOM.gE("as_ul");if(!b)return false;var n;if(a==40)n=this.iHigh+1;else if(a==38)n=this.iHigh-1;if(n>b.childNodes.length)n=b.childNodes.length;if(n<1)n=1;this.setHighlight(n)};_b.AutoSuggest.prototype.setHighlight=function(n){var a=_b.DOM.gE("as_ul");if(!a)return false;if(this.iHigh>0)this.clearHighlight();this.iHigh=Number(n);a.childNodes[this.iHigh-1].className="as_highlight";this.killTimeout()};_b.AutoSuggest.prototype.clearHighlight=function(){var a=_b.DOM.gE("as_ul");if(!a)return false;if(this.iHigh>0){a.childNodes[this.iHigh-1].className="";this.iHigh=0}};_b.AutoSuggest.prototype.setHighlightedValue=function(){if(this.iHigh){this.sInp=this.fld.value=this.aSug[this.iHigh-1].value;this.fld.focus();if(this.fld.selectionStart)this.fld.setSelectionRange(this.sInp.length,this.sInp.length);this.clearSuggestions();if(typeof(this.oP.callback)=="function")this.oP.callback(this.aSug[this.iHigh-1])}};_b.AutoSuggest.prototype.killTimeout=function(){clearTimeout(this.toID)};_b.AutoSuggest.prototype.resetTimeout=function(){clearTimeout(this.toID);var a=this;this.toID=setTimeout(function(){a.clearSuggestions()},1000)};_b.AutoSuggest.prototype.clearSuggestions=function(){this.killTimeout();var a=_b.DOM.gE(this.idAs);var b=this;if(a){var c=new _b.Fader(a,1,0,250,function(){_b.DOM.remE(b.idAs)})}};if(typeof(_b.Ajax)=="undefined")_b.Ajax={};_b.Ajax=function(){this.req={};this.isIE=false};_b.Ajax.prototype.makeRequest=function(a,b,c,d){if(b!="POST")b="GET";this.onComplete=c;this.onError=d;var e=this;if(window.XMLHttpRequest){this.req=new XMLHttpRequest();this.req.onreadystatechange=function(){e.processReqChange()};this.req.open("GET",a,true);this.req.send(null)}else if(window.ActiveXObject){this.req=new ActiveXObject("Microsoft.XMLHTTP");if(this.req){this.req.onreadystatechange=function(){e.processReqChange()};this.req.open(b,a,true);this.req.send()}}};_b.Ajax.prototype.processReqChange=function(){if(this.req.readyState==4){if(this.req.status==200){this.onComplete(this.req)}else{this.onError(this.req.status)}}};if(typeof(_b.DOM)=="undefined")_b.DOM={};_b.DOM.cE=function(b,c,d,e){var f=document.createElement(b);if(!f)return 0;for(var a in c)f[a]=c[a];var t=typeof(d);if(t=="string"&&!e)f.appendChild(document.createTextNode(d));else if(t=="string"&&e)f.innerHTML=d;else if(t=="object")f.appendChild(d);return f};_b.DOM.gE=function(e){var t=typeof(e);if(t=="undefined")return 0;else if(t=="string"){var a=document.getElementById(e);if(!a)return 0;else if(typeof(a.appendChild)!="undefined")return a;else return 0}else if(typeof(e.appendChild)!="undefined")return e;else return 0};_b.DOM.remE=function(a){var e=this.gE(a);if(!e)return 0;else if(e.parentNode.removeChild(e))return true;else return 0};_b.DOM.getPos=function(e){var e=this.gE(e);var a=e;var b=0;if(a.offsetParent){while(a.offsetParent){b+=a.offsetLeft;a=a.offsetParent}}else if(a.x)b+=a.x;var a=e;var c=0;if(a.offsetParent){while(a.offsetParent){c+=a.offsetTop;a=a.offsetParent}}else if(a.y)c+=a.y;return{x:b,y:c}};if(typeof(_b.Fader)=="undefined")_b.Fader={};_b.Fader=function(a,b,c,d,e){if(!a)return 0;this.e=a;this.from=b;this.to=c;this.cb=e;this.nDur=d;this.nInt=50;this.nTime=0;var p=this;this.nID=setInterval(function(){p._fade()},this.nInt)};_b.Fader.prototype._fade=function(){this.nTime+=this.nInt;var a=Math.round(this._tween(this.nTime,this.from,this.to,this.nDur)*100);var b=a/100;if(this.e.filters){try{this.e.filters.item("DXImageTransform.Microsoft.Alpha").opacity=a}catch(e){this.e.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity='+a+')'}}else{this.e.style.opacity=b}if(this.nTime==this.nDur){clearInterval(this.nID);if(this.cb!=undefined)this.cb()}};_b.Fader.prototype._tween=function(t,b,c,d){return b+((c-b)*(t/d))};

--- a/lib/common.inc.php
+++ b/lib/common.inc.php
@@ -1,4 +1,6 @@
 <?php

+date_default_timezone_set("Australia/ACT");

+

 require_once ('jpgraph/jpgraph.php');

 require_once ('jpgraph/jpgraph_line.php');

 require_once ('jpgraph/jpgraph_log.php');

@@ -6,6 +8,9 @@
 require_once ('jpgraph/jpgraph_pie.php');

 require_once ('jpgraph/jpgraph_bar.php');

 require_once ('jpgraph/jpgraph_date.php');

+

+error_reporting(E_ALL ^ E_NOTICE);

+

 

 $link = mysql_connect('localhost', 'root', '');

 if (!$link) {

@@ -31,17 +36,19 @@
      $totale += array_sum_all($value);

   return $totale; 

  }

+// magic query modifiers

 $agency = mysql_real_escape_string(stripslashes($_REQUEST['agency']));

-if ($agency != "") $agencyQ = "agencyName = '" . $agency . "' AND";

+if ($agency != "") $agencyQ = "agencyName = '" . $agency . "' AND ";

 $supplier = mysql_real_escape_string(stripslashes($_REQUEST['supplier']));

 if ($supplier != "") {

   $supplierParts = explode("-", $supplier);

-  if ($supplierParts[0] > 0) $supplierQ = "supplierABN = '" . $supplierParts[0] . "' AND";

-  else $supplierQ = "supplierName LIKE '%" . $supplierParts[1] . "%' AND";

+  if ($supplierParts[0] > 0) $supplierQ = "supplierABN = '" . $supplierParts[0] . "' AND ";

+  else $supplierQ = "supplierName LIKE '%" . $supplierParts[1] . "%' AND ";

 }

+$startYear = 2007;

 $year = mysql_real_escape_string(stripslashes($_REQUEST['year']));

-if ($year != "") $yearQ = "agencyName = '" . $agency . "' AND";

-

+if ($year != "") $yearQ = "YEAR(publishDate) = " . $year . " AND ";

+$standardQ = "childCN = 0 AND YEAR(contractStart) >= 2007 AND YEAR(contractStart) <= 2010";

 $start =0.0;

 

 function include_header($title) {

@@ -53,9 +60,35 @@
     <head>

         <title>Contract Dashboard - <?=$title?></title>

         <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.8.0r4/build/reset-fonts-grids/reset-fonts-grids.css"> 

+

+            <script type="text/javascript" src="lib/bsn.AutoSuggest_2.1.3_comp.js" charset="utf-8"></script>

+<link rel="stylesheet" href="autosuggest_inquisitor.css" type="text/css" media="screen" charset="utf-8" />

+            <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>

+<script type="text/javascript">

+$(document).ready(function()

+{

+  //hide the all of the element with class msg_body

+  $(".msg_body").hide();

+  //toggle the componenet with class msg_body

+  $(".msg_head").click(function()

+  {

+    $(this).next(".msg_body").slideToggle(600);

+  });

+});

+</script>

+

+		<style type="text/css" title="currentStyle"> 

+			@import "media/css/demo_table.css";

+		</style> 

+		<script type="text/javascript" language="javascript" src="media/js/jquery.dataTables.js"></script> 

+		<script type="text/javascript" charset="utf-8"> 

+			$(document).ready(function() {

+				$('table').dataTable();

+			} );

+		</script> 

         <link type="text/css" rel="stylesheet" href="style.css">

         </head>

-<body><div id="doc3" class="yui-t4"/>

+<body><div id="doc3" class="yui-t4">

     <div id="hd">

         <h1> contract dashboard</h1>

         </div>

@@ -68,13 +101,28 @@
             <a href="displayProcurementMethod.php">procurement method</a>

             <a href="displayConfidentialities.php">contractual confidentiality</a>

             <a href="displayConsultancies.php">consultancies</a>

+            <a href="displayAmendments.php">amendments</a>

             <a href="displayMap.php">postcodes</a>

-            <div id="search"> search &nbsp; <form><input type="text" id="searchKeywords"/></form></div>

+            <div id="search"><form method="post" action="search.php" class="asholder">

+	<label for="searchKeyword">search</label>

+	<input type="text" id="searchKeyword" name="searchKeyword"  value="" style="width:150px" />

+        <input type="hidden" id="searchID" name="searchID" value=""/><input type="submit" value="submit" />

+</form></div>

+            <script type="text/javascript">

+	

+	var options_xml = {

+		script: function (input) { return "search_autosuggest.php?input="+input; },

+		varname:"input",

+		callback: function (obj) { document.getElementById('searchID').value = obj.id; }

+	};

+	var as_xml = new bsn.AutoSuggest('searchKeyword', options_xml);

+</script>

+

             </div>

              <div id="bd" role="main"> 

     <div id="yui-main"> 

         <div class="yui-b"><div class="yui-g">

-<?

+<?php

 $start = (float) array_sum(explode(' ',microtime())); 

 }

 

@@ -93,7 +141,9 @@
         </li>

         </ul> <br>        </div> </div>

      

-    <?

+    <?php

    echo '<div id="ft"><p>'."Processing time: ". sprintf("%.4f", ($end-$start))." seconds".'</p></div>'; 

-echo '</div> </body> </html>';

-} ?>
+   echo '</div> </body> </html>';

+} 

+?>

+

--- a/lib/fonts/AUTHORS
+++ b/lib/fonts/AUTHORS

--- a/lib/fonts/COPYING
+++ b/lib/fonts/COPYING

--- a/lib/fonts/ChangeLog
+++ b/lib/fonts/ChangeLog

 Binary files a/lib/fonts/LiberationMono-Bold.ttf and b/lib/fonts/LiberationMono-Bold.ttf differ
 Binary files a/lib/fonts/LiberationMono-BoldItalic.ttf and b/lib/fonts/LiberationMono-BoldItalic.ttf differ
 Binary files a/lib/fonts/LiberationMono-Italic.ttf and b/lib/fonts/LiberationMono-Italic.ttf differ
 Binary files a/lib/fonts/LiberationMono-Regular.ttf and b/lib/fonts/LiberationMono-Regular.ttf differ
 Binary files a/lib/fonts/LiberationSans-Bold.ttf and b/lib/fonts/LiberationSans-Bold.ttf differ
 Binary files a/lib/fonts/LiberationSans-BoldItalic.ttf and b/lib/fonts/LiberationSans-BoldItalic.ttf differ
 Binary files a/lib/fonts/LiberationSans-Italic.ttf and b/lib/fonts/LiberationSans-Italic.ttf differ
 Binary files a/lib/fonts/LiberationSans-Regular.ttf and b/lib/fonts/LiberationSans-Regular.ttf differ
 Binary files a/lib/fonts/LiberationSerif-Bold.ttf and b/lib/fonts/LiberationSerif-Bold.ttf differ
 Binary files a/lib/fonts/LiberationSerif-BoldItalic.ttf and b/lib/fonts/LiberationSerif-BoldItalic.ttf differ
 Binary files a/lib/fonts/LiberationSerif-Italic.ttf and b/lib/fonts/LiberationSerif-Italic.ttf differ
 Binary files a/lib/fonts/LiberationSerif-Regular.ttf and b/lib/fonts/LiberationSerif-Regular.ttf differ
--- a/lib/fonts/License.txt
+++ b/lib/fonts/License.txt

--- a/lib/fonts/README
+++ b/lib/fonts/README

--- a/lib/jpgraph/contour_dev/findpolygon.php
+++ b/lib/jpgraph/contour_dev/findpolygon.php

--- a/lib/jpgraph/contour_dev/tri-quad.php
+++ b/lib/jpgraph/contour_dev/tri-quad.php

--- a/lib/jpgraph/flag_mapping
+++ b/lib/jpgraph/flag_mapping

 Binary files a/lib/jpgraph/flags.dat and b/lib/jpgraph/flags.dat differ
 Binary files a/lib/jpgraph/flags_thumb100x100.dat and b/lib/jpgraph/flags_thumb100x100.dat differ
 Binary files a/lib/jpgraph/flags_thumb35x35.dat and b/lib/jpgraph/flags_thumb35x35.dat differ
 Binary files a/lib/jpgraph/flags_thumb60x60.dat and b/lib/jpgraph/flags_thumb60x60.dat differ
--- a/lib/jpgraph/gd_image.inc.php
+++ b/lib/jpgraph/gd_image.inc.php

--- a/lib/jpgraph/imgdata_balls.inc.php
+++ b/lib/jpgraph/imgdata_balls.inc.php

--- a/lib/jpgraph/imgdata_bevels.inc.php
+++ b/lib/jpgraph/imgdata_bevels.inc.php

--- a/lib/jpgraph/imgdata_diamonds.inc.php
+++ b/lib/jpgraph/imgdata_diamonds.inc.php

--- a/lib/jpgraph/imgdata_pushpins.inc.php
+++ b/lib/jpgraph/imgdata_pushpins.inc.php

--- a/lib/jpgraph/imgdata_squares.inc.php
+++ b/lib/jpgraph/imgdata_squares.inc.php

--- a/lib/jpgraph/imgdata_stars.inc.php
+++ b/lib/jpgraph/imgdata_stars.inc.php

--- a/lib/jpgraph/jpg-config.inc.php
+++ b/lib/jpgraph/jpg-config.inc.php

--- a/lib/jpgraph/jpgraph.php
+++ b/lib/jpgraph/jpgraph.php

--- a/lib/jpgraph/jpgraph_antispam-digits.php
+++ b/lib/jpgraph/jpgraph_antispam-digits.php

--- a/lib/jpgraph/jpgraph_antispam.php
+++ b/lib/jpgraph/jpgraph_antispam.php

--- a/lib/jpgraph/jpgraph_bar.php
+++ b/lib/jpgraph/jpgraph_bar.php

--- a/lib/jpgraph/jpgraph_canvas.php
+++ b/lib/jpgraph/jpgraph_canvas.php

--- a/lib/jpgraph/jpgraph_canvtools.php
+++ b/lib/jpgraph/jpgraph_canvtools.php

--- a/lib/jpgraph/jpgraph_contour.php
+++ b/lib/jpgraph/jpgraph_contour.php

--- a/lib/jpgraph/jpgraph_date.php
+++ b/lib/jpgraph/jpgraph_date.php

--- a/lib/jpgraph/jpgraph_errhandler.inc.php
+++ b/lib/jpgraph/jpgraph_errhandler.inc.php

--- a/lib/jpgraph/jpgraph_error.php
+++ b/lib/jpgraph/jpgraph_error.php

--- a/lib/jpgraph/jpgraph_flags.php
+++ b/lib/jpgraph/jpgraph_flags.php

--- a/lib/jpgraph/jpgraph_gantt.php
+++ b/lib/jpgraph/jpgraph_gantt.php

--- a/lib/jpgraph/jpgraph_gb2312.php
+++ b/lib/jpgraph/jpgraph_gb2312.php

--- a/lib/jpgraph/jpgraph_gradient.php
+++ b/lib/jpgraph/jpgraph_gradient.php

--- a/lib/jpgraph/jpgraph_iconplot.php
+++ b/lib/jpgraph/jpgraph_iconplot.php

--- a/lib/jpgraph/jpgraph_imgtrans.php
+++ b/lib/jpgraph/jpgraph_imgtrans.php

--- a/lib/jpgraph/jpgraph_led.php
+++ b/lib/jpgraph/jpgraph_led.php

--- a/lib/jpgraph/jpgraph_legend.inc.php
+++ b/lib/jpgraph/jpgraph_legend.inc.php

--- a/lib/jpgraph/jpgraph_line.php
+++ b/lib/jpgraph/jpgraph_line.php

--- a/lib/jpgraph/jpgraph_log.php
+++ b/lib/jpgraph/jpgraph_log.php

--- a/lib/jpgraph/jpgraph_meshinterpolate.inc.php
+++ b/lib/jpgraph/jpgraph_meshinterpolate.inc.php

--- a/lib/jpgraph/jpgraph_mgraph.php
+++ b/lib/jpgraph/jpgraph_mgraph.php

--- a/lib/jpgraph/jpgraph_pie.php
+++ b/lib/jpgraph/jpgraph_pie.php

--- a/lib/jpgraph/jpgraph_pie3d.php
+++ b/lib/jpgraph/jpgraph_pie3d.php

--- a/lib/jpgraph/jpgraph_plotband.php
+++ b/lib/jpgraph/jpgraph_plotband.php

--- a/lib/jpgraph/jpgraph_plotline.php
+++ b/lib/jpgraph/jpgraph_plotline.php

--- a/lib/jpgraph/jpgraph_plotmark.inc.php
+++ b/lib/jpgraph/jpgraph_plotmark.inc.php

--- a/lib/jpgraph/jpgraph_polar.php
+++ b/lib/jpgraph/jpgraph_polar.php

--- a/lib/jpgraph/jpgraph_radar.php
+++ b/lib/jpgraph/jpgraph_radar.php

--- a/lib/jpgraph/jpgraph_regstat.php
+++ b/lib/jpgraph/jpgraph_regstat.php

--- a/lib/jpgraph/jpgraph_rgb.inc.php
+++ b/lib/jpgraph/jpgraph_rgb.inc.php

--- a/lib/jpgraph/jpgraph_scatter.php
+++ b/lib/jpgraph/jpgraph_scatter.php

--- a/lib/jpgraph/jpgraph_stock.php
+++ b/lib/jpgraph/jpgraph_stock.php

--- a/lib/jpgraph/jpgraph_text.inc.php
+++ b/lib/jpgraph/jpgraph_text.inc.php

--- a/lib/jpgraph/jpgraph_ttf.inc.php
+++ b/lib/jpgraph/jpgraph_ttf.inc.php

--- a/lib/jpgraph/jpgraph_utils.inc.php
+++ b/lib/jpgraph/jpgraph_utils.inc.php

--- a/lib/jpgraph/lang/de.inc.php
+++ b/lib/jpgraph/lang/de.inc.php

--- a/lib/jpgraph/lang/en.inc.php
+++ b/lib/jpgraph/lang/en.inc.php

--- a/lib/jpgraph/lang/prod.inc.php
+++ b/lib/jpgraph/lang/prod.inc.php

file:b/lib/jquery.js (new)
--- /dev/null
+++ b/lib/jquery.js
@@ -1,1 +1,19 @@
-
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();

--- a/lib/wordcloud.php
+++ b/lib/wordcloud.php

symlink:b/liberation (new)
--- /dev/null
+++ b/liberation
@@ -1,1 +1,1 @@
-
+/usr/share/fonts/liberation/

--- /dev/null
+++ b/media/css/demo_page.css
@@ -1,1 +1,93 @@
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * General page setup
+ */
+#dt_example {
+	font: 80%/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
+	margin: 0;
+	padding: 0;
+	color: #333;
+	background-color: #fff;
+}
+
+
+#dt_example #container {
+	width: 800px;
+	margin: 30px auto;
+	padding: 0;
+}
+
+
+#dt_example #footer {
+	margin: 50px auto 0 auto;
+	padding: 0;
+}
+
+#dt_example #demo {
+	margin: 30px auto 0 auto;
+}
+
+#dt_example .demo_jui {
+	margin: 30px auto 0 auto;
+}
+
+#dt_example .big {
+	font-size: 1.3em;
+	font-weight: bold;
+	line-height: 1.6em;
+	color: #4E6CA3;
+}
+
+#dt_example .spacer {
+	height: 20px;
+	clear: both;
+}
+
+#dt_example .clear {
+	clear: both;
+}
+
+#dt_example pre {
+	padding: 15px;
+	background-color: #F5F5F5;
+	border: 1px solid #CCCCCC;
+}
+
+#dt_example h1 {
+	margin-top: 2em;
+	font-size: 1.3em;
+	font-weight: normal;
+	line-height: 1.6em;
+	color: #4E6CA3;
+	border-bottom: 1px solid #B0BED9;
+	clear: both;
+}
+
+#dt_example h2 {
+	font-size: 1.2em;
+	font-weight: normal;
+	line-height: 1.6em;
+	color: #4E6CA3;
+	clear: both;
+}
+
+#dt_example a {
+	color: #0063DC;
+	text-decoration: none;
+}
+
+#dt_example a:hover {
+	text-decoration: underline;
+}
+
+#dt_example ul {
+	color: #4E6CA3;
+}
+
+.css_right {
+	float: right;
+}
+
+.css_left {
+	float: left;
+}

--- /dev/null
+++ b/media/css/demo_table.css
@@ -1,1 +1,539 @@
-
+/*
+ *  File:         demo_table.css
+ *  CVS:          $Id$
+ *  Description:  CSS descriptions for DataTables demo pages
+ *  Author:       Allan Jardine
+ *  Created:      Tue May 12 06:47:22 BST 2009
+ *  Modified:     $Date$ by $Author$
+ *  Language:     CSS
+ *  Project:      DataTables
+ *
+ *  Copyright 2009 Allan Jardine. All Rights Reserved.
+ *
+ * ***************************************************************************
+ * DESCRIPTION
+ *
+ * The styles given here are suitable for the demos that are used with the standard DataTables
+ * distribution (see www.datatables.net). You will most likely wish to modify these styles to
+ * meet the layout requirements of your site.
+ *
+ * Common issues:
+ *   'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is
+ *     no conflict between the two pagination types. If you want to use full_numbers pagination
+ *     ensure that you either have "example_alt_pagination" as a body class name, or better yet,
+ *     modify that selector.
+ *   Note that the path used for Images is relative. All images are by default located in
+ *     ../images/ - relative to this CSS file.
+ */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables features
+ */
+
+.dataTables_wrapper {
+	position: relative;
+	min-height: 302px;
+	clear: both;
+	_height: 302px;
+	zoom: 1; /* Feeling sorry for IE */
+}
+
+.dataTables_processing {
+	position: absolute;
+	top: 50%;
+	left: 50%;
+	width: 250px;
+	height: 30px;
+	margin-left: -125px;
+	margin-top: -15px;
+	padding: 14px 0 2px 0;
+	border: 1px solid #ddd;
+	text-align: center;
+	color: #999;
+	font-size: 14px;
+	background-color: white;
+}
+
+/*.dataTables_length {*/
+/*	width: 40%;*/
+/*	float: left;*/
+/*}*/
+/**/
+/*.dataTables_filter {*/
+/*	width: 50%;*/
+/*	float: right;*/
+/*	text-align: right;*/
+/*}*/
+
+.dataTables_info {
+	width: 60%;
+	float: left;
+}
+
+.dataTables_paginate {
+	width: 44px;
+	* width: 50px;
+	float: right;
+	text-align: right;
+}
+
+/* Pagination nested */
+.paginate_disabled_previous, .paginate_enabled_previous, .paginate_disabled_next, .paginate_enabled_next {
+	height: 19px;
+	width: 19px;
+	margin-left: 3px;
+	float: left;
+}
+
+.paginate_disabled_previous {
+	background-image: url('../images/back_disabled.jpg');
+}
+
+.paginate_enabled_previous {
+	background-image: url('../images/back_enabled.jpg');
+}
+
+.paginate_disabled_next {
+	background-image: url('../images/forward_disabled.jpg');
+}
+
+.paginate_enabled_next {
+	background-image: url('../images/forward_enabled.jpg');
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables display
+ */
+table.display {
+	margin: 0 auto;
+	clear: both;
+	width: 100%;
+	
+	/* Note Firefox 3.5 and before have a bug with border-collapse
+	 * ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 ) 
+	 * border-spacing: 0; is one possible option. Conditional-css.com is
+	 * useful for this kind of thing
+	 *
+	 * Further note IE 6/7 has problems when calculating widths with border width.
+	 * It subtracts one px relative to the other browsers from the first column, and
+	 * adds one to the end...
+	 *
+	 * If you want that effect I'd suggest setting a border-top/left on th/td's and 
+	 * then filling in the gaps with other borders.
+	 */
+}
+
+table.display thead th {
+	padding: 3px 18px 3px 10px;
+	border-bottom: 1px solid black;
+	font-weight: bold;
+	cursor: pointer;
+	* cursor: hand;
+}
+
+table.display tfoot th {
+	padding: 3px 18px 3px 10px;
+	border-top: 1px solid black;
+	font-weight: bold;
+}
+
+table.display tr.heading2 td {
+	border-bottom: 1px solid #aaa;
+}
+
+table.display td {
+	padding: 3px 10px;
+}
+
+table.display td.center {
+	text-align: center;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables sorting
+ */
+
+.sorting_asc {
+	background: url('../images/sort_asc.png') no-repeat center right;
+}
+
+.sorting_desc {
+	background: url('../images/sort_desc.png') no-repeat center right;
+}
+
+.sorting {
+	background: url('../images/sort_both.png') no-repeat center right;
+}
+
+.sorting_asc_disabled {
+	background: url('../images/sort_asc_disabled.png') no-repeat center right;
+}
+
+.sorting_desc_disabled {
+	background: url('../images/sort_desc_disabled.png') no-repeat center right;
+}
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables row classes
+ */
+table.display tr.odd.gradeA {
+	background-color: #ddffdd;
+}
+
+table.display tr.even.gradeA {
+	background-color: #eeffee;
+}
+
+table.display tr.odd.gradeC {
+	background-color: #ddddff;
+}
+
+table.display tr.even.gradeC {
+	background-color: #eeeeff;
+}
+
+table.display tr.odd.gradeX {
+	background-color: #ffdddd;
+}
+
+table.display tr.even.gradeX {
+	background-color: #ffeeee;
+}
+
+table.display tr.odd.gradeU {
+	background-color: #ddd;
+}
+
+table.display tr.even.gradeU {
+	background-color: #eee;
+}
+
+
+tr.odd {
+	background-color: #E2E4FF;
+}
+
+tr.even {
+	background-color: white;
+}
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Misc
+ */
+.dataTables_scroll {
+	clear: both;
+}
+
+.dataTables_scrollBody {
+	*margin-top: -1px;
+}
+
+.top, .bottom {
+	padding: 15px;
+	background-color: #F5F5F5;
+	border: 1px solid #CCCCCC;
+}
+
+.top .dataTables_info {
+	float: none;
+}
+
+.clear {
+	clear: both;
+}
+
+.dataTables_empty {
+	text-align: center;
+}
+
+tfoot input {
+	margin: 0.5em 0;
+	width: 100%;
+	color: #444;
+}
+
+tfoot input.search_init {
+	color: #999;
+}
+
+td.group {
+	background-color: #d1cfd0;
+	border-bottom: 2px solid #A19B9E;
+	border-top: 2px solid #A19B9E;
+}
+
+td.details {
+	background-color: #d1cfd0;
+	border: 2px solid #A19B9E;
+}
+
+
+.example_alt_pagination div.dataTables_info {
+	width: 40%;
+}
+
+.paging_full_numbers {
+	width: 400px;
+	height: 22px;
+	line-height: 22px;
+}
+
+.paging_full_numbers span.paginate_button,
+ 	.paging_full_numbers span.paginate_active {
+	border: 1px solid #aaa;
+	-webkit-border-radius: 5px;
+	-moz-border-radius: 5px;
+	padding: 2px 5px;
+	margin: 0 3px;
+	cursor: pointer;
+	*cursor: hand;
+}
+
+.paging_full_numbers span.paginate_button {
+	background-color: #ddd;
+}
+
+.paging_full_numbers span.paginate_button:hover {
+	background-color: #ccc;
+}
+
+.paging_full_numbers span.paginate_active {
+	background-color: #99B3FF;
+}
+
+table.display tr.even.row_selected td {
+	background-color: #B0BED9;
+}
+
+table.display tr.odd.row_selected td {
+	background-color: #9FAFD1;
+}
+
+
+/*
+ * Sorting classes for columns
+ */
+/* For the standard odd/even */
+tr.odd td.sorting_1 {
+	background-color: #D3D6FF;
+}
+
+tr.odd td.sorting_2 {
+	background-color: #DADCFF;
+}
+
+tr.odd td.sorting_3 {
+	background-color: #E0E2FF;
+}
+
+tr.even td.sorting_1 {
+	background-color: #EAEBFF;
+}
+
+tr.even td.sorting_2 {
+	background-color: #F2F3FF;
+}
+
+tr.even td.sorting_3 {
+	background-color: #F9F9FF;
+}
+
+
+/* For the Conditional-CSS grading rows */
+/*
+ 	Colour calculations (based off the main row colours)
+  Level 1:
+		dd > c4
+		ee > d5
+	Level 2:
+	  dd > d1
+	  ee > e2
+ */
+tr.odd.gradeA td.sorting_1 {
+	background-color: #c4ffc4;
+}
+
+tr.odd.gradeA td.sorting_2 {
+	background-color: #d1ffd1;
+}
+
+tr.odd.gradeA td.sorting_3 {
+	background-color: #d1ffd1;
+}
+
+tr.even.gradeA td.sorting_1 {
+	background-color: #d5ffd5;
+}
+
+tr.even.gradeA td.sorting_2 {
+	background-color: #e2ffe2;
+}
+
+tr.even.gradeA td.sorting_3 {
+	background-color: #e2ffe2;
+}
+
+tr.odd.gradeC td.sorting_1 {
+	background-color: #c4c4ff;
+}
+
+tr.odd.gradeC td.sorting_2 {
+	background-color: #d1d1ff;
+}
+
+tr.odd.gradeC td.sorting_3 {
+	background-color: #d1d1ff;
+}
+
+tr.even.gradeC td.sorting_1 {
+	background-color: #d5d5ff;
+}
+
+tr.even.gradeC td.sorting_2 {
+	background-color: #e2e2ff;
+}
+
+tr.even.gradeC td.sorting_3 {
+	background-color: #e2e2ff;
+}
+
+tr.odd.gradeX td.sorting_1 {
+	background-color: #ffc4c4;
+}
+
+tr.odd.gradeX td.sorting_2 {
+	background-color: #ffd1d1;
+}
+
+tr.odd.gradeX td.sorting_3 {
+	background-color: #ffd1d1;
+}
+
+tr.even.gradeX td.sorting_1 {
+	background-color: #ffd5d5;
+}
+
+tr.even.gradeX td.sorting_2 {
+	background-color: #ffe2e2;
+}
+
+tr.even.gradeX td.sorting_3 {
+	background-color: #ffe2e2;
+}
+
+tr.odd.gradeU td.sorting_1 {
+	background-color: #c4c4c4;
+}
+
+tr.odd.gradeU td.sorting_2 {
+	background-color: #d1d1d1;
+}
+
+tr.odd.gradeU td.sorting_3 {
+	background-color: #d1d1d1;
+}
+
+tr.even.gradeU td.sorting_1 {
+	background-color: #d5d5d5;
+}
+
+tr.even.gradeU td.sorting_2 {
+	background-color: #e2e2e2;
+}
+
+tr.even.gradeU td.sorting_3 {
+	background-color: #e2e2e2;
+}
+
+
+/*
+ * Row highlighting example
+ */
+.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted {
+	background-color: #ECFFB3;
+}
+
+.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted {
+	background-color: #E6FF99;
+}
+
+.ex_highlight_row #example tr.even:hover {
+	background-color: #ECFFB3;
+}
+
+.ex_highlight_row #example tr.even:hover td.sorting_1 {
+	background-color: #DDFF75;
+}
+
+.ex_highlight_row #example tr.even:hover td.sorting_2 {
+	background-color: #E7FF9E;
+}
+
+.ex_highlight_row #example tr.even:hover td.sorting_3 {
+	background-color: #E2FF89;
+}
+
+.ex_highlight_row #example tr.odd:hover {
+	background-color: #E6FF99;
+}
+
+.ex_highlight_row #example tr.odd:hover td.sorting_1 {
+	background-color: #D6FF5C;
+}
+
+.ex_highlight_row #example tr.odd:hover td.sorting_2 {
+	background-color: #E0FF84;
+}
+
+.ex_highlight_row #example tr.odd:hover td.sorting_3 {
+	background-color: #DBFF70;
+}
+
+
+/*
+ * KeyTable
+ */
+table.KeyTable td {
+	border: 3px solid transparent;
+}
+
+table.KeyTable td.focus {
+	border: 3px solid #3366FF;
+}
+
+table.display tr.gradeA {
+	background-color: #eeffee;
+}
+
+table.display tr.gradeC {
+	background-color: #ddddff;
+}
+
+table.display tr.gradeX {
+	background-color: #ffdddd;
+}
+
+table.display tr.gradeU {
+	background-color: #ddd;
+}
+
+div.box {
+	height: 100px;
+	padding: 10px;
+	overflow: auto;
+	border: 1px solid #8080FF;
+	background-color: #E5E5FF;
+}
+

--- /dev/null
+++ b/media/css/demo_table_jui.css
@@ -1,1 +1,509 @@
-
+/*
+ *  File:         demo_table_jui.css
+ *  CVS:          $Id$
+ *  Description:  CSS descriptions for DataTables demo pages
+ *  Author:       Allan Jardine
+ *  Created:      Tue May 12 06:47:22 BST 2009
+ *  Modified:     $Date$ by $Author$
+ *  Language:     CSS
+ *  Project:      DataTables
+ *
+ *  Copyright 2009 Allan Jardine. All Rights Reserved.
+ *
+ * ***************************************************************************
+ * DESCRIPTION
+ *
+ * The styles given here are suitable for the demos that are used with the standard DataTables
+ * distribution (see www.datatables.net). You will most likely wish to modify these styles to
+ * meet the layout requirements of your site.
+ *
+ * Common issues:
+ *   'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is
+ *     no conflict between the two pagination types. If you want to use full_numbers pagination
+ *     ensure that you either have "example_alt_pagination" as a body class name, or better yet,
+ *     modify that selector.
+ *   Note that the path used for Images is relative. All images are by default located in
+ *     ../images/ - relative to this CSS file.
+ */
+
+
+/*
+ * jQuery UI specific styling
+ */
+
+.paging_two_button .ui-button {
+	float: left;
+	cursor: pointer;
+	* cursor: hand;
+}
+
+.paging_full_numbers .ui-button {
+	padding: 2px 6px;
+	margin: 0;
+	cursor: pointer;
+	* cursor: hand;
+}
+
+.ui-buttonset .ui-button {
+	margin-right: -0.1em !important;
+}
+
+.paging_full_numbers {
+	width: 350px !important;
+}
+
+.ui-toolbar {
+	padding: 5px;
+}
+
+.dataTables_paginate {
+	width: auto;
+}
+
+.dataTables_info {
+	padding-top: 3px;
+}
+
+table.display thead th {
+	padding: 3px 0px 3px 10px;
+	cursor: pointer;
+	* cursor: hand;
+}
+
+
+/*
+ * Sort arrow icon positioning
+ */
+table.display thead th div.DataTables_sort_wrapper {
+	position: relative;
+	padding-right: 20px;
+	padding-right: 20px;
+}
+
+table.display thead th div.DataTables_sort_wrapper span {
+	position: absolute;
+	top: 50%;
+	margin-top: -8px;
+	right: 0;
+}
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * Everything below this line is the same as demo_table.css. This file is
+ * required for 'cleanliness' of the markup
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables features
+ */
+
+.dataTables_wrapper {
+	position: relative;
+	min-height: 302px;
+	_height: 302px;
+	clear: both;
+}
+
+.dataTables_processing {
+	position: absolute;
+	top: 0px;
+	left: 50%;
+	width: 250px;
+	margin-left: -125px;
+	border: 1px solid #ddd;
+	text-align: center;
+	color: #999;
+	font-size: 11px;
+	padding: 2px 0;
+}
+
+.dataTables_length {
+	width: 40%;
+	float: left;
+}
+
+.dataTables_filter {
+	width: 50%;
+	float: right;
+	text-align: right;
+}
+
+.dataTables_info {
+	width: 50%;
+	float: left;
+}
+
+.dataTables_paginate {
+	float: right;
+	text-align: right;
+}
+
+/* Pagination nested */
+.paginate_disabled_previous, .paginate_enabled_previous, .paginate_disabled_next, .paginate_enabled_next {
+	height: 19px;
+	width: 19px;
+	margin-left: 3px;
+	float: left;
+}
+
+.paginate_disabled_previous {
+	background-image: url('../images/back_disabled.jpg');
+}
+
+.paginate_enabled_previous {
+	background-image: url('../images/back_enabled.jpg');
+}
+
+.paginate_disabled_next {
+	background-image: url('../images/forward_disabled.jpg');
+}
+
+.paginate_enabled_next {
+	background-image: url('../images/forward_enabled.jpg');
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables display
+ */
+table.display {
+	margin: 0 auto;
+	width: 100%;
+	clear: both;
+	border-collapse: collapse;
+}
+
+table.display tfoot th {
+	padding: 3px 0px 3px 10px;
+	font-weight: bold;
+	font-weight: normal;
+}
+
+table.display tr.heading2 td {
+	border-bottom: 1px solid #aaa;
+}
+
+table.display td {
+	padding: 3px 10px;
+}
+
+table.display td.center {
+	text-align: center;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables sorting
+ */
+
+.sorting_asc {
+	background: url('../images/sort_asc.jpg') no-repeat center right;
+}
+
+.sorting_desc {
+	background: url('../images/sort_desc.jpg') no-repeat center right;
+}
+
+.sorting {
+	background: url('../images/sort_both.jpg') no-repeat center right;
+}
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables row classes
+ */
+table.display tr.odd.gradeA {
+	background-color: #ddffdd;
+}
+
+table.display tr.even.gradeA {
+	background-color: #eeffee;
+}
+
+
+
+
+table.display tr.odd.gradeA {
+	background-color: #ddffdd;
+}
+
+table.display tr.even.gradeA {
+	background-color: #eeffee;
+}
+
+table.display tr.odd.gradeC {
+	background-color: #ddddff;
+}
+
+table.display tr.even.gradeC {
+	background-color: #eeeeff;
+}
+
+table.display tr.odd.gradeX {
+	background-color: #ffdddd;
+}
+
+table.display tr.even.gradeX {
+	background-color: #ffeeee;
+}
+
+table.display tr.odd.gradeU {
+	background-color: #ddd;
+}
+
+table.display tr.even.gradeU {
+	background-color: #eee;
+}
+
+
+tr.odd {
+	background-color: #E2E4FF;
+}
+
+tr.even {
+	background-color: white;
+}
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Misc
+ */
+.dataTables_scroll {
+	clear: both;
+}
+
+.top, .bottom {
+	padding: 15px;
+	background-color: #F5F5F5;
+	border: 1px solid #CCCCCC;
+}
+
+.top .dataTables_info {
+	float: none;
+}
+
+.clear {
+	clear: both;
+}
+
+.dataTables_empty {
+	text-align: center;
+}
+
+tfoot input {
+	margin: 0.5em 0;
+	width: 100%;
+	color: #444;
+}
+
+tfoot input.search_init {
+	color: #999;
+}
+
+td.group {
+	background-color: #d1cfd0;
+	border-bottom: 2px solid #A19B9E;
+	border-top: 2px solid #A19B9E;
+}
+
+td.details {
+	background-color: #d1cfd0;
+	border: 2px solid #A19B9E;
+}
+
+
+.example_alt_pagination div.dataTables_info {
+	width: 40%;
+}
+
+.paging_full_numbers span.paginate_button,
+ 	.paging_full_numbers span.paginate_active {
+	border: 1px solid #aaa;
+	-webkit-border-radius: 5px;
+	-moz-border-radius: 5px;
+	padding: 2px 5px;
+	margin: 0 3px;
+	cursor: pointer;
+	*cursor: hand;
+}
+
+.paging_full_numbers span.paginate_button {
+	background-color: #ddd;
+}
+
+.paging_full_numbers span.paginate_button:hover {
+	background-color: #ccc;
+}
+
+.paging_full_numbers span.paginate_active {
+	background-color: #99B3FF;
+}
+
+table.display tr.even.row_selected td {
+	background-color: #B0BED9;
+}
+
+table.display tr.odd.row_selected td {
+	background-color: #9FAFD1;
+}
+
+
+/*
+ * Sorting classes for columns
+ */
+/* For the standard odd/even */
+tr.odd td.sorting_1 {
+	background-color: #D3D6FF;
+}
+
+tr.odd td.sorting_2 {
+	background-color: #DADCFF;
+}
+
+tr.odd td.sorting_3 {
+	background-color: #E0E2FF;
+}
+
+tr.even td.sorting_1 {
+	background-color: #EAEBFF;
+}
+
+tr.even td.sorting_2 {
+	background-color: #F2F3FF;
+}
+
+tr.even td.sorting_3 {
+	background-color: #F9F9FF;
+}
+
+
+/* For the Conditional-CSS grading rows */
+/*
+ 	Colour calculations (based off the main row colours)
+  Level 1:
+		dd > c4
+		ee > d5
+	Level 2:
+	  dd > d1
+	  ee > e2
+ */
+tr.odd.gradeA td.sorting_1 {
+	background-color: #c4ffc4;
+}
+
+tr.odd.gradeA td.sorting_2 {
+	background-color: #d1ffd1;
+}
+
+tr.odd.gradeA td.sorting_3 {
+	background-color: #d1ffd1;
+}
+
+tr.even.gradeA td.sorting_1 {
+	background-color: #d5ffd5;
+}
+
+tr.even.gradeA td.sorting_2 {
+	background-color: #e2ffe2;
+}
+
+tr.even.gradeA td.sorting_3 {
+	background-color: #e2ffe2;
+}
+
+tr.odd.gradeC td.sorting_1 {
+	background-color: #c4c4ff;
+}
+
+tr.odd.gradeC td.sorting_2 {
+	background-color: #d1d1ff;
+}
+
+tr.odd.gradeC td.sorting_3 {
+	background-color: #d1d1ff;
+}
+
+tr.even.gradeC td.sorting_1 {
+	background-color: #d5d5ff;
+}
+
+tr.even.gradeC td.sorting_2 {
+	background-color: #e2e2ff;
+}
+
+tr.even.gradeC td.sorting_3 {
+	background-color: #e2e2ff;
+}
+
+tr.odd.gradeX td.sorting_1 {
+	background-color: #ffc4c4;
+}
+
+tr.odd.gradeX td.sorting_2 {
+	background-color: #ffd1d1;
+}
+
+tr.odd.gradeX td.sorting_3 {
+	background-color: #ffd1d1;
+}
+
+tr.even.gradeX td.sorting_1 {
+	background-color: #ffd5d5;
+}
+
+tr.even.gradeX td.sorting_2 {
+	background-color: #ffe2e2;
+}
+
+tr.even.gradeX td.sorting_3 {
+	background-color: #ffe2e2;
+}
+
+tr.odd.gradeU td.sorting_1 {
+	background-color: #c4c4c4;
+}
+
+tr.odd.gradeU td.sorting_2 {
+	background-color: #d1d1d1;
+}
+
+tr.odd.gradeU td.sorting_3 {
+	background-color: #d1d1d1;
+}
+
+tr.even.gradeU td.sorting_1 {
+	background-color: #d5d5d5;
+}
+
+tr.even.gradeU td.sorting_2 {
+	background-color: #e2e2e2;
+}
+
+tr.even.gradeU td.sorting_3 {
+	background-color: #e2e2e2;
+}
+
+
+/*
+ * Row highlighting example
+ */
+.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted {
+	background-color: #ECFFB3;
+}
+
+.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted {
+	background-color: #E6FF99;
+}

 Binary files /dev/null and b/media/images/Sorting icons.psd differ
 Binary files /dev/null and b/media/images/back_disabled.jpg differ
 Binary files /dev/null and b/media/images/back_enabled.jpg differ
 Binary files /dev/null and b/media/images/favicon.ico differ
 Binary files /dev/null and b/media/images/forward_disabled.jpg differ
 Binary files /dev/null and b/media/images/forward_enabled.jpg differ
 Binary files /dev/null and b/media/images/sort_asc.png differ
 Binary files /dev/null and b/media/images/sort_asc_disabled.png differ
 Binary files /dev/null and b/media/images/sort_both.png differ
 Binary files /dev/null and b/media/images/sort_desc.png differ
 Binary files /dev/null and b/media/images/sort_desc_disabled.png differ
--- /dev/null
+++ b/media/js/jquery.dataTables.js
@@ -1,1 +1,6816 @@
+/*
+ * File:        jquery.dataTables.js
+ * Version:     1.7.4
+ * Description: Paginate, search and sort HTML tables
+ * Author:      Allan Jardine (www.sprymedia.co.uk)
+ * Created:     28/3/2008
+ * Language:    Javascript
+ * License:     GPL v2 or BSD 3 point style
+ * Project:     Mtaala
+ * Contact:     allan.jardine@sprymedia.co.uk
+ * 
+ * Copyright 2008-2010 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, as supplied with this software.
+ * 
+ * This source file is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ * 
+ * For details please refer to: http://www.datatables.net
+ */
 
+/*
+ * When considering jsLint, we need to allow eval() as it it is used for reading cookies and 
+ * building the dynamic multi-column sort functions.
+ */
+/*jslint evil: true, undef: true, browser: true */
+/*globals $, jQuery,_fnExternApiFunc,_fnInitalise,_fnLanguageProcess,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnGatherData,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxUpdateDraw,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnArrayCmp,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap*/
+
+(function($, window, document) {
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Section - DataTables variables
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	
+	/*
+	 * Variable: dataTableSettings
+	 * Purpose:  Store the settings for each dataTables instance
+	 * Scope:    jQuery.fn
+	 */
+	$.fn.dataTableSettings = [];
+	var _aoSettings = $.fn.dataTableSettings; /* Short reference for fast internal lookup */
+	
+	/*
+	 * Variable: dataTableExt
+	 * Purpose:  Container for customisable parts of DataTables
+	 * Scope:    jQuery.fn
+	 */
+	$.fn.dataTableExt = {};
+	var _oExt = $.fn.dataTableExt;
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Section - DataTables extensible objects
+	 * 
+	 * The _oExt object is used to provide an area where user dfined plugins can be 
+	 * added to DataTables. The following properties of the object are used:
+	 *   oApi - Plug-in API functions
+	 *   aTypes - Auto-detection of types
+	 *   oSort - Sorting functions used by DataTables (based on the type)
+	 *   oPagination - Pagination functions for different input styles
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	
+	/*
+	 * Variable: sVersion
+	 * Purpose:  Version string for plug-ins to check compatibility
+	 * Scope:    jQuery.fn.dataTableExt
+	 * Notes:    Allowed format is a.b.c.d.e where:
+	 *   a:int, b:int, c:int, d:string(dev|beta), e:int. d and e are optional
+	 */
+	_oExt.sVersion = "1.7.4";
+	
+	/*
+	 * Variable: sErrMode
+	 * Purpose:  How should DataTables report an error. Can take the value 'alert' or 'throw'
+	 * Scope:    jQuery.fn.dataTableExt
+	 */
+	_oExt.sErrMode = "alert";
+	
+	/*
+	 * Variable: iApiIndex
+	 * Purpose:  Index for what 'this' index API functions should use
+	 * Scope:    jQuery.fn.dataTableExt
+	 */
+	_oExt.iApiIndex = 0;
+	
+	/*
+	 * Variable: oApi
+	 * Purpose:  Container for plugin API functions
+	 * Scope:    jQuery.fn.dataTableExt
+	 */
+	_oExt.oApi = { };
+	
+	/*
+	 * Variable: aFiltering
+	 * Purpose:  Container for plugin filtering functions
+	 * Scope:    jQuery.fn.dataTableExt
+	 */
+	_oExt.afnFiltering = [ ];
+	
+	/*
+	 * Variable: aoFeatures
+	 * Purpose:  Container for plugin function functions
+	 * Scope:    jQuery.fn.dataTableExt
+	 * Notes:    Array of objects with the following parameters:
+	 *   fnInit: Function for initialisation of Feature. Takes oSettings and returns node
+	 *   cFeature: Character that will be matched in sDom - case sensitive
+	 *   sFeature: Feature name - just for completeness :-)
+	 */
+	_oExt.aoFeatures = [ ];
+	
+	/*
+	 * Variable: ofnSearch
+	 * Purpose:  Container for custom filtering functions
+	 * Scope:    jQuery.fn.dataTableExt
+	 * Notes:    This is an object (the name should match the type) for custom filtering function,
+	 *   which can be used for live DOM checking or formatted text filtering
+	 */
+	_oExt.ofnSearch = { };
+	
+	/*
+	 * Variable: afnSortData
+	 * Purpose:  Container for custom sorting data source functions
+	 * Scope:    jQuery.fn.dataTableExt
+	 * Notes:    Array (associative) of functions which is run prior to a column of this 
+	 *   'SortDataType' being sorted upon.
+	 *   Function input parameters:
+	 *     object:oSettings-  DataTables settings object
+	 *     int:iColumn - Target column number
+	 *   Return value: Array of data which exactly matched the full data set size for the column to
+	 *     be sorted upon
+	 */
+	_oExt.afnSortData = [ ];
+	
+	/*
+	 * Variable: oStdClasses
+	 * Purpose:  Storage for the various classes that DataTables uses
+	 * Scope:    jQuery.fn.dataTableExt
+	 */
+	_oExt.oStdClasses = {
+		/* Two buttons buttons */
+		"sPagePrevEnabled": "paginate_enabled_previous",
+		"sPagePrevDisabled": "paginate_disabled_previous",
+		"sPageNextEnabled": "paginate_enabled_next",
+		"sPageNextDisabled": "paginate_disabled_next",
+		"sPageJUINext": "",
+		"sPageJUIPrev": "",
+		
+		/* Full numbers paging buttons */
+		"sPageButton": "paginate_button",
+		"sPageButtonActive": "paginate_active",
+		"sPageButtonStaticDisabled": "paginate_button",
+		"sPageFirst": "first",
+		"sPagePrevious": "previous",
+		"sPageNext": "next",
+		"sPageLast": "last",
+		
+		/* Stripping classes */
+		"sStripOdd": "odd",
+		"sStripEven": "even",
+		
+		/* Empty row */
+		"sRowEmpty": "dataTables_empty",
+		
+		/* Features */
+		"sWrapper": "dataTables_wrapper",
+		"sFilter": "dataTables_filter",
+		"sInfo": "dataTables_info",
+		"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
+		"sLength": "dataTables_length",
+		"sProcessing": "dataTables_processing",
+		
+		/* Sorting */
+		"sSortAsc": "sorting_asc",
+		"sSortDesc": "sorting_desc",
+		"sSortable": "sorting", /* Sortable in both directions */
+		"sSortableAsc": "sorting_asc_disabled",
+		"sSortableDesc": "sorting_desc_disabled",
+		"sSortableNone": "sorting_disabled",
+		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+		"sSortJUIAsc": "",
+		"sSortJUIDesc": "",
+		"sSortJUI": "",
+		"sSortJUIAscAllowed": "",
+		"sSortJUIDescAllowed": "",
+		"sSortJUIWrapper": "",
+		
+		/* Scrolling */
+		"sScrollWrapper": "dataTables_scroll",
+		"sScrollHead": "dataTables_scrollHead",
+		"sScrollHeadInner": "dataTables_scrollHeadInner",
+		"sScrollBody": "dataTables_scrollBody",
+		"sScrollFoot": "dataTables_scrollFoot",
+		"sScrollFootInner": "dataTables_scrollFootInner",
+		
+		/* Misc */
+		"sFooterTH": ""
+	};
+	
+	/*
+	 * Variable: oJUIClasses
+	 * Purpose:  Storage for the various classes that DataTables uses - jQuery UI suitable
+	 * Scope:    jQuery.fn.dataTableExt
+	 */
+	_oExt.oJUIClasses = {
+		/* Two buttons buttons */
+		"sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
+		"sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
+		"sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
+		"sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
+		"sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
+		"sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
+		
+		/* Full numbers paging buttons */
+		"sPageButton": "fg-button ui-button ui-state-default",
+		"sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
+		"sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
+		"sPageFirst": "first ui-corner-tl ui-corner-bl",
+		"sPagePrevious": "previous",
+		"sPageNext": "next",
+		"sPageLast": "last ui-corner-tr ui-corner-br",
+		
+		/* Stripping classes */
+		"sStripOdd": "odd",
+		"sStripEven": "even",
+		
+		/* Empty row */
+		"sRowEmpty": "dataTables_empty",
+		
+		/* Features */
+		"sWrapper": "dataTables_wrapper",
+		"sFilter": "dataTables_filter",
+		"sInfo": "dataTables_info",
+		"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
+			"ui-buttonset-multi paging_", /* Note that the type is postfixed */
+		"sLength": "dataTables_length",
+		"sProcessing": "dataTables_processing",
+		
+		/* Sorting */
+		"sSortAsc": "ui-state-default",
+		"sSortDesc": "ui-state-default",
+		"sSortable": "ui-state-default",
+		"sSortableAsc": "ui-state-default",
+		"sSortableDesc": "ui-state-default",
+		"sSortableNone": "ui-state-default",
+		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+		"sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
+		"sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
+		"sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
+		"sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
+		"sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
+		"sSortJUIWrapper": "DataTables_sort_wrapper",
+		
+		/* Scrolling */
+		"sScrollWrapper": "dataTables_scroll",
+		"sScrollHead": "dataTables_scrollHead ui-state-default",
+		"sScrollHeadInner": "dataTables_scrollHeadInner",
+		"sScrollBody": "dataTables_scrollBody",
+		"sScrollFoot": "dataTables_scrollFoot ui-state-default",
+		"sScrollFootInner": "dataTables_scrollFootInner",
+		
+		/* Misc */
+		"sFooterTH": "ui-state-default"
+	};
+	
+	/*
+	 * Variable: oPagination
+	 * Purpose:  Container for the various type of pagination that dataTables supports
+	 * Scope:    jQuery.fn.dataTableExt
+	 */
+	_oExt.oPagination = {
+		/*
+		 * Variable: two_button
+		 * Purpose:  Standard two button (forward/back) pagination
+	 	 * Scope:    jQuery.fn.dataTableExt.oPagination
+		 */
+		"two_button": {
+			/*
+			 * Function: oPagination.two_button.fnInit
+			 * Purpose:  Initalise dom elements required for pagination with forward/back buttons only
+			 * Returns:  -
+	 		 * Inputs:   object:oSettings - dataTables settings object
+	     *           node:nPaging - the DIV which contains this pagination control
+			 *           function:fnCallbackDraw - draw function which must be called on update
+			 */
+			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+			{
+				var nPrevious, nNext, nPreviousInner, nNextInner;
+				
+				/* Store the next and previous elements in the oSettings object as they can be very
+				 * usful for automation - particularly testing
+				 */
+				if ( !oSettings.bJUI )
+				{
+					nPrevious = document.createElement( 'div' );
+					nNext = document.createElement( 'div' );
+				}
+				else
+				{
+					nPrevious = document.createElement( 'a' );
+					nNext = document.createElement( 'a' );
+					
+					nNextInner = document.createElement('span');
+					nNextInner.className = oSettings.oClasses.sPageJUINext;
+					nNext.appendChild( nNextInner );
+					
+					nPreviousInner = document.createElement('span');
+					nPreviousInner.className = oSettings.oClasses.sPageJUIPrev;
+					nPrevious.appendChild( nPreviousInner );
+				}
+				
+				nPrevious.className = oSettings.oClasses.sPagePrevDisabled;
+				nNext.className = oSettings.oClasses.sPageNextDisabled;
+				
+				nPrevious.title = oSettings.oLanguage.oPaginate.sPrevious;
+				nNext.title = oSettings.oLanguage.oPaginate.sNext;
+				
+				nPaging.appendChild( nPrevious );
+				nPaging.appendChild( nNext );
+				
+				$(nPrevious).click( function() {
+					if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
+					{
+						/* Only draw when the page has actually changed */
+						fnCallbackDraw( oSettings );
+					}
+				} );
+				
+				$(nNext).click( function() {
+					if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
+					{
+						fnCallbackDraw( oSettings );
+					}
+				} );
+				
+				/* Take the brutal approach to cancelling text selection */
+				$(nPrevious).bind( 'selectstart', function () { return false; } );
+				$(nNext).bind( 'selectstart', function () { return false; } );
+				
+				/* ID the first elements only */
+				if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
+				{
+					nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
+					nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
+					nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
+				}
+			},
+			
+			/*
+			 * Function: oPagination.two_button.fnUpdate
+			 * Purpose:  Update the two button pagination at the end of the draw
+			 * Returns:  -
+	 		 * Inputs:   object:oSettings - dataTables settings object
+			 *           function:fnCallbackDraw - draw function to call on page change
+			 */
+			"fnUpdate": function ( oSettings, fnCallbackDraw )
+			{
+				if ( !oSettings.aanFeatures.p )
+				{
+					return;
+				}
+				
+				/* Loop over each instance of the pager */
+				var an = oSettings.aanFeatures.p;
+				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
+				{
+					if ( an[i].childNodes.length !== 0 )
+					{
+						an[i].childNodes[0].className = 
+							( oSettings._iDisplayStart === 0 ) ? 
+							oSettings.oClasses.sPagePrevDisabled : oSettings.oClasses.sPagePrevEnabled;
+						
+						an[i].childNodes[1].className = 
+							( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ? 
+							oSettings.oClasses.sPageNextDisabled : oSettings.oClasses.sPageNextEnabled;
+					}
+				}
+			}
+		},
+		
+		
+		/*
+		 * Variable: iFullNumbersShowPages
+		 * Purpose:  Change the number of pages which can be seen
+	 	 * Scope:    jQuery.fn.dataTableExt.oPagination
+		 */
+		"iFullNumbersShowPages": 5,
+		
+		/*
+		 * Variable: full_numbers
+		 * Purpose:  Full numbers pagination
+	 	 * Scope:    jQuery.fn.dataTableExt.oPagination
+		 */
+		"full_numbers": {
+			/*
+			 * Function: oPagination.full_numbers.fnInit
+			 * Purpose:  Initalise dom elements required for pagination with a list of the pages
+			 * Returns:  -
+	 		 * Inputs:   object:oSettings - dataTables settings object
+	     *           node:nPaging - the DIV which contains this pagination control
+			 *           function:fnCallbackDraw - draw function which must be called on update
+			 */
+			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+			{
+				var nFirst = document.createElement( 'span' );
+				var nPrevious = document.createElement( 'span' );
+				var nList = document.createElement( 'span' );
+				var nNext = document.createElement( 'span' );
+				var nLast = document.createElement( 'span' );
+				
+				nFirst.innerHTML = oSettings.oLanguage.oPaginate.sFirst;
+				nPrevious.innerHTML = oSettings.oLanguage.oPaginate.sPrevious;
+				nNext.innerHTML = oSettings.oLanguage.oPaginate.sNext;
+				nLast.innerHTML = oSettings.oLanguage.oPaginate.sLast;
+				
+				var oClasses = oSettings.oClasses;
+				nFirst.className = oClasses.sPageButton+" "+oClasses.sPageFirst;
+				nPrevious.className = oClasses.sPageButton+" "+oClasses.sPagePrevious;
+				nNext.className= oClasses.sPageButton+" "+oClasses.sPageNext;
+				nLast.className = oClasses.sPageButton+" "+oClasses.sPageLast;
+				
+				nPaging.appendChild( nFirst );
+				nPaging.appendChild( nPrevious );
+				nPaging.appendChild( nList );
+				nPaging.appendChild( nNext );
+				nPaging.appendChild( nLast );
+				
+				$(nFirst).click( function () {
+					if ( oSettings.oApi._fnPageChange( oSettings, "first" ) )
+					{
+						fnCallbackDraw( oSettings );
+					}
+				} );
+				
+				$(nPrevious).click( function() {
+					if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
+					{
+						fnCallbackDraw( oSettings );
+					}
+				} );
+				
+				$(nNext).click( function() {
+					if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
+					{
+						fnCallbackDraw( oSettings );
+					}
+				} );
+				
+				$(nLast).click( function() {
+					if ( oSettings.oApi._fnPageChange( oSettings, "last" ) )
+					{
+						fnCallbackDraw( oSettings );
+					}
+				} );
+				
+				/* Take the brutal approach to cancelling text selection */
+				$('span', nPaging)
+					.bind( 'mousedown', function () { return false; } )
+					.bind( 'selectstart', function () { return false; } );
+				
+				/* ID the first elements only */
+				if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
+				{
+					nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
+					nFirst.setAttribute( 'id', oSettings.sTableId+'_first' );
+					nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
+					nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
+					nLast.setAttribute( 'id', oSettings.sTableId+'_last' );
+				}
+			},
+			
+			/*
+			 * Function: oPagination.full_numbers.fnUpdate
+			 * Purpose:  Update the list of page buttons shows
+			 * Returns:  -
+	 		 * Inputs:   object:oSettings - dataTables settings object
+			 *           function:fnCallbackDraw - draw function to call on page change
+			 */
+			"fnUpdate": function ( oSettings, fnCallbackDraw )
+			{
+				if ( !oSettings.aanFeatures.p )
+				{
+					return;
+				}
+				
+				var iPageCount = _oExt.oPagination.iFullNumbersShowPages;
+				var iPageCountHalf = Math.floor(iPageCount / 2);
+				var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
+				var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
+				var sList = "";
+				var iStartButton, iEndButton, i, iLen;
+				var oClasses = oSettings.oClasses;
+				
+				/* Pages calculation */
+				if (iPages < iPageCount)
+				{
+					iStartButton = 1;
+					iEndButton = iPages;
+				}
+				else
+				{
+					if (iCurrentPage <= iPageCountHalf)
+					{
+						iStartButton = 1;
+						iEndButton = iPageCount;
+					}
+					else
+					{
+						if (iCurrentPage >= (iPages - iPageCountHalf))
+						{
+							iStartButton = iPages - iPageCount + 1;
+							iEndButton = iPages;
+						}
+						else
+						{
+							iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
+							iEndButton = iStartButton + iPageCount - 1;
+						}
+					}
+				}
+				
+				/* Build the dynamic list */
+				for ( i=iStartButton ; i<=iEndButton ; i++ )
+				{
+					if ( iCurrentPage != i )
+					{
+						sList += '<span class="'+oClasses.sPageButton+'">'+i+'</span>';
+					}
+					else
+					{
+						sList += '<span class="'+oClasses.sPageButtonActive+'">'+i+'</span>';
+					}
+				}
+				
+				/* Loop over each instance of the pager */
+				var an = oSettings.aanFeatures.p;
+				var anButtons, anStatic, nPaginateList;
+				var fnClick = function() {
+					/* Use the information in the element to jump to the required page */
+					var iTarget = (this.innerHTML * 1) - 1;
+					oSettings._iDisplayStart = iTarget * oSettings._iDisplayLength;
+					fnCallbackDraw( oSettings );
+					return false;
+				};
+				var fnFalse = function () { return false; };
+				
+				for ( i=0, iLen=an.length ; i<iLen ; i++ )
+				{
+					if ( an[i].childNodes.length === 0 )
+					{
+						continue;
+					}
+					
+					/* Build up the dynamic list forst - html and listeners */
+					var qjPaginateList = $('span:eq(2)', an[i]);
+					qjPaginateList.html( sList );
+					$('span', qjPaginateList).click( fnClick ).bind( 'mousedown', fnFalse )
+						.bind( 'selectstart', fnFalse );
+					
+					/* Update the 'premanent botton's classes */
+					anButtons = an[i].getElementsByTagName('span');
+					anStatic = [
+						anButtons[0], anButtons[1], 
+						anButtons[anButtons.length-2], anButtons[anButtons.length-1]
+					];
+					$(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
+					if ( iCurrentPage == 1 )
+					{
+						anStatic[0].className += " "+oClasses.sPageButtonStaticDisabled;
+						anStatic[1].className += " "+oClasses.sPageButtonStaticDisabled;
+					}
+					else
+					{
+						anStatic[0].className += " "+oClasses.sPageButton;
+						anStatic[1].className += " "+oClasses.sPageButton;
+					}
+					
+					if ( iPages === 0 || iCurrentPage == iPages || oSettings._iDisplayLength == -1 )
+					{
+						anStatic[2].className += " "+oClasses.sPageButtonStaticDisabled;
+						anStatic[3].className += " "+oClasses.sPageButtonStaticDisabled;
+					}
+					else
+					{
+						anStatic[2].className += " "+oClasses.sPageButton;
+						anStatic[3].className += " "+oClasses.sPageButton;
+					}
+				}
+			}
+		}
+	};
+	
+	/*
+	 * Variable: oSort
+	 * Purpose:  Wrapper for the sorting functions that can be used in DataTables
+	 * Scope:    jQuery.fn.dataTableExt
+	 * Notes:    The functions provided in this object are basically standard javascript sort
+	 *   functions - they expect two inputs which they then compare and then return a priority
+	 *   result. For each sort method added, two functions need to be defined, an ascending sort and
+	 *   a descending sort.
+	 */
+	_oExt.oSort = {
+		/*
+		 * text sorting
+		 */
+		"string-asc": function ( a, b )
+		{
+			var x = a.toLowerCase();
+			var y = b.toLowerCase();
+			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+		},
+		
+		"string-desc": function ( a, b )
+		{
+			var x = a.toLowerCase();
+			var y = b.toLowerCase();
+			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+		},
+		
+		
+		/*
+		 * html sorting (ignore html tags)
+		 */
+		"html-asc": function ( a, b )
+		{
+			var x = a.replace( /<.*?>/g, "" ).toLowerCase();
+			var y = b.replace( /<.*?>/g, "" ).toLowerCase();
+			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+		},
+		
+		"html-desc": function ( a, b )
+		{
+			var x = a.replace( /<.*?>/g, "" ).toLowerCase();
+			var y = b.replace( /<.*?>/g, "" ).toLowerCase();
+			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+		},
+		
+		
+		/*
+		 * date sorting
+		 */
+		"date-asc": function ( a, b )
+		{
+			var x = Date.parse( a );
+			var y = Date.parse( b );
+			
+			if ( isNaN(x) || x==="" )
+			{
+    		x = Date.parse( "01/01/1970 00:00:00" );
+			}
+			if ( isNaN(y) || y==="" )
+			{
+				y =	Date.parse( "01/01/1970 00:00:00" );
+			}
+			
+			return x - y;
+		},
+		
+		"date-desc": function ( a, b )
+		{
+			var x = Date.parse( a );
+			var y = Date.parse( b );
+			
+			if ( isNaN(x) || x==="" )
+			{
+    		x = Date.parse( "01/01/1970 00:00:00" );
+			}
+			if ( isNaN(y) || y==="" )
+			{
+				y =	Date.parse( "01/01/1970 00:00:00" );
+			}
+			
+			return y - x;
+		},
+		
+		
+		/*
+		 * numerical sorting
+		 */
+		"numeric-asc": function ( a, b )
+		{
+			var x = (a=="-" || a==="") ? 0 : a*1;
+			var y = (b=="-" || b==="") ? 0 : b*1;
+			return x - y;
+		},
+		
+		"numeric-desc": function ( a, b )
+		{
+			var x = (a=="-" || a==="") ? 0 : a*1;
+			var y = (b=="-" || b==="") ? 0 : b*1;
+			return y - x;
+		}
+	};
+	
+	
+	/*
+	 * Variable: aTypes
+	 * Purpose:  Container for the various type of type detection that dataTables supports
+	 * Scope:    jQuery.fn.dataTableExt
+	 * Notes:    The functions in this array are expected to parse a string to see if it is a data
+	 *   type that it recognises. If so then the function should return the name of the type (a
+	 *   corresponding sort function should be defined!), if the type is not recognised then the
+	 *   function should return null such that the parser and move on to check the next type.
+	 *   Note that ordering is important in this array - the functions are processed linearly,
+	 *   starting at index 0.
+	 *   Note that the input for these functions is always a string! It cannot be any other data
+	 *   type
+	 */
+	_oExt.aTypes = [
+		/*
+		 * Function: -
+		 * Purpose:  Check to see if a string is numeric
+		 * Returns:  string:'numeric' or null
+		 * Inputs:   string:sText - string to check
+		 */
+		function ( sData )
+		{
+			/* Allow zero length strings as a number */
+			if ( sData.length === 0 )
+			{
+				return 'numeric';
+			}
+			
+			var sValidFirstChars = "0123456789-";
+			var sValidChars = "0123456789.";
+			var Char;
+			var bDecimal = false;
+			
+			/* Check for a valid first char (no period and allow negatives) */
+			Char = sData.charAt(0); 
+			if (sValidFirstChars.indexOf(Char) == -1) 
+			{
+				return null;
+			}
+			
+			/* Check all the other characters are valid */
+			for ( var i=1 ; i<sData.length ; i++ ) 
+			{
+				Char = sData.charAt(i); 
+				if (sValidChars.indexOf(Char) == -1) 
+				{
+					return null;
+				}
+				
+				/* Only allowed one decimal place... */
+				if ( Char == "." )
+				{
+					if ( bDecimal )
+					{
+						return null;
+					}
+					bDecimal = true;
+				}
+			}
+			
+			return 'numeric';
+		},
+		
+		/*
+		 * Function: -
+		 * Purpose:  Check to see if a string is actually a formatted date
+		 * Returns:  string:'date' or null
+		 * Inputs:   string:sText - string to check
+		 */
+		function ( sData )
+		{
+			var iParse = Date.parse(sData);
+			if ( (iParse !== null && !isNaN(iParse)) || sData.length === 0 )
+			{
+				return 'date';
+			}
+			return null;
+		},
+		
+		/*
+		 * Function: -
+		 * Purpose:  Check to see if a string should be treated as an HTML string
+		 * Returns:  string:'html' or null
+		 * Inputs:   string:sText - string to check
+		 */
+		function ( sData )
+		{
+			if ( sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
+			{
+				return 'html';
+			}
+			return null;
+		}
+	];
+	
+	/*
+	 * Function: fnVersionCheck
+	 * Purpose:  Check a version string against this version of DataTables. Useful for plug-ins
+	 * Returns:  bool:true -this version of DataTables is greater or equal to the required version
+	 *                false -this version of DataTales is not suitable
+	 * Inputs:   string:sVersion - the version to check against. May be in the following formats:
+	 *             "a", "a.b" or "a.b.c"
+	 * Notes:    This function will only check the first three parts of a version string. It is
+	 *   assumed that beta and dev versions will meet the requirements. This might change in future
+	 */
+	_oExt.fnVersionCheck = function( sVersion )
+	{
+		/* This is cheap, but very effective */
+		var fnZPad = function (Zpad, count)
+		{
+			while(Zpad.length < count) {
+				Zpad += '0';
+			}
+			return Zpad;
+		};
+		var aThis = _oExt.sVersion.split('.');
+		var aThat = sVersion.split('.');
+		var sThis = '', sThat = '';
+		
+		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
+		{
+			sThis += fnZPad( aThis[i], 3 );
+			sThat += fnZPad( aThat[i], 3 );
+		}
+		
+		return parseInt(sThis, 10) >= parseInt(sThat, 10);
+	};
+	
+	/*
+	 * Variable: _oExternConfig
+	 * Purpose:  Store information for DataTables to access globally about other instances
+	 * Scope:    jQuery.fn.dataTableExt
+	 */
+	_oExt._oExternConfig = {
+		/* int:iNextUnique - next unique number for an instance */
+		"iNextUnique": 0
+	};
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Section - DataTables prototype
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	
+	/*
+	 * Function: dataTable
+	 * Purpose:  DataTables information
+	 * Returns:  -
+	 * Inputs:   object:oInit - initalisation options for the table
+	 */
+	$.fn.dataTable = function( oInit )
+	{
+		/*
+		 * Function: classSettings
+		 * Purpose:  Settings container function for all 'class' properties which are required
+		 *   by dataTables
+		 * Returns:  -
+		 * Inputs:   -
+		 */
+		function classSettings ()
+		{
+			this.fnRecordsTotal = function ()
+			{
+				if ( this.oFeatures.bServerSide ) {
+					return parseInt(this._iRecordsTotal, 10);
+				} else {
+					return this.aiDisplayMaster.length;
+				}
+			};
+			
+			this.fnRecordsDisplay = function ()
+			{
+				if ( this.oFeatures.bServerSide ) {
+					return parseInt(this._iRecordsDisplay, 10);
+				} else {
+					return this.aiDisplay.length;
+				}
+			};
+			
+			this.fnDisplayEnd = function ()
+			{
+				if ( this.oFeatures.bServerSide ) {
+					if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
+						return this._iDisplayStart+this.aiDisplay.length;
+					} else {
+						return Math.min( this._iDisplayStart+this._iDisplayLength, 
+							this._iRecordsDisplay );
+					}
+				} else {
+					return this._iDisplayEnd;
+				}
+			};
+			
+			/*
+			 * Variable: oInstance
+			 * Purpose:  The DataTables object for this table
+			 * Scope:    jQuery.dataTable.classSettings 
+			 */
+			this.oInstance = null;
+			
+			/*
+			 * Variable: sInstance
+			 * Purpose:  Unique idendifier for each instance of the DataTables object
+			 * Scope:    jQuery.dataTable.classSettings 
+			 */
+			this.sInstance = null;
+			
+			/*
+			 * Variable: oFeatures
+			 * Purpose:  Indicate the enablement of key dataTable features
+			 * Scope:    jQuery.dataTable.classSettings 
+			 */
+			this.oFeatures = {
+				"bPaginate": true,
+				"bLengthChange": true,
+				"bFilter": true,
+				"bSort": true,
+				"bInfo": true,
+				"bAutoWidth": true,
+				"bProcessing": false,
+				"bSortClasses": true,
+				"bStateSave": false,
+				"bServerSide": false
+			};
+			
+			/*
+			 * Variable: oScroll
+			 * Purpose:  Container for scrolling options
+			 * Scope:    jQuery.dataTable.classSettings 
+			 */
+			this.oScroll = {
+				"sX": "",
+				"sXInner": "",
+				"sY": "",
+				"bCollapse": false,
+				"bInfinite": false,
+				"iLoadGap": 100,
+				"iBarWidth": 0
+			};
+			
+			/*
+			 * Variable: aanFeatures
+			 * Purpose:  Array referencing the nodes which are used for the features
+			 * Scope:    jQuery.dataTable.classSettings 
+			 * Notes:    The parameters of this object match what is allowed by sDom - i.e.
+			 *   'l' - Length changing
+			 *   'f' - Filtering input
+			 *   't' - The table!
+			 *   'i' - Information
+			 *   'p' - Pagination
+			 *   'r' - pRocessing
+			 */
+			this.aanFeatures = [];
+			
+			/*
+			 * Variable: oLanguage
+			 * Purpose:  Store the language strings used by dataTables
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    The words in the format _VAR_ are variables which are dynamically replaced
+			 *   by javascript
+			 */
+			this.oLanguage = {
+				"sProcessing": "Processing...",
+				"sLengthMenu": "Show _MENU_ entries",
+				"sZeroRecords": "No matching records found",
+				"sEmptyTable": "No data available in table",
+				"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+				"sInfoEmpty": "Showing 0 to 0 of 0 entries",
+				"sInfoFiltered": "(filtered from _MAX_ total entries)",
+				"sInfoPostFix": "",
+				"sSearch": "Search:",
+				"sUrl": "",
+				"oPaginate": {
+					"sFirst":    "First",
+					"sPrevious": "Previous",
+					"sNext":     "Next",
+					"sLast":     "Last"
+				},
+				"fnInfoCallback": null
+			};
+			
+			/*
+			 * Variable: aoData
+			 * Purpose:  Store data information
+			 * Scope:    jQuery.dataTable.classSettings 
+			 * Notes:    This is an array of objects with the following parameters:
+			 *   int: _iId - internal id for tracking
+			 *   array: _aData - internal data - used for sorting / filtering etc
+			 *   node: nTr - display node
+			 *   array node: _anHidden - hidden TD nodes
+			 *   string: _sRowStripe
+			 */
+			this.aoData = [];
+			
+			/*
+			 * Variable: aiDisplay
+			 * Purpose:  Array of indexes which are in the current display (after filtering etc)
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.aiDisplay = [];
+			
+			/*
+			 * Variable: aiDisplayMaster
+			 * Purpose:  Array of indexes for display - no filtering
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.aiDisplayMaster = [];
+							
+			/*
+			 * Variable: aoColumns
+			 * Purpose:  Store information about each column that is in use
+			 * Scope:    jQuery.dataTable.classSettings 
+			 */
+			this.aoColumns = [];
+			
+			/*
+			 * Variable: iNextId
+			 * Purpose:  Store the next unique id to be used for a new row
+			 * Scope:    jQuery.dataTable.classSettings 
+			 */
+			this.iNextId = 0;
+			
+			/*
+			 * Variable: asDataSearch
+			 * Purpose:  Search data array for regular expression searching
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.asDataSearch = [];
+			
+			/*
+			 * Variable: oPreviousSearch
+			 * Purpose:  Store the previous search incase we want to force a re-search
+			 *   or compare the old search to a new one
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.oPreviousSearch = {
+				"sSearch": "",
+				"bRegex": false,
+				"bSmart": true
+			};
+			
+			/*
+			 * Variable: aoPreSearchCols
+			 * Purpose:  Store the previous search for each column
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.aoPreSearchCols = [];
+			
+			/*
+			 * Variable: aaSorting
+			 * Purpose:  Sorting information
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    Index 0 - column number
+			 *           Index 1 - current sorting direction
+			 *           Index 2 - index of asSorting for this column
+			 */
+			this.aaSorting = [ [0, 'asc', 0] ];
+			
+			/*
+			 * Variable: aaSortingFixed
+			 * Purpose:  Sorting information that is always applied
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.aaSortingFixed = null;
+			
+			/*
+			 * Variable: asStripClasses
+			 * Purpose:  Classes to use for the striping of a table
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.asStripClasses = [];
+			
+			/*
+			 * Variable: asDestoryStrips
+			 * Purpose:  If restoring a table - we should restore it's striping classes as well
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.asDestoryStrips = [];
+			
+			/*
+			 * Variable: sDestroyWidth
+			 * Purpose:  If restoring a table - we should restore it's width
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.sDestroyWidth = 0;
+			
+			/*
+			 * Variable: fnRowCallback
+			 * Purpose:  Call this function every time a row is inserted (draw)
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.fnRowCallback = null;
+			
+			/*
+			 * Variable: fnHeaderCallback
+			 * Purpose:  Callback function for the header on each draw
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.fnHeaderCallback = null;
+			
+			/*
+			 * Variable: fnFooterCallback
+			 * Purpose:  Callback function for the footer on each draw
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.fnFooterCallback = null;
+			
+			/*
+			 * Variable: aoDrawCallback
+			 * Purpose:  Array of callback functions for draw callback functions
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    Each array element is an object with the following parameters:
+			 *   function:fn - function to call
+			 *   string:sName - name callback (feature). useful for arranging array
+			 */
+			this.aoDrawCallback = [];
+			
+			/*
+			 * Variable: fnInitComplete
+			 * Purpose:  Callback function for when the table has been initalised
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.fnInitComplete = null;
+			
+			/*
+			 * Variable: sTableId
+			 * Purpose:  Cache the table ID for quick access
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.sTableId = "";
+			
+			/*
+			 * Variable: nTable
+			 * Purpose:  Cache the table node for quick access
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.nTable = null;
+			
+			/*
+			 * Variable: nTHead
+			 * Purpose:  Permanent ref to the thead element
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.nTHead = null;
+			
+			/*
+			 * Variable: nTFoot
+			 * Purpose:  Permanent ref to the tfoot element - if it exists
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.nTFoot = null;
+			
+			/*
+			 * Variable: nTBody
+			 * Purpose:  Permanent ref to the tbody element
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.nTBody = null;
+			
+			/*
+			 * Variable: nTableWrapper
+			 * Purpose:  Cache the wrapper node (contains all DataTables controlled elements)
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.nTableWrapper = null;
+			
+			/*
+			 * Variable: bInitialised
+			 * Purpose:  Indicate if all required information has been read in
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.bInitialised = false;
+			
+			/*
+			 * Variable: aoOpenRows
+			 * Purpose:  Information about open rows
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    Has the parameters 'nTr' and 'nParent'
+			 */
+			this.aoOpenRows = [];
+			
+			/*
+			 * Variable: sDom
+			 * Purpose:  Dictate the positioning that the created elements will take
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    
+			 *   The following options are allowed:
+			 *     'l' - Length changing
+			 *     'f' - Filtering input
+			 *     't' - The table!
+			 *     'i' - Information
+			 *     'p' - Pagination
+			 *     'r' - pRocessing
+			 *   The following constants are allowed:
+			 *     'H' - jQueryUI theme "header" classes
+			 *     'F' - jQueryUI theme "footer" classes
+			 *   The following syntax is expected:
+			 *     '<' and '>' - div elements
+			 *     '<"class" and '>' - div with a class
+			 *   Examples:
+			 *     '<"wrapper"flipt>', '<lf<t>ip>'
+			 */
+			this.sDom = 'lfrtip';
+			
+			/*
+			 * Variable: sPaginationType
+			 * Purpose:  Note which type of sorting should be used
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.sPaginationType = "two_button";
+			
+			/*
+			 * Variable: iCookieDuration
+			 * Purpose:  The cookie duration (for bStateSave) in seconds - default 2 hours
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.iCookieDuration = 60 * 60 * 2;
+			
+			/*
+			 * Variable: sCookiePrefix
+			 * Purpose:  The cookie name prefix
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.sCookiePrefix = "SpryMedia_DataTables_";
+			
+			/*
+			 * Variable: fnCookieCallback
+			 * Purpose:  Callback function for cookie creation
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.fnCookieCallback = null;
+			
+			/*
+			 * Variable: aoStateSave
+			 * Purpose:  Array of callback functions for state saving
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    Each array element is an object with the following parameters:
+			 *   function:fn - function to call. Takes two parameters, oSettings and the JSON string to
+			 *     save that has been thus far created. Returns a JSON string to be inserted into a 
+			 *     json object (i.e. '"param": [ 0, 1, 2]')
+			 *   string:sName - name of callback
+			 */
+			this.aoStateSave = [];
+			
+			/*
+			 * Variable: aoStateLoad
+			 * Purpose:  Array of callback functions for state loading
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    Each array element is an object with the following parameters:
+			 *   function:fn - function to call. Takes two parameters, oSettings and the object stored.
+			 *     May return false to cancel state loading.
+			 *   string:sName - name of callback
+			 */
+			this.aoStateLoad = [];
+			
+			/*
+			 * Variable: oLoadedState
+			 * Purpose:  State that was loaded from the cookie. Useful for back reference
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.oLoadedState = null;
+			
+			/*
+			 * Variable: sAjaxSource
+			 * Purpose:  Source url for AJAX data for the table
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.sAjaxSource = null;
+			
+			/*
+			 * Variable: bAjaxDataGet
+			 * Purpose:  Note if draw should be blocked while getting data
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.bAjaxDataGet = true;
+			
+			/*
+			 * Variable: fnServerData
+			 * Purpose:  Function to get the server-side data - can be overruled by the developer
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.fnServerData = function ( url, data, callback ) {
+				$.ajax( {
+					"url": url,
+					"data": data,
+					"success": callback,
+					"dataType": "json",
+					"cache": false,
+					"error": function (xhr, error, thrown) {
+						if ( error == "parsererror" ) {
+							alert( "DataTables warning: JSON data from server could not be parsed. "+
+								"This is caused by a JSON formatting error." );
+						}
+					}
+				} );
+			};
+			
+			/*
+			 * Variable: fnFormatNumber
+			 * Purpose:  Format numbers for display
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.fnFormatNumber = function ( iIn )
+			{
+				if ( iIn < 1000 )
+				{
+					/* A small optimisation for what is likely to be the vast majority of use cases */
+					return iIn;
+				}
+				else
+				{
+					var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
+					
+					for ( var i=0 ; i<iLen ; i++ )
+					{
+						if ( i%3 === 0 && i !== 0 )
+						{
+							out = ','+out;
+						}
+						out = a[iLen-i-1]+out;
+					}
+				}
+				return out;
+			};
+			
+			/*
+			 * Variable: aLengthMenu
+			 * Purpose:  List of options that can be used for the user selectable length menu
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Note:     This varaible can take for form of a 1D array, in which case the value and the 
+			 *   displayed value in the menu are the same, or a 2D array in which case the value comes
+			 *   from the first array, and the displayed value to the end user comes from the second
+			 *   array. 2D example: [ [ 10, 25, 50, 100, -1 ], [ 10, 25, 50, 100, 'All' ] ];
+			 */
+			this.aLengthMenu = [ 10, 25, 50, 100 ];
+			
+			/*
+			 * Variable: iDraw
+			 * Purpose:  Counter for the draws that the table does. Also used as a tracker for
+			 *   server-side processing
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.iDraw = 0;
+			
+			/*
+			 * Variable: bDrawing
+			 * Purpose:  Indicate if a redraw is being done - useful for Ajax
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.bDrawing = 0;
+			
+			/*
+			 * Variable: iDrawError
+			 * Purpose:  Last draw error
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.iDrawError = -1;
+			
+			/*
+			 * Variable: _iDisplayLength, _iDisplayStart, _iDisplayEnd
+			 * Purpose:  Display length variables
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    These variable must NOT be used externally to get the data length. Rather, use
+			 *   the fnRecordsTotal() (etc) functions.
+			 */
+			this._iDisplayLength = 10;
+			this._iDisplayStart = 0;
+			this._iDisplayEnd = 10;
+			
+			/*
+			 * Variable: _iRecordsTotal, _iRecordsDisplay
+			 * Purpose:  Display length variables used for server side processing
+			 * Scope:    jQuery.dataTable.classSettings
+			 * Notes:    These variable must NOT be used externally to get the data length. Rather, use
+			 *   the fnRecordsTotal() (etc) functions.
+			 */
+			this._iRecordsTotal = 0;
+			this._iRecordsDisplay = 0;
+			
+			/*
+			 * Variable: bJUI
+			 * Purpose:  Should we add the markup needed for jQuery UI theming?
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.bJUI = false;
+			
+			/*
+			 * Variable: bJUI
+			 * Purpose:  Should we add the markup needed for jQuery UI theming?
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.oClasses = _oExt.oStdClasses;
+			
+			/*
+			 * Variable: bFiltered and bSorted
+			 * Purpose:  Flags to allow callback functions to see what actions have been performed
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.bFiltered = false;
+			this.bSorted = false;
+			
+			/*
+			 * Variable: oInit
+			 * Purpose:  Initialisation object that is used for the table
+			 * Scope:    jQuery.dataTable.classSettings
+			 */
+			this.oInit = null;
+		}
+		
+		/*
+		 * Variable: oApi
+		 * Purpose:  Container for publicly exposed 'private' functions
+		 * Scope:    jQuery.dataTable
+		 */
+		this.oApi = {};
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - API functions
+		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+		
+		/*
+		 * Function: fnDraw
+		 * Purpose:  Redraw the table
+		 * Returns:  -
+		 * Inputs:   bool:bComplete - Refilter and resort (if enabled) the table before the draw.
+		 *             Optional: default - true
+		 */
+		this.fnDraw = function( bComplete )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			if ( typeof bComplete != 'undefined' && bComplete === false )
+			{
+				_fnCalculateEnd( oSettings );
+				_fnDraw( oSettings );
+			}
+			else
+			{
+				_fnReDraw( oSettings );
+			}
+		};
+		
+		/*
+		 * Function: fnFilter
+		 * Purpose:  Filter the input based on data
+		 * Returns:  -
+		 * Inputs:   string:sInput - string to filter the table on
+		 *           int:iColumn - optional - column to limit filtering to
+		 *           bool:bRegex - optional - treat as regular expression or not - default false
+		 *           bool:bSmart - optional - perform smart filtering or not - default true
+		 *           bool:bShowGlobal - optional - show the input global filter in it's input box(es)
+		 *              - default true
+		 */
+		this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			
+			if ( !oSettings.oFeatures.bFilter )
+			{
+				return;
+			}
+			
+			if ( typeof bRegex == 'undefined' )
+			{
+				bRegex = false;
+			}
+			
+			if ( typeof bSmart == 'undefined' )
+			{
+				bSmart = true;
+			}
+			
+			if ( typeof bShowGlobal == 'undefined' )
+			{
+				bShowGlobal = true;
+			}
+			
+			if ( typeof iColumn == "undefined" || iColumn === null )
+			{
+				/* Global filter */
+				_fnFilterComplete( oSettings, {
+					"sSearch":sInput,
+					"bRegex": bRegex,
+					"bSmart": bSmart
+				}, 1 );
+				
+				if ( bShowGlobal && typeof oSettings.aanFeatures.f != 'undefined' )
+				{
+					var n = oSettings.aanFeatures.f;
+					for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+					{
+						$('input', n[i]).val( sInput );
+					}
+				}
+			}
+			else
+			{
+				/* Single column filter */
+				oSettings.aoPreSearchCols[ iColumn ].sSearch = sInput;
+				oSettings.aoPreSearchCols[ iColumn ].bRegex = bRegex;
+				oSettings.aoPreSearchCols[ iColumn ].bSmart = bSmart;
+				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+			}
+		};
+		
+		/*
+		 * Function: fnSettings
+		 * Purpose:  Get the settings for a particular table for extern. manipulation
+		 * Returns:  -
+		 * Inputs:   -
+		 */
+		this.fnSettings = function( nNode  )
+		{
+			return _fnSettingsFromNode( this[_oExt.iApiIndex] );
+		};
+		
+		/*
+		 * Function: fnVersionCheck
+		 * Notes:    The function is the same as the 'static' function provided in the ext variable
+		 */
+		this.fnVersionCheck = _oExt.fnVersionCheck;
+		
+		/*
+		 * Function: fnSort
+		 * Purpose:  Sort the table by a particular row
+		 * Returns:  -
+		 * Inputs:   int:iCol - the data index to sort on. Note that this will
+		 *   not match the 'display index' if you have hidden data entries
+		 */
+		this.fnSort = function( aaSort )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			oSettings.aaSorting = aaSort;
+			_fnSort( oSettings );
+		};
+		
+		/*
+		 * Function: fnSortListener
+		 * Purpose:  Attach a sort listener to an element for a given column
+		 * Returns:  -
+		 * Inputs:   node:nNode - the element to attach the sort listener to
+		 *           int:iColumn - the column that a click on this node will sort on
+		 *           function:fnCallback - callback function when sort is run - optional
+		 */
+		this.fnSortListener = function( nNode, iColumn, fnCallback )
+		{
+			_fnSortAttachListener( _fnSettingsFromNode( this[_oExt.iApiIndex] ), nNode, iColumn,
+			 	fnCallback );
+		};
+		
+		/*
+		 * Function: fnAddData
+		 * Purpose:  Add new row(s) into the table
+		 * Returns:  array int: array of indexes (aoData) which have been added (zero length on error)
+		 * Inputs:   array:mData - the data to be added. The length must match
+		 *               the original data from the DOM
+		 *             or
+		 *             array array:mData - 2D array of data to be added
+		 *           bool:bRedraw - redraw the table or not - default true
+		 * Notes:    Warning - the refilter here will cause the table to redraw
+		 *             starting at zero
+		 * Notes:    Thanks to Yekimov Denis for contributing the basis for this function!
+		 */
+		this.fnAddData = function( mData, bRedraw )
+		{
+			if ( mData.length === 0 )
+			{
+				return [];
+			}
+			
+			var aiReturn = [];
+			var iTest;
+			
+			/* Find settings from table node */
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			
+			/* Check if we want to add multiple rows or not */
+			if ( typeof mData[0] == "object" )
+			{
+				for ( var i=0 ; i<mData.length ; i++ )
+				{
+					iTest = _fnAddData( oSettings, mData[i] );
+					if ( iTest == -1 )
+					{
+						return aiReturn;
+					}
+					aiReturn.push( iTest );
+				}
+			}
+			else
+			{
+				iTest = _fnAddData( oSettings, mData );
+				if ( iTest == -1 )
+				{
+					return aiReturn;
+				}
+				aiReturn.push( iTest );
+			}
+			
+			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+			
+			if ( typeof bRedraw == 'undefined' || bRedraw )
+			{
+				_fnReDraw( oSettings );
+			}
+			return aiReturn;
+		};
+		
+		/*
+		 * Function: fnDeleteRow
+		 * Purpose:  Remove a row for the table
+		 * Returns:  array:aReturn - the row that was deleted
+		 * Inputs:   mixed:mTarget - 
+		 *             int: - index of aoData to be deleted, or
+		 *             node(TR): - TR element you want to delete
+		 *           function:fnCallBack - callback function - default null
+		 *           bool:bRedraw - redraw the table or not - default true
+		 */
+		this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
+		{
+			/* Find settings from table node */
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			var i, iAODataIndex;
+			
+			iAODataIndex = (typeof mTarget == 'object') ? 
+				_fnNodeToDataIndex(oSettings, mTarget) : mTarget;
+			
+			/* Return the data array from this row */
+			var oData = oSettings.aoData.splice( iAODataIndex, 1 );
+			
+			/* Remove the target row from the search array */
+			var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
+			oSettings.asDataSearch.splice( iDisplayIndex, 1 );
+			
+			/* Delete from the display arrays */
+			_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
+			_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
+			
+			/* If there is a user callback function - call it */
+			if ( typeof fnCallBack == "function" )
+			{
+				fnCallBack.call( this, oSettings, oData );
+			}
+			
+			/* Check for an 'overflow' they case for dislaying the table */
+			if ( oSettings._iDisplayStart >= oSettings.aiDisplay.length )
+			{
+				oSettings._iDisplayStart -= oSettings._iDisplayLength;
+				if ( oSettings._iDisplayStart < 0 )
+				{
+					oSettings._iDisplayStart = 0;
+				}
+			}
+			
+			if ( typeof bRedraw == 'undefined' || bRedraw )
+			{
+				_fnCalculateEnd( oSettings );
+				_fnDraw( oSettings );
+			}
+			
+			return oData;
+		};
+		
+		/*
+		 * Function: fnClearTable
+		 * Purpose:  Quickly and simply clear a table
+		 * Returns:  -
+		 * Inputs:   bool:bRedraw - redraw the table or not - default true
+		 * Notes:    Thanks to Yekimov Denis for contributing the basis for this function!
+		 */
+		this.fnClearTable = function( bRedraw )
+		{
+			/* Find settings from table node */
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			_fnClearTable( oSettings );
+			
+			if ( typeof bRedraw == 'undefined' || bRedraw )
+			{
+				_fnDraw( oSettings );
+			}
+		};
+		
+		/*
+		 * Function: fnOpen
+		 * Purpose:  Open a display row (append a row after the row in question)
+		 * Returns:  node:nNewRow - the row opened
+		 * Inputs:   node:nTr - the table row to 'open'
+		 *           string:sHtml - the HTML to put into the row
+		 *           string:sClass - class to give the new TD cell
+		 */
+		this.fnOpen = function( nTr, sHtml, sClass )
+		{
+			/* Find settings from table node */
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			
+			/* the old open one if there is one */
+			this.fnClose( nTr );
+			
+			var nNewRow = document.createElement("tr");
+			var nNewCell = document.createElement("td");
+			nNewRow.appendChild( nNewCell );
+			nNewCell.className = sClass;
+			nNewCell.colSpan = _fnVisbleColumns( oSettings );
+			nNewCell.innerHTML = sHtml;
+			
+			/* If the nTr isn't on the page at the moment - then we don't insert at the moment */
+			var nTrs = $('tr', oSettings.nTBody);
+			if ( $.inArray(nTr, nTrs) != -1 )
+			{
+				$(nNewRow).insertAfter(nTr);
+			}
+			
+			oSettings.aoOpenRows.push( {
+				"nTr": nNewRow,
+				"nParent": nTr
+			} );
+			
+			return nNewRow;
+		};
+		
+		/*
+		 * Function: fnClose
+		 * Purpose:  Close a display row
+		 * Returns:  int: 0 (success) or 1 (failed)
+		 * Inputs:   node:nTr - the table row to 'close'
+		 */
+		this.fnClose = function( nTr )
+		{
+			/* Find settings from table node */
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			
+			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
+			{
+				if ( oSettings.aoOpenRows[i].nParent == nTr )
+				{
+					var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
+					if ( nTrParent )
+					{
+						/* Remove it if it is currently on display */
+						nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
+					}
+					oSettings.aoOpenRows.splice( i, 1 );
+					return 0;
+				}
+			}
+			return 1;
+		};
+		
+		/*
+		 * Function: fnGetData
+		 * Purpose:  Return an array with the data which is used to make up the table
+		 * Returns:  array array string: 2d data array ([row][column]) or array string: 1d data array
+		 *           or
+		 *           array string (if iRow specified)
+		 * Inputs:   mixed:mRow - optional - if not present, then the full 2D array for the table 
+		 *             if given then:
+		 *               int: - return 1D array for aoData entry of this index
+		 *               node(TR): - return 1D array for this TR element
+		 * Inputs:   int:iRow - optional - if present then the array returned will be the data for
+		 *             the row with the index 'iRow'
+		 */
+		this.fnGetData = function( mRow )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			
+			if ( typeof mRow != 'undefined' )
+			{
+				var iRow = (typeof mRow == 'object') ? 
+					_fnNodeToDataIndex(oSettings, mRow) : mRow;
+				return oSettings.aoData[iRow]._aData;
+			}
+			return _fnGetDataMaster( oSettings );
+		};
+		
+		/*
+		 * Function: fnGetNodes
+		 * Purpose:  Return an array with the TR nodes used for drawing the table
+		 * Returns:  array node: TR elements
+		 *           or
+		 *           node (if iRow specified)
+		 * Inputs:   int:iRow - optional - if present then the array returned will be the node for
+		 *             the row with the index 'iRow'
+		 */
+		this.fnGetNodes = function( iRow )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			
+			if ( typeof iRow != 'undefined' )
+			{
+				return oSettings.aoData[iRow].nTr;
+			}
+			return _fnGetTrNodes( oSettings );
+		};
+		
+		/*
+		 * Function: fnGetPosition
+		 * Purpose:  Get the array indexes of a particular cell from it's DOM element
+		 * Returns:  int: - row index, or array[ int, int, int ]: - row index, column index (visible)
+		 *             and column index including hidden columns
+		 * Inputs:   node:nNode - this can either be a TR or a TD in the table, the return is
+		 *             dependent on this input
+		 */
+		this.fnGetPosition = function( nNode )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			var i;
+			
+			if ( nNode.nodeName.toUpperCase() == "TR" )
+			{
+				return _fnNodeToDataIndex(oSettings, nNode);
+			}
+			else if ( nNode.nodeName.toUpperCase() == "TD" )
+			{
+				var iDataIndex = _fnNodeToDataIndex(oSettings, nNode.parentNode);
+				var iCorrector = 0;
+				for ( var j=0 ; j<oSettings.aoColumns.length ; j++ )
+				{
+					if ( oSettings.aoColumns[j].bVisible )
+					{
+						if ( oSettings.aoData[iDataIndex].nTr.getElementsByTagName('td')[j-iCorrector] == nNode )
+						{
+							return [ iDataIndex, j-iCorrector, j ];
+						}
+					}
+					else
+					{
+						iCorrector++;
+					}
+				}
+			}
+			return null;
+		};
+		
+		/*
+		 * Function: fnUpdate
+		 * Purpose:  Update a table cell or row
+		 * Returns:  int: 0 okay, 1 error
+		 * Inputs:   array string 'or' string:mData - data to update the cell/row with
+		 *           mixed:mRow - 
+		 *             int: - index of aoData to be updated, or
+		 *             node(TR): - TR element you want to update
+		 *           int:iColumn - the column to update - optional (not used of mData is 2D)
+		 *           bool:bRedraw - redraw the table or not - default true
+		 *           bool:bAction - perform predraw actions or not (you will want this as 'true' if
+		 *             you have bRedraw as true) - default true
+		 */
+		this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			var iVisibleColumn;
+			var sDisplay;
+			var iRow = (typeof mRow == 'object') ? 
+				_fnNodeToDataIndex(oSettings, mRow) : mRow;
+			
+			if ( typeof mData != 'object' )
+			{
+				sDisplay = mData;
+				oSettings.aoData[iRow]._aData[iColumn] = sDisplay;
+				
+				if ( oSettings.aoColumns[iColumn].fnRender !== null )
+				{
+					sDisplay = oSettings.aoColumns[iColumn].fnRender( {
+						"iDataRow": iRow,
+						"iDataColumn": iColumn,
+						"aData": oSettings.aoData[iRow]._aData,
+						"oSettings": oSettings
+					} );
+					
+					if ( oSettings.aoColumns[iColumn].bUseRendered )
+					{
+						oSettings.aoData[iRow]._aData[iColumn] = sDisplay;
+					}
+				}
+				
+				iVisibleColumn = _fnColumnIndexToVisible( oSettings, iColumn );
+				if ( iVisibleColumn !== null )
+				{
+					oSettings.aoData[iRow].nTr.getElementsByTagName('td')[iVisibleColumn].innerHTML = 
+						sDisplay;
+				}
+			}
+			else
+			{
+				if ( mData.length != oSettings.aoColumns.length )
+				{
+					_fnLog( oSettings, 0, 'An array passed to fnUpdate must have the same number of '+
+						'columns as the table in question - in this case '+oSettings.aoColumns.length );
+					return 1;
+				}
+				
+				for ( var i=0 ; i<mData.length ; i++ )
+				{
+					sDisplay = mData[i];
+					oSettings.aoData[iRow]._aData[i] = sDisplay;
+					
+					if ( oSettings.aoColumns[i].fnRender !== null )
+					{
+						sDisplay = oSettings.aoColumns[i].fnRender( {
+							"iDataRow": iRow,
+							"iDataColumn": i,
+							"aData": oSettings.aoData[iRow]._aData,
+							"oSettings": oSettings
+						} );
+						
+						if ( oSettings.aoColumns[i].bUseRendered )
+						{
+							oSettings.aoData[iRow]._aData[i] = sDisplay;
+						}
+					}
+					
+					iVisibleColumn = _fnColumnIndexToVisible( oSettings, i );
+					if ( iVisibleColumn !== null )
+					{
+						oSettings.aoData[iRow].nTr.getElementsByTagName('td')[iVisibleColumn].innerHTML = 
+							sDisplay;
+					}
+				}
+			}
+			
+			/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
+			 * will rebuild the search array - however, the redraw might be disabled by the user)
+			 */
+			var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
+			oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow( oSettings, 
+				oSettings.aoData[iRow]._aData );
+			
+			/* Perform pre-draw actions */
+			if ( typeof bAction == 'undefined' || bAction )
+			{
+				_fnAjustColumnSizing( oSettings );
+			}
+			
+			/* Redraw the table */
+			if ( typeof bRedraw == 'undefined' || bRedraw )
+			{
+				_fnReDraw( oSettings );
+			}
+			return 0;
+		};
+		
+		
+		/*
+		 * Function: fnShowColoumn
+		 * Purpose:  Show a particular column
+		 * Returns:  -
+		 * Inputs:   int:iCol - the column whose display should be changed
+		 *           bool:bShow - show (true) or hide (false) the column
+		 *           bool:bRedraw - redraw the table or not - default true
+		 */
+		this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			var i, iLen;
+			var iColumns = oSettings.aoColumns.length;
+			var nTd, anTds;
+			
+			/* No point in doing anything if we are requesting what is already true */
+			if ( oSettings.aoColumns[iCol].bVisible == bShow )
+			{
+				return;
+			}
+			
+			var nTrHead = $('>tr', oSettings.nTHead)[0];
+			var nTrFoot = $('>tr', oSettings.nTFoot)[0];
+			var anTheadTh = [];
+			var anTfootTh = [];
+			for ( i=0 ; i<iColumns ; i++ )
+			{
+				anTheadTh.push( oSettings.aoColumns[i].nTh );
+				anTfootTh.push( oSettings.aoColumns[i].nTf );
+			}
+			
+			/* Show the column */
+			if ( bShow )
+			{
+				var iInsert = 0;
+				for ( i=0 ; i<iCol ; i++ )
+				{
+					if ( oSettings.aoColumns[i].bVisible )
+					{
+						iInsert++;
+					}
+				}
+				
+				/* Need to decide if we should use appendChild or insertBefore */
+				if ( iInsert >= _fnVisbleColumns( oSettings ) )
+				{
+					nTrHead.appendChild( anTheadTh[iCol] );
+					if ( nTrFoot )
+					{
+						nTrFoot.appendChild( anTfootTh[iCol] );
+					}
+					
+					for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+					{
+						nTd = oSettings.aoData[i]._anHidden[iCol];
+						oSettings.aoData[i].nTr.appendChild( nTd );
+					}
+				}
+				else
+				{
+					/* Which coloumn should we be inserting before? */
+					var iBefore;
+					for ( i=iCol ; i<iColumns ; i++ )
+					{
+						iBefore = _fnColumnIndexToVisible( oSettings, i );
+						if ( iBefore !== null )
+						{
+							break;
+						}
+					}
+					
+					nTrHead.insertBefore( anTheadTh[iCol], nTrHead.getElementsByTagName('th')[iBefore] );
+					if ( nTrFoot )
+					{
+						nTrFoot.insertBefore( anTfootTh[iCol], nTrFoot.getElementsByTagName('th')[iBefore] );
+					}
+					
+					anTds = _fnGetTdNodes( oSettings );
+					for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+					{
+						nTd = oSettings.aoData[i]._anHidden[iCol];
+						oSettings.aoData[i].nTr.insertBefore( nTd, $('>td:eq('+iBefore+')', 
+							oSettings.aoData[i].nTr)[0] );
+					}
+				}
+				
+				oSettings.aoColumns[iCol].bVisible = true;
+			}
+			else
+			{
+				/* Remove a column from display */
+				nTrHead.removeChild( anTheadTh[iCol] );
+				if ( nTrFoot )
+				{
+					nTrFoot.removeChild( anTfootTh[iCol] );
+				}
+				
+				anTds = _fnGetTdNodes( oSettings );
+				for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+				{
+					nTd = anTds[ ( i*oSettings.aoColumns.length) + (iCol*1) ];
+					oSettings.aoData[i]._anHidden[iCol] = nTd;
+					nTd.parentNode.removeChild( nTd );
+				}
+				
+				oSettings.aoColumns[iCol].bVisible = false;
+			}
+			
+			/* If there are any 'open' rows, then we need to alter the colspan for this col change */
+			for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
+			{
+				oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
+			}
+			
+			/* Do a redraw incase anything depending on the table columns needs it 
+			 * (built-in: scrolling) 
+			 */
+			if ( typeof bRedraw == 'undefined' || bRedraw )
+			{
+				_fnAjustColumnSizing( oSettings );
+				_fnDraw( oSettings );
+			}
+			
+			_fnSaveState( oSettings );
+		};
+		
+		/*
+		 * Function: fnPageChange
+		 * Purpose:  Change the pagination
+		 * Returns:  -
+		 * Inputs:   string:sAction - paging action to take: "first", "previous", "next" or "last"
+		 *           bool:bRedraw - redraw the table or not - optional - default true
+		 */
+		this.fnPageChange = function ( sAction, bRedraw )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			_fnPageChange( oSettings, sAction );
+			_fnCalculateEnd( oSettings );
+			
+			if ( typeof bRedraw == 'undefined' || bRedraw )
+			{
+				_fnDraw( oSettings );
+			}
+		};
+		
+		/*
+		 * Function: fnDestroy
+		 * Purpose:  Destructor for the DataTable
+		 * Returns:  -
+		 * Inputs:   -
+		 */
+		this.fnDestroy = function ( )
+		{
+			var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+			var nOrig = oSettings.nTableWrapper.parentNode;
+			var nBody = oSettings.nTBody;
+			var i, iLen;
+			
+			/* Flag to note that the table is currently being destoryed - no action should be taken */
+			oSettings.bDestroying = true;
+			
+			/* Restore hidden columns */
+			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+			{
+				if ( oSettings.aoColumns[i].bVisible === false )
+				{
+					this.fnSetColumnVis( i, true );
+				}
+			}
+			
+			/* If there is an 'empty' indicator row, remove it */
+			$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
+			
+			/* When scrolling we had to break the table up - restore it */
+			if ( oSettings.nTable != oSettings.nTHead.parentNode )
+			{
+				$('>thead', oSettings.nTable).remove();
+				oSettings.nTable.appendChild( oSettings.nTHead );
+			}
+			
+			if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
+			{
+				$('>tfoot', oSettings.nTable).remove();
+				oSettings.nTable.appendChild( oSettings.nTFoot );
+			}
+			
+			/* Remove the DataTables generated nodes, events and classes */
+			oSettings.nTable.parentNode.removeChild( oSettings.nTable );
+			$(oSettings.nTableWrapper).remove();
+			
+			oSettings.aaSorting = [];
+			oSettings.aaSortingFixed = [];
+			_fnSortingClasses( oSettings );
+			
+			$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripClasses.join(' ') );
+			
+			if ( !oSettings.bJUI )
+			{
+				$('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,
+					_oExt.oStdClasses.sSortableAsc,
+					_oExt.oStdClasses.sSortableDesc,
+					_oExt.oStdClasses.sSortableNone ].join(' ')
+				);
+			}
+			else
+			{
+				$('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,
+					_oExt.oJUIClasses.sSortableAsc,
+					_oExt.oJUIClasses.sSortableDesc,
+					_oExt.oJUIClasses.sSortableNone ].join(' ')
+				);
+				$('th span', oSettings.nTHead).remove();
+			}
+			
+			/* Add the TR elements back into the table in their original order */
+			nOrig.appendChild( oSettings.nTable );
+			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+			{
+				nBody.appendChild( oSettings.aoData[i].nTr );
+			}
+			
+			/* Restore the width of the original table */
+			oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
+			
+			/* If the were originally odd/even type classes - then we add them back here. Note
+			 * this is not fool proof (for example if not all rows as odd/even classes - but 
+			 * it's a good effort without getting carried away
+			 */
+			$('>tr:even', nBody).addClass( oSettings.asDestoryStrips[0] );
+			$('>tr:odd', nBody).addClass( oSettings.asDestoryStrips[1] );
+			
+			/* Remove the settings object from the settings array */
+			for ( i=0, iLen=_aoSettings.length ; i<iLen ; i++ )
+			{
+				if ( _aoSettings[i] == oSettings )
+				{
+					_aoSettings.splice( i, 1 );
+				}
+			}
+			
+			/* End it all */
+			oSettings = null;
+		};
+		
+		/*
+		 * Function: _fnAjustColumnSizing
+		 * Purpose:  Update tale sizing based on content. This would most likely be used for scrolling
+		 *   and will typically need a redraw after it.
+		 * Returns:  -
+		 * Inputs:   bool:bRedraw - redraw the table or not, you will typically want to - default true
+		 */
+		this.fnAdjustColumnSizing = function ( bRedraw )
+		{
+			_fnAjustColumnSizing( _fnSettingsFromNode( this[_oExt.iApiIndex] ) );
+			
+			if ( typeof bRedraw == 'undefined' || bRedraw )
+			{
+				this.fnDraw( false );
+			}
+		};
+		
+		/*
+		 * Plugin API functions
+		 * 
+		 * This call will add the functions which are defined in _oExt.oApi to the
+		 * DataTables object, providing a rather nice way to allow plug-in API functions. Note that
+		 * this is done here, so that API function can actually override the built in API functions if
+		 * required for a particular purpose.
+		 */
+		
+		/*
+		 * Function: _fnExternApiFunc
+		 * Purpose:  Create a wrapper function for exporting an internal func to an external API func
+		 * Returns:  function: - wrapped function
+		 * Inputs:   string:sFunc - API function name
+		 */
+		function _fnExternApiFunc (sFunc)
+		{
+			return function() {
+					var aArgs = [_fnSettingsFromNode(this[_oExt.iApiIndex])].concat( 
+						Array.prototype.slice.call(arguments) );
+					return _oExt.oApi[sFunc].apply( this, aArgs );
+				};
+		}
+		
+		for ( var sFunc in _oExt.oApi )
+		{
+			if ( sFunc )
+			{
+				/*
+				 * Function: anon
+				 * Purpose:  Wrap the plug-in API functions in order to provide the settings as 1st arg 
+				 *   and execute in this scope
+				 * Returns:  -
+				 * Inputs:   -
+				 */
+				this[sFunc] = _fnExternApiFunc(sFunc);
+			}
+		}
+		
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Local functions
+		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Initalisation
+		 */
+		
+		/*
+		 * Function: _fnInitalise
+		 * Purpose:  Draw the table for the first time, adding all required features
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnInitalise ( oSettings )
+		{
+			var i, iLen;
+			
+			/* Ensure that the table data is fully initialised */
+			if ( oSettings.bInitialised === false )
+			{
+				setTimeout( function(){ _fnInitalise( oSettings ); }, 200 );
+				return;
+			}
+			
+			/* Show the display HTML options */
+			_fnAddOptionsHtml( oSettings );
+			
+			/* Draw the headers for the table */
+			_fnDrawHead( oSettings );
+			
+			/* Okay to show that something is going on now */
+			_fnProcessingDisplay( oSettings, true );
+			
+			/* Calculate sizes for columns */
+			if ( oSettings.oFeatures.bAutoWidth )
+			{
+				_fnCalculateColumnWidths( oSettings );
+			}
+			
+			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+			{
+				if ( oSettings.aoColumns[i].sWidth !== null )
+				{
+					oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
+				}
+			}
+			
+			/* If there is default sorting required - let's do it. The sort function
+			 * will do the drawing for us. Otherwise we draw the table
+			 */
+			if ( oSettings.oFeatures.bSort )
+			{
+				_fnSort( oSettings );
+			}
+			else
+			{
+				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+				_fnCalculateEnd( oSettings );
+				_fnDraw( oSettings );
+			}
+			
+			/* if there is an ajax source */
+			if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
+			{
+				oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, [], function(json) {
+					/* Got the data - add it to the table */
+					for ( i=0 ; i<json.aaData.length ; i++ )
+					{
+						_fnAddData( oSettings, json.aaData[i] );
+					}
+					
+					/* Reset the init display for cookie saving. We've already done a filter, and
+					 * therefore cleared it before. So we need to make it appear 'fresh'
+					 */
+					oSettings.iInitDisplayStart = oSettings._iDisplayStart;
+					
+					if ( oSettings.oFeatures.bSort )
+					{
+						_fnSort( oSettings );
+					}
+					else
+					{
+						oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+						_fnCalculateEnd( oSettings );
+						_fnDraw( oSettings );
+					}
+					
+					_fnProcessingDisplay( oSettings, false );
+					
+					/* Run the init callback if there is one - done here for ajax source for json obj */
+					if ( typeof oSettings.fnInitComplete == 'function' )
+					{
+						oSettings.fnInitComplete.call( oSettings.oInstance, oSettings, json );
+					}
+				} );
+				return;
+			}
+			
+			if ( !oSettings.oFeatures.bServerSide )
+			{
+				_fnProcessingDisplay( oSettings, false );
+			}
+		}
+		
+		/*
+		 * Function: _fnLanguageProcess
+		 * Purpose:  Copy language variables from remote object to a local one
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           object:oLanguage - Language information
+		 *           bool:bInit - init once complete
+		 */
+		function _fnLanguageProcess( oSettings, oLanguage, bInit )
+		{
+			_fnMap( oSettings.oLanguage, oLanguage, 'sProcessing' );
+			_fnMap( oSettings.oLanguage, oLanguage, 'sLengthMenu' );
+			_fnMap( oSettings.oLanguage, oLanguage, 'sEmptyTable' );
+			_fnMap( oSettings.oLanguage, oLanguage, 'sZeroRecords' );
+			_fnMap( oSettings.oLanguage, oLanguage, 'sInfo' );
+			_fnMap( oSettings.oLanguage, oLanguage, 'sInfoEmpty' );
+			_fnMap( oSettings.oLanguage, oLanguage, 'sInfoFiltered' );
+			_fnMap( oSettings.oLanguage, oLanguage, 'sInfoPostFix' );
+			_fnMap( oSettings.oLanguage, oLanguage, 'sSearch' );
+			
+			if ( typeof oLanguage.oPaginate != 'undefined' )
+			{
+				_fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sFirst' );
+				_fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sPrevious' );
+				_fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sNext' );
+				_fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sLast' );
+			}
+			
+			/* Backwards compatibility - if there is no sEmptyTable given, then use the same as
+			 * sZeroRecords - assuming that is given.
+			 */
+			if ( typeof oLanguage.sEmptyTable == 'undefined' && 
+			     typeof oLanguage.sZeroRecords != 'undefined' )
+			{
+				_fnMap( oSettings.oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
+			}
+			
+			if ( bInit )
+			{
+				_fnInitalise( oSettings );
+			}
+		}
+		
+		/*
+		 * Function: _fnAddColumn
+		 * Purpose:  Add a column to the list used for the table with default values
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           node:nTh - the th element for this column
+		 */
+		function _fnAddColumn( oSettings, nTh )
+		{
+			oSettings.aoColumns[ oSettings.aoColumns.length++ ] = {
+				"sType": null,
+				"_bAutoType": true,
+				"bVisible": true,
+				"bSearchable": true,
+				"bSortable": true,
+				"asSorting": [ 'asc', 'desc' ],
+				"sSortingClass": oSettings.oClasses.sSortable,
+				"sSortingClassJUI": oSettings.oClasses.sSortJUI,
+				"sTitle": nTh ? nTh.innerHTML : '',
+				"sName": '',
+				"sWidth": null,
+				"sWidthOrig": null,
+				"sClass": null,
+				"fnRender": null,
+				"bUseRendered": true,
+				"iDataSort": oSettings.aoColumns.length-1,
+				"sSortDataType": 'std',
+				"nTh": nTh ? nTh : document.createElement('th'),
+				"nTf": null
+			};
+			
+			var iCol = oSettings.aoColumns.length-1;
+			var oCol = oSettings.aoColumns[ iCol ];
+			
+			/* Add a column specific filter */
+			if ( typeof oSettings.aoPreSearchCols[ iCol ] == 'undefined' ||
+			     oSettings.aoPreSearchCols[ iCol ] === null )
+			{
+				oSettings.aoPreSearchCols[ iCol ] = {
+					"sSearch": "",
+					"bRegex": false,
+					"bSmart": true
+				};
+			}
+			else
+			{
+				/* Don't require that the user must specify bRegex and / or bSmart */
+				if ( typeof oSettings.aoPreSearchCols[ iCol ].bRegex == 'undefined' )
+				{
+					oSettings.aoPreSearchCols[ iCol ].bRegex = true;
+				}
+				
+				if ( typeof oSettings.aoPreSearchCols[ iCol ].bSmart == 'undefined' )
+				{
+					oSettings.aoPreSearchCols[ iCol ].bSmart = true;
+				}
+			} 
+			
+			/* Use the column options function to initialise classes etc */
+			_fnColumnOptions( oSettings, iCol, null );
+		}
+		
+		/*
+		 * Function: _fnColumnOptions
+		 * Purpose:  Apply options for a column
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           int:iCol - column index to consider
+		 *           object:oOptions - object with sType, bVisible and bSearchable
+		 */
+		function _fnColumnOptions( oSettings, iCol, oOptions )
+		{
+			var oCol = oSettings.aoColumns[ iCol ];
+			
+			/* User specified column options */
+			if ( typeof oOptions != 'undefined' && oOptions !== null )
+			{
+				if ( typeof oOptions.sType != 'undefined' )
+				{
+					oCol.sType = oOptions.sType;
+					oCol._bAutoType = false;
+				}
+				
+				_fnMap( oCol, oOptions, "bVisible" );
+				_fnMap( oCol, oOptions, "bSearchable" );
+				_fnMap( oCol, oOptions, "bSortable" );
+				_fnMap( oCol, oOptions, "sTitle" );
+				_fnMap( oCol, oOptions, "sName" );
+				_fnMap( oCol, oOptions, "sWidth" );
+				_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
+				_fnMap( oCol, oOptions, "sClass" );
+				_fnMap( oCol, oOptions, "fnRender" );
+				_fnMap( oCol, oOptions, "bUseRendered" );
+				_fnMap( oCol, oOptions, "iDataSort" );
+				_fnMap( oCol, oOptions, "asSorting" );
+				_fnMap( oCol, oOptions, "sSortDataType" );
+			}
+			
+			/* Feature sorting overrides column specific when off */
+			if ( !oSettings.oFeatures.bSort )
+			{
+				oCol.bSortable = false;
+			}
+			
+			/* Check that the class assignment is correct for sorting */
+			if ( !oCol.bSortable ||
+					 ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
+			{
+				oCol.sSortingClass = oSettings.oClasses.sSortableNone;
+				oCol.sSortingClassJUI = "";
+			}
+			else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
+			{
+				oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
+				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
+			}
+			else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
+			{
+				oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
+				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
+			}
+		}
+		
+		/*
+		 * Function: _fnAddData
+		 * Purpose:  Add a data array to the table, creating DOM node etc
+		 * Returns:  int: - >=0 if successful (index of new aoData entry), -1 if failed
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           array:aData - data array to be added
+		 * Notes:    There are two basic methods for DataTables to get data to display - a JS array
+		 *   (which is dealt with by this function), and the DOM, which has it's own optimised
+		 *   function (_fnGatherData). Be careful to make the same changes here as there and vice-versa
+		 */
+		function _fnAddData ( oSettings, aDataSupplied )
+		{
+			/* Sanity check the length of the new array */
+			if ( aDataSupplied.length != oSettings.aoColumns.length &&
+				oSettings.iDrawError != oSettings.iDraw )
+			{
+				_fnLog( oSettings, 0, "Added data (size "+aDataSupplied.length+") does not match known "+
+					"number of columns ("+oSettings.aoColumns.length+")" );
+				oSettings.iDrawError = oSettings.iDraw;
+				return -1;
+			}
+			
+			
+			/* Create the object for storing information about this new row */
+			var aData = aDataSupplied.slice();
+			var iThisIndex = oSettings.aoData.length;
+			oSettings.aoData.push( {
+				"nTr": document.createElement('tr'),
+				"_iId": oSettings.iNextId++,
+				"_aData": aData,
+				"_anHidden": [],
+				"_sRowStripe": ''
+			} );
+			
+			/* Create the cells */
+			var nTd, sThisType;
+			for ( var i=0 ; i<aData.length ; i++ )
+			{
+				nTd = document.createElement('td');
+				
+				/* Allow null data (from a data array) - simply deal with it as a blank string */
+				if ( aData[i] === null )
+				{
+					aData[i] = '';
+				}
+				
+				if ( typeof oSettings.aoColumns[i].fnRender == 'function' )
+				{
+					var sRendered = oSettings.aoColumns[i].fnRender( {
+							"iDataRow": iThisIndex,
+							"iDataColumn": i,
+							"aData": aData,
+							"oSettings": oSettings
+						} );
+					nTd.innerHTML = sRendered;
+					if ( oSettings.aoColumns[i].bUseRendered )
+					{
+						/* Use the rendered data for filtering/sorting */
+						oSettings.aoData[iThisIndex]._aData[i] = sRendered;
+					}
+				}
+				else
+				{
+					nTd.innerHTML = aData[i];
+				}
+				
+				/* Cast everything as a string - so we can treat everything equally when sorting */
+				if ( typeof aData[i] != 'string' )
+				{
+					aData[i] += "";
+				}
+				aData[i] = $.trim(aData[i]);
+				
+				/* Add user defined class */
+				if ( oSettings.aoColumns[i].sClass !== null )
+				{
+					nTd.className = oSettings.aoColumns[i].sClass;
+				}
+				
+				/* See if we should auto-detect the column type */
+				if ( oSettings.aoColumns[i]._bAutoType && oSettings.aoColumns[i].sType != 'string' )
+				{
+					/* Attempt to auto detect the type - same as _fnGatherData() */
+					sThisType = _fnDetectType( oSettings.aoData[iThisIndex]._aData[i] );
+					if ( oSettings.aoColumns[i].sType === null )
+					{
+						oSettings.aoColumns[i].sType = sThisType;
+					}
+					else if ( oSettings.aoColumns[i].sType != sThisType )
+					{
+						/* String is always the 'fallback' option */
+						oSettings.aoColumns[i].sType = 'string';
+					}
+				}
+					
+				if ( oSettings.aoColumns[i].bVisible )
+				{
+					oSettings.aoData[iThisIndex].nTr.appendChild( nTd );
+					oSettings.aoData[iThisIndex]._anHidden[i] = null;
+				}
+				else
+				{
+					oSettings.aoData[iThisIndex]._anHidden[i] = nTd;
+				}
+			}
+			
+			/* Add to the display array */
+			oSettings.aiDisplayMaster.push( iThisIndex );
+			return iThisIndex;
+		}
+		
+		/*
+		 * Function: _fnGatherData
+		 * Purpose:  Read in the data from the target table from the DOM
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 * Notes:    This is a optimised version of _fnAddData (more or less) for reading information
+		 *   from the DOM. The basic actions must be identical in the two functions.
+		 */
+		function _fnGatherData( oSettings )
+		{
+			var iLoop, i, iLen, j, jLen, jInner,
+			 	nTds, nTrs, nTd, aLocalData, iThisIndex,
+				iRow, iRows, iColumn, iColumns;
+			
+			/*
+			 * Process by row first
+			 * Add the data object for the whole table - storing the tr node. Note - no point in getting
+			 * DOM based data if we are going to go and replace it with Ajax source data.
+			 */
+			if ( oSettings.sAjaxSource === null )
+			{
+				nTrs = oSettings.nTBody.childNodes;
+				for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+				{
+					if ( nTrs[i].nodeName.toUpperCase() == "TR" )
+					{
+						iThisIndex = oSettings.aoData.length;
+						oSettings.aoData.push( {
+							"nTr": nTrs[i],
+							"_iId": oSettings.iNextId++,
+							"_aData": [],
+							"_anHidden": [],
+							"_sRowStripe": ''
+						} );
+						
+						oSettings.aiDisplayMaster.push( iThisIndex );
+						
+						aLocalData = oSettings.aoData[iThisIndex]._aData;
+						nTds = nTrs[i].childNodes;
+						jInner = 0;
+						
+						for ( j=0, jLen=nTds.length ; j<jLen ; j++ )
+						{
+							if ( nTds[j].nodeName.toUpperCase() == "TD" )
+							{
+								aLocalData[jInner] = $.trim(nTds[j].innerHTML);
+								jInner++;
+							}
+						}
+					}
+				}
+			}
+			
+			/* Gather in the TD elements of the Table - note that this is basically the same as
+			 * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
+			 * setup!
+			 */
+			nTrs = _fnGetTrNodes( oSettings );
+			nTds = [];
+			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+			{
+				for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
+				{
+					nTd = nTrs[i].childNodes[j];
+					if ( nTd.nodeName.toUpperCase() == "TD" )
+					{
+						nTds.push( nTd );
+					}
+				}
+			}
+			
+			/* Sanity check */
+			if ( nTds.length != nTrs.length * oSettings.aoColumns.length )
+			{
+				_fnLog( oSettings, 1, "Unexpected number of TD elements. Expected "+
+					(nTrs.length * oSettings.aoColumns.length)+" and got "+nTds.length+". DataTables does "+
+					"not support rowspan / colspan in the table body, and there must be one cell for each "+
+					"row/column combination." );
+			}
+			
+			/* Now process by column */
+			for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
+			{
+				/* Get the title of the column - unless there is a user set one */
+				if ( oSettings.aoColumns[iColumn].sTitle === null )
+				{
+					oSettings.aoColumns[iColumn].sTitle = oSettings.aoColumns[iColumn].nTh.innerHTML;
+				}
+				
+				var
+					bAutoType = oSettings.aoColumns[iColumn]._bAutoType,
+					bRender = typeof oSettings.aoColumns[iColumn].fnRender == 'function',
+					bClass = oSettings.aoColumns[iColumn].sClass !== null,
+					bVisible = oSettings.aoColumns[iColumn].bVisible,
+					nCell, sThisType, sRendered;
+				
+				/* A single loop to rule them all (and be more efficient) */
+				if ( bAutoType || bRender || bClass || !bVisible )
+				{
+					for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
+					{
+						nCell = nTds[ (iRow*iColumns) + iColumn ];
+						
+						/* Type detection */
+						if ( bAutoType )
+						{
+							if ( oSettings.aoColumns[iColumn].sType != 'string' )
+							{
+								sThisType = _fnDetectType( oSettings.aoData[iRow]._aData[iColumn] );
+								if ( oSettings.aoColumns[iColumn].sType === null )
+								{
+									oSettings.aoColumns[iColumn].sType = sThisType;
+								}
+								else if ( oSettings.aoColumns[iColumn].sType != sThisType )
+								{
+									/* String is always the 'fallback' option */
+									oSettings.aoColumns[iColumn].sType = 'string';
+								}
+							}
+						}
+						
+						/* Rendering */
+						if ( bRender )
+						{
+							sRendered = oSettings.aoColumns[iColumn].fnRender( {
+									"iDataRow": iRow,
+									"iDataColumn": iColumn,
+									"aData": oSettings.aoData[iRow]._aData,
+									"oSettings": oSettings
+								} );
+							nCell.innerHTML = sRendered;
+							if ( oSettings.aoColumns[iColumn].bUseRendered )
+							{
+								/* Use the rendered data for filtering/sorting */
+								oSettings.aoData[iRow]._aData[iColumn] = sRendered;
+							}
+						}
+						
+						/* Classes */
+						if ( bClass )
+						{
+							nCell.className += ' '+oSettings.aoColumns[iColumn].sClass;
+						}
+						
+						/* Column visability */
+						if ( !bVisible )
+						{
+							oSettings.aoData[iRow]._anHidden[iColumn] = nCell;
+							nCell.parentNode.removeChild( nCell );
+						}
+						else
+						{
+							oSettings.aoData[iRow]._anHidden[iColumn] = null;
+						}
+					}
+				}
+			}
+		}
+		
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Drawing functions
+		 */
+		
+		/*
+		 * Function: _fnDrawHead
+		 * Purpose:  Create the HTML header for the table
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnDrawHead( oSettings )
+		{
+			var i, nTh, iLen, j, jLen;
+			var iThs = oSettings.nTHead.getElementsByTagName('th').length;
+			var iCorrector = 0;
+			
+			/* If there is a header in place - then use it - otherwise it's going to get nuked... */
+			if ( iThs !== 0 )
+			{
+				/* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
+				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+				{
+					nTh = oSettings.aoColumns[i].nTh;
+					
+					if ( oSettings.aoColumns[i].bVisible )
+					{
+						/* Set the title of the column if it is user defined (not what was auto detected) */
+						if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
+						{
+							nTh.innerHTML = oSettings.aoColumns[i].sTitle;
+						}
+					}
+					else
+					{
+						nTh.parentNode.removeChild( nTh );
+						iCorrector++;
+					}
+				}
+			}
+			else
+			{
+				/* We don't have a header in the DOM - so we are going to have to create one */
+				var nTr = document.createElement( "tr" );
+				
+				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+				{
+					nTh = oSettings.aoColumns[i].nTh;
+					nTh.innerHTML = oSettings.aoColumns[i].sTitle;
+					
+					if ( oSettings.aoColumns[i].bVisible )
+					{
+						if ( oSettings.aoColumns[i].sClass !== null )
+						{
+							nTh.className = oSettings.aoColumns[i].sClass;
+						}
+						
+						nTr.appendChild( nTh );
+					}
+				}
+				$(oSettings.nTHead).html( '' )[0].appendChild( nTr );
+			}
+			
+			/* Add the extra markup needed by jQuery UI's themes */
+			if ( oSettings.bJUI )
+			{
+				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+				{
+					nTh = oSettings.aoColumns[i].nTh;
+					
+					var nDiv = document.createElement('div');
+					nDiv.className = oSettings.oClasses.sSortJUIWrapper;
+					$(nTh).contents().appendTo(nDiv);
+					
+					nDiv.appendChild( document.createElement('span') );
+					nTh.appendChild( nDiv );
+				}
+			}
+			
+			/* Add sort listener */
+			var fnNoSelect = function (e) {
+				this.onselectstart = function() { return false; };
+				return false;
+			};
+			
+			if ( oSettings.oFeatures.bSort )
+			{
+				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+				{
+					if ( oSettings.aoColumns[i].bSortable !== false )
+					{
+						_fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
+						
+						/* Take the brutal approach to cancelling text selection in header */
+						$(oSettings.aoColumns[i].nTh).mousedown( fnNoSelect );
+					}
+					else
+					{
+						$(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
+					}
+				}
+			}
+			
+			/* Cache the footer elements */
+			if ( oSettings.nTFoot !== null )
+			{
+				iCorrector = 0;
+				var nTfs = oSettings.nTFoot.getElementsByTagName('th');
+				for ( i=0, iLen=nTfs.length ; i<iLen ; i++ )
+				{
+					if ( typeof oSettings.aoColumns[i] != 'undefined' )
+					{
+						oSettings.aoColumns[i].nTf = nTfs[i-iCorrector];
+						
+						if ( oSettings.oClasses.sFooterTH !== "" )
+						{
+							oSettings.aoColumns[i].nTf.className += " "+oSettings.oClasses.sFooterTH;
+						}
+						
+						if ( !oSettings.aoColumns[i].bVisible )
+						{
+							nTfs[i-iCorrector].parentNode.removeChild( nTfs[i-iCorrector] );
+							iCorrector++;
+						}
+					}
+				}
+			}
+		}
+		
+		/*
+		 * Function: _fnDraw
+		 * Purpose:  Insert the required TR nodes into the table for display
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnDraw( oSettings )
+		{
+			var i, iLen;
+			var anRows = [];
+			var iRowCount = 0;
+			var bRowError = false;
+			var iStrips = oSettings.asStripClasses.length;
+			var iOpenRows = oSettings.aoOpenRows.length;
+			
+			oSettings.bDrawing = true;
+			
+			/* Check and see if we have an initial draw position from state saving */
+			if ( typeof oSettings.iInitDisplayStart != 'undefined' && oSettings.iInitDisplayStart != -1 )
+			{
+				if ( oSettings.oFeatures.bServerSide )
+				{
+					oSettings._iDisplayStart = oSettings.iInitDisplayStart;
+				}
+				else
+				{
+					oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
+						0 : oSettings.iInitDisplayStart;
+				}
+				oSettings.iInitDisplayStart = -1;
+				_fnCalculateEnd( oSettings );
+			}
+			
+			/* If we are dealing with Ajax - do it here */
+			if ( oSettings.oFeatures.bServerSide && 
+			     !_fnAjaxUpdate( oSettings ) )
+			{
+				return;
+			}
+			else if ( !oSettings.oFeatures.bServerSide )
+			{
+				oSettings.iDraw++;
+			}
+			
+			if ( oSettings.aiDisplay.length !== 0 )
+			{
+				var iStart = oSettings._iDisplayStart;
+				var iEnd = oSettings._iDisplayEnd;
+				
+				if ( oSettings.oFeatures.bServerSide )
+				{
+					iStart = 0;
+					iEnd = oSettings.aoData.length;
+				}
+				
+				for ( var j=iStart ; j<iEnd ; j++ )
+				{
+					var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
+					var nRow = aoData.nTr;
+					
+					/* Remove the old stripping classes and then add the new one */
+					if ( iStrips !== 0 )
+					{
+						var sStrip = oSettings.asStripClasses[ iRowCount % iStrips ];
+						if ( aoData._sRowStripe != sStrip )
+						{
+							$(nRow).removeClass( aoData._sRowStripe ).addClass( sStrip );
+							aoData._sRowStripe = sStrip;
+						}
+					}
+					
+					/* Custom row callback function - might want to manipule the row */
+					if ( typeof oSettings.fnRowCallback == "function" )
+					{
+						nRow = oSettings.fnRowCallback.call( oSettings.oInstance, nRow, 
+							oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j );
+						if ( !nRow && !bRowError )
+						{
+							_fnLog( oSettings, 0, "A node was not returned by fnRowCallback" );
+							bRowError = true;
+						}
+					}
+					
+					anRows.push( nRow );
+					iRowCount++;
+					
+					/* If there is an open row - and it is attached to this parent - attach it on redraw */
+					if ( iOpenRows !== 0 )
+					{
+						for ( var k=0 ; k<iOpenRows ; k++ )
+						{
+							if ( nRow == oSettings.aoOpenRows[k].nParent )
+							{
+								anRows.push( oSettings.aoOpenRows[k].nTr );
+							}
+						}
+					}
+				}
+			}
+			else
+			{
+				/* Table is empty - create a row with an empty message in it */
+				anRows[ 0 ] = document.createElement( 'tr' );
+				
+				if ( typeof oSettings.asStripClasses[0] != 'undefined' )
+				{
+					anRows[ 0 ].className = oSettings.asStripClasses[0];
+				}
+				
+				var nTd = document.createElement( 'td' );
+				nTd.setAttribute( 'valign', "top" );
+				nTd.colSpan = _fnVisbleColumns( oSettings );
+				nTd.className = oSettings.oClasses.sRowEmpty;
+				if ( typeof oSettings.oLanguage.sEmptyTable != 'undefined' &&
+				     oSettings.fnRecordsTotal() === 0 )
+				{
+					nTd.innerHTML = oSettings.oLanguage.sEmptyTable;
+				}
+				else
+				{
+					nTd.innerHTML = oSettings.oLanguage.sZeroRecords.replace(
+						'_MAX_', oSettings.fnFormatNumber(oSettings.fnRecordsTotal()) );
+				}
+				
+				anRows[ iRowCount ].appendChild( nTd );
+			}
+			
+			/* Callback the header and footer custom funcation if there is one */
+			if ( typeof oSettings.fnHeaderCallback == 'function' )
+			{
+				oSettings.fnHeaderCallback.call( oSettings.oInstance, $('>tr', oSettings.nTHead)[0], 
+					_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),
+					oSettings.aiDisplay );
+			}
+			
+			if ( typeof oSettings.fnFooterCallback == 'function' )
+			{
+				oSettings.fnFooterCallback.call( oSettings.oInstance, $('>tr', oSettings.nTFoot)[0], 
+					_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),
+					oSettings.aiDisplay );
+			}
+			
+			/* 
+			 * Need to remove any old row from the display - note we can't just empty the tbody using
+			 * $().html('') since this will unbind the jQuery event handlers (even although the node 
+			 * still exists!) - equally we can't use innerHTML, since IE throws an exception.
+			 */
+			var
+				nAddFrag = document.createDocumentFragment(),
+				nRemoveFrag = document.createDocumentFragment(),
+				nBodyPar, nTrs;
+			
+			if ( oSettings.nTBody )
+			{
+				nBodyPar = oSettings.nTBody.parentNode;
+				nRemoveFrag.appendChild( oSettings.nTBody );
+				
+				/* When doing infinite scrolling, only remove child rows when sorting, filtering or start
+				 * up. When not infinite scroll, always do it.
+				 */
+				if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
+				 	oSettings.bSorted || oSettings.bFiltered )
+				{
+					nTrs = oSettings.nTBody.childNodes;
+					for ( i=nTrs.length-1 ; i>=0 ; i-- )
+					{
+						nTrs[i].parentNode.removeChild( nTrs[i] );
+					}
+				}
+				
+				/* Put the draw table into the dom */
+				for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
+				{
+					nAddFrag.appendChild( anRows[i] );
+				}
+				
+				oSettings.nTBody.appendChild( nAddFrag );
+				if ( nBodyPar !== null )
+				{
+					nBodyPar.appendChild( oSettings.nTBody );
+				}
+			}
+			
+			/* Call all required callback functions for the end of a draw */
+			for ( i=0, iLen=oSettings.aoDrawCallback.length ; i<iLen ; i++ )
+			{
+				oSettings.aoDrawCallback[i].fn.call( oSettings.oInstance, oSettings );
+			}
+			
+			/* Draw is complete, sorting and filtering must be as well */
+			oSettings.bSorted = false;
+			oSettings.bFiltered = false;
+			oSettings.bDrawing = false;
+				
+			/* On first draw, initilaisation is now complete */
+			if ( typeof oSettings._bInitComplete == "undefined" )
+			{
+				oSettings._bInitComplete = true;
+				
+				if ( typeof oSettings.fnInitComplete == 'function' &&
+					   (oSettings.oFeatures.bServerSide || oSettings.sAjaxSource === null) )
+				{
+					oSettings.fnInitComplete.call( oSettings.oInstance, oSettings );
+				}
+			}
+		}
+		
+		/*
+		 * Function: _fnReDraw
+		 * Purpose:  Redraw the table - taking account of the various features which are enabled
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnReDraw( oSettings )
+		{
+			if ( oSettings.oFeatures.bSort )
+			{
+				/* Sorting will refilter and draw for us */
+				_fnSort( oSettings, oSettings.oPreviousSearch );
+			}
+			else if ( oSettings.oFeatures.bFilter )
+			{
+				/* Filtering will redraw for us */
+				_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
+			}
+			else
+			{
+				_fnCalculateEnd( oSettings );
+				_fnDraw( oSettings );
+			}
+		}
+		
+		/*
+		 * Function: _fnAjaxUpdate
+		 * Purpose:  Update the table using an Ajax call
+		 * Returns:  bool: block the table drawing or not
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnAjaxUpdate( oSettings )
+		{
+			if ( oSettings.bAjaxDataGet )
+			{
+				_fnProcessingDisplay( oSettings, true );
+				var iColumns = oSettings.aoColumns.length;
+				var aoData = [];
+				var i;
+				
+				/* Paging and general */
+				oSettings.iDraw++;
+				aoData.push( { "name": "sEcho",          "value": oSettings.iDraw } );
+				aoData.push( { "name": "iColumns",       "value": iColumns } );
+				aoData.push( { "name": "sColumns",       "value": _fnColumnOrdering(oSettings) } );
+				aoData.push( { "name": "iDisplayStart",  "value": oSettings._iDisplayStart } );
+				aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
+					oSettings._iDisplayLength : -1 } );
+				
+				/* Column names */
+				var aNames = [];
+				for ( i=0 ; i<iColumns ; i++ )
+				{
+					aNames.push( oSettings.aoColumns[i].sName );
+				}
+				aoData.push( { "name": "sNames", "value": aNames.join(',') } );
+				
+				/* Filtering */
+				if ( oSettings.oFeatures.bFilter !== false )
+				{
+					aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
+					aoData.push( { "name": "bRegex",  "value": oSettings.oPreviousSearch.bRegex } );
+					for ( i=0 ; i<iColumns ; i++ )
+					{
+						aoData.push( { "name": "sSearch_"+i,     "value": oSettings.aoPreSearchCols[i].sSearch } );
+						aoData.push( { "name": "bRegex_"+i,      "value": oSettings.aoPreSearchCols[i].bRegex } );
+						aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
+					}
+				}
+				
+				/* Sorting */
+				if ( oSettings.oFeatures.bSort !== false )
+				{
+					var iFixed = oSettings.aaSortingFixed !== null ? oSettings.aaSortingFixed.length : 0;
+					var iUser = oSettings.aaSorting.length;
+					aoData.push( { "name": "iSortingCols",   "value": iFixed+iUser } );
+					for ( i=0 ; i<iFixed ; i++ )
+					{
+						aoData.push( { "name": "iSortCol_"+i,  "value": oSettings.aaSortingFixed[i][0] } );
+						aoData.push( { "name": "sSortDir_"+i,  "value": oSettings.aaSortingFixed[i][1] } );
+					}
+					
+					for ( i=0 ; i<iUser ; i++ )
+					{
+						aoData.push( { "name": "iSortCol_"+(i+iFixed),  "value": oSettings.aaSorting[i][0] } );
+						aoData.push( { "name": "sSortDir_"+(i+iFixed),  "value": oSettings.aaSorting[i][1] } );
+					}
+					
+					for ( i=0 ; i<iColumns ; i++ )
+					{
+						aoData.push( { "name": "bSortable_"+i,  "value": oSettings.aoColumns[i].bSortable } );
+					}
+				}
+				
+				oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,
+					function(json) {
+						_fnAjaxUpdateDraw( oSettings, json );
+					} );
+				return false;
+			}
+			else
+			{
+				return true;
+			}
+		}
+		
+		/*
+		 * Function: _fnAjaxUpdateDraw
+		 * Purpose:  Data the data from the server (nuking the old) and redraw the table
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           object:json - json data return from the server.
+		 *             The following must be defined:
+		 *               iTotalRecords, iTotalDisplayRecords, aaData
+		 *             The following may be defined:
+		 *               sColumns
+		 */
+		function _fnAjaxUpdateDraw ( oSettings, json )
+		{
+			if ( typeof json.sEcho != 'undefined' )
+			{
+				/* Protect against old returns over-writing a new one. Possible when you get
+				 * very fast interaction, and later queires are completed much faster
+				 */
+				if ( json.sEcho*1 < oSettings.iDraw )
+				{
+					return;
+				}
+				else
+				{
+					oSettings.iDraw = json.sEcho * 1;
+				}
+			}
+			
+			if ( !oSettings.oScroll.bInfinite ||
+				   (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
+			{
+				_fnClearTable( oSettings );
+			}
+			oSettings._iRecordsTotal = json.iTotalRecords;
+			oSettings._iRecordsDisplay = json.iTotalDisplayRecords;
+			
+			/* Determine if reordering is required */
+			var sOrdering = _fnColumnOrdering(oSettings);
+			var bReOrder = (typeof json.sColumns != 'undefined' && sOrdering !== "" && json.sColumns != sOrdering );
+			if ( bReOrder )
+			{
+				var aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
+			}
+			
+			for ( var i=0, iLen=json.aaData.length ; i<iLen ; i++ )
+			{
+				if ( bReOrder )
+				{
+					/* If we need to re-order, then create a new array with the correct order and add it */
+					var aData = [];
+					for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
+					{
+						aData.push( json.aaData[i][ aiIndex[j] ] );
+					}
+					_fnAddData( oSettings, aData );
+				}
+				else
+				{
+					/* No re-order required, sever got it "right" - just straight add */
+					_fnAddData( oSettings, json.aaData[i] );
+				}
+			}
+			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+			
+			oSettings.bAjaxDataGet = false;
+			_fnDraw( oSettings );
+			oSettings.bAjaxDataGet = true;
+			_fnProcessingDisplay( oSettings, false );
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Options (features) HTML
+		 */
+		
+		/*
+		 * Function: _fnAddOptionsHtml
+		 * Purpose:  Add the options to the page HTML for the table
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnAddOptionsHtml ( oSettings )
+		{
+			/*
+			 * Create a temporary, empty, div which we can later on replace with what we have generated
+			 * we do it this way to rendering the 'options' html offline - speed :-)
+			 */
+			var nHolding = document.createElement( 'div' );
+			oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
+			
+			/* 
+			 * All DataTables are wrapped in a div - this is not currently optional - backwards 
+			 * compatability. It can be removed if you don't want it.
+			 */
+			oSettings.nTableWrapper = document.createElement( 'div' );
+			oSettings.nTableWrapper.className = oSettings.oClasses.sWrapper;
+			if ( oSettings.sTableId !== '' )
+			{
+				oSettings.nTableWrapper.setAttribute( 'id', oSettings.sTableId+'_wrapper' );
+			}
+			
+			/* Track where we want to insert the option */
+			var nInsertNode = oSettings.nTableWrapper;
+			
+			/* Loop over the user set positioning and place the elements as needed */
+			var aDom = oSettings.sDom.split('');
+			var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
+			for ( var i=0 ; i<aDom.length ; i++ )
+			{
+				iPushFeature = 0;
+				cOption = aDom[i];
+				
+				if ( cOption == '<' )
+				{
+					/* New container div */
+					nNewNode = document.createElement( 'div' );
+					
+					/* Check to see if we should append an id and/or a class name to the container */
+					cNext = aDom[i+1];
+					if ( cNext == "'" || cNext == '"' )
+					{
+						sAttr = "";
+						j = 2;
+						while ( aDom[i+j] != cNext )
+						{
+							sAttr += aDom[i+j];
+							j++;
+						}
+						
+						/* Replace jQuery UI constants */
+						if ( sAttr == "H" )
+						{
+							sAttr = "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix";
+						}
+						else if ( sAttr == "F" )
+						{
+							sAttr = "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix";
+						}
+						
+						/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
+						 * breaks the string into parts and applies them as needed
+						 */
+						if ( sAttr.indexOf('.') != -1 )
+						{
+							var aSplit = sAttr.split('.');
+							nNewNode.setAttribute('id', aSplit[0].substr(1, aSplit[0].length-1) );
+							nNewNode.className = aSplit[1];
+						}
+						else if ( sAttr.charAt(0) == "#" )
+						{
+							nNewNode.setAttribute('id', sAttr.substr(1, sAttr.length-1) );
+						}
+						else
+						{
+							nNewNode.className = sAttr;
+						}
+						
+						i += j; /* Move along the position array */
+					}
+					
+					nInsertNode.appendChild( nNewNode );
+					nInsertNode = nNewNode;
+				}
+				else if ( cOption == '>' )
+				{
+					/* End container div */
+					nInsertNode = nInsertNode.parentNode;
+				}
+				else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
+				{
+					/* Length */
+					nTmp = _fnFeatureHtmlLength( oSettings );
+					iPushFeature = 1;
+				}
+				else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
+				{
+					/* Filter */
+					nTmp = _fnFeatureHtmlFilter( oSettings );
+					iPushFeature = 1;
+				}
+				else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
+				{
+					/* pRocessing */
+					nTmp = _fnFeatureHtmlProcessing( oSettings );
+					iPushFeature = 1;
+				}
+				else if ( cOption == 't' )
+				{
+					/* Table */
+					nTmp = _fnFeatureHtmlTable( oSettings );
+					iPushFeature = 1;
+				}
+				else if ( cOption ==  'i' && oSettings.oFeatures.bInfo )
+				{
+					/* Info */
+					nTmp = _fnFeatureHtmlInfo( oSettings );
+					iPushFeature = 1;
+				}
+				else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
+				{
+					/* Pagination */
+					nTmp = _fnFeatureHtmlPaginate( oSettings );
+					iPushFeature = 1;
+				}
+				else if ( _oExt.aoFeatures.length !== 0 )
+				{
+					/* Plug-in features */
+					var aoFeatures = _oExt.aoFeatures;
+					for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
+					{
+						if ( cOption == aoFeatures[k].cFeature )
+						{
+							nTmp = aoFeatures[k].fnInit( oSettings );
+							if ( nTmp )
+							{
+								iPushFeature = 1;
+							}
+							break;
+						}
+					}
+				}
+				
+				/* Add to the 2D features array */
+				if ( iPushFeature == 1 && nTmp !== null )
+				{
+					if ( typeof oSettings.aanFeatures[cOption] != 'object' )
+					{
+						oSettings.aanFeatures[cOption] = [];
+					}
+					oSettings.aanFeatures[cOption].push( nTmp );
+					nInsertNode.appendChild( nTmp );
+				}
+			}
+			
+			/* Built our DOM structure - replace the holding div with what we want */
+			nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Feature: Filtering
+		 */
+		
+		/*
+		 * Function: _fnFeatureHtmlTable
+		 * Purpose:  Add any control elements for the table - specifically scrolling
+		 * Returns:  node: - Node to add to the DOM
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnFeatureHtmlTable ( oSettings )
+		{
+			/* Chack if scrolling is enabled or not - if not then leave the DOM unaltered */
+			if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
+			{
+				return oSettings.nTable;
+			}
+			
+			/*
+			 * The HTML structure that we want to generate in this function is:
+			 *  div - nScroller
+			 *    div - nScrollHead
+			 *      div - nScrollHeadInner
+			 *        table - nScrollHeadTable
+			 *          thead - nThead
+			 *    div - nScrollBody
+			 *      table - oSettings.nTable
+			 *        thead - nTheadSize
+			 *        tbody - nTbody
+			 *    div - nScrollFoot
+			 *      div - nScrollFootInner
+			 *        table - nScrollFootTable
+			 *          tfoot - nTfoot
+			 */
+			var
+			 	nScroller = document.createElement('div'),
+			 	nScrollHead = document.createElement('div'),
+			 	nScrollHeadInner = document.createElement('div'),
+			 	nScrollBody = document.createElement('div'),
+			 	nScrollFoot = document.createElement('div'),
+			 	nScrollFootInner = document.createElement('div'),
+			 	nScrollHeadTable = oSettings.nTable.cloneNode(false),
+			 	nScrollFootTable = oSettings.nTable.cloneNode(false),
+				nThead = oSettings.nTable.getElementsByTagName('thead')[0],
+			 	nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null : 
+					oSettings.nTable.getElementsByTagName('tfoot')[0],
+				oClasses = (typeof oInit.bJQueryUI != 'undefined' && oInit.bJQueryUI) ?
+			 		_oExt.oJUIClasses : _oExt.oStdClasses;
+			
+			nScrollHead.appendChild( nScrollHeadInner );
+			nScrollFoot.appendChild( nScrollFootInner );
+			nScrollBody.appendChild( oSettings.nTable );
+			nScroller.appendChild( nScrollHead );
+			nScroller.appendChild( nScrollBody );
+			nScrollHeadInner.appendChild( nScrollHeadTable );
+			nScrollHeadTable.appendChild( nThead );
+			if ( nTfoot !== null )
+			{
+				nScroller.appendChild( nScrollFoot );
+				nScrollFootInner.appendChild( nScrollFootTable );
+				nScrollFootTable.appendChild( nTfoot );
+			}
+			
+			nScroller.className = oClasses.sScrollWrapper;
+			nScrollHead.className = oClasses.sScrollHead;
+			nScrollHeadInner.className = oClasses.sScrollHeadInner;
+			nScrollBody.className = oClasses.sScrollBody;
+			nScrollFoot.className = oClasses.sScrollFoot;
+			nScrollFootInner.className = oClasses.sScrollFootInner;
+			
+			nScrollHead.style.overflow = "hidden";
+			nScrollHead.style.position = "relative";
+			nScrollFoot.style.overflow = "hidden";
+			nScrollBody.style.overflow = "auto";
+			nScrollHead.style.border = "0";
+			nScrollFoot.style.border = "0";
+			nScrollHeadInner.style.width = "150%"; /* will be overwritten */
+			
+			/* Modify attributes to respect the clones */
+			nScrollHeadTable.removeAttribute('id');
+			nScrollHeadTable.style.marginLeft = "0";
+			oSettings.nTable.style.marginLeft = "0";
+			if ( nTfoot !== null )
+			{
+				nScrollFootTable.removeAttribute('id');
+				nScrollFootTable.style.marginLeft = "0";
+			}
+			
+			/* Move any caption elements from the body to the header */
+			var nCaptions = $('>caption', oSettings.nTable);
+			for ( var i=0, iLen=nCaptions.length ; i<iLen ; i++ )
+			{
+				nScrollHeadTable.appendChild( nCaptions[i] );
+			}
+			
+			/*
+			 * Sizing
+			 */
+			/* When xscrolling add the width and a scroller to move the header with the body */
+			if ( oSettings.oScroll.sX !== "" )
+			{
+				nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
+				nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
+				
+				if ( nTfoot !== null )
+				{
+					nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );	
+				}
+				
+				/* When the body is scrolled, then we also want to scroll the headers */
+				$(nScrollBody).scroll( function (e) {
+					nScrollHead.scrollLeft = this.scrollLeft;
+					
+					if ( nTfoot !== null )
+					{
+						nScrollFoot.scrollLeft = this.scrollLeft;
+					}
+				} );
+			}
+			
+			/* When yscrolling, add the height */
+			if ( oSettings.oScroll.sY !== "" )
+			{
+				nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
+			}
+			
+			/* Redraw - align columns across the tables */
+			oSettings.aoDrawCallback.push( {
+				"fn": _fnScrollDraw,
+				"sName": "scrolling"
+			} );
+			
+			/* Infinite scrolling event handlers */
+			if ( oSettings.oScroll.bInfinite )
+			{
+				$(nScrollBody).scroll( function() {
+					/* Use a blocker to stop scrolling from loading more data while other data is still loading */
+					if ( !oSettings.bDrawing )
+					{
+						/* Check if we should load the next data set */
+						if ( $(this).scrollTop() + $(this).height() > 
+							$(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
+						{
+							/* Only do the redraw if we have to - we might be at the end of the data */
+							if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
+							{
+								_fnPageChange( oSettings, 'next' );
+								_fnCalculateEnd( oSettings );
+								_fnDraw( oSettings );
+							}
+						}
+					}
+				} );
+			}
+			
+			oSettings.nScrollHead = nScrollHead;
+			oSettings.nScrollFoot = nScrollFoot;
+			
+			return nScroller;
+		}
+		
+		/*
+		 * Function: _fnScrollDraw
+		 * Purpose:  Update the various tables for resizing
+		 * Returns:  node: - Node to add to the DOM
+		 * Inputs:   object:o - dataTables settings object
+		 * Notes:    It's a bit of a pig this function, but basically the idea to:
+		 *   1. Re-create the table inside the scrolling div
+		 *   2. Take live measurements from the DOM
+		 *   3. Apply the measurements
+		 *   4. Clean up
+		 */
+		function _fnScrollDraw ( o )
+		{
+			var
+				nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
+				nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
+				nScrollBody = o.nTable.parentNode,
+				i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
+				iWidth, aApplied=[], iSanityWidth;
+			
+			/*
+			 * 1. Re-create the table inside the scrolling div
+			 */
+			
+			/* Remove the old minimised thead and tfoot elements in the inner table */
+			var nTheadSize = o.nTable.getElementsByTagName('thead');
+			if ( nTheadSize.length > 0 )
+			{
+				o.nTable.removeChild( nTheadSize[0] );
+			}
+			
+			if ( o.nTFoot !== null )
+			{
+				/* Remove the old minimised footer element in the cloned header */
+				var nTfootSize = o.nTable.getElementsByTagName('tfoot');
+				if ( nTfootSize.length > 0 )
+				{
+					o.nTable.removeChild( nTfootSize[0] );
+				}
+			}
+			
+			/* Clone the current header and footer elements and then place it into the inner table */
+			nTheadSize = o.nTHead.cloneNode(true);
+			o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
+			
+			if ( o.nTFoot !== null )
+			{
+				nTfootSize = o.nTFoot.cloneNode(true);
+				o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
+			}
+			
+			/*
+			 * 2. Take live measurements from the DOM - do not alter the DOM itself!
+			 */
+			
+			/* Remove old sizing and apply the calculated column widths
+			 * Get the unique column headers in the newly created (cloned) header. We want to apply the
+			 * calclated sizes to this header
+			 */
+			var nThs = _fnGetUniqueThs( nTheadSize );
+			for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
+			{
+				iVis = _fnVisibleToColumnIndex( o, i );
+				nThs[i].style.width = o.aoColumns[iVis].sWidth;
+			}
+			
+			if ( o.nTFoot !== null )
+			{
+				_fnApplyToChildren( function(n) {
+					n.style.width = "";
+				}, nTfootSize.getElementsByTagName('tr') );
+			}
+			
+			/* Size the table as a whole */
+			iSanityWidth = $(o.nTable).outerWidth();
+			if ( o.oScroll.sX === "" )
+			{
+				/* No x scrolling */
+				o.nTable.style.width = "100%";
+				
+				/* I know this is rubbish - but IE7 will make the width of the table when 100% include
+				 * the scrollbar - which is shouldn't. This needs feature detection in future - to do
+				 */
+				if ( $.browser.msie && $.browser.version <= 7 )
+				{
+					o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth()-o.oScroll.iBarWidth );
+				}
+			}
+			else
+			{
+				if ( o.oScroll.sXInner !== "" )
+				{
+					/* x scroll inner has been given - use it */
+					o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
+				}
+				else if ( iSanityWidth == $(nScrollBody).width() &&
+				   $(nScrollBody).height() < $(o.nTable).height() )
+				{
+					/* There is y-scrolling - try to take account of the y scroll bar */
+					o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
+					if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
+					{
+						/* Not possible to take account of it */
+						o.nTable.style.width = _fnStringToCss( iSanityWidth );
+					}
+				}
+				else
+				{
+					/* All else fails */
+					o.nTable.style.width = _fnStringToCss( iSanityWidth );
+				}
+			}
+			
+			/* Recalculate the sanity width - now that we've applied the required width, before it was
+			 * a temporary variable. This is required because the column width calculation is done
+			 * before this table DOM is created.
+			 */
+			iSanityWidth = $(o.nTable).outerWidth();
+			
+			/* We want the hidden header to have zero height, so remove padding and borders. Then
+			 * set the width based on the real headers
+			 */
+			anHeadToSize = o.nTHead.getElementsByTagName('tr');
+			anHeadSizers = nTheadSize.getElementsByTagName('tr');
+			
+			_fnApplyToChildren( function(nSizer, nToSize) {
+				oStyle = nSizer.style;
+				oStyle.paddingTop = "0";
+				oStyle.paddingBottom = "0";
+				oStyle.borderTopWidth = "0";
+				oStyle.borderBottomWidth = "0";
+				oStyle.height = 0;
+				
+				iWidth = $(nSizer).width();
+				nToSize.style.width = _fnStringToCss( iWidth );
+				aApplied.push( iWidth );
+			}, anHeadSizers, anHeadToSize );
+			$(anHeadSizers).height(0);
+			
+			if ( o.nTFoot !== null )
+			{
+				/* Clone the current footer and then place it into the body table as a "hidden header" */
+				anFootSizers = nTfootSize.getElementsByTagName('tr');
+				anFootToSize = o.nTFoot.getElementsByTagName('tr');
+				
+				_fnApplyToChildren( function(nSizer, nToSize) {
+					oStyle = nSizer.style;
+					oStyle.paddingTop = "0";
+					oStyle.paddingBottom = "0";
+					oStyle.borderTopWidth = "0";
+					oStyle.borderBottomWidth = "0";
+					
+					iWidth = $(nSizer).width();
+					nToSize.style.width = _fnStringToCss( iWidth );
+					aApplied.push( iWidth );
+				}, anFootSizers, anFootToSize );
+				$(anFootSizers).height(0);
+			}
+			
+			/*
+			 * 3. Apply the measurements
+			 */
+			
+			/* "Hide" the header and footer that we used for the sizing. We want to also fix their width
+			 * to what they currently are
+			 */
+			_fnApplyToChildren( function(nSizer) {
+				nSizer.innerHTML = "";
+				nSizer.style.width = _fnStringToCss( aApplied.shift() );
+			}, anHeadSizers );
+			
+			if ( o.nTFoot !== null )
+			{
+				_fnApplyToChildren( function(nSizer) {
+					nSizer.innerHTML = "";
+					nSizer.style.width = _fnStringToCss( aApplied.shift() );
+				}, anFootSizers );
+			}
+			
+			/* Sanity check that the table is of a sensible width. If not then we are going to get
+			 * misalignment
+			 */
+			if ( $(o.nTable).outerWidth() < iSanityWidth )
+			{
+				if ( o.oScroll.sX === "" )
+				{
+					_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+						" misalignment. It is suggested that you enable x-scrolling or increase the width"+
+						" the table has in which to be drawn" );
+				}
+				else if ( o.oScroll.sXInner !== "" )
+				{
+					_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+						" misalignment. It is suggested that you increase the sScrollXInner property to"+
+						" allow it to draw in a larger area, or simply remove that parameter to allow"+
+						" automatic calculation" );
+				}
+			}
+			
+			
+			/*
+			 * 4. Clean up
+			 */
+			
+			if ( o.oScroll.sY === "" )
+			{
+				/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
+				 * the scrollbar height from the visible display, rather than adding it on. We need to
+				 * set the height in order to sort this. Don't want to do it in any other browsers.
+				 */
+				if ( $.browser.msie && $.browser.version <= 7 )
+				{
+					nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
+				}
+			}
+			
+			if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
+			{
+				nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
+				
+				var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
+				 	o.oScroll.iBarWidth : 0;
+				if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
+				{
+					nScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra );
+				}
+			}
+			
+			/* Finally set the width's of the header and footer tables */
+			var iOuterWidth = $(o.nTable).outerWidth();
+			nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
+			nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth+o.oScroll.iBarWidth );
+			nScrollHeadInner.parentNode.style.width = _fnStringToCss( $(nScrollBody).width() );
+			
+			if ( o.nTFoot !== null )
+			{
+				var
+					nScrollFootInner = o.nScrollFoot.getElementsByTagName('div')[0],
+					nScrollFootTable = nScrollFootInner.getElementsByTagName('table')[0];
+				
+				nScrollFootInner.style.width = _fnStringToCss( o.nTable.offsetWidth+o.oScroll.iBarWidth );
+				nScrollFootTable.style.width = _fnStringToCss( o.nTable.offsetWidth );
+			}
+			
+			/* If sorting or filtering has occured, jump the scrolling back to the top */
+			if ( o.bSorted || o.bFiltered )
+			{
+				nScrollBody.scrollTop = 0;
+			}
+		}
+		
+		/*
+		 * Function: _fnAjustColumnSizing
+		 * Purpose:  Ajust the table column widths for new data
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 * Notes:    You would probably want to do a redraw after calling this function!
+		 */
+		function _fnAjustColumnSizing ( oSettings )
+		{
+			/* Not interested in doing column width calculation if autowidth is disabled */
+			if ( oSettings.oFeatures.bAutoWidth === false )
+			{
+				return false;
+			}
+			
+			_fnCalculateColumnWidths( oSettings );
+			for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+			{
+				oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
+			}
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Feature: Filtering
+		 */
+		
+		/*
+		 * Function: _fnFeatureHtmlFilter
+		 * Purpose:  Generate the node required for filtering text
+		 * Returns:  node
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnFeatureHtmlFilter ( oSettings )
+		{
+			var nFilter = document.createElement( 'div' );
+			if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.f == "undefined" )
+			{
+				nFilter.setAttribute( 'id', oSettings.sTableId+'_filter' );
+			}
+			nFilter.className = oSettings.oClasses.sFilter;
+			var sSpace = oSettings.oLanguage.sSearch==="" ? "" : " ";
+			nFilter.innerHTML = oSettings.oLanguage.sSearch+sSpace+'<input type="text" />';
+			
+			var jqFilter = $("input", nFilter);
+			jqFilter.val( oSettings.oPreviousSearch.sSearch.replace('"','&quot;') );
+			jqFilter.keyup( function(e) {
+				/* Update all other filter input elements for the new display */
+				var n = oSettings.aanFeatures.f;
+				for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+				{
+					if ( n[i] != this.parentNode )
+					{
+						$('input', n[i]).val( this.value );
+					}
+				}
+				
+				/* Now do the filter */
+				if ( this.value != oSettings.oPreviousSearch.sSearch )
+				{
+					_fnFilterComplete( oSettings, { 
+						"sSearch": this.value, 
+						"bRegex":  oSettings.oPreviousSearch.bRegex,
+						"bSmart":  oSettings.oPreviousSearch.bSmart 
+					} );
+				}
+			} );
+			
+			jqFilter.keypress( function(e) {
+				/* Prevent default */
+				if ( e.keyCode == 13 )
+				{
+					return false;
+				}
+			} );
+			
+			return nFilter;
+		}
+		
+		/*
+		 * Function: _fnFilterComplete
+		 * Purpose:  Filter the table using both the global filter and column based filtering
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           object:oSearch: search information
+		 *           int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
+		 */
+		function _fnFilterComplete ( oSettings, oInput, iForce )
+		{
+			/* Filter on everything */
+			_fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart );
+			
+			/* Now do the individual column filter */
+			for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
+			{
+				_fnFilterColumn( oSettings, oSettings.aoPreSearchCols[i].sSearch, i, 
+					oSettings.aoPreSearchCols[i].bRegex, oSettings.aoPreSearchCols[i].bSmart );
+			}
+			
+			/* Custom filtering */
+			if ( _oExt.afnFiltering.length !== 0 )
+			{
+				_fnFilterCustom( oSettings );
+			}
+			
+			/* Tell the draw function we have been filtering */
+			oSettings.bFiltered = true;
+			
+			/* Redraw the table */
+			oSettings._iDisplayStart = 0;
+			_fnCalculateEnd( oSettings );
+			_fnDraw( oSettings );
+			
+			/* Rebuild search array 'offline' */
+			_fnBuildSearchArray( oSettings, 0 );
+		}
+		
+		/*
+		 * Function: _fnFilterCustom
+		 * Purpose:  Apply custom filtering functions
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnFilterCustom( oSettings )
+		{
+			var afnFilters = _oExt.afnFiltering;
+			for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
+			{
+				var iCorrector = 0;
+				for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
+				{
+					var iDisIndex = oSettings.aiDisplay[j-iCorrector];
+					
+					/* Check if we should use this row based on the filtering function */
+					if ( !afnFilters[i]( oSettings, oSettings.aoData[iDisIndex]._aData, iDisIndex ) )
+					{
+						oSettings.aiDisplay.splice( j-iCorrector, 1 );
+						iCorrector++;
+					}
+				}
+			}
+		}
+		
+		/*
+		 * Function: _fnFilterColumn
+		 * Purpose:  Filter the table on a per-column basis
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           string:sInput - string to filter on
+		 *           int:iColumn - column to filter
+		 *           bool:bRegex - treat search string as a regular expression or not
+		 *           bool:bSmart - use smart filtering or not
+		 */
+		function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart )
+		{
+			if ( sInput === "" )
+			{
+				return;
+			}
+			
+			var iIndexCorrector = 0;
+			var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );
+			
+			for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
+			{
+				var sData = _fnDataToSearch( oSettings.aoData[ oSettings.aiDisplay[i] ]._aData[iColumn],
+					oSettings.aoColumns[iColumn].sType );
+				if ( ! rpSearch.test( sData ) )
+				{
+					oSettings.aiDisplay.splice( i, 1 );
+					iIndexCorrector++;
+				}
+			}
+		}
+		
+		/*
+		 * Function: _fnFilter
+		 * Purpose:  Filter the data table based on user input and draw the table
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           string:sInput - string to filter on
+		 *           int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
+		 *           bool:bRegex - treat as a regular expression or not
+		 *           bool:bSmart - perform smart filtering or not
+		 */
+		function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart )
+		{
+			var i;
+			var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );
+			
+			/* Check if we are forcing or not - optional parameter */
+			if ( typeof iForce == 'undefined' || iForce === null )
+			{
+				iForce = 0;
+			}
+			
+			/* Need to take account of custom filtering functions - always filter */
+			if ( _oExt.afnFiltering.length !== 0 )
+			{
+				iForce = 1;
+			}
+			
+			/*
+			 * If the input is blank - we want the full data set
+			 */
+			if ( sInput.length <= 0 )
+			{
+				oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+			}
+			else
+			{
+				/*
+				 * We are starting a new search or the new search string is smaller 
+				 * then the old one (i.e. delete). Search from the master array
+			 	 */
+				if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
+					   oSettings.oPreviousSearch.sSearch.length > sInput.length || iForce == 1 ||
+					   sInput.indexOf(oSettings.oPreviousSearch.sSearch) !== 0 )
+				{
+					/* Nuke the old display array - we are going to rebuild it */
+					oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+					
+					/* Force a rebuild of the search array */
+					_fnBuildSearchArray( oSettings, 1 );
+					
+					/* Search through all records to populate the search array
+					 * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 
+					 * mapping
+					 */
+					for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
+					{
+						if ( rpSearch.test(oSettings.asDataSearch[i]) )
+						{
+							oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
+						}
+					}
+			  }
+			  else
+				{
+			  	/* Using old search array - refine it - do it this way for speed
+			  	 * Don't have to search the whole master array again
+			 		 */
+			  	var iIndexCorrector = 0;
+			  	
+			  	/* Search the current results */
+			  	for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
+					{
+			  		if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
+						{
+			  			oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
+			  			iIndexCorrector++;
+			  		}
+			  	}
+			  }
+			}
+			oSettings.oPreviousSearch.sSearch = sInput;
+			oSettings.oPreviousSearch.bRegex = bRegex;
+			oSettings.oPreviousSearch.bSmart = bSmart;
+		}
+		
+		/*
+		 * Function: _fnBuildSearchArray
+		 * Purpose:  Create an array which can be quickly search through
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           int:iMaster - use the master data array - optional
+		 */
+		function _fnBuildSearchArray ( oSettings, iMaster )
+		{
+			/* Clear out the old data */
+			oSettings.asDataSearch.splice( 0, oSettings.asDataSearch.length );
+			
+			var aArray = (typeof iMaster != 'undefined' && iMaster == 1) ?
+			 	oSettings.aiDisplayMaster : oSettings.aiDisplay;
+			
+			for ( var i=0, iLen=aArray.length ; i<iLen ; i++ )
+			{
+				oSettings.asDataSearch[i] = _fnBuildSearchRow( oSettings, 
+					oSettings.aoData[ aArray[i] ]._aData );
+			}
+		}
+		
+		/*
+		 * Function: _fnBuildSearchRow
+		 * Purpose:  Create a searchable string from a single data row
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           array:aData - aoData[]._aData array to use for the data to search
+		 */
+		function _fnBuildSearchRow( oSettings, aData )
+		{
+			var sSearch = '';
+			var nTmp = document.createElement('div');
+			
+			for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
+			{
+				if ( oSettings.aoColumns[j].bSearchable )
+				{
+					var sData = aData[j];
+					sSearch += _fnDataToSearch( sData, oSettings.aoColumns[j].sType )+'  ';
+				}
+			}
+			
+			/* If it looks like there is an HTML entity in the string, attempt to decode it */
+			if ( sSearch.indexOf('&') !== -1 )
+			{
+				nTmp.innerHTML = sSearch;
+				sSearch = nTmp.textContent ? nTmp.textContent : nTmp.innerText;
+				
+				/* IE and Opera appear to put an newline where there is a <br> tag - remove it */
+				sSearch = sSearch.replace(/\n/g," ").replace(/\r/g,"");
+			}
+			
+			return sSearch;
+		}
+		
+		/*
+		 * Function: _fnFilterCreateSearch
+		 * Purpose:  Build a regular expression object suitable for searching a table
+		 * Returns:  RegExp: - constructed object
+		 * Inputs:   string:sSearch - string to search for
+		 *           bool:bRegex - treat as a regular expression or not
+		 *           bool:bSmart - perform smart filtering or not
+		 */
+		function _fnFilterCreateSearch( sSearch, bRegex, bSmart )
+		{
+			var asSearch, sRegExpString;
+			
+			if ( bSmart )
+			{
+				/* Generate the regular expression to use. Something along the lines of:
+				 * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
+				 */
+				asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
+				sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
+				return new RegExp( sRegExpString, "i" );
+			}
+			else
+			{
+				sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
+				return new RegExp( sSearch, "i" );
+			}
+		}
+		
+		/*
+		 * Function: _fnDataToSearch
+		 * Purpose:  Convert raw data into something that the user can search on
+		 * Returns:  string: - search string
+		 * Inputs:   string:sData - data to be modified
+		 *           string:sType - data type
+		 */
+		function _fnDataToSearch ( sData, sType )
+		{
+			if ( typeof _oExt.ofnSearch[sType] == "function" )
+			{
+				return _oExt.ofnSearch[sType]( sData );
+			}
+			else if ( sType == "html" )
+			{
+				return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
+			}
+			else if ( typeof sData == "string" )
+			{
+				return sData.replace(/\n/g," ");
+			}
+			return sData;
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Feature: Sorting
+		 */
+		
+		/*
+	 	 * Function: _fnSort
+		 * Purpose:  Change the order of the table
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           bool:bApplyClasses - optional - should we apply classes or not
+		 * Notes:    We always sort the master array and then apply a filter again
+		 *   if it is needed. This probably isn't optimal - but atm I can't think
+		 *   of any other way which is (each has disadvantages). we want to sort aiDisplayMaster - 
+		 *   but according to aoData[]._aData
+		 */
+		function _fnSort ( oSettings, bApplyClasses )
+		{
+			var aaSort = [];
+			var oSort = _oExt.oSort;
+			var aoData = oSettings.aoData;
+			var iDataSort;
+			var iDataType;
+			var i, j, jLen;
+			
+			/* No sorting required if server-side or no sorting array */
+			if ( !oSettings.oFeatures.bServerSide && 
+				(oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
+			{
+				if ( oSettings.aaSortingFixed !== null )
+				{
+					aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
+				}
+				else
+				{
+					aaSort = oSettings.aaSorting.slice();
+				}
+				
+				/* If there is a sorting data type, and a fuction belonging to it, then we need to
+				 * get the data from the developer's function and apply it for this column
+				 */
+				for ( i=0 ; i<aaSort.length ; i++ )
+				{
+					var iColumn = aaSort[i][0];
+					var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
+					var sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
+					if ( typeof _oExt.afnSortData[sDataType] != 'undefined' )
+					{
+						var aData = _oExt.afnSortData[sDataType]( oSettings, iColumn, iVisColumn );
+						for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
+						{
+							aoData[j]._aData[iColumn] = aData[j];
+						}
+					}
+				}
+				
+				/* DataTables offers two different methods for doing the 2D array sorting over multiple
+				 * columns. The first is to construct a function dynamically, and then evaluate and run
+				 * the function, while the second has no need for evalulation, but is a little bit slower.
+				 * This is used for environments which do not allow eval() for code execuation such as AIR
+				 */
+				if ( !window.runtime )
+				{
+					/* Dynamically created sorting function. Based on the information that we have, we can
+					 * create a sorting function as if it were specifically written for this sort. Here we
+					 * want to build a function something like (for two column sorting):
+					 *  fnLocalSorting = function(a,b){
+					 *  	var iTest;
+					 *  	iTest = oSort['string-asc']('data11', 'data12');
+					 *  	if (iTest === 0)
+					 *  		iTest = oSort['numeric-desc']('data21', 'data22');
+					 *  		if (iTest === 0)
+					 *  			return oSort['numeric-desc'](1,2);
+					 *  	return iTest;
+					 *  }
+					 * So basically we have a test for each column, and if that column matches, test the
+					 * next one. If all columns match, then we use a numeric sort on the position the two
+					 * row have in the original data array in order to provide a stable sort. In order to
+					 * get the position for the numeric stablisation, we need to take a clone of the current
+					 * display array and then get the position of the sorting value from that during the
+					 * sort.
+					 *
+					 * Note that for use with the Closure compiler, we need to be very careful how we deal 
+					 * with this eval. Closure will rename all of our local variables, resutling in breakage
+					 * if the variables in the eval don't also reflect this. For this reason, we need to use
+					 * 'this' to store the variables we need in the eval, so we can control them. A little
+					 * nasty, but well worth it for using Closure.
+					 */
+					this.ClosureDataTables = {
+						"fn": function(){},
+						"data": aoData,
+						"sort": _oExt.oSort,
+						"master": oSettings.aiDisplayMaster.slice()
+					};
+					var sDynamicSort = "this.ClosureDataTables.fn = function(a,b){"+
+						"var iTest, oSort=this.ClosureDataTables.sort, "+
+						"aoData=this.ClosureDataTables.data, "+
+						"aiOrig=this.ClosureDataTables.master;";
+					
+					for ( i=0 ; i<aaSort.length-1 ; i++ )
+					{
+						iDataSort = oSettings.aoColumns[ aaSort[i][0] ].iDataSort;
+						iDataType = oSettings.aoColumns[ iDataSort ].sType;
+						sDynamicSort += "iTest = oSort['"+iDataType+"-"+aaSort[i][1]+"']"+
+							"( aoData[a]._aData["+iDataSort+"], aoData[b]._aData["+iDataSort+"] ); if ( iTest === 0 )";
+					}
+					
+					if ( aaSort.length > 0 )
+					{
+						iDataSort = oSettings.aoColumns[ aaSort[aaSort.length-1][0] ].iDataSort;
+						iDataType = oSettings.aoColumns[ iDataSort ].sType;
+						sDynamicSort += "iTest = oSort['"+iDataType+"-"+aaSort[aaSort.length-1][1]+"']"+
+							"( aoData[a]._aData["+iDataSort+"], aoData[b]._aData["+iDataSort+"] );"+
+							"if (iTest===0) "+
+								"return oSort['numeric-asc'](jQuery.inArray(a,aiOrig), jQuery.inArray(b,aiOrig)); "+
+							"return iTest;}";
+						
+						/* The eval has to be done to a variable for IE */
+						eval( sDynamicSort );
+						oSettings.aiDisplayMaster.sort( this.ClosureDataTables.fn );
+					}
+					this.ClosureDataTables = undefined;
+				}
+				else
+				{
+					/*
+					 * Non-eval() sorting (AIR and other environments which doesn't allow code in eval()
+					 * Note that for reasonable sized data sets this method is around 1.5 times slower than
+					 * the eval above (hence why it is not used all the time). Oddly enough, it is ever so
+					 * slightly faster for very small sets (presumably the eval has overhead).
+					 *   Single column (1083 records) - eval: 32mS   AIR: 38mS
+					 *   Two columns (1083 records) -   eval: 55mS   AIR: 66mS
+					 */
+					
+					/* Build a cached array so the sort doesn't have to process this stuff on every call */
+					var aAirSort = [];
+					var iLen = aaSort.length;
+					for ( i=0 ; i<iLen ; i++ )
+					{
+						iDataSort = oSettings.aoColumns[ aaSort[i][0] ].iDataSort;
+						aAirSort.push( [
+							iDataSort,
+							oSettings.aoColumns[ iDataSort ].sType+'-'+aaSort[i][1]
+						] );
+					}
+					
+					oSettings.aiDisplayMaster.sort( function (a,b) {
+						var iTest;
+						for ( var i=0 ; i<iLen ; i++ )
+						{
+							iTest = oSort[ aAirSort[i][1] ]( aoData[a]._aData[aAirSort[i][0]], aoData[b]._aData[aAirSort[i][0]] );
+							if ( iTest !== 0 )
+							{
+								return iTest;
+							}
+						}
+						return 0;
+					} );
+				}
+			}
+			
+			/* Alter the sorting classes to take account of the changes */
+			if ( typeof bApplyClasses == 'undefined' || bApplyClasses )
+			{
+				_fnSortingClasses( oSettings );
+			}
+			
+			/* Tell the draw function that we have sorted the data */
+			oSettings.bSorted = true;
+			
+			/* Copy the master data into the draw array and re-draw */
+			if ( oSettings.oFeatures.bFilter )
+			{
+				/* _fnFilter() will redraw the table for us */
+				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+			}
+			else
+			{
+				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+				oSettings._iDisplayStart = 0; /* reset display back to page 0 */
+				_fnCalculateEnd( oSettings );
+				_fnDraw( oSettings );
+			}
+		}
+		
+		/*
+		 * Function: _fnSortAttachListener
+		 * Purpose:  Attach a sort handler (click) to a node
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           node:nNode - node to attach the handler to
+		 *           int:iDataIndex - column sorting index
+		 *           function:fnCallback - callback function - optional
+		 */
+		function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
+		{
+			$(nNode).click( function (e) {
+				/* If the column is not sortable - don't to anything */
+				if ( oSettings.aoColumns[iDataIndex].bSortable === false )
+				{
+					return;
+				}
+				
+				/*
+				 * This is a little bit odd I admit... I declare a temporary function inside the scope of
+				 * _fnDrawHead and the click handler in order that the code presented here can be used 
+				 * twice - once for when bProcessing is enabled, and another time for when it is 
+				 * disabled, as we need to perform slightly different actions.
+				 *   Basically the issue here is that the Javascript engine in modern browsers don't 
+				 * appear to allow the rendering engine to update the display while it is still excuting
+				 * it's thread (well - it does but only after long intervals). This means that the 
+				 * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
+				 * I force an execution break by using setTimeout - but this breaks the expected 
+				 * thread continuation for the end-developer's point of view (their code would execute
+				 * too early), so we on;y do it when we absolutely have to.
+				 */
+				var fnInnerSorting = function () {
+					var iColumn, iNextSort;
+					
+					/* If the shift key is pressed then we are multipe column sorting */
+					if ( e.shiftKey )
+					{
+						/* Are we already doing some kind of sort on this column? */
+						var bFound = false;
+						for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
+						{
+							if ( oSettings.aaSorting[i][0] == iDataIndex )
+							{
+								bFound = true;
+								iColumn = oSettings.aaSorting[i][0];
+								iNextSort = oSettings.aaSorting[i][2]+1;
+								
+								if ( typeof oSettings.aoColumns[iColumn].asSorting[iNextSort] == 'undefined' )
+								{
+									/* Reached the end of the sorting options, remove from multi-col sort */
+									oSettings.aaSorting.splice( i, 1 );
+								}
+								else
+								{
+									/* Move onto next sorting direction */
+									oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
+									oSettings.aaSorting[i][2] = iNextSort;
+								}
+								break;
+							}
+						}
+						
+						/* No sort yet - add it in */
+						if ( bFound === false )
+						{
+							oSettings.aaSorting.push( [ iDataIndex, 
+								oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
+						}
+					}
+					else
+					{
+						/* If no shift key then single column sort */
+						if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
+						{
+							iColumn = oSettings.aaSorting[0][0];
+							iNextSort = oSettings.aaSorting[0][2]+1;
+							if ( typeof oSettings.aoColumns[iColumn].asSorting[iNextSort] == 'undefined' )
+							{
+								iNextSort = 0;
+							}
+							oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
+							oSettings.aaSorting[0][2] = iNextSort;
+						}
+						else
+						{
+							oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
+							oSettings.aaSorting.push( [ iDataIndex, 
+								oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
+						}
+					}
+					
+					/* Run the sort */
+					_fnSort( oSettings );
+				}; /* /fnInnerSorting */
+				
+				if ( !oSettings.oFeatures.bProcessing )
+				{
+					fnInnerSorting();
+				}
+				else
+				{
+					_fnProcessingDisplay( oSettings, true );
+					setTimeout( function() {
+						fnInnerSorting();
+						if ( !oSettings.oFeatures.bServerSide )
+						{
+							_fnProcessingDisplay( oSettings, false );
+						}
+					}, 0 );
+				}
+				
+				/* Call the user specified callback function - used for async user interaction */
+				if ( typeof fnCallback == 'function' )
+				{
+					fnCallback( oSettings );
+				}
+			} );
+		}
+		
+		/*
+		 * Function: _fnSortingClasses
+		 * Purpose:  Set the sortting classes on the header
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 * Notes:    It is safe to call this function when bSort and bSortClasses are false
+		 */
+		function _fnSortingClasses( oSettings )
+		{
+			var i, iLen, j, jLen, iFound;
+			var aaSort, sClass;
+			var iColumns = oSettings.aoColumns.length;
+			var oClasses = oSettings.oClasses;
+			
+			for ( i=0 ; i<iColumns ; i++ )
+			{
+				if ( oSettings.aoColumns[i].bSortable )
+				{
+					$(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
+				 		" "+ oSettings.aoColumns[i].sSortingClass );
+				}
+			}
+			
+			if ( oSettings.aaSortingFixed !== null )
+			{
+				aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
+			}
+			else
+			{
+				aaSort = oSettings.aaSorting.slice();
+			}
+			
+			/* Apply the required classes to the header */
+			for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+			{
+				if ( oSettings.aoColumns[i].bSortable )
+				{
+					sClass = oSettings.aoColumns[i].sSortingClass;
+					iFound = -1;
+					for ( j=0 ; j<aaSort.length ; j++ )
+					{
+						if ( aaSort[j][0] == i )
+						{
+							sClass = ( aaSort[j][1] == "asc" ) ?
+								oClasses.sSortAsc : oClasses.sSortDesc;
+							iFound = j;
+							break;
+						}
+					}
+					$(oSettings.aoColumns[i].nTh).addClass( sClass );
+					
+					if ( oSettings.bJUI )
+					{
+						/* jQuery UI uses extra markup */
+						var jqSpan = $("span", oSettings.aoColumns[i].nTh);
+						jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+ 
+							oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
+						
+						var sSpanClass;
+						if ( iFound == -1 )
+						{
+						 	sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
+						}
+						else if ( aaSort[iFound][1] == "asc" )
+						{
+							sSpanClass = oClasses.sSortJUIAsc;
+						}
+						else
+						{
+							sSpanClass = oClasses.sSortJUIDesc;
+						}
+						
+						jqSpan.addClass( sSpanClass );
+					}
+				}
+				else
+				{
+					/* No sorting on this column, so add the base class. This will have been assigned by
+					 * _fnAddColumn
+					 */
+					$(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
+				}
+			}
+			
+			/* 
+			 * Apply the required classes to the table body
+			 * Note that this is given as a feature switch since it can significantly slow down a sort
+			 * on large data sets (adding and removing of classes is always slow at the best of times..)
+			 * Further to this, note that this code is admitadly fairly ugly. It could be made a lot 
+			 * simpiler using jQuery selectors and add/removeClass, but that is significantly slower
+			 * (on the order of 5 times slower) - hence the direct DOM manipulation here.
+			 */
+			sClass = oClasses.sSortColumn;
+			
+			if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
+			{
+				var nTds = _fnGetTdNodes( oSettings );
+				
+				/* Remove the old classes */
+				if ( nTds.length >= iColumns )
+				{
+					for ( i=0 ; i<iColumns ; i++ )
+					{
+						if ( nTds[i].className.indexOf(sClass+"1") != -1 )
+						{
+							for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
+							{
+								nTds[(iColumns*j)+i].className = 
+									$.trim( nTds[(iColumns*j)+i].className.replace( sClass+"1", "" ) );
+							}
+						}
+						else if ( nTds[i].className.indexOf(sClass+"2") != -1 )
+						{
+							for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
+							{
+								nTds[(iColumns*j)+i].className = 
+									$.trim( nTds[(iColumns*j)+i].className.replace( sClass+"2", "" ) );
+							}
+						}
+						else if ( nTds[i].className.indexOf(sClass+"3") != -1 )
+						{
+							for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
+							{
+								nTds[(iColumns*j)+i].className = 
+									$.trim( nTds[(iColumns*j)+i].className.replace( " "+sClass+"3", "" ) );
+							}
+						}
+					}
+				}
+				
+				/* Add the new classes to the table */
+				var iClass = 1, iTargetCol;
+				for ( i=0 ; i<aaSort.length ; i++ )
+				{
+					iTargetCol = parseInt( aaSort[i][0], 10 );
+					for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
+					{
+						nTds[(iColumns*j)+iTargetCol].className += " "+sClass+iClass;
+					}
+					
+					if ( iClass < 3 )
+					{
+						iClass++;
+					}
+				}
+			}
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Feature: Pagination. Note that most of the paging logic is done in 
+		 * _oExt.oPagination
+		 */
+		
+		/*
+		 * Function: _fnFeatureHtmlPaginate
+		 * Purpose:  Generate the node required for default pagination
+		 * Returns:  node
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnFeatureHtmlPaginate ( oSettings )
+		{
+			if ( oSettings.oScroll.bInfinite )
+			{
+				return null;
+			}
+			
+			var nPaginate = document.createElement( 'div' );
+			nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
+			
+			_oExt.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, 
+				function( oSettings ) {
+					_fnCalculateEnd( oSettings );
+					_fnDraw( oSettings );
+				}
+			);
+			
+			/* Add a draw callback for the pagination on first instance, to update the paging display */
+			if ( typeof oSettings.aanFeatures.p == "undefined" )
+			{
+				oSettings.aoDrawCallback.push( {
+					"fn": function( oSettings ) {
+						_oExt.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
+							_fnCalculateEnd( oSettings );
+							_fnDraw( oSettings );
+						} );
+					},
+					"sName": "pagination"
+				} );
+			}
+			return nPaginate;
+		}
+		
+		/*
+		 * Function: _fnPageChange
+		 * Purpose:  Alter the display settings to change the page
+		 * Returns:  bool:true - page has changed, false - no change (no effect) eg 'first' on page 1
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           string:sAction - paging action to take: "first", "previous", "next" or "last"
+		 */
+		function _fnPageChange ( oSettings, sAction )
+		{
+			var iOldStart = oSettings._iDisplayStart;
+			
+			if ( sAction == "first" )
+			{
+				oSettings._iDisplayStart = 0;
+			}
+			else if ( sAction == "previous" )
+			{
+				oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
+					oSettings._iDisplayStart - oSettings._iDisplayLength :
+					0;
+				
+				/* Correct for underrun */
+				if ( oSettings._iDisplayStart < 0 )
+				{
+				  oSettings._iDisplayStart = 0;
+				}
+			}
+			else if ( sAction == "next" )
+			{
+				if ( oSettings._iDisplayLength >= 0 )
+				{
+					/* Make sure we are not over running the display array */
+					if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
+					{
+						oSettings._iDisplayStart += oSettings._iDisplayLength;
+					}
+				}
+				else
+				{
+					oSettings._iDisplayStart = 0;
+				}
+			}
+			else if ( sAction == "last" )
+			{
+				if ( oSettings._iDisplayLength >= 0 )
+				{
+					var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
+					oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
+				}
+				else
+				{
+					oSettings._iDisplayStart = 0;
+				}
+			}
+			else
+			{
+				_fnLog( oSettings, 0, "Unknown paging action: "+sAction );
+			}
+			
+			return iOldStart != oSettings._iDisplayStart;
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Feature: HTML info
+		 */
+		
+		/*
+		 * Function: _fnFeatureHtmlInfo
+		 * Purpose:  Generate the node required for the info display
+		 * Returns:  node
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnFeatureHtmlInfo ( oSettings )
+		{
+			var nInfo = document.createElement( 'div' );
+			nInfo.className = oSettings.oClasses.sInfo;
+			
+			/* Actions that are to be taken once only for this feature */
+			if ( typeof oSettings.aanFeatures.i == "undefined" )
+			{
+				/* Add draw callback */
+				oSettings.aoDrawCallback.push( {
+					"fn": _fnUpdateInfo,
+					"sName": "information"
+				} );
+				
+				/* Add id */
+				if ( oSettings.sTableId !== '' )
+				{
+					nInfo.setAttribute( 'id', oSettings.sTableId+'_info' );
+				}
+			}
+			
+			return nInfo;
+		}
+		
+		/*
+		 * Function: _fnUpdateInfo
+		 * Purpose:  Update the information elements in the display
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnUpdateInfo ( oSettings )
+		{
+			/* Show information about the table */
+			if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
+			{
+				return;
+			}
+			
+			var
+				iStart = oSettings._iDisplayStart+1, iEnd = oSettings.fnDisplayEnd(),
+				iMax = oSettings.fnRecordsTotal(), iTotal = oSettings.fnRecordsDisplay(),
+				sStart = oSettings.fnFormatNumber( iStart ), sEnd = oSettings.fnFormatNumber( iEnd ),
+				sMax = oSettings.fnFormatNumber( iMax ), sTotal = oSettings.fnFormatNumber( iTotal ),
+				sOut;
+			
+			/* When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+			 * internally
+			 */
+			if ( oSettings.oScroll.bInfinite )
+			{
+				sStart = oSettings.fnFormatNumber( 1 );
+			}
+			
+			if ( oSettings.fnRecordsDisplay() === 0 && 
+				   oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
+			{
+				/* Empty record set */
+				sOut = oSettings.oLanguage.sInfoEmpty+ oSettings.oLanguage.sInfoPostFix;
+			}
+			else if ( oSettings.fnRecordsDisplay() === 0 )
+			{
+				/* Rmpty record set after filtering */
+				sOut = oSettings.oLanguage.sInfoEmpty +' '+ 
+					oSettings.oLanguage.sInfoFiltered.replace('_MAX_', sMax)+
+						oSettings.oLanguage.sInfoPostFix;
+			}
+			else if ( oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
+			{
+				/* Normal record set */
+				sOut = oSettings.oLanguage.sInfo.
+						replace('_START_', sStart).
+						replace('_END_',   sEnd).
+						replace('_TOTAL_', sTotal)+ 
+					oSettings.oLanguage.sInfoPostFix;
+			}
+			else
+			{
+				/* Record set after filtering */
+				sOut = oSettings.oLanguage.sInfo.
+						replace('_START_', sStart).
+						replace('_END_',   sEnd).
+						replace('_TOTAL_', sTotal) +' '+ 
+					oSettings.oLanguage.sInfoFiltered.replace('_MAX_', 
+						oSettings.fnFormatNumber(oSettings.fnRecordsTotal()))+ 
+					oSettings.oLanguage.sInfoPostFix;
+			}
+			
+			if ( oSettings.oLanguage.fnInfoCallback !== null )
+			{
+				sOut = oSettings.oLanguage.fnInfoCallback( oSettings, iStart, iEnd, iMax, iTotal, sOut );
+			}
+			
+			var n = oSettings.aanFeatures.i;
+			for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+			{
+				$(n[i]).html( sOut );
+			}
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Feature: Length change
+		 */
+		
+		/*
+		 * Function: _fnFeatureHtmlLength
+		 * Purpose:  Generate the node required for user display length changing
+		 * Returns:  node
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnFeatureHtmlLength ( oSettings )
+		{
+			if ( oSettings.oScroll.bInfinite )
+			{
+				return null;
+			}
+			
+			/* This can be overruled by not using the _MENU_ var/macro in the language variable */
+			var sName = (oSettings.sTableId === "") ? "" : 'name="'+oSettings.sTableId+'_length"';
+			var sStdMenu = '<select size="1" '+sName+'>';
+			var i, iLen;
+			
+			if ( oSettings.aLengthMenu.length == 2 && typeof oSettings.aLengthMenu[0] == 'object' && 
+					typeof oSettings.aLengthMenu[1] == 'object' )
+			{
+				for ( i=0, iLen=oSettings.aLengthMenu[0].length ; i<iLen ; i++ )
+				{
+					sStdMenu += '<option value="'+oSettings.aLengthMenu[0][i]+'">'+
+						oSettings.aLengthMenu[1][i]+'</option>';
+				}
+			}
+			else
+			{
+				for ( i=0, iLen=oSettings.aLengthMenu.length ; i<iLen ; i++ )
+				{
+					sStdMenu += '<option value="'+oSettings.aLengthMenu[i]+'">'+
+						oSettings.aLengthMenu[i]+'</option>';
+				}
+			}
+			sStdMenu += '</select>';
+			
+			var nLength = document.createElement( 'div' );
+			if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.l == "undefined" )
+			{
+				nLength.setAttribute( 'id', oSettings.sTableId+'_length' );
+			}
+			nLength.className = oSettings.oClasses.sLength;
+			nLength.innerHTML = oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu );
+			
+			/*
+			 * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
+			 * and Stefan Skopnik for fixing the fix!
+			 */
+			$('select option[value="'+oSettings._iDisplayLength+'"]',nLength).attr("selected",true);
+			
+			$('select', nLength).change( function(e) {
+				var iVal = $(this).val();
+				
+				/* Update all other length options for the new display */
+				var n = oSettings.aanFeatures.l;
+				for ( i=0, iLen=n.length ; i<iLen ; i++ )
+				{
+					if ( n[i] != this.parentNode )
+					{
+						$('select', n[i]).val( iVal );
+					}
+				}
+				
+				/* Redraw the table */
+				oSettings._iDisplayLength = parseInt(iVal, 10);
+				_fnCalculateEnd( oSettings );
+				
+				/* If we have space to show extra rows (backing up from the end point - then do so */
+				if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
+				{
+					oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
+					if ( oSettings._iDisplayStart < 0 )
+					{
+						oSettings._iDisplayStart = 0;
+					}
+				}
+				
+				if ( oSettings._iDisplayLength == -1 )
+				{
+					oSettings._iDisplayStart = 0;
+				}
+				
+				_fnDraw( oSettings );
+			} );
+			
+			return nLength;
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Feature: Processing incidator
+		 */
+		
+		/*
+		 * Function: _fnFeatureHtmlProcessing
+		 * Purpose:  Generate the node required for the processing node
+		 * Returns:  node
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnFeatureHtmlProcessing ( oSettings )
+		{
+			var nProcessing = document.createElement( 'div' );
+			
+			if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.r == "undefined" )
+			{
+				nProcessing.setAttribute( 'id', oSettings.sTableId+'_processing' );
+			}
+			nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
+			nProcessing.className = oSettings.oClasses.sProcessing;
+			oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
+			
+			return nProcessing;
+		}
+		
+		/*
+		 * Function: _fnProcessingDisplay
+		 * Purpose:  Display or hide the processing indicator
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           bool:
+		 *   true - show the processing indicator
+		 *   false - don't show
+		 */
+		function _fnProcessingDisplay ( oSettings, bShow )
+		{
+			if ( oSettings.oFeatures.bProcessing )
+			{
+				var an = oSettings.aanFeatures.r;
+				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
+				{
+					an[i].style.visibility = bShow ? "visible" : "hidden";
+				}
+			}
+		}
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Support functions
+		 */
+		
+		/*
+		 * Function: _fnVisibleToColumnIndex
+		 * Purpose:  Covert the index of a visible column to the index in the data array (take account
+		 *   of hidden columns)
+		 * Returns:  int:i - the data index
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnVisibleToColumnIndex( oSettings, iMatch )
+		{
+			var iColumn = -1;
+			
+			for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
+			{
+				if ( oSettings.aoColumns[i].bVisible === true )
+				{
+					iColumn++;
+				}
+				
+				if ( iColumn == iMatch )
+				{
+					return i;
+				}
+			}
+			
+			return null;
+		}
+		
+		/*
+		 * Function: _fnColumnIndexToVisible
+		 * Purpose:  Covert the index of an index in the data array and convert it to the visible
+		 *   column index (take account of hidden columns)
+		 * Returns:  int:i - the data index
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnColumnIndexToVisible( oSettings, iMatch )
+		{
+			var iVisible = -1;
+			for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
+			{
+				if ( oSettings.aoColumns[i].bVisible === true )
+				{
+					iVisible++;
+				}
+				
+				if ( i == iMatch )
+				{
+					return oSettings.aoColumns[i].bVisible === true ? iVisible : null;
+				}
+			}
+			
+			return null;
+		}
+		
+		
+		/*
+		 * Function: _fnNodeToDataIndex
+		 * Purpose:  Take a TR element and convert it to an index in aoData
+		 * Returns:  int:i - index if found, null if not
+		 * Inputs:   object:s - dataTables settings object
+		 *           node:n - the TR element to find
+		 */
+		function _fnNodeToDataIndex( s, n )
+		{
+			var i, iLen;
+			
+			/* Optimisation - see if the nodes which are currently visible match, since that is
+			 * the most likely node to be asked for (a selector or event for example)
+			 */
+			for ( i=s._iDisplayStart, iLen=s._iDisplayEnd ; i<iLen ; i++ )
+			{
+				if ( s.aoData[ s.aiDisplay[i] ].nTr == n )
+				{
+					return s.aiDisplay[i];
+				}
+			}
+			
+			/* Otherwise we are in for a slog through the whole data cache */
+			for ( i=0, iLen=s.aoData.length ; i<iLen ; i++ )
+			{
+				if ( s.aoData[i].nTr == n )
+				{
+					return i;
+				}
+			}
+			return null;
+		}
+		
+		/*
+		 * Function: _fnVisbleColumns
+		 * Purpose:  Get the number of visible columns
+		 * Returns:  int:i - the number of visible columns
+		 * Inputs:   object:oS - dataTables settings object
+		 */
+		function _fnVisbleColumns( oS )
+		{
+			var iVis = 0;
+			for ( var i=0 ; i<oS.aoColumns.length ; i++ )
+			{
+				if ( oS.aoColumns[i].bVisible === true )
+				{
+					iVis++;
+				}
+			}
+			return iVis;
+		}
+		
+		/*
+		 * Function: _fnCalculateEnd
+		 * Purpose:  Rcalculate the end point based on the start point
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnCalculateEnd( oSettings )
+		{
+			if ( oSettings.oFeatures.bPaginate === false )
+			{
+				oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+			}
+			else
+			{
+				/* Set the end point of the display - based on how many elements there are
+				 * still to display
+				 */
+				if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
+					   oSettings._iDisplayLength == -1 )
+				{
+					oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+				}
+				else
+				{
+					oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
+				}
+			}
+		}
+		
+		/*
+		 * Function: _fnConvertToWidth
+		 * Purpose:  Convert a CSS unit width to pixels (e.g. 2em)
+		 * Returns:  int:iWidth - width in pixels
+		 * Inputs:   string:sWidth - width to be converted
+		 *           node:nParent - parent to get the with for (required for
+		 *             relative widths) - optional
+		 */
+		function _fnConvertToWidth ( sWidth, nParent )
+		{
+			if ( !sWidth || sWidth === null || sWidth === '' )
+			{
+				return 0;
+			}
+			
+			if ( typeof nParent == "undefined" )
+			{
+				nParent = document.getElementsByTagName('body')[0];
+			}
+			
+			var iWidth;
+			var nTmp = document.createElement( "div" );
+			nTmp.style.width = sWidth;
+			
+			nParent.appendChild( nTmp );
+			iWidth = nTmp.offsetWidth;
+			nParent.removeChild( nTmp );
+			
+			return ( iWidth );
+		}
+		
+		/*
+		 * Function: _fnCalculateColumnWidths
+		 * Purpose:  Calculate the width of columns for the table
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnCalculateColumnWidths ( oSettings )
+		{
+			var iTableWidth = oSettings.nTable.offsetWidth;
+			var iUserInputs = 0;
+			var iTmpWidth;
+			var iVisibleColumns = 0;
+			var iColums = oSettings.aoColumns.length;
+			var i;
+			var oHeaders = $('th', oSettings.nTHead);
+			
+			/* Convert any user input sizes into pixel sizes */
+			for ( i=0 ; i<iColums ; i++ )
+			{
+				if ( oSettings.aoColumns[i].bVisible )
+				{
+					iVisibleColumns++;
+					
+					if ( oSettings.aoColumns[i].sWidth !== null )
+					{
+						iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig, 
+							oSettings.nTable.parentNode );
+						if ( iTmpWidth !== null )
+						{
+							oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
+						}
+							
+						iUserInputs++;
+					}
+				}
+			}
+			
+			/* If the number of columns in the DOM equals the number that we have to process in 
+			 * DataTables, then we can use the offsets that are created by the web-browser. No custom 
+			 * sizes can be set in order for this to happen, nor scrolling used
+			 */
+			if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
+				oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
+			{
+				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+				{
+					iTmpWidth = $(oHeaders[i]).width();
+					if ( iTmpWidth !== null )
+					{
+						oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
+					}
+				}
+			}
+			else
+			{
+				/* Otherwise we are going to have to do some calculations to get the width of each column.
+				 * Construct a 1 row table with the widest node in the data, and any user defined widths,
+				 * then insert it into the DOM and allow the browser to do all the hard work of
+				 * calculating table widths.
+				 */
+				var
+					nCalcTmp = oSettings.nTable.cloneNode( false ),
+					nBody = document.createElement( 'tbody' ),
+					nTr = document.createElement( 'tr' ),
+					nDivSizing;
+				
+				nCalcTmp.removeAttribute( "id" );
+				nCalcTmp.appendChild( oSettings.nTHead.cloneNode(true) );
+				if ( oSettings.nTFoot !== null )
+				{
+					nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
+					_fnApplyToChildren( function(n) {
+						n.style.width = "";
+					}, nCalcTmp.getElementsByTagName('tr') );
+				}
+				
+				nCalcTmp.appendChild( nBody );
+				nBody.appendChild( nTr );
+				
+				/* Remove any sizing that was previously applied by the styles */
+				var jqColSizing = $('thead th', nCalcTmp);
+				if ( jqColSizing.length === 0 )
+				{
+					jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
+				}
+				jqColSizing.each( function (i) {
+					this.style.width = "";
+					
+					var iIndex = _fnVisibleToColumnIndex( oSettings, i );
+					if ( iIndex !== null && oSettings.aoColumns[iIndex].sWidthOrig !== "" )
+					{
+						this.style.width = oSettings.aoColumns[iIndex].sWidthOrig;
+					}
+				} );
+				
+				/* Find the biggest td for each column and put it into the table */
+				for ( i=0 ; i<iColums ; i++ )
+				{
+					if ( oSettings.aoColumns[i].bVisible )
+					{
+						var nTd = _fnGetWidestNode( oSettings, i );
+						if ( nTd !== null )
+						{
+							nTd = nTd.cloneNode(true);
+							nTr.appendChild( nTd );
+						}
+					}
+				}
+				
+				/* Build the table and 'display' it */
+				var nWrapper = oSettings.nTable.parentNode;
+				nWrapper.appendChild( nCalcTmp );
+				
+				/* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
+				 * when not scrolling leave the table width as it is. This results in slightly different,
+				 * but I think correct behaviour
+				 */
+				if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
+				{
+					nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
+				}
+				else if ( oSettings.oScroll.sX !== "" )
+				{
+					nCalcTmp.style.width = "";
+					if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
+					{
+						nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
+					}
+				}
+				else if ( oSettings.oScroll.sY !== "" )
+				{
+					nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
+				}
+				nCalcTmp.style.visibility = "hidden";
+				
+				/* Scrolling considerations */
+				_fnScrollingWidthAdjust( oSettings, nCalcTmp );
+				
+				/* Read the width's calculated by the browser and store them for use by the caller. We
+				 * first of all try to use the elements in the body, but it is possible that there are
+				 * no elements there, under which circumstances we use the header elements
+				 */
+				var oNodes = $("tbody tr:eq(0)>td", nCalcTmp);
+				if ( oNodes.length === 0 )
+				{
+					oNodes = $("thead tr:eq(0)>th", nCalcTmp);
+				}
+				
+				var iIndex, iCorrector = 0, iWidth;
+				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+				{
+					if ( oSettings.aoColumns[i].bVisible )
+					{
+						iWidth = $(oNodes[iCorrector]).width();
+						if ( iWidth !== null && iWidth > 0 )
+						{
+							oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
+						}
+						iCorrector++;
+					}
+				}
+				
+				oSettings.nTable.style.width = _fnStringToCss( $(nCalcTmp).outerWidth() );
+				nCalcTmp.parentNode.removeChild( nCalcTmp );
+			}
+		}
+		
+		/*
+		 * Function: _fnScrollingWidthAdjust
+		 * Purpose:  Adjust a table's width to take account of scrolling
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           node:n - table node
+		 */
+		function _fnScrollingWidthAdjust ( oSettings, n )
+		{
+			if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
+			{
+				/* When y-scrolling only, we want to remove the width of the scroll bar so the table
+				 * + scroll bar will fit into the area avaialble.
+				 */
+				var iOrigWidth = $(n).width();
+				n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
+			}
+			else if ( oSettings.oScroll.sX !== "" )
+			{
+				/* When x-scrolling both ways, fix the table at it's current size, without adjusting */
+				n.style.width = _fnStringToCss( $(n).outerWidth() );
+			}
+		}
+		
+		/*
+		 * Function: _fnGetWidestNode
+		 * Purpose:  Get the widest node
+		 * Returns:  string: - max strlens for each column
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           int:iCol - column of interest
+		 *           boolean:bFast - Should we use fast (but non-accurate) calculation - optional,
+		 *             default true
+		 * Notes:    This operation is _expensive_ (!!!). It requires a lot of DOM interaction, but
+		 *   this is the only way to reliably get the widest string. For example 'mmm' would be wider
+		 *   than 'iiii' so we can't just ocunt characters. If this can be optimised it would be good
+		 *   to do so!
+		 */
+		function _fnGetWidestNode( oSettings, iCol, bFast )
+		{
+			/* Use fast not non-accurate calculate based on the strlen */
+			if ( typeof bFast == 'undefined' || bFast )
+			{
+				var iMaxLen = _fnGetMaxLenString( oSettings, iCol );
+				var iFastVis = _fnColumnIndexToVisible( oSettings, iCol);
+				if ( iMaxLen < 0 )
+				{
+					return null;
+				}
+				return oSettings.aoData[iMaxLen].nTr.getElementsByTagName('td')[iFastVis];
+			}
+			
+			/* Use the slow approach, but get high quality answers - note that this code is not actually
+			 * used by DataTables by default. If you want to use it you can alter the call to 
+			 * _fnGetWidestNode to pass 'false' as the third argument
+			 */
+			var
+				iMax = -1, i, iLen,
+				iMaxIndex = -1,
+				n = document.createElement('div');
+			
+			n.style.visibility = "hidden";
+			n.style.position = "absolute";
+			document.body.appendChild( n );
+			
+			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+			{
+				n.innerHTML = oSettings.aoData[i]._aData[iCol];
+				if ( n.offsetWidth > iMax )
+				{
+					iMax = n.offsetWidth;
+					iMaxIndex = i;
+				}
+			}
+			document.body.removeChild( n );
+			
+			if ( iMaxIndex >= 0 )
+			{
+				var iVis = _fnColumnIndexToVisible( oSettings, iCol);
+				var nRet = oSettings.aoData[iMaxIndex].nTr.getElementsByTagName('td')[iVis];
+				if ( nRet )
+				{
+					return nRet;
+				}
+			}
+			return null;
+		}
+		
+		/*
+		 * Function: _fnGetMaxLenString
+		 * Purpose:  Get the maximum strlen for each data column
+		 * Returns:  string: - max strlens for each column
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           int:iCol - column of interest
+		 */
+		function _fnGetMaxLenString( oSettings, iCol )
+		{
+			var iMax = -1;
+			var iMaxIndex = -1;
+			
+			for ( var i=0 ; i<oSettings.aoData.length ; i++ )
+			{
+				var s = oSettings.aoData[i]._aData[iCol];
+				if ( s.length > iMax )
+				{
+					iMax = s.length;
+					iMaxIndex = i;
+				}
+			}
+			
+			return iMaxIndex;
+		}
+		
+		/*
+		 * Function: _fnStringToCss
+		 * Purpose:  Append a CSS unit (only if required) to a string
+		 * Returns:  0 if match, 1 if length is different, 2 if no match
+		 * Inputs:   array:aArray1 - first array
+		 *           array:aArray2 - second array
+		 */
+		function _fnStringToCss( s )
+		{
+			if ( s === null )
+			{
+				return "0px";
+			}
+			
+			if ( typeof s == 'number' )
+			{
+				if ( s < 0 )
+				{
+					return "0px";
+				}
+				return s+"px";
+			}
+			
+			/* Check if the last character is not 0-9 */
+			var c = s.charCodeAt( s.length-1 );
+			if (c < 0x30 || c > 0x39)
+			{
+				return s;
+			}
+			return s+"px";
+		}
+		
+		/*
+		 * Function: _fnArrayCmp
+		 * Purpose:  Compare two arrays
+		 * Returns:  0 if match, 1 if length is different, 2 if no match
+		 * Inputs:   array:aArray1 - first array
+		 *           array:aArray2 - second array
+		 */
+		function _fnArrayCmp( aArray1, aArray2 )
+		{
+			if ( aArray1.length != aArray2.length )
+			{
+				return 1;
+			}
+			
+			for ( var i=0 ; i<aArray1.length ; i++ )
+			{
+				if ( aArray1[i] != aArray2[i] )
+				{
+					return 2;
+				}
+			}
+			
+			return 0;
+		}
+		
+		/*
+		 * Function: _fnDetectType
+		 * Purpose:  Get the sort type based on an input string
+		 * Returns:  string: - type (defaults to 'string' if no type can be detected)
+		 * Inputs:   string:sData - data we wish to know the type of
+		 * Notes:    This function makes use of the DataTables plugin objct _oExt 
+		 *   (.aTypes) such that new types can easily be added.
+		 */
+		function _fnDetectType( sData )
+		{
+			var aTypes = _oExt.aTypes;
+			var iLen = aTypes.length;
+			
+			for ( var i=0 ; i<iLen ; i++ )
+			{
+				var sType = aTypes[i]( sData );
+				if ( sType !== null )
+				{
+					return sType;
+				}
+			}
+			
+			return 'string';
+		}
+		
+		/*
+		 * Function: _fnSettingsFromNode
+		 * Purpose:  Return the settings object for a particular table
+		 * Returns:  object: Settings object - or null if not found
+		 * Inputs:   node:nTable - table we are using as a dataTable
+		 */
+		function _fnSettingsFromNode ( nTable )
+		{
+			for ( var i=0 ; i<_aoSettings.length ; i++ )
+			{
+				if ( _aoSettings[i].nTable == nTable )
+				{
+					return _aoSettings[i];
+				}
+			}
+			
+			return null;
+		}
+		
+		/*
+		 * Function: _fnGetDataMaster
+		 * Purpose:  Return an array with the full table data
+		 * Returns:  array array:aData - Master data array
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnGetDataMaster ( oSettings )
+		{
+			var aData = [];
+			var iLen = oSettings.aoData.length;
+			for ( var i=0 ; i<iLen; i++ )
+			{
+				aData.push( oSettings.aoData[i]._aData );
+			}
+			return aData;
+		}
+		
+		/*
+		 * Function: _fnGetTrNodes
+		 * Purpose:  Return an array with the TR nodes for the table
+		 * Returns:  array: - TR array
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnGetTrNodes ( oSettings )
+		{
+			var aNodes = [];
+			var iLen = oSettings.aoData.length;
+			for ( var i=0 ; i<iLen ; i++ )
+			{
+				aNodes.push( oSettings.aoData[i].nTr );
+			}
+			return aNodes;
+		}
+		
+		/*
+		 * Function: _fnGetTdNodes
+		 * Purpose:  Return an array with the TD nodes for the table
+		 * Returns:  array: - TD array
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnGetTdNodes ( oSettings )
+		{
+			var nTrs = _fnGetTrNodes( oSettings );
+			var nTds = [], nTd;
+			var anReturn = [];
+			var iCorrector;
+			var iRow, iRows, iColumn, iColumns;
+			
+			for ( iRow=0, iRows=nTrs.length ; iRow<iRows ; iRow++ )
+			{
+				nTds = [];
+				for ( iColumn=0, iColumns=nTrs[iRow].childNodes.length ; iColumn<iColumns ; iColumn++ )
+				{
+					nTd = nTrs[iRow].childNodes[iColumn];
+					if ( nTd.nodeName.toUpperCase() == "TD" )
+					{
+						nTds.push( nTd );
+					}
+				}
+				
+				iCorrector = 0;
+				for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
+				{
+					if ( oSettings.aoColumns[iColumn].bVisible )
+					{
+						anReturn.push( nTds[iColumn-iCorrector] );
+					}
+					else
+					{
+						anReturn.push( oSettings.aoData[iRow]._anHidden[iColumn] );
+						iCorrector++;
+					}
+				}
+			}
+			return anReturn;
+		}
+		
+		/*
+		 * Function: _fnEscapeRegex
+		 * Purpose:  scape a string stuch that it can be used in a regular expression
+		 * Returns:  string: - escaped string
+		 * Inputs:   string:sVal - string to escape
+		 */
+		function _fnEscapeRegex ( sVal )
+		{
+			var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^' ];
+		  var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
+		  return sVal.replace(reReplace, '\\$1');
+		}
+		
+		/*
+		 * Function: _fnDeleteIndex
+		 * Purpose:  Take an array of integers (index array) and remove a target integer (value - not 
+		 *             the key!)
+		 * Returns:  -
+		 * Inputs:   a:array int - Index array to target
+		 *           int:iTarget - value to find
+		 */
+		function _fnDeleteIndex( a, iTarget )
+		{
+			var iTargetIndex = -1;
+			
+			for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+			{
+				if ( a[i] == iTarget )
+				{
+					iTargetIndex = i;
+				}
+				else if ( a[i] > iTarget )
+				{
+					a[i]--;
+				}
+			}
+			
+			if ( iTargetIndex != -1 )
+			{
+				a.splice( iTargetIndex, 1 );
+			}
+		}
+		
+		/*
+		 * Function: _fnReOrderIndex
+		 * Purpose:  Figure out how to reorder a display list
+		 * Returns:  array int:aiReturn - index list for reordering
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnReOrderIndex ( oSettings, sColumns )
+		{
+			var aColumns = sColumns.split(',');
+			var aiReturn = [];
+			
+			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+			{
+				for ( var j=0 ; j<iLen ; j++ )
+				{
+					if ( oSettings.aoColumns[i].sName == aColumns[j] )
+					{
+						aiReturn.push( j );
+						break;
+					}
+				}
+			}
+			
+			return aiReturn;
+		}
+		
+		/*
+		 * Function: _fnColumnOrdering
+		 * Purpose:  Get the column ordering that DataTables expects
+		 * Returns:  string: - comma separated list of names
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnColumnOrdering ( oSettings )
+		{
+			var sNames = '';
+			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+			{
+				sNames += oSettings.aoColumns[i].sName+',';
+			}
+			if ( sNames.length == iLen )
+			{
+				return "";
+			}
+			return sNames.slice(0, -1);
+		}
+		
+		/*
+		 * Function: _fnLog
+		 * Purpose:  Log an error message
+		 * Returns:  -
+		 * Inputs:   int:iLevel - log error messages, or display them to the user
+		 *           string:sMesg - error message
+		 */
+		function _fnLog( oSettings, iLevel, sMesg )
+		{
+			var sAlert = oSettings.sTableId === "" ?
+			 	"DataTables warning: " +sMesg :
+			 	"DataTables warning (table id = '"+oSettings.sTableId+"'): " +sMesg;
+			
+			if ( iLevel === 0 )
+			{
+				if ( _oExt.sErrMode == 'alert' )
+				{
+					alert( sAlert );
+				}
+				else
+				{
+					throw sAlert;
+				}
+				return;
+			}
+			else if ( typeof console != 'undefined' && typeof console.log != 'undefined' )
+			{
+				console.log( sAlert );
+			}
+		}
+		
+		/*
+		 * Function: _fnClearTable
+		 * Purpose:  Nuke the table
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnClearTable( oSettings )
+		{
+			oSettings.aoData.splice( 0, oSettings.aoData.length );
+			oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
+			oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
+			_fnCalculateEnd( oSettings );
+		}
+		
+		/*
+		 * Function: _fnSaveState
+		 * Purpose:  Save the state of a table in a cookie such that the page can be reloaded
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 */
+		function _fnSaveState ( oSettings )
+		{
+			if ( !oSettings.oFeatures.bStateSave || typeof oSettings.bDestroying != 'undefined' )
+			{
+				return;
+			}
+			
+			/* Store the interesting variables */
+			var i, iLen, sTmp;
+			var sValue = "{";
+			sValue += '"iCreate":'+ new Date().getTime()+',';
+			sValue += '"iStart":'+ oSettings._iDisplayStart+',';
+			sValue += '"iEnd":'+ oSettings._iDisplayEnd+',';
+			sValue += '"iLength":'+ oSettings._iDisplayLength+',';
+			sValue += '"sFilter":"'+ encodeURIComponent(oSettings.oPreviousSearch.sSearch)+'",';
+			sValue += '"sFilterEsc":'+ !oSettings.oPreviousSearch.bRegex+',';
+			
+			sValue += '"aaSorting":[ ';
+			for ( i=0 ; i<oSettings.aaSorting.length ; i++ )
+			{
+				sValue += '['+oSettings.aaSorting[i][0]+',"'+oSettings.aaSorting[i][1]+'"],';
+			}
+			sValue = sValue.substring(0, sValue.length-1);
+			sValue += "],";
+			
+			sValue += '"aaSearchCols":[ ';
+			for ( i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
+			{
+				sValue += '["'+encodeURIComponent(oSettings.aoPreSearchCols[i].sSearch)+
+					'",'+!oSettings.aoPreSearchCols[i].bRegex+'],';
+			}
+			sValue = sValue.substring(0, sValue.length-1);
+			sValue += "],";
+			
+			sValue += '"abVisCols":[ ';
+			for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+			{
+				sValue += oSettings.aoColumns[i].bVisible+",";
+			}
+			sValue = sValue.substring(0, sValue.length-1);
+			sValue += "]";
+			
+			/* Save state from any plug-ins */
+			for ( i=0, iLen=oSettings.aoStateSave.length ; i<iLen ; i++ )
+			{
+				sTmp = oSettings.aoStateSave[i].fn( oSettings, sValue );
+				if ( sTmp !== "" )
+				{
+					sValue = sTmp;
+				}
+			}
+			
+			sValue += "}";
+			
+			_fnCreateCookie( oSettings.sCookiePrefix+oSettings.sInstance, sValue, 
+				oSettings.iCookieDuration, oSettings.sCookiePrefix, oSettings.fnCookieCallback );
+		}
+		
+		/*
+		 * Function: _fnLoadState
+		 * Purpose:  Attempt to load a saved table state from a cookie
+		 * Returns:  -
+		 * Inputs:   object:oSettings - dataTables settings object
+		 *           object:oInit - DataTables init object so we can override settings
+		 */
+		function _fnLoadState ( oSettings, oInit )
+		{
+			if ( !oSettings.oFeatures.bStateSave )
+			{
+				return;
+			}
+			
+			var oData, i, iLen;
+			var sData = _fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
+			if ( sData !== null && sData !== '' )
+			{
+				/* Try/catch the JSON eval - if it is bad then we ignore it - note that 1.7.0 and before
+				 * incorrectly used single quotes for some strings - hence the replace below
+				 */
+				try
+				{
+					oData = (typeof $.parseJSON == 'function') ? 
+						$.parseJSON( sData.replace(/'/g, '"') ) : eval( '('+sData+')' );
+				}
+				catch( e )
+				{
+					return;
+				}
+				
+				/* Allow custom and plug-in manipulation functions to alter the data set which was
+				 * saved, and also reject any saved state by returning false
+				 */
+				for ( i=0, iLen=oSettings.aoStateLoad.length ; i<iLen ; i++ )
+				{
+					if ( !oSettings.aoStateLoad[i].fn( oSettings, oData ) )
+					{
+						return;
+					}
+				}
+				
+				/* Store the saved state so it might be accessed at any time (particualrly a plug-in */
+				oSettings.oLoadedState = $.extend( true, {}, oData );
+				
+				/* Restore key features */
+				oSettings._iDisplayStart = oData.iStart;
+				oSettings.iInitDisplayStart = oData.iStart;
+				oSettings._iDisplayEnd = oData.iEnd;
+				oSettings._iDisplayLength = oData.iLength;
+				oSettings.oPreviousSearch.sSearch = decodeURIComponent(oData.sFilter);
+				oSettings.aaSorting = oData.aaSorting.slice();
+				oSettings.saved_aaSorting = oData.aaSorting.slice();
+				
+				/*
+				 * Search filtering - global reference added in 1.4.1
+				 * Note that we use a 'not' for the value of the regular expression indicator to maintain
+				 * compatibility with pre 1.7 versions, where this was basically inverted. Added in 1.7.0
+				 */
+				if ( typeof oData.sFilterEsc != 'undefined' )
+				{
+					oSettings.oPreviousSearch.bRegex = !oData.sFilterEsc;
+				}
+				
+				/* Column filtering - added in 1.5.0 beta 6 */
+				if ( typeof oData.aaSearchCols != 'undefined' )
+				{
+					for ( i=0 ; i<oData.aaSearchCols.length ; i++ )
+					{
+						oSettings.aoPreSearchCols[i] = {
+							"sSearch": decodeURIComponent(oData.aaSearchCols[i][0]),
+							"bRegex": !oData.aaSearchCols[i][1]
+						};
+					}
+				}
+				
+				/* Column visibility state - added in 1.5.0 beta 10 */
+				if ( typeof oData.abVisCols != 'undefined' )
+				{
+					/* Pass back visibiliy settings to the init handler, but to do not here override
+					 * the init object that the user might have passed in
+					 */
+					oInit.saved_aoColumns = [];
+					for ( i=0 ; i<oData.abVisCols.length ; i++ )
+					{
+						oInit.saved_aoColumns[i] = {};
+						oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
+					}
+				}
+			}
+		}
+		
+		/*
+		 * Function: _fnCreateCookie
+		 * Purpose:  Create a new cookie with a value to store the state of a table
+		 * Returns:  -
+		 * Inputs:   string:sName - name of the cookie to create
+		 *           string:sValue - the value the cookie should take
+		 *           int:iSecs - duration of the cookie
+		 *           string:sBaseName - sName is made up of the base + file name - this is the base
+		 *           function:fnCallback - User definable function to modify the cookie
+		 */
+		function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
+		{
+			var date = new Date();
+			date.setTime( date.getTime()+(iSecs*1000) );
+			
+			/* 
+			 * Shocking but true - it would appear IE has major issues with having the path not having
+			 * a trailing slash on it. We need the cookie to be available based on the path, so we
+			 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
+			 * patch to use at least some of the path
+			 */
+			var aParts = window.location.pathname.split('/');
+			var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
+			var sFullCookie, oData;
+			
+			if ( fnCallback !== null )
+			{
+				oData = (typeof $.parseJSON == 'function') ? 
+					$.parseJSON( sValue ) : eval( '('+sValue+')' );
+				sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
+					aParts.join('/')+"/" );
+			}
+			else
+			{
+				sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
+					"; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
+			}
+			
+			/* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
+			 * belonging to DataTables. This is FAR from bullet proof
+			 */
+			var sOldName="", iOldTime=9999999999999;
+			var iLength = _fnReadCookie( sNameFile )!==null ? document.cookie.length : 
+				sFullCookie.length + document.cookie.length;
+			
+			if ( iLength+10 > 4096 ) /* Magic 10 for padding */
+			{
+				var aCookies =document.cookie.split(';');
+				for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
+				{
+					if ( aCookies[i].indexOf( sBaseName ) != -1 )
+					{
+						/* It's a DataTables cookie, so eval it and check the time stamp */
+						var aSplitCookie = aCookies[i].split('=');
+						try { oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' ); }
+						catch( e ) { continue; }
+						
+						if ( typeof oData.iCreate != 'undefined' && oData.iCreate < iOldTime )
+						{
+							sOldName = aSplitCookie[0];
+							iOldTime = oData.iCreate;
+						}
+					}
+				}
+				
+				if ( sOldName !== "" )
+				{
+					document.cookie = sOldName+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
+						aParts.join('/') + "/";
+				}
+			}
+			
+			document.cookie = sFullCookie;
+		}
+		
+		/*
+		 * Function: _fnReadCookie
+		 * Purpose:  Read an old cookie to get a cookie with an old table state
+		 * Returns:  string: - contents of the cookie - or null if no cookie with that name found
+		 * Inputs:   string:sName - name of the cookie to read
+		 */
+		function _fnReadCookie ( sName )
+		{
+			var
+				aParts = window.location.pathname.split('/'),
+				sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
+			 	sCookieContents = document.cookie.split(';');
+			
+			for( var i=0 ; i<sCookieContents.length ; i++ )
+			{
+				var c = sCookieContents[i];
+				
+				while (c.charAt(0)==' ')
+				{
+					c = c.substring(1,c.length);
+				}
+				
+				if (c.indexOf(sNameEQ) === 0)
+				{
+					return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
+				}
+			}
+			return null;
+		}
+		
+		/*
+		 * Function: _fnGetUniqueThs
+		 * Purpose:  Get an array of unique th elements, one for each column
+		 * Returns:  array node:aReturn - list of unique ths
+		 * Inputs:   node:nThead - The thead element for the table
+		 */
+		function _fnGetUniqueThs ( nThead )
+		{
+			var nTrs = nThead.getElementsByTagName('tr');
+			
+			/* Nice simple case */
+			if ( nTrs.length == 1 )
+			{
+				return nTrs[0].getElementsByTagName('th');
+			}
+			
+			/* Otherwise we need to figure out the layout array to get the nodes */
+			var aLayout = [], aReturn = [];
+			var ROWSPAN = 2, COLSPAN = 3, TDELEM = 4;
+			var i, j, k, iLen, jLen, iColumnShifted;
+			var fnShiftCol = function ( a, i, j ) {
+				while ( typeof a[i][j] != 'undefined' ) {
+					j++;
+				}
+				return j;
+			};
+			var fnAddRow = function ( i ) {
+				if ( typeof aLayout[i] == 'undefined' ) {
+					aLayout[i] = [];
+				}
+			};
+			
+			/* Calculate a layout array */
+			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+			{
+				fnAddRow( i );
+				var iColumn = 0;
+				var nTds = [];
+				
+				for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
+				{
+					if ( nTrs[i].childNodes[j].nodeName.toUpperCase() == "TD" ||
+					     nTrs[i].childNodes[j].nodeName.toUpperCase() == "TH" )
+					{
+						nTds.push( nTrs[i].childNodes[j] );
+					}
+				}
+				
+				for ( j=0, jLen=nTds.length ; j<jLen ; j++ )
+				{
+					var iColspan = nTds[j].getAttribute('colspan') * 1;
+					var iRowspan = nTds[j].getAttribute('rowspan') * 1;
+					
+					if ( !iColspan || iColspan===0 || iColspan===1 )
+					{
+						iColumnShifted = fnShiftCol( aLayout, i, iColumn );
+						aLayout[i][iColumnShifted] = (nTds[j].nodeName.toUpperCase()=="TD") ? TDELEM : nTds[j];
+						if ( iRowspan || iRowspan===0 || iRowspan===1 )
+						{
+							for ( k=1 ; k<iRowspan ; k++ )
+							{
+								fnAddRow( i+k );
+								aLayout[i+k][iColumnShifted] = ROWSPAN;
+							}
+						}
+						iColumn++;
+					}
+					else
+					{
+						iColumnShifted = fnShiftCol( aLayout, i, iColumn );
+						for ( k=0 ; k<iColspan ; k++ )
+						{
+							aLayout[i][iColumnShifted+k] = COLSPAN;
+						}
+						iColumn += iColspan;
+					}
+				}
+			}
+			
+			/* Convert the layout array into a node array */
+			for ( i=0, iLen=aLayout.length ; i<iLen ; i++ )
+			{
+				for ( j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
+				{
+					if ( typeof aLayout[i][j] == 'object' )
+					{
+						aReturn[j] = aLayout[i][j];
+					}
+				}
+			}
+			
+			return aReturn;
+		}
+		
+		/*
+		 * Function: _fnScrollBarWidth
+		 * Purpose:  Get the width of a scroll bar in this browser being used
+		 * Returns:  int: - width in pixels
+		 * Inputs:   -
+		 * Notes:    All credit for this function belongs to Alexandre Gomes. Thanks for sharing!
+		 *   http://www.alexandre-gomes.com/?p=115
+		 */
+		function _fnScrollBarWidth ()
+		{  
+			var inner = document.createElement('p');  
+			var style = inner.style;
+			style.width = "100%";  
+			style.height = "200px";  
+			
+			var outer = document.createElement('div');  
+			style = outer.style;
+			style.position = "absolute";  
+			style.top = "0px";  
+			style.left = "0px";  
+			style.visibility = "hidden";  
+			style.width = "200px";  
+			style.height = "150px";  
+			style.overflow = "hidden";  
+			outer.appendChild(inner);  
+			
+			document.body.appendChild(outer);  
+			var w1 = inner.offsetWidth;  
+			outer.style.overflow = 'scroll';  
+			var w2 = inner.offsetWidth;  
+			if ( w1 == w2 )
+			{
+				w2 = outer.clientWidth;  
+			}
+			
+			document.body.removeChild(outer); 
+			return (w1 - w2);  
+		}
+		
+		/*
+		 * Function: _fnApplyToChildren
+		 * Purpose:  Apply a given function to the display child nodes of an element array (typically
+		 *   TD children of TR rows
+		 * Returns:  - (done by reference)
+		 * Inputs:   function:fn - Method to apply to the objects
+		 *           array nodes:an1 - List of elements to look through for display children
+		 *           array nodes:an2 - Another list (identical structure to the first) - optional
+		 */
+		function _fnApplyToChildren( fn, an1, an2 )
+		{
+			for ( var i=0, iLen=an1.length ; i<iLen ; i++ )
+			{
+				for ( var j=0, jLen=an1[i].childNodes.length ; j<jLen ; j++ )
+				{
+					if ( an1[i].childNodes[j].nodeType == 1 )
+					{
+						if ( typeof an2 != 'undefined' )
+						{
+							fn( an1[i].childNodes[j], an2[i].childNodes[j] );
+						}
+						else
+						{
+							fn( an1[i].childNodes[j] );
+						}
+					}
+				}
+			}
+		}
+		
+		/*
+		 * Function: _fnMap
+		 * Purpose:  See if a property is defined on one object, if so assign it to the other object
+		 * Returns:  - (done by reference)
+		 * Inputs:   object:oRet - target object
+		 *           object:oSrc - source object
+		 *           string:sName - property
+		 *           string:sMappedName - name to map too - optional, sName used if not given
+		 */
+		function _fnMap( oRet, oSrc, sName, sMappedName )
+		{
+			if ( typeof sMappedName == 'undefined' )
+			{
+				sMappedName = sName;
+			}
+			if ( typeof oSrc[sName] != 'undefined' )
+			{
+				oRet[sMappedName] = oSrc[sName];
+			}
+		}
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - API
+		 * 
+		 * I'm not overly happy with this solution - I'd much rather that there was a way of getting
+		 * a list of all the private functions and do what we need to dynamically - but that doesn't
+		 * appear to be possible. Bonkers. A better solution would be to provide a 'bind' type object
+		 * To do - bind type method in DTs 2.x.
+		 */
+		this.oApi._fnExternApiFunc = _fnExternApiFunc;
+		this.oApi._fnInitalise = _fnInitalise;
+		this.oApi._fnLanguageProcess = _fnLanguageProcess;
+		this.oApi._fnAddColumn = _fnAddColumn;
+		this.oApi._fnColumnOptions = _fnColumnOptions;
+		this.oApi._fnAddData = _fnAddData;
+		this.oApi._fnGatherData = _fnGatherData;
+		this.oApi._fnDrawHead = _fnDrawHead;
+		this.oApi._fnDraw = _fnDraw;
+		this.oApi._fnReDraw = _fnReDraw;
+		this.oApi._fnAjaxUpdate = _fnAjaxUpdate;
+		this.oApi._fnAjaxUpdateDraw = _fnAjaxUpdateDraw;
+		this.oApi._fnAddOptionsHtml = _fnAddOptionsHtml;
+		this.oApi._fnFeatureHtmlTable = _fnFeatureHtmlTable;
+		this.oApi._fnScrollDraw = _fnScrollDraw;
+		this.oApi._fnAjustColumnSizing = _fnAjustColumnSizing;
+		this.oApi._fnFeatureHtmlFilter = _fnFeatureHtmlFilter;
+		this.oApi._fnFilterComplete = _fnFilterComplete;
+		this.oApi._fnFilterCustom = _fnFilterCustom;
+		this.oApi._fnFilterColumn = _fnFilterColumn;
+		this.oApi._fnFilter = _fnFilter;
+		this.oApi._fnBuildSearchArray = _fnBuildSearchArray;
+		this.oApi._fnBuildSearchRow = _fnBuildSearchRow;
+		this.oApi._fnFilterCreateSearch = _fnFilterCreateSearch;
+		this.oApi._fnDataToSearch = _fnDataToSearch;
+		this.oApi._fnSort = _fnSort;
+		this.oApi._fnSortAttachListener = _fnSortAttachListener;
+		this.oApi._fnSortingClasses = _fnSortingClasses;
+		this.oApi._fnFeatureHtmlPaginate = _fnFeatureHtmlPaginate;
+		this.oApi._fnPageChange = _fnPageChange;
+		this.oApi._fnFeatureHtmlInfo = _fnFeatureHtmlInfo;
+		this.oApi._fnUpdateInfo = _fnUpdateInfo;
+		this.oApi._fnFeatureHtmlLength = _fnFeatureHtmlLength;
+		this.oApi._fnFeatureHtmlProcessing = _fnFeatureHtmlProcessing;
+		this.oApi._fnProcessingDisplay = _fnProcessingDisplay;
+		this.oApi._fnVisibleToColumnIndex = _fnVisibleToColumnIndex;
+		this.oApi._fnColumnIndexToVisible = _fnColumnIndexToVisible;
+		this.oApi._fnNodeToDataIndex = _fnNodeToDataIndex;
+		this.oApi._fnVisbleColumns = _fnVisbleColumns;
+		this.oApi._fnCalculateEnd = _fnCalculateEnd;
+		this.oApi._fnConvertToWidth = _fnConvertToWidth;
+		this.oApi._fnCalculateColumnWidths = _fnCalculateColumnWidths;
+		this.oApi._fnScrollingWidthAdjust = _fnScrollingWidthAdjust;
+		this.oApi._fnGetWidestNode = _fnGetWidestNode;
+		this.oApi._fnGetMaxLenString = _fnGetMaxLenString;
+		this.oApi._fnStringToCss = _fnStringToCss;
+		this.oApi._fnArrayCmp = _fnArrayCmp;
+		this.oApi._fnDetectType = _fnDetectType;
+		this.oApi._fnSettingsFromNode = _fnSettingsFromNode;
+		this.oApi._fnGetDataMaster = _fnGetDataMaster;
+		this.oApi._fnGetTrNodes = _fnGetTrNodes;
+		this.oApi._fnGetTdNodes = _fnGetTdNodes;
+		this.oApi._fnEscapeRegex = _fnEscapeRegex;
+		this.oApi._fnDeleteIndex = _fnDeleteIndex;
+		this.oApi._fnReOrderIndex = _fnReOrderIndex;
+		this.oApi._fnColumnOrdering = _fnColumnOrdering;
+		this.oApi._fnLog = _fnLog;
+		this.oApi._fnClearTable = _fnClearTable;
+		this.oApi._fnSaveState = _fnSaveState;
+		this.oApi._fnLoadState = _fnLoadState;
+		this.oApi._fnCreateCookie = _fnCreateCookie;
+		this.oApi._fnReadCookie = _fnReadCookie;
+		this.oApi._fnGetUniqueThs = _fnGetUniqueThs;
+		this.oApi._fnScrollBarWidth = _fnScrollBarWidth;
+		this.oApi._fnApplyToChildren = _fnApplyToChildren;
+		this.oApi._fnMap = _fnMap;
+		
+		
+		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+		 * Section - Constructor
+		 */
+		
+		/* Want to be able to reference "this" inside the this.each function */
+		var _that = this;
+		return this.each(function()
+		{
+			var i=0, iLen, j, jLen, k, kLen;
+			
+			/* Check to see if we are re-initalising a table */
+			for ( i=0, iLen=_aoSettings.length ; i<iLen ; i++ )
+			{
+				/* Base check on table node */
+				if ( _aoSettings[i].nTable == this )
+				{
+					if ( typeof oInit == 'undefined' || 
+					   ( typeof oInit.bRetrieve != 'undefined' && oInit.bRetrieve === true ) )
+					{
+						return _aoSettings[i].oInstance;
+					}
+					else if ( typeof oInit.bDestroy != 'undefined' && oInit.bDestroy === true )
+					{
+						_aoSettings[i].oInstance.fnDestroy();
+						break;
+					}
+					else
+					{
+						_fnLog( _aoSettings[i], 0, "Cannot reinitialise DataTable.\n\n"+
+							"To retrieve the DataTables object for this table, please pass either no arguments "+
+							"to the dataTable() function, or set bRetrieve to true. Alternatively, to destory "+
+							"the old table and create a new one, set bDestroy to true (note that a lot of "+
+							"changes to the configuration can be made through the API which is usually much "+
+							"faster)." );
+						return;
+					}
+				}
+				
+				/* If the element we are initialising has the same ID as a table which was previously
+				 * initialised, but the table nodes don't match (from before) then we destory the old
+				 * instance by simply deleting it. This is under the assumption that the table has been
+				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
+				 */
+				if ( _aoSettings[i].sTableId !== "" && _aoSettings[i].sTableId == this.getAttribute('id') )
+				{
+					_aoSettings.splice( i, 1 );
+					break;
+				}
+			}
+			
+			/* Make a complete and independent copy of the settings object */
+			var oSettings = new classSettings();
+			_aoSettings.push( oSettings );
+			
+			var bInitHandedOff = false;
+			var bUsePassedData = false;
+			
+			/* Set the id */
+			var sId = this.getAttribute( 'id' );
+			if ( sId !== null )
+			{
+				oSettings.sTableId = sId;
+				oSettings.sInstance = sId;
+			}
+			else
+			{
+				oSettings.sInstance = _oExt._oExternConfig.iNextUnique ++;
+			}
+			
+			/* Sanity check */
+			if ( this.nodeName.toLowerCase() != 'table' )
+			{
+				_fnLog( oSettings, 0, "Attempted to initialise DataTables on a node which is not a "+
+					"table: "+this.nodeName );
+				return;
+			}
+			
+			/* Store 'this' in the settings object for later retrieval */
+			oSettings.oInstance = _that;
+			
+			/* Set the table node */
+			oSettings.nTable = this;
+			
+			/* Bind the API functions to the settings, so we can perform actions whenever oSettings is
+			 * available
+			 */
+			oSettings.oApi = _that.oApi;
+			
+			/* State the table's width for if a destroy is called at a later time */
+			oSettings.sDestroyWidth = $(this).width();
+			
+			/* Store the features that we have available */
+			if ( typeof oInit != 'undefined' && oInit !== null )
+			{
+				oSettings.oInit = oInit;
+				_fnMap( oSettings.oFeatures, oInit, "bPaginate" );
+				_fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
+				_fnMap( oSettings.oFeatures, oInit, "bFilter" );
+				_fnMap( oSettings.oFeatures, oInit, "bSort" );
+				_fnMap( oSettings.oFeatures, oInit, "bInfo" );
+				_fnMap( oSettings.oFeatures, oInit, "bProcessing" );
+				_fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
+				_fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
+				_fnMap( oSettings.oFeatures, oInit, "bServerSide" );
+				_fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
+				_fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
+				_fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
+				_fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
+				_fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
+				_fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
+				_fnMap( oSettings, oInit, "asStripClasses" );
+				_fnMap( oSettings, oInit, "fnRowCallback" );
+				_fnMap( oSettings, oInit, "fnHeaderCallback" );
+				_fnMap( oSettings, oInit, "fnFooterCallback" );
+				_fnMap( oSettings, oInit, "fnCookieCallback" );
+				_fnMap( oSettings, oInit, "fnInitComplete" );
+				_fnMap( oSettings, oInit, "fnServerData" );
+				_fnMap( oSettings, oInit, "fnFormatNumber" );
+				_fnMap( oSettings, oInit, "aaSorting" );
+				_fnMap( oSettings, oInit, "aaSortingFixed" );
+				_fnMap( oSettings, oInit, "aLengthMenu" );
+				_fnMap( oSettings, oInit, "sPaginationType" );
+				_fnMap( oSettings, oInit, "sAjaxSource" );
+				_fnMap( oSettings, oInit, "iCookieDuration" );
+				_fnMap( oSettings, oInit, "sCookiePrefix" );
+				_fnMap( oSettings, oInit, "sDom" );
+				_fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
+				_fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
+				_fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
+				_fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
+				_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
+				
+				/* Callback functions which are array driven */
+				if ( typeof oInit.fnDrawCallback == 'function' )
+				{
+					oSettings.aoDrawCallback.push( {
+						"fn": oInit.fnDrawCallback,
+						"sName": "user"
+					} );
+				}
+				
+				if ( typeof oInit.fnStateSaveCallback == 'function' )
+				{
+					oSettings.aoStateSave.push( {
+						"fn": oInit.fnStateSaveCallback,
+						"sName": "user"
+					} );
+				}
+				
+				if ( typeof oInit.fnStateLoadCallback == 'function' )
+				{
+					oSettings.aoStateLoad.push( {
+						"fn": oInit.fnStateLoadCallback,
+						"sName": "user"
+					} );
+				}
+				
+				if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
+					   oSettings.oFeatures.bSortClasses )
+				{
+					/* Enable sort classes for server-side processing. Safe to do it here, since server-side
+					 * processing must be enabled by the developer
+					 */
+					oSettings.aoDrawCallback.push( {
+						"fn": _fnSortingClasses,
+						"sName": "server_side_sort_classes"
+					} );
+				}
+				
+				if ( typeof oInit.bJQueryUI != 'undefined' && oInit.bJQueryUI )
+				{
+					/* Use the JUI classes object for display. You could clone the oStdClasses object if 
+					 * you want to have multiple tables with multiple independent classes 
+					 */
+					oSettings.oClasses = _oExt.oJUIClasses;
+					
+					if ( typeof oInit.sDom == 'undefined' )
+					{
+						/* Set the DOM to use a layout suitable for jQuery UI's theming */
+						oSettings.sDom = '<"H"lfr>t<"F"ip>';
+					}
+				}
+				
+				/* Calculate the scroll bar width and cache it for use later on */
+				if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
+				{
+					oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
+				}
+				
+				if ( typeof oInit.iDisplayStart != 'undefined' && 
+				     typeof oSettings.iInitDisplayStart == 'undefined' )
+				{
+					/* Display start point, taking into account the save saving */
+					oSettings.iInitDisplayStart = oInit.iDisplayStart;
+					oSettings._iDisplayStart = oInit.iDisplayStart;
+				}
+				
+				/* Must be done after everything which can be overridden by a cookie! */
+				if ( typeof oInit.bStateSave != 'undefined' )
+				{
+					oSettings.oFeatures.bStateSave = oInit.bStateSave;
+					_fnLoadState( oSettings, oInit );
+					oSettings.aoDrawCallback.push( {
+						"fn": _fnSaveState,
+						"sName": "state_save"
+					} );
+				}
+				
+				if ( typeof oInit.aaData != 'undefined' )
+				{
+					bUsePassedData = true;
+				}
+				
+				/* Backwards compatability */
+				/* aoColumns / aoData - remove at some point... */
+				if ( typeof oInit != 'undefined' && typeof oInit.aoData != 'undefined' )
+				{
+					oInit.aoColumns = oInit.aoData;
+				}
+				
+				/* Language definitions */
+				if ( typeof oInit.oLanguage != 'undefined' )
+				{
+					if ( typeof oInit.oLanguage.sUrl != 'undefined' && oInit.oLanguage.sUrl !== "" )
+					{
+						/* Get the language definitions from a file */
+						oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
+						$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) { 
+							_fnLanguageProcess( oSettings, json, true ); } );
+						bInitHandedOff = true;
+					}
+					else
+					{
+						_fnLanguageProcess( oSettings, oInit.oLanguage, false );
+					}
+				}
+				/* Warning: The _fnLanguageProcess function is async to the remainder of this function due
+				 * to the XHR. We use _bInitialised in _fnLanguageProcess() to check this the processing 
+				 * below is complete. The reason for spliting it like this is optimisation - we can fire
+				 * off the XHR (if needed) and then continue processing the data.
+				 */
+			}
+			else
+			{
+				/* Create a dummy object for quick manipulation later on. */
+				oInit = {};
+			}
+			
+			/*
+			 * Stripes
+			 * Add the strip classes now that we know which classes to apply - unless overruled
+			 */
+			if ( typeof oInit.asStripClasses == 'undefined' )
+			{
+				oSettings.asStripClasses.push( oSettings.oClasses.sStripOdd );
+				oSettings.asStripClasses.push( oSettings.oClasses.sStripEven );
+			}
+			
+			/* Remove row stripe classes if they are already on the table row */
+			var bStripeRemove = false;
+			var anRows = $('tbody>tr', this);
+			for ( i=0, iLen=oSettings.asStripClasses.length ; i<iLen ; i++ )
+			{
+				if ( anRows.filter(":lt(2)").hasClass( oSettings.asStripClasses[i]) )
+				{
+					bStripeRemove = true;
+					break;
+				}
+			}
+					
+			if ( bStripeRemove )
+			{
+				/* Store the classes which we are about to remove so they can be readded on destory */
+				oSettings.asDestoryStrips = [ '', '' ];
+				if ( $(anRows[0]).hasClass(oSettings.oClasses.sStripOdd) )
+				{
+					oSettings.asDestoryStrips[0] += oSettings.oClasses.sStripOdd+" ";
+				}
+				if ( $(anRows[0]).hasClass(oSettings.oClasses.sStripEven) )
+				{
+					oSettings.asDestoryStrips[0] += oSettings.oClasses.sStripEven;
+				}
+				if ( $(anRows[1]).hasClass(oSettings.oClasses.sStripOdd) )
+				{
+					oSettings.asDestoryStrips[1] += oSettings.oClasses.sStripOdd+" ";
+				}
+				if ( $(anRows[1]).hasClass(oSettings.oClasses.sStripEven) )
+				{
+					oSettings.asDestoryStrips[1] += oSettings.oClasses.sStripEven;
+				}
+				
+				anRows.removeClass( oSettings.asStripClasses.join(' ') );
+			}
+			
+			/*
+			 * Columns
+			 * See if we should load columns automatically or use defined ones
+			 */
+			var nThead = this.getElementsByTagName('thead');
+			var anThs = nThead.length===0 ? [] : _fnGetUniqueThs( nThead[0] );
+			var aoColumnsInit;
+			
+			/* If not given a column array, generate one with nulls */
+			if ( typeof oInit.aoColumns == 'undefined' )
+			{
+				aoColumnsInit = [];
+				for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
+				{
+					aoColumnsInit.push( null );
+				}
+			}
+			else
+			{
+				aoColumnsInit = oInit.aoColumns;
+			}
+			
+			/* Add the columns */
+			for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
+			{
+				/* Check if we have column visibilty state to restore */
+				if ( typeof oInit.saved_aoColumns != 'undefined' && oInit.saved_aoColumns.length == iLen )
+				{
+					if ( aoColumnsInit[i] === null )
+					{
+						aoColumnsInit[i] = {};
+					}
+					aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
+				}
+				
+				_fnAddColumn( oSettings, anThs ? anThs[i] : null );
+			}
+			
+			/* Add options from column definations */
+			if ( typeof oInit.aoColumnDefs != 'undefined' )
+			{
+				/* Loop over the column defs array - loop in reverse so first instace has priority */
+				for ( i=oInit.aoColumnDefs.length-1 ; i>=0 ; i-- )
+				{
+					/* Each column def can target multiple columns, as it is an array */
+					var aTargets = oInit.aoColumnDefs[i].aTargets;
+					if ( !$.isArray( aTargets ) )
+					{
+						_fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
+					}
+					for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
+					{
+						if ( typeof aTargets[j] == 'number' && aTargets[j] >= 0 )
+						{
+							/* 0+ integer, left to right column counting. We add columns which are unknown
+							 * automatically. Is this the right behaviour for this? We should at least
+							 * log it in future. We cannot do this for the negative or class targets, only here.
+							 */
+							while( oSettings.aoColumns.length <= aTargets[j] )
+							{
+								_fnAddColumn( oSettings );
+							}
+							_fnColumnOptions( oSettings, aTargets[j], oInit.aoColumnDefs[i] );
+						}
+						else if ( typeof aTargets[j] == 'number' && aTargets[j] < 0 )
+						{
+							/* Negative integer, right to left column counting */
+							_fnColumnOptions( oSettings, oSettings.aoColumns.length+aTargets[j], 
+								oInit.aoColumnDefs[i] );
+						}
+						else if ( typeof aTargets[j] == 'string' )
+						{
+							/* Class name matching on TH element */
+							for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
+							{
+								if ( aTargets[j] == "_all" ||
+								     oSettings.aoColumns[k].nTh.className.indexOf( aTargets[j] ) != -1 )
+								{
+									_fnColumnOptions( oSettings, k, oInit.aoColumnDefs[i] );
+								}
+							}
+						}
+					}
+				}
+			}
+			
+			/* Add options from column array - after the defs array so this has priority */
+			if ( typeof aoColumnsInit != 'undefined' )
+			{
+				for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
+				{
+					_fnColumnOptions( oSettings, i, aoColumnsInit[i] );
+				}
+			}
+			
+			/*
+			 * Sorting
+			 * Check the aaSorting array
+			 */
+			for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
+			{
+				if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
+				{
+					oSettings.aaSorting[i][0] = 0;
+				}
+				var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
+				
+				/* Add a default sorting index */
+				if ( typeof oSettings.aaSorting[i][2] == 'undefined' )
+				{
+					oSettings.aaSorting[i][2] = 0;
+				}
+				
+				/* If aaSorting is not defined, then we use the first indicator in asSorting */
+				if ( typeof oInit.aaSorting == "undefined" && 
+						 typeof oSettings.saved_aaSorting == "undefined" )
+				{
+					oSettings.aaSorting[i][1] = oColumn.asSorting[0];
+				}
+				
+				/* Set the current sorting index based on aoColumns.asSorting */
+				for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
+				{
+					if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
+					{
+						oSettings.aaSorting[i][2] = j;
+						break;
+					}
+				}
+			}
+				
+			/* Do a first pass on the sorting classes (allows any size changes to be taken into
+			 * account, and also will apply sorting disabled classes if disabled
+			 */
+			_fnSortingClasses( oSettings );
+			
+			/*
+			 * Final init
+			 * Sanity check that there is a thead and tbody. If not let's just create them
+			 */
+			if ( this.getElementsByTagName('thead').length === 0 )
+			{
+				this.appendChild( document.createElement( 'thead' ) );
+			}
+			
+			if ( this.getElementsByTagName('tbody').length === 0 )
+			{
+				this.appendChild( document.createElement( 'tbody' ) );
+			}
+			
+			oSettings.nTHead = this.getElementsByTagName('thead')[0];
+			oSettings.nTBody = this.getElementsByTagName('tbody')[0];
+			if ( this.getElementsByTagName('tfoot').length > 0 )
+			{
+				oSettings.nTFoot = this.getElementsByTagName('tfoot')[0];
+			}
+			
+			/* Check if there is data passing into the constructor */
+			if ( bUsePassedData )
+			{
+				for ( i=0 ; i<oInit.aaData.length ; i++ )
+				{
+					_fnAddData( oSettings, oInit.aaData[ i ] );
+				}
+			}
+			else
+			{
+				/* Grab the data from the page */
+				_fnGatherData( oSettings );
+			}
+			
+			/* Copy the data index array */
+			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+			
+			/* Initialisation complete - table can be drawn */
+			oSettings.bInitialised = true;
+			
+			/* Check if we need to initialise the table (it might not have been handed off to the
+			 * language processor)
+			 */
+			if ( bInitHandedOff === false )
+			{
+				_fnInitalise( oSettings );
+			}
+		});
+	};
+})(jQuery, window, document);
+

--- /dev/null
+++ b/media/js/jquery.dataTables.min.js
@@ -1,1 +1,143 @@
+/*
+ * File:        jquery.dataTables.min.js
+ * Version:     1.7.4
+ * Author:      Allan Jardine (www.sprymedia.co.uk)
+ * Info:        www.datatables.net
+ * 
+ * Copyright 2008-2010 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, as supplied with this software.
+ * 
+ * This source file is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ */
+(function(j,X,p){j.fn.dataTableSettings=[];var E=j.fn.dataTableSettings;j.fn.dataTableExt={};var n=j.fn.dataTableExt;n.sVersion="1.7.4";n.sErrMode="alert";n.iApiIndex=0;n.oApi={};n.afnFiltering=[];n.aoFeatures=[];n.ofnSearch={};n.afnSortData=[];n.oStdClasses={sPagePrevEnabled:"paginate_enabled_previous",sPagePrevDisabled:"paginate_disabled_previous",sPageNextEnabled:"paginate_enabled_next",sPageNextDisabled:"paginate_disabled_next",sPageJUINext:"",sPageJUIPrev:"",sPageButton:"paginate_button",sPageButtonActive:"paginate_active",
+sPageButtonStaticDisabled:"paginate_button",sPageFirst:"first",sPagePrevious:"previous",sPageNext:"next",sPageLast:"last",sStripOdd:"odd",sStripEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",
+sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sFooterTH:""};n.oJUIClasses={sPagePrevEnabled:"fg-button ui-button ui-state-default ui-corner-left",sPagePrevDisabled:"fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
+sPageNextEnabled:"fg-button ui-button ui-state-default ui-corner-right",sPageNextDisabled:"fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",sPageJUINext:"ui-icon ui-icon-circle-arrow-e",sPageJUIPrev:"ui-icon ui-icon-circle-arrow-w",sPageButton:"fg-button ui-button ui-state-default",sPageButtonActive:"fg-button ui-button ui-state-default ui-state-disabled",sPageButtonStaticDisabled:"fg-button ui-button ui-state-default ui-state-disabled",sPageFirst:"first ui-corner-tl ui-corner-bl",
+sPagePrevious:"previous",sPageNext:"next",sPageLast:"last ui-corner-tr ui-corner-br",sStripOdd:"odd",sStripEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"ui-state-default",sSortDesc:"ui-state-default",sSortable:"ui-state-default",sSortableAsc:"ui-state-default",
+sSortableDesc:"ui-state-default",sSortableNone:"ui-state-default",sSortColumn:"sorting_",sSortJUIAsc:"css_right ui-icon ui-icon-triangle-1-n",sSortJUIDesc:"css_right ui-icon ui-icon-triangle-1-s",sSortJUI:"css_right ui-icon ui-icon-carat-2-n-s",sSortJUIAscAllowed:"css_right ui-icon ui-icon-carat-1-n",sSortJUIDescAllowed:"css_right ui-icon ui-icon-carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead ui-state-default",sScrollHeadInner:"dataTables_scrollHeadInner",
+sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot ui-state-default",sScrollFootInner:"dataTables_scrollFootInner",sFooterTH:"ui-state-default"};n.oPagination={two_button:{fnInit:function(g,l,r){var s,v,y;if(g.bJUI){s=p.createElement("a");v=p.createElement("a");y=p.createElement("span");y.className=g.oClasses.sPageJUINext;v.appendChild(y);y=p.createElement("span");y.className=g.oClasses.sPageJUIPrev;s.appendChild(y)}else{s=p.createElement("div");v=p.createElement("div")}s.className=
+g.oClasses.sPagePrevDisabled;v.className=g.oClasses.sPageNextDisabled;s.title=g.oLanguage.oPaginate.sPrevious;v.title=g.oLanguage.oPaginate.sNext;l.appendChild(s);l.appendChild(v);j(s).click(function(){g.oApi._fnPageChange(g,"previous")&&r(g)});j(v).click(function(){g.oApi._fnPageChange(g,"next")&&r(g)});j(s).bind("selectstart",function(){return false});j(v).bind("selectstart",function(){return false});if(g.sTableId!==""&&typeof g.aanFeatures.p=="undefined"){l.setAttribute("id",g.sTableId+"_paginate");
+s.setAttribute("id",g.sTableId+"_previous");v.setAttribute("id",g.sTableId+"_next")}},fnUpdate:function(g){if(g.aanFeatures.p)for(var l=g.aanFeatures.p,r=0,s=l.length;r<s;r++)if(l[r].childNodes.length!==0){l[r].childNodes[0].className=g._iDisplayStart===0?g.oClasses.sPagePrevDisabled:g.oClasses.sPagePrevEnabled;l[r].childNodes[1].className=g.fnDisplayEnd()==g.fnRecordsDisplay()?g.oClasses.sPageNextDisabled:g.oClasses.sPageNextEnabled}}},iFullNumbersShowPages:5,full_numbers:{fnInit:function(g,l,r){var s=
+p.createElement("span"),v=p.createElement("span"),y=p.createElement("span"),D=p.createElement("span"),w=p.createElement("span");s.innerHTML=g.oLanguage.oPaginate.sFirst;v.innerHTML=g.oLanguage.oPaginate.sPrevious;D.innerHTML=g.oLanguage.oPaginate.sNext;w.innerHTML=g.oLanguage.oPaginate.sLast;var x=g.oClasses;s.className=x.sPageButton+" "+x.sPageFirst;v.className=x.sPageButton+" "+x.sPagePrevious;D.className=x.sPageButton+" "+x.sPageNext;w.className=x.sPageButton+" "+x.sPageLast;l.appendChild(s);l.appendChild(v);
+l.appendChild(y);l.appendChild(D);l.appendChild(w);j(s).click(function(){g.oApi._fnPageChange(g,"first")&&r(g)});j(v).click(function(){g.oApi._fnPageChange(g,"previous")&&r(g)});j(D).click(function(){g.oApi._fnPageChange(g,"next")&&r(g)});j(w).click(function(){g.oApi._fnPageChange(g,"last")&&r(g)});j("span",l).bind("mousedown",function(){return false}).bind("selectstart",function(){return false});if(g.sTableId!==""&&typeof g.aanFeatures.p=="undefined"){l.setAttribute("id",g.sTableId+"_paginate");
+s.setAttribute("id",g.sTableId+"_first");v.setAttribute("id",g.sTableId+"_previous");D.setAttribute("id",g.sTableId+"_next");w.setAttribute("id",g.sTableId+"_last")}},fnUpdate:function(g,l){if(g.aanFeatures.p){var r=n.oPagination.iFullNumbersShowPages,s=Math.floor(r/2),v=Math.ceil(g.fnRecordsDisplay()/g._iDisplayLength),y=Math.ceil(g._iDisplayStart/g._iDisplayLength)+1,D="",w,x=g.oClasses;if(v<r){s=1;w=v}else if(y<=s){s=1;w=r}else if(y>=v-s){s=v-r+1;w=v}else{s=y-Math.ceil(r/2)+1;w=s+r-1}for(r=s;r<=
+w;r++)D+=y!=r?'<span class="'+x.sPageButton+'">'+r+"</span>":'<span class="'+x.sPageButtonActive+'">'+r+"</span>";w=g.aanFeatures.p;var z,C=function(){g._iDisplayStart=(this.innerHTML*1-1)*g._iDisplayLength;l(g);return false},L=function(){return false};r=0;for(s=w.length;r<s;r++)if(w[r].childNodes.length!==0){z=j("span:eq(2)",w[r]);z.html(D);j("span",z).click(C).bind("mousedown",L).bind("selectstart",L);z=w[r].getElementsByTagName("span");z=[z[0],z[1],z[z.length-2],z[z.length-1]];j(z).removeClass(x.sPageButton+
+" "+x.sPageButtonActive+" "+x.sPageButtonStaticDisabled);if(y==1){z[0].className+=" "+x.sPageButtonStaticDisabled;z[1].className+=" "+x.sPageButtonStaticDisabled}else{z[0].className+=" "+x.sPageButton;z[1].className+=" "+x.sPageButton}if(v===0||y==v||g._iDisplayLength==-1){z[2].className+=" "+x.sPageButtonStaticDisabled;z[3].className+=" "+x.sPageButtonStaticDisabled}else{z[2].className+=" "+x.sPageButton;z[3].className+=" "+x.sPageButton}}}}}};n.oSort={"string-asc":function(g,l){g=g.toLowerCase();
+l=l.toLowerCase();return g<l?-1:g>l?1:0},"string-desc":function(g,l){g=g.toLowerCase();l=l.toLowerCase();return g<l?1:g>l?-1:0},"html-asc":function(g,l){g=g.replace(/<.*?>/g,"").toLowerCase();l=l.replace(/<.*?>/g,"").toLowerCase();return g<l?-1:g>l?1:0},"html-desc":function(g,l){g=g.replace(/<.*?>/g,"").toLowerCase();l=l.replace(/<.*?>/g,"").toLowerCase();return g<l?1:g>l?-1:0},"date-asc":function(g,l){g=Date.parse(g);l=Date.parse(l);if(isNaN(g)||g==="")g=Date.parse("01/01/1970 00:00:00");if(isNaN(l)||
+l==="")l=Date.parse("01/01/1970 00:00:00");return g-l},"date-desc":function(g,l){g=Date.parse(g);l=Date.parse(l);if(isNaN(g)||g==="")g=Date.parse("01/01/1970 00:00:00");if(isNaN(l)||l==="")l=Date.parse("01/01/1970 00:00:00");return l-g},"numeric-asc":function(g,l){return(g=="-"||g===""?0:g*1)-(l=="-"||l===""?0:l*1)},"numeric-desc":function(g,l){return(l=="-"||l===""?0:l*1)-(g=="-"||g===""?0:g*1)}};n.aTypes=[function(g){if(g.length===0)return"numeric";var l,r=false;l=g.charAt(0);if("0123456789-".indexOf(l)==
+-1)return null;for(var s=1;s<g.length;s++){l=g.charAt(s);if("0123456789.".indexOf(l)==-1)return null;if(l=="."){if(r)return null;r=true}}return"numeric"},function(g){var l=Date.parse(g);if(l!==null&&!isNaN(l)||g.length===0)return"date";return null},function(g){if(g.indexOf("<")!=-1&&g.indexOf(">")!=-1)return"html";return null}];n.fnVersionCheck=function(g){var l=function(w,x){for(;w.length<x;)w+="0";return w},r=n.sVersion.split(".");g=g.split(".");for(var s="",v="",y=0,D=g.length;y<D;y++){s+=l(r[y],
+3);v+=l(g[y],3)}return parseInt(s,10)>=parseInt(v,10)};n._oExternConfig={iNextUnique:0};j.fn.dataTable=function(g){function l(){this.fnRecordsTotal=function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsTotal,10):this.aiDisplayMaster.length};this.fnRecordsDisplay=function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsDisplay,10):this.aiDisplay.length};this.fnDisplayEnd=function(){return this.oFeatures.bServerSide?this.oFeatures.bPaginate===false||this._iDisplayLength==-1?
+this._iDisplayStart+this.aiDisplay.length:Math.min(this._iDisplayStart+this._iDisplayLength,this._iRecordsDisplay):this._iDisplayEnd};this.sInstance=this.oInstance=null;this.oFeatures={bPaginate:true,bLengthChange:true,bFilter:true,bSort:true,bInfo:true,bAutoWidth:true,bProcessing:false,bSortClasses:true,bStateSave:false,bServerSide:false};this.oScroll={sX:"",sXInner:"",sY:"",bCollapse:false,bInfinite:false,iLoadGap:100,iBarWidth:0};this.aanFeatures=[];this.oLanguage={sProcessing:"Processing...",
+sLengthMenu:"Show _MENU_ entries",sZeroRecords:"No matching records found",sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sSearch:"Search:",sUrl:"",oPaginate:{sFirst:"First",sPrevious:"Previous",sNext:"Next",sLast:"Last"},fnInfoCallback:null};this.aoData=[];this.aiDisplay=[];this.aiDisplayMaster=[];this.aoColumns=[];this.iNextId=0;this.asDataSearch=
+[];this.oPreviousSearch={sSearch:"",bRegex:false,bSmart:true};this.aoPreSearchCols=[];this.aaSorting=[[0,"asc",0]];this.aaSortingFixed=null;this.asStripClasses=[];this.asDestoryStrips=[];this.sDestroyWidth=0;this.fnFooterCallback=this.fnHeaderCallback=this.fnRowCallback=null;this.aoDrawCallback=[];this.fnInitComplete=null;this.sTableId="";this.nTableWrapper=this.nTBody=this.nTFoot=this.nTHead=this.nTable=null;this.bInitialised=false;this.aoOpenRows=[];this.sDom="lfrtip";this.sPaginationType="two_button";
+this.iCookieDuration=7200;this.sCookiePrefix="SpryMedia_DataTables_";this.fnCookieCallback=null;this.aoStateSave=[];this.aoStateLoad=[];this.sAjaxSource=this.oLoadedState=null;this.bAjaxDataGet=true;this.fnServerData=function(a,b,c){j.ajax({url:a,data:b,success:c,dataType:"json",cache:false,error:function(d,f){f=="parsererror"&&alert("DataTables warning: JSON data from server could not be parsed. This is caused by a JSON formatting error.")}})};this.fnFormatNumber=function(a){if(a<1E3)return a;else{var b=
+a+"";a=b.split("");var c="";b=b.length;for(var d=0;d<b;d++){if(d%3===0&&d!==0)c=","+c;c=a[b-d-1]+c}}return c};this.aLengthMenu=[10,25,50,100];this.bDrawing=this.iDraw=0;this.iDrawError=-1;this._iDisplayLength=10;this._iDisplayStart=0;this._iDisplayEnd=10;this._iRecordsDisplay=this._iRecordsTotal=0;this.bJUI=false;this.oClasses=n.oStdClasses;this.bSorted=this.bFiltered=false;this.oInit=null}function r(a){return function(){var b=[B(this[n.iApiIndex])].concat(Array.prototype.slice.call(arguments));return n.oApi[a].apply(this,
+b)}}function s(a){var b,c;if(a.bInitialised===false)setTimeout(function(){s(a)},200);else{pa(a);z(a);K(a,true);a.oFeatures.bAutoWidth&&Y(a);b=0;for(c=a.aoColumns.length;b<c;b++)if(a.aoColumns[b].sWidth!==null)a.aoColumns[b].nTh.style.width=u(a.aoColumns[b].sWidth);if(a.oFeatures.bSort)O(a);else{a.aiDisplay=a.aiDisplayMaster.slice();F(a);C(a)}if(a.sAjaxSource!==null&&!a.oFeatures.bServerSide)a.fnServerData.call(a.oInstance,a.sAjaxSource,[],function(d){for(b=0;b<d.aaData.length;b++)w(a,d.aaData[b]);
+a.iInitDisplayStart=a._iDisplayStart;if(a.oFeatures.bSort)O(a);else{a.aiDisplay=a.aiDisplayMaster.slice();F(a);C(a)}K(a,false);typeof a.fnInitComplete=="function"&&a.fnInitComplete.call(a.oInstance,a,d)});else a.oFeatures.bServerSide||K(a,false)}}function v(a,b,c){o(a.oLanguage,b,"sProcessing");o(a.oLanguage,b,"sLengthMenu");o(a.oLanguage,b,"sEmptyTable");o(a.oLanguage,b,"sZeroRecords");o(a.oLanguage,b,"sInfo");o(a.oLanguage,b,"sInfoEmpty");o(a.oLanguage,b,"sInfoFiltered");o(a.oLanguage,b,"sInfoPostFix");
+o(a.oLanguage,b,"sSearch");if(typeof b.oPaginate!="undefined"){o(a.oLanguage.oPaginate,b.oPaginate,"sFirst");o(a.oLanguage.oPaginate,b.oPaginate,"sPrevious");o(a.oLanguage.oPaginate,b.oPaginate,"sNext");o(a.oLanguage.oPaginate,b.oPaginate,"sLast")}typeof b.sEmptyTable=="undefined"&&typeof b.sZeroRecords!="undefined"&&o(a.oLanguage,b,"sZeroRecords","sEmptyTable");c&&s(a)}function y(a,b){a.aoColumns[a.aoColumns.length++]={sType:null,_bAutoType:true,bVisible:true,bSearchable:true,bSortable:true,asSorting:["asc",
+"desc"],sSortingClass:a.oClasses.sSortable,sSortingClassJUI:a.oClasses.sSortJUI,sTitle:b?b.innerHTML:"",sName:"",sWidth:null,sWidthOrig:null,sClass:null,fnRender:null,bUseRendered:true,iDataSort:a.aoColumns.length-1,sSortDataType:"std",nTh:b?b:p.createElement("th"),nTf:null};b=a.aoColumns.length-1;if(typeof a.aoPreSearchCols[b]=="undefined"||a.aoPreSearchCols[b]===null)a.aoPreSearchCols[b]={sSearch:"",bRegex:false,bSmart:true};else{if(typeof a.aoPreSearchCols[b].bRegex=="undefined")a.aoPreSearchCols[b].bRegex=
+true;if(typeof a.aoPreSearchCols[b].bSmart=="undefined")a.aoPreSearchCols[b].bSmart=true}D(a,b,null)}function D(a,b,c){b=a.aoColumns[b];if(typeof c!="undefined"&&c!==null){if(typeof c.sType!="undefined"){b.sType=c.sType;b._bAutoType=false}o(b,c,"bVisible");o(b,c,"bSearchable");o(b,c,"bSortable");o(b,c,"sTitle");o(b,c,"sName");o(b,c,"sWidth");o(b,c,"sWidth","sWidthOrig");o(b,c,"sClass");o(b,c,"fnRender");o(b,c,"bUseRendered");o(b,c,"iDataSort");o(b,c,"asSorting");o(b,c,"sSortDataType")}if(!a.oFeatures.bSort)b.bSortable=
+false;if(!b.bSortable||j.inArray("asc",b.asSorting)==-1&&j.inArray("desc",b.asSorting)==-1){b.sSortingClass=a.oClasses.sSortableNone;b.sSortingClassJUI=""}else if(j.inArray("asc",b.asSorting)!=-1&&j.inArray("desc",b.asSorting)==-1){b.sSortingClass=a.oClasses.sSortableAsc;b.sSortingClassJUI=a.oClasses.sSortJUIAscAllowed}else if(j.inArray("asc",b.asSorting)==-1&&j.inArray("desc",b.asSorting)!=-1){b.sSortingClass=a.oClasses.sSortableDesc;b.sSortingClassJUI=a.oClasses.sSortJUIDescAllowed}}function w(a,
+b){if(b.length!=a.aoColumns.length&&a.iDrawError!=a.iDraw){I(a,0,"Added data (size "+b.length+") does not match known number of columns ("+a.aoColumns.length+")");a.iDrawError=a.iDraw;return-1}b=b.slice();var c=a.aoData.length;a.aoData.push({nTr:p.createElement("tr"),_iId:a.iNextId++,_aData:b,_anHidden:[],_sRowStripe:""});for(var d,f,e=0;e<b.length;e++){d=p.createElement("td");if(b[e]===null)b[e]="";if(typeof a.aoColumns[e].fnRender=="function"){f=a.aoColumns[e].fnRender({iDataRow:c,iDataColumn:e,
+aData:b,oSettings:a});d.innerHTML=f;if(a.aoColumns[e].bUseRendered)a.aoData[c]._aData[e]=f}else d.innerHTML=b[e];if(typeof b[e]!="string")b[e]+="";b[e]=j.trim(b[e]);if(a.aoColumns[e].sClass!==null)d.className=a.aoColumns[e].sClass;if(a.aoColumns[e]._bAutoType&&a.aoColumns[e].sType!="string"){f=Z(a.aoData[c]._aData[e]);if(a.aoColumns[e].sType===null)a.aoColumns[e].sType=f;else if(a.aoColumns[e].sType!=f)a.aoColumns[e].sType="string"}if(a.aoColumns[e].bVisible){a.aoData[c].nTr.appendChild(d);a.aoData[c]._anHidden[e]=
+null}else a.aoData[c]._anHidden[e]=d}a.aiDisplayMaster.push(c);return c}function x(a){var b,c,d,f,e,i,h,k;if(a.sAjaxSource===null){h=a.nTBody.childNodes;b=0;for(c=h.length;b<c;b++)if(h[b].nodeName.toUpperCase()=="TR"){i=a.aoData.length;a.aoData.push({nTr:h[b],_iId:a.iNextId++,_aData:[],_anHidden:[],_sRowStripe:""});a.aiDisplayMaster.push(i);k=a.aoData[i]._aData;i=h[b].childNodes;d=e=0;for(f=i.length;d<f;d++)if(i[d].nodeName.toUpperCase()=="TD"){k[e]=j.trim(i[d].innerHTML);e++}}}h=R(a);i=[];b=0;for(c=
+h.length;b<c;b++){d=0;for(f=h[b].childNodes.length;d<f;d++){e=h[b].childNodes[d];e.nodeName.toUpperCase()=="TD"&&i.push(e)}}i.length!=h.length*a.aoColumns.length&&I(a,1,"Unexpected number of TD elements. Expected "+h.length*a.aoColumns.length+" and got "+i.length+". DataTables does not support rowspan / colspan in the table body, and there must be one cell for each row/column combination.");h=0;for(d=a.aoColumns.length;h<d;h++){if(a.aoColumns[h].sTitle===null)a.aoColumns[h].sTitle=a.aoColumns[h].nTh.innerHTML;
+f=a.aoColumns[h]._bAutoType;e=typeof a.aoColumns[h].fnRender=="function";k=a.aoColumns[h].sClass!==null;var m=a.aoColumns[h].bVisible,q,t;if(f||e||k||!m){b=0;for(c=a.aoData.length;b<c;b++){q=i[b*d+h];if(f)if(a.aoColumns[h].sType!="string"){t=Z(a.aoData[b]._aData[h]);if(a.aoColumns[h].sType===null)a.aoColumns[h].sType=t;else if(a.aoColumns[h].sType!=t)a.aoColumns[h].sType="string"}if(e){t=a.aoColumns[h].fnRender({iDataRow:b,iDataColumn:h,aData:a.aoData[b]._aData,oSettings:a});q.innerHTML=t;if(a.aoColumns[h].bUseRendered)a.aoData[b]._aData[h]=
+t}if(k)q.className+=" "+a.aoColumns[h].sClass;if(m)a.aoData[b]._anHidden[h]=null;else{a.aoData[b]._anHidden[h]=q;q.parentNode.removeChild(q)}}}}}function z(a){var b,c,d,f=0;if(a.nTHead.getElementsByTagName("th").length!==0){b=0;for(d=a.aoColumns.length;b<d;b++){c=a.aoColumns[b].nTh;if(a.aoColumns[b].bVisible){if(a.aoColumns[b].sTitle!=c.innerHTML)c.innerHTML=a.aoColumns[b].sTitle}else{c.parentNode.removeChild(c);f++}}}else{f=p.createElement("tr");b=0;for(d=a.aoColumns.length;b<d;b++){c=a.aoColumns[b].nTh;
+c.innerHTML=a.aoColumns[b].sTitle;if(a.aoColumns[b].bVisible){if(a.aoColumns[b].sClass!==null)c.className=a.aoColumns[b].sClass;f.appendChild(c)}}j(a.nTHead).html("")[0].appendChild(f)}if(a.bJUI){b=0;for(d=a.aoColumns.length;b<d;b++){c=a.aoColumns[b].nTh;f=p.createElement("div");f.className=a.oClasses.sSortJUIWrapper;j(c).contents().appendTo(f);f.appendChild(p.createElement("span"));c.appendChild(f)}}d=function(){this.onselectstart=function(){return false};return false};if(a.oFeatures.bSort)for(b=
+0;b<a.aoColumns.length;b++)if(a.aoColumns[b].bSortable!==false){$(a,a.aoColumns[b].nTh,b);j(a.aoColumns[b].nTh).mousedown(d)}else j(a.aoColumns[b].nTh).addClass(a.oClasses.sSortableNone);if(a.nTFoot!==null){f=0;c=a.nTFoot.getElementsByTagName("th");b=0;for(d=c.length;b<d;b++)if(typeof a.aoColumns[b]!="undefined"){a.aoColumns[b].nTf=c[b-f];if(a.oClasses.sFooterTH!=="")a.aoColumns[b].nTf.className+=" "+a.oClasses.sFooterTH;if(!a.aoColumns[b].bVisible){c[b-f].parentNode.removeChild(c[b-f]);f++}}}}function C(a){var b,
+c,d=[],f=0,e=false;b=a.asStripClasses.length;c=a.aoOpenRows.length;a.bDrawing=true;if(typeof a.iInitDisplayStart!="undefined"&&a.iInitDisplayStart!=-1){a._iDisplayStart=a.oFeatures.bServerSide?a.iInitDisplayStart:a.iInitDisplayStart>=a.fnRecordsDisplay()?0:a.iInitDisplayStart;a.iInitDisplayStart=-1;F(a)}if(!(a.oFeatures.bServerSide&&!qa(a))){a.oFeatures.bServerSide||a.iDraw++;if(a.aiDisplay.length!==0){var i=a._iDisplayStart,h=a._iDisplayEnd;if(a.oFeatures.bServerSide){i=0;h=a.aoData.length}for(i=
+i;i<h;i++){var k=a.aoData[a.aiDisplay[i]],m=k.nTr;if(b!==0){var q=a.asStripClasses[f%b];if(k._sRowStripe!=q){j(m).removeClass(k._sRowStripe).addClass(q);k._sRowStripe=q}}if(typeof a.fnRowCallback=="function"){m=a.fnRowCallback.call(a.oInstance,m,a.aoData[a.aiDisplay[i]]._aData,f,i);if(!m&&!e){I(a,0,"A node was not returned by fnRowCallback");e=true}}d.push(m);f++;if(c!==0)for(k=0;k<c;k++)m==a.aoOpenRows[k].nParent&&d.push(a.aoOpenRows[k].nTr)}}else{d[0]=p.createElement("tr");if(typeof a.asStripClasses[0]!=
+"undefined")d[0].className=a.asStripClasses[0];e=p.createElement("td");e.setAttribute("valign","top");e.colSpan=S(a);e.className=a.oClasses.sRowEmpty;e.innerHTML=typeof a.oLanguage.sEmptyTable!="undefined"&&a.fnRecordsTotal()===0?a.oLanguage.sEmptyTable:a.oLanguage.sZeroRecords.replace("_MAX_",a.fnFormatNumber(a.fnRecordsTotal()));d[f].appendChild(e)}typeof a.fnHeaderCallback=="function"&&a.fnHeaderCallback.call(a.oInstance,j(">tr",a.nTHead)[0],U(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay);
+typeof a.fnFooterCallback=="function"&&a.fnFooterCallback.call(a.oInstance,j(">tr",a.nTFoot)[0],U(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay);f=p.createDocumentFragment();b=p.createDocumentFragment();if(a.nTBody){e=a.nTBody.parentNode;b.appendChild(a.nTBody);if(!a.oScroll.bInfinite||!a._bInitComplete||a.bSorted||a.bFiltered){c=a.nTBody.childNodes;for(b=c.length-1;b>=0;b--)c[b].parentNode.removeChild(c[b])}b=0;for(c=d.length;b<c;b++)f.appendChild(d[b]);a.nTBody.appendChild(f);e!==null&&e.appendChild(a.nTBody)}b=
+0;for(c=a.aoDrawCallback.length;b<c;b++)a.aoDrawCallback[b].fn.call(a.oInstance,a);a.bSorted=false;a.bFiltered=false;a.bDrawing=false;if(typeof a._bInitComplete=="undefined"){a._bInitComplete=true;if(typeof a.fnInitComplete=="function"&&(a.oFeatures.bServerSide||a.sAjaxSource===null))a.fnInitComplete.call(a.oInstance,a)}}}function L(a){if(a.oFeatures.bSort)O(a,a.oPreviousSearch);else if(a.oFeatures.bFilter)P(a,a.oPreviousSearch);else{F(a);C(a)}}function qa(a){if(a.bAjaxDataGet){K(a,true);var b=a.aoColumns.length,
+c=[],d;a.iDraw++;c.push({name:"sEcho",value:a.iDraw});c.push({name:"iColumns",value:b});c.push({name:"sColumns",value:aa(a)});c.push({name:"iDisplayStart",value:a._iDisplayStart});c.push({name:"iDisplayLength",value:a.oFeatures.bPaginate!==false?a._iDisplayLength:-1});var f=[];for(d=0;d<b;d++)f.push(a.aoColumns[d].sName);c.push({name:"sNames",value:f.join(",")});if(a.oFeatures.bFilter!==false){c.push({name:"sSearch",value:a.oPreviousSearch.sSearch});c.push({name:"bRegex",value:a.oPreviousSearch.bRegex});
+for(d=0;d<b;d++){c.push({name:"sSearch_"+d,value:a.aoPreSearchCols[d].sSearch});c.push({name:"bRegex_"+d,value:a.aoPreSearchCols[d].bRegex});c.push({name:"bSearchable_"+d,value:a.aoColumns[d].bSearchable})}}if(a.oFeatures.bSort!==false){f=a.aaSortingFixed!==null?a.aaSortingFixed.length:0;var e=a.aaSorting.length;c.push({name:"iSortingCols",value:f+e});for(d=0;d<f;d++){c.push({name:"iSortCol_"+d,value:a.aaSortingFixed[d][0]});c.push({name:"sSortDir_"+d,value:a.aaSortingFixed[d][1]})}for(d=0;d<e;d++){c.push({name:"iSortCol_"+
+(d+f),value:a.aaSorting[d][0]});c.push({name:"sSortDir_"+(d+f),value:a.aaSorting[d][1]})}for(d=0;d<b;d++)c.push({name:"bSortable_"+d,value:a.aoColumns[d].bSortable})}a.fnServerData.call(a.oInstance,a.sAjaxSource,c,function(i){ra(a,i)});return false}else return true}function ra(a,b){if(typeof b.sEcho!="undefined")if(b.sEcho*1<a.iDraw)return;else a.iDraw=b.sEcho*1;if(!a.oScroll.bInfinite||a.oScroll.bInfinite&&(a.bSorted||a.bFiltered))ba(a);a._iRecordsTotal=b.iTotalRecords;a._iRecordsDisplay=b.iTotalDisplayRecords;
+var c=aa(a);if(c=typeof b.sColumns!="undefined"&&c!==""&&b.sColumns!=c)var d=sa(a,b.sColumns);for(var f=0,e=b.aaData.length;f<e;f++)if(c){for(var i=[],h=0,k=a.aoColumns.length;h<k;h++)i.push(b.aaData[f][d[h]]);w(a,i)}else w(a,b.aaData[f]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=false;C(a);a.bAjaxDataGet=true;K(a,false)}function pa(a){var b=p.createElement("div");a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=p.createElement("div");a.nTableWrapper.className=a.oClasses.sWrapper;
+a.sTableId!==""&&a.nTableWrapper.setAttribute("id",a.sTableId+"_wrapper");for(var c=a.nTableWrapper,d=a.sDom.split(""),f,e,i,h,k,m,q,t=0;t<d.length;t++){e=0;i=d[t];if(i=="<"){h=p.createElement("div");k=d[t+1];if(k=="'"||k=='"'){m="";for(q=2;d[t+q]!=k;){m+=d[t+q];q++}if(m=="H")m="fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix";else if(m=="F")m="fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix";if(m.indexOf(".")!=-1){k=m.split(".");
+h.setAttribute("id",k[0].substr(1,k[0].length-1));h.className=k[1]}else if(m.charAt(0)=="#")h.setAttribute("id",m.substr(1,m.length-1));else h.className=m;t+=q}c.appendChild(h);c=h}else if(i==">")c=c.parentNode;else if(i=="l"&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange){f=ta(a);e=1}else if(i=="f"&&a.oFeatures.bFilter){f=ua(a);e=1}else if(i=="r"&&a.oFeatures.bProcessing){f=va(a);e=1}else if(i=="t"){f=wa(a);e=1}else if(i=="i"&&a.oFeatures.bInfo){f=xa(a);e=1}else if(i=="p"&&a.oFeatures.bPaginate){f=
+ya(a);e=1}else if(n.aoFeatures.length!==0){h=n.aoFeatures;q=0;for(k=h.length;q<k;q++)if(i==h[q].cFeature){if(f=h[q].fnInit(a))e=1;break}}if(e==1&&f!==null){if(typeof a.aanFeatures[i]!="object")a.aanFeatures[i]=[];a.aanFeatures[i].push(f);c.appendChild(f)}}b.parentNode.replaceChild(a.nTableWrapper,b)}function wa(a){if(a.oScroll.sX===""&&a.oScroll.sY==="")return a.nTable;var b=p.createElement("div"),c=p.createElement("div"),d=p.createElement("div"),f=p.createElement("div"),e=p.createElement("div"),
+i=p.createElement("div"),h=a.nTable.cloneNode(false),k=a.nTable.cloneNode(false),m=a.nTable.getElementsByTagName("thead")[0],q=a.nTable.getElementsByTagName("tfoot").length===0?null:a.nTable.getElementsByTagName("tfoot")[0],t=typeof g.bJQueryUI!="undefined"&&g.bJQueryUI?n.oJUIClasses:n.oStdClasses;c.appendChild(d);e.appendChild(i);f.appendChild(a.nTable);b.appendChild(c);b.appendChild(f);d.appendChild(h);h.appendChild(m);if(q!==null){b.appendChild(e);i.appendChild(k);k.appendChild(q)}b.className=
+t.sScrollWrapper;c.className=t.sScrollHead;d.className=t.sScrollHeadInner;f.className=t.sScrollBody;e.className=t.sScrollFoot;i.className=t.sScrollFootInner;c.style.overflow="hidden";c.style.position="relative";e.style.overflow="hidden";f.style.overflow="auto";c.style.border="0";e.style.border="0";d.style.width="150%";h.removeAttribute("id");h.style.marginLeft="0";a.nTable.style.marginLeft="0";if(q!==null){k.removeAttribute("id");k.style.marginLeft="0"}d=j(">caption",a.nTable);i=0;for(k=d.length;i<
+k;i++)h.appendChild(d[i]);if(a.oScroll.sX!==""){c.style.width=u(a.oScroll.sX);f.style.width=u(a.oScroll.sX);if(q!==null)e.style.width=u(a.oScroll.sX);j(f).scroll(function(){c.scrollLeft=this.scrollLeft;if(q!==null)e.scrollLeft=this.scrollLeft})}if(a.oScroll.sY!=="")f.style.height=u(a.oScroll.sY);a.aoDrawCallback.push({fn:za,sName:"scrolling"});a.oScroll.bInfinite&&j(f).scroll(function(){if(!a.bDrawing)if(j(this).scrollTop()+j(this).height()>j(a.nTable).height()-a.oScroll.iLoadGap)if(a.fnDisplayEnd()<
+a.fnRecordsDisplay()){ca(a,"next");F(a);C(a)}});a.nScrollHead=c;a.nScrollFoot=e;return b}function za(a){var b=a.nScrollHead.getElementsByTagName("div")[0],c=b.getElementsByTagName("table")[0],d=a.nTable.parentNode,f,e,i,h,k,m,q,t,H=[];i=a.nTable.getElementsByTagName("thead");i.length>0&&a.nTable.removeChild(i[0]);if(a.nTFoot!==null){k=a.nTable.getElementsByTagName("tfoot");k.length>0&&a.nTable.removeChild(k[0])}i=a.nTHead.cloneNode(true);a.nTable.insertBefore(i,a.nTable.childNodes[0]);if(a.nTFoot!==
+null){k=a.nTFoot.cloneNode(true);a.nTable.insertBefore(k,a.nTable.childNodes[1])}var J=da(i);f=0;for(e=J.length;f<e;f++){q=ea(a,f);J[f].style.width=a.aoColumns[q].sWidth}a.nTFoot!==null&&M(function(A){A.style.width=""},k.getElementsByTagName("tr"));f=j(a.nTable).outerWidth();if(a.oScroll.sX===""){a.nTable.style.width="100%";if(j.browser.msie&&j.browser.version<=7)a.nTable.style.width=u(j(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else if(a.oScroll.sXInner!=="")a.nTable.style.width=u(a.oScroll.sXInner);
+else if(f==j(d).width()&&j(d).height()<j(a.nTable).height()){a.nTable.style.width=u(f-a.oScroll.iBarWidth);if(j(a.nTable).outerWidth()>f-a.oScroll.iBarWidth)a.nTable.style.width=u(f)}else a.nTable.style.width=u(f);f=j(a.nTable).outerWidth();e=a.nTHead.getElementsByTagName("tr");i=i.getElementsByTagName("tr");M(function(A,G){m=A.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth="0";m.borderBottomWidth="0";m.height=0;t=j(A).width();G.style.width=u(t);H.push(t)},i,e);j(i).height(0);if(a.nTFoot!==
+null){h=k.getElementsByTagName("tr");k=a.nTFoot.getElementsByTagName("tr");M(function(A,G){m=A.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth="0";m.borderBottomWidth="0";t=j(A).width();G.style.width=u(t);H.push(t)},h,k);j(h).height(0)}M(function(A){A.innerHTML="";A.style.width=u(H.shift())},i);a.nTFoot!==null&&M(function(A){A.innerHTML="";A.style.width=u(H.shift())},h);if(j(a.nTable).outerWidth()<f)if(a.oScroll.sX==="")I(a,1,"The table cannot fit into the current element which will cause column misalignment. It is suggested that you enable x-scrolling or increase the width the table has in which to be drawn");
+else a.oScroll.sXInner!==""&&I(a,1,"The table cannot fit into the current element which will cause column misalignment. It is suggested that you increase the sScrollXInner property to allow it to draw in a larger area, or simply remove that parameter to allow automatic calculation");if(a.oScroll.sY==="")if(j.browser.msie&&j.browser.version<=7)d.style.height=u(a.nTable.offsetHeight+a.oScroll.iBarWidth);if(a.oScroll.sY!==""&&a.oScroll.bCollapse){d.style.height=u(a.oScroll.sY);h=a.oScroll.sX!==""&&a.nTable.offsetWidth>
+d.offsetWidth?a.oScroll.iBarWidth:0;if(a.nTable.offsetHeight<d.offsetHeight)d.style.height=u(j(a.nTable).height()+h)}h=j(a.nTable).outerWidth();c.style.width=u(h);b.style.width=u(h+a.oScroll.iBarWidth);b.parentNode.style.width=u(j(d).width());if(a.nTFoot!==null){b=a.nScrollFoot.getElementsByTagName("div")[0];c=b.getElementsByTagName("table")[0];b.style.width=u(a.nTable.offsetWidth+a.oScroll.iBarWidth);c.style.width=u(a.nTable.offsetWidth)}if(a.bSorted||a.bFiltered)d.scrollTop=0}function V(a){if(a.oFeatures.bAutoWidth===
+false)return false;Y(a);for(var b=0,c=a.aoColumns.length;b<c;b++)a.aoColumns[b].nTh.style.width=a.aoColumns[b].sWidth}function ua(a){var b=p.createElement("div");a.sTableId!==""&&typeof a.aanFeatures.f=="undefined"&&b.setAttribute("id",a.sTableId+"_filter");b.className=a.oClasses.sFilter;b.innerHTML=a.oLanguage.sSearch+(a.oLanguage.sSearch===""?"":" ")+'<input type="text" />';var c=j("input",b);c.val(a.oPreviousSearch.sSearch.replace('"',"&quot;"));c.keyup(function(){for(var d=a.aanFeatures.f,f=0,
+e=d.length;f<e;f++)d[f]!=this.parentNode&&j("input",d[f]).val(this.value);this.value!=a.oPreviousSearch.sSearch&&P(a,{sSearch:this.value,bRegex:a.oPreviousSearch.bRegex,bSmart:a.oPreviousSearch.bSmart})});c.keypress(function(d){if(d.keyCode==13)return false});return b}function P(a,b,c){Aa(a,b.sSearch,c,b.bRegex,b.bSmart);for(b=0;b<a.aoPreSearchCols.length;b++)Ba(a,a.aoPreSearchCols[b].sSearch,b,a.aoPreSearchCols[b].bRegex,a.aoPreSearchCols[b].bSmart);n.afnFiltering.length!==0&&Ca(a);a.bFiltered=true;
+a._iDisplayStart=0;F(a);C(a);fa(a,0)}function Ca(a){for(var b=n.afnFiltering,c=0,d=b.length;c<d;c++)for(var f=0,e=0,i=a.aiDisplay.length;e<i;e++){var h=a.aiDisplay[e-f];if(!b[c](a,a.aoData[h]._aData,h)){a.aiDisplay.splice(e-f,1);f++}}}function Ba(a,b,c,d,f){if(b!==""){var e=0;b=ga(b,d,f);for(d=a.aiDisplay.length-1;d>=0;d--){f=ha(a.aoData[a.aiDisplay[d]]._aData[c],a.aoColumns[c].sType);if(!b.test(f)){a.aiDisplay.splice(d,1);e++}}}}function Aa(a,b,c,d,f){var e=ga(b,d,f);if(typeof c=="undefined"||c===
+null)c=0;if(n.afnFiltering.length!==0)c=1;if(b.length<=0){a.aiDisplay.splice(0,a.aiDisplay.length);a.aiDisplay=a.aiDisplayMaster.slice()}else if(a.aiDisplay.length==a.aiDisplayMaster.length||a.oPreviousSearch.sSearch.length>b.length||c==1||b.indexOf(a.oPreviousSearch.sSearch)!==0){a.aiDisplay.splice(0,a.aiDisplay.length);fa(a,1);for(c=0;c<a.aiDisplayMaster.length;c++)e.test(a.asDataSearch[c])&&a.aiDisplay.push(a.aiDisplayMaster[c])}else{var i=0;for(c=0;c<a.asDataSearch.length;c++)if(!e.test(a.asDataSearch[c])){a.aiDisplay.splice(c-
+i,1);i++}}a.oPreviousSearch.sSearch=b;a.oPreviousSearch.bRegex=d;a.oPreviousSearch.bSmart=f}function fa(a,b){a.asDataSearch.splice(0,a.asDataSearch.length);b=typeof b!="undefined"&&b==1?a.aiDisplayMaster:a.aiDisplay;for(var c=0,d=b.length;c<d;c++)a.asDataSearch[c]=ia(a,a.aoData[b[c]]._aData)}function ia(a,b){for(var c="",d=p.createElement("div"),f=0,e=a.aoColumns.length;f<e;f++)if(a.aoColumns[f].bSearchable)c+=ha(b[f],a.aoColumns[f].sType)+"  ";if(c.indexOf("&")!==-1){d.innerHTML=c;c=d.textContent?
+d.textContent:d.innerText;c=c.replace(/\n/g," ").replace(/\r/g,"")}return c}function ga(a,b,c){if(c){a=b?a.split(" "):ja(a).split(" ");a="^(?=.*?"+a.join(")(?=.*?")+").*$";return new RegExp(a,"i")}else{a=b?a:ja(a);return new RegExp(a,"i")}}function ha(a,b){if(typeof n.ofnSearch[b]=="function")return n.ofnSearch[b](a);else if(b=="html")return a.replace(/\n/g," ").replace(/<.*?>/g,"");else if(typeof a=="string")return a.replace(/\n/g," ");return a}function O(a,b){var c=[],d=n.oSort,f=a.aoData,e,i,h,
+k;if(!a.oFeatures.bServerSide&&(a.aaSorting.length!==0||a.aaSortingFixed!==null)){c=a.aaSortingFixed!==null?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(h=0;h<c.length;h++){e=c[h][0];i=N(a,e);k=a.aoColumns[e].sSortDataType;if(typeof n.afnSortData[k]!="undefined"){var m=n.afnSortData[k](a,e,i);i=0;for(k=f.length;i<k;i++)f[i]._aData[e]=m[i]}}if(X.runtime){var q=[],t=c.length;for(h=0;h<t;h++){e=a.aoColumns[c[h][0]].iDataSort;q.push([e,a.aoColumns[e].sType+"-"+c[h][1]])}a.aiDisplayMaster.sort(function(H,
+J){for(var A,G=0;G<t;G++){A=d[q[G][1]](f[H]._aData[q[G][0]],f[J]._aData[q[G][0]]);if(A!==0)return A}return 0})}else{this.ClosureDataTables={fn:function(){},data:f,sort:n.oSort,master:a.aiDisplayMaster.slice()};k="this.ClosureDataTables.fn = function(a,b){var iTest, oSort=this.ClosureDataTables.sort, aoData=this.ClosureDataTables.data, aiOrig=this.ClosureDataTables.master;";for(h=0;h<c.length-1;h++){e=a.aoColumns[c[h][0]].iDataSort;i=a.aoColumns[e].sType;k+="iTest = oSort['"+i+"-"+c[h][1]+"']( aoData[a]._aData["+
+e+"], aoData[b]._aData["+e+"] ); if ( iTest === 0 )"}if(c.length>0){e=a.aoColumns[c[c.length-1][0]].iDataSort;i=a.aoColumns[e].sType;k+="iTest = oSort['"+i+"-"+c[c.length-1][1]+"']( aoData[a]._aData["+e+"], aoData[b]._aData["+e+"] );if (iTest===0) return oSort['numeric-asc'](jQuery.inArray(a,aiOrig), jQuery.inArray(b,aiOrig)); return iTest;}";eval(k);a.aiDisplayMaster.sort(this.ClosureDataTables.fn)}this.ClosureDataTables=undefined}}if(typeof b=="undefined"||b)T(a);a.bSorted=true;if(a.oFeatures.bFilter)P(a,
+a.oPreviousSearch,1);else{a.aiDisplay=a.aiDisplayMaster.slice();a._iDisplayStart=0;F(a);C(a)}}function $(a,b,c,d){j(b).click(function(f){if(a.aoColumns[c].bSortable!==false){var e=function(){var i,h;if(f.shiftKey){for(var k=false,m=0;m<a.aaSorting.length;m++)if(a.aaSorting[m][0]==c){k=true;i=a.aaSorting[m][0];h=a.aaSorting[m][2]+1;if(typeof a.aoColumns[i].asSorting[h]=="undefined")a.aaSorting.splice(m,1);else{a.aaSorting[m][1]=a.aoColumns[i].asSorting[h];a.aaSorting[m][2]=h}break}k===false&&a.aaSorting.push([c,
+a.aoColumns[c].asSorting[0],0])}else if(a.aaSorting.length==1&&a.aaSorting[0][0]==c){i=a.aaSorting[0][0];h=a.aaSorting[0][2]+1;if(typeof a.aoColumns[i].asSorting[h]=="undefined")h=0;a.aaSorting[0][1]=a.aoColumns[i].asSorting[h];a.aaSorting[0][2]=h}else{a.aaSorting.splice(0,a.aaSorting.length);a.aaSorting.push([c,a.aoColumns[c].asSorting[0],0])}O(a)};if(a.oFeatures.bProcessing){K(a,true);setTimeout(function(){e();a.oFeatures.bServerSide||K(a,false)},0)}else e();typeof d=="function"&&d(a)}})}function T(a){var b,
+c,d,f,e,i=a.aoColumns.length,h=a.oClasses;for(b=0;b<i;b++)a.aoColumns[b].bSortable&&j(a.aoColumns[b].nTh).removeClass(h.sSortAsc+" "+h.sSortDesc+" "+a.aoColumns[b].sSortingClass);f=a.aaSortingFixed!==null?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(b=0;b<a.aoColumns.length;b++)if(a.aoColumns[b].bSortable){e=a.aoColumns[b].sSortingClass;d=-1;for(c=0;c<f.length;c++)if(f[c][0]==b){e=f[c][1]=="asc"?h.sSortAsc:h.sSortDesc;d=c;break}j(a.aoColumns[b].nTh).addClass(e);if(a.bJUI){c=j("span",
+a.aoColumns[b].nTh);c.removeClass(h.sSortJUIAsc+" "+h.sSortJUIDesc+" "+h.sSortJUI+" "+h.sSortJUIAscAllowed+" "+h.sSortJUIDescAllowed);c.addClass(d==-1?a.aoColumns[b].sSortingClassJUI:f[d][1]=="asc"?h.sSortJUIAsc:h.sSortJUIDesc)}}else j(a.aoColumns[b].nTh).addClass(a.aoColumns[b].sSortingClass);e=h.sSortColumn;if(a.oFeatures.bSort&&a.oFeatures.bSortClasses){d=W(a);if(d.length>=i)for(b=0;b<i;b++)if(d[b].className.indexOf(e+"1")!=-1){c=0;for(a=d.length/i;c<a;c++)d[i*c+b].className=j.trim(d[i*c+b].className.replace(e+
+"1",""))}else if(d[b].className.indexOf(e+"2")!=-1){c=0;for(a=d.length/i;c<a;c++)d[i*c+b].className=j.trim(d[i*c+b].className.replace(e+"2",""))}else if(d[b].className.indexOf(e+"3")!=-1){c=0;for(a=d.length/i;c<a;c++)d[i*c+b].className=j.trim(d[i*c+b].className.replace(" "+e+"3",""))}h=1;var k;for(b=0;b<f.length;b++){k=parseInt(f[b][0],10);c=0;for(a=d.length/i;c<a;c++)d[i*c+k].className+=" "+e+h;h<3&&h++}}}function ya(a){if(a.oScroll.bInfinite)return null;var b=p.createElement("div");b.className=
+a.oClasses.sPaging+a.sPaginationType;n.oPagination[a.sPaginationType].fnInit(a,b,function(c){F(c);C(c)});typeof a.aanFeatures.p=="undefined"&&a.aoDrawCallback.push({fn:function(c){n.oPagination[c.sPaginationType].fnUpdate(c,function(d){F(d);C(d)})},sName:"pagination"});return b}function ca(a,b){var c=a._iDisplayStart;if(b=="first")a._iDisplayStart=0;else if(b=="previous"){a._iDisplayStart=a._iDisplayLength>=0?a._iDisplayStart-a._iDisplayLength:0;if(a._iDisplayStart<0)a._iDisplayStart=0}else if(b==
+"next")if(a._iDisplayLength>=0){if(a._iDisplayStart+a._iDisplayLength<a.fnRecordsDisplay())a._iDisplayStart+=a._iDisplayLength}else a._iDisplayStart=0;else if(b=="last")if(a._iDisplayLength>=0){b=parseInt((a.fnRecordsDisplay()-1)/a._iDisplayLength,10)+1;a._iDisplayStart=(b-1)*a._iDisplayLength}else a._iDisplayStart=0;else I(a,0,"Unknown paging action: "+b);return c!=a._iDisplayStart}function xa(a){var b=p.createElement("div");b.className=a.oClasses.sInfo;if(typeof a.aanFeatures.i=="undefined"){a.aoDrawCallback.push({fn:Da,
+sName:"information"});a.sTableId!==""&&b.setAttribute("id",a.sTableId+"_info")}return b}function Da(a){if(!(!a.oFeatures.bInfo||a.aanFeatures.i.length===0)){var b=a._iDisplayStart+1,c=a.fnDisplayEnd(),d=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),e=a.fnFormatNumber(b),i=a.fnFormatNumber(c),h=a.fnFormatNumber(d),k=a.fnFormatNumber(f);if(a.oScroll.bInfinite)e=a.fnFormatNumber(1);e=a.fnRecordsDisplay()===0&&a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfoEmpty+a.oLanguage.sInfoPostFix:a.fnRecordsDisplay()===
+0?a.oLanguage.sInfoEmpty+" "+a.oLanguage.sInfoFiltered.replace("_MAX_",h)+a.oLanguage.sInfoPostFix:a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfo.replace("_START_",e).replace("_END_",i).replace("_TOTAL_",k)+a.oLanguage.sInfoPostFix:a.oLanguage.sInfo.replace("_START_",e).replace("_END_",i).replace("_TOTAL_",k)+" "+a.oLanguage.sInfoFiltered.replace("_MAX_",a.fnFormatNumber(a.fnRecordsTotal()))+a.oLanguage.sInfoPostFix;if(a.oLanguage.fnInfoCallback!==null)e=a.oLanguage.fnInfoCallback(a,b,
+c,d,f,e);a=a.aanFeatures.i;b=0;for(c=a.length;b<c;b++)j(a[b]).html(e)}}function ta(a){if(a.oScroll.bInfinite)return null;var b='<select size="1" '+(a.sTableId===""?"":'name="'+a.sTableId+'_length"')+">",c,d;if(a.aLengthMenu.length==2&&typeof a.aLengthMenu[0]=="object"&&typeof a.aLengthMenu[1]=="object"){c=0;for(d=a.aLengthMenu[0].length;c<d;c++)b+='<option value="'+a.aLengthMenu[0][c]+'">'+a.aLengthMenu[1][c]+"</option>"}else{c=0;for(d=a.aLengthMenu.length;c<d;c++)b+='<option value="'+a.aLengthMenu[c]+
+'">'+a.aLengthMenu[c]+"</option>"}b+="</select>";var f=p.createElement("div");a.sTableId!==""&&typeof a.aanFeatures.l=="undefined"&&f.setAttribute("id",a.sTableId+"_length");f.className=a.oClasses.sLength;f.innerHTML=a.oLanguage.sLengthMenu.replace("_MENU_",b);j('select option[value="'+a._iDisplayLength+'"]',f).attr("selected",true);j("select",f).change(function(){var e=j(this).val(),i=a.aanFeatures.l;c=0;for(d=i.length;c<d;c++)i[c]!=this.parentNode&&j("select",i[c]).val(e);a._iDisplayLength=parseInt(e,
+10);F(a);if(a.fnDisplayEnd()==a.fnRecordsDisplay()){a._iDisplayStart=a.fnDisplayEnd()-a._iDisplayLength;if(a._iDisplayStart<0)a._iDisplayStart=0}if(a._iDisplayLength==-1)a._iDisplayStart=0;C(a)});return f}function va(a){var b=p.createElement("div");a.sTableId!==""&&typeof a.aanFeatures.r=="undefined"&&b.setAttribute("id",a.sTableId+"_processing");b.innerHTML=a.oLanguage.sProcessing;b.className=a.oClasses.sProcessing;a.nTable.parentNode.insertBefore(b,a.nTable);return b}function K(a,b){if(a.oFeatures.bProcessing){a=
+a.aanFeatures.r;for(var c=0,d=a.length;c<d;c++)a[c].style.visibility=b?"visible":"hidden"}}function ea(a,b){for(var c=-1,d=0;d<a.aoColumns.length;d++){a.aoColumns[d].bVisible===true&&c++;if(c==b)return d}return null}function N(a,b){for(var c=-1,d=0;d<a.aoColumns.length;d++){a.aoColumns[d].bVisible===true&&c++;if(d==b)return a.aoColumns[d].bVisible===true?c:null}return null}function Q(a,b){var c,d;c=a._iDisplayStart;for(d=a._iDisplayEnd;c<d;c++)if(a.aoData[a.aiDisplay[c]].nTr==b)return a.aiDisplay[c];
+c=0;for(d=a.aoData.length;c<d;c++)if(a.aoData[c].nTr==b)return c;return null}function S(a){for(var b=0,c=0;c<a.aoColumns.length;c++)a.aoColumns[c].bVisible===true&&b++;return b}function F(a){a._iDisplayEnd=a.oFeatures.bPaginate===false?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength>a.aiDisplay.length||a._iDisplayLength==-1?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Ea(a,b){if(!a||a===null||a==="")return 0;if(typeof b=="undefined")b=p.getElementsByTagName("body")[0];var c=
+p.createElement("div");c.style.width=a;b.appendChild(c);a=c.offsetWidth;b.removeChild(c);return a}function Y(a){var b=0,c,d=0,f=a.aoColumns.length,e,i=j("th",a.nTHead);for(e=0;e<f;e++)if(a.aoColumns[e].bVisible){d++;if(a.aoColumns[e].sWidth!==null){c=Ea(a.aoColumns[e].sWidthOrig,a.nTable.parentNode);if(c!==null)a.aoColumns[e].sWidth=u(c);b++}}if(f==i.length&&b===0&&d==f&&a.oScroll.sX===""&&a.oScroll.sY==="")for(e=0;e<a.aoColumns.length;e++){c=j(i[e]).width();if(c!==null)a.aoColumns[e].sWidth=u(c)}else{b=
+a.nTable.cloneNode(false);e=p.createElement("tbody");c=p.createElement("tr");b.removeAttribute("id");b.appendChild(a.nTHead.cloneNode(true));if(a.nTFoot!==null){b.appendChild(a.nTFoot.cloneNode(true));M(function(h){h.style.width=""},b.getElementsByTagName("tr"))}b.appendChild(e);e.appendChild(c);e=j("thead th",b);if(e.length===0)e=j("tbody tr:eq(0)>td",b);e.each(function(h){this.style.width="";h=ea(a,h);if(h!==null&&a.aoColumns[h].sWidthOrig!=="")this.style.width=a.aoColumns[h].sWidthOrig});for(e=
+0;e<f;e++)if(a.aoColumns[e].bVisible){d=Fa(a,e);if(d!==null){d=d.cloneNode(true);c.appendChild(d)}}e=a.nTable.parentNode;e.appendChild(b);if(a.oScroll.sX!==""&&a.oScroll.sXInner!=="")b.style.width=u(a.oScroll.sXInner);else if(a.oScroll.sX!==""){b.style.width="";if(j(b).width()<e.offsetWidth)b.style.width=u(e.offsetWidth)}else if(a.oScroll.sY!=="")b.style.width=u(e.offsetWidth);b.style.visibility="hidden";Ga(a,b);f=j("tbody tr:eq(0)>td",b);if(f.length===0)f=j("thead tr:eq(0)>th",b);for(e=c=0;e<a.aoColumns.length;e++)if(a.aoColumns[e].bVisible){d=
+j(f[c]).width();if(d!==null&&d>0)a.aoColumns[e].sWidth=u(d);c++}a.nTable.style.width=u(j(b).outerWidth());b.parentNode.removeChild(b)}}function Ga(a,b){if(a.oScroll.sX===""&&a.oScroll.sY!==""){j(b).width();b.style.width=u(j(b).outerWidth()-a.oScroll.iBarWidth)}else if(a.oScroll.sX!=="")b.style.width=u(j(b).outerWidth())}function Fa(a,b,c){if(typeof c=="undefined"||c){c=Ha(a,b);b=N(a,b);if(c<0)return null;return a.aoData[c].nTr.getElementsByTagName("td")[b]}var d=-1,f,e;c=-1;var i=p.createElement("div");
+i.style.visibility="hidden";i.style.position="absolute";p.body.appendChild(i);f=0;for(e=a.aoData.length;f<e;f++){i.innerHTML=a.aoData[f]._aData[b];if(i.offsetWidth>d){d=i.offsetWidth;c=f}}p.body.removeChild(i);if(c>=0){b=N(a,b);if(a=a.aoData[c].nTr.getElementsByTagName("td")[b])return a}return null}function Ha(a,b){for(var c=-1,d=-1,f=0;f<a.aoData.length;f++){var e=a.aoData[f]._aData[b];if(e.length>c){c=e.length;d=f}}return d}function u(a){if(a===null)return"0px";if(typeof a=="number"){if(a<0)return"0px";
+return a+"px"}var b=a.charCodeAt(a.length-1);if(b<48||b>57)return a;return a+"px"}function Ma(a,b){if(a.length!=b.length)return 1;for(var c=0;c<a.length;c++)if(a[c]!=b[c])return 2;return 0}function Z(a){for(var b=n.aTypes,c=b.length,d=0;d<c;d++){var f=b[d](a);if(f!==null)return f}return"string"}function B(a){for(var b=0;b<E.length;b++)if(E[b].nTable==a)return E[b];return null}function U(a){for(var b=[],c=a.aoData.length,d=0;d<c;d++)b.push(a.aoData[d]._aData);return b}function R(a){for(var b=[],c=
+a.aoData.length,d=0;d<c;d++)b.push(a.aoData[d].nTr);return b}function W(a){var b=R(a),c=[],d,f=[],e,i,h,k;e=0;for(i=b.length;e<i;e++){c=[];h=0;for(k=b[e].childNodes.length;h<k;h++){d=b[e].childNodes[h];d.nodeName.toUpperCase()=="TD"&&c.push(d)}h=d=0;for(k=a.aoColumns.length;h<k;h++)if(a.aoColumns[h].bVisible)f.push(c[h-d]);else{f.push(a.aoData[e]._anHidden[h]);d++}}return f}function ja(a){return a.replace(new RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^)","g"),"\\$1")}function ka(a,
+b){for(var c=-1,d=0,f=a.length;d<f;d++)if(a[d]==b)c=d;else a[d]>b&&a[d]--;c!=-1&&a.splice(c,1)}function sa(a,b){b=b.split(",");for(var c=[],d=0,f=a.aoColumns.length;d<f;d++)for(var e=0;e<f;e++)if(a.aoColumns[d].sName==b[e]){c.push(e);break}return c}function aa(a){for(var b="",c=0,d=a.aoColumns.length;c<d;c++)b+=a.aoColumns[c].sName+",";if(b.length==d)return"";return b.slice(0,-1)}function I(a,b,c){a=a.sTableId===""?"DataTables warning: "+c:"DataTables warning (table id = '"+a.sTableId+"'): "+c;if(b===
+0)if(n.sErrMode=="alert")alert(a);else throw a;else typeof console!="undefined"&&typeof console.log!="undefined"&&console.log(a)}function ba(a){a.aoData.splice(0,a.aoData.length);a.aiDisplayMaster.splice(0,a.aiDisplayMaster.length);a.aiDisplay.splice(0,a.aiDisplay.length);F(a)}function la(a){if(!(!a.oFeatures.bStateSave||typeof a.bDestroying!="undefined")){var b,c,d,f="{";f+='"iCreate":'+(new Date).getTime()+",";f+='"iStart":'+a._iDisplayStart+",";f+='"iEnd":'+a._iDisplayEnd+",";f+='"iLength":'+a._iDisplayLength+
+",";f+='"sFilter":"'+encodeURIComponent(a.oPreviousSearch.sSearch)+'",';f+='"sFilterEsc":'+!a.oPreviousSearch.bRegex+",";f+='"aaSorting":[ ';for(b=0;b<a.aaSorting.length;b++)f+="["+a.aaSorting[b][0]+',"'+a.aaSorting[b][1]+'"],';f=f.substring(0,f.length-1);f+="],";f+='"aaSearchCols":[ ';for(b=0;b<a.aoPreSearchCols.length;b++)f+='["'+encodeURIComponent(a.aoPreSearchCols[b].sSearch)+'",'+!a.aoPreSearchCols[b].bRegex+"],";f=f.substring(0,f.length-1);f+="],";f+='"abVisCols":[ ';for(b=0;b<a.aoColumns.length;b++)f+=
+a.aoColumns[b].bVisible+",";f=f.substring(0,f.length-1);f+="]";b=0;for(c=a.aoStateSave.length;b<c;b++){d=a.aoStateSave[b].fn(a,f);if(d!=="")f=d}f+="}";Ia(a.sCookiePrefix+a.sInstance,f,a.iCookieDuration,a.sCookiePrefix,a.fnCookieCallback)}}function Ja(a,b){if(a.oFeatures.bStateSave){var c,d,f;d=ma(a.sCookiePrefix+a.sInstance);if(d!==null&&d!==""){try{c=typeof j.parseJSON=="function"?j.parseJSON(d.replace(/'/g,'"')):eval("("+d+")")}catch(e){return}d=0;for(f=a.aoStateLoad.length;d<f;d++)if(!a.aoStateLoad[d].fn(a,
+c))return;a.oLoadedState=j.extend(true,{},c);a._iDisplayStart=c.iStart;a.iInitDisplayStart=c.iStart;a._iDisplayEnd=c.iEnd;a._iDisplayLength=c.iLength;a.oPreviousSearch.sSearch=decodeURIComponent(c.sFilter);a.aaSorting=c.aaSorting.slice();a.saved_aaSorting=c.aaSorting.slice();if(typeof c.sFilterEsc!="undefined")a.oPreviousSearch.bRegex=!c.sFilterEsc;if(typeof c.aaSearchCols!="undefined")for(d=0;d<c.aaSearchCols.length;d++)a.aoPreSearchCols[d]={sSearch:decodeURIComponent(c.aaSearchCols[d][0]),bRegex:!c.aaSearchCols[d][1]};
+if(typeof c.abVisCols!="undefined"){b.saved_aoColumns=[];for(d=0;d<c.abVisCols.length;d++){b.saved_aoColumns[d]={};b.saved_aoColumns[d].bVisible=c.abVisCols[d]}}}}}function Ia(a,b,c,d,f){var e=new Date;e.setTime(e.getTime()+c*1E3);c=X.location.pathname.split("/");a=a+"_"+c.pop().replace(/[\/:]/g,"").toLowerCase();var i;if(f!==null){i=typeof j.parseJSON=="function"?j.parseJSON(b):eval("("+b+")");b=f(a,i,e.toGMTString(),c.join("/")+"/")}else b=a+"="+encodeURIComponent(b)+"; expires="+e.toGMTString()+
+"; path="+c.join("/")+"/";f="";e=9999999999999;if((ma(a)!==null?p.cookie.length:b.length+p.cookie.length)+10>4096){a=p.cookie.split(";");for(var h=0,k=a.length;h<k;h++)if(a[h].indexOf(d)!=-1){var m=a[h].split("=");try{i=eval("("+decodeURIComponent(m[1])+")")}catch(q){continue}if(typeof i.iCreate!="undefined"&&i.iCreate<e){f=m[0];e=i.iCreate}}if(f!=="")p.cookie=f+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+c.join("/")+"/"}p.cookie=b}function ma(a){var b=X.location.pathname.split("/");a=a+"_"+
+b[b.length-1].replace(/[\/:]/g,"").toLowerCase()+"=";b=p.cookie.split(";");for(var c=0;c<b.length;c++){for(var d=b[c];d.charAt(0)==" ";)d=d.substring(1,d.length);if(d.indexOf(a)===0)return decodeURIComponent(d.substring(a.length,d.length))}return null}function da(a){a=a.getElementsByTagName("tr");if(a.length==1)return a[0].getElementsByTagName("th");var b=[],c=[],d,f,e,i,h,k,m=function(G,Na,na){for(;typeof G[Na][na]!="undefined";)na++;return na},q=function(G){if(typeof b[G]=="undefined")b[G]=[]};
+d=0;for(i=a.length;d<i;d++){q(d);var t=0,H=[];f=0;for(h=a[d].childNodes.length;f<h;f++)if(a[d].childNodes[f].nodeName.toUpperCase()=="TD"||a[d].childNodes[f].nodeName.toUpperCase()=="TH")H.push(a[d].childNodes[f]);f=0;for(h=H.length;f<h;f++){var J=H[f].getAttribute("colspan")*1,A=H[f].getAttribute("rowspan")*1;if(!J||J===0||J===1){k=m(b,d,t);b[d][k]=H[f].nodeName.toUpperCase()=="TD"?4:H[f];if(A||A===0||A===1)for(e=1;e<A;e++){q(d+e);b[d+e][k]=2}t++}else{k=m(b,d,t);for(e=0;e<J;e++)b[d][k+e]=3;t+=J}}}d=
+0;for(i=b.length;d<i;d++){f=0;for(h=b[d].length;f<h;f++)if(typeof b[d][f]=="object")c[f]=b[d][f]}return c}function Ka(){var a=p.createElement("p"),b=a.style;b.width="100%";b.height="200px";var c=p.createElement("div");b=c.style;b.position="absolute";b.top="0px";b.left="0px";b.visibility="hidden";b.width="200px";b.height="150px";b.overflow="hidden";c.appendChild(a);p.body.appendChild(c);b=a.offsetWidth;c.style.overflow="scroll";a=a.offsetWidth;if(b==a)a=c.clientWidth;p.body.removeChild(c);return b-
+a}function M(a,b,c){for(var d=0,f=b.length;d<f;d++)for(var e=0,i=b[d].childNodes.length;e<i;e++)if(b[d].childNodes[e].nodeType==1)typeof c!="undefined"?a(b[d].childNodes[e],c[d].childNodes[e]):a(b[d].childNodes[e])}function o(a,b,c,d){if(typeof d=="undefined")d=c;if(typeof b[c]!="undefined")a[d]=b[c]}this.oApi={};this.fnDraw=function(a){var b=B(this[n.iApiIndex]);if(typeof a!="undefined"&&a===false){F(b);C(b)}else L(b)};this.fnFilter=function(a,b,c,d,f){var e=B(this[n.iApiIndex]);if(e.oFeatures.bFilter){if(typeof c==
+"undefined")c=false;if(typeof d=="undefined")d=true;if(typeof f=="undefined")f=true;if(typeof b=="undefined"||b===null){P(e,{sSearch:a,bRegex:c,bSmart:d},1);if(f&&typeof e.aanFeatures.f!="undefined"){b=e.aanFeatures.f;c=0;for(d=b.length;c<d;c++)j("input",b[c]).val(a)}}else{e.aoPreSearchCols[b].sSearch=a;e.aoPreSearchCols[b].bRegex=c;e.aoPreSearchCols[b].bSmart=d;P(e,e.oPreviousSearch,1)}}};this.fnSettings=function(){return B(this[n.iApiIndex])};this.fnVersionCheck=n.fnVersionCheck;this.fnSort=function(a){var b=
+B(this[n.iApiIndex]);b.aaSorting=a;O(b)};this.fnSortListener=function(a,b,c){$(B(this[n.iApiIndex]),a,b,c)};this.fnAddData=function(a,b){if(a.length===0)return[];var c=[],d,f=B(this[n.iApiIndex]);if(typeof a[0]=="object")for(var e=0;e<a.length;e++){d=w(f,a[e]);if(d==-1)return c;c.push(d)}else{d=w(f,a);if(d==-1)return c;c.push(d)}f.aiDisplay=f.aiDisplayMaster.slice();if(typeof b=="undefined"||b)L(f);return c};this.fnDeleteRow=function(a,b,c){var d=B(this[n.iApiIndex]);a=typeof a=="object"?Q(d,a):a;
+var f=d.aoData.splice(a,1),e=j.inArray(a,d.aiDisplay);d.asDataSearch.splice(e,1);ka(d.aiDisplayMaster,a);ka(d.aiDisplay,a);typeof b=="function"&&b.call(this,d,f);if(d._iDisplayStart>=d.aiDisplay.length){d._iDisplayStart-=d._iDisplayLength;if(d._iDisplayStart<0)d._iDisplayStart=0}if(typeof c=="undefined"||c){F(d);C(d)}return f};this.fnClearTable=function(a){var b=B(this[n.iApiIndex]);ba(b);if(typeof a=="undefined"||a)C(b)};this.fnOpen=function(a,b,c){var d=B(this[n.iApiIndex]);this.fnClose(a);var f=
+p.createElement("tr"),e=p.createElement("td");f.appendChild(e);e.className=c;e.colSpan=S(d);e.innerHTML=b;b=j("tr",d.nTBody);j.inArray(a,b)!=-1&&j(f).insertAfter(a);d.aoOpenRows.push({nTr:f,nParent:a});return f};this.fnClose=function(a){for(var b=B(this[n.iApiIndex]),c=0;c<b.aoOpenRows.length;c++)if(b.aoOpenRows[c].nParent==a){(a=b.aoOpenRows[c].nTr.parentNode)&&a.removeChild(b.aoOpenRows[c].nTr);b.aoOpenRows.splice(c,1);return 0}return 1};this.fnGetData=function(a){var b=B(this[n.iApiIndex]);if(typeof a!=
+"undefined"){a=typeof a=="object"?Q(b,a):a;return b.aoData[a]._aData}return U(b)};this.fnGetNodes=function(a){var b=B(this[n.iApiIndex]);if(typeof a!="undefined")return b.aoData[a].nTr;return R(b)};this.fnGetPosition=function(a){var b=B(this[n.iApiIndex]);if(a.nodeName.toUpperCase()=="TR")return Q(b,a);else if(a.nodeName.toUpperCase()=="TD")for(var c=Q(b,a.parentNode),d=0,f=0;f<b.aoColumns.length;f++)if(b.aoColumns[f].bVisible){if(b.aoData[c].nTr.getElementsByTagName("td")[f-d]==a)return[c,f-d,f]}else d++;
+return null};this.fnUpdate=function(a,b,c,d,f){var e=B(this[n.iApiIndex]),i;b=typeof b=="object"?Q(e,b):b;if(typeof a!="object"){i=a;e.aoData[b]._aData[c]=i;if(e.aoColumns[c].fnRender!==null){i=e.aoColumns[c].fnRender({iDataRow:b,iDataColumn:c,aData:e.aoData[b]._aData,oSettings:e});if(e.aoColumns[c].bUseRendered)e.aoData[b]._aData[c]=i}c=N(e,c);if(c!==null)e.aoData[b].nTr.getElementsByTagName("td")[c].innerHTML=i}else{if(a.length!=e.aoColumns.length){I(e,0,"An array passed to fnUpdate must have the same number of columns as the table in question - in this case "+
+e.aoColumns.length);return 1}for(var h=0;h<a.length;h++){i=a[h];e.aoData[b]._aData[h]=i;if(e.aoColumns[h].fnRender!==null){i=e.aoColumns[h].fnRender({iDataRow:b,iDataColumn:h,aData:e.aoData[b]._aData,oSettings:e});if(e.aoColumns[h].bUseRendered)e.aoData[b]._aData[h]=i}c=N(e,h);if(c!==null)e.aoData[b].nTr.getElementsByTagName("td")[c].innerHTML=i}}a=j.inArray(b,e.aiDisplay);e.asDataSearch[a]=ia(e,e.aoData[b]._aData);if(typeof f=="undefined"||f)V(e);if(typeof d=="undefined"||d)L(e);return 0};this.fnSetColumnVis=
+function(a,b,c){var d=B(this[n.iApiIndex]),f,e;e=d.aoColumns.length;var i,h;if(d.aoColumns[a].bVisible!=b){i=j(">tr",d.nTHead)[0];var k=j(">tr",d.nTFoot)[0],m=[],q=[];for(f=0;f<e;f++){m.push(d.aoColumns[f].nTh);q.push(d.aoColumns[f].nTf)}if(b){for(f=b=0;f<a;f++)d.aoColumns[f].bVisible&&b++;if(b>=S(d)){i.appendChild(m[a]);k&&k.appendChild(q[a]);f=0;for(e=d.aoData.length;f<e;f++){i=d.aoData[f]._anHidden[a];d.aoData[f].nTr.appendChild(i)}}else{for(f=a;f<e;f++){h=N(d,f);if(h!==null)break}i.insertBefore(m[a],
+i.getElementsByTagName("th")[h]);k&&k.insertBefore(q[a],k.getElementsByTagName("th")[h]);W(d);f=0;for(e=d.aoData.length;f<e;f++){i=d.aoData[f]._anHidden[a];d.aoData[f].nTr.insertBefore(i,j(">td:eq("+h+")",d.aoData[f].nTr)[0])}}d.aoColumns[a].bVisible=true}else{i.removeChild(m[a]);k&&k.removeChild(q[a]);h=W(d);f=0;for(e=d.aoData.length;f<e;f++){i=h[f*d.aoColumns.length+a*1];d.aoData[f]._anHidden[a]=i;i.parentNode.removeChild(i)}d.aoColumns[a].bVisible=false}f=0;for(e=d.aoOpenRows.length;f<e;f++)d.aoOpenRows[f].nTr.colSpan=
+S(d);if(typeof c=="undefined"||c){V(d);C(d)}la(d)}};this.fnPageChange=function(a,b){var c=B(this[n.iApiIndex]);ca(c,a);F(c);if(typeof b=="undefined"||b)C(c)};this.fnDestroy=function(){var a=B(this[n.iApiIndex]),b=a.nTableWrapper.parentNode,c=a.nTBody,d,f;a.bDestroying=true;d=0;for(f=a.aoColumns.length;d<f;d++)a.aoColumns[d].bVisible===false&&this.fnSetColumnVis(d,true);j("tbody>tr>td."+a.oClasses.sRowEmpty,a.nTable).parent().remove();if(a.nTable!=a.nTHead.parentNode){j(">thead",a.nTable).remove();
+a.nTable.appendChild(a.nTHead)}if(a.nTFoot&&a.nTable!=a.nTFoot.parentNode){j(">tfoot",a.nTable).remove();a.nTable.appendChild(a.nTFoot)}a.nTable.parentNode.removeChild(a.nTable);j(a.nTableWrapper).remove();a.aaSorting=[];a.aaSortingFixed=[];T(a);j(R(a)).removeClass(a.asStripClasses.join(" "));if(a.bJUI){j("th",a.nTHead).removeClass([n.oStdClasses.sSortable,n.oJUIClasses.sSortableAsc,n.oJUIClasses.sSortableDesc,n.oJUIClasses.sSortableNone].join(" "));j("th span",a.nTHead).remove()}else j("th",a.nTHead).removeClass([n.oStdClasses.sSortable,
+n.oStdClasses.sSortableAsc,n.oStdClasses.sSortableDesc,n.oStdClasses.sSortableNone].join(" "));b.appendChild(a.nTable);d=0;for(f=a.aoData.length;d<f;d++)c.appendChild(a.aoData[d].nTr);a.nTable.style.width=u(a.sDestroyWidth);j(">tr:even",c).addClass(a.asDestoryStrips[0]);j(">tr:odd",c).addClass(a.asDestoryStrips[1]);d=0;for(f=E.length;d<f;d++)E[d]==a&&E.splice(d,1)};this.fnAdjustColumnSizing=function(a){V(B(this[n.iApiIndex]));if(typeof a=="undefined"||a)this.fnDraw(false)};for(var oa in n.oApi)if(oa)this[oa]=
+r(oa);this.oApi._fnExternApiFunc=r;this.oApi._fnInitalise=s;this.oApi._fnLanguageProcess=v;this.oApi._fnAddColumn=y;this.oApi._fnColumnOptions=D;this.oApi._fnAddData=w;this.oApi._fnGatherData=x;this.oApi._fnDrawHead=z;this.oApi._fnDraw=C;this.oApi._fnReDraw=L;this.oApi._fnAjaxUpdate=qa;this.oApi._fnAjaxUpdateDraw=ra;this.oApi._fnAddOptionsHtml=pa;this.oApi._fnFeatureHtmlTable=wa;this.oApi._fnScrollDraw=za;this.oApi._fnAjustColumnSizing=V;this.oApi._fnFeatureHtmlFilter=ua;this.oApi._fnFilterComplete=
+P;this.oApi._fnFilterCustom=Ca;this.oApi._fnFilterColumn=Ba;this.oApi._fnFilter=Aa;this.oApi._fnBuildSearchArray=fa;this.oApi._fnBuildSearchRow=ia;this.oApi._fnFilterCreateSearch=ga;this.oApi._fnDataToSearch=ha;this.oApi._fnSort=O;this.oApi._fnSortAttachListener=$;this.oApi._fnSortingClasses=T;this.oApi._fnFeatureHtmlPaginate=ya;this.oApi._fnPageChange=ca;this.oApi._fnFeatureHtmlInfo=xa;this.oApi._fnUpdateInfo=Da;this.oApi._fnFeatureHtmlLength=ta;this.oApi._fnFeatureHtmlProcessing=va;this.oApi._fnProcessingDisplay=
+K;this.oApi._fnVisibleToColumnIndex=ea;this.oApi._fnColumnIndexToVisible=N;this.oApi._fnNodeToDataIndex=Q;this.oApi._fnVisbleColumns=S;this.oApi._fnCalculateEnd=F;this.oApi._fnConvertToWidth=Ea;this.oApi._fnCalculateColumnWidths=Y;this.oApi._fnScrollingWidthAdjust=Ga;this.oApi._fnGetWidestNode=Fa;this.oApi._fnGetMaxLenString=Ha;this.oApi._fnStringToCss=u;this.oApi._fnArrayCmp=Ma;this.oApi._fnDetectType=Z;this.oApi._fnSettingsFromNode=B;this.oApi._fnGetDataMaster=U;this.oApi._fnGetTrNodes=R;this.oApi._fnGetTdNodes=
+W;this.oApi._fnEscapeRegex=ja;this.oApi._fnDeleteIndex=ka;this.oApi._fnReOrderIndex=sa;this.oApi._fnColumnOrdering=aa;this.oApi._fnLog=I;this.oApi._fnClearTable=ba;this.oApi._fnSaveState=la;this.oApi._fnLoadState=Ja;this.oApi._fnCreateCookie=Ia;this.oApi._fnReadCookie=ma;this.oApi._fnGetUniqueThs=da;this.oApi._fnScrollBarWidth=Ka;this.oApi._fnApplyToChildren=M;this.oApi._fnMap=o;var La=this;return this.each(function(){var a=0,b,c,d,f;a=0;for(b=E.length;a<b;a++){if(E[a].nTable==this)if(typeof g=="undefined"||
+typeof g.bRetrieve!="undefined"&&g.bRetrieve===true)return E[a].oInstance;else if(typeof g.bDestroy!="undefined"&&g.bDestroy===true){E[a].oInstance.fnDestroy();break}else{I(E[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, please pass either no arguments to the dataTable() function, or set bRetrieve to true. Alternatively, to destory the old table and create a new one, set bDestroy to true (note that a lot of changes to the configuration can be made through the API which is usually much faster).");
+return}if(E[a].sTableId!==""&&E[a].sTableId==this.getAttribute("id")){E.splice(a,1);break}}var e=new l;E.push(e);var i=false,h=false;a=this.getAttribute("id");if(a!==null){e.sTableId=a;e.sInstance=a}else e.sInstance=n._oExternConfig.iNextUnique++;if(this.nodeName.toLowerCase()!="table")I(e,0,"Attempted to initialise DataTables on a node which is not a table: "+this.nodeName);else{e.oInstance=La;e.nTable=this;e.oApi=La.oApi;e.sDestroyWidth=j(this).width();if(typeof g!="undefined"&&g!==null){e.oInit=
+g;o(e.oFeatures,g,"bPaginate");o(e.oFeatures,g,"bLengthChange");o(e.oFeatures,g,"bFilter");o(e.oFeatures,g,"bSort");o(e.oFeatures,g,"bInfo");o(e.oFeatures,g,"bProcessing");o(e.oFeatures,g,"bAutoWidth");o(e.oFeatures,g,"bSortClasses");o(e.oFeatures,g,"bServerSide");o(e.oScroll,g,"sScrollX","sX");o(e.oScroll,g,"sScrollXInner","sXInner");o(e.oScroll,g,"sScrollY","sY");o(e.oScroll,g,"bScrollCollapse","bCollapse");o(e.oScroll,g,"bScrollInfinite","bInfinite");o(e.oScroll,g,"iScrollLoadGap","iLoadGap");
+o(e,g,"asStripClasses");o(e,g,"fnRowCallback");o(e,g,"fnHeaderCallback");o(e,g,"fnFooterCallback");o(e,g,"fnCookieCallback");o(e,g,"fnInitComplete");o(e,g,"fnServerData");o(e,g,"fnFormatNumber");o(e,g,"aaSorting");o(e,g,"aaSortingFixed");o(e,g,"aLengthMenu");o(e,g,"sPaginationType");o(e,g,"sAjaxSource");o(e,g,"iCookieDuration");o(e,g,"sCookiePrefix");o(e,g,"sDom");o(e,g,"oSearch","oPreviousSearch");o(e,g,"aoSearchCols","aoPreSearchCols");o(e,g,"iDisplayLength","_iDisplayLength");o(e,g,"bJQueryUI",
+"bJUI");o(e.oLanguage,g,"fnInfoCallback");typeof g.fnDrawCallback=="function"&&e.aoDrawCallback.push({fn:g.fnDrawCallback,sName:"user"});typeof g.fnStateSaveCallback=="function"&&e.aoStateSave.push({fn:g.fnStateSaveCallback,sName:"user"});typeof g.fnStateLoadCallback=="function"&&e.aoStateLoad.push({fn:g.fnStateLoadCallback,sName:"user"});e.oFeatures.bServerSide&&e.oFeatures.bSort&&e.oFeatures.bSortClasses&&e.aoDrawCallback.push({fn:T,sName:"server_side_sort_classes"});if(typeof g.bJQueryUI!="undefined"&&
+g.bJQueryUI){e.oClasses=n.oJUIClasses;if(typeof g.sDom=="undefined")e.sDom='<"H"lfr>t<"F"ip>'}if(e.oScroll.sX!==""||e.oScroll.sY!=="")e.oScroll.iBarWidth=Ka();if(typeof g.iDisplayStart!="undefined"&&typeof e.iInitDisplayStart=="undefined"){e.iInitDisplayStart=g.iDisplayStart;e._iDisplayStart=g.iDisplayStart}if(typeof g.bStateSave!="undefined"){e.oFeatures.bStateSave=g.bStateSave;Ja(e,g);e.aoDrawCallback.push({fn:la,sName:"state_save"})}if(typeof g.aaData!="undefined")h=true;if(typeof g!="undefined"&&
+typeof g.aoData!="undefined")g.aoColumns=g.aoData;if(typeof g.oLanguage!="undefined")if(typeof g.oLanguage.sUrl!="undefined"&&g.oLanguage.sUrl!==""){e.oLanguage.sUrl=g.oLanguage.sUrl;j.getJSON(e.oLanguage.sUrl,null,function(q){v(e,q,true)});i=true}else v(e,g.oLanguage,false)}else g={};if(typeof g.asStripClasses=="undefined"){e.asStripClasses.push(e.oClasses.sStripOdd);e.asStripClasses.push(e.oClasses.sStripEven)}c=false;d=j("tbody>tr",this);a=0;for(b=e.asStripClasses.length;a<b;a++)if(d.filter(":lt(2)").hasClass(e.asStripClasses[a])){c=
+true;break}if(c){e.asDestoryStrips=["",""];if(j(d[0]).hasClass(e.oClasses.sStripOdd))e.asDestoryStrips[0]+=e.oClasses.sStripOdd+" ";if(j(d[0]).hasClass(e.oClasses.sStripEven))e.asDestoryStrips[0]+=e.oClasses.sStripEven;if(j(d[1]).hasClass(e.oClasses.sStripOdd))e.asDestoryStrips[1]+=e.oClasses.sStripOdd+" ";if(j(d[1]).hasClass(e.oClasses.sStripEven))e.asDestoryStrips[1]+=e.oClasses.sStripEven;d.removeClass(e.asStripClasses.join(" "))}a=this.getElementsByTagName("thead");c=a.length===0?[]:da(a[0]);
+var k;if(typeof g.aoColumns=="undefined"){k=[];a=0;for(b=c.length;a<b;a++)k.push(null)}else k=g.aoColumns;a=0;for(b=k.length;a<b;a++){if(typeof g.saved_aoColumns!="undefined"&&g.saved_aoColumns.length==b){if(k[a]===null)k[a]={};k[a].bVisible=g.saved_aoColumns[a].bVisible}y(e,c?c[a]:null)}if(typeof g.aoColumnDefs!="undefined")for(a=g.aoColumnDefs.length-1;a>=0;a--){var m=g.aoColumnDefs[a].aTargets;j.isArray(m)||I(e,1,"aTargets must be an array of targets, not a "+typeof m);c=0;for(d=m.length;c<d;c++)if(typeof m[c]==
+"number"&&m[c]>=0){for(;e.aoColumns.length<=m[c];)y(e);D(e,m[c],g.aoColumnDefs[a])}else if(typeof m[c]=="number"&&m[c]<0)D(e,e.aoColumns.length+m[c],g.aoColumnDefs[a]);else if(typeof m[c]=="string"){b=0;for(f=e.aoColumns.length;b<f;b++)if(m[c]=="_all"||e.aoColumns[b].nTh.className.indexOf(m[c])!=-1)D(e,b,g.aoColumnDefs[a])}}if(typeof k!="undefined"){a=0;for(b=k.length;a<b;a++)D(e,a,k[a])}a=0;for(b=e.aaSorting.length;a<b;a++){if(e.aaSorting[a][0]>=e.aoColumns.length)e.aaSorting[a][0]=0;k=e.aoColumns[e.aaSorting[a][0]];
+if(typeof e.aaSorting[a][2]=="undefined")e.aaSorting[a][2]=0;if(typeof g.aaSorting=="undefined"&&typeof e.saved_aaSorting=="undefined")e.aaSorting[a][1]=k.asSorting[0];c=0;for(d=k.asSorting.length;c<d;c++)if(e.aaSorting[a][1]==k.asSorting[c]){e.aaSorting[a][2]=c;break}}T(e);this.getElementsByTagName("thead").length===0&&this.appendChild(p.createElement("thead"));this.getElementsByTagName("tbody").length===0&&this.appendChild(p.createElement("tbody"));e.nTHead=this.getElementsByTagName("thead")[0];
+e.nTBody=this.getElementsByTagName("tbody")[0];if(this.getElementsByTagName("tfoot").length>0)e.nTFoot=this.getElementsByTagName("tfoot")[0];if(h)for(a=0;a<g.aaData.length;a++)w(e,g.aaData[a]);else x(e);e.aiDisplay=e.aiDisplayMaster.slice();e.bInitialised=true;i===false&&s(e)}})}})(jQuery,window,document);
 

 Binary files /dev/null and b/media/js/jquery.dataTables.min.js.gz differ
--- /dev/null
+++ b/media/js/jquery.js
@@ -1,1 +1,166 @@
-
+/*!
+ * jQuery JavaScript Library v1.4.3
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu Oct 14 23:10:06 2010 -0400
+ */
+(function(E,A){function U(){return false}function ba(){return true}function ja(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ga(a){var b,d,e=[],f=[],h,k,l,n,s,v,B,D;k=c.data(this,this.nodeType?"events":"__events__");if(typeof k==="function")k=k.events;if(!(a.liveFired===this||!k||!k.live||a.button&&a.type==="click")){if(a.namespace)D=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var H=k.live.slice(0);for(n=0;n<H.length;n++){k=H[n];k.origType.replace(X,
+"")===a.type?f.push(k.selector):H.splice(n--,1)}f=c(a.target).closest(f,a.currentTarget);s=0;for(v=f.length;s<v;s++){B=f[s];for(n=0;n<H.length;n++){k=H[n];if(B.selector===k.selector&&(!D||D.test(k.namespace))){l=B.elem;h=null;if(k.preType==="mouseenter"||k.preType==="mouseleave"){a.type=k.preType;h=c(a.relatedTarget).closest(k.selector)[0]}if(!h||h!==l)e.push({elem:l,handleObj:k,level:B.level})}}}s=0;for(v=e.length;s<v;s++){f=e[s];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;
+a.handleObj=f.handleObj;D=f.handleObj.origHandler.apply(f.elem,arguments);if(D===false||a.isPropagationStopped()){d=f.level;if(D===false)b=false}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(Ha,"`").replace(Ia,"&")}function ka(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Ja.test(b))return c.filter(b,
+e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function la(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var k in e[h])c.event.add(this,h,e[h][k],e[h][k].data)}}})}function Ka(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}
+function ma(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?La:Ma,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function ca(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Na.test(a)?e(a,h):ca(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?
+e(a,""):c.each(b,function(f,h){ca(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(na.concat.apply([],na.slice(0,b)),function(){d[this]=a});return d}function oa(a){if(!da[a]){var b=c("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";da[a]=d}return da[a]}function ea(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var u=E.document,c=function(){function a(){if(!b.isReady){try{u.documentElement.doScroll("left")}catch(i){setTimeout(a,
+1);return}b.ready()}}var b=function(i,r){return new b.fn.init(i,r)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,k=/\S/,l=/^\s+/,n=/\s+$/,s=/\W/,v=/\d/,B=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,D=/^[\],:{}\s]*$/,H=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,G=/(?:^|:|,)(?:\s*\[)+/g,M=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,j=/(msie) ([\w.]+)/,o=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,
+q=[],t,x=Object.prototype.toString,C=Object.prototype.hasOwnProperty,P=Array.prototype.push,N=Array.prototype.slice,R=String.prototype.trim,Q=Array.prototype.indexOf,L={};b.fn=b.prototype={init:function(i,r){var y,z,F;if(!i)return this;if(i.nodeType){this.context=this[0]=i;this.length=1;return this}if(i==="body"&&!r&&u.body){this.context=u;this[0]=u.body;this.selector="body";this.length=1;return this}if(typeof i==="string")if((y=h.exec(i))&&(y[1]||!r))if(y[1]){F=r?r.ownerDocument||r:u;if(z=B.exec(i))if(b.isPlainObject(r)){i=
+[u.createElement(z[1])];b.fn.attr.call(i,r,true)}else i=[F.createElement(z[1])];else{z=b.buildFragment([y[1]],[F]);i=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,i)}else{if((z=u.getElementById(y[2]))&&z.parentNode){if(z.id!==y[2])return f.find(i);this.length=1;this[0]=z}this.context=u;this.selector=i;return this}else if(!r&&!s.test(i)){this.selector=i;this.context=u;i=u.getElementsByTagName(i);return b.merge(this,i)}else return!r||r.jquery?(r||f).find(i):b(r).find(i);
+else if(b.isFunction(i))return f.ready(i);if(i.selector!==A){this.selector=i.selector;this.context=i.context}return b.makeArray(i,this)},selector:"",jquery:"1.4.3",length:0,size:function(){return this.length},toArray:function(){return N.call(this,0)},get:function(i){return i==null?this.toArray():i<0?this.slice(i)[0]:this[i]},pushStack:function(i,r,y){var z=b();b.isArray(i)?P.apply(z,i):b.merge(z,i);z.prevObject=this;z.context=this.context;if(r==="find")z.selector=this.selector+(this.selector?" ":
+"")+y;else if(r)z.selector=this.selector+"."+r+"("+y+")";return z},each:function(i,r){return b.each(this,i,r)},ready:function(i){b.bindReady();if(b.isReady)i.call(u,b);else q&&q.push(i);return this},eq:function(i){return i===-1?this.slice(i):this.slice(i,+i+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(i){return this.pushStack(b.map(this,function(r,y){return i.call(r,
+y,r)}))},end:function(){return this.prevObject||b(null)},push:P,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var i=arguments[0]||{},r=1,y=arguments.length,z=false,F,I,K,J,fa;if(typeof i==="boolean"){z=i;i=arguments[1]||{};r=2}if(typeof i!=="object"&&!b.isFunction(i))i={};if(y===r){i=this;--r}for(;r<y;r++)if((F=arguments[r])!=null)for(I in F){K=i[I];J=F[I];if(i!==J)if(z&&J&&(b.isPlainObject(J)||(fa=b.isArray(J)))){if(fa){fa=false;clone=K&&b.isArray(K)?K:[]}else clone=
+K&&b.isPlainObject(K)?K:{};i[I]=b.extend(z,clone,J)}else if(J!==A)i[I]=J}return i};b.extend({noConflict:function(i){E.$=e;if(i)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(i){i===true&&b.readyWait--;if(!b.readyWait||i!==true&&!b.isReady){if(!u.body)return setTimeout(b.ready,1);b.isReady=true;if(!(i!==true&&--b.readyWait>0)){if(q){for(var r=0;i=q[r++];)i.call(u,b);q=null}b.fn.triggerHandler&&b(u).triggerHandler("ready")}}},bindReady:function(){if(!p){p=true;if(u.readyState==="complete")return setTimeout(b.ready,
+1);if(u.addEventListener){u.addEventListener("DOMContentLoaded",t,false);E.addEventListener("load",b.ready,false)}else if(u.attachEvent){u.attachEvent("onreadystatechange",t);E.attachEvent("onload",b.ready);var i=false;try{i=E.frameElement==null}catch(r){}u.documentElement.doScroll&&i&&a()}}},isFunction:function(i){return b.type(i)==="function"},isArray:Array.isArray||function(i){return b.type(i)==="array"},isWindow:function(i){return i&&typeof i==="object"&&"setInterval"in i},isNaN:function(i){return i==
+null||!v.test(i)||isNaN(i)},type:function(i){return i==null?String(i):L[x.call(i)]||"object"},isPlainObject:function(i){if(!i||b.type(i)!=="object"||i.nodeType||b.isWindow(i))return false;if(i.constructor&&!C.call(i,"constructor")&&!C.call(i.constructor.prototype,"isPrototypeOf"))return false;for(var r in i);return r===A||C.call(i,r)},isEmptyObject:function(i){for(var r in i)return false;return true},error:function(i){throw i;},parseJSON:function(i){if(typeof i!=="string"||!i)return null;i=b.trim(i);
+if(D.test(i.replace(H,"@").replace(w,"]").replace(G,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(i):(new Function("return "+i))();else b.error("Invalid JSON: "+i)},noop:function(){},globalEval:function(i){if(i&&k.test(i)){var r=u.getElementsByTagName("head")[0]||u.documentElement,y=u.createElement("script");y.type="text/javascript";if(b.support.scriptEval)y.appendChild(u.createTextNode(i));else y.text=i;r.insertBefore(y,r.firstChild);r.removeChild(y)}},nodeName:function(i,r){return i.nodeName&&i.nodeName.toUpperCase()===
+r.toUpperCase()},each:function(i,r,y){var z,F=0,I=i.length,K=I===A||b.isFunction(i);if(y)if(K)for(z in i){if(r.apply(i[z],y)===false)break}else for(;F<I;){if(r.apply(i[F++],y)===false)break}else if(K)for(z in i){if(r.call(i[z],z,i[z])===false)break}else for(y=i[0];F<I&&r.call(y,F,y)!==false;y=i[++F]);return i},trim:R?function(i){return i==null?"":R.call(i)}:function(i){return i==null?"":i.toString().replace(l,"").replace(n,"")},makeArray:function(i,r){var y=r||[];if(i!=null){var z=b.type(i);i.length==
+null||z==="string"||z==="function"||z==="regexp"||b.isWindow(i)?P.call(y,i):b.merge(y,i)}return y},inArray:function(i,r){if(r.indexOf)return r.indexOf(i);for(var y=0,z=r.length;y<z;y++)if(r[y]===i)return y;return-1},merge:function(i,r){var y=i.length,z=0;if(typeof r.length==="number")for(var F=r.length;z<F;z++)i[y++]=r[z];else for(;r[z]!==A;)i[y++]=r[z++];i.length=y;return i},grep:function(i,r,y){var z=[],F;y=!!y;for(var I=0,K=i.length;I<K;I++){F=!!r(i[I],I);y!==F&&z.push(i[I])}return z},map:function(i,
+r,y){for(var z=[],F,I=0,K=i.length;I<K;I++){F=r(i[I],I,y);if(F!=null)z[z.length]=F}return z.concat.apply([],z)},guid:1,proxy:function(i,r,y){if(arguments.length===2)if(typeof r==="string"){y=i;i=y[r];r=A}else if(r&&!b.isFunction(r)){y=r;r=A}if(!r&&i)r=function(){return i.apply(y||this,arguments)};if(i)r.guid=i.guid=i.guid||r.guid||b.guid++;return r},access:function(i,r,y,z,F,I){var K=i.length;if(typeof r==="object"){for(var J in r)b.access(i,J,r[J],z,F,y);return i}if(y!==A){z=!I&&z&&b.isFunction(y);
+for(J=0;J<K;J++)F(i[J],r,z?y.call(i[J],J,F(i[J],r)):y,I);return i}return K?F(i[0],r):A},now:function(){return(new Date).getTime()},uaMatch:function(i){i=i.toLowerCase();i=M.exec(i)||g.exec(i)||j.exec(i)||i.indexOf("compatible")<0&&o.exec(i)||[];return{browser:i[1]||"",version:i[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(i,r){L["[object "+r+"]"]=r.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=
+m.version}if(b.browser.webkit)b.browser.safari=true;if(Q)b.inArray=function(i,r){return Q.call(r,i)};if(!/\s/.test("\u00a0")){l=/^[\s\xA0]+/;n=/[\s\xA0]+$/}f=b(u);if(u.addEventListener)t=function(){u.removeEventListener("DOMContentLoaded",t,false);b.ready()};else if(u.attachEvent)t=function(){if(u.readyState==="complete"){u.detachEvent("onreadystatechange",t);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=u.documentElement,b=u.createElement("script"),d=u.createElement("div"),
+e="script"+c.now();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],k=u.createElement("select"),l=k.appendChild(u.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),
+hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:l.selected,optDisabled:false,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};k.disabled=true;c.support.optDisabled=!l.disabled;b.type="text/javascript";try{b.appendChild(u.createTextNode("window."+e+"=1;"))}catch(n){}a.insertBefore(b,
+a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function s(){c.support.noCloneEvent=false;d.detachEvent("onclick",s)});d.cloneNode(true).fireEvent("onclick")}d=u.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=u.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var s=u.createElement("div");
+s.style.width=s.style.paddingLeft="1px";u.body.appendChild(s);c.boxModel=c.support.boxModel=s.offsetWidth===2;if("zoom"in s.style){s.style.display="inline";s.style.zoom=1;c.support.inlineBlockNeedsLayout=s.offsetWidth===2;s.style.display="";s.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=s.offsetWidth!==2}s.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var v=s.getElementsByTagName("td");c.support.reliableHiddenOffsets=v[0].offsetHeight===
+0;v[0].style.display="";v[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&v[0].offsetHeight===0;s.innerHTML="";u.body.removeChild(s).style.display="none"});a=function(s){var v=u.createElement("div");s="on"+s;var B=s in v;if(!B){v.setAttribute(s,"return;");B=typeof v[s]==="function"}return B};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",
+cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var pa={},Oa=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?pa:a;var e=a.nodeType,f=e?a[c.expando]:null,h=c.cache;if(!(e&&!f&&typeof b==="string"&&d===A)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=
+c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==A)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?pa:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);else if(d)delete f[e];else for(var k in a)delete a[k]}},acceptData:function(a){if(a.nodeName){var b=
+c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){if(typeof a==="undefined")return this.length?c.data(this[0]):null;else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===A){var e=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(e===A&&this.length){e=c.data(this[0],a);if(e===A&&this[0].nodeType===1){e=this[0].getAttribute("data-"+a);if(typeof e===
+"string")try{e=e==="true"?true:e==="false"?false:e==="null"?null:!c.isNaN(e)?parseFloat(e):Oa.test(e)?c.parseJSON(e):e}catch(f){}else e=A}}return e===A&&d[1]?this.data(d[0]):e}else return this.each(function(){var h=c(this),k=[d[0],b];h.triggerHandler("setData"+d[1]+"!",k);c.data(this,a,b);h.triggerHandler("changeData"+d[1]+"!",k)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=c.data(a,b);if(!d)return e||
+[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===A)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
+a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var qa=/[\n\t]/g,ga=/\s+/,Pa=/\r/g,Qa=/^(?:href|src|style)$/,Ra=/^(?:button|input)$/i,Sa=/^(?:button|input|object|select|textarea)$/i,Ta=/^a(?:rea)?$/i,ra=/^(?:radio|checkbox)$/i;c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,
+a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(s){var v=c(this);v.addClass(a.call(this,s,v.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ga),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1)if(f.className){for(var h=" "+f.className+" ",k=f.className,l=0,n=b.length;l<n;l++)if(h.indexOf(" "+b[l]+" ")<0)k+=" "+b[l];f.className=c.trim(k)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(n){var s=
+c(this);s.removeClass(a.call(this,n,s.attr("class")))});if(a&&typeof a==="string"||a===A)for(var b=(a||"").split(ga),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(qa," "),k=0,l=b.length;k<l;k++)h=h.replace(" "+b[k]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,
+f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,k=c(this),l=b,n=a.split(ga);f=n[h++];){l=e?l:!k.hasClass(f);k[l?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(qa," ").indexOf(a)>-1)return true;return false},
+val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var k=f[h];if(k.selected&&(c.support.optDisabled?!k.disabled:k.getAttribute("disabled")===null)&&(!k.parentNode.disabled||!c.nodeName(k.parentNode,"optgroup"))){a=c(k).val();if(b)return a;d.push(a)}}return d}if(ra.test(b.type)&&
+!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Pa,"")}return A}var l=c.isFunction(a);return this.each(function(n){var s=c(this),v=a;if(this.nodeType===1){if(l)v=a.call(this,n,s.val());if(v==null)v="";else if(typeof v==="number")v+="";else if(c.isArray(v))v=c.map(v,function(D){return D==null?"":D+""});if(c.isArray(v)&&ra.test(this.type))this.checked=c.inArray(s.val(),v)>=0;else if(c.nodeName(this,"select")){var B=c.makeArray(v);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),B)>=0});if(!B.length)this.selectedIndex=-1}else this.value=v}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return A;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==A;b=e&&c.props[b]||b;if(a.nodeType===1){var h=Qa.test(b);if((b in a||a[b]!==A)&&e&&!h){if(f){b==="type"&&Ra.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Sa.test(a.nodeName)||Ta.test(a.nodeName)&&a.href?0:A;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return A;a=!c.support.hrefNormalized&&e&&
+h?a.getAttribute(b,2):a.getAttribute(b);return a===null?A:a}}});var X=/\.(.*)$/,ha=/^(?:textarea|input|select)$/i,Ha=/\./g,Ia=/ /g,Ua=/[^\w\s.|`]/g,Va=function(a){return a.replace(Ua,"\\$&")},sa={focusin:0,focusout:0};c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var k=a.nodeType?"events":"__events__",l=h[k],n=h.handle;if(typeof l===
+"function"){n=l.handle;l=l.events}else if(!l){a.nodeType||(h[k]=h=function(){});h.events=l={}}if(!n)h.handle=n=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(n.elem,arguments):A};n.elem=a;b=b.split(" ");for(var s=0,v;k=b[s++];){h=f?c.extend({},f):{handler:d,data:e};if(k.indexOf(".")>-1){v=k.split(".");k=v.shift();h.namespace=v.slice(0).sort().join(".")}else{v=[];h.namespace=""}h.type=k;if(!h.guid)h.guid=d.guid;var B=l[k],D=c.event.special[k]||{};if(!B){B=l[k]=[];
+if(!D.setup||D.setup.call(a,e,v,n)===false)if(a.addEventListener)a.addEventListener(k,n,false);else a.attachEvent&&a.attachEvent("on"+k,n)}if(D.add){D.add.call(a,h);if(!h.handler.guid)h.handler.guid=d.guid}B.push(h);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,k=0,l,n,s,v,B,D,H=a.nodeType?"events":"__events__",w=c.data(a),G=w&&w[H];if(w&&G){if(typeof G==="function"){w=G;G=G.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||
+typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in G)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[k++];){v=f;l=f.indexOf(".")<0;n=[];if(!l){n=f.split(".");f=n.shift();s=RegExp("(^|\\.)"+c.map(n.slice(0).sort(),Va).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(B=G[f])if(d){v=c.event.special[f]||{};for(h=e||0;h<B.length;h++){D=B[h];if(d.guid===D.guid){if(l||s.test(D.namespace)){e==null&&B.splice(h--,1);v.remove&&v.remove.call(a,D)}if(e!=null)break}}if(B.length===0||e!=null&&B.length===1){if(!v.teardown||
+v.teardown.call(a,n)===false)c.removeEvent(a,f,w.handle);delete G[f]}}else for(h=0;h<B.length;h++){D=B[h];if(l||s.test(D.namespace)){c.event.remove(a,v,D.handler,h);B.splice(h--,1)}}}if(c.isEmptyObject(G)){if(b=w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,H);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=
+f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return A;a.result=A;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===
+false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){e=a.target;var k,l=f.replace(X,""),n=c.nodeName(e,"a")&&l==="click",s=c.event.special[l]||{};if((!s._default||s._default.call(d,a)===false)&&!n&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[l]){if(k=e["on"+l])e["on"+l]=null;c.event.triggered=true;e[l]()}}catch(v){}if(k)e["on"+l]=k;c.event.triggered=false}}},handle:function(a){var b,d,e;
+d=[];var f,h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var k=d.length;f<k;f++){var l=d[f];if(b||e.test(l.namespace)){a.handler=l.handler;a.data=
+l.data;a.handleObj=l;l=l.handler.apply(this,h);if(l!==A){a.result=l;if(l===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||u;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=u.documentElement;d=u.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==A)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ga,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
+Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=u.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
+c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ba;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ba;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ba;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
+var ta=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},ua=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?ua:ta,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?ua:ta)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
+"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=A;return ja("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=A;return ja("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
+va=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ha.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=va(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===A||f===e))if(e!=null||f){a.type="change";a.liveFired=
+A;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",va(a))}},setup:function(){if(this.type===
+"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ha.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ha.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}u.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){sa[b]++===0&&u.addEventListener(a,d,true)},teardown:function(){--sa[b]===
+0&&u.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=A}var k=b==="one"?c.proxy(f,function(n){c(this).unbind(n,k);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var l=this.length;h<l;h++)c.event.add(this[h],d,k,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
+a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
+1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var wa={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var k,l=0,n,s,v=h||this.selector;h=h?this:c(this.context);if(typeof d===
+"object"&&!d.preventDefault){for(k in d)h[b](k,e,d[k],v);return this}if(c.isFunction(e)){f=e;e=A}for(d=(d||"").split(" ");(k=d[l++])!=null;){n=X.exec(k);s="";if(n){s=n[0];k=k.replace(X,"")}if(k==="hover")d.push("mouseenter"+s,"mouseleave"+s);else{n=k;if(k==="focus"||k==="blur"){d.push(wa[k]+s);k+=s}else k=(wa[k]||k)+s;if(b==="live"){s=0;for(var B=h.length;s<B;s++)c.event.add(h[s],"live."+Y(k,v),{data:e,selector:v,handler:f,origType:k,origHandler:f,preType:n})}else h.unbind("live."+Y(k,v),f)}}return this}});
+c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
+(function(){function a(g,j,o,m,p,q){p=0;for(var t=m.length;p<t;p++){var x=m[p];if(x){x=x[g];for(var C=false;x;){if(x.sizcache===o){C=m[x.sizset];break}if(x.nodeType===1&&!q){x.sizcache=o;x.sizset=p}if(x.nodeName.toLowerCase()===j){C=x;break}x=x[g]}m[p]=C}}}function b(g,j,o,m,p,q){p=0;for(var t=m.length;p<t;p++){var x=m[p];if(x){x=x[g];for(var C=false;x;){if(x.sizcache===o){C=m[x.sizset];break}if(x.nodeType===1){if(!q){x.sizcache=o;x.sizset=p}if(typeof j!=="string"){if(x===j){C=true;break}}else if(l.filter(j,
+[x]).length>0){C=x;break}}x=x[g]}m[p]=C}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,k=true;[0,0].sort(function(){k=false;return 0});var l=function(g,j,o,m){o=o||[];var p=j=j||u;if(j.nodeType!==1&&j.nodeType!==9)return[];if(!g||typeof g!=="string")return o;var q=[],t,x,C,P,N=true,R=l.isXML(j),Q=g,L;do{d.exec("");if(t=d.exec(Q)){Q=t[3];q.push(t[1]);if(t[2]){P=t[3];
+break}}}while(t);if(q.length>1&&s.exec(g))if(q.length===2&&n.relative[q[0]])x=M(q[0]+q[1],j);else for(x=n.relative[q[0]]?[j]:l(q.shift(),j);q.length;){g=q.shift();if(n.relative[g])g+=q.shift();x=M(g,x)}else{if(!m&&q.length>1&&j.nodeType===9&&!R&&n.match.ID.test(q[0])&&!n.match.ID.test(q[q.length-1])){t=l.find(q.shift(),j,R);j=t.expr?l.filter(t.expr,t.set)[0]:t.set[0]}if(j){t=m?{expr:q.pop(),set:D(m)}:l.find(q.pop(),q.length===1&&(q[0]==="~"||q[0]==="+")&&j.parentNode?j.parentNode:j,R);x=t.expr?l.filter(t.expr,
+t.set):t.set;if(q.length>0)C=D(x);else N=false;for(;q.length;){t=L=q.pop();if(n.relative[L])t=q.pop();else L="";if(t==null)t=j;n.relative[L](C,t,R)}}else C=[]}C||(C=x);C||l.error(L||g);if(f.call(C)==="[object Array]")if(N)if(j&&j.nodeType===1)for(g=0;C[g]!=null;g++){if(C[g]&&(C[g]===true||C[g].nodeType===1&&l.contains(j,C[g])))o.push(x[g])}else for(g=0;C[g]!=null;g++)C[g]&&C[g].nodeType===1&&o.push(x[g]);else o.push.apply(o,C);else D(C,o);if(P){l(P,p,o,m);l.uniqueSort(o)}return o};l.uniqueSort=function(g){if(w){h=
+k;g.sort(w);if(h)for(var j=1;j<g.length;j++)g[j]===g[j-1]&&g.splice(j--,1)}return g};l.matches=function(g,j){return l(g,null,null,j)};l.matchesSelector=function(g,j){return l(j,null,null,[g]).length>0};l.find=function(g,j,o){var m;if(!g)return[];for(var p=0,q=n.order.length;p<q;p++){var t=n.order[p],x;if(x=n.leftMatch[t].exec(g)){var C=x[1];x.splice(1,1);if(C.substr(C.length-1)!=="\\"){x[1]=(x[1]||"").replace(/\\/g,"");m=n.find[t](x,j,o);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=j.getElementsByTagName("*"));
+return{set:m,expr:g}};l.filter=function(g,j,o,m){for(var p=g,q=[],t=j,x,C,P=j&&j[0]&&l.isXML(j[0]);g&&j.length;){for(var N in n.filter)if((x=n.leftMatch[N].exec(g))!=null&&x[2]){var R=n.filter[N],Q,L;L=x[1];C=false;x.splice(1,1);if(L.substr(L.length-1)!=="\\"){if(t===q)q=[];if(n.preFilter[N])if(x=n.preFilter[N](x,t,o,q,m,P)){if(x===true)continue}else C=Q=true;if(x)for(var i=0;(L=t[i])!=null;i++)if(L){Q=R(L,x,i,t);var r=m^!!Q;if(o&&Q!=null)if(r)C=true;else t[i]=false;else if(r){q.push(L);C=true}}if(Q!==
+A){o||(t=q);g=g.replace(n.match[N],"");if(!C)return[];break}}}if(g===p)if(C==null)l.error(g);else break;p=g}return t};l.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=l.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
+POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,j){var o=typeof j==="string",m=o&&!/\W/.test(j);o=o&&!m;if(m)j=j.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=o||q&&q.nodeName.toLowerCase()===
+j?q||false:q===j}o&&l.filter(j,g,true)},">":function(g,j){var o=typeof j==="string",m,p=0,q=g.length;if(o&&!/\W/.test(j))for(j=j.toLowerCase();p<q;p++){if(m=g[p]){o=m.parentNode;g[p]=o.nodeName.toLowerCase()===j?o:false}}else{for(;p<q;p++)if(m=g[p])g[p]=o?m.parentNode:m.parentNode===j;o&&l.filter(j,g,true)}},"":function(g,j,o){var m=e++,p=b,q;if(typeof j==="string"&&!/\W/.test(j)){q=j=j.toLowerCase();p=a}p("parentNode",j,m,g,q,o)},"~":function(g,j,o){var m=e++,p=b,q;if(typeof j==="string"&&!/\W/.test(j)){q=
+j=j.toLowerCase();p=a}p("previousSibling",j,m,g,q,o)}},find:{ID:function(g,j,o){if(typeof j.getElementById!=="undefined"&&!o)return(g=j.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,j){if(typeof j.getElementsByName!=="undefined"){for(var o=[],m=j.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&o.push(m[p]);return o.length===0?null:o}},TAG:function(g,j){return j.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,j,o,m,p,q){g=" "+g[1].replace(/\\/g,
+"")+" ";if(q)return g;q=0;for(var t;(t=j[q])!=null;q++)if(t)if(p^(t.className&&(" "+t.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))o||m.push(t);else if(o)j[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var j=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=j[1]+(j[2]||1)-0;g[3]=j[3]-0}g[0]=e++;return g},ATTR:function(g,j,o,
+m,p,q){j=g[1].replace(/\\/g,"");if(!q&&n.attrMap[j])g[1]=n.attrMap[j];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,j,o,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=l(g[3],null,null,j);else{g=l.filter(g[3],j,o,true^p);o||m.push.apply(m,g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
+true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,j,o){return!!l(o[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
+g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,j){return j===0},last:function(g,j,o,m){return j===m.length-1},even:function(g,j){return j%2===0},odd:function(g,j){return j%2===1},lt:function(g,j,o){return j<o[3]-0},gt:function(g,j,o){return j>o[3]-0},nth:function(g,j,o){return o[3]-
+0===j},eq:function(g,j,o){return o[3]-0===j}},filter:{PSEUDO:function(g,j,o,m){var p=j[1],q=n.filters[p];if(q)return q(g,o,j,m);else if(p==="contains")return(g.textContent||g.innerText||l.getText([g])||"").indexOf(j[3])>=0;else if(p==="not"){j=j[3];o=0;for(m=j.length;o<m;o++)if(j[o]===g)return false;return true}else l.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,j){var o=j[1],m=g;switch(o){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(o===
+"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":o=j[2];var p=j[3];if(o===1&&p===0)return true;var q=j[0],t=g.parentNode;if(t&&(t.sizcache!==q||!g.nodeIndex)){var x=0;for(m=t.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++x;t.sizcache=q}m=g.nodeIndex-p;return o===0?m===0:m%o===0&&m/o>=0}},ID:function(g,j){return g.nodeType===1&&g.getAttribute("id")===j},TAG:function(g,j){return j==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
+j},CLASS:function(g,j){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(j)>-1},ATTR:function(g,j){var o=j[1];o=n.attrHandle[o]?n.attrHandle[o](g):g[o]!=null?g[o]:g.getAttribute(o);var m=o+"",p=j[2],q=j[4];return o==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&o!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,j,o,m){var p=n.setFilters[j[2]];
+if(p)return p(g,o,j,m)}}},s=n.match.POS,v=function(g,j){return"\\"+(j-0+1)},B;for(B in n.match){n.match[B]=RegExp(n.match[B].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[B]=RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[B].source.replace(/\\(\d+)/g,v))}var D=function(g,j){g=Array.prototype.slice.call(g,0);if(j){j.push.apply(j,g);return j}return g};try{Array.prototype.slice.call(u.documentElement.childNodes,0)}catch(H){D=function(g,j){var o=j||[],m=0;if(f.call(g)==="[object Array]")Array.prototype.push.apply(o,
+g);else if(typeof g.length==="number")for(var p=g.length;m<p;m++)o.push(g[m]);else for(;g[m];m++)o.push(g[m]);return o}}var w,G;if(u.documentElement.compareDocumentPosition)w=function(g,j){if(g===j){h=true;return 0}if(!g.compareDocumentPosition||!j.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(j)&4?-1:1};else{w=function(g,j){var o=[],m=[],p=g.parentNode,q=j.parentNode,t=p;if(g===j){h=true;return 0}else if(p===q)return G(g,j);else if(p){if(!q)return 1}else return-1;
+for(;t;){o.unshift(t);t=t.parentNode}for(t=q;t;){m.unshift(t);t=t.parentNode}p=o.length;q=m.length;for(t=0;t<p&&t<q;t++)if(o[t]!==m[t])return G(o[t],m[t]);return t===p?G(g,m[t],-1):G(o[t],j,1)};G=function(g,j,o){if(g===j)return o;for(g=g.nextSibling;g;){if(g===j)return-1;g=g.nextSibling}return 1}}l.getText=function(g){for(var j="",o,m=0;g[m];m++){o=g[m];if(o.nodeType===3||o.nodeType===4)j+=o.nodeValue;else if(o.nodeType!==8)j+=l.getText(o.childNodes)}return j};(function(){var g=u.createElement("div"),
+j="script"+(new Date).getTime();g.innerHTML="<a name='"+j+"'/>";var o=u.documentElement;o.insertBefore(g,o.firstChild);if(u.getElementById(j)){n.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:A:[]};n.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}o.removeChild(g);
+o=g=null})();(function(){var g=u.createElement("div");g.appendChild(u.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(j,o){var m=o.getElementsByTagName(j[1]);if(j[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(j){return j.getAttribute("href",2)};g=null})();u.querySelectorAll&&
+function(){var g=l,j=u.createElement("div");j.innerHTML="<p class='TEST'></p>";if(!(j.querySelectorAll&&j.querySelectorAll(".TEST").length===0)){l=function(m,p,q,t){p=p||u;if(!t&&!l.isXML(p))if(p.nodeType===9)try{return D(p.querySelectorAll(m),q)}catch(x){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var C=p.id,P=p.id="__sizzle__";try{return D(p.querySelectorAll("#"+P+" "+m),q)}catch(N){}finally{if(C)p.id=C;else p.removeAttribute("id")}}return g(m,p,q,t)};for(var o in g)l[o]=g[o];
+j=null}}();(function(){var g=u.documentElement,j=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,o=false;try{j.call(u.documentElement,":sizzle")}catch(m){o=true}if(j)l.matchesSelector=function(p,q){try{if(o||!n.match.PSEUDO.test(q))return j.call(p,q)}catch(t){}return l(q,null,null,[p]).length>0}})();(function(){var g=u.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===
+0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(j,o,m){if(typeof o.getElementsByClassName!=="undefined"&&!m)return o.getElementsByClassName(j[1])};g=null}}})();l.contains=u.documentElement.contains?function(g,j){return g!==j&&(g.contains?g.contains(j):true)}:function(g,j){return!!(g.compareDocumentPosition(j)&16)};l.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var M=function(g,
+j){for(var o=[],m="",p,q=j.nodeType?[j]:j;p=n.match.PSEUDO.exec(g);){m+=p[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;p=0;for(var t=q.length;p<t;p++)l(g,q[p],o);return l.filter(m,o)};c.find=l;c.expr=l.selectors;c.expr[":"]=c.expr.filters;c.unique=l.uniqueSort;c.text=l.getText;c.isXMLDoc=l.isXML;c.contains=l.contains})();var Wa=/Until$/,Xa=/^(?:parents|prevUntil|prevAll)/,Ya=/,/,Ja=/^.[^:#\[\.,]*$/,Za=Array.prototype.slice,$a=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("",
+"find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var k=0;k<d;k++)if(b[k]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(ka(this,a,false),"not",a)},filter:function(a){return this.pushStack(ka(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,
+b){var d=[],e,f,h=this[0];if(c.isArray(a)){var k={},l,n=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:n})}h=h.parentNode;n++}}return d}k=$a.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(k?k.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||
+!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});
+c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",
+d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Wa.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||Ya.test(e))&&Xa.test(a))f=f.reverse();return this.pushStack(f,a,Za.call(arguments).join(","))}});
+c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===A||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var xa=/ jQuery\d+="(?:\d+|null)"/g,
+$=/^\s+/,ya=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,za=/<([\w:]+)/,ab=/<tbody/i,bb=/<|&#?\w+;/,Aa=/<(?:script|object|embed|option|style)/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,cb=/\=([^="'>\s]+\/)>/g,O={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],
+area:[1,"<map>","</map>"],_default:[0,"",""]};O.optgroup=O.option;O.tbody=O.tfoot=O.colgroup=O.caption=O.thead;O.th=O.td;if(!c.support.htmlSerialize)O._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==A)return this.empty().append((this[0]&&this[0].ownerDocument||u).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,
+d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},
+unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=
+c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));
+c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(xa,"").replace(cb,'="$1">').replace($,
+"")],e)[0]}else return this.cloneNode(true)});if(a===true){la(this,b);la(this.find("*"),b.find("*"))}return b},html:function(a){if(a===A)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(xa,""):null;else if(typeof a==="string"&&!Aa.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!O[(za.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ya,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?
+this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,
+true)},domManip:function(a,b,d){var e,f,h=a[0],k=[],l;if(!c.support.checkClone&&arguments.length===3&&typeof h==="string"&&Ba.test(h))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(h))return this.each(function(s){var v=c(this);a[0]=h.call(this,s,b?v.html():A);v.domManip(a,b,d)});if(this[0]){e=h&&h.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);l=e.fragment;if(f=l.childNodes.length===1?l=l.firstChild:
+l.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var n=this.length;f<n;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):this[f]:this[f],f>0||e.cacheable||this.length>1?l.cloneNode(true):l)}k.length&&c.each(k,Ka)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:u;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===u&&!Aa.test(a[0])&&(c.support.checkClone||
+!Ba.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=
+d.length;f<h;f++){var k=(f>0?this.clone(true):this).get();c(d[f])[b](k);e=e.concat(k)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||u;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||u;for(var f=[],h=0,k;(k=a[h])!=null;h++){if(typeof k==="number")k+="";if(k){if(typeof k==="string"&&!bb.test(k))k=b.createTextNode(k);else if(typeof k==="string"){k=k.replace(ya,"<$1></$2>");var l=(za.exec(k)||["",""])[1].toLowerCase(),n=O[l]||O._default,
+s=n[0],v=b.createElement("div");for(v.innerHTML=n[1]+k+n[2];s--;)v=v.lastChild;if(!c.support.tbody){s=ab.test(k);l=l==="table"&&!s?v.firstChild&&v.firstChild.childNodes:n[1]==="<table>"&&!s?v.childNodes:[];for(n=l.length-1;n>=0;--n)c.nodeName(l[n],"tbody")&&!l[n].childNodes.length&&l[n].parentNode.removeChild(l[n])}!c.support.leadingWhitespace&&$.test(k)&&v.insertBefore(b.createTextNode($.exec(k)[0]),v.firstChild);k=v.childNodes}if(k.nodeType)f.push(k);else f=c.merge(f,k)}}if(d)for(h=0;f[h];h++)if(e&&
+c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,k=0,l;(l=a[k])!=null;k++)if(!(l.nodeName&&c.noData[l.nodeName.toLowerCase()]))if(d=l[c.expando]){if((b=e[d])&&b.events)for(var n in b.events)f[n]?
+c.event.remove(l,n):c.removeEvent(l,n,b.handle);if(h)delete l[c.expando];else l.removeAttribute&&l.removeAttribute(c.expando);delete e[d]}}});var Ca=/alpha\([^)]*\)/i,db=/opacity=([^)]*)/,eb=/-([a-z])/ig,fb=/([A-Z])/g,Da=/^-?\d+(?:px)?$/i,gb=/^-?\d/,hb={position:"absolute",visibility:"hidden",display:"block"},La=["Left","Right"],Ma=["Top","Bottom"],W,ib=u.defaultView&&u.defaultView.getComputedStyle,jb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===A)return this;
+return c.access(this,a,b,true,function(d,e,f){return f!==A?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),k=a.style,l=c.cssHooks[h];b=c.cssProps[h]||
+h;if(d!==A){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!l||!("set"in l)||(d=l.set(a,d))!==A)try{k[b]=d}catch(n){}}}else{if(l&&"get"in l&&(f=l.get(a,false,e))!==A)return f;return k[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==A)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=
+e[f]},camelCase:function(a){return a.replace(eb,jb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=ma(d,b,f);else c.swap(d,hb,function(){h=ma(d,b,f)});return h+"px"}},set:function(d,e){if(Da.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return db.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":
+b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=d.filter||"";d.filter=Ca.test(f)?f.replace(Ca,e):d.filter+" "+e}};if(ib)W=function(a,b,d){var e;d=d.replace(fb,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return A;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};else if(u.documentElement.currentStyle)W=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],
+h=a.style;if(!Da.test(f)&&gb.test(f)){d=h.left;e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f};if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var kb=c.now(),lb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+mb=/^(?:select|textarea)/i,nb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ob=/^(?:GET|HEAD|DELETE)$/,Na=/\[\]$/,T=/\=\?(&|$)/,ia=/\?/,pb=/([?&])_=[^&]*/,qb=/^(\w+:)?\/\/([^\/?#]+)/,rb=/%20/g,sb=/#.*$/,Ea=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ea)return Ea.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=
+b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(k,l){if(l==="success"||l==="notmodified")h.html(f?c("<div>").append(k.responseText.replace(lb,"")).find(f):k.responseText);d&&h.each(d,[k.responseText,l,k])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
+!this.disabled&&(this.checked||mb.test(this.nodeName)||nb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
+getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
+script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),k=ob.test(h);b.url=b.url.replace(sb,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ia.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
+!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+kb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var l=E[d];E[d]=function(m){f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);if(c.isFunction(l))l(m);else{E[d]=A;try{delete E[d]}catch(p){}}v&&v.removeChild(B)}}if(b.dataType==="script"&&b.cache===null)b.cache=
+false;if(b.cache===false&&h==="GET"){var n=c.now(),s=b.url.replace(pb,"$1_="+n);b.url=s+(s===b.url?(ia.test(b.url)?"&":"?")+"_="+n:"")}if(b.data&&h==="GET")b.url+=(ia.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");n=(n=qb.exec(b.url))&&(n[1]&&n[1]!==location.protocol||n[2]!==location.host);if(b.dataType==="script"&&h==="GET"&&n){var v=u.getElementsByTagName("head")[0]||u.documentElement,B=u.createElement("script");if(b.scriptCharset)B.charset=b.scriptCharset;B.src=
+b.url;if(!d){var D=false;B.onload=B.onreadystatechange=function(){if(!D&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){D=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);B.onload=B.onreadystatechange=null;v&&B.parentNode&&v.removeChild(B)}}}v.insertBefore(B,v.firstChild);return A}var H=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!k||a&&a.contentType)w.setRequestHeader("Content-Type",
+b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}n||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(G){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
+c.triggerGlobal(b,"ajaxSend",[w,b]);var M=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){H||c.handleComplete(b,w,e,f);H=true;if(w)w.onreadystatechange=c.noop}else if(!H&&w&&(w.readyState===4||m==="timeout")){H=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
+c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&g.call&&g.call(w);M("abort")}}catch(j){}b.async&&b.timeout>0&&setTimeout(function(){w&&!H&&M("timeout")},b.timeout);try{w.send(k||b.data==null?null:b.data)}catch(o){c.handleError(b,w,null,o);c.handleComplete(b,w,e,f)}b.async||M();return w}},param:function(a,b){var d=[],e=function(h,k){k=c.isFunction(k)?k():k;d[d.length]=encodeURIComponent(h)+
+"="+encodeURIComponent(k)};if(b===A)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)ca(f,a[f],b,e);return d.join("&").replace(rb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",[b,a])},handleComplete:function(a,
+b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),e=a.getResponseHeader("Etag");
+if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});if(E.ActiveXObject)c.ajaxSettings.xhr=
+function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var da={},tb=/^(?:toggle|show|hide)$/,ub=/^([+\-]=)?([\d+.\-]+)(.*)$/,aa,na=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",3),a,b,d);else{a=
+0;for(b=this.length;a<b;a++){if(!c.data(this[a],"olddisplay")&&this[a].style.display==="none")this[a].style.display="";this[a].style.display===""&&c.css(this[a],"display")==="none"&&c.data(this[a],"olddisplay",oa(this[a].nodeName))}for(a=0;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",d)}for(a=
+0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,d,e);if(c.isEmptyObject(a))return this.each(f.complete);
+return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),k,l=this.nodeType===1,n=l&&c(this).is(":hidden"),s=this;for(k in a){var v=c.camelCase(k);if(k!==v){a[v]=a[k];delete a[k];k=v}if(a[k]==="hide"&&n||a[k]==="show"&&!n)return h.complete.call(this);if(l&&(k==="height"||k==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(oa(this.nodeName)===
+"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[k])){(h.specialEasing=h.specialEasing||{})[k]=a[k][1];a[k]=a[k][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(B,D){var H=new c.fx(s,h,B);if(tb.test(D))H[D==="toggle"?n?"show":"hide":D](a);else{var w=ub.exec(D),G=H.cur(true)||0;if(w){var M=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(s,B,(M||1)+g);
+G=(M||1)/H.cur(true)*G;c.style(s,B,G+g)}if(w[1])M=(w[1]==="-="?-1:1)*M+G;H.custom(G,M,g)}else H.custom(G,D,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
+d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
+Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(h){return f.step(h)}
+this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var f=this;a=c.fx;e.elem=this.elem;if(e()&&c.timers.push(e)&&!aa)aa=setInterval(a.tick,a.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
+this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(l,n){f.style["overflow"+n]=h.overflow[l]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
+this.options.show)for(var k in this.options.curAnim)c.style(this.elem,k,this.options.orig[k]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
+c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(aa);aa=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
+b.elem}).length};var vb=/^t(?:able|d|h)$/i,Fa=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in u.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(k){c.offset.setOffset(this,a,k)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=ea(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
+h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(s){c.offset.setOffset(this,a,s)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,e=b.ownerDocument,f,h=e.documentElement,k=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;
+for(var l=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==k&&b!==h;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;f=e?e.getComputedStyle(b,null):b.currentStyle;l-=b.scrollTop;n-=b.scrollLeft;if(b===d){l+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&vb.test(b.nodeName))){l+=parseFloat(f.borderTopWidth)||0;n+=parseFloat(f.borderLeftWidth)||0}d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&f.overflow!=="visible"){l+=
+parseFloat(f.borderTopWidth)||0;n+=parseFloat(f.borderLeftWidth)||0}f=f}if(f.position==="relative"||f.position==="static"){l+=k.offsetTop;n+=k.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){l+=Math.max(h.scrollTop,k.scrollTop);n+=Math.max(h.scrollLeft,k.scrollLeft)}return{top:l,left:n}};c.offset={initialize:function(){var a=u.body,b=u.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
+height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
+f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
+"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),k=c.css(a,"top"),l=c.css(a,"left"),n=e==="absolute"&&c.inArray("auto",[k,l])>-1;e={};var s={};if(n)s=f.position();k=n?s.top:parseInt(k,10)||0;l=n?s.left:parseInt(l,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+k;if(b.left!=null)e.left=b.left-h.left+l;"using"in b?b.using.call(a,
+e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Fa.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||u.body;a&&!Fa.test(a.nodeName)&&
+c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==A)return this.each(function(){if(h=ea(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=ea(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
+c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(h){var k=c(this);k[d](e.call(this,h,k[d]()))});return c.isWindow(f)?f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b]:f.nodeType===9?Math.max(f.documentElement["client"+
+b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]):e===A?parseFloat(c.css(f,d)):this.css(d,typeof e==="string"?e:e+"px")}})})(window);

--- /dev/null
+++ b/media/unit_testing/controller.js
@@ -1,1 +1,94 @@
+var giTotalTestCount = 0;
+var giActiveModule = 0;
+var giModuleTests;
+var giStartTime;
+var giTest;
+var gbStop = false;
+var gtoTest;
 
+function fnTestStart ( sTestInfo )
+{
+	gaoTest[ giActiveModule ].iTests++;
+	document.getElementById('test_info').innerHTML += 
+		(giActiveModule+1)+'.'+(giModuleTests+1)+'. '+sTestInfo+'... ';
+	document.getElementById('test_number').innerHTML = giTotalTestCount+1;
+	giModuleTests++;
+	giTotalTestCount++;
+	
+	/* Set a timer to catch stalled script */
+	gtoTest = setTimeout( function () {
+		fnMessage( '<span class="error">WARNING - test script stalled. Likely a JS error</span>' );
+		gbStop = true;
+	}, 3000 );
+}
+
+function fnTestResult ( bResult )
+{
+	clearTimeout( gtoTest );
+	if ( bResult )
+	{
+		fnMessage( 'Passed' );
+	}
+	else
+	{
+		fnMessage( '<span class="error">FAILED</span>' );
+		gbStop = true;
+		fnEnd( false );
+	}
+}
+
+function fnUnitStart( iTest )
+{
+	if ( !gbStop )
+	{
+		giModuleTests = 0;
+		window.parent.test_arena.location.href = 
+			(iTest==0?"":"../")+'templates/'+gaoTest[iTest].sTemplate+'.php?scripts='+gaoTest[iTest].sTest;
+		giTest = iTest;
+	}
+}
+
+function fnStartMessage( sMessage )
+{
+	fnMessage( '<br><b>'+gaoTest[giTest].sGroup+' - '+sMessage+'</b>' );
+}
+
+function fnMessage( sMessage )
+{
+	var nInfo = document.getElementById('test_info');
+	nInfo.innerHTML += sMessage+'<br>';
+	nInfo.scrollTop = nInfo.scrollHeight;
+}
+
+function fnUnitComplete()
+{
+	if ( giActiveModule < gaoTest.length - 1 )
+	{
+		fnUnitStart( ++giActiveModule );
+	}
+	else
+	{
+		fnEnd( true );
+	}
+}
+
+function fnEnd( bSuccess )
+{ 
+	var iEndTime = new Date().getTime();
+	var sTime = '<br>This test run took '+parseInt((iEndTime-giStartTime)/1000, 10)+
+			' second(s) to complete.';
+	
+	if ( bSuccess )
+	{
+		$('#test_running').html( 'Tests complete. '+giTotalTestCount+' tests were run.'+sTime );
+	}
+	else
+	{
+		$('#test_running').html( 'Unit tests failed at test '+giTotalTestCount+'.'+sTime );
+	}
+}
+
+$(document).ready( function () {
+	giStartTime = new Date().getTime();
+	fnUnitStart( giActiveModule );
+} );

--- /dev/null
+++ b/media/unit_testing/controller.php
@@ -1,1 +1,100 @@
-
+<?php
+	header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); 
+	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); 
+	header( 'Cache-Control: no-store, no-cache, must-revalidate' ); 
+	header( 'Cache-Control: post-check=0, pre-check=0', false ); 
+	header( 'Pragma: no-cache' ); 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="Content-type" content="text/html; charset=utf-8">
+		<title>DataTables unit test controller</title>
+		
+		<style type="text/css" media="screen">
+			#controller {
+				font: 12px/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
+				margin: 0;
+				padding: 0 0 0 0.5em;
+				color: #333;
+				background-color: #fff;
+			}
+			
+			#test_info {
+				position: absolute;
+				top: 0;
+				right: 0;
+				width: 50%;
+				height: 100%;
+				font-size: 11px;
+				overflow: auto;
+			}
+			
+			.error {
+				color: red;
+			}
+			
+			#controller h1 {
+				color: #4E6CA3;
+				font-size: 18px;
+			}
+		</style>
+		
+		<script type="text/javascript" language="javascript" src="../js/jquery.js"></script>
+		<script type="text/javascript" charset="utf-8">
+			var gaoTest = [
+			<?php
+				function fnReadDir( &$aReturn, $path )
+				{
+					$rDir = opendir( $path );
+        	while ( ($file = readdir($rDir)) !== false )
+					{
+						if ( $file == "." || $file == ".." || $file == ".DS_Store" )
+						{
+							continue;
+						}
+						else if ( is_dir( $path.'/'.$file ) )
+						{
+							fnReadDir( $aReturn, $path.'/'.$file );
+						}
+						else
+						{
+							array_push( $aReturn, $path.'/'.$file );
+						}
+					}
+					closedir($rDir);
+				}
+				
+				/* Get the tests dynamically from the 'tests' directory, and their templates */
+				$aFiles = array();
+				fnReadDir( &$aFiles, "tests" );
+				
+				for ( $i=0 ; $i<count($aFiles) ; $i++ )
+				{
+					$sTemplate;
+					$fp = fopen( $aFiles[$i], "r" );
+					fscanf( $fp, "// DATA_TEMPLATE: %s", &$sTemplate );
+					fclose( $fp );
+					
+					$aPath = split('/', $aFiles[$i]);
+					
+					echo '{ '.
+						'"sTemplate": "'.$sTemplate.'", '.
+						'"sTest": "'.$aFiles[$i].'", '.
+						'"sGroup": "'.$aPath[1].'"},'."\n";
+				}
+				
+			?>
+			null ];
+			gaoTest.pop(); /* No interest in the null */
+		</script>
+		<script type="text/javascript" language="javascript" src="controller.js"></script>
+	</head>
+	<body id="controller">
+		<h1>DataTables unit testing</h1>
+		<div id="test_running">Running test: <span id="test_number"></span></div>
+		<div id="test_info">
+			<b>Test information:</b><br>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/index.html
@@ -1,1 +1,7 @@
-
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
+<html>
+	<frameset rows="20%,80%">
+		<frame name="controller" id="controller" src="controller.php">
+		<frame name="test_arena" id="test_arena">
+	</frameset>
+</html>

--- /dev/null
+++ b/media/unit_testing/performance/draw.html
@@ -1,1 +1,482 @@
-
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.datatables.net/favicon.ico" />
+		
+		<title>DataTables example</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" charset="utf-8">
+			$(document).ready(function() {
+				var oTable = $('#example').dataTable();
+				var oSettings = oTable.fnSettings();
+				var iStart = new Date().getTime();
+				
+				//console.profile();
+				//for ( var i=0, iLen=1000 ; i<iLen ; i++ )
+				//{
+				//	oSettings._iDisplayLength = 100;
+				//	oTable.oApi._fnCalculateEnd( oSettings );
+				//	oTable.oApi._fnDraw( oSettings );
+				//	
+				//	oSettings._iDisplayLength = 10;
+				//	oTable.oApi._fnCalculateEnd( oSettings );
+				//	oTable.oApi._fnDraw( oSettings );
+				//}
+				//console.profileEnd();
+				
+				var iEnd = new Date().getTime();
+				document.getElementById('output').innerHTML = "Test took "+(iEnd-iStart)+"mS";
+			} );
+		</script>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> performance test - draw
+			</div>
+			<div id="output"></div>
+			
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr class="gradeX">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 4.0</td>
+			<td>Win 95+</td>
+			<td class="center">4</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.0</td>
+			<td>Win 95+</td>
+			<td class="center">5</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.5</td>
+			<td>Win 95+</td>
+			<td class="center">5.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 6</td>
+			<td>Win 98+</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet Explorer 7</td>
+			<td>Win XP SP2+</td>
+			<td class="center">7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>AOL browser (AOL desktop)</td>
+			<td>Win XP</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.5</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 2.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 3.0</td>
+			<td>Win 2k+ / OSX.3+</td>
+			<td class="center">1.9</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.0</td>
+			<td>OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.5</td>
+			<td>OSX.3+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape 7.2</td>
+			<td>Win 95+ / Mac OS 8.6-9.2</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Browser 8</td>
+			<td>Win 98SE+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Navigator 9</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.1</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.2</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.2</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.3</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.4</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.4</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.5</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.6</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.7</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.8</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Seamonkey 1.1</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Epiphany 2.20</td>
+			<td>Gnome</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.2</td>
+			<td>OSX.3</td>
+			<td class="center">125.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.3</td>
+			<td>OSX.3</td>
+			<td class="center">312.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 2.0</td>
+			<td>OSX.4+</td>
+			<td class="center">419.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 3.0</td>
+			<td>OSX.4+</td>
+			<td class="center">522.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>OmniWeb 5.5</td>
+			<td>OSX.4+</td>
+			<td class="center">420</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>iPod Touch / iPhone</td>
+			<td>iPod</td>
+			<td class="center">420.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>S60</td>
+			<td>S60</td>
+			<td class="center">413</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.0</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.0</td>
+			<td>Win 95+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.2</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.5</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera for Wii</td>
+			<td>Wii</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nokia N800</td>
+			<td>N800</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nintendo DS browser</td>
+			<td>Nintendo DS</td>
+			<td class="center">8.5</td>
+			<td class="center">C/A<sup>1</sup></td>
+		</tr>
+		<tr class="gradeC">
+			<td>KHTML</td>
+			<td>Konqureror 3.1</td>
+			<td>KDE 3.1</td>
+			<td class="center">3.1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.3</td>
+			<td>KDE 3.3</td>
+			<td class="center">3.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.5</td>
+			<td>KDE 3.5</td>
+			<td class="center">3.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Tasman</td>
+			<td>Internet Explorer 4.5</td>
+			<td>Mac OS 8-9</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.1</td>
+			<td>Mac OS 7.6-9</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.2</td>
+			<td>Mac OS 8-X</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.1</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.4</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Dillo 0.8</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Links</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Lynx</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>IE Mobile</td>
+			<td>Windows Mobile 6</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>PSP browser</td>
+			<td>PSP</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeU">
+			<td>Other browsers</td>
+			<td>All others</td>
+			<td>-</td>
+			<td class="center">-</td>
+			<td class="center">U</td>
+		</tr>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</tfoot>
+</table>
+			</div>
+			<div class="spacer"></div>
+			
+			
+			<div id="footer" style="text-align:center;">
+				<span style="font-size:10px;">
+					DataTables &copy; Allan Jardine 2008-2009.
+				</span>
+			</div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/performance/large.php
@@ -1,1 +1,102 @@
+<?php
+  /* MySQL connection */
+	include( $_SERVER['DOCUMENT_ROOT']."/datatables/mysql.php" ); /* ;-) */
+	
+	$gaSql['link'] =  mysql_pconnect( $gaSql['server'], $gaSql['user'], $gaSql['password']  ) or
+		die( 'Could not open connection to server' );
+	
+	mysql_select_db( $gaSql['db'], $gaSql['link'] ) or 
+		die( 'Could not select database '. $gaSql['db'] );
 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.datatables.net/favicon.ico" />
+		
+		<title>DataTables example</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" charset="utf-8">
+			$(document).ready(function() {
+				var iStart = new Date().getTime();
+				
+				if ( typeof console != 'undefined' ) {
+					console.profile();
+				}
+				for ( var i=0 ; i<1 ; i++ )
+				{
+					var oTable = $('#example').dataTable({"bDestroy": true});
+				}
+				if ( typeof console != 'undefined' ) {
+					console.profileEnd();
+				}
+				
+				var iEnd = new Date().getTime();
+				document.getElementById('output').innerHTML = "Test took "+(iEnd-iStart)+"mS";
+			} );
+		</script>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> performance test - draw
+			</div>
+			<div id="output"></div>
+
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th>id</th>
+			<th>name</th>
+			<th>phone</th>
+			<th>email</th>
+			<th>city</th>
+			<th>zip</th>
+			<th>state</th>
+			<th>country</th>
+			<th>zip2</th>
+		</tr>
+	</thead>
+	<tbody>
+<?php
+	$sQuery = "
+		SELECT *
+		FROM   testData
+		LIMIT  2000
+	";
+	$rResult = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
+	while ( $aRow = mysql_fetch_array( $rResult ) )
+	{
+		echo '<tr>';
+		echo '<td><a href="1">'.$aRow['id'].'</a></td>';
+		echo '<td>'.$aRow['name'].'</td>';
+		echo '<td>'.$aRow['phone'].'</td>';
+		echo '<td>'.$aRow['email'].'</td>';
+		echo '<td>'.$aRow['city'].'</td>';
+		echo '<td>'.$aRow['zip'].'</td>';
+		echo '<td>'.$aRow['state'].'</td>';
+		echo '<td>'.$aRow['country'].'</td>';
+		echo '<td>'.$aRow['zip2'].'</td>';
+		echo '</tr>';
+		
+	}
+?>
+	</tbody>
+</table>
+			</div>
+			<div class="spacer"></div>
+			
+			<div id="footer" style="text-align:center;">
+				<span style="font-size:10px;">
+					DataTables &copy; Allan Jardine 2008-2009.
+				</span>
+			</div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/performance/page.html
@@ -1,1 +1,477 @@
-
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.datatables.net/favicon.ico" />
+		
+		<title>DataTables example</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" charset="utf-8">
+			$(document).ready(function() {
+				var oTable = $('#example').dataTable();
+				var oSettings = oTable.fnSettings();
+				var iStart = new Date().getTime();
+				
+				//for ( var i=0, iLen=100 ; i<iLen ; i++ )
+				//{
+				console.profile( );
+					oTable.fnPageChange( "next" );
+					oTable.fnPageChange( "previous" );
+				console.profileEnd( );
+				//}
+				
+				var iEnd = new Date().getTime();
+				document.getElementById('output').innerHTML = "Test took "+(iEnd-iStart)+"mS";
+			} );
+		</script>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> performance test - draw
+			</div>
+			<div id="output"></div>
+			
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr class="gradeX">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 4.0</td>
+			<td>Win 95+</td>
+			<td class="center">4</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.0</td>
+			<td>Win 95+</td>
+			<td class="center">5</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.5</td>
+			<td>Win 95+</td>
+			<td class="center">5.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 6</td>
+			<td>Win 98+</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet Explorer 7</td>
+			<td>Win XP SP2+</td>
+			<td class="center">7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>AOL browser (AOL desktop)</td>
+			<td>Win XP</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.5</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 2.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 3.0</td>
+			<td>Win 2k+ / OSX.3+</td>
+			<td class="center">1.9</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.0</td>
+			<td>OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.5</td>
+			<td>OSX.3+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape 7.2</td>
+			<td>Win 95+ / Mac OS 8.6-9.2</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Browser 8</td>
+			<td>Win 98SE+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Navigator 9</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.1</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.2</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.2</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.3</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.4</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.4</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.5</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.6</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.7</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.8</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Seamonkey 1.1</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Epiphany 2.20</td>
+			<td>Gnome</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.2</td>
+			<td>OSX.3</td>
+			<td class="center">125.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.3</td>
+			<td>OSX.3</td>
+			<td class="center">312.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 2.0</td>
+			<td>OSX.4+</td>
+			<td class="center">419.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 3.0</td>
+			<td>OSX.4+</td>
+			<td class="center">522.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>OmniWeb 5.5</td>
+			<td>OSX.4+</td>
+			<td class="center">420</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>iPod Touch / iPhone</td>
+			<td>iPod</td>
+			<td class="center">420.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>S60</td>
+			<td>S60</td>
+			<td class="center">413</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.0</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.0</td>
+			<td>Win 95+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.2</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.5</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera for Wii</td>
+			<td>Wii</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nokia N800</td>
+			<td>N800</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nintendo DS browser</td>
+			<td>Nintendo DS</td>
+			<td class="center">8.5</td>
+			<td class="center">C/A<sup>1</sup></td>
+		</tr>
+		<tr class="gradeC">
+			<td>KHTML</td>
+			<td>Konqureror 3.1</td>
+			<td>KDE 3.1</td>
+			<td class="center">3.1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.3</td>
+			<td>KDE 3.3</td>
+			<td class="center">3.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.5</td>
+			<td>KDE 3.5</td>
+			<td class="center">3.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Tasman</td>
+			<td>Internet Explorer 4.5</td>
+			<td>Mac OS 8-9</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.1</td>
+			<td>Mac OS 7.6-9</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.2</td>
+			<td>Mac OS 8-X</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.1</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.4</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Dillo 0.8</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Links</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Lynx</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>IE Mobile</td>
+			<td>Windows Mobile 6</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>PSP browser</td>
+			<td>PSP</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeU">
+			<td>Other browsers</td>
+			<td>All others</td>
+			<td>-</td>
+			<td class="center">-</td>
+			<td class="center">U</td>
+		</tr>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</tfoot>
+</table>
+			</div>
+			<div class="spacer"></div>
+			
+			
+			<div id="footer" style="text-align:center;">
+				<span style="font-size:10px;">
+					DataTables &copy; Allan Jardine 2008-2009.
+				</span>
+			</div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/performance/sort.html
@@ -1,1 +1,477 @@
-
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.datatables.net/favicon.ico" />
+		
+		<title>DataTables example</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" charset="utf-8">
+			$(document).ready(function() {
+				var oTable = $('#example').dataTable();
+				var oSettings = oTable.fnSettings();
+				var iStart = new Date().getTime();
+				
+				for ( var i=0, iLen=100 ; i<iLen ; i++ )
+				{
+				console.profile( );
+					oTable.fnSort( [[1, 'asc']] );
+					oTable.fnSort( [[0, 'asc']] );
+				console.profileEnd( );
+				}
+				
+				var iEnd = new Date().getTime();
+				document.getElementById('output').innerHTML = "Test took "+(iEnd-iStart)+"mS";
+			} );
+		</script>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> performance test - draw
+			</div>
+			<div id="output"></div>
+			
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr class="gradeX">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 4.0</td>
+			<td>Win 95+</td>
+			<td class="center">4</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.0</td>
+			<td>Win 95+</td>
+			<td class="center">5</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.5</td>
+			<td>Win 95+</td>
+			<td class="center">5.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 6</td>
+			<td>Win 98+</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet Explorer 7</td>
+			<td>Win XP SP2+</td>
+			<td class="center">7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>AOL browser (AOL desktop)</td>
+			<td>Win XP</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.5</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 2.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 3.0</td>
+			<td>Win 2k+ / OSX.3+</td>
+			<td class="center">1.9</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.0</td>
+			<td>OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.5</td>
+			<td>OSX.3+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape 7.2</td>
+			<td>Win 95+ / Mac OS 8.6-9.2</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Browser 8</td>
+			<td>Win 98SE+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Navigator 9</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.1</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.2</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.2</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.3</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.4</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.4</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.5</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.6</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.7</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.8</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Seamonkey 1.1</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Epiphany 2.20</td>
+			<td>Gnome</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.2</td>
+			<td>OSX.3</td>
+			<td class="center">125.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.3</td>
+			<td>OSX.3</td>
+			<td class="center">312.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 2.0</td>
+			<td>OSX.4+</td>
+			<td class="center">419.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 3.0</td>
+			<td>OSX.4+</td>
+			<td class="center">522.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>OmniWeb 5.5</td>
+			<td>OSX.4+</td>
+			<td class="center">420</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>iPod Touch / iPhone</td>
+			<td>iPod</td>
+			<td class="center">420.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>S60</td>
+			<td>S60</td>
+			<td class="center">413</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.0</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.0</td>
+			<td>Win 95+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.2</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.5</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera for Wii</td>
+			<td>Wii</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nokia N800</td>
+			<td>N800</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nintendo DS browser</td>
+			<td>Nintendo DS</td>
+			<td class="center">8.5</td>
+			<td class="center">C/A<sup>1</sup></td>
+		</tr>
+		<tr class="gradeC">
+			<td>KHTML</td>
+			<td>Konqureror 3.1</td>
+			<td>KDE 3.1</td>
+			<td class="center">3.1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.3</td>
+			<td>KDE 3.3</td>
+			<td class="center">3.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.5</td>
+			<td>KDE 3.5</td>
+			<td class="center">3.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Tasman</td>
+			<td>Internet Explorer 4.5</td>
+			<td>Mac OS 8-9</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.1</td>
+			<td>Mac OS 7.6-9</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.2</td>
+			<td>Mac OS 8-X</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.1</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.4</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Dillo 0.8</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Links</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Lynx</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>IE Mobile</td>
+			<td>Windows Mobile 6</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>PSP browser</td>
+			<td>PSP</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeU">
+			<td>Other browsers</td>
+			<td>All others</td>
+			<td>-</td>
+			<td class="center">-</td>
+			<td class="center">U</td>
+		</tr>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</tfoot>
+</table>
+			</div>
+			<div class="spacer"></div>
+			
+			
+			<div id="footer" style="text-align:center;">
+				<span style="font-size:10px;">
+					DataTables &copy; Allan Jardine 2008-2009.
+				</span>
+			</div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/templates/-complex_header.php
@@ -1,1 +1,469 @@
-
+<?php
+	header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); 
+	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); 
+	header( 'Cache-Control: no-store, no-cache, must-revalidate' ); 
+	header( 'Cache-Control: post-check=0, pre-check=0', false ); 
+	header( 'Pragma: no-cache' ); 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.sprymedia.co.uk/media/images/favicon.ico" />
+		
+		<title>DataTables unit testing</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" language="javascript" src="../unit_test.js"></script>
+		<?php
+			$aScripts = split( ":", $_GET['scripts'] );
+			for ( $i=0 ; $i<count($aScripts) ; $i++ )
+			{
+				echo '<script type="text/javascript" language="javascript" src="../'.$aScripts[$i].'?rand='.rand().'"></script>'."\n";
+			}
+		?>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> unit test template for reading DOM data
+			</div>
+			
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th rowspan="2" class="bl bt">Rendering engine</th>
+			<th colspan="3" class="bl br bt">Browser details</th>
+			<th class="br bt">CSS grade</th>
+		</tr>
+		<tr>
+			<th class="bl">Browser</th>
+			<th>Platform(s)</th>
+			<th class="br">Engine version</th>
+			<th class="br bt">CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr class="gradeX">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 4.0</td>
+			<td>Win 95+</td>
+			<td class="center">4</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.0</td>
+			<td>Win 95+</td>
+			<td class="center">5</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.5</td>
+			<td>Win 95+</td>
+			<td class="center">5.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 6</td>
+			<td>Win 98+</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet Explorer 7</td>
+			<td>Win XP SP2+</td>
+			<td class="center">7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>AOL browser (AOL desktop)</td>
+			<td>Win XP</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.5</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 2.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 3.0</td>
+			<td>Win 2k+ / OSX.3+</td>
+			<td class="center">1.9</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.0</td>
+			<td>OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.5</td>
+			<td>OSX.3+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape 7.2</td>
+			<td>Win 95+ / Mac OS 8.6-9.2</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Browser 8</td>
+			<td>Win 98SE+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Navigator 9</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.1</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.2</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.2</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.3</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.4</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.4</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.5</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.6</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.7</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.8</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Seamonkey 1.1</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Epiphany 2.20</td>
+			<td>Gnome</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.2</td>
+			<td>OSX.3</td>
+			<td class="center">125.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.3</td>
+			<td>OSX.3</td>
+			<td class="center">312.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 2.0</td>
+			<td>OSX.4+</td>
+			<td class="center">419.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 3.0</td>
+			<td>OSX.4+</td>
+			<td class="center">522.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>OmniWeb 5.5</td>
+			<td>OSX.4+</td>
+			<td class="center">420</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>iPod Touch / iPhone</td>
+			<td>iPod</td>
+			<td class="center">420.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>S60</td>
+			<td>S60</td>
+			<td class="center">413</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.0</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.0</td>
+			<td>Win 95+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.2</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.5</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera for Wii</td>
+			<td>Wii</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nokia N800</td>
+			<td>N800</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nintendo DS browser</td>
+			<td>Nintendo DS</td>
+			<td class="center">8.5</td>
+			<td class="center">C/A<sup>1</sup></td>
+		</tr>
+		<tr class="gradeC">
+			<td>KHTML</td>
+			<td>Konqureror 3.1</td>
+			<td>KDE 3.1</td>
+			<td class="center">3.1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.3</td>
+			<td>KDE 3.3</td>
+			<td class="center">3.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.5</td>
+			<td>KDE 3.5</td>
+			<td class="center">3.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Tasman</td>
+			<td>Internet Explorer 4.5</td>
+			<td>Mac OS 8-9</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.1</td>
+			<td>Mac OS 7.6-9</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.2</td>
+			<td>Mac OS 8-X</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.1</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.4</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Dillo 0.8</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Links</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Lynx</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>IE Mobile</td>
+			<td>Windows Mobile 6</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>PSP browser</td>
+			<td>PSP</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeU">
+			<td>Other browsers</td>
+			<td>All others</td>
+			<td>-</td>
+			<td class="center">-</td>
+			<td class="center">U</td>
+		</tr>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</tfoot>
+</table>
+			</div>
+			<div class="spacer"></div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/templates/2512.php
@@ -1,1 +1,464 @@
-
+<?php
+	header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); 
+	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); 
+	header( 'Cache-Control: no-store, no-cache, must-revalidate' ); 
+	header( 'Cache-Control: post-check=0, pre-check=0', false ); 
+	header( 'Pragma: no-cache' ); 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.sprymedia.co.uk/media/images/favicon.ico" />
+		
+		<title>DataTables unit testing</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" language="javascript" src="../unit_test.js"></script>
+		<?php
+			$aScripts = split( ":", $_GET['scripts'] );
+			for ( $i=0 ; $i<count($aScripts) ; $i++ )
+			{
+				echo '<script type="text/javascript" language="javascript" src="../'.$aScripts[$i].'?rand='.rand().'"></script>'."\n";
+			}
+		?>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> unit test template for reading DOM data
+			</div>
+			
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr class="gradeX">
+			<td>Trident</td>
+			<td>testsearchstring <br>html &amp; entity</td>
+			<td>Win 95+</td>
+			<td class="center">4</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.0</td>
+			<td>Win 95+</td>
+			<td class="center">5</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.5</td>
+			<td>Win 95+</td>
+			<td class="center">5.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 6</td>
+			<td>Win 98+</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet Explorer 7</td>
+			<td>Win XP SP2+</td>
+			<td class="center">7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>AOL browser (AOL desktop)</td>
+			<td>Win XP</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.5</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 2.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 3.0</td>
+			<td>Win 2k+ / OSX.3+</td>
+			<td class="center">1.9</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.0</td>
+			<td>OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.5</td>
+			<td>OSX.3+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape 7.2</td>
+			<td>Win 95+ / Mac OS 8.6-9.2</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Browser 8</td>
+			<td>Win 98SE+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Navigator 9</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.1</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.2</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.2</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.3</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.4</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.4</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.5</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.6</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.7</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.8</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Seamonkey 1.1</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Epiphany 2.20</td>
+			<td>Gnome</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.2</td>
+			<td>OSX.3</td>
+			<td class="center">125.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.3</td>
+			<td>OSX.3</td>
+			<td class="center">312.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 2.0</td>
+			<td>OSX.4+</td>
+			<td class="center">419.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 3.0</td>
+			<td>OSX.4+</td>
+			<td class="center">522.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>OmniWeb 5.5</td>
+			<td>OSX.4+</td>
+			<td class="center">420</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>iPod Touch / iPhone</td>
+			<td>iPod</td>
+			<td class="center">420.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>S60</td>
+			<td>S60</td>
+			<td class="center">413</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.0</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.0</td>
+			<td>Win 95+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.2</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.5</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera for Wii</td>
+			<td>Wii</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nokia N800</td>
+			<td>N800</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nintendo DS browser</td>
+			<td>Nintendo DS</td>
+			<td class="center">8.5</td>
+			<td class="center">C/A<sup>1</sup></td>
+		</tr>
+		<tr class="gradeC">
+			<td>KHTML</td>
+			<td>Konqureror 3.1</td>
+			<td>KDE 3.1</td>
+			<td class="center">3.1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.3</td>
+			<td>KDE 3.3</td>
+			<td class="center">3.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.5</td>
+			<td>KDE 3.5</td>
+			<td class="center">3.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Tasman</td>
+			<td>Internet Explorer 4.5</td>
+			<td>Mac OS 8-9</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.1</td>
+			<td>Mac OS 7.6-9</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.2</td>
+			<td>Mac OS 8-X</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.1</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.4</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Dillo 0.8</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Links</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Lynx</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>IE Mobile</td>
+			<td>Windows Mobile 6</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>PSP browser</td>
+			<td>PSP</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeU">
+			<td>Other browsers</td>
+			<td>All others</td>
+			<td>-</td>
+			<td class="center">-</td>
+			<td class="center">U</td>
+		</tr>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</tfoot>
+</table>
+			</div>
+			<div class="spacer"></div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/templates/dom_data.php
@@ -1,1 +1,465 @@
-
+<?php
+	header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); 
+	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); 
+	header( 'Cache-Control: no-store, no-cache, must-revalidate' ); 
+	header( 'Cache-Control: post-check=0, pre-check=0', false ); 
+	header( 'Pragma: no-cache' ); 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.sprymedia.co.uk/media/images/favicon.ico" />
+		
+		<title>DataTables unit testing</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" language="javascript" src="../unit_test.js"></script>
+		<?php
+			$aScripts = split( ":", $_GET['scripts'] );
+			for ( $i=0 ; $i<count($aScripts) ; $i++ )
+			{
+				echo '<script type="text/javascript" language="javascript" src="../'.$aScripts[$i].'?rand='.rand().'"></script>'."\n";
+			}
+		?>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> unit test template for reading DOM data
+			</div>
+			
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr class="gradeX">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 4.0</td>
+			<td>Win 95+</td>
+			<td class="center">4</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.0</td>
+			<td>Win 95+</td>
+			<td class="center">5</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.5</td>
+			<td>Win 95+</td>
+			<td class="center">5.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 6</td>
+			<td>Win 98+</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet Explorer 7</td>
+			<td>Win XP SP2+</td>
+			<td class="center">7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>AOL browser (AOL desktop)</td>
+			<td>Win XP</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.5</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 2.0</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 3.0</td>
+			<td>Win 2k+ / OSX.3+</td>
+			<td class="center">1.9</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.0</td>
+			<td>OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.5</td>
+			<td>OSX.3+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape 7.2</td>
+			<td>Win 95+ / Mac OS 8.6-9.2</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Browser 8</td>
+			<td>Win 98SE+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Navigator 9</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.1</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.2</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.2</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.3</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.4</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.4</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.5</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.6</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">1.6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.7</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.8</td>
+			<td>Win 98+ / OSX.1+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Seamonkey 1.1</td>
+			<td>Win 98+ / OSX.2+</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Epiphany 2.20</td>
+			<td>Gnome</td>
+			<td class="center">1.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.2</td>
+			<td>OSX.3</td>
+			<td class="center">125.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 1.3</td>
+			<td>OSX.3</td>
+			<td class="center">312.8</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 2.0</td>
+			<td>OSX.4+</td>
+			<td class="center">419.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>Safari 3.0</td>
+			<td>OSX.4+</td>
+			<td class="center">522.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>OmniWeb 5.5</td>
+			<td>OSX.4+</td>
+			<td class="center">420</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>iPod Touch / iPhone</td>
+			<td>iPod</td>
+			<td class="center">420.1</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Webkit</td>
+			<td>S60</td>
+			<td>S60</td>
+			<td class="center">413</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.0</td>
+			<td>Win 95+ / OSX.1+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 7.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.0</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 8.5</td>
+			<td>Win 95+ / OSX.2+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.0</td>
+			<td>Win 95+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.2</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera 9.5</td>
+			<td>Win 88+ / OSX.3+</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Opera for Wii</td>
+			<td>Wii</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nokia N800</td>
+			<td>N800</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Presto</td>
+			<td>Nintendo DS browser</td>
+			<td>Nintendo DS</td>
+			<td class="center">8.5</td>
+			<td class="center">C/A<sup>1</sup></td>
+		</tr>
+		<tr class="gradeC">
+			<td>KHTML</td>
+			<td>Konqureror 3.1</td>
+			<td>KDE 3.1</td>
+			<td class="center">3.1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.3</td>
+			<td>KDE 3.3</td>
+			<td class="center">3.3</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>KHTML</td>
+			<td>Konqureror 3.5</td>
+			<td>KDE 3.5</td>
+			<td class="center">3.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Tasman</td>
+			<td>Internet Explorer 4.5</td>
+			<td>Mac OS 8-9</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.1</td>
+			<td>Mac OS 7.6-9</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Tasman</td>
+			<td>Internet Explorer 5.2</td>
+			<td>Mac OS 8-X</td>
+			<td class="center">1</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.1</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Misc</td>
+			<td>NetFront 3.4</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Dillo 0.8</td>
+			<td>Embedded devices</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Links</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeX">
+			<td>Misc</td>
+			<td>Lynx</td>
+			<td>Text only</td>
+			<td class="center">-</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>IE Mobile</td>
+			<td>Windows Mobile 6</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Misc</td>
+			<td>PSP browser</td>
+			<td>PSP</td>
+			<td class="center">-</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeU">
+			<td>Other browsers</td>
+			<td>All others</td>
+			<td>-</td>
+			<td class="center">-</td>
+			<td class="center">U</td>
+		</tr>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</tfoot>
+</table>
+			</div>
+			<div class="spacer"></div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/templates/dymanic_table.php
@@ -1,1 +1,45 @@
-
+<?php
+	header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); 
+	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); 
+	header( 'Cache-Control: no-store, no-cache, must-revalidate' ); 
+	header( 'Cache-Control: post-check=0, pre-check=0', false ); 
+	header( 'Pragma: no-cache' ); 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.sprymedia.co.uk/media/images/favicon.ico" />
+		
+		<title>DataTables unit testing</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" language="javascript" src="../unit_test.js"></script>
+		<script type="text/javascript" charset="utf-8">
+			$(document).ready( function () {
+				$('#demo').html( '<table cellpadding="0" cellspacing="0" border="0" class="display" id="example"></table>' );
+			} );
+		</script>
+		<?php
+			$aScripts = split( ":", $_GET['scripts'] );
+			for ( $i=0 ; $i<count($aScripts) ; $i++ )
+			{
+				echo '<script type="text/javascript" language="javascript" src="../'.$aScripts[$i].'?rand='.rand().'"></script>'."\n";
+			}
+		?>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> dynamic table template
+			</div>
+			
+			<h1>Live example</h1>
+			<div id="demo"></div>
+			<div class="spacer"></div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/templates/empty_table.php
@@ -1,1 +1,55 @@
-
+<?php
+	header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); 
+	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); 
+	header( 'Cache-Control: no-store, no-cache, must-revalidate' ); 
+	header( 'Cache-Control: post-check=0, pre-check=0', false ); 
+	header( 'Pragma: no-cache' ); 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.sprymedia.co.uk/media/images/favicon.ico" />
+		
+		<title>DataTables unit testing</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" language="javascript" src="../unit_test.js"></script>
+		<?php
+			$aScripts = split( ":", $_GET['scripts'] );
+			for ( $i=0 ; $i<count($aScripts) ; $i++ )
+			{
+				echo '<script type="text/javascript" language="javascript" src="../'.$aScripts[$i].'?rand='.rand().'"></script>'."\n";
+			}
+		?>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> empty table template
+			</div>
+			
+			<h1>Live example</h1>
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+		
+	</tbody>
+</table>
+			</div>
+			<div class="spacer"></div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/templates/js_data.php
@@ -1,1 +1,124 @@
-
+<?php
+	header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); 
+	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); 
+	header( 'Cache-Control: no-store, no-cache, must-revalidate' ); 
+	header( 'Cache-Control: post-check=0, pre-check=0', false ); 
+	header( 'Pragma: no-cache' ); 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.sprymedia.co.uk/media/images/favicon.ico" />
+		
+		<title>DataTables unit testing</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" language="javascript" src="../unit_test.js"></script>
+		<script type="text/javascript" charset="utf-8">
+			/* Make the data source available for testing */
+			var gaaData = [
+				['Trident','Internet Explorer 4.0','Win 95+','4','X'],
+				['Trident','Internet Explorer 5.0','Win 95+','5','C'],
+				['Trident','Internet Explorer 5.5','Win 95+','5.5','A'],
+				['Trident','Internet Explorer 6','Win 98+','6','A'],
+				['Trident','Internet Explorer 7','Win XP SP2+','7','A'],
+				['Trident','AOL browser (AOL desktop)','Win XP','6','A'],
+				['Gecko','Firefox 1.0','Win 98+ / OSX.2+','1.7','A'],
+				['Gecko','Firefox 1.5','Win 98+ / OSX.2+','1.8','A'],
+				['Gecko','Firefox 2.0','Win 98+ / OSX.2+','1.8','A'],
+				['Gecko','Firefox 3.0','Win 2k+ / OSX.3+','1.9','A'],
+				['Gecko','Camino 1.0','OSX.2+','1.8','A'],
+				['Gecko','Camino 1.5','OSX.3+','1.8','A'],
+				['Gecko','Netscape 7.2','Win 95+ / Mac OS 8.6-9.2','1.7','A'],
+				['Gecko','Netscape Browser 8','Win 98SE+','1.7','A'],
+				['Gecko','Netscape Navigator 9','Win 98+ / OSX.2+','1.8','A'],
+				['Gecko','Mozilla 1.0','Win 95+ / OSX.1+',1,'A'],
+				['Gecko','Mozilla 1.1','Win 95+ / OSX.1+',1.1,'A'],
+				['Gecko','Mozilla 1.2','Win 95+ / OSX.1+',1.2,'A'],
+				['Gecko','Mozilla 1.3','Win 95+ / OSX.1+',1.3,'A'],
+				['Gecko','Mozilla 1.4','Win 95+ / OSX.1+',1.4,'A'],
+				['Gecko','Mozilla 1.5','Win 95+ / OSX.1+',1.5,'A'],
+				['Gecko','Mozilla 1.6','Win 95+ / OSX.1+',1.6,'A'],
+				['Gecko','Mozilla 1.7','Win 98+ / OSX.1+',1.7,'A'],
+				['Gecko','Mozilla 1.8','Win 98+ / OSX.1+',1.8,'A'],
+				['Gecko','Seamonkey 1.1','Win 98+ / OSX.2+','1.8','A'],
+				['Gecko','Epiphany 2.20','Gnome','1.8','A'],
+				['Webkit','Safari 1.2','OSX.3','125.5','A'],
+				['Webkit','Safari 1.3','OSX.3','312.8','A'],
+				['Webkit','Safari 2.0','OSX.4+','419.3','A'],
+				['Webkit','Safari 3.0','OSX.4+','522.1','A'],
+				['Webkit','OmniWeb 5.5','OSX.4+','420','A'],
+				['Webkit','iPod Touch / iPhone','iPod','420.1','A'],
+				['Webkit','S60','S60','413','A'],
+				['Presto','Opera 7.0','Win 95+ / OSX.1+','-','A'],
+				['Presto','Opera 7.5','Win 95+ / OSX.2+','-','A'],
+				['Presto','Opera 8.0','Win 95+ / OSX.2+','-','A'],
+				['Presto','Opera 8.5','Win 95+ / OSX.2+','-','A'],
+				['Presto','Opera 9.0','Win 95+ / OSX.3+','-','A'],
+				['Presto','Opera 9.2','Win 88+ / OSX.3+','-','A'],
+				['Presto','Opera 9.5','Win 88+ / OSX.3+','-','A'],
+				['Presto','Opera for Wii','Wii','-','A'],
+				['Presto','Nokia N800','N800','-','A'],
+				['Presto','Nintendo DS browser','Nintendo DS','8.5','C/A<sup>1</sup>'],
+				['KHTML','Konqureror 3.1','KDE 3.1','3.1','C'],
+				['KHTML','Konqureror 3.3','KDE 3.3','3.3','A'],
+				['KHTML','Konqureror 3.5','KDE 3.5','3.5','A'],
+				['Tasman','Internet Explorer 4.5','Mac OS 8-9','-','X'],
+				['Tasman','Internet Explorer 5.1','Mac OS 7.6-9','1','C'],
+				['Tasman','Internet Explorer 5.2','Mac OS 8-X','1','C'],
+				['Misc','NetFront 3.1','Embedded devices','-','C'],
+				['Misc','NetFront 3.4','Embedded devices','-','A'],
+				['Misc','Dillo 0.8','Embedded devices','-','X'],
+				['Misc','Links','Text only','-','X'],
+				['Misc','Lynx','Text only','-','X'],
+				['Misc','IE Mobile','Windows Mobile 6','-','C'],
+				['Misc','PSP browser','PSP','-','C'],
+				['Other browsers','All others','-','-','U']
+			];
+		</script>
+		<?php
+			$aScripts = split( ":", $_GET['scripts'] );
+			for ( $i=0 ; $i<count($aScripts) ; $i++ )
+			{
+				echo '<script type="text/javascript" language="javascript" src="../'.$aScripts[$i].'?rand='.rand().'"></script>'."\n";
+			}
+		?>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> unit test template for reading DOM data
+			</div>
+			
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</tfoot>
+</table>
+			</div>
+			<div class="spacer"></div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/templates/two_tables.php
@@ -1,1 +1,227 @@
+<?php
+	header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); 
+	header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); 
+	header( 'Cache-Control: no-store, no-cache, must-revalidate' ); 
+	header( 'Cache-Control: post-check=0, pre-check=0', false ); 
+	header( 'Pragma: no-cache' ); 
+?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<link rel="shortcut icon" type="image/ico" href="http://www.sprymedia.co.uk/media/images/favicon.ico" />
+		
+		<title>DataTables unit testing</title>
+		<style type="text/css" title="currentStyle">
+			@import "../../css/demo_page.css";
+			@import "../../css/demo_table.css";
+		</style>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.js"></script>
+		<script type="text/javascript" language="javascript" src="../../js/jquery.dataTables.js"></script>
+		<script type="text/javascript" language="javascript" src="../unit_test.js"></script>
+		<?php
+			$aScripts = split( ":", $_GET['scripts'] );
+			for ( $i=0 ; $i<count($aScripts) ; $i++ )
+			{
+				echo '<script type="text/javascript" language="javascript" src="../'.$aScripts[$i].'?rand='.rand().'"></script>'."\n";
+			}
+		?>
+	</head>
+	<body id="dt_example">
+		<div id="container">
+			<div class="full_width big">
+				<i>DataTables</i> unit test template for two tables
+			</div>
+			
+			<div id="demo">
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example1">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr class="gradeX">
+			<td>Trident</td>
+			<td>testsearchstring <br>html &amp; entity</td>
+			<td>Win 95+</td>
+			<td class="center">4</td>
+			<td class="center">X</td>
+		</tr>
+		<tr class="gradeC">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.0</td>
+			<td>Win 95+</td>
+			<td class="center">5</td>
+			<td class="center">C</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 5.5</td>
+			<td>Win 95+</td>
+			<td class="center">5.5</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet
+				 Explorer 6</td>
+			<td>Win 98+</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>Internet Explorer 7</td>
+			<td>Win XP SP2+</td>
+			<td class="center">7</td>
+			<td class="center">A</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Trident</td>
+			<td>AOL browser (AOL desktop)</td>
+			<td>Win XP</td>
+			<td class="center">6</td>
+			<td class="center">A</td>
+		</tr>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+			<th>Engine version</th>
+			<th>CSS grade</th>
+		</tr>
+	</tfoot>
+</table>
 
+
+<table cellpadding="0" cellspacing="0" border="0" class="display" id="example2">
+	<thead>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.0</td>
+			<td>Win 98+ / OSX.2+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 1.5</td>
+			<td>Win 98+ / OSX.2+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 2.0</td>
+			<td>Win 98+ / OSX.2+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Firefox 3.0</td>
+			<td>Win 2k+ / OSX.3+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.0</td>
+			<td>OSX.2+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Camino 1.5</td>
+			<td>OSX.3+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape 7.2</td>
+			<td>Win 95+ / Mac OS 8.6-9.2</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Browser 8</td>
+			<td>Win 98SE+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Netscape Navigator 9</td>
+			<td>Win 98+ / OSX.2+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.0</td>
+			<td>Win 95+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.1</td>
+			<td>Win 95+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.2</td>
+			<td>Win 95+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.3</td>
+			<td>Win 95+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.4</td>
+			<td>Win 95+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.5</td>
+			<td>Win 95+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.6</td>
+			<td>Win 95+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.7</td>
+			<td>Win 98+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Mozilla 1.8</td>
+			<td>Win 98+ / OSX.1+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Seamonkey 1.1</td>
+			<td>Win 98+ / OSX.2+</td>
+		</tr>
+		<tr class="gradeA">
+			<td>Gecko</td>
+			<td>Epiphany 2.20</td>
+			<td>Gnome</td>
+		</tr>
+	</tbody>
+	<tfoot>
+		<tr>
+			<th>Rendering engine</th>
+			<th>Browser</th>
+			<th>Platform(s)</th>
+		</tr>
+	</tfoot>
+</table>
+			</div>
+			<div class="spacer"></div>
+		</div>
+	</body>
+</html>

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/-complex_header.js
@@ -1,1 +1,52 @@
+// DATA_TEMPLATE: -complex_header
+oTest.fnStart( "Complex header" );
 
+
+$(document).ready( function () {
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Sorting on colspan has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on non-unique TH and first TH has no effect",
+		function () { $('#example thead th:eq(2)').click(); },
+		function () { return $('#example tbody tr td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on non-unique TH and second TH will sort",
+		function () { $('#example thead th:eq(6)').click(); },
+		function () { return $('#example tbody tr td:eq(4)').html() == "A"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on non-unique TH and second TH will sort - reserve",
+		function () { $('#example thead th:eq(6)').click(); },
+		function () { return $('#example tbody tr td:eq(4)').html() == "X"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on unique TH will sort",
+		function () { $('#example thead th:eq(5)').click(); },
+		function () { return $('#example tbody tr td:eq(3)').html() == "-"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on unique TH will sort - reserve",
+		function () { $('#example thead th:eq(5)').click(); },
+		function () { return $('#example tbody tr td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on unique rowspan TH will sort",
+		function () { $('#example thead th:eq(0)').click(); },
+		function () { return $('#example tbody tr td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/-iDraw.js
@@ -1,1 +1,41 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "iDraw - check that iDraw increments for each draw" );
 
+
+$(document).ready( function () {
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"After first draw, iDraw is 1",
+		null,
+		function () { return oSettings.iDraw == 1; }
+	);
+	
+	oTest.fnTest( 
+		"After second draw, iDraw is 2",
+		function () { oTable.fnDraw() },
+		function () { return oSettings.iDraw == 2; }
+	);
+	
+	oTest.fnTest( 
+		"After sort",
+		function () { oTable.fnSort([[1,'asc']]) },
+		function () { return oSettings.iDraw == 3; }
+	);
+	
+	oTest.fnTest( 
+		"After filter",
+		function () { oTable.fnFilter('gecko') },
+		function () { return oSettings.iDraw == 4; }
+	);
+	
+	oTest.fnTest( 
+		"After another filter",
+		function () { oTable.fnFilter('gec') },
+		function () { return oSettings.iDraw == 5; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2512.js
@@ -1,1 +1,17 @@
+// DATA_TEMPLATE: 2512
+oTest.fnStart( "Check filtering with BR and HTML entity" );
 
+
+$(document).ready( function () {
+	$('#example').dataTable();
+	
+	/* Basic checks */
+	oTest.fnTest( 
+		"Check filtering",
+		function () { $('#example').dataTable().fnFilter('testsearchstring'); },
+		function () { return $('#example tbody tr').length == 1; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2530-2.js
@@ -1,1 +1,15 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "User given with is left when no scrolling" );
 
+$(document).ready( function () {
+	$('#example')[0].style.width = "80%";
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Check user width is left",
+		null,
+		function () { return $('#example').width() == 640; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2530.js
@@ -1,1 +1,29 @@
+// DATA_TEMPLATE: dymanic_table
+oTest.fnStart( "2530 - Check width's when dealing with empty strings" );
 
+
+$(document).ready( function () {
+	$('#example').dataTable( {
+		"aaData": [
+			['','Internet Explorer 4.0','Win 95+','4','X'],
+			['','Internet Explorer 5.0','Win 95+','5','C']
+		],
+		"aoColumns": [
+			{ "sTitle": "", "sWidth": "40px" },
+			{ "sTitle": "Browser" },
+			{ "sTitle": "Platform" },
+			{ "sTitle": "Version", "sClass": "center" },
+			{ "sTitle": "Grade", "sClass": "center" }
+		]
+	} );
+	
+	/* Basic checks */
+	oTest.fnTest( 
+		"Check calculated widths",
+		null,
+		function () { return $('#example tbody tr td:eq(0)').width() < 100; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2569.js
@@ -1,1 +1,36 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "Destroy with hidden columns" );
 
+$(document).ready( function () {
+	$('#example').dataTable( {
+		"aoColumnDefs": [ 
+			{ "bSearchable": false, "bVisible": false, "aTargets": [ 2 ] },
+			{ "bVisible": false, "aTargets": [ 3 ] }
+		]
+	} );
+	$('#example').dataTable().fnDestroy();
+	
+	oTest.fnTest( 
+		"Check that the number of columns in table is correct",
+		null,
+		function () { return $('#example tbody tr:eq(0) td').length == 5; }
+	);
+	
+	
+	oTest.fnTest( 
+		"And with scrolling",
+		function () {
+			$('#example').dataTable( {
+				"sScrollY": 200,
+				"aoColumnDefs": [ 
+					{ "bSearchable": false, "bVisible": false, "aTargets": [ 2 ] },
+					{ "bVisible": false, "aTargets": [ 3 ] }
+				]
+			} );
+			$('#example').dataTable().fnDestroy();
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 5; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2600.js
@@ -1,1 +1,44 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "2600 - Display rewind when changing length" );
 
+$(document).ready( function () {
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Info correct on init",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Page 2",
+		function () { $('#example_next').click(); },
+		function () { return $('#example_info').html() == "Showing 11 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Page 3",
+		function () { $('#example_next').click(); },
+		function () { return $('#example_info').html() == "Showing 21 to 30 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Page 4",
+		function () { $('#example_next').click(); },
+		function () { return $('#example_info').html() == "Showing 31 to 40 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Page 5",
+		function () { $('#example_next').click(); },
+		function () { return $('#example_info').html() == "Showing 41 to 50 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Rewind",
+		function () { $('#example_length select').val('100'); $('#example_length select').change(); },
+		function () { return $('#example_info').html() == "Showing 1 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2608.js
@@ -1,1 +1,54 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "2608 - State saving escaping filters" );
 
+$(document).ready( function () {
+	$('#example').dataTable( {
+		"bStateSave": true
+	} );
+	
+	oTest.fnTest( 
+		"Set the filter",
+		function () {
+			$('#example_filter input').val( '\\s*CVM\\s*$' );
+			$('#example_filter input').keyup();
+		},
+		function () { return $('#example_filter input').val() == '\\s*CVM\\s*$'; }
+	);
+	
+	oTest.fnTest( 
+		"Destroy the table and remake it - checking the filter was saved",
+		function () {
+			$('#example').dataTable( {
+				"bStateSave": true,
+				"bDestroy": true
+			} );
+		},
+		function () { return $('#example_filter input').val() == '\\s*CVM\\s*$'; }
+	);
+	
+	oTest.fnTest( 
+		"Do it again without state saving and make sure filter is empty",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true
+			} );
+		},
+		function () { return $('#example_filter input').val() == ''; }
+	);
+	
+	oTest.fnTest( 
+		"Clean up",
+		function () {
+			$('#example').dataTable( {
+				"bStateSave": true,
+				"bDestroy": true
+			} );
+			$('#example_filter input').val( '' );
+			$('#example_filter input').keyup();
+		},
+		function () { return $('#example_filter input').val() == ''; }
+	);
+	
+	oTest.fnCookieDestroy( $('#example').dataTable() );
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2635.js
@@ -1,1 +1,40 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "2635 - Hiding column and state saving" );
 
+$(document).ready( function () {
+	$('#example').dataTable( {
+		"bStateSave": true
+	} );
+	
+	oTest.fnTest( 
+		"Set the hidden column",
+		function () {
+			$('#example').dataTable().fnSetColumnVis( 2, false );
+		},
+		function () { return $('#example thead th').length == 4; }
+	);
+	
+	oTest.fnTest( 
+		"Destroy the table and remake it - checking one column was removed",
+		function () {
+			$('#example').dataTable( {
+				"bStateSave": true,
+				"bDestroy": true
+			} );
+		},
+		function () { return $('#example thead th').length == 4; }
+	);
+	
+	oTest.fnTest( 
+		"Do it again without state saving and make sure we are back to 5 columns",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true
+			} );
+		},
+		function () { return $('#example thead th').length == 5; }
+	);
+	
+	oTest.fnCookieDestroy( $('#example').dataTable() );
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2746-stable-sort.js
@@ -1,1 +1,199 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "2746 - Stable sorting" );
 
+$(document).ready( function () {
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Initial sort",
+		null,
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'Firefox 1.0' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Firefox 1.5' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Firefox 2.0';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Reserve initial sort",
+		function () {
+			$('#example thead th:eq(0)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Webkit' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Webkit' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'Safari 1.2' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Safari 1.3' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Safari 2.0';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Reserve to go back to initial sort sort",
+		function () {
+			$('#example thead th:eq(0)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'Firefox 1.0' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Firefox 1.5' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Firefox 2.0';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Reserve initial sort again",
+		function () {
+			$('#example thead th:eq(0)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Webkit' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Webkit' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'Safari 1.2' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Safari 1.3' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Safari 2.0';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"And once more back to the initial sort",
+		function () {
+			$('#example thead th:eq(0)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'Firefox 1.0' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Firefox 1.5' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Firefox 2.0';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sort on second column",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Other browsers' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Trident' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'All others' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'AOL browser (AOL desktop)' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Camino 1.0';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Reserve sort on second column",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Webkit' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'Seamonkey 1.1' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Safari 3.0' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Safari 2.0';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"And back to asc sorting on second column",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Other browsers' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Trident' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'All others' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'AOL browser (AOL desktop)' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Camino 1.0';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sort on third column, having now sorted on second",
+		function () {
+			$('#example thead th:eq(2)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Other browsers' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Misc' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'All others' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Dillo 0.8' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'NetFront 3.1';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Reserve sort on third column",
+		function () {
+			$('#example thead th:eq(2)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Misc' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Trident' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'IE Mobile' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Internet Explorer 7' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'AOL browser (AOL desktop)';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Return sorting on third column to asc",
+		function () {
+			$('#example thead th:eq(2)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Other browsers' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Misc' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'All others' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Dillo 0.8' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'NetFront 3.1';
+			return ret;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sort on first column having sorted on second then third columns",
+		function () {
+			$('#example thead th:eq(0)').click();
+		},
+		function () {
+			var ret =
+				$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(1) td:eq(0)').html() == 'Gecko' &&
+				$('#example tbody tr:eq(0) td:eq(1)').html() == 'Epiphany 2.20' &&
+				$('#example tbody tr:eq(1) td:eq(1)').html() == 'Camino 1.0' &&
+				$('#example tbody tr:eq(2) td:eq(1)').html() == 'Camino 1.5';
+			return ret;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2799.js
@@ -1,1 +1,14 @@
+// DATA_TEMPLATE: two_tables
+oTest.fnStart( "Initialise two tables" );
 
+$(document).ready( function () {
+	$('table.display').dataTable();
+	
+	oTest.fnTest( 
+		"Check that initialisation was okay",
+		null,
+		function () { return true; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2840-restore-table-width.js
@@ -1,1 +1,19 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "2840 - Restore table width on fnDestory" );
 
+$(document).ready( function () {
+	document.cookie = "";
+	$('#example').dataTable( {
+		"sScrollX": "100%",
+		"sScrollXInner": "110%"
+	} );
+	$('#example').dataTable().fnDestroy();
+	
+	oTest.fnTest( 
+		"Width after destroy",
+		null,
+		function () { return $('#example').width() == "800"; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/2914-state-save-sort.js
@@ -1,1 +1,39 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "2914 - State saving with an empty array" );
 
+$(document).ready( function () {
+	document.cookie = "";
+	$('#example').dataTable( {
+		"bStateSave": true,
+		"aaSorting": []
+	} );
+	
+	oTest.fnTest( 
+		"No sort",
+		null,
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnTest( 
+		"Next page",
+		function () {
+			$('#example').dataTable().fnPageChange( 'next' );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnTest( 
+		"Destroy the table and remake it - checking we are still on the next page",
+		function () {
+			$('#example').dataTable( {
+				"bStateSave": true,
+					"aaSorting": [],
+				"bDestroy": true
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnCookieDestroy( $('#example').dataTable() );
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/_zero_config.js
@@ -1,1 +1,437 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "Sanity checks for DataTables with DOM data" );
 
+oTest.fnTest( 
+	"jQuery.dataTable function",
+	null,
+	function () { return typeof jQuery().dataTable == "function"; }
+);
+
+oTest.fnTest(
+	"jQuery.dataTableSettings storage array",
+	null,
+	function () { return typeof jQuery().dataTableSettings == "object"; }
+);
+
+oTest.fnTest(
+	"jQuery.dataTableExt plugin object",
+	null,
+	function () { return typeof jQuery().dataTableExt == "object"; }
+);
+
+$(document).ready( function () {
+	$('#example').dataTable();
+	
+	/* Basic checks */
+	oTest.fnTest( 
+		"Length changing div exists",
+		null,
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Filtering div exists",
+		null,
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Information div exists",
+		null,
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Pagination div exists",
+		null,
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is off by default",
+		null,
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnTest( 
+		"10 rows shown on the first page",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Initial sort occured",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	/* Need to use the WaitTest for sorting due to the setTimeout datatables uses */
+	oTest.fnTest( 
+		"Sorting (first click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (second click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (third click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (first click) on numeric column",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "-"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (second click) on numeric column",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column (first click)",
+		function () { 
+			$('#example thead th:eq(0)').click();
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () { var b = 
+			$('#example tbody td:eq(0)').html() == "Gecko" && 
+			$('#example tbody td:eq(1)').html() == "Camino 1.0"; return b; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - sorting second column only",
+		function () { 
+			$('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	/* Basic paging */
+	oTest.fnTest( 
+		"Paging to second page",
+		function () { $('#example_next').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "IE Mobile"; }
+	);
+	
+	oTest.fnTest( 
+		"Paging to first page",
+		function () { $('#example_previous').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Attempting to page back beyond the first page",
+		function () { $('#example_previous').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	/* Changing length */
+	oTest.fnTest( 
+		"Changing table length to 25 records",
+		function () { $("select[name=example_length]").val('25').change(); },
+		function () { return $('#example tbody tr').length == 25; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 50 records",
+		function () { $("select[name=example_length]").val('50').change(); },
+		function () { return $('#example tbody tr').length == 50; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 100 records",
+		function () { $("select[name=example_length]").val('100').change(); },
+		function () { return $('#example tbody tr').length == 57; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 10 records",
+		function () { $("select[name=example_length]").val('10').change(); },
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	/*
+	 * Information element
+	 */
+	oTest.fnTest(
+		"Information on zero config",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 11 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on third page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 21 to 30 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on last page",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 51 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information back on first page",
+		function () {
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 25 records",
+		function () { $("select[name=example_length]").val('25').change(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 25 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 25 records - second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 26 to 50 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 100 records - first page",
+		function () {
+			$('#example_previous').click();
+			$("select[name=example_length]").val('100').change();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information back to 10 records",
+		function () {
+			$('#example_previous').click();
+			$("select[name=example_length]").val('10').change();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' last page",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 31 to 31 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' back to first page",
+		function () {
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page - second time",
+		function () {
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter increased to 'Win 98'",
+		function () { $('#example_filter input').val("Win 98").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 9 of 9 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter decreased to 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page - third time",
+		function () {
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter removed",
+		function () { $('#example_filter input').val("").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	/*
+	 * Filtering
+	 */
+	oTest.fnTest(
+		"Filter 'W' - rows",
+		function () { 
+			/* Reset the table such that the old sorting doesn't mess things up */
+			oSession.fnRestore();
+			$('#example').dataTable();
+			$('#example_filter input').val("W").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'W' - info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 42 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Wi'",
+		function () { $('#example_filter input').val("Wi").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 32 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "AOL browser (AOL desktop)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1 info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1 reverse",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - maintaing reverse sorting col 1",
+		function () { $('#example_filter input').val("Win XP").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Internet Explorer 7"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - sorting col 3",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - sorting col 3 - reversed",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "7"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting col 3 - reversed info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 6 of 6 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'nothinghere'",
+		function () { $('#example_filter input').val("nothinghere").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 
+			"No matching records found"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'nothinghere' - info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 0 to 0 of 0 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter back to blank and 1st column sorting",
+		function () {
+			$('#example_filter input').val("").keyup();
+			$('#example thead th:eq(0)').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Prefixing a filter entry",
+		function () {
+			$('#example_filter input').val("Win").keyup();
+			$('#example_filter input').val("GeckoWin").keyup();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 0 to 0 of 0 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Prefixing a filter entry with space",
+		function () {
+			$('#example_filter input').val("Gecko Win").keyup();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 17 entries (filtered from 57 total entries)"; }
+	);
+	
+	
+	
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aaSorting.js
@@ -1,1 +1,183 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aaSorting" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default sorting is single column",
+		null,
+		function () {
+			return oSettings.aaSorting.length == 1 && typeof oSettings.aaSorting[0] == 'object';
+		}
+	);
+	
+	oTest.fnTest( 
+		"Default sorting is first column asc",
+		null,
+		function () {
+			return oSettings.aaSorting[0].length == 3 && oSettings.aaSorting[0][0] == 0 &&
+				oSettings.aaSorting[0][1] == 'asc';
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting is applied",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Custom sorting on single string column asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Custom sorting on single string column desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Custom sorting on single int column asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "-"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Custom sorting on single int column desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string asc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','asc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string asc / string desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','asc'], ['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string desc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','desc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "iPod Touch / iPhone"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string desc / string desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','desc'], ['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Safari 3.0"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string asc / int asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','asc'], ['3','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "1"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string asc / int desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','asc'], ['3','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "1.9"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string desc / int asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','desc'], ['3','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "125.5"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string desc / int desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','desc'], ['3','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (3 column) - string asc / int asc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSorting": [['0','asc'], ['3','asc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(7) td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aaSortingFixed.js
@@ -1,1 +1,60 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aaSortingFixed" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"No fixed sorting by default",
+		null,
+		function () {
+			return oSettings.aaSortingFixed == null;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Fixed sorting on first column (string/asc) with user sorting on second column (string/asc)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSortingFixed": [['0','asc']]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnTest( 
+		"Fixed sorting on first column (string/asc) with user sorting on second column (string/desc)",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Fixed sorting on fourth column (int/asc) with user sorting on second column (string/asc)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaSortingFixed": [['3','asc']]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Fixed sorting on fourth column (int/asc) with user sorting on second column (string/desc)",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "PSP browser"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.bSearchable.js
@@ -1,1 +1,67 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.bSeachable" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Columns are searchable by default",
+		function () { oTable.fnFilter("Camino"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html().match(/Camino/); }
+	);
+	
+	oTest.fnTest( 
+		"Disabling sorting on a column removes it from the global filter",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "bSearchable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("Camino");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnTest( 
+		"Disabled on one column has no effect on other columns",
+		function () { oTable.fnFilter("Webkit"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Webkit"; }
+	);
+	
+	oTest.fnTest( 
+		"Disable filtering on multiple columns",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					{ "bSearchable": false },
+					{ "bSearchable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("Webkit");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnTest( 
+		"Filter on second disabled column",
+		function () { oTable.fnFilter("Camino"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.bSortable.js
@@ -1,1 +1,105 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.bSortable" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"All columns are sortable by default",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Can disable sorting from one column",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "bSortable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() != "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Disabled column has no sorting class",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc") == false; }
+	);
+	
+	oTest.fnTest( 
+		"Other columns can still sort",
+		function () {
+			$('#example thead th:eq(4)').click();
+			$('#example thead th:eq(4)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == "X"; }
+	);
+	
+	oTest.fnTest( 
+		"Disable sorting on multiple columns - no sorting classes",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "bSortable": false },
+					null,
+					{ "bSortable": false },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example thead th:eq(1)').hasClass("sorting") ||
+				$('#example thead th:eq(3)').hasClass("sorting")
+			return bReturn == false;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting on disabled column 1 has no effect",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() != "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on disabled column 2 has no effect",
+		function () {
+			$('#example thead th:eq(3)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() != "-"; }
+	);
+	
+	oTest.fnTest( 
+		"Second sort on disabled column 2 has no effect",
+		function () {
+			$('#example thead th:eq(3)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() != "-"; }
+	);
+	
+	oTest.fnTest( 
+		"Even with multiple disabled sorting columns other columns can still sort",
+		function () {
+			$('#example thead th:eq(4)').click();
+			$('#example thead th:eq(4)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == "X"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.bUseRendered.js
@@ -1,1 +1,145 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.bUseRendered" );
 
+/* bUseRendered is used to alter sorting data, if false then the original data is used for
+ * sorting rather than the rendered data
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var mTmp = 0;
+	
+	var oTable = $('#example').dataTable( {
+		"aoColumns": [
+			null,
+			{ "fnRender": function (a) {
+				if ( mTmp == 0 ) {
+					mTmp++;
+					return "aaa";
+				} else
+					return a.aData[a.iDataColumn];
+			} },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default for bUseRendered is true - rendered data is used for sorting",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'aaa'; }
+	);
+	
+	oTest.fnTest( 
+		"When bUseRendered is false, original data is used for sorting",
+		function () {
+			mTmp = 0;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ 
+						"bUseRendered": false,
+						"fnRender": function (a) {
+							if ( mTmp == 0 ) {
+								mTmp++;
+								return "aaa";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					null,
+					null,
+					null
+				]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	
+	oTest.fnTest( 
+		"bUseRendered set to false on one columns and true (default) on two others",
+		function () {
+			mTmp = 0;
+			var mTmp2 = 0;
+			var mTmp3 = 0;
+			
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					{
+						"fnRender": function (a) {
+							if ( mTmp == 0 ) {
+								mTmp++;
+								return "aaa1";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					{ 
+						"bUseRendered": false,
+						"fnRender": function (a) {
+							if ( mTmp2 == 0 ) {
+								mTmp2++;
+								return "aaa2";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					{
+						"fnRender": function (a) {
+							if ( mTmp3 == 0 ) {
+								mTmp3++;
+								return "zzz3";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'aaa1'; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column rendering - 2nd column sorting",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column rendering - 3rd column sorting",
+		function () {
+			$('#example thead th:eq(2)').click();
+			$('#example thead th:eq(2)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(2)').html() == 'zzz3'; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column rendering - 4th column sorting",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == '-'; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column rendering - 5th column sorting",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.bVisible.js
@@ -1,1 +1,132 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.bVisible" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"All columns are visible by default",
+		null,
+		function () { return $('#example tbody tr:eq(0) td').length == 5; }
+	);
+	
+	oTest.fnTest( 
+		"Can hide one column and it removes td column from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "bVisible": false },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 4; }
+	);
+	
+	oTest.fnTest( 
+		"Can hide one column and it removes thead th column from DOM",
+		null,
+		function () { return $('#example thead tr:eq(0) th').length == 4; }
+	);
+	
+	oTest.fnTest( 
+		"Can hide one column and it removes tfoot th column from DOM",
+		null,
+		function () { return $('#example tfoot tr:eq(0) th').length == 4; }
+	);
+	
+	oTest.fnTest( 
+		"The correct thead column has been hidden",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Platform(s)" &&
+				jqNodes[2].innerHTML == "Engine version" &&
+				jqNodes[3].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"The correct tbody column has been hidden",
+		function () {
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } );
+		},
+		function () {
+			var jqNodes = $('#example tbody tr:eq(0) td');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Gecko" &&
+				jqNodes[1].innerHTML == "Gnome" &&
+				jqNodes[2].innerHTML == "1.8" &&
+				jqNodes[3].innerHTML == "A";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Can hide multiple columns and it removes td column from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "bVisible": false },
+					{ "bVisible": false },
+					null,
+					{ "bVisible": false }
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"Multiple hide - removes thead th column from DOM",
+		null,
+		function () { return $('#example thead tr:eq(0) th').length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"Multiple hide - removes tfoot th column from DOM",
+		null,
+		function () { return $('#example tfoot tr:eq(0) th').length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"Multiple hide - the correct thead columns have been hidden",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Engine version"
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Multiple hide - the correct tbody columns have been hidden",
+		function () {
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } );
+		},
+		function () {
+			var jqNodes = $('#example tbody tr:eq(0) td');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Gecko" &&
+				jqNodes[1].innerHTML == "1"
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.fnRender.js
@@ -1,1 +1,175 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.fnRender" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var mTmp = 0;
+	var oTable = $('#example').dataTable( {
+		"aoColumns": [
+			null,
+			{ "fnRender": function (a) {
+				mTmp++;
+				return a.aData[a.iDataColumn];
+			} },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Single column - fnRender is called once for each row",
+		null,
+		function () { return mTmp == 57; }
+	);
+	
+	oTest.fnTest( 
+		"Confirm that fnRender passes one argument (an object) with three parameters",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( arguments.length != 1 || typeof a.iDataRow=='undefined' ||
+						 	typeof a.iDataColumn=='undefined' || typeof a.aData=='undefined' )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnTest( 
+		"fnRender iDataColumn is row number",
+		function () {
+			var iCount = 0;
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( iCount != a.iDataRow )
+						{
+							mTmp = false;
+						}
+						iCount++;
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnTest( 
+		"fnRender iDataColumn is the column",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( a.iDataColumn != 1 )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnTest( 
+		"fnRender aData is data array of correct size",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( a.aData.length != 5 )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnTest( 
+		"Passed back data is put into the DOM",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						return 'unittest';
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'unittest'; }
+	);
+	
+	oTest.fnTest( 
+		"Passed back data is put into the DOM",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					null,
+					{ "fnRender": function (a) {
+						return 'unittest1';
+					} },
+					{ "fnRender": function (a) {
+						return 'unittest2';
+					} },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example tbody tr:eq(0) td:eq(2)').html() == 'unittest1' &&
+				$('#example tbody tr:eq(0) td:eq(3)').html() == 'unittest2';
+			return bReturn; }
+	);
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.iDataSort.js
@@ -1,1 +1,88 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.iDataSort" );
 
+$(document).ready( function () {
+	/* Should know that sorting already works by default from other tests, so we can jump
+	 * right in here
+	 */
+	var oTable = $('#example').dataTable( {
+		"aoColumns": [
+			null,
+			{ "iDataSort": 4 },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Sorting on first column is uneffected",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko'; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on second column is the order of the fifth",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	oTest.fnTest( 
+		"Reserve sorting on second column uses fifth column as well",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'X'; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on 5th column retains it's own sorting",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Use 2nd col for sorting 5th col and via-versa - no effect on first col sorting",
+		function () {
+			mTmp = 0;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "iDataSort": 4 },
+					null,
+					null,
+					{ "iDataSort": 1 }
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko'; }
+	);
+	
+	oTest.fnTest( 
+		"2nd col sorting uses fifth col",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	oTest.fnTest( 
+		"2nd col sorting uses fifth col - reversed",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'X'; }
+	);
+	
+	oTest.fnTest( 
+		"5th col sorting uses 2nd col",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	oTest.fnTest( 
+		"5th col sorting uses 2nd col - reversed",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'Seamonkey 1.1'; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.sClass.js
@@ -1,1 +1,111 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.sClass" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"By default the test class hasn't been applied to the column (sanity!)",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(2)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - first row",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aoColumns": [
+					null,
+					null,
+					{ "sClass": 'unittest' },
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(1) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - third row",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - last row",
+		null,
+		function () { return $('#example tbody tr:eq(9) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - has not applied to other columns - 1st",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(0)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - has not applied to other columns - 5th",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - seventh row - second page",
+		function () { $('#example_next').click(); },
+		function () { return $('#example tbody tr:eq(6) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - has not applied to header",
+		null,
+		function () { return $('#example thead tr:eq(3) th:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - has not applied to footer",
+		null,
+		function () { return $('#example thead tr:eq(3) th:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Class defined for multiple columns - first row",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aoColumns": [
+					{ "sClass": 'unittest2' },
+					null,
+					null,
+					{ "sClass": 'unittest1' },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example tbody tr:eq(3) td:eq(0)').hasClass('unittest2') &&
+				$('#example tbody tr:eq(8) td:eq(3)').hasClass('unittest1');
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Class defined for multiple columns - has not applied to other columns - 5th 1",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').hasClass('unittest1') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Class defined for multiple columns - has not applied to other columns - 5th 2",
+		null,
+		function () { return $('#example tbody tr:eq(6) td:eq(4)').hasClass('unittest2') == false; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.sName.js
@@ -1,1 +1,27 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.sName" );
 
+/* This has no effect at all in DOM methods - so we just check that it has applied the name */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aoColumns": [
+			null,
+			null,
+			null,
+			{ "sName": 'unit test' },
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Names are stored in the columns object",
+		null,
+		function () { return oSettings.aoColumns[3].sName =="unit test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.sTitle.js
@@ -1,1 +1,78 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.sTitle" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Column names are read from the DOM by default",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Browser" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Can set a single column title - and others are read from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "sTitle": 'unit test' },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "unit test" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Can set multiple column titles",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aoColumns": [
+					null,
+					{ "sTitle": 'unit test 1' },
+					null,
+					null,
+					{ "sTitle": 'unit test 2' }
+				]
+			} );
+		},
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "unit test 1" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "unit test 2";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoColumns.sWidth.js
@@ -1,1 +1,84 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoColumns.sWidth" );
 
+/* NOTE - we need to disable the auto width for the majority of these test in order to preform 
+ * these tests as the auto width will convert the width to a px value. We can do 'non-exact' tests
+ * with auto width enabled however to ensure it scales columns as required
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bAutoWidth": false,
+		"aoColumns": [
+			null,
+			{ "sWidth": '40%' },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"With auto width disabled the width for one column is appled",
+		null,
+		function () { return $('#example thead th:eq(1)')[0].style.width == "40%"; }
+	);
+	
+	oTest.fnTest( 
+		"With auto width disabled the width for one column is appled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bAutoWidth": false,
+				"aoColumns": [
+					null,
+					null,
+					{ "sWidth": '20%' },
+					{ "sWidth": '30%' },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn =
+				$('#example thead th:eq(2)')[0].style.width == "20%" &&
+				$('#example thead th:eq(3)')[0].style.width == "30%";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"With auto width, it will make the smallest column the largest with percentage width given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoColumns": [
+					null,
+					null,
+					null,
+					{ "sWidth": '40%' },
+					null
+				]
+			} );
+		},
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			
+			if ( a3>a0 && a3>a1 && a3>a2 && a3>a4 )
+				return true;
+			else
+				return false;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/aoSearchCols.js
@@ -1,1 +1,112 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "aoSearchCols" );
 
+/* We could be here forever testing this one, so we test a limited subset on a couple of colums */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default should be to have a empty colums array",
+		null,
+		function () {
+			var bReturn = 
+				oSettings.aoPreSearchCols[0].sSearch == 0 && !oSettings.aoPreSearchCols[0].bRegex &&
+				oSettings.aoPreSearchCols[1].sSearch == 0 && !oSettings.aoPreSearchCols[1].bRegex &&
+				oSettings.aoPreSearchCols[2].sSearch == 0 && !oSettings.aoPreSearchCols[2].bRegex &&
+				oSettings.aoPreSearchCols[3].sSearch == 0 && !oSettings.aoPreSearchCols[3].bRegex &&
+				oSettings.aoPreSearchCols[4].sSearch == 0 && !oSettings.aoPreSearchCols[4].bRegex;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Search on a single column - no regex statement given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoSearchCols": [
+					null,
+					{ "sSearch": "Mozilla" },
+					null,
+					{ "sSearch": "1" },
+					null
+				]
+			} );
+		},
+		function () { return $('#example_info').html() == "Showing 1 to 9 of 9 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest( 
+		"Search on two columns - no regex statement given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoSearchCols": [
+					null,
+					{ "sSearch": "Mozilla" },
+					null,
+					{ "sSearch": "1.5" },
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "1.5"; }
+	);
+	
+	oTest.fnTest( 
+		"Search on single column - escape regex false",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					null,
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example_info').html() == "Showing 1 to 3 of 3 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest( 
+		"Search on two columns - escape regex false on first, true on second",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					{ "sSearch": "3.3", "bEscapeRegex": true },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Konqureror 3.3"; }
+	);
+	
+	oTest.fnTest( 
+		"Search on two columns (no records) - escape regex false on first, true on second",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					{ "sSearch": "Allan", "bEscapeRegex": true },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/asStripClasses.js
@@ -1,1 +1,106 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "asStripClasses" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Default row striping is applied",
+		null,
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('odd') &&
+			       $('#example tbody tr:eq(1)').hasClass('even') &&
+			       $('#example tbody tr:eq(2)').hasClass('odd') &&
+			       $('#example tbody tr:eq(3)').hasClass('even');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Row striping does not effect current classes",
+		null,
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('gradeA') &&
+			       $('#example tbody tr:eq(1)').hasClass('gradeA') &&
+			       $('#example tbody tr:eq(2)').hasClass('gradeA') &&
+			       $('#example tbody tr:eq(3)').hasClass('gradeA');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Row striping on the second page",
+		function () { $('#example_next').click(); },
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('odd') &&
+			       $('#example tbody tr:eq(1)').hasClass('even') &&
+			       $('#example tbody tr:eq(2)').hasClass('odd') &&
+			       $('#example tbody tr:eq(3)').hasClass('even');
+		}
+	);
+	
+	/* No striping */
+	oTest.fnTest( 
+		"No row striping",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"asStripClasses": []
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)')[0].className == "gradeA" &&
+			       $('#example tbody tr:eq(1)')[0].className == "gradeA" &&
+			       $('#example tbody tr:eq(2)')[0].className == "gradeA" &&
+			       $('#example tbody tr:eq(3)')[0].className == "gradeA";
+		}
+	);
+	
+	/* Custom striping */
+	oTest.fnTest( 
+		"Custom striping [2]",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"asStripClasses": [ 'test1', 'test2' ]
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test1') &&
+			       $('#example tbody tr:eq(3)').hasClass('test2');
+		}
+	);
+	
+	
+	/* long array of striping */
+	oTest.fnTest( 
+		"Custom striping [4]",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"asStripClasses": [ 'test1', 'test2', 'test3', 'test4' ]
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test3') &&
+			       $('#example tbody tr:eq(3)').hasClass('test4');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Custom striping is restarted on second page [2]",
+		function () { $('#example_next').click(); },
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test3') &&
+			       $('#example tbody tr:eq(3)').hasClass('test4');
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bAutoWidth.js
@@ -1,1 +1,138 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bAutoWidth" );
 
+/* It's actually a little tricky to test this. We can't test absolute numbers because
+ * different browsers and different platforms will render the width of the columns slightly
+ * differently. However, we certainly can test the principle of what should happen (column 
+ * width doesn't change over pages)
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Auto width is enabled by default",
+		null,
+		function () { return oSettings.oFeatures.bAutoWidth; }
+	);
+	
+	oTest.fnTest( 
+		"First column has a width assigned to it",
+		null,
+		function () { return $('#example thead th:eq(0)').attr('style').match(/width/i); }
+	);
+	
+	/*
+	This would seem like a better test - but there appear to be difficulties with tables
+	which are bigger (calculated) than there is actually room for. I suspect this is actually
+	a bug in datatables
+	oTest.fnTest( 
+		"Check column widths on first page match second page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			console.log( a0, b0, a1, b1, a2, b2, a3, b3 );
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return true;
+			else
+				return false;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check column widths on second page match thid page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return true;
+			else
+				return false;
+		}
+	);
+	*/
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Auto width can be disabled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bAutoWidth": false
+			} );
+	 		oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bAutoWidth == false; }
+	);
+	
+	oTest.fnTest( 
+		"First column does not have a width assigned to it",
+		null,
+		function () { return $('#example thead th:eq(0)').attr('style') == null; }
+	);
+	
+	/*
+	oTest.fnTest( 
+		"Check column widths on first page do not match second page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return false;
+			else
+				return true;
+		}
+	);
+	*/
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Auto width enabled override",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bAutoWidth": true
+			} );
+	 		oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bAutoWidth; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bFilter.js
@@ -1,1 +1,40 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bFilter" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Filtering div exists by default",
+		null,
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Fltering can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bFilter": false
+			} );
+		},
+		function () { return document.getElementById('example_filter') == null; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Filtering enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bFilter": true
+			} );
+		},
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bInfiniteScroll.js
@@ -1,1 +1,130 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bInfiniteScroll" );
 
+
+$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"bScrollInfinite": true,
+		"sScrollY": "200px"
+	} );
+	
+	oTest.fnTest( 
+		"10 rows by default",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Info",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes",
+		null,
+		function () { return $('#example tbody>tr').length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll on 20px adds 10 rows",
+		function () { $('div.dataTables_scrollBody').scrollTop(20); },
+		function () { return $('#example tbody tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Info after 20px scroll",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after 20px scroll",
+		null,
+		function () { return $('#example tbody>tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Scroll on 10px more results in the same number of rows",
+		function () { $('div.dataTables_scrollBody').scrollTop(30); },
+		function () { return $('#example tbody tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Info after 10 more px scroll",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll to 240px adds another 10 rows",
+		function () { $('div.dataTables_scrollBody').scrollTop(240); },
+		function () { return $('#example tbody tr').length == 30; }
+	);
+	
+	oTest.fnTest( 
+		"Info after 240px scroll",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 30 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after 240px scroll",
+		null,
+		function () { return $('#example tbody>tr').length == 30; }
+	);
+	
+	oTest.fnTest( 
+		"Filtering will drop back to 10 rows",
+		function () { 
+			$('div.dataTables_scrollBody').scrollTop(0);
+			oTable.fnFilter('gec')
+		},
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Info after filtering",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 10 of 20 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after filtering",
+		null,
+		function () { return $('#example tbody>tr').length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll after filtering adds 10",
+		function () { $('div.dataTables_scrollBody').scrollTop(20); },
+		function () { return $('#example tbody tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after filtering",
+		null,
+		function () { return $('#example tbody>tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting will drop back to 10 rows",
+		function () { oTable.fnSort([[1,'asc']]) },
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll after sorting adds 10",
+		function () { $('div.dataTables_scrollBody').scrollTop(20); },
+		function () { return $('#example tbody tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after scrolling",
+		null,
+		function () { return $('#example tbody>tr').length == 20; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bInfo.js
@@ -1,1 +1,40 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bInfo" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Info div exists by default",
+		null,
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Info can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bInfo": false
+			} );
+		},
+		function () { return document.getElementById('example_info') == null; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Info enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bInfo": true
+			} );
+		},
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bJQueryUI.js
@@ -1,1 +1,40 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bJQueryUI" );
 
+$(document).ready( function () {
+	$('#example').dataTable( {
+		"bJQueryUI": true
+	} );
+	
+	oTest.fnTest( 
+		"Header elements are fully wrapped by DIVs",
+		null,
+		function () {
+			var test = true;
+			$('#example thead th').each( function () {
+				if ( this.childNodes > 1 ) {
+					test = false;
+				}
+			} );
+			return test;
+		}
+	);
+	
+	oTest.fnTest( 
+		"One div for each header element",
+		null,
+		function () {
+			return $('#example thead th div').length == 5;
+		}
+	);
+	
+	oTest.fnTest( 
+		"One span for each header element, nested as child of div",
+		null,
+		function () {
+			return $('#example thead th div>span').length == 5;
+		}
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bLengthChange.js
@@ -1,1 +1,71 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bLengthChange" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Length div exists by default",
+		null,
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	oTest.fnTest(
+		"Four default options",
+		null,
+		function () { return $("select[name=example_length] option").length == 4; }
+	);
+	
+	oTest.fnTest(
+		"Default options",
+		null,
+		function () {
+			var opts = $("select[name='example_length'] option");
+			return opts[0].getAttribute('value') == 10 && opts[1].getAttribute('value') == 25 &&
+				opts[2].getAttribute('value') == 50 && opts[3].getAttribute('value') == 100;
+		}
+	);
+	
+	oTest.fnTest(
+		"Info takes length into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Change length can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bLengthChange": false
+			} );
+		},
+		function () { return document.getElementById('example_length') == null; }
+	);
+	
+	oTest.fnTest(
+		"Information takes length disabled into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Length change enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bLengthChange": true
+			} );
+		},
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bPaginate.js
@@ -1,1 +1,55 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bPaginate" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Pagiantion div exists by default",
+		null,
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	oTest.fnTest(
+		"Information div takes paging into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Pagiantion can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bPaginate": false
+			} );
+		},
+		function () { return document.getElementById('example_paginate') == null; }
+	);
+	
+	oTest.fnTest(
+		"Information div takes paging disabled into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 57 of 57 entries"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Pagiantion enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bPaginate": true
+			} );
+		},
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bProcessing.js
@@ -1,1 +1,99 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bProcessing" );
 
+/* It's actually a bit hard to set this one due to the fact that it will only be shown
+ * when DataTables is doing some kind of processing. The server-side processing is a bit
+ * better to test this than here - so we just the interal functions to enable it and check
+ * that it is available
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Processing is off by default",
+		null,
+		function () { return oSettings.oFeatures.bProcessing == false; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is not in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div cannot be shown",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div cannot be hidden",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, false ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Processing can be enabled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bProcessing": true
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bProcessing == true; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing'); }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is hidden by default",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing').style.visibility = "hidden"; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div can be shown",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing').style.visibility = "visible"; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div can be hidden",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, false ); },
+		function () { return document.getElementById('example_processing').style.visibility = "hidden"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Processing disabled override",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bProcessing": false
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bProcessing == false; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is not in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bServerSide.js
@@ -1,1 +1,18 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bServerSide" );
 
+/* Not interested in server-side processing here other than to check that it is off */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Server side is off by default",
+		null,
+		function () { return oSettings.oFeatures.bServerSide == false; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bSort.js
@@ -1,1 +1,101 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bSort" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Sorting is on by default",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting Asc by default class applied",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass("sorting_asc"); }
+	);
+	
+	oTest.fnTest(
+		"Click on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting class removed from first column",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass("sorting_asc") != true; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting asc class applied to second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc"); }
+	);
+	
+	oTest.fnTest(
+		"Reverse on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting acs class removed from second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc") != true; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting desc class applied to second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_desc"); }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Pagiantion can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bSort": false
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnTest(
+		"Disabled classes applied",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass('sorting_disabled'); }
+	);
+	
+	oTest.fnTest(
+		"Click on second column has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnTest(
+		"Reverse on second column has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Sorting enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bSort": true
+			} );
+		},
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/bSortClasses.js
@@ -1,1 +1,128 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "bSortClasses" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Sorting classes are applied by default",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	oTest.fnTest( 
+		"Sorting classes are applied to all required cells",
+		null,
+		function () { return $('#example tbody tr:eq(7) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	oTest.fnTest( 
+		"Sorting classes are not applied to non-sorting columns",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_1') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - add column 1",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - add column 2",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(2)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - add column 3",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(3)')[0], { 'shift': true } );
+		},
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') &&
+						 $('#example tbody tr:eq(0) td:eq(3)').hasClass('sorting_3');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Remove sorting classes on single column sort",
+		function () { 
+			$('#example thead th:eq(4)').click();
+		},
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') == false &&
+						 $('#example tbody tr:eq(0) td:eq(3)').hasClass('sorting_3') == false;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting class 1 was added",
+		null,
+		function () { return $('#example tbody tr:eq(1) td:eq(4)').hasClass('sorting_1'); }
+	);
+	
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Sorting classes can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bSortClasses": false
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting classes disabled - add column 1 - no effect",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting classes disabled - add column 2 - no effect",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(2)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') == false;
+		}
+	);
+	
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Sorting classes enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bSortClasses": true
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/fnCookieCallback.js
@@ -1,1 +1,97 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "Cookie callback" );
 
+
+$(document).ready( function () {
+	var mPass;
+	/* Note that in order to be fully effective here for saving state, there would need to be a
+	 * stringify function to serialise the data array
+	 */
+	
+	oTest.fnTest( 
+		"null by default",
+		function () {
+			$('#example').dataTable();
+		},
+		function () { return $('#example').dataTable().fnSettings().fnCookieCallback == null; }
+	);
+	
+	oTest.fnTest( 
+		"Number of arguments",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"bStateSave": true,
+				"fnCookieCallback": function (sName, oData, sExpires, sPath) {
+					mPass = arguments.length;
+					return sName + "=; expires=" + sExpires +"; path=" + sPath;
+				}
+			} );
+		},
+		function () { return mPass == 4; }
+	);
+	
+	oTest.fnTest( 
+		"Name",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"bStateSave": true,
+				"fnCookieCallback": function (sName, oData, sExpires, sPath) {
+					mPass = sName=="SpryMedia_DataTables_example_dom_data.php";
+					return sName + "=; expires=" + sExpires +"; path=" + sPath;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Data",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"bStateSave": true,
+				"fnCookieCallback": function (sName, oData, sExpires, sPath) {
+					mPass = typeof oData.iStart != 'undefined';
+					return sName + "=; expires=" + sExpires +"; path=" + sPath;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Expires",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"bStateSave": true,
+				"fnCookieCallback": function (sName, oData, sExpires, sPath) {
+					mPass = typeof sExpires == 'string';
+					return sName + "=; expires=" + sExpires +"; path=" + sPath;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Path",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"bStateSave": true,
+				"fnCookieCallback": function (sName, oData, sExpires, sPath) {
+					mPass = sPath.match(/media\/unit_testing\/templates/);
+					return sName + "=; expires=" + sExpires +"; path=" + sPath;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnCookieDestroy( $('#example').dataTable() );
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/fnDeleteRow.js
@@ -1,1 +1,30 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "fnDeleteRow" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Check that the default data is sane",
+		null,
+		function () { return oSettings.asDataSearch.join(' ').match(/4.0/g).length == 3; }
+	);
+	
+	oTest.fnTest( 
+		"Remove the first data row, and check that hte search data has been updated",
+		function () { oTable.fnDeleteRow( 0 ); },
+		function () { return oSettings.asDataSearch.join(' ').match(/4.0/g).length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"Check that the info element has been updated",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 10 of 56 entries"; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/fnDrawCallback.js
@@ -1,1 +1,80 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "fnDrawCallback" );
 
+/* Fairly boring function compared to the others! */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnDrawCallback == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"One argument passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"fnDrawCallback": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnTest( 
+		"That one argument is the settings object",
+		function () {
+			oSession.fnRestore();
+			
+			oTable = $('#example').dataTable( {
+				"fnDrawCallback": function ( oSettings ) {
+					mPass = oSettings;
+				}
+			} );
+		},
+		function () { return oTable.fnSettings() == mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback called once on first draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"fnDrawCallback": function ( ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnTest( 
+		"fnRowCallback called once on each draw there after as well",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return mPass == 4; }
+	);
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/fnFooterCallback.js
@@ -1,1 +1,227 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "fnFooterCallback" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnFooterCallback == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Five arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 5; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback called once per draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnTest( 
+		"fnRowCallback called on paging (i.e. another draw)",
+		function () { $('#example_next').click(); },
+		function () { return mPass == 2; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					nFoot.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+				}
+			} );
+		},
+		function () { return $('#example tfoot th:eq(0)').html() == "Displaying 10 records"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Data array has length matching original data",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aasData.length != 57 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Data array's column lengths match original data",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					for ( var i=0, iLen=aasData.length ; i<iLen ; i++ )
+					{
+						if ( aasData[i].length != 5 )
+						{
+							mPass = false;
+						}
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iStart correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart != 0 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iStart correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart == 10 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			$('#example_next').click();
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iEnd correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd != 10 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iEnd correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd == 20 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			$('#example_next').click();
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"aiDisplay length is full data when not filtered",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 57 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"aiDisplay length is 9 when filtering on 'Mozilla'",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			oTable = $('#example').dataTable( {
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 9 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			oTable.fnFilter( "Mozilla" );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/fnHeaderCallback.js
@@ -1,1 +1,227 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "fnHeaderCallback" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnHeaderCallback == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Five arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 5; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback called once per draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnTest( 
+		"fnRowCallback called on paging (i.e. another draw)",
+		function () { $('#example_next').click(); },
+		function () { return mPass == 2; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+				}
+			} );
+		},
+		function () { return $('#example thead th:eq(0)').html() == "Displaying 10 records"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Data array has length matching original data",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aasData.length != 57 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Data array's column lengths match original data",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					for ( var i=0, iLen=aasData.length ; i<iLen ; i++ )
+					{
+						if ( aasData[i].length != 5 )
+						{
+							mPass = false;
+						}
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iStart correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart != 0 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iStart correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart == 10 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			$('#example_next').click();
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iEnd correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd != 10 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iEnd correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd == 20 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			$('#example_next').click();
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"aiDisplay length is full data when not filtered",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 57 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"aiDisplay length is 9 when filtering on 'Mozilla'",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			oTable = $('#example').dataTable( {
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 9 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			oTable.fnFilter( "Mozilla" );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/fnInfoCallback.js
@@ -1,1 +1,115 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "fnInfoCallback checks" );
 
+$(document).ready( function () {
+	var mPass;
+	
+	$('#example').dataTable();
+	
+	/* Basic checks */
+	oTest.fnTest( 
+		"null by default",
+		null,
+		function () { return $('#example').dataTable().fnSettings().oLanguage.fnInfoCallback == null; }
+	);
+	
+	oTest.fnTest( 
+		"Agrument length",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"fnInfoCallback": function( oS, iStart, iEnd, iMax, iTotal, sPre ) {
+					mPass = arguments.length;
+					return sPre;
+				}
+			} );
+		},
+		function () { return mPass == 6; }
+	);
+	
+	oTest.fnTest( 
+		"Settings first",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"fnInfoCallback": function( oS, iStart, iEnd, iMax, iTotal, sPre ) {
+					mPass = (oS == $('#example').dataTable().fnSettings()) ? true : false;
+					return sPre;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Start arg",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"fnInfoCallback": function( oS, iStart, iEnd, iMax, iTotal, sPre ) {
+					return iStart;
+				}
+			} );
+		},
+		function () { return $('#example_info').html() == "1"; }
+	);
+	
+	oTest.fnTest( 
+		"End arg",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"fnInfoCallback": function( oS, iStart, iEnd, iMax, iTotal, sPre ) {
+					return iEnd;
+				}
+			} );
+		},
+		function () { return $('#example_info').html() == "10"; }
+	);
+	
+	oTest.fnTest( 
+		"Max arg",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"fnInfoCallback": function( oS, iStart, iEnd, iMax, iTotal, sPre ) {
+					return iMax;
+				}
+			} );
+		},
+		function () { return $('#example_info').html() == "57"; }
+	);
+	
+	oTest.fnTest( 
+		"Max arg - filter",
+		function () {
+			$('#example').dataTable().fnFilter("1.0");
+		},
+		function () { return $('#example_info').html() == "57"; }
+	);
+	
+	oTest.fnTest( 
+		"Total arg",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"fnInfoCallback": function( oS, iStart, iEnd, iMax, iTotal, sPre ) {
+					return iTotal;
+				}
+			} );
+		},
+		function () { return $('#example_info').html() == "57"; }
+	);
+	
+	oTest.fnTest( 
+		"Total arg - filter",
+		function () {
+			$('#example').dataTable().fnFilter("1.0");
+		},
+		function () { return $('#example_info').html() == "3"; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/fnInitComplete.js
@@ -1,1 +1,94 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "fnInitComplete" );
 
+/* Fairly boring function compared to the others! */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnInitComplete == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"One argument passed (for DOM!)",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"fnInitComplete": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnTest( 
+		"That one argument is the settings object",
+		function () {
+			oSession.fnRestore();
+			
+			oTable = $('#example').dataTable( {
+				"fnInitComplete": function ( oSettings ) {
+					mPass = oSettings;
+				}
+			} );
+		},
+		function () { return oTable.fnSettings() == mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnInitComplete called once on first draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"fnInitComplete": function ( ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnTest( 
+		"fnInitComplete never called there after",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"10 rows in the table on complete",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"fnInitComplete": function ( ) {
+					mPass = $('#example tbody tr').length;
+				}
+			} );
+		},
+		function () { return mPass == 10; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/fnRowCallback.js
@@ -1,1 +1,105 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "fnRowCallback" );
 
+/* Note - fnRowCallback MUST return the first arguments (modified or not) */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnRowCallback == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Four arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"fnRowCallback": function ( nTr ) {
+					mPass = arguments.length;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass == 4; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback called once for each drawn row",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					mPass++;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass == 10; }
+	);
+	
+	oTest.fnTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					$(nTr).addClass('unit_test');
+					return nTr;
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(1)').hasClass('unit_test'); }
+	);
+	
+	oTest.fnTest( 
+		"Data array has length matching columns",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					if ( asData.length != 5 )
+						mPass = false;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Data array has length matching columns",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			var iCount = 0;
+			$('#example').dataTable( {
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					if ( iCount != iDrawIndex )
+						mPass = false;
+					iCount++;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/iDisplayLength.js
@@ -1,1 +1,76 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "iDisplayLength" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable();
+	
+	oTest.fnTest( 
+		"Default length is ten",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Select menu shows 10",
+		null,
+		function () { return $('#example_length select').val() == 10; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Set initial length to 25",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"iDisplayLength": 25
+			} );
+		},
+		function () { return $('#example tbody tr').length == 25; }
+	);
+	
+	oTest.fnTest( 
+		"Select menu shows 25",
+		null,
+		function () { return $('#example_length select').val() == 25; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Set initial length to 100",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"iDisplayLength": 100
+			} );
+		},
+		function () { return $('#example tbody tr').length == 57; }
+	);
+	
+	oTest.fnTest( 
+		"Select menu shows 25",
+		null,
+		function () { return $('#example_length select').val() == 100; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Set initial length to 23 (unknown select menu length)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"iDisplayLength": 23
+			} );
+		},
+		function () { return $('#example tbody tr').length == 23; }
+	);
+	
+	oTest.fnTest( 
+		"Select menu shows 10 (since 23 is unknow)",
+		null,
+		function () { return $('#example_length select').val() == 10; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.oPaginate.js
@@ -1,1 +1,80 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.oPaginate" );
 
+/* Note that the paging language information only has relevence in full numbers */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( { "sPaginationType": "full_numbers" } );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate defaults",
+		null,
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.oPaginate.sFirst == "First" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "Previous" &&
+				oSettings.oLanguage.oPaginate.sNext == "Next" &&
+				oSettings.oLanguage.oPaginate.sLast == "Last";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate defaults are in the DOM",
+		null,
+		function () {
+			var bReturn = 
+				$('#example_paginate .first').html() == "First" &&
+				$('#example_paginate .previous').html() == "Previous" &&
+				$('#example_paginate .next').html() == "Next" &&
+				$('#example_paginate .last').html() == "Last";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sPaginationType": "full_numbers",
+				"oLanguage": {
+					"oPaginate": {
+						"sFirst":    "unit1",
+						"sPrevious": "test2",
+						"sNext":     "unit3",
+						"sLast":     "test4"
+					}
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.oPaginate.sFirst == "unit1" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "test2" &&
+				oSettings.oLanguage.oPaginate.sNext == "unit3" &&
+				oSettings.oLanguage.oPaginate.sLast == "test4";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate definitions are in the DOM",
+		null,
+		function () {
+			var bReturn = 
+				$('#example_paginate .first').html() == "unit1" &&
+				$('#example_paginate .previous').html() == "test2" &&
+				$('#example_paginate .next').html() == "unit3" &&
+				$('#example_paginate .last').html() == "test4";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.sInfo.js
@@ -1,1 +1,109 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.sInfo" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Info language is 'Showing _START_ to _END_ of _TOTAL_ entries' by default",
+		null,
+		function () { return oSettings.oLanguage.sInfo == "Showing _START_ to _END_ of _TOTAL_ entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Info language can be defined - without any macros",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sInfo": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sInfo == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macro _START_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oLanguage": {
+					"sInfo": "unit _START_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macro _END_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oLanguage": {
+					"sInfo": "unit _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 10 test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macro _TOTAL_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oLanguage": {
+					"sInfo": "unit _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 57 test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macros _START_ and _END_",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oLanguage": {
+					"sInfo": "unit _START_ _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 10 test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macros _START_, _END_ and _TOTAL_",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oLanguage": {
+					"sInfo": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 10 57 test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.sInfoEmpty.js
@@ -1,1 +1,75 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.sInfoEmpty" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Info empty language is 'Showing 0 to 0 of 0 entries' by default",
+		function () { oTable.fnFilter("nothinghere"); },
+		function () { return oSettings.oLanguage.sInfoEmpty == "Showing 0 to 0 of 0 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"Showing 0 to 0 of 0 entries";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Info empty language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sInfoEmpty": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("nothinghere");
+		},
+		function () { return oSettings.oLanguage.sInfoEmpty == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"unit test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Macro's not replaced",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sInfoEmpty": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+			oTable.fnFilter("nothinghere");
+		},
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"unit _START_ _END_ _TOTAL_ test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.sInfoPostFix.js
@@ -1,1 +1,73 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.sInfoPostFix" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Info post fix language is '' (blank) by default",
+		null,
+		function () { return oSettings.oLanguage.sInfoPostFix == ""; }
+	);
+	
+	oTest.fnTest( 
+		"Width no post fix, the basic info shows",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Info post fix language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sInfoPostFix": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sInfoPostFix == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries unit test"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Macros have no effect in the post fix",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sInfoPostFix": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries unit _START_ _END_ _TOTAL_ test"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Post fix is applied after fintering info",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sInfoPostFix": "unit test"
+				}
+			} );
+			oTable.fnFilter("nothinghere");
+		},
+		function () { return document.getElementById('example_info').innerHTML = "Showing 0 to 0 of 0 entries unit (filtered from 57 total entries) test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.sLengthMenu.js
@@ -1,1 +1,101 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.sLengthMenu" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Menu language is 'Show _MENU_ entries' by default",
+		null,
+		function () { return oSettings.oLanguage.sLengthMenu == "Show _MENU_ entries"; }
+	);
+	
+	oTest.fnTest(
+		"_MENU_ macro is replaced by select menu in DOM",
+		null,
+		function () { return $('select', oSettings.aanFeatures.l[0]).length == 1 }
+	);
+	
+	oTest.fnTest(
+		"Default is put into DOM",
+		null,
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren[0].nodeValue == "Show " &&
+				anChildren[2].nodeValue == " entries";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Menu length language can be defined - no _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sLengthMenu": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sLengthMenu == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Menu length language definition is in the DOM",
+		null,
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			return anChildren[0].nodeValue == "unit test";
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Menu length language can be defined - with _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sLengthMenu": "unit _MENU_ test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren[0].nodeValue == "unit " &&
+				anChildren[2].nodeValue == " test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Only the _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sLengthMenu": "_MENU_"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren.length == 1 &&
+				$('select', oSettings.aanFeatures.l[0]).length == 1;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.sProcessing.js
@@ -1,1 +1,47 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.sProcessing" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bProcessing": true
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Processing language is 'Processing...' by default",
+		null,
+		function () { return oSettings.oLanguage.sProcessing == "Processing..."; }
+	);
+	
+	oTest.fnTest( 
+		"Processing language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_processing').innerHTML = "Processing..."; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Processing language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bProcessing": true,
+				"oLanguage": {
+					"sProcessing": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sProcessing == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Processing language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_processing').innerHTML = "unit test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.sSearch.js
@@ -1,1 +1,61 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.sSearch" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Search language is 'Search:' by default",
+		null,
+		function () { return oSettings.oLanguage.sSearch == "Search:"; }
+	);
+	
+	oTest.fnTest( 
+		"Search language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_filter').childNodes[0].nodeValue
+		 	== "Search: "; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Search language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sSearch": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sSearch == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_filter').childNodes[0].nodeValue
+		 	== "unit test "; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Blank search has a no (separator) inserted",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sSearch": ""
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return document.getElementById('example_filter').childNodes.length == 1; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.sUrl.js
@@ -1,1 +1,59 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.sUrl" );
 
+/* Note that we only test the internal storage of language information pulled form a file here
+ * as the other language tests will check it goes into the DOM correctly
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"sUrl is blank by default",
+		null,
+		function () { return oSettings.oLanguage.sUrl == ""; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Loading of German file loads language information",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sUrl": "../../../examples/examples_support/de_DE.txt"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.sProcessing == "Bitte warten..." &&
+				oSettings.oLanguage.sLengthMenu == "_MENU_ Einträge anzeigen" &&
+				oSettings.oLanguage.sZeroRecords == "Keine Einträge vorhanden." &&
+				oSettings.oLanguage.sInfo == "_START_ bis _END_ von _TOTAL_ Einträgen" &&
+				oSettings.oLanguage.sInfoEmpty == "0 bis 0 von 0 Einträgen" &&
+				oSettings.oLanguage.sInfoFiltered == "(gefiltert von _MAX_  Einträgen)" &&
+				oSettings.oLanguage.sInfoPostFix == "" &&
+				oSettings.oLanguage.sSearch == "Suchen" &&
+				oSettings.oLanguage.oPaginate.sFirst == "Erster" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "Zurück" &&
+				oSettings.oLanguage.oPaginate.sNext == "Nächster" &&
+				oSettings.oLanguage.oPaginate.sLast == "Letzter";
+				
+			return bReturn;
+		}
+	);
+	
+	/* One DOM check just to ensure that they go into the DOM */
+	oTest.fnTest(
+		"Loaded language goes into the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "1 bis 10 von 57 Einträgen"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oLanguage.sZeroRecords.js
@@ -1,1 +1,45 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oLanguage.sZeroRecords" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Zero records language is 'No matching records found' by default",
+		null,
+		function () { return oSettings.oLanguage.sZeroRecords == "No matching records found"; }
+	);
+	
+	oTest.fnTest(
+		"Text is shown when empty table (after filtering)",
+		function () { oTable.fnFilter('nothinghere'); },
+		function () { return $('#example tbody tr td')[0].innerHTML == "No matching records found" }
+	);
+	
+	
+	
+	oTest.fnTest( 
+		"Zero records language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oLanguage": {
+					"sZeroRecords": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sZeroRecords == "unit test"; }
+	);
+	
+	oTest.fnTest(
+		"Text is shown when empty table (after filtering)",
+		function () { oTable.fnFilter('nothinghere2'); },
+		function () { return $('#example tbody tr td')[0].innerHTML == "unit test" }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/oSearch.js
@@ -1,1 +1,101 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "oSearch" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default values should be blank",
+		null,
+		function () {
+			var bReturn = oSettings.oPreviousSearch.sSearch == "" && 
+			              !oSettings.oPreviousSearch.bRegex;
+			return bReturn;
+		}
+	);
+	
+	/* This test might be considered iffy since the full object isn't given, but it's reasonable to
+	 * expect DataTables to cope with this. It should just assumine regex false
+	 */
+	oTest.fnTest( 
+		"Search term only in object",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"oSearch": {
+					"sSearch": "Mozilla"
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnTest( 
+		"New search will kill old one",
+		function () {
+			oTable.fnFilter("Opera");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Presto"; }
+	);
+	
+	oTest.fnTest( 
+		"Search plain text term and escape regex true",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oSearch": {
+					"sSearch": "DS",
+					"bRegex": false
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Nintendo DS browser"; }
+	);
+	
+	oTest.fnTest( 
+		"Search plain text term and escape regex false",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oSearch": {
+					"sSearch": "Opera",
+					"bRegex": true
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Presto"; }
+	);
+	
+	oTest.fnTest( 
+		"Search regex text term and escape regex true",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oSearch": {
+					"sSearch": "1.*",
+					"bRegex": false
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnTest( 
+		"Search regex text term and escape regex false",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"oSearch": {
+					"sSearch": "1.*",
+					"bRegex": true
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/sAjaxSource.js
@@ -1,1 +1,18 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "sAjaxSource" );
 
+/* Not interested in ajax source here other than to check it's default */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Server side is off by default",
+		null,
+		function () { return oSettings.sAjaxSource == null; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/sDom.js
@@ -1,1 +1,319 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "sDom" );
 
+/* This is going to be brutal on the browser! There is a lot that can be tested here... */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default DOM varaible",
+		null,
+		function () { return oSettings.sDom == "lfrtip"; }
+	);
+	
+	oTest.fnTest( 
+		"Default DOM in document",
+		null,
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				nNodes[4] == nInfo &&
+				nNodes[5] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check example 1 in code propagates",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sDom": '<"wrapper"flipt>'
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.sDom == '<"wrapper"flipt>'; }
+	);
+	
+	oTest.fnTest( 
+		"Check example 1 in DOM",
+		null,
+		function () {
+			var jqNodes = $('#demo div, #demo table');
+			var nNodes = [];
+			
+			/* Strip the paging nodes */
+			for ( var i=0, iLen=jqNodes.length ; i<iLen ; i++ )
+			{
+				if ( jqNodes[i].getAttribute('id') != "example_previous" &&
+				     jqNodes[i].getAttribute('id') != "example_next" )
+				{
+					nNodes.push( jqNodes[i] );
+				}
+			}
+			
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			var nCustomWrapper = $('div.wrapper')[0];
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nCustomWrapper &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nLength &&
+				nNodes[4] == nInfo &&
+				nNodes[5] == nPaging &&
+				nNodes[6] == nTable;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check example 2 in DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sDom": '<lf<t>ip>'
+			} );
+		},
+		function () {
+			var jqNodes = $('#demo div, #demo table');
+			var nNodes = [];
+			var nCustomWrappers = []
+			
+			/* Strip the paging nodes */
+			for ( var i=0, iLen=jqNodes.length ; i<iLen ; i++ )
+			{
+				if ( jqNodes[i].getAttribute('id') != "example_previous" &&
+				     jqNodes[i].getAttribute('id') != "example_next" )
+				{
+					nNodes.push( jqNodes[i] );
+				}
+				
+				/* Only the two custom divs don't have class names */
+				if ( !jqNodes[i].getAttribute('class') )
+				{
+					nCustomWrappers.push( jqNodes[i] );
+				}
+			}
+			
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nCustomWrappers[0] &&
+				nNodes[2] == nLength &&
+				nNodes[3] == nFilter &&
+				nNodes[4] == nCustomWrappers[1] &&
+				nNodes[5] == nTable &&
+				nNodes[6] == nInfo &&
+				nNodes[7] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check no length element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sDom": 'frtip'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				null == nLength &&
+				nNodes[1] == nFilter &&
+				nNodes[2] == nTable &&
+				nNodes[3] == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check no filter element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sDom": 'lrtip'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				null == nFilter &&
+				nNodes[2] == nTable &&
+				nNodes[3] == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	/* Note we don't test for no table as this is not supported (and it would be fairly daft! */
+	
+	oTest.fnTest( 
+		"Check no info element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sDom": 'lfrtp'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				null == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check no paging element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sDom": 'lfrti'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				nNodes[4] == nInfo &&
+				null == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Element with an id",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"sDom": '<"#test"lf>rti'
+			} );
+		},
+		function () {
+			return $('#test').length == 1;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Element with an id and a class",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"sDom": '<"#test.classTest"lf>rti'
+			} );
+		},
+		function () {
+			return ($('#test').length == 1 && $('#test')[0].className == "classTest");
+		}
+	);
+	
+	oTest.fnTest( 
+		"Element with just a class",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"sDom": '<"classTest"lf>rti'
+			} );
+		},
+		function () {
+			return ($('div.classTest').length == 1 );
+		}
+	);
+	
+	oTest.fnTest( 
+		"Two elements with an id",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"sDom": '<"#test1"lf>rti<"#test2"lf>'
+			} );
+		},
+		function () {
+			return ($('#test1').length == 1 && $('#test2').length == 1);
+		}
+	);
+	
+	oTest.fnTest( 
+		"Two elements with an id and one with a class",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"sDom": '<"#test1"lf>rti<"#test2.classTest"lf>'
+			} );
+		},
+		function () {
+			return ($('#test1').length == 1 && $('#test2').length == 1 && $('div.classTest').length == 1);
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/1_dom/sPaginationType.js
@@ -1,1 +1,122 @@
+// DATA_TEMPLATE: dom_data
+oTest.fnStart( "sPaginationType" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable();
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Check two button paging is the default",
+		null,
+		function () { return oSettings.sPaginationType == "two_button"; }
+	);
+	
+	oTest.fnTest( 
+		"Check class is applied",
+		null,
+		function () { return $('#example_paginate').hasClass('paging_two_button'); }
+	);
+	
+	oTest.fnTest( 
+		"Two div elements are in the wrapper",
+		null,
+		function () { return $('#example_paginate div').length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"We have the previous button",
+		null,
+		function () { return document.getElementById('example_previous'); }
+	);
+	
+	oTest.fnTest( 
+		"We have the next button",
+		null,
+		function () { return document.getElementById('example_next'); }
+	);
+	
+	oTest.fnTest( 
+		"Previous button is disabled",
+		null,
+		function () { return $('#example_previous').hasClass('paginate_disabled_previous'); }
+	);
+	
+	oTest.fnTest( 
+		"Next button is enabled",
+		null,
+		function () { return $('#example_next').hasClass('paginate_enabled_next'); }
+	);
+	
+	/* Don't test paging - that's done by the zero config test script. */
+	
+	
+	/* Two buttons paging */
+	oTest.fnTest( 
+		"Can enabled full numbers paging",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sPaginationType": "full_numbers"
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.sPaginationType == "full_numbers"; }
+	);
+	
+	oTest.fnTest( 
+		"Check full numbers class is applied",
+		null,
+		function () { return $('#example_paginate').hasClass('paging_full_numbers'); }
+	);
+	
+	
+	var nFirst, nPrevious, nNext, nLast;
+	oTest.fnTest( 
+		"Jump to last page",
+		function () {
+			nFirst = $('div.dataTables_paginate span.first');
+			nPrevious = $('div.dataTables_paginate span.previous');
+			nNext = $('div.dataTables_paginate span.next');
+			nLast = $('div.dataTables_paginate span.last');
+			nLast.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 51 to 57 of 57 entries";
+		}
+	);
+	
+	oTest.fnTest( 
+		"Go to two pages previous",
+		function () {
+			nPrevious.click();
+			nPrevious.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 31 to 40 of 57 entries";
+		}
+	);
+	
+	oTest.fnTest( 
+		"Next (second last) page",
+		function () {
+			nNext.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 41 to 50 of 57 entries";
+		}
+	);
+	
+	oTest.fnTest( 
+		"Jump to first page",
+		function () {
+			nFirst.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries";
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/_zero_config.js
@@ -1,1 +1,440 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "Sanity checks for DataTables with data from JS" );
 
+oTest.fnTest( 
+	"jQuery.dataTable function",
+	null,
+	function () { return typeof jQuery().dataTable == "function"; }
+);
+
+oTest.fnTest(
+	"jQuery.dataTableSettings storage array",
+	null,
+	function () { return typeof jQuery().dataTableSettings == "object"; }
+);
+
+oTest.fnTest(
+	"jQuery.dataTableExt plugin object",
+	null,
+	function () { return typeof jQuery().dataTableExt == "object"; }
+);
+
+$(document).ready( function () {
+	var oInit = {
+		"aaData": gaaData
+	};
+	$('#example').dataTable( oInit );
+	
+	/* Basic checks */
+	oTest.fnTest( 
+		"Length changing div exists",
+		null,
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Filtering div exists",
+		null,
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Information div exists",
+		null,
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Pagination div exists",
+		null,
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is off by default",
+		null,
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnTest( 
+		"10 rows shown on the first page",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Initial sort occured",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	/* Need to use the WaitTest for sorting due to the setTimeout datatables uses */
+	oTest.fnTest( 
+		"Sorting (first click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (second click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (third click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (first click) on numeric column",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "-"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (second click) on numeric column",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column (first click)",
+		function () { 
+			$('#example thead th:eq(0)').click();
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () { var b = 
+			$('#example tbody td:eq(0)').html() == "Gecko" && 
+			$('#example tbody td:eq(1)').html() == "Camino 1.0"; return b; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - sorting second column only",
+		function () { 
+			$('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	/* Basic paging */
+	oTest.fnTest( 
+		"Paging to second page",
+		function () { $('#example_next').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "IE Mobile"; }
+	);
+	
+	oTest.fnTest( 
+		"Paging to first page",
+		function () { $('#example_previous').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Attempting to page back beyond the first page",
+		function () { $('#example_previous').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	/* Changing length */
+	oTest.fnTest( 
+		"Changing table length to 25 records",
+		function () { $("select[name=example_length]").val('25').change(); },
+		function () { return $('#example tbody tr').length == 25; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 50 records",
+		function () { $("select[name=example_length]").val('50').change(); },
+		function () { return $('#example tbody tr').length == 50; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 100 records",
+		function () { $("select[name=example_length]").val('100').change(); },
+		function () { return $('#example tbody tr').length == 57; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 10 records",
+		function () { $("select[name=example_length]").val('10').change(); },
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	/*
+	 * Information element
+	 */
+	oTest.fnTest(
+		"Information on zero config",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 11 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on third page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 21 to 30 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on last page",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 51 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information back on first page",
+		function () {
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 25 records",
+		function () { $("select[name=example_length]").val('25').change(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 25 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 25 records - second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 26 to 50 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 100 records - first page",
+		function () {
+			$('#example_previous').click();
+			$("select[name=example_length]").val('100').change();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information back to 10 records",
+		function () {
+			$('#example_previous').click();
+			$("select[name=example_length]").val('10').change();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' last page",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 31 to 31 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' back to first page",
+		function () {
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page - second time",
+		function () {
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter increased to 'Win 98'",
+		function () { $('#example_filter input').val("Win 98").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 9 of 9 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter decreased to 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page - third time",
+		function () {
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter removed",
+		function () { $('#example_filter input').val("").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	/*
+	 * Filtering
+	 */
+	oTest.fnTest(
+		"Filter 'W' - rows",
+		function () { 
+			/* Reset the table such that the old sorting doesn't mess things up */
+			oSession.fnRestore();
+			$('#example').dataTable( oInit );
+			$('#example_filter input').val("W").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'W' - info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 42 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Wi'",
+		function () { $('#example_filter input').val("Wi").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 32 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "AOL browser (AOL desktop)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1 info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1 reverse",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - maintaing reverse sorting col 1",
+		function () { $('#example_filter input').val("Win XP").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Internet Explorer 7"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - sorting col 3",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - sorting col 3 - reversed",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "7"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting col 3 - reversed info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 6 of 6 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'nothinghere'",
+		function () { $('#example_filter input').val("nothinghere").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 
+			"No matching records found"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'nothinghere' - info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 0 to 0 of 0 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter back to blank and 1st column sorting",
+		function () {
+			$('#example_filter input').val("").keyup();
+			$('#example thead th:eq(0)').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Prefixing a filter entry",
+		function () {
+			$('#example_filter input').val("Win").keyup();
+			$('#example_filter input').val("GeckoWin").keyup();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 0 to 0 of 0 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Prefixing a filter entry with space",
+		function () {
+			$('#example_filter input').val("Gecko Win").keyup();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 17 entries (filtered from 57 total entries)"; }
+	);
+	
+	
+	
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aaSorting.js
@@ -1,1 +1,198 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aaSorting" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default sorting is single column",
+		null,
+		function () {
+			return oSettings.aaSorting.length == 1 && typeof oSettings.aaSorting[0] == 'object';
+		}
+	);
+	
+	oTest.fnTest( 
+		"Default sorting is first column asc",
+		null,
+		function () {
+			return oSettings.aaSorting[0].length == 3 && oSettings.aaSorting[0][0] == 0 &&
+				oSettings.aaSorting[0][1] == 'asc';
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting is applied",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Custom sorting on single string column asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Custom sorting on single string column desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Custom sorting on single int column asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "-"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Custom sorting on single int column desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string asc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','asc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string asc / string desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','asc'], ['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string desc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','desc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "iPod Touch / iPhone"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string desc / string desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','desc'], ['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Safari 3.0"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string asc / int asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','asc'], ['3','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "1"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string asc / int desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','asc'], ['3','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "1.9"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string desc / int asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','desc'], ['3','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "125.5"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (2 column) - string desc / int desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','desc'], ['3','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column sorting (3 column) - string asc / int asc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSorting": [['0','asc'], ['3','asc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(7) td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aaSortingFixed.js
@@ -1,1 +1,64 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aaSortingFixed" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"No fixed sorting by default",
+		null,
+		function () {
+			return oSettings.aaSortingFixed == null;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Fixed sorting on first column (string/asc) with user sorting on second column (string/asc)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSortingFixed": [['0','asc']]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnTest( 
+		"Fixed sorting on first column (string/asc) with user sorting on second column (string/desc)",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Fixed sorting on fourth column (int/asc) with user sorting on second column (string/asc)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aaSortingFixed": [['3','asc']]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Fixed sorting on fourth column (int/asc) with user sorting on second column (string/desc)",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "PSP browser"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.bSearchable.js
@@ -1,1 +1,71 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.bSeachable" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Columns are searchable by default",
+		function () { oTable.fnFilter("Camino"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html().match(/Camino/); }
+	);
+	
+	oTest.fnTest( 
+		"Disabling sorting on a column removes it from the global filter",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "bSearchable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("Camino");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnTest( 
+		"Disabled on one column has no effect on other columns",
+		function () { oTable.fnFilter("Webkit"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Webkit"; }
+	);
+	
+	oTest.fnTest( 
+		"Disable filtering on multiple columns",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					{ "bSearchable": false },
+					{ "bSearchable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("Webkit");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnTest( 
+		"Filter on second disabled column",
+		function () { oTable.fnFilter("Camino"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.bSortable.js
@@ -1,1 +1,109 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.bSortable" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"All columns are sortable by default",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Can disable sorting from one column",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "bSortable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() != "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Disabled column has no sorting class",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc") == false; }
+	);
+	
+	oTest.fnTest( 
+		"Other columns can still sort",
+		function () {
+			$('#example thead th:eq(4)').click();
+			$('#example thead th:eq(4)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == "X"; }
+	);
+	
+	oTest.fnTest( 
+		"Disable sorting on multiple columns - no sorting classes",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "bSortable": false },
+					null,
+					{ "bSortable": false },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example thead th:eq(1)').hasClass("sorting") ||
+				$('#example thead th:eq(3)').hasClass("sorting")
+			return bReturn == false;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting on disabled column 1 has no effect",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() != "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on disabled column 2 has no effect",
+		function () {
+			$('#example thead th:eq(3)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() != "-"; }
+	);
+	
+	oTest.fnTest( 
+		"Second sort on disabled column 2 has no effect",
+		function () {
+			$('#example thead th:eq(3)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() != "-"; }
+	);
+	
+	oTest.fnTest( 
+		"Even with multiple disabled sorting columns other columns can still sort",
+		function () {
+			$('#example thead th:eq(4)').click();
+			$('#example thead th:eq(4)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == "X"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.bUseRendered.js
@@ -1,1 +1,148 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.bUseRendered" );
 
+/* bUseRendered is used to alter sorting data, if false then the original data is used for
+ * sorting rather than the rendered data
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var mTmp = 0;
+	
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData,
+		"aoColumns": [
+			null,
+			{ "fnRender": function (a) {
+				if ( mTmp == 0 ) {
+					mTmp++;
+					return "aaa";
+				} else
+					return a.aData[a.iDataColumn];
+			} },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default for bUseRendered is true - rendered data is used for sorting",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'aaa'; }
+	);
+	
+	oTest.fnTest( 
+		"When bUseRendered is false, original data is used for sorting",
+		function () {
+			mTmp = 0;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ 
+						"bUseRendered": false,
+						"fnRender": function (a) {
+							if ( mTmp == 0 ) {
+								mTmp++;
+								return "aaa";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					null,
+					null,
+					null
+				]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	
+	oTest.fnTest( 
+		"bUseRendered set to false on one columns and true (default) on two others",
+		function () {
+			mTmp = 0;
+			var mTmp2 = 0;
+			var mTmp3 = 0;
+			
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					{
+						"fnRender": function (a) {
+							if ( mTmp == 0 ) {
+								mTmp++;
+								return "aaa1";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					{ 
+						"bUseRendered": false,
+						"fnRender": function (a) {
+							if ( mTmp2 == 0 ) {
+								mTmp2++;
+								return "aaa2";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					{
+						"fnRender": function (a) {
+							if ( mTmp3 == 0 ) {
+								mTmp3++;
+								return "zzz3";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'aaa1'; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column rendering - 2nd column sorting",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column rendering - 3rd column sorting",
+		function () {
+			$('#example thead th:eq(2)').click();
+			$('#example thead th:eq(2)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(2)').html() == 'zzz3'; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column rendering - 4th column sorting",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == '-'; }
+	);
+	
+	oTest.fnTest( 
+		"Multi-column rendering - 5th column sorting",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.bVisible.js
@@ -1,1 +1,110 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.bVisible" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"All columns are visible by default",
+		null,
+		function () { return $('#example tbody tr:eq(0) td').length == 5; }
+	);
+	
+	oTest.fnTest( 
+		"Can hide one column and it removes td column from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "bVisible": false },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 4; }
+	);
+	
+	oTest.fnTest( 
+		"Can hide one column and it removes thead th column from DOM",
+		null,
+		function () { return $('#example thead tr:eq(0) th').length == 4; }
+	);
+	
+	oTest.fnTest( 
+		"Can hide one column and it removes tfoot th column from DOM",
+		null,
+		function () { return $('#example tfoot tr:eq(0) th').length == 4; }
+	);
+	
+	oTest.fnTest( 
+		"The correct tbody column has been hidden",
+		function () {
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } );
+		},
+		function () {
+			var jqNodes = $('#example tbody tr:eq(0) td');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Gecko" &&
+				jqNodes[1].innerHTML == "Gnome" &&
+				jqNodes[2].innerHTML == "1.8" &&
+				jqNodes[3].innerHTML == "A";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Can hide multiple columns and it removes td column from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "bVisible": false },
+					{ "bVisible": false },
+					null,
+					{ "bVisible": false }
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"Multiple hide - removes thead th column from DOM",
+		null,
+		function () { return $('#example thead tr:eq(0) th').length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"Multiple hide - removes tfoot th column from DOM",
+		null,
+		function () { return $('#example tfoot tr:eq(0) th').length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"Multiple hide - the correct tbody columns have been hidden",
+		function () {
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } );
+		},
+		function () {
+			var jqNodes = $('#example tbody tr:eq(0) td');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Gecko" &&
+				jqNodes[1].innerHTML == "1"
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.fnRender.js
@@ -1,1 +1,182 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.fnRender" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var mTmp = 0;
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData,
+		"aoColumns": [
+			null,
+			{ "fnRender": function (a) {
+				mTmp++;
+				return a.aData[a.iDataColumn];
+			} },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Single column - fnRender is called once for each row",
+		null,
+		function () { return mTmp == 57; }
+	);
+	
+	oTest.fnTest( 
+		"Confirm that fnRender passes one argument (an object) with three parameters",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( arguments.length != 1 || typeof a.iDataRow=='undefined' ||
+						 	typeof a.iDataColumn=='undefined' || typeof a.aData=='undefined' )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnTest( 
+		"fnRender iDataColumn is row number",
+		function () {
+			var iCount = 0;
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( iCount != a.iDataRow )
+						{
+							mTmp = false;
+						}
+						iCount++;
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnTest( 
+		"fnRender iDataColumn is the column",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( a.iDataColumn != 1 )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnTest( 
+		"fnRender aData is data array of correct size",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( a.aData.length != 5 )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnTest( 
+		"Passed back data is put into the DOM",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						return 'unittest';
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'unittest'; }
+	);
+	
+	oTest.fnTest( 
+		"Passed back data is put into the DOM",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					null,
+					{ "fnRender": function (a) {
+						return 'unittest1';
+					} },
+					{ "fnRender": function (a) {
+						return 'unittest2';
+					} },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example tbody tr:eq(0) td:eq(2)').html() == 'unittest1' &&
+				$('#example tbody tr:eq(0) td:eq(3)').html() == 'unittest2';
+			return bReturn; }
+	);
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.iDataSort.js
@@ -1,1 +1,90 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.iDataSort" );
 
+$(document).ready( function () {
+	/* Should know that sorting already works by default from other tests, so we can jump
+	 * right in here
+	 */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData,
+		"aoColumns": [
+			null,
+			{ "iDataSort": 4 },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Sorting on first column is uneffected",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko'; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on second column is the order of the fifth",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	oTest.fnTest( 
+		"Reserve sorting on second column uses fifth column as well",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'X'; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting on 5th column retains it's own sorting",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Use 2nd col for sorting 5th col and via-versa - no effect on first col sorting",
+		function () {
+			mTmp = 0;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "iDataSort": 4 },
+					null,
+					null,
+					{ "iDataSort": 1 }
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko'; }
+	);
+	
+	oTest.fnTest( 
+		"2nd col sorting uses fifth col",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	oTest.fnTest( 
+		"2nd col sorting uses fifth col - reversed",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'X'; }
+	);
+	
+	oTest.fnTest( 
+		"5th col sorting uses 2nd col",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	oTest.fnTest( 
+		"5th col sorting uses 2nd col - reversed",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'Seamonkey 1.1'; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.sClass.js
@@ -1,1 +1,115 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.sClass" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"By default the test class hasn't been applied to the column (sanity!)",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(2)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - first row",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					null,
+					{ "sClass": 'unittest' },
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(1) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - third row",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - last row",
+		null,
+		function () { return $('#example tbody tr:eq(9) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - has not applied to other columns - 1st",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(0)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - has not applied to other columns - 5th",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - seventh row - second page",
+		function () { $('#example_next').click(); },
+		function () { return $('#example tbody tr:eq(6) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - has not applied to header",
+		null,
+		function () { return $('#example thead tr:eq(3) th:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Add a class to a single column - has not applied to footer",
+		null,
+		function () { return $('#example thead tr:eq(3) th:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Class defined for multiple columns - first row",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					{ "sClass": 'unittest2' },
+					null,
+					null,
+					{ "sClass": 'unittest1' },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example tbody tr:eq(3) td:eq(0)').hasClass('unittest2') &&
+				$('#example tbody tr:eq(8) td:eq(3)').hasClass('unittest1');
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Class defined for multiple columns - has not applied to other columns - 5th 1",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').hasClass('unittest1') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Class defined for multiple columns - has not applied to other columns - 5th 2",
+		null,
+		function () { return $('#example tbody tr:eq(6) td:eq(4)').hasClass('unittest2') == false; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.sName.js
@@ -1,1 +1,28 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.sName" );
 
+/* This has no effect at all in DOM methods - so we just check that it has applied the name */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData,
+		"aoColumns": [
+			null,
+			null,
+			null,
+			{ "sName": 'unit test' },
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Names are stored in the columns object",
+		null,
+		function () { return oSettings.aoColumns[3].sName =="unit test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.sTitle.js
@@ -1,1 +1,82 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.sTitle" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"If not given, then the columns titles are empty",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Browser" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Can set a single column title - and others are read from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "sTitle": 'unit test' },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "unit test" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Can set multiple column titles",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					{ "sTitle": 'unit test 1' },
+					null,
+					null,
+					{ "sTitle": 'unit test 2' }
+				]
+			} );
+		},
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "unit test 1" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "unit test 2";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoColumns.sWidth.js
@@ -1,1 +1,87 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoColumns.sWidth" );
 
+/* NOTE - we need to disable the auto width for the majority of these test in order to preform 
+ * these tests as the auto width will convert the width to a px value. We can do 'non-exact' tests
+ * with auto width enabled however to ensure it scales columns as required
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData,
+		"bAutoWidth": false,
+		"aoColumns": [
+			null,
+			{ "sWidth": '40%' },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"With auto width disabled the width for one column is appled",
+		null,
+		function () { return $('#example thead th:eq(1)')[0].style.width == "40%"; }
+	);
+	
+	oTest.fnTest( 
+		"With auto width disabled the width for one column is appled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"bAutoWidth": false,
+				"aoColumns": [
+					null,
+					null,
+					{ "sWidth": '20%' },
+					{ "sWidth": '30%' },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn =
+				$('#example thead th:eq(2)')[0].style.width == "20%" &&
+				$('#example thead th:eq(3)')[0].style.width == "30%";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"With auto width, it will make the smallest column the largest with percentage width given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoColumns": [
+					null,
+					null,
+					null,
+					{ "sWidth": '40%' },
+					null
+				]
+			} );
+		},
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			
+			if ( a3>a0 && a3>a1 && a3>a2 && a3>a4 )
+				return true;
+			else
+				return false;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/aoSearchCols.js
@@ -1,1 +1,119 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "aoSearchCols" );
 
+/* We could be here forever testing this one, so we test a limited subset on a couple of colums */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default should be to have a empty colums array",
+		null,
+		function () {
+			var bReturn = 
+				oSettings.aoPreSearchCols[0].sSearch == 0 && !oSettings.aoPreSearchCols[0].bRegex &&
+				oSettings.aoPreSearchCols[1].sSearch == 0 && !oSettings.aoPreSearchCols[1].bRegex &&
+				oSettings.aoPreSearchCols[2].sSearch == 0 && !oSettings.aoPreSearchCols[2].bRegex &&
+				oSettings.aoPreSearchCols[3].sSearch == 0 && !oSettings.aoPreSearchCols[3].bRegex &&
+				oSettings.aoPreSearchCols[4].sSearch == 0 && !oSettings.aoPreSearchCols[4].bRegex;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Search on a single column - no regex statement given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoSearchCols": [
+					null,
+					{ "sSearch": "Mozilla" },
+					null,
+					{ "sSearch": "1" },
+					null
+				]
+			} );
+		},
+		function () { return $('#example_info').html() == "Showing 1 to 9 of 9 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest( 
+		"Search on two columns - no regex statement given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoSearchCols": [
+					null,
+					{ "sSearch": "Mozilla" },
+					null,
+					{ "sSearch": "1.5" },
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "1.5"; }
+	);
+	
+	oTest.fnTest( 
+		"Search on single column - escape regex false",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					null,
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example_info').html() == "Showing 1 to 3 of 3 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest( 
+		"Search on two columns - escape regex false on first, true on second",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					{ "sSearch": "3.3", "bEscapeRegex": true },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Konqureror 3.3"; }
+	);
+	
+	oTest.fnTest( 
+		"Search on two columns (no records) - escape regex false on first, true on second",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					{ "sSearch": "Allan", "bEscapeRegex": true },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/asStripClasses.js
@@ -1,1 +1,100 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "asStripClasses" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	
+	oTest.fnTest( 
+		"Default row striping is applied",
+		null,
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('odd') &&
+			       $('#example tbody tr:eq(1)').hasClass('even') &&
+			       $('#example tbody tr:eq(2)').hasClass('odd') &&
+			       $('#example tbody tr:eq(3)').hasClass('even');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Row striping on the second page",
+		function () { $('#example_next').click(); },
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('odd') &&
+			       $('#example tbody tr:eq(1)').hasClass('even') &&
+			       $('#example tbody tr:eq(2)').hasClass('odd') &&
+			       $('#example tbody tr:eq(3)').hasClass('even');
+		}
+	);
+	
+	/* No striping */
+	oTest.fnTest( 
+		"No row striping",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"asStripClasses": []
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)')[0].className == "" &&
+			       $('#example tbody tr:eq(1)')[0].className == "" &&
+			       $('#example tbody tr:eq(2)')[0].className == "" &&
+			       $('#example tbody tr:eq(3)')[0].className == "";
+		}
+	);
+	
+	/* Custom striping */
+	oTest.fnTest( 
+		"Custom striping [2]",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"asStripClasses": [ 'test1', 'test2' ]
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test1') &&
+			       $('#example tbody tr:eq(3)').hasClass('test2');
+		}
+	);
+	
+	
+	/* long array of striping */
+	oTest.fnTest( 
+		"Custom striping [4]",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"asStripClasses": [ 'test1', 'test2', 'test3', 'test4' ]
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test3') &&
+			       $('#example tbody tr:eq(3)').hasClass('test4');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Custom striping is restarted on second page [2]",
+		function () { $('#example_next').click(); },
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test3') &&
+			       $('#example tbody tr:eq(3)').hasClass('test4');
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bAutoWidth.js
@@ -1,1 +1,142 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bAutoWidth" );
 
+/* It's actually a little tricky to test this. We can't test absolute numbers because
+ * different browsers and different platforms will render the width of the columns slightly
+ * differently. However, we certainly can test the principle of what should happen (column 
+ * width doesn't change over pages)
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Auto width is enabled by default",
+		null,
+		function () { return oSettings.oFeatures.bAutoWidth; }
+	);
+	
+	oTest.fnTest( 
+		"First column has a width assigned to it",
+		null,
+		function () { return $('#example thead th:eq(0)').attr('style').match(/width/i); }
+	);
+	
+	/*
+	This would seem like a better test - but there appear to be difficulties with tables
+	which are bigger (calculated) than there is actually room for. I suspect this is actually
+	a bug in datatables
+	oTest.fnTest( 
+		"Check column widths on first page match second page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			console.log( a0, b0, a1, b1, a2, b2, a3, b3 );
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return true;
+			else
+				return false;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check column widths on second page match thid page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return true;
+			else
+				return false;
+		}
+	);
+	*/
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Auto width can be disabled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"bAutoWidth": false
+			} );
+	 		oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bAutoWidth == false; }
+	);
+	
+	oTest.fnTest( 
+		"First column does not have a width assigned to it",
+		null,
+		function () { return $('#example thead th:eq(0)').attr('style') == null; }
+	);
+	
+	/*
+	oTest.fnTest( 
+		"Check column widths on first page do not match second page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return false;
+			else
+				return true;
+		}
+	);
+	*/
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Auto width enabled override",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"bAutoWidth": true
+			} );
+	 		oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bAutoWidth; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bFilter.js
@@ -1,1 +1,44 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bFilter" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	
+	oTest.fnTest( 
+		"Filtering div exists by default",
+		null,
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Fltering can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bFilter": false
+			} );
+		},
+		function () { return document.getElementById('example_filter') == null; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Filtering enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bFilter": true
+			} );
+		},
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bInfo.js
@@ -1,1 +1,44 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bInfo" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	
+	oTest.fnTest( 
+		"Info div exists by default",
+		null,
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Info can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bInfo": false
+			} );
+		},
+		function () { return document.getElementById('example_info') == null; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Info enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bInfo": true
+			} );
+		},
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bLengthChange.js
@@ -1,1 +1,75 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bLengthChange" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	
+	oTest.fnTest( 
+		"Length div exists by default",
+		null,
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	oTest.fnTest(
+		"Four default options",
+		null,
+		function () { return $("select[name=example_length] option").length == 4; }
+	);
+	
+	oTest.fnTest(
+		"Default options",
+		null,
+		function () {
+			var opts = $("select[name='example_length'] option");
+			return opts[0].getAttribute('value') == 10 && opts[1].getAttribute('value') == 25 &&
+				opts[2].getAttribute('value') == 50 && opts[3].getAttribute('value') == 100;
+		}
+	);
+	
+	oTest.fnTest(
+		"Info takes length into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Change length can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bLengthChange": false
+			} );
+		},
+		function () { return document.getElementById('example_length') == null; }
+	);
+	
+	oTest.fnTest(
+		"Information takes length disabled into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Length change enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bLengthChange": true
+			} );
+		},
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bPaginate.js
@@ -1,1 +1,59 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bPaginate" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	
+	oTest.fnTest( 
+		"Pagiantion div exists by default",
+		null,
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	oTest.fnTest(
+		"Information div takes paging into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Pagiantion can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bPaginate": false
+			} );
+		},
+		function () { return document.getElementById('example_paginate') == null; }
+	);
+	
+	oTest.fnTest(
+		"Information div takes paging disabled into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 57 of 57 entries"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Pagiantion enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bPaginate": true
+			} );
+		},
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bProcessing.js
@@ -1,1 +1,103 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bProcessing" );
 
+/* It's actually a bit hard to set this one due to the fact that it will only be shown
+ * when DataTables is doing some kind of processing. The server-side processing is a bit
+ * better to test this than here - so we just the interal functions to enable it and check
+ * that it is available
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Processing is off by default",
+		null,
+		function () { return oSettings.oFeatures.bProcessing == false; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is not in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div cannot be shown",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div cannot be hidden",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, false ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Processing can be enabled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"bProcessing": true
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bProcessing == true; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing'); }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is hidden by default",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing').style.visibility = "hidden"; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div can be shown",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing').style.visibility = "visible"; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div can be hidden",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, false ); },
+		function () { return document.getElementById('example_processing').style.visibility = "hidden"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Processing disabled override",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"bProcessing": false
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bProcessing == false; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is not in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bServerSide.js
@@ -1,1 +1,20 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bServerSide" );
 
+/* Not interested in server-side processing here other than to check that it is off */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Server side is off by default",
+		null,
+		function () { return oSettings.oFeatures.bServerSide == false; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bSort.js
@@ -1,1 +1,99 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bSort" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	
+	oTest.fnTest( 
+		"Sorting is on by default",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting Asc by default class applied",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass("sorting_asc"); }
+	);
+	
+	oTest.fnTest(
+		"Click on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting class removed from first column",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass("sorting_asc") != true; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting asc class applied to second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc"); }
+	);
+	
+	oTest.fnTest(
+		"Reverse on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting acs class removed from second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc") != true; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting desc class applied to second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_desc"); }
+	);
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Pagiantion can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bSort": false
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnTest(
+		"Click on second column has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnTest(
+		"Reverse on second column has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Sorting enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bSort": true
+			} );
+		},
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/bSortClasses.js
@@ -1,1 +1,132 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "bSortClasses" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	
+	oTest.fnTest( 
+		"Sorting classes are applied by default",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	oTest.fnTest( 
+		"Sorting classes are applied to all required cells",
+		null,
+		function () { return $('#example tbody tr:eq(7) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	oTest.fnTest( 
+		"Sorting classes are not applied to non-sorting columns",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_1') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - add column 1",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - add column 2",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(2)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - add column 3",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(3)')[0], { 'shift': true } );
+		},
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') &&
+						 $('#example tbody tr:eq(0) td:eq(3)').hasClass('sorting_3');
+		}
+	);
+	
+	oTest.fnTest( 
+		"Remove sorting classes on single column sort",
+		function () { 
+			$('#example thead th:eq(4)').click();
+		},
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') == false &&
+						 $('#example tbody tr:eq(0) td:eq(3)').hasClass('sorting_3') == false;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting class 1 was added",
+		null,
+		function () { return $('#example tbody tr:eq(1) td:eq(4)').hasClass('sorting_1'); }
+	);
+	
+	
+	/* Check can disable */
+	oTest.fnTest( 
+		"Sorting classes can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bSortClasses": false
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting classes disabled - add column 1 - no effect",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Sorting classes disabled - add column 2 - no effect",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(2)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') == false;
+		}
+	);
+	
+	
+	/* Enable makes no difference */
+	oTest.fnTest( 
+		"Sorting classes enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"bSortClasses": true
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/fnDrawCallback.js
@@ -1,1 +1,85 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "fnDrawCallback" );
 
+/* Fairly boring function compared to the others! */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnDrawCallback == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"One argument passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnDrawCallback": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnTest( 
+		"That one argument is the settings object",
+		function () {
+			oSession.fnRestore();
+			
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"fnDrawCallback": function ( oSettings ) {
+					mPass = oSettings;
+				}
+			} );
+		},
+		function () { return oTable.fnSettings() == mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback called once on first draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnDrawCallback": function ( ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnTest( 
+		"fnRowCallback called once on each draw there after as well",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return mPass == 4; }
+	);
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/fnFooterCallback.js
@@ -1,1 +1,240 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "fnFooterCallback" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnFooterCallback == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Five arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 5; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback called once per draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnTest( 
+		"fnRowCallback called on paging (i.e. another draw)",
+		function () { $('#example_next').click(); },
+		function () { return mPass == 2; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					nFoot.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+				}
+			} );
+		},
+		function () { return $('#example tfoot th:eq(0)').html() == "Displaying 10 records"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Data array has length matching original data",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aasData.length != 57 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Data array's column lengths match original data",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					for ( var i=0, iLen=aasData.length ; i<iLen ; i++ )
+					{
+						if ( aasData[i].length != 5 )
+						{
+							mPass = false;
+						}
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iStart correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart != 0 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iStart correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart == 10 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			$('#example_next').click();
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iEnd correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd != 10 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iEnd correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd == 20 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			$('#example_next').click();
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"aiDisplay length is full data when not filtered",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 57 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"aiDisplay length is 9 when filtering on 'Mozilla'",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"fnFooterCallback": function ( nFoot, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 9 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			oTable.fnFilter( "Mozilla" );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/fnHeaderCallback.js
@@ -1,1 +1,240 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "fnHeaderCallback" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnHeaderCallback == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Five arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 5; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback called once per draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnTest( 
+		"fnRowCallback called on paging (i.e. another draw)",
+		function () { $('#example_next').click(); },
+		function () { return mPass == 2; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+				}
+			} );
+		},
+		function () { return $('#example thead th:eq(0)').html() == "Displaying 10 records"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Data array has length matching original data",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aasData.length != 57 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Data array's column lengths match original data",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					for ( var i=0, iLen=aasData.length ; i<iLen ; i++ )
+					{
+						if ( aasData[i].length != 5 )
+						{
+							mPass = false;
+						}
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iStart correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart != 0 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iStart correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart == 10 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			$('#example_next').click();
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iEnd correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd != 10 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"iEnd correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd == 20 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			$('#example_next').click();
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"aiDisplay length is full data when not filtered",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 57 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"aiDisplay length is 9 when filtering on 'Mozilla'",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 9 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			oTable.fnFilter( "Mozilla" );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/fnInitComplete.js
@@ -1,1 +1,83 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "fnInitComplete" );
 
+/* Fairly boring function compared to the others! */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnInitComplete == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"One argument passed (for DOM!)",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnInitComplete": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnTest( 
+		"That one argument is the settings object",
+		function () {
+			oSession.fnRestore();
+			
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"fnInitComplete": function ( oSettings ) {
+					mPass = oSettings;
+				}
+			} );
+		},
+		function () { return oTable.fnSettings() == mPass; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnInitComplete called once on first draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnInitComplete": function ( ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnTest( 
+		"fnInitComplete never called there after",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/fnRowCallback.js
@@ -1,1 +1,112 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "fnRowCallback" );
 
+/* Note - fnRowCallback MUST return the first arguments (modified or not) */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnRowCallback == null; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Four arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnRowCallback": function ( nTr ) {
+					mPass = arguments.length;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass == 4; }
+	);
+	
+	
+	oTest.fnTest( 
+		"fnRowCallback called once for each drawn row",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					mPass++;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass == 10; }
+	);
+	
+	oTest.fnTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					$(nTr).addClass('unit_test');
+					return nTr;
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(1)').hasClass('unit_test'); }
+	);
+	
+	oTest.fnTest( 
+		"Data array has length matching columns",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					if ( asData.length != 5 )
+						mPass = false;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Data array has length matching columns",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			var iCount = 0;
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					if ( iCount != iDrawIndex )
+						mPass = false;
+					iCount++;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/iDisplayLength.js
@@ -1,1 +1,81 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "iDisplayLength" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	
+	oTest.fnTest( 
+		"Default length is ten",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Select menu shows 10",
+		null,
+		function () { return $('#example_length select').val() == 10; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Set initial length to 25",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"iDisplayLength": 25
+			} );
+		},
+		function () { return $('#example tbody tr').length == 25; }
+	);
+	
+	oTest.fnTest( 
+		"Select menu shows 25",
+		null,
+		function () { return $('#example_length select').val() == 25; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Set initial length to 100",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"iDisplayLength": 100
+			} );
+		},
+		function () { return $('#example tbody tr').length == 57; }
+	);
+	
+	oTest.fnTest( 
+		"Select menu shows 25",
+		null,
+		function () { return $('#example_length select').val() == 100; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Set initial length to 23 (unknown select menu length)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"iDisplayLength": 23
+			} );
+		},
+		function () { return $('#example tbody tr').length == 23; }
+	);
+	
+	oTest.fnTest( 
+		"Select menu shows 10 (since 23 is unknow)",
+		null,
+		function () { return $('#example_length select').val() == 10; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.oPaginate.js
@@ -1,1 +1,84 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.oPaginate" );
 
+/* Note that the paging language information only has relevence in full numbers */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData,
+		"sPaginationType": "full_numbers"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate defaults",
+		null,
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.oPaginate.sFirst == "First" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "Previous" &&
+				oSettings.oLanguage.oPaginate.sNext == "Next" &&
+				oSettings.oLanguage.oPaginate.sLast == "Last";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate defaults are in the DOM",
+		null,
+		function () {
+			var bReturn = 
+				$('#example_paginate .first').html() == "First" &&
+				$('#example_paginate .previous').html() == "Previous" &&
+				$('#example_paginate .next').html() == "Next" &&
+				$('#example_paginate .last').html() == "Last";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"sPaginationType": "full_numbers",
+				"oLanguage": {
+					"oPaginate": {
+						"sFirst":    "unit1",
+						"sPrevious": "test2",
+						"sNext":     "unit3",
+						"sLast":     "test4"
+					}
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.oPaginate.sFirst == "unit1" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "test2" &&
+				oSettings.oLanguage.oPaginate.sNext == "unit3" &&
+				oSettings.oLanguage.oPaginate.sLast == "test4";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate definitions are in the DOM",
+		null,
+		function () {
+			var bReturn = 
+				$('#example_paginate .first').html() == "unit1" &&
+				$('#example_paginate .previous').html() == "test2" &&
+				$('#example_paginate .next').html() == "unit3" &&
+				$('#example_paginate .last').html() == "test4";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.sInfo.js
@@ -1,1 +1,117 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.sInfo" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Info language is 'Showing _START_ to _END_ of _TOTAL_ entries' by default",
+		null,
+		function () { return oSettings.oLanguage.sInfo == "Showing _START_ to _END_ of _TOTAL_ entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Info language can be defined - without any macros",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfo": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sInfo == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macro _START_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfo": "unit _START_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macro _END_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfo": "unit _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 10 test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macro _TOTAL_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfo": "unit _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 57 test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macros _START_ and _END_",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfo": "unit _START_ _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 10 test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language can be defined - with macros _START_, _END_ and _TOTAL_",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfo": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 10 57 test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.sInfoEmpty.js
@@ -1,1 +1,79 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.sInfoEmpty" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Info empty language is 'Showing 0 to 0 of 0 entries' by default",
+		function () { oTable.fnFilter("nothinghere"); },
+		function () { return oSettings.oLanguage.sInfoEmpty == "Showing 0 to 0 of 0 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"Showing 0 to 0 of 0 entries";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Info empty language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfoEmpty": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("nothinghere");
+		},
+		function () { return oSettings.oLanguage.sInfoEmpty == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"unit test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Macro's not replaced",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfoEmpty": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+			oTable.fnFilter("nothinghere");
+		},
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"unit _START_ _END_ _TOTAL_ test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.sInfoPostFix.js
@@ -1,1 +1,78 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.sInfoPostFix" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Info post fix language is '' (blank) by default",
+		null,
+		function () { return oSettings.oLanguage.sInfoPostFix == ""; }
+	);
+	
+	oTest.fnTest( 
+		"Width no post fix, the basic info shows",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Info post fix language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfoPostFix": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sInfoPostFix == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries unit test"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Macros have no effect in the post fix",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfoPostFix": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries unit _START_ _END_ _TOTAL_ test"; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Post fix is applied after fintering info",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sInfoPostFix": "unit test"
+				}
+			} );
+			oTable.fnFilter("nothinghere");
+		},
+		function () { return document.getElementById('example_info').innerHTML = "Showing 0 to 0 of 0 entries unit (filtered from 57 total entries) test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.sLengthMenu.js
@@ -1,1 +1,106 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.sLengthMenu" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Menu language is 'Show _MENU_ entries' by default",
+		null,
+		function () { return oSettings.oLanguage.sLengthMenu == "Show _MENU_ entries"; }
+	);
+	
+	oTest.fnTest(
+		"_MENU_ macro is replaced by select menu in DOM",
+		null,
+		function () { return $('select', oSettings.aanFeatures.l[0]).length == 1 }
+	);
+	
+	oTest.fnTest(
+		"Default is put into DOM",
+		null,
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren[0].nodeValue == "Show " &&
+				anChildren[2].nodeValue == " entries";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Menu length language can be defined - no _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sLengthMenu": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sLengthMenu == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Menu length language definition is in the DOM",
+		null,
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			return anChildren[0].nodeValue == "unit test";
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Menu length language can be defined - with _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sLengthMenu": "unit _MENU_ test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren[0].nodeValue == "unit " &&
+				anChildren[2].nodeValue == " test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnTest( 
+		"Only the _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sLengthMenu": "_MENU_"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren.length == 1 &&
+				$('select', oSettings.aanFeatures.l[0]).length == 1;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.sProcessing.js
@@ -1,1 +1,49 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.sProcessing" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData,
+		"bProcessing": true
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Processing language is 'Processing...' by default",
+		null,
+		function () { return oSettings.oLanguage.sProcessing == "Processing..."; }
+	);
+	
+	oTest.fnTest( 
+		"Processing language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_processing').innerHTML = "Processing..."; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Processing language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"bProcessing": true,
+				"oLanguage": {
+					"sProcessing": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sProcessing == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Processing language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_processing').innerHTML = "unit test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.sSearch.js
@@ -1,1 +1,65 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.sSearch" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Search language is 'Search:' by default",
+		null,
+		function () { return oSettings.oLanguage.sSearch == "Search:"; }
+	);
+	
+	oTest.fnTest( 
+		"Search language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_filter').childNodes[0].nodeValue
+		 	== "Search: "; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Search language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sSearch": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sSearch == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_filter').childNodes[0].nodeValue
+		 	== "unit test "; }
+	);
+	
+	
+	oTest.fnTest( 
+		"Blank search has a no (separator) inserted",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sSearch": ""
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return document.getElementById('example_filter').childNodes.length == 1; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.sUrl.js
@@ -1,1 +1,62 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.sUrl" );
 
+/* Note that we only test the internal storage of language information pulled form a file here
+ * as the other language tests will check it goes into the DOM correctly
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"sUrl is blank by default",
+		null,
+		function () { return oSettings.oLanguage.sUrl == ""; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Loading of German file loads language information",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sUrl": "../../../examples/examples_support/de_DE.txt"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.sProcessing == "Bitte warten..." &&
+				oSettings.oLanguage.sLengthMenu == "_MENU_ Einträge anzeigen" &&
+				oSettings.oLanguage.sZeroRecords == "Keine Einträge vorhanden." &&
+				oSettings.oLanguage.sInfo == "_START_ bis _END_ von _TOTAL_ Einträgen" &&
+				oSettings.oLanguage.sInfoEmpty == "0 bis 0 von 0 Einträgen" &&
+				oSettings.oLanguage.sInfoFiltered == "(gefiltert von _MAX_  Einträgen)" &&
+				oSettings.oLanguage.sInfoPostFix == "" &&
+				oSettings.oLanguage.sSearch == "Suchen" &&
+				oSettings.oLanguage.oPaginate.sFirst == "Erster" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "Zurück" &&
+				oSettings.oLanguage.oPaginate.sNext == "Nächster" &&
+				oSettings.oLanguage.oPaginate.sLast == "Letzter";
+				
+			return bReturn;
+		}
+	);
+	
+	/* One DOM check just to ensure that they go into the DOM */
+	oTest.fnTest(
+		"Loaded language goes into the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "1 bis 10 von 57 Einträgen"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oLanguage.sZeroRecords.js
@@ -1,1 +1,48 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oLanguage.sZeroRecords" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Zero records language is 'No matching records found' by default",
+		null,
+		function () { return oSettings.oLanguage.sZeroRecords == "No matching records found"; }
+	);
+	
+	oTest.fnTest(
+		"Text is shown when empty table (after filtering)",
+		function () { oTable.fnFilter('nothinghere'); },
+		function () { return $('#example tbody tr td')[0].innerHTML == "No matching records found" }
+	);
+	
+	
+	
+	oTest.fnTest( 
+		"Zero records language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oLanguage": {
+					"sZeroRecords": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sZeroRecords == "unit test"; }
+	);
+	
+	oTest.fnTest(
+		"Text is shown when empty table (after filtering)",
+		function () { oTable.fnFilter('nothinghere2'); },
+		function () { return $('#example tbody tr td')[0].innerHTML == "unit test" }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/oSearch.js
@@ -1,1 +1,108 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "oSearch" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default values should be blank",
+		null,
+		function () {
+			var bReturn = oSettings.oPreviousSearch.sSearch == "" && 
+			              !oSettings.oPreviousSearch.bRegex;
+			return bReturn;
+		}
+	);
+	
+	/* This test might be considered iffy since the full object isn't given, but it's reasonable to
+	 * expect DataTables to cope with this. It should just assumine regex false
+	 */
+	oTest.fnTest( 
+		"Search term only in object",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"oSearch": {
+					"sSearch": "Mozilla"
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnTest( 
+		"New search will kill old one",
+		function () {
+			oTable.fnFilter("Opera");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Presto"; }
+	);
+	
+	oTest.fnTest( 
+		"Search plain text term and escape regex true",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oSearch": {
+					"sSearch": "DS",
+					"bRegex": false
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Nintendo DS browser"; }
+	);
+	
+	oTest.fnTest( 
+		"Search plain text term and escape regex false",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oSearch": {
+					"sSearch": "Opera",
+					"bRegex": true
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Presto"; }
+	);
+	
+	oTest.fnTest( 
+		"Search regex text term and escape regex true",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oSearch": {
+					"sSearch": "1.*",
+					"bRegex": false
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnTest( 
+		"Search regex text term and escape regex false",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"oSearch": {
+					"sSearch": "1.*",
+					"bRegex": true
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/sAjaxSource.js
@@ -1,1 +1,20 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "sAjaxSource" );
 
+/* Not interested in ajax source here other than to check it's default */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Server side is off by default",
+		null,
+		function () { return oSettings.sAjaxSource == null; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/sDom.js
@@ -1,1 +1,262 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "sDom" );
 
+/* This is going to be brutal on the browser! There is a lot that can be tested here... */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Default DOM varaible",
+		null,
+		function () { return oSettings.sDom == "lfrtip"; }
+	);
+	
+	oTest.fnTest( 
+		"Default DOM in document",
+		null,
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				nNodes[4] == nInfo &&
+				nNodes[5] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check example 1 in code propagates",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"sDom": '<"wrapper"flipt>'
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.sDom == '<"wrapper"flipt>'; }
+	);
+	
+	oTest.fnTest( 
+		"Check example 1 in DOM",
+		null,
+		function () {
+			var jqNodes = $('#demo div, #demo table');
+			var nNodes = [];
+			
+			/* Strip the paging nodes */
+			for ( var i=0, iLen=jqNodes.length ; i<iLen ; i++ )
+			{
+				if ( jqNodes[i].getAttribute('id') != "example_previous" &&
+				     jqNodes[i].getAttribute('id') != "example_next" )
+				{
+					nNodes.push( jqNodes[i] );
+				}
+			}
+			
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			var nCustomWrapper = $('div.wrapper')[0];
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nCustomWrapper &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nLength &&
+				nNodes[4] == nInfo &&
+				nNodes[5] == nPaging &&
+				nNodes[6] == nTable;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check example 2 in DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"sDom": '<lf<t>ip>'
+			} );
+		},
+		function () {
+			var jqNodes = $('#demo div, #demo table');
+			var nNodes = [];
+			var nCustomWrappers = []
+			
+			/* Strip the paging nodes */
+			for ( var i=0, iLen=jqNodes.length ; i<iLen ; i++ )
+			{
+				if ( jqNodes[i].getAttribute('id') != "example_previous" &&
+				     jqNodes[i].getAttribute('id') != "example_next" )
+				{
+					nNodes.push( jqNodes[i] );
+				}
+				
+				/* Only the two custom divs don't have class names */
+				if ( !jqNodes[i].getAttribute('class') )
+				{
+					nCustomWrappers.push( jqNodes[i] );
+				}
+			}
+			
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nCustomWrappers[0] &&
+				nNodes[2] == nLength &&
+				nNodes[3] == nFilter &&
+				nNodes[4] == nCustomWrappers[1] &&
+				nNodes[5] == nTable &&
+				nNodes[6] == nInfo &&
+				nNodes[7] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check no length element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"sDom": 'frtip'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				null == nLength &&
+				nNodes[1] == nFilter &&
+				nNodes[2] == nTable &&
+				nNodes[3] == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check no filter element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"sDom": 'lrtip'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				null == nFilter &&
+				nNodes[2] == nTable &&
+				nNodes[3] == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	/* Note we don't test for no table as this is not supported (and it would be fairly daft! */
+	
+	oTest.fnTest( 
+		"Check no info element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"sDom": 'lfrtp'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				null == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"Check no paging element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"aaData": gaaData,
+				"sDom": 'lfrti'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				nNodes[4] == nInfo &&
+				null == nPaging;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/2_js/sPaginationType.js
@@ -1,1 +1,125 @@
+// DATA_TEMPLATE: js_data
+oTest.fnStart( "sPaginationType" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"aaData": gaaData
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"Check two button paging is the default",
+		null,
+		function () { return oSettings.sPaginationType == "two_button"; }
+	);
+	
+	oTest.fnTest( 
+		"Check class is applied",
+		null,
+		function () { return $('#example_paginate').hasClass('paging_two_button'); }
+	);
+	
+	oTest.fnTest( 
+		"Two div elements are in the wrapper",
+		null,
+		function () { return $('#example_paginate div').length == 2; }
+	);
+	
+	oTest.fnTest( 
+		"We have the previous button",
+		null,
+		function () { return document.getElementById('example_previous'); }
+	);
+	
+	oTest.fnTest( 
+		"We have the next button",
+		null,
+		function () { return document.getElementById('example_next'); }
+	);
+	
+	oTest.fnTest( 
+		"Previous button is disabled",
+		null,
+		function () { return $('#example_previous').hasClass('paginate_disabled_previous'); }
+	);
+	
+	oTest.fnTest( 
+		"Next button is enabled",
+		null,
+		function () { return $('#example_next').hasClass('paginate_enabled_next'); }
+	);
+	
+	/* Don't test paging - that's done by the zero config test script. */
+	
+	
+	/* Two buttons paging */
+	oTest.fnTest( 
+		"Can enabled full numbers paging",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"aaData": gaaData,
+				"sPaginationType": "full_numbers"
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.sPaginationType == "full_numbers"; }
+	);
+	
+	oTest.fnTest( 
+		"Check full numbers class is applied",
+		null,
+		function () { return $('#example_paginate').hasClass('paging_full_numbers'); }
+	);
+	
+	
+	var nFirst, nPrevious, nNext, nLast;
+	oTest.fnTest( 
+		"Jump to last page",
+		function () {
+			nFirst = $('div.dataTables_paginate span.first');
+			nPrevious = $('div.dataTables_paginate span.previous');
+			nNext = $('div.dataTables_paginate span.next');
+			nLast = $('div.dataTables_paginate span.last');
+			nLast.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 51 to 57 of 57 entries";
+		}
+	);
+	
+	oTest.fnTest( 
+		"Go to two pages previous",
+		function () {
+			nPrevious.click();
+			nPrevious.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 31 to 40 of 57 entries";
+		}
+	);
+	
+	oTest.fnTest( 
+		"Next (second last) page",
+		function () {
+			nNext.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 41 to 50 of 57 entries";
+		}
+	);
+	
+	oTest.fnTest( 
+		"Jump to first page",
+		function () {
+			nFirst.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries";
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/_zero_config.js
@@ -1,1 +1,440 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "Sanity checks for DataTables with data from JS" );
 
+oTest.fnTest( 
+	"jQuery.dataTable function",
+	null,
+	function () { return typeof jQuery().dataTable == "function"; }
+);
+
+oTest.fnTest(
+	"jQuery.dataTableSettings storage array",
+	null,
+	function () { return typeof jQuery().dataTableSettings == "object"; }
+);
+
+oTest.fnTest(
+	"jQuery.dataTableExt plugin object",
+	null,
+	function () { return typeof jQuery().dataTableExt == "object"; }
+);
+
+$(document).ready( function () {
+	var oInit = {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	};
+	$('#example').dataTable( oInit );
+	
+	/* Basic checks */
+	oTest.fnWaitTest( 
+		"Length changing div exists",
+		null,
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Filtering div exists",
+		null,
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Information div exists",
+		null,
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Pagination div exists",
+		null,
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	oTest.fnTest( 
+		"Processing div is off by default",
+		null,
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"10 rows shown on the first page",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Initial sort occured",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	/* Need to use the WaitTest for sorting due to the setTimeout datatables uses */
+	oTest.fnTest( 
+		"Sorting (first click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (second click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (third click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (first click) on numeric column",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "-"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting (second click) on numeric column",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column (first click)",
+		function () { 
+			$('#example thead th:eq(0)').click();
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () { var b = 
+			$('#example tbody td:eq(0)').html() == "Gecko" && 
+			$('#example tbody td:eq(1)').html() == "Camino 1.0"; return b; }
+	);
+	
+	oTest.fnTest( 
+		"Sorting multi-column - sorting second column only",
+		function () { 
+			$('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	/* Basic paging */
+	oTest.fnTest( 
+		"Paging to second page",
+		function () { $('#example_next').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "IE Mobile"; }
+	);
+	
+	oTest.fnTest( 
+		"Paging to first page",
+		function () { $('#example_previous').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnTest( 
+		"Attempting to page back beyond the first page",
+		function () { $('#example_previous').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	/* Changing length */
+	oTest.fnTest( 
+		"Changing table length to 25 records",
+		function () { $("select[name=example_length]").val('25').change(); },
+		function () { return $('#example tbody tr').length == 25; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 50 records",
+		function () { $("select[name=example_length]").val('50').change(); },
+		function () { return $('#example tbody tr').length == 50; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 100 records",
+		function () { $("select[name=example_length]").val('100').change(); },
+		function () { return $('#example tbody tr').length == 57; }
+	);
+	
+	oTest.fnTest( 
+		"Changing table length to 10 records",
+		function () { $("select[name=example_length]").val('10').change(); },
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	/*
+	 * Information element
+	 */
+	oTest.fnTest(
+		"Information on zero config",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 11 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on third page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 21 to 30 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information on last page",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 51 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information back on first page",
+		function () {
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 25 records",
+		function () { $("select[name=example_length]").val('25').change(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 25 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 25 records - second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 26 to 50 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with 100 records - first page",
+		function () {
+			$('#example_previous').click();
+			$("select[name=example_length]").val('100').change();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information back to 10 records",
+		function () {
+			$('#example_previous').click();
+			$("select[name=example_length]").val('10').change();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' last page",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 31 to 31 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' back to first page",
+		function () {
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page - second time",
+		function () {
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter increased to 'Win 98'",
+		function () { $('#example_filter input').val("Win 98").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 9 of 9 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter decreased to 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter 'Win' second page - third time",
+		function () {
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Information with filter removed",
+		function () { $('#example_filter input').val("").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	/*
+	 * Filtering
+	 */
+	oTest.fnWaitTest(
+		"Filter 'W' - rows",
+		function () { 
+			/* Reset the table such that the old sorting doesn't mess things up */
+			oSession.fnRestore();
+			$('#example').dataTable( oInit );
+			$('#example_filter input').val("W").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'W' - info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 42 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Wi'",
+		function () { $('#example_filter input').val("Wi").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 32 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "AOL browser (AOL desktop)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1 info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting column 1 reverse",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - maintaing reverse sorting col 1",
+		function () { $('#example_filter input').val("Win XP").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Internet Explorer 7"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - sorting col 3",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win XP' - sorting col 3 - reversed",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "7"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'Win' - sorting col 3 - reversed info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 6 of 6 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'nothinghere'",
+		function () { $('#example_filter input').val("nothinghere").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 
+			"No matching records found"; }
+	);
+	
+	oTest.fnTest(
+		"Filter 'nothinghere' - info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 0 to 0 of 0 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Filter back to blank and 1st column sorting",
+		function () {
+			$('#example_filter input').val("").keyup();
+			$('#example thead th:eq(0)').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest(
+		"Prefixing a filter entry",
+		function () {
+			$('#example_filter input').val("Win").keyup();
+			$('#example_filter input').val("GeckoWin").keyup();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 0 to 0 of 0 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest(
+		"Prefixing a filter entry with space",
+		function () {
+			$('#example_filter input').val("Gecko Win").keyup();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 17 entries (filtered from 57 total entries)"; }
+	);
+	
+	
+	
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aaSorting.js
@@ -1,1 +1,198 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aaSorting" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default sorting is single column",
+		null,
+		function () {
+			return oSettings.aaSorting.length == 1 && typeof oSettings.aaSorting[0] == 'object';
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Default sorting is first column asc",
+		null,
+		function () {
+			return oSettings.aaSorting[0].length == 3 && oSettings.aaSorting[0][0] == 0 &&
+				oSettings.aaSorting[0][1] == 'asc';
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting is applied",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Custom sorting on single string column asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Custom sorting on single string column desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Custom sorting on single int column asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "-"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Custom sorting on single int column desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string asc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','asc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string asc / string desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','asc'], ['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string desc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','desc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "iPod Touch / iPhone"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string desc / string desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','desc'], ['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Safari 3.0"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string asc / int asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','asc'], ['3','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string asc / int desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','asc'], ['3','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "1.9"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string desc / int asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','desc'], ['3','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "125.5"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string desc / int desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','desc'], ['3','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (3 column) - string asc / int asc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSorting": [['0','asc'], ['3','asc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(7) td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aaSortingFixed.js
@@ -1,1 +1,67 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aaSortingFixed" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"No fixed sorting by default",
+		null,
+		function () {
+			return oSettings.aaSortingFixed == null;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Fixed sorting on first column (string/asc) with user sorting on second column (string/asc)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSortingFixed": [['0','asc']],
+				"fnInitComplete": function () {
+					$('#example thead th:eq(1)').click();
+				}
+			} );
+			//
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Fixed sorting on first column (string/asc) with user sorting on second column (string/desc)",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Fixed sorting on fourth column (int/asc) with user sorting on second column (string/asc)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aaSortingFixed": [['3','asc']]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Fixed sorting on fourth column (int/asc) with user sorting on second column (string/desc)",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "PSP browser"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.bSearchable.js
@@ -1,1 +1,76 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.bSeachable" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Columns are searchable by default",
+		function () { oTable.fnFilter("Camino"); },
+		function () {
+			if ( $('#example tbody tr:eq(0) td:eq(1)')[0] )
+				return $('#example tbody tr:eq(0) td:eq(1)').html().match(/Camino/);
+			else
+				return null;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Disabling sorting on a column removes it from the global filter",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "bSearchable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("Camino");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Disabled on one column has no effect on other columns",
+		function () { oTable.fnFilter("Webkit"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Webkit"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Disable filtering on multiple columns",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					{ "bSearchable": false },
+					{ "bSearchable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("Webkit");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Filter on second disabled column",
+		function () { oTable.fnFilter("Camino"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.bSortable.js
@@ -1,1 +1,109 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.bSortable" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"All columns are sortable by default",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Can disable sorting from one column",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "bSortable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() != "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Disabled column has no sorting class",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc") == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Other columns can still sort",
+		function () {
+			$('#example thead th:eq(4)').click();
+			$('#example thead th:eq(4)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == "X"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Disable sorting on multiple columns - no sorting classes",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "bSortable": false },
+					null,
+					{ "bSortable": false },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example thead th:eq(1)').hasClass("sorting") ||
+				$('#example thead th:eq(3)').hasClass("sorting")
+			return bReturn == false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting on disabled column 1 has no effect",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() != "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting on disabled column 2 has no effect",
+		function () {
+			$('#example thead th:eq(3)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() != "-"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Second sort on disabled column 2 has no effect",
+		function () {
+			$('#example thead th:eq(3)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() != "-"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Even with multiple disabled sorting columns other columns can still sort",
+		function () {
+			$('#example thead th:eq(4)').click();
+			$('#example thead th:eq(4)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == "X"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.bUseRendered.js
@@ -1,1 +1,148 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.bUseRendered" );
 
+/* bUseRendered is used to alter sorting data, if false then the original data is used for
+ * sorting rather than the rendered data
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var mTmp = 0;
+	
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+		"aoColumns": [
+			null,
+			{ "fnRender": function (a) {
+				if ( mTmp == 0 ) {
+					mTmp++;
+					return "aaa";
+				} else
+					return a.aData[a.iDataColumn];
+			} },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default for bUseRendered is true - rendered data is used for sorting",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'aaa'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"When bUseRendered is false, original data is used for sorting",
+		function () {
+			mTmp = 0;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ 
+						"bUseRendered": false,
+						"fnRender": function (a) {
+							if ( mTmp == 0 ) {
+								mTmp++;
+								return "aaa";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					null,
+					null,
+					null
+				]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"bUseRendered set to false on one columns and true (default) on two others",
+		function () {
+			mTmp = 0;
+			var mTmp2 = 0;
+			var mTmp3 = 0;
+			
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					{
+						"fnRender": function (a) {
+							if ( mTmp == 0 ) {
+								mTmp++;
+								return "aaa1";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					{ 
+						"bUseRendered": false,
+						"fnRender": function (a) {
+							if ( mTmp2 == 0 ) {
+								mTmp2++;
+								return "aaa2";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					{
+						"fnRender": function (a) {
+							if ( mTmp3 == 0 ) {
+								mTmp3++;
+								return "zzz3";
+							} else {
+								return a.aData[a.iDataColumn];
+							}
+						}
+					},
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'aaa1'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column rendering - 2nd column sorting",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column rendering - 3rd column sorting",
+		function () {
+			$('#example thead th:eq(2)').click();
+			$('#example thead th:eq(2)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(2)').html() == 'zzz3'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column rendering - 4th column sorting",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == '-'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column rendering - 5th column sorting",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.bVisible.js
@@ -1,1 +1,124 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.bVisible" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"All columns are visible by default",
+		null,
+		function () { return $('#example tbody tr:eq(0) td').length == 5; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Can hide one column and it removes td column from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "bVisible": false },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 4; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Can hide one column and it removes thead th column from DOM",
+		null,
+		function () { return $('#example thead tr:eq(0) th').length == 4; }
+	);
+	
+	oTest.fnWaitTest( 
+		"The correct thead column has been hidden",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Platform(s)" &&
+				jqNodes[2].innerHTML == "Engine version" &&
+				jqNodes[3].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"The correct tbody column has been hidden",
+		function () {
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } );
+		},
+		function () {
+			var jqNodes = $('#example tbody tr:eq(0) td');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Gecko" &&
+				jqNodes[1].innerHTML == "Gnome" &&
+				jqNodes[2].innerHTML == "1.8" &&
+				jqNodes[3].innerHTML == "A";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Can hide multiple columns and it removes td column from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "bVisible": false },
+					{ "bVisible": false },
+					null,
+					{ "bVisible": false }
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 2; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multiple hide - removes thead th column from DOM",
+		null,
+		function () { return $('#example thead tr:eq(0) th').length == 2; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multiple hide - the correct thead columns have been hidden",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Engine version"
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Multiple hide - the correct tbody columns have been hidden",
+		function () {
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } );
+		},
+		function () {
+			var jqNodes = $('#example tbody tr:eq(0) td');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Gecko" &&
+				jqNodes[1].innerHTML == "1"
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.fnRender.js
@@ -1,1 +1,182 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.fnRender" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var mTmp = 0;
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+		"aoColumns": [
+			null,
+			{ "fnRender": function (a) {
+				mTmp++;
+				return a.aData[a.iDataColumn];
+			} },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Single column - fnRender is called once for each row",
+		null,
+		function () { return mTmp == 57; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Confirm that fnRender passes one argument (an object) with three parameters",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( arguments.length != 1 || typeof a.iDataRow=='undefined' ||
+						 	typeof a.iDataColumn=='undefined' || typeof a.aData=='undefined' )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRender iDataColumn is row number",
+		function () {
+			var iCount = 0;
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( iCount != a.iDataRow )
+						{
+							mTmp = false;
+						}
+						iCount++;
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRender iDataColumn is the column",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( a.iDataColumn != 1 )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRender aData is data array of correct size",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( a.aData.length != 5 )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Passed back data is put into the DOM",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						return 'unittest';
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'unittest'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Passed back data is put into the DOM",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					null,
+					{ "fnRender": function (a) {
+						return 'unittest1';
+					} },
+					{ "fnRender": function (a) {
+						return 'unittest2';
+					} },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example tbody tr:eq(0) td:eq(2)').html() == 'unittest1' &&
+				$('#example tbody tr:eq(0) td:eq(3)').html() == 'unittest2';
+			return bReturn; }
+	);
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.iDataSort.js
@@ -1,1 +1,90 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.iDataSort" );
 
+$(document).ready( function () {
+	/* Should know that sorting already works by default from other tests, so we can jump
+	 * right in here
+	 */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+		"aoColumns": [
+			null,
+			{ "iDataSort": 4 },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Sorting on first column is uneffected",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting on second column is the order of the fifth",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Reserve sorting on second column uses fifth column as well",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'X'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting on 5th column retains it's own sorting",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Use 2nd col for sorting 5th col and via-versa - no effect on first col sorting",
+		function () {
+			mTmp = 0;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "iDataSort": 4 },
+					null,
+					null,
+					{ "iDataSort": 1 }
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"2nd col sorting uses fifth col",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'A'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"2nd col sorting uses fifth col - reversed",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').html() == 'X'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"5th col sorting uses 2nd col",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'All others'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"5th col sorting uses 2nd col - reversed",
+		function () { $('#example thead th:eq(4)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'Seamonkey 1.1'; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.sClass.js
@@ -1,1 +1,115 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.sClass" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"By default the test class hasn't been applied to the column (sanity!)",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(2)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - first row",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					null,
+					{ "sClass": 'unittest' },
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(1) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - third row",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - last row",
+		null,
+		function () { return $('#example tbody tr:eq(9) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - has not applied to other columns - 1st",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(0)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - has not applied to other columns - 5th",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - seventh row - second page",
+		function () { $('#example_next').click(); },
+		function () { return $('#example tbody tr:eq(6) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - has not applied to header",
+		null,
+		function () { return $('#example thead tr:eq(3) th:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - has not applied to footer",
+		null,
+		function () { return $('#example thead tr:eq(3) th:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Class defined for multiple columns - first row",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					{ "sClass": 'unittest2' },
+					null,
+					null,
+					{ "sClass": 'unittest1' },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example tbody tr:eq(3) td:eq(0)').hasClass('unittest2') &&
+				$('#example tbody tr:eq(8) td:eq(3)').hasClass('unittest1');
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Class defined for multiple columns - has not applied to other columns - 5th 1",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').hasClass('unittest1') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Class defined for multiple columns - has not applied to other columns - 5th 2",
+		null,
+		function () { return $('#example tbody tr:eq(6) td:eq(4)').hasClass('unittest2') == false; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.sName.js
@@ -1,1 +1,28 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.sName" );
 
+/* This has no effect at all in DOM methods - so we just check that it has applied the name */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+		"aoColumns": [
+			null,
+			null,
+			null,
+			{ "sName": 'unit test' },
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Names are stored in the columns object",
+		null,
+		function () { return oSettings.aoColumns[3].sName =="unit test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.sTitle.js
@@ -1,1 +1,82 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.sTitle" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"If not given, then the columns titles are empty",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Browser" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Can set a single column title - and others are read from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "sTitle": 'unit test' },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "unit test" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Can set multiple column titles",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					{ "sTitle": 'unit test 1' },
+					null,
+					null,
+					{ "sTitle": 'unit test 2' }
+				]
+			} );
+		},
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "unit test 1" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "unit test 2";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoColumns.sWidth.js
@@ -1,1 +1,87 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.sWidth" );
 
+/* NOTE - we need to disable the auto width for the majority of these test in order to preform 
+ * these tests as the auto width will convert the width to a px value. We can do 'non-exact' tests
+ * with auto width enabled however to ensure it scales columns as required
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+		"bAutoWidth": false,
+		"aoColumns": [
+			null,
+			{ "sWidth": '40%' },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"With auto width disabled the width for one column is appled",
+		null,
+		function () { return $('#example thead th:eq(1)')[0].style.width == "40%"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"With auto width disabled the width for one column is appled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bAutoWidth": false,
+				"aoColumns": [
+					null,
+					null,
+					{ "sWidth": '20%' },
+					{ "sWidth": '30%' },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn =
+				$('#example thead th:eq(2)')[0].style.width == "20%" &&
+				$('#example thead th:eq(3)')[0].style.width == "30%";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"With auto width, it will make the smallest column the largest with percentage width given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoColumns": [
+					null,
+					null,
+					null,
+					{ "sWidth": '40%' },
+					null
+				]
+			} );
+		},
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			
+			if ( a3>a0 && a3>a1 && a3>a2 && a3>a4 )
+				return true;
+			else
+				return false;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/aoSearchCols.js
@@ -1,1 +1,119 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoSearchCols" );
 
+/* We could be here forever testing this one, so we test a limited subset on a couple of colums */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default should be to have a empty colums array",
+		null,
+		function () {
+			var bReturn = 
+				oSettings.aoPreSearchCols[0].sSearch == 0 && !oSettings.aoPreSearchCols[0].bRegex &&
+				oSettings.aoPreSearchCols[1].sSearch == 0 && !oSettings.aoPreSearchCols[1].bRegex &&
+				oSettings.aoPreSearchCols[2].sSearch == 0 && !oSettings.aoPreSearchCols[2].bRegex &&
+				oSettings.aoPreSearchCols[3].sSearch == 0 && !oSettings.aoPreSearchCols[3].bRegex &&
+				oSettings.aoPreSearchCols[4].sSearch == 0 && !oSettings.aoPreSearchCols[4].bRegex;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Search on a single column - no regex statement given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoSearchCols": [
+					null,
+					{ "sSearch": "Mozilla" },
+					null,
+					{ "sSearch": "1" },
+					null
+				]
+			} );
+		},
+		function () { return $('#example_info').html() == "Showing 1 to 9 of 9 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search on two columns - no regex statement given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoSearchCols": [
+					null,
+					{ "sSearch": "Mozilla" },
+					null,
+					{ "sSearch": "1.5" },
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "1.5"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search on single column - escape regex false",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					null,
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example_info').html() == "Showing 1 to 3 of 3 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search on two columns - escape regex false on first, true on second",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					{ "sSearch": "3.3", "bEscapeRegex": true },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Konqureror 3.3"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search on two columns (no records) - escape regex false on first, true on second",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"aoSearchCols": [
+					{ "sSearch": ".*ML", "bEscapeRegex": false },
+					{ "sSearch": "Allan", "bEscapeRegex": true },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/asStripClasses.js
@@ -1,1 +1,105 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "asStripClasses" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Default row striping is applied",
+		null,
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('odd') &&
+			       $('#example tbody tr:eq(1)').hasClass('even') &&
+			       $('#example tbody tr:eq(2)').hasClass('odd') &&
+			       $('#example tbody tr:eq(3)').hasClass('even');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Row striping on the second page",
+		function () { $('#example_next').click(); },
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('odd') &&
+			       $('#example tbody tr:eq(1)').hasClass('even') &&
+			       $('#example tbody tr:eq(2)').hasClass('odd') &&
+			       $('#example tbody tr:eq(3)').hasClass('even');
+		}
+	);
+	
+	/* No striping */
+	oTest.fnWaitTest( 
+		"No row striping",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"asStripClasses": []
+			} );
+		},
+		function () {
+			if ( typeof $('#example tbody tr:eq(1)')[0] == 'undefined' )
+			{
+				/* Use the 'wait for' to allow this to become true */
+				return false;
+			}
+			return $('#example tbody tr:eq(0)')[0].className == "" &&
+			       $('#example tbody tr:eq(1)')[0].className == "" &&
+			       $('#example tbody tr:eq(2)')[0].className == "" &&
+			       $('#example tbody tr:eq(3)')[0].className == "";
+		}
+	);
+	
+	/* Custom striping */
+	oTest.fnWaitTest( 
+		"Custom striping [2]",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"asStripClasses": [ 'test1', 'test2' ]
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test1') &&
+			       $('#example tbody tr:eq(3)').hasClass('test2');
+		}
+	);
+	
+	
+	/* long array of striping */
+	oTest.fnWaitTest( 
+		"Custom striping [4]",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"asStripClasses": [ 'test1', 'test2', 'test3', 'test4' ]
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test3') &&
+			       $('#example tbody tr:eq(3)').hasClass('test4');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Custom striping is restarted on second page [2]",
+		function () { $('#example_next').click(); },
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test3') &&
+			       $('#example tbody tr:eq(3)').hasClass('test4');
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bAutoWidth.js
@@ -1,1 +1,142 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bAutoWidth" );
 
+/* It's actually a little tricky to test this. We can't test absolute numbers because
+ * different browsers and different platforms will render the width of the columns slightly
+ * differently. However, we certainly can test the principle of what should happen (column 
+ * width doesn't change over pages)
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Auto width is enabled by default",
+		null,
+		function () { return oSettings.oFeatures.bAutoWidth; }
+	);
+	
+	oTest.fnWaitTest( 
+		"First column has a width assigned to it",
+		null,
+		function () { return $('#example thead th:eq(0)').attr('style').match(/width/i); }
+	);
+	
+	/*
+	This would seem like a better test - but there appear to be difficulties with tables
+	which are bigger (calculated) than there is actually room for. I suspect this is actually
+	a bug in datatables
+	oTest.fnWaitTest( 
+		"Check column widths on first page match second page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			console.log( a0, b0, a1, b1, a2, b2, a3, b3 );
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return true;
+			else
+				return false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check column widths on second page match thid page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return true;
+			else
+				return false;
+		}
+	);
+	*/
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Auto width can be disabled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bAutoWidth": false
+			} );
+	 		oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bAutoWidth == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"First column does not have a width assigned to it",
+		null,
+		function () { return $('#example thead th:eq(0)').attr('style') == null; }
+	);
+	
+	/*
+	oTest.fnWaitTest( 
+		"Check column widths on first page do not match second page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return false;
+			else
+				return true;
+		}
+	);
+	*/
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Auto width enabled override",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bAutoWidth": true
+			} );
+	 		oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bAutoWidth; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bFilter.js
@@ -1,1 +1,44 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bFilter" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Filtering div exists by default",
+		null,
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Fltering can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bFilter": false
+			} );
+		},
+		function () { return document.getElementById('example_filter') == null; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Filtering enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bFilter": true
+			} );
+		},
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bInfo.js
@@ -1,1 +1,44 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bInfo" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Info div exists by default",
+		null,
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Info can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bInfo": false
+			} );
+		},
+		function () { return document.getElementById('example_info') == null; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Info enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bInfo": true
+			} );
+		},
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bLengthChange.js
@@ -1,1 +1,75 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bLengthChange" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Length div exists by default",
+		null,
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	oTest.fnWaitTest(
+		"Four default options",
+		null,
+		function () { return $("select[name=example_length] option").length == 4; }
+	);
+	
+	oTest.fnWaitTest(
+		"Default options",
+		null,
+		function () {
+			var opts = $("select[name='example_length'] option");
+			return opts[0].getAttribute('value') == 10 && opts[1].getAttribute('value') == 25 &&
+				opts[2].getAttribute('value') == 50 && opts[3].getAttribute('value') == 100;
+		}
+	);
+	
+	oTest.fnWaitTest(
+		"Info takes length into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Change length can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bLengthChange": false
+			} );
+		},
+		function () { return document.getElementById('example_length') == null; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information takes length disabled into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Length change enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bLengthChange": true
+			} );
+		},
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bPaginate.js
@@ -1,1 +1,59 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bPaginate" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Pagiantion div exists by default",
+		null,
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information div takes paging into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Pagiantion can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bPaginate": false
+			} );
+		},
+		function () { return document.getElementById('example_paginate') == null; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information div takes paging disabled into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 57 of 57 entries"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Pagiantion enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bPaginate": true
+			} );
+		},
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bProcessing.js
@@ -1,1 +1,103 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bProcessing" );
 
+/* It's actually a bit hard to set this one due to the fact that it will only be shown
+ * when DataTables is doing some kind of processing. The server-side processing is a bit
+ * better to test this than here - so we just the interal functions to enable it and check
+ * that it is available
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Processing is off by default",
+		null,
+		function () { return oSettings.oFeatures.bProcessing == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is not in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div cannot be shown",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div cannot be hidden",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, false ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Processing can be enabled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bProcessing": true
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bProcessing == true; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is hidden by default",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing').style.visibility = "hidden"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div can be shown",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing').style.visibility = "visible"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div can be hidden",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, false ); },
+		function () { return document.getElementById('example_processing').style.visibility = "hidden"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Processing disabled override",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bProcessing": false
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bProcessing == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is not in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bServerSide.js
@@ -1,1 +1,20 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bServerSide" );
 
+/* Not interested in server-side processing here other than to check that it is off */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Server side is off by default",
+		null,
+		function () { return oSettings.oFeatures.bServerSide == false; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bSort.js
@@ -1,1 +1,99 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bSort" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Sorting is on by default",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting Asc by default class applied",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass("sorting_asc"); }
+	);
+	
+	oTest.fnWaitTest(
+		"Click on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting class removed from first column",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass("sorting_asc") != true; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting asc class applied to second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc"); }
+	);
+	
+	oTest.fnWaitTest(
+		"Reverse on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting acs class removed from second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc") != true; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting desc class applied to second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_desc"); }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Pagiantion can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bSort": false
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Click on second column has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Reverse on second column has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Sorting enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bSort": true
+			} );
+		},
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/bSortClasses.js
@@ -1,1 +1,132 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bSortClasses" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Sorting classes are applied by default",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting classes are applied to all required cells",
+		null,
+		function () { return $('#example tbody tr:eq(7) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting classes are not applied to non-sorting columns",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_1') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting multi-column - add column 1",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting multi-column - add column 2",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(2)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting multi-column - add column 3",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(3)')[0], { 'shift': true } );
+		},
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') &&
+						 $('#example tbody tr:eq(0) td:eq(3)').hasClass('sorting_3');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Remove sorting classes on single column sort",
+		function () { 
+			$('#example thead th:eq(4)').click();
+		},
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') == false &&
+						 $('#example tbody tr:eq(0) td:eq(3)').hasClass('sorting_3') == false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting class 1 was added",
+		null,
+		function () { return $('#example tbody tr:eq(1) td:eq(4)').hasClass('sorting_1'); }
+	);
+	
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Sorting classes can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bSortClasses": false
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting classes disabled - add column 1 - no effect",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting classes disabled - add column 2 - no effect",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(2)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') == false;
+		}
+	);
+	
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Sorting classes enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bSortClasses": true
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/fnDrawCallback.js
@@ -1,1 +1,98 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnDrawCallback" );
 
+/* Fairly boring function compared to the others! */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass, bInit;
+	
+	oTest.fnWaitTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnDrawCallback == null; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"One argument passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			bInit = false;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnDrawCallback": function ( ) {
+					mPass = arguments.length;
+				},
+				"fnInitComplete": function () {
+					bInit = true;
+				}
+			} );
+		},
+		function () { return mPass == 1 && bInit; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"That one argument is the settings object",
+		function () {
+			oSession.fnRestore();
+			
+			bInit = false;
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnDrawCallback": function ( oSettings ) {
+					mPass = oSettings;
+				},
+				"fnInitComplete": function () {
+					bInit = true;
+				}
+			} );
+		},
+		function () { return oTable.fnSettings() == mPass && bInit; }
+	);
+	
+	
+	/* The draw callback is called once for the init and then when the data is added */
+	oTest.fnWaitTest( 
+		"fnRowCallback called once on first draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			bInit = false;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnDrawCallback": function ( ) {
+					mPass++;
+				},
+				"fnInitComplete": function () {
+					bInit = true;
+				}
+			} );
+		},
+		function () { return mPass == 2 && bInit; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback called once on each draw there after as well",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return mPass == 5; }
+	);
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/fnHeaderCallback.js
@@ -1,1 +1,191 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnHeaderCallback" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass, bInit;
+	
+	oTest.fnWaitTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnHeaderCallback == null; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Five arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			bInit = false;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnHeaderCallback": function ( ) {
+					mPass = arguments.length;
+				},
+				"fnInitComplete": function () {
+					bInit = true;
+				}
+			} );
+		},
+		function () { return mPass == 5 && bInit; }
+	);
+	
+	
+	/* The header callback is called once for the init and then when the data is added */
+	oTest.fnWaitTest( 
+		"fnHeaderCallback called once per draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			bInit = false;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					mPass++;
+				},
+				"fnInitComplete": function () {
+					bInit = true;
+				}
+			} );
+		},
+		function () { return mPass == 2 && bInit; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback called on paging (i.e. another draw)",
+		function () { $('#example_next').click(); },
+		function () { return mPass == 3; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+				}
+			} );
+		},
+		function () { return $('#example thead th:eq(0)').html() == "Displaying 10 records"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"iStart correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart != 0 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"iStart correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart == 10 )
+					{
+						mPass = true;
+					}
+				},
+				"fnInitComplete": function () {
+					$('#example_next').click();
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"iEnd correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd == 20 )
+					{
+						mPass = true;
+					}
+				},
+				"fnInitComplete": function () {
+					$('#example_next').click();
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"aiDisplay length is full data when not filtered",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 57 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnWaitTest( 
+		"aiDisplay length is 9 when filtering on 'Mozilla'",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 9 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			oTable.fnFilter( "Mozilla" );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/fnInitComplete.js
@@ -1,1 +1,100 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnInitComplete" );
 
+/* Fairly boring function compared to the others! */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnWaitTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnInitComplete == null; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Two arguments passed (for Ajax!)",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnInitComplete": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 2; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"That one argument is the settings object",
+		function () {
+			oSession.fnRestore();
+			
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnInitComplete": function ( oSettings ) {
+					mPass = oSettings;
+				}
+			} );
+		},
+		function () { return oTable.fnSettings() == mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"fnInitComplete called once on first draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnInitComplete": function ( ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnInitComplete never called there after",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"10 rows in the table on complete",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnInitComplete": function ( ) {
+					mPass = $('#example tbody tr').length;
+				}
+			} );
+		},
+		function () { return mPass == 10; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/fnRowCallback.js
@@ -1,1 +1,112 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnRowCallback" );
 
+/* Note - fnRowCallback MUST return the first arguments (modified or not) */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnWaitTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnRowCallback == null; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Four arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnRowCallback": function ( nTr ) {
+					mPass = arguments.length;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass == 4; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback called once for each drawn row",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					mPass++;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					$(nTr).addClass('unit_test');
+					return nTr;
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(1)').hasClass('unit_test'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Data array has length matching columns",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					if ( asData.length != 5 )
+						mPass = false;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Data array has length matching columns",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			var iCount = 0;
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					if ( iCount != iDrawIndex )
+						mPass = false;
+					iCount++;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/fnServerData.js
@@ -1,1 +1,64 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnServerData for Ajax sourced data" );
 
+$(document).ready( function () {
+	var mPass;
+	
+	oTest.fnTest( 
+		"Argument length",
+		function () {
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnServerData": function () {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 3; }
+	);
+	
+	oTest.fnTest( 
+		"Url",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnServerData": function (sUrl, aoData, fnCallback) {
+					mPass = sUrl == "../../../examples/examples_support/json_source.txt";
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Data array",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnServerData": function (sUrl, aoData, fnCallback) {
+					mPass = aoData.length==0;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnTest( 
+		"Callback function",
+		function () {
+			$('#example').dataTable( {
+				"bDestroy": true,
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"fnServerData": function (sUrl, aoData, fnCallback) {
+					mPass = typeof fnCallback == 'function';
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/iDisplayLength.js
@@ -1,1 +1,81 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "iDisplayLength" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Default length is ten",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Select menu shows 10",
+		null,
+		function () { return $('#example_length select').val() == 10; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Set initial length to 25",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"iDisplayLength": 25
+			} );
+		},
+		function () { return $('#example tbody tr').length == 25; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Select menu shows 25",
+		null,
+		function () { return $('#example_length select').val() == 25; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Set initial length to 100",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"iDisplayLength": 100
+			} );
+		},
+		function () { return $('#example tbody tr').length == 57; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Select menu shows 25",
+		null,
+		function () { return $('#example_length select').val() == 100; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Set initial length to 23 (unknown select menu length)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"iDisplayLength": 23
+			} );
+		},
+		function () { return $('#example tbody tr').length == 23; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Select menu shows 10 (since 23 is unknow)",
+		null,
+		function () { return $('#example_length select').val() == 10; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.oPaginate.js
@@ -1,1 +1,84 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.oPaginate" );
 
+/* Note that the paging language information only has relevence in full numbers */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+		"sPaginationType": "full_numbers"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"oLanguage.oPaginate defaults",
+		null,
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.oPaginate.sFirst == "First" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "Previous" &&
+				oSettings.oLanguage.oPaginate.sNext == "Next" &&
+				oSettings.oLanguage.oPaginate.sLast == "Last";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate defaults are in the DOM",
+		null,
+		function () {
+			var bReturn = 
+				$('#example_paginate .first').html() == "First" &&
+				$('#example_paginate .previous').html() == "Previous" &&
+				$('#example_paginate .next').html() == "Next" &&
+				$('#example_paginate .last').html() == "Last";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"oLanguage.oPaginate can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"sPaginationType": "full_numbers",
+				"oLanguage": {
+					"oPaginate": {
+						"sFirst":    "unit1",
+						"sPrevious": "test2",
+						"sNext":     "unit3",
+						"sLast":     "test4"
+					}
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.oPaginate.sFirst == "unit1" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "test2" &&
+				oSettings.oLanguage.oPaginate.sNext == "unit3" &&
+				oSettings.oLanguage.oPaginate.sLast == "test4";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate definitions are in the DOM",
+		null,
+		function () {
+			var bReturn = 
+				$('#example_paginate .first').html() == "unit1" &&
+				$('#example_paginate .previous').html() == "test2" &&
+				$('#example_paginate .next').html() == "unit3" &&
+				$('#example_paginate .last').html() == "test4";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.sInfo.js
@@ -1,1 +1,117 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sInfo" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Info language is 'Showing _START_ to _END_ of _TOTAL_ entries' by default",
+		null,
+		function () { return oSettings.oLanguage.sInfo == "Showing _START_ to _END_ of _TOTAL_ entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - without any macros",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfo": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sInfo == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "unit test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macro _START_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfo": "unit _START_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macro _END_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfo": "unit _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 10 test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macro _TOTAL_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfo": "unit _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 57 test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macros _START_ and _END_",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfo": "unit _START_ _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 10 test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macros _START_, _END_ and _TOTAL_",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfo": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 10 57 test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.sInfoEmpty.js
@@ -1,1 +1,79 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sInfoEmpty" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Info empty language is 'Showing 0 to 0 of 0 entries' by default",
+		function () { oTable.fnFilter("nothinghere"); },
+		function () { return oSettings.oLanguage.sInfoEmpty == "Showing 0 to 0 of 0 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"Showing 0 to 0 of 0 entries";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Info empty language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfoEmpty": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("nothinghere");
+		},
+		function () { return oSettings.oLanguage.sInfoEmpty == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"unit test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Macro's not replaced",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfoEmpty": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+			oTable.fnFilter("nothinghere");
+		},
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"unit _START_ _END_ _TOTAL_ test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.sInfoPostFix.js
@@ -1,1 +1,78 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sInfoPostFix" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Info post fix language is '' (blank) by default",
+		null,
+		function () { return oSettings.oLanguage.sInfoPostFix == ""; }
+	);
+	
+	oTest.fnTest( 
+		"Width no post fix, the basic info shows",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Info post fix language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfoPostFix": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sInfoPostFix == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries unit test"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Macros have no effect in the post fix",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfoPostFix": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries unit _START_ _END_ _TOTAL_ test"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Post fix is applied after fintering info",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sInfoPostFix": "unit test"
+				}
+			} );
+			oTable.fnFilter("nothinghere");
+		},
+		function () { return document.getElementById('example_info').innerHTML = "Showing 0 to 0 of 0 entries unit (filtered from 57 total entries) test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.sLengthMenu.js
@@ -1,1 +1,106 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sLengthMenu" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Menu language is 'Show _MENU_ entries' by default",
+		null,
+		function () { return oSettings.oLanguage.sLengthMenu == "Show _MENU_ entries"; }
+	);
+	
+	oTest.fnTest(
+		"_MENU_ macro is replaced by select menu in DOM",
+		null,
+		function () { return $('select', oSettings.aanFeatures.l[0]).length == 1 }
+	);
+	
+	oTest.fnTest(
+		"Default is put into DOM",
+		null,
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren[0].nodeValue == "Show " &&
+				anChildren[2].nodeValue == " entries";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Menu length language can be defined - no _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sLengthMenu": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sLengthMenu == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Menu length language definition is in the DOM",
+		null,
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			return anChildren[0].nodeValue == "unit test";
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Menu length language can be defined - with _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sLengthMenu": "unit _MENU_ test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren[0].nodeValue == "unit " &&
+				anChildren[2].nodeValue == " test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Only the _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sLengthMenu": "_MENU_"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren.length == 1 &&
+				$('select', oSettings.aanFeatures.l[0]).length == 1;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.sProcessing.js
@@ -1,1 +1,49 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sProcessing" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+		"bProcessing": true
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Processing language is 'Processing...' by default",
+		null,
+		function () { return oSettings.oLanguage.sProcessing == "Processing..."; }
+	);
+	
+	oTest.fnTest( 
+		"Processing language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_processing').innerHTML = "Processing..."; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Processing language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"bProcessing": true,
+				"oLanguage": {
+					"sProcessing": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sProcessing == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Processing language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_processing').innerHTML = "unit test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.sSearch.js
@@ -1,1 +1,65 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sSearch" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Search language is 'Search:' by default",
+		null,
+		function () { return oSettings.oLanguage.sSearch == "Search:"; }
+	);
+	
+	oTest.fnTest( 
+		"Search language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_filter').childNodes[0].nodeValue
+		 	== "Search: "; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Search language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sSearch": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sSearch == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_filter').childNodes[0].nodeValue
+		 	== "unit test "; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Blank search has a no space (separator) inserted",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sSearch": ""
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return document.getElementById('example_filter').childNodes.length == 1; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.sUrl.js
@@ -1,1 +1,62 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sUrl" );
 
+/* Note that we only test the internal storage of language information pulled form a file here
+ * as the other language tests will check it goes into the DOM correctly
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"sUrl is blank by default",
+		null,
+		function () { return oSettings.oLanguage.sUrl == ""; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Loading of German file loads language information",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sUrl": "../../../examples/examples_support/de_DE.txt"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.sProcessing == "Bitte warten..." &&
+				oSettings.oLanguage.sLengthMenu == "_MENU_ Einträge anzeigen" &&
+				oSettings.oLanguage.sZeroRecords == "Keine Einträge vorhanden." &&
+				oSettings.oLanguage.sInfo == "_START_ bis _END_ von _TOTAL_ Einträgen" &&
+				oSettings.oLanguage.sInfoEmpty == "0 bis 0 von 0 Einträgen" &&
+				oSettings.oLanguage.sInfoFiltered == "(gefiltert von _MAX_  Einträgen)" &&
+				oSettings.oLanguage.sInfoPostFix == "" &&
+				oSettings.oLanguage.sSearch == "Suchen" &&
+				oSettings.oLanguage.oPaginate.sFirst == "Erster" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "Zurück" &&
+				oSettings.oLanguage.oPaginate.sNext == "Nächster" &&
+				oSettings.oLanguage.oPaginate.sLast == "Letzter";
+				
+			return bReturn;
+		}
+	);
+	
+	/* One DOM check just to ensure that they go into the DOM */
+	oTest.fnTest(
+		"Loaded language goes into the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "1 bis 10 von 57 Einträgen"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oLanguage.sZeroRecords.js
@@ -1,1 +1,48 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sZeroRecords" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Zero records language is 'No matching records found' by default",
+		null,
+		function () { return oSettings.oLanguage.sZeroRecords == "No matching records found"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Text is shown when empty table (after filtering)",
+		function () { oTable.fnFilter('nothinghere'); },
+		function () { return $('#example tbody tr td')[0].innerHTML == "No matching records found" }
+	);
+	
+	
+	
+	oTest.fnWaitTest( 
+		"Zero records language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oLanguage": {
+					"sZeroRecords": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sZeroRecords == "unit test"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Text is shown when empty table (after filtering)",
+		function () { oTable.fnFilter('nothinghere2'); },
+		function () { return $('#example tbody tr td')[0].innerHTML == "unit test" }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/oSearch.js
@@ -1,1 +1,108 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oSearch" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default values should be blank",
+		null,
+		function () {
+			var bReturn = oSettings.oPreviousSearch.sSearch == "" && 
+			              !oSettings.oPreviousSearch.bRegex;
+			return bReturn;
+		}
+	);
+	
+	/* This test might be considered iffy since the full object isn't given, but it's reasonable to
+	 * expect DataTables to cope with this. It should just assumine regex false
+	 */
+	oTest.fnWaitTest( 
+		"Search term only in object",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oSearch": {
+					"sSearch": "Mozilla"
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"New search will kill old one",
+		function () {
+			oTable.fnFilter("Opera");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Presto"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search plain text term and escape regex true",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oSearch": {
+					"sSearch": "DS",
+					"bRegex": false
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Nintendo DS browser"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search plain text term and escape regex false",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oSearch": {
+					"sSearch": "Opera",
+					"bRegex": true
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Presto"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search regex text term and escape regex true",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oSearch": {
+					"sSearch": "1.*",
+					"bRegex": false
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search regex text term and escape regex false",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"oSearch": {
+					"sSearch": "1.*",
+					"bRegex": true
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "Gecko"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/sAjaxSource.js
@@ -1,1 +1,22 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "sAjaxSource" );
 
+/* Sanitfy check really - all the other tests blast this */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Server side is off by default",
+		null,
+		function () { 
+			return oSettings.sAjaxSource == "../../../examples/examples_support/json_source.txt";
+		}
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/sDom.js
@@ -1,1 +1,262 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "sDom" );
 
+/* This is going to be brutal on the browser! There is a lot that can be tested here... */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default DOM varaible",
+		null,
+		function () { return oSettings.sDom == "lfrtip"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Default DOM in document",
+		null,
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				nNodes[4] == nInfo &&
+				nNodes[5] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check example 1 in code propagates",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"sDom": '<"wrapper"flipt>'
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.sDom == '<"wrapper"flipt>'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Check example 1 in DOM",
+		null,
+		function () {
+			var jqNodes = $('#demo div, #demo table');
+			var nNodes = [];
+			
+			/* Strip the paging nodes */
+			for ( var i=0, iLen=jqNodes.length ; i<iLen ; i++ )
+			{
+				if ( jqNodes[i].getAttribute('id') != "example_previous" &&
+				     jqNodes[i].getAttribute('id') != "example_next" )
+				{
+					nNodes.push( jqNodes[i] );
+				}
+			}
+			
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			var nCustomWrapper = $('div.wrapper')[0];
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nCustomWrapper &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nLength &&
+				nNodes[4] == nInfo &&
+				nNodes[5] == nPaging &&
+				nNodes[6] == nTable;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check example 2 in DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"sDom": '<lf<t>ip>'
+			} );
+		},
+		function () {
+			var jqNodes = $('#demo div, #demo table');
+			var nNodes = [];
+			var nCustomWrappers = []
+			
+			/* Strip the paging nodes */
+			for ( var i=0, iLen=jqNodes.length ; i<iLen ; i++ )
+			{
+				if ( jqNodes[i].getAttribute('id') != "example_previous" &&
+				     jqNodes[i].getAttribute('id') != "example_next" )
+				{
+					nNodes.push( jqNodes[i] );
+				}
+				
+				/* Only the two custom divs don't have class names */
+				if ( !jqNodes[i].getAttribute('class') )
+				{
+					nCustomWrappers.push( jqNodes[i] );
+				}
+			}
+			
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nCustomWrappers[0] &&
+				nNodes[2] == nLength &&
+				nNodes[3] == nFilter &&
+				nNodes[4] == nCustomWrappers[1] &&
+				nNodes[5] == nTable &&
+				nNodes[6] == nInfo &&
+				nNodes[7] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check no length element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"sDom": 'frtip'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				null == nLength &&
+				nNodes[1] == nFilter &&
+				nNodes[2] == nTable &&
+				nNodes[3] == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check no filter element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"sDom": 'lrtip'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				null == nFilter &&
+				nNodes[2] == nTable &&
+				nNodes[3] == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	/* Note we don't test for no table as this is not supported (and it would be fairly daft! */
+	
+	oTest.fnWaitTest( 
+		"Check no info element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"sDom": 'lfrtp'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				null == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check no paging element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"sDom": 'lfrti'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				nNodes[4] == nInfo &&
+				null == nPaging;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/3_ajax/sPaginationType.js
@@ -1,1 +1,134 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "sPaginationType" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"sAjaxSource": "../../../examples/examples_support/json_source.txt"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Check two button paging is the default",
+		null,
+		function () { return oSettings.sPaginationType == "two_button"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Check class is applied",
+		null,
+		function () { return $('#example_paginate').hasClass('paging_two_button'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Two div elements are in the wrapper",
+		null,
+		function () { return $('#example_paginate div').length == 2; }
+	);
+	
+	oTest.fnWaitTest( 
+		"We have the previous button",
+		null,
+		function () { return document.getElementById('example_previous'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"We have the next button",
+		null,
+		function () { return document.getElementById('example_next'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Previous button is disabled",
+		null,
+		function () { return $('#example_previous').hasClass('paginate_disabled_previous'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Next button is enabled",
+		null,
+		function () { return $('#example_next').hasClass('paginate_enabled_next'); }
+	);
+	
+	/* Don't test paging - that's done by the zero config test script. */
+	
+	
+	/* Two buttons paging */
+	var bComplete = false;
+	oTest.fnWaitTest( 
+		"Can enabled full numbers paging",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"sAjaxSource": "../../../examples/examples_support/json_source.txt",
+				"sPaginationType": "full_numbers",
+				"fnInitComplete": function () {
+					bComplete = true;
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			if ( bComplete )
+				return oSettings.sPaginationType == "full_numbers";
+			else
+				return false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check full numbers class is applied",
+		null,
+		function () { return $('#example_paginate').hasClass('paging_full_numbers'); }
+	);
+	
+	
+	var nFirst, nPrevious, nNext, nLast;
+	oTest.fnWaitTest( 
+		"Jump to last page",
+		function () {
+			nFirst = $('div.dataTables_paginate span.first');
+			nPrevious = $('div.dataTables_paginate span.previous');
+			nNext = $('div.dataTables_paginate span.next');
+			nLast = $('div.dataTables_paginate span.last');
+			nLast.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 51 to 57 of 57 entries";
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Go to two pages previous",
+		function () {
+			nPrevious.click();
+			nPrevious.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 31 to 40 of 57 entries";
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Next (second last) page",
+		function () {
+			nNext.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 41 to 50 of 57 entries";
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Jump to first page",
+		function () {
+			nFirst.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries";
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/-iDraw.js
@@ -1,1 +1,44 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "iDraw - check that iDraw increments for each draw" );
 
+
+$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"After first draw, iDraw is 1",
+		null,
+		function () { return oSettings.iDraw == 1; }
+	);
+	
+	oTest.fnWaitTest( 
+		"After second draw, iDraw is 2",
+		function () { oTable.fnDraw() },
+		function () { return oSettings.iDraw == 2; }
+	);
+	
+	oTest.fnWaitTest( 
+		"After sort",
+		function () { oTable.fnSort([[1,'asc']]) },
+		function () { return oSettings.iDraw == 3; }
+	);
+	
+	oTest.fnWaitTest( 
+		"After filter",
+		function () { oTable.fnFilter('gecko') },
+		function () { return oSettings.iDraw == 4; }
+	);
+	
+	oTest.fnWaitTest( 
+		"After another filter",
+		function () { oTable.fnFilter('gec') },
+		function () { return oSettings.iDraw == 5; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/2440.js
@@ -1,1 +1,32 @@
+// DATA_TEMPLATE: empty_table
+/*
+ * NOTE: There are some differences in this zero config script for server-side
+ * processing compared to the other data sources. The main reason for this is the
+ * difference in how the server-side processing does it's filtering. Also the
+ * sorting state is always reset on each draw.
+ */
+oTest.fnStart( "Info element with display all" );
 
+$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTable.fnSettings()._iDisplayLength = -1;
+	oTable.oApi._fnCalculateEnd( oTable.fnSettings() );
+	oTable.fnDraw();
+	
+	
+	/* Basic checks */
+	oTest.fnWaitTest( 
+		"Check length is correct when -1 length given",
+		null,
+		function () {
+			return document.getElementById('example_info').innerHTML == 
+				"Showing 1 to 57 of 57 entries";
+		}
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/2569.js
@@ -1,1 +1,47 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "Destroy with hidden columns" );
 
+$(document).ready( function () {
+	var mTest;
+	
+	
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+		"aoColumnDefs": [ 
+			{ "bSearchable": false, "bVisible": false, "aTargets": [ 2 ] },
+			{ "bVisible": false, "aTargets": [ 3 ] }
+		],
+		"fnInitComplete": function () {
+			this.fnDestroy();
+		}
+	} );
+	
+	oTest.fnWaitTest( 
+		"Check that the number of columns in table is correct",
+		null,
+		function () { return $('#example tbody tr:eq(0) td').length == 5; }
+	);
+	
+	
+	oTest.fnTest( 
+		"And with scrolling",
+		function () {
+			$('#example').dataTable( {
+				"bServerSide": true,
+				"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sScrollY": 200,
+				"aoColumnDefs": [ 
+					{ "bSearchable": false, "bVisible": false, "aTargets": [ 2 ] },
+					{ "bVisible": false, "aTargets": [ 3 ] }
+				],
+				"fnInitComplete": function () {
+					this.fnDestroy();
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 5; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/2600.js
@@ -1,1 +1,47 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "2600 - Display rewind when changing length" );
 
+$(document).ready( function () {
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Info correct on init",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Page 2",
+		function () { $('#example_next').click(); },
+		function () { return $('#example_info').html() == "Showing 11 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Page 3",
+		function () { $('#example_next').click(); },
+		function () { return $('#example_info').html() == "Showing 21 to 30 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Page 4",
+		function () { $('#example_next').click(); },
+		function () { return $('#example_info').html() == "Showing 31 to 40 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Page 5",
+		function () { $('#example_next').click(); },
+		function () { return $('#example_info').html() == "Showing 41 to 50 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Rewind",
+		function () { $('#example_length select').val('100'); $('#example_length select').change(); },
+		function () { return $('#example_info').html() == "Showing 1 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/_zero_config.js
@@ -1,1 +1,424 @@
+// DATA_TEMPLATE: empty_table
+/*
+ * NOTE: There are some differences in this zero config script for server-side
+ * processing compared to the other data sources. The main reason for this is the
+ * difference in how the server-side processing does it's filtering. Also the
+ * sorting state is always reset on each draw.
+ */
+oTest.fnStart( "Sanity checks for DataTables with data from JS" );
 
+oTest.fnWaitTest( 
+	"jQuery.dataTable function",
+	null,
+	function () { return typeof jQuery().dataTable == "function"; }
+);
+
+oTest.fnWaitTest(
+	"jQuery.dataTableSettings storage array",
+	null,
+	function () { return typeof jQuery().dataTableSettings == "object"; }
+);
+
+oTest.fnWaitTest(
+	"jQuery.dataTableExt plugin object",
+	null,
+	function () { return typeof jQuery().dataTableExt == "object"; }
+);
+
+$(document).ready( function () {
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	/* Basic checks */
+	oTest.fnWaitTest( 
+		"Length changing div exists",
+		null,
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Filtering div exists",
+		null,
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Information div exists",
+		null,
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Pagination div exists",
+		null,
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is off by default",
+		null,
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"10 rows shown on the first page",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Initial sort occured",
+		null,
+		function () { return $('#example tbody td:eq(0)').html() == "Gecko"; }
+	);
+	
+	/* Need to use the WaitTest for sorting due to the setTimeout datatables uses */
+	oTest.fnWaitTest( 
+		"Sorting (first click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting (second click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting (third click) on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting (first click) on numeric column",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "-"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting (second click) on numeric column",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting multi-column (first click)",
+		function () { 
+			$('#example thead th:eq(0)').click();
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () { var b = 
+			$('#example tbody td:eq(0)').html() == "Gecko" && 
+			$('#example tbody td:eq(1)').html() == "Camino 1.0"; return b; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting multi-column - sorting first column only",
+		function () { 
+			$('#example thead th:eq(0)').click(); },
+		function () { var b = 
+			$('#example tbody td:eq(0)').html() == "Gecko" && 
+			$('#example tbody td:eq(1)').html() == "Firefox 1.0"; return b; }
+	);
+	
+	/* Basic paging */
+	oTest.fnWaitTest( 
+		"Paging to second page",
+		function () { $('#example_next').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Mozilla 1.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Paging to first page",
+		function () { $('#example_previous').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Attempting to page back beyond the first page",
+		function () { $('#example_previous').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	/* Changing length */
+	oTest.fnWaitTest( 
+		"Changing table length to 25 records",
+		function () { $("select[name=example_length]").val('25').change(); },
+		function () { return $('#example tbody tr').length == 25; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Changing table length to 50 records",
+		function () { $("select[name=example_length]").val('50').change(); },
+		function () { return $('#example tbody tr').length == 50; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Changing table length to 100 records",
+		function () { $("select[name=example_length]").val('100').change(); },
+		function () { return $('#example tbody tr').length == 57; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Changing table length to 10 records",
+		function () { $("select[name=example_length]").val('10').change(); },
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	/*
+	 * Information element
+	 */
+	oTest.fnWaitTest(
+		"Information on zero config",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information on second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 11 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information on third page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 21 to 30 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information on last page",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 51 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information back on first page",
+		function () {
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with 25 records",
+		function () { $("select[name=example_length]").val('25').change(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 25 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with 25 records - second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == "Showing 26 to 50 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with 100 records - first page",
+		function () {
+			$('#example_previous').click();
+			$("select[name=example_length]").val('100').change();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 57 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information back to 10 records",
+		function () {
+			$('#example_previous').click();
+			$("select[name=example_length]").val('10').change();
+		},
+		function () { return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter 'Win' second page",
+		function () { $('#example_next').click(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter 'Win' last page",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 31 to 31 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter 'Win' back to first page",
+		function () {
+			$('#example_previous').click();
+			$('#example_previous').click();
+			$('#example_previous').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter 'Win' second page - second time",
+		function () {
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter increased to 'Win 98'",
+		function () { $('#example_filter input').val("Win 98").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 9 of 9 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter decreased to 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter 'Win' second page - third time",
+		function () {
+			$('#example_next').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 11 to 20 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information with filter removed",
+		function () { $('#example_filter input').val("").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	/*
+	 * Filtering
+	 */
+	oTest.fnWaitTest(
+		"Filter 'W' - rows",
+		function () {
+			$('#example_filter input').val("W").keyup(); },
+		function () { return $('#example tbody tr:eq(4) td:eq(1)').html() == "Netscape 7.2"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'W' - info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 42 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'Wi'",
+		function () { $('#example_filter input').val("Wi").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 32 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'Win'",
+		function () { $('#example_filter input').val("Win").keyup(); },
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'Win' - sorting column 1",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "AOL browser (AOL desktop)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'Win' - sorting column 1 info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 31 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'Win' - sorting column 1 reverse",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'Win XP' - maintaing reverse sorting col 1",
+		function () { $('#example_filter input').val("Win XP").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Internet Explorer 7"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'Win XP' - sorting col 3",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "6"; }
+	);
+	
+	/* Note the filtering is different from the DOM since the server doesn't do
+	 * "smart filtering" like the client side does
+	 */
+	oTest.fnWaitTest(
+		"Filter 'Win XP' - sorting col 3 - reversed",
+		function () { $('#example thead th:eq(3)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "7"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'Win' - sorting col 3 - reversed info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 2 of 2 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'nothinghere'",
+		function () { $('#example_filter input').val("nothinghere").keyup(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == 
+			"No matching records found"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter 'nothinghere' - info",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 0 to 0 of 0 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Filter back to blank and 1st column sorting",
+		function () {
+			$('#example_filter input').val("").keyup();
+			$('#example thead th:eq(0)').click();
+		},
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aaSorting.js
@@ -1,1 +1,212 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aaSorting" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default sorting is single column",
+		null,
+		function () {
+			return oSettings.aaSorting.length == 1 && typeof oSettings.aaSorting[0] == 'object';
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Default sorting is first column asc",
+		null,
+		function () {
+			return oSettings.aaSorting[0].length == 3 && oSettings.aaSorting[0][0] == 0 &&
+				oSettings.aaSorting[0][1] == 'asc';
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting is applied",
+		null,
+		function () { return $('#example tbody td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Custom sorting on single string column asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Custom sorting on single string column desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Custom sorting on single int column asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "-"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Custom sorting on single int column desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string asc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','asc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string asc / string desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','asc'], ['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string desc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','desc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "iPod Touch / iPhone"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string desc / string desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','desc'], ['1','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Safari 3.0"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string asc / int asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','asc'], ['3','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string asc / int desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','asc'], ['3','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "1.9"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string desc / int asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','desc'], ['3','asc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "125.5"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (2 column) - string desc / int desc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','desc'], ['3','desc']]
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "522.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multi-column sorting (3 column) - string asc / int asc / string asc",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSorting": [['0','asc'], ['3','asc'], ['1','asc']]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(7) td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aaSortingFixed.js
@@ -1,1 +1,67 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aaSortingFixed" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"No fixed sorting by default",
+		null,
+		function () {
+			return oSettings.aaSortingFixed == null;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Fixed sorting on first column (string/asc) with user sorting on second column (string/asc)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSortingFixed": [['0','asc']]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Fixed sorting on first column (string/asc) with user sorting on second column (string/desc)",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Fixed sorting on fourth column (int/asc) with user sorting on second column (string/asc)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aaSortingFixed": [['3','asc']]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Fixed sorting on fourth column (int/asc) with user sorting on second column (string/desc)",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "PSP browser"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.bSearchable.js
@@ -1,1 +1,25 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.bSeachable" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Columns are searchable by default",
+		function () { oTable.fnFilter("Camino"); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Camino 1.0"; }
+	);
+	
+	/* NOT ACTUALLY GOING TO TEST BSEARCHABLE HERE. Reason being is that it requires the server
+	 * side to alter it's processing, and this information about columns is not actually sent to
+	 * the server
+	 */
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.bSortable.js
@@ -1,1 +1,112 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.bSortable" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"All columns are sortable by default",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Can disable sorting from one column",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "bSortable": false },
+					null,
+					null,
+					null
+				]
+			} );
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Disabled column has no sorting class",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc") == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Other columns can still sort",
+		function () {
+			$('#example thead th:eq(4)').click();
+			$('#example thead th:eq(4)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Internet Explorer 4.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Disable sorting on multiple columns - no sorting classes",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "bSortable": false },
+					null,
+					{ "bSortable": false },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example thead th:eq(1)').hasClass("sorting") ||
+				$('#example thead th:eq(3)').hasClass("sorting")
+			return bReturn == false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting on disabled column 1 has no effect",
+		function () {
+			$('#example thead th:eq(1)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting on disabled column 2 has no effect",
+		function () {
+			$('#example thead th:eq(3)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Second sort on disabled column 2 has no effect",
+		function () {
+			$('#example thead th:eq(3)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Even with multiple disabled sorting columns other columns can still sort",
+		function () {
+			$('#example thead th:eq(4)').click();
+			$('#example thead th:eq(4)').click();
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Internet Explorer 4.0"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.bUseRendered.js
@@ -1,1 +1,43 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.bUseRendered" );
 
+/* bUseRendered is used to alter sorting data, if false then the original data is used for
+ * sorting rather than the rendered data
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var mTmp = 0;
+	
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+		"aoColumns": [
+			null,
+			{ "fnRender": function (a) {
+				if ( mTmp == 0 ) {
+					mTmp++;
+					return "aaa";
+				} else
+					return a.aData[a.iDataColumn];
+			} },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default for bUseRendered is true - rendered data is used for sorting",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'aaa'; }
+	);
+	
+	/* Limited to what we can do here as the sorting is done on the server side. So stop here. */
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.bVisible.js
@@ -1,1 +1,123 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.bVisible" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"All columns are visible by default",
+		null,
+		function () { return $('#example tbody tr:eq(0) td').length == 5; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Can hide one column and it removes td column from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "bVisible": false },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 4; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Can hide one column and it removes thead th column from DOM",
+		null,
+		function () { return $('#example thead tr:eq(0) th').length == 4; }
+	);
+	
+	oTest.fnWaitTest( 
+		"The correct thead column has been hidden",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Platform(s)" &&
+				jqNodes[2].innerHTML == "Engine version" &&
+				jqNodes[3].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"The correct tbody column has been hidden",
+		null,
+		function () {
+			var jqNodes = $('#example tbody tr:eq(0) td');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Gecko" &&
+				jqNodes[1].innerHTML == "Win 98+ / OSX.2+" &&
+				jqNodes[2].innerHTML == "1.7" &&
+				jqNodes[3].innerHTML == "A";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Can hide multiple columns and it removes td column from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "bVisible": false },
+					{ "bVisible": false },
+					null,
+					{ "bVisible": false }
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td').length == 2; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multiple hide - removes thead th column from DOM",
+		null,
+		function () { return $('#example thead tr:eq(0) th').length == 2; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Multiple hide - the correct thead columns have been hidden",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Engine version"
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Multiple hide - the correct tbody columns have been hidden",
+		null,
+		function () {
+			var jqNodes = $('#example tbody tr:eq(0) td');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Gecko" &&
+				jqNodes[1].innerHTML == "1.7"
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.fnRender.js
@@ -1,1 +1,189 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.fnRender" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var mTmp = 0;
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+		"aoColumns": [
+			null,
+			{ "fnRender": function (a) {
+				mTmp++;
+				return a.aData[a.iDataColumn];
+			} },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Single column - fnRender is called once for each row",
+		null,
+		function () { return mTmp == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Confirm that fnRender passes one argument (an object) with three parameters",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( arguments.length != 1 || typeof a.iDataRow=='undefined' ||
+						 	typeof a.iDataColumn=='undefined' || typeof a.aData=='undefined' )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRender iDataColumn is row number",
+		function () {
+			var iCount = 0;
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( iCount != a.iDataRow )
+						{
+							mTmp = false;
+						}
+						iCount++;
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRender iDataColumn is the column",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( a.iDataColumn != 1 )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRender aData is data array of correct size",
+		function () {
+			mTmp = true;
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						if ( a.aData.length != 5 )
+						{
+							mTmp = false;
+						}
+						return a.aData[a.iDataColumn];
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return mTmp; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Passed back data is put into the DOM",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "fnRender": function (a) {
+						return 'unittest';
+					} },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == 'unittest'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Passed back data is put into the DOM",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					null,
+					{ "fnRender": function (a) {
+						return 'unittest1';
+					} },
+					{ "fnRender": function (a) {
+						return 'unittest2';
+					} },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example tbody tr:eq(0) td:eq(2)').html() == 'unittest1' &&
+				$('#example tbody tr:eq(0) td:eq(3)').html() == 'unittest2';
+			return bReturn; }
+	);
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.sClass.js
@@ -1,1 +1,118 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.sClass" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"By default the test class hasn't been applied to the column (sanity!)",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(2)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - first row",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					null,
+					{ "sClass": 'unittest' },
+					null,
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(1) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - third row",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - last row",
+		null,
+		function () { return $('#example tbody tr:eq(9) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - has not applied to other columns - 1st",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(0)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - has not applied to other columns - 5th",
+		null,
+		function () { return $('#example tbody tr:eq(3) td:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - seventh row - second page",
+		function () { $('#example_next').click(); },
+		function () { return $('#example tbody tr:eq(6) td:eq(2)').hasClass('unittest'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - has not applied to header",
+		null,
+		function () { return $('#example thead tr:eq(3) th:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Add a class to a single column - has not applied to footer",
+		null,
+		function () { return $('#example thead tr:eq(3) th:eq(4)').hasClass('unittest') == false; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Class defined for multiple columns - first row",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					{ "sClass": 'unittest2' },
+					null,
+					null,
+					{ "sClass": 'unittest1' },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn = 
+				$('#example tbody tr:eq(3) td:eq(0)').hasClass('unittest2') &&
+				$('#example tbody tr:eq(8) td:eq(3)').hasClass('unittest1');
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Class defined for multiple columns - has not applied to other columns - 5th 1",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(4)').hasClass('unittest1') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Class defined for multiple columns - has not applied to other columns - 5th 2",
+		null,
+		function () { return $('#example tbody tr:eq(6) td:eq(4)').hasClass('unittest2') == false; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.sName.js
@@ -1,1 +1,29 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.sName" );
 
+/* This has no effect at all in DOM methods - so we just check that it has applied the name */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+		"aoColumns": [
+			null,
+			null,
+			null,
+			{ "sName": 'unit test' },
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Names are stored in the columns object",
+		null,
+		function () { return oSettings.aoColumns[3].sName =="unit test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.sTitle.js
@@ -1,1 +1,85 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.sTitle" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"If not given, then the columns titles are empty",
+		null,
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "Browser" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Can set a single column title - and others are read from DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "sTitle": 'unit test' },
+					null,
+					null,
+					null
+				]
+			} );
+		},
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "unit test" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "CSS grade";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Can set multiple column titles",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					{ "sTitle": 'unit test 1' },
+					null,
+					null,
+					{ "sTitle": 'unit test 2' }
+				]
+			} );
+		},
+		function () {
+			var jqNodes = $('#example thead tr:eq(0) th');
+			var bReturn = 
+				jqNodes[0].innerHTML == "Rendering engine" &&
+				jqNodes[1].innerHTML == "unit test 1" &&
+				jqNodes[2].innerHTML == "Platform(s)" &&
+				jqNodes[3].innerHTML == "Engine version" &&
+				jqNodes[4].innerHTML == "unit test 2";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoColumns.sWidth.js
@@ -1,1 +1,90 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoColumns.sWidth" );
 
+/* NOTE - we need to disable the auto width for the majority of these test in order to preform 
+ * these tests as the auto width will convert the width to a px value. We can do 'non-exact' tests
+ * with auto width enabled however to ensure it scales columns as required
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+		"bAutoWidth": false,
+		"aoColumns": [
+			null,
+			{ "sWidth": '40%' },
+			null,
+			null,
+			null
+		]
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"With auto width disabled the width for one column is appled",
+		null,
+		function () { return $('#example thead th:eq(1)')[0].style.width == "40%"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"With auto width disabled the width for one column is appled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bAutoWidth": false,
+				"aoColumns": [
+					null,
+					null,
+					{ "sWidth": '20%' },
+					{ "sWidth": '30%' },
+					null
+				]
+			} );
+		},
+		function () {
+			var bReturn =
+				$('#example thead th:eq(2)')[0].style.width == "20%" &&
+				$('#example thead th:eq(3)')[0].style.width == "30%";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"With auto width, it will make the smallest column the largest with percentage width given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"aoColumns": [
+					null,
+					null,
+					null,
+					{ "sWidth": '40%' },
+					null
+				]
+			} );
+		},
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			
+			if ( a3>a0 && a3>a1 && a3>a2 && a3>a4 )
+				return true;
+			else
+				return false;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/aoSearchCols.js
@@ -1,1 +1,70 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "aoSearchCols" );
 
+/* We could be here forever testing this one, so we test a limited subset on a couple of colums */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing_filter_col.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default should be to have a empty colums array",
+		null,
+		function () {
+			var bReturn = 
+				oSettings.aoPreSearchCols[0].sSearch == 0 && !oSettings.aoPreSearchCols[0].bRegex &&
+				oSettings.aoPreSearchCols[1].sSearch == 0 && !oSettings.aoPreSearchCols[1].bRegex &&
+				oSettings.aoPreSearchCols[2].sSearch == 0 && !oSettings.aoPreSearchCols[2].bRegex &&
+				oSettings.aoPreSearchCols[3].sSearch == 0 && !oSettings.aoPreSearchCols[3].bRegex &&
+				oSettings.aoPreSearchCols[4].sSearch == 0 && !oSettings.aoPreSearchCols[4].bRegex;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Search on a single column - no regex statement given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing_filter_col.php",
+				"aoSearchCols": [
+					null,
+					{ "sSearch": "Mozilla" },
+					null,
+					{ "sSearch": "1" },
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search on two columns - no regex statement given",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing_filter_col.php",
+				"aoSearchCols": [
+					null,
+					{ "sSearch": "Mozilla" },
+					null,
+					{ "sSearch": "1.5" },
+					null
+				]
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "1.5"; }
+	);
+	
+	/* No regex escape searches here - would need to be implemented on the server-side */
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/asStripClasses.js
@@ -1,1 +1,109 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "asStripClasses" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Default row striping is applied",
+		null,
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('odd') &&
+			       $('#example tbody tr:eq(1)').hasClass('even') &&
+			       $('#example tbody tr:eq(2)').hasClass('odd') &&
+			       $('#example tbody tr:eq(3)').hasClass('even');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Row striping on the second page",
+		function () { $('#example_next').click(); },
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('odd') &&
+			       $('#example tbody tr:eq(1)').hasClass('even') &&
+			       $('#example tbody tr:eq(2)').hasClass('odd') &&
+			       $('#example tbody tr:eq(3)').hasClass('even');
+		}
+	);
+	
+	/* No striping */
+	oTest.fnWaitTest( 
+		"No row striping",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"asStripClasses": []
+			} );
+		},
+		function () {
+			if ( typeof $('#example tbody tr:eq(1)')[0] == 'undefined' )
+			{
+				/* Use the 'wait for' to allow this to become true */
+				return false;
+			}
+			return $('#example tbody tr:eq(0)')[0].className == "" &&
+			       $('#example tbody tr:eq(1)')[0].className == "" &&
+			       $('#example tbody tr:eq(2)')[0].className == "" &&
+			       $('#example tbody tr:eq(3)')[0].className == "";
+		}
+	);
+	
+	/* Custom striping */
+	oTest.fnWaitTest( 
+		"Custom striping [2]",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"asStripClasses": [ 'test1', 'test2' ]
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test1') &&
+			       $('#example tbody tr:eq(3)').hasClass('test2');
+		}
+	);
+	
+	
+	/* long array of striping */
+	oTest.fnWaitTest( 
+		"Custom striping [4]",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"asStripClasses": [ 'test1', 'test2', 'test3', 'test4' ]
+			} );
+		},
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test3') &&
+			       $('#example tbody tr:eq(3)').hasClass('test4');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Custom striping is restarted on second page [2]",
+		function () { $('#example_next').click(); },
+		function () {
+			return $('#example tbody tr:eq(0)').hasClass('test1') &&
+			       $('#example tbody tr:eq(1)').hasClass('test2') &&
+			       $('#example tbody tr:eq(2)').hasClass('test3') &&
+			       $('#example tbody tr:eq(3)').hasClass('test4');
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bAutoWidth.js
@@ -1,1 +1,145 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bAutoWidth" );
 
+/* It's actually a little tricky to test this. We can't test absolute numbers because
+ * different browsers and different platforms will render the width of the columns slightly
+ * differently. However, we certainly can test the principle of what should happen (column 
+ * width doesn't change over pages)
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Auto width is enabled by default",
+		null,
+		function () { return oSettings.oFeatures.bAutoWidth; }
+	);
+	
+	oTest.fnWaitTest( 
+		"First column has a width assigned to it",
+		null,
+		function () { return $('#example thead th:eq(0)').attr('style').match(/width/i); }
+	);
+	
+	/*
+	This would seem like a better test - but there appear to be difficulties with tables
+	which are bigger (calculated) than there is actually room for. I suspect this is actually
+	a bug in datatables
+	oTest.fnWaitTest( 
+		"Check column widths on first page match second page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			console.log( a0, b0, a1, b1, a2, b2, a3, b3 );
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return true;
+			else
+				return false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check column widths on second page match thid page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return true;
+			else
+				return false;
+		}
+	);
+	*/
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Auto width can be disabled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bAutoWidth": false
+			} );
+	 		oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bAutoWidth == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"First column does not have a width assigned to it",
+		null,
+		function () { return $('#example thead th:eq(0)').attr('style') == null; }
+	);
+	
+	/*
+	oTest.fnWaitTest( 
+		"Check column widths on first page do not match second page",
+		null,
+		function () {
+			var anThs = $('#example thead th');
+			var a0 = anThs[0].offsetWidth;
+			var a1 = anThs[1].offsetWidth;
+			var a2 = anThs[2].offsetWidth;
+			var a3 = anThs[3].offsetWidth;
+			var a4 = anThs[4].offsetWidth;
+			$('#example_next').click();
+			var b0 = anThs[0].offsetWidth;
+			var b1 = anThs[1].offsetWidth;
+			var b2 = anThs[2].offsetWidth;
+			var b3 = anThs[3].offsetWidth;
+			var b4 = anThs[4].offsetWidth;
+			if ( a0==b0 && a1==b1 && a2==b2 && a3==b3 )
+				return false;
+			else
+				return true;
+		}
+	);
+	*/
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Auto width enabled override",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bAutoWidth": true
+			} );
+	 		oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bAutoWidth; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bFilter.js
@@ -1,1 +1,47 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bFilter" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Filtering div exists by default",
+		null,
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Fltering can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bFilter": false
+			} );
+		},
+		function () { return document.getElementById('example_filter') == null; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Filtering enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bFilter": true
+			} );
+		},
+		function () { return document.getElementById('example_filter') != null; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bInfiniteScroll.js
@@ -1,1 +1,165 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bInfiniteScroll" );
 
+
+$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"bScrollInfinite": true,
+		"sScrollY": "200px",
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"10 rows by default",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Info",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes",
+		null,
+		function () { return $('#example tbody>tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes function",
+		null,
+		function () { return $('#example').dataTable().fnGetNodes().length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll on 20px adds 10 rows",
+		function () { $('div.dataTables_scrollBody').scrollTop(20); },
+		function () { return $('#example tbody tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Info after 20px scroll",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after 20px scroll",
+		null,
+		function () { return $('#example tbody>tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes function after 20px scroll",
+		null,
+		function () { return $('#example').dataTable().fnGetNodes().length == 20; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll on 10px more results in the same number of rows",
+		function () { $('div.dataTables_scrollBody').scrollTop(30); },
+		function () { return $('#example tbody tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Info after 10 more px scroll",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 20 of 57 entries"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll to 240px adds another 10 rows",
+		function () { $('div.dataTables_scrollBody').scrollTop(240); },
+		function () { return $('#example tbody tr').length == 30; }
+	);
+	
+	oTest.fnTest( 
+		"Info after 240px scroll",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 30 of 57 entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after 240px scroll",
+		null,
+		function () { return $('#example tbody>tr').length == 30; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes function after 240px scroll",
+		null,
+		function () { return $('#example').dataTable().fnGetNodes().length == 30; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Filtering will drop back to 10 rows",
+		function () { oTable.fnFilter('gec') },
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Info after filtering",
+		null,
+		function () { return $('#example_info').html() == "Showing 1 to 10 of 20 entries (filtered from 57 total entries)"; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after filtering",
+		null,
+		function () { return $('#example tbody>tr').length == 10; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes function after filtering",
+		null,
+		function () { return $('#example').dataTable().fnGetNodes().length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll after filtering adds 10",
+		function () { $('div.dataTables_scrollBody').scrollTop(20); },
+		function () { return $('#example tbody tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after filtering",
+		null,
+		function () { return $('#example tbody>tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes function after filtering",
+		null,
+		function () { return $('#example').dataTable().fnGetNodes().length == 20; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting will drop back to 10 rows",
+		function () { oTable.fnSort([[1,'asc']]) },
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Scroll after sorting adds 10",
+		function () { $('div.dataTables_scrollBody').scrollTop(20); },
+		function () { return $('#example tbody tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes after scrolling",
+		null,
+		function () { return $('#example tbody>tr').length == 20; }
+	);
+	
+	oTest.fnTest( 
+		"Get nodes function after scrolling",
+		null,
+		function () { return $('#example').dataTable().fnGetNodes().length == 20; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bInfo.js
@@ -1,1 +1,47 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bInfo" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Info div exists by default",
+		null,
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Info can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bInfo": false
+			} );
+		},
+		function () { return document.getElementById('example_info') == null; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Info enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bInfo": true
+			} );
+		},
+		function () { return document.getElementById('example_info') != null; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bLengthChange.js
@@ -1,1 +1,78 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bLengthChange" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Length div exists by default",
+		null,
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	oTest.fnWaitTest(
+		"Four default options",
+		null,
+		function () { return $("select[name=example_length] option").length == 4; }
+	);
+	
+	oTest.fnWaitTest(
+		"Default options",
+		null,
+		function () {
+			var opts = $("select[name='example_length'] option");
+			return opts[0].getAttribute('value') == 10 && opts[1].getAttribute('value') == 25 &&
+				opts[2].getAttribute('value') == 50 && opts[3].getAttribute('value') == 100;
+		}
+	);
+	
+	oTest.fnWaitTest(
+		"Info takes length into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Change length can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bLengthChange": false
+			} );
+		},
+		function () { return document.getElementById('example_length') == null; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information takes length disabled into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Length change enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bLengthChange": true
+			} );
+		},
+		function () { return document.getElementById('example_length') != null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bPaginate.js
@@ -1,1 +1,62 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bPaginate" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Pagiantion div exists by default",
+		null,
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information div takes paging into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 10 of 57 entries"; }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Pagiantion can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bPaginate": false
+			} );
+		},
+		function () { return document.getElementById('example_paginate') == null; }
+	);
+	
+	oTest.fnWaitTest(
+		"Information div takes paging disabled into account",
+		null,
+		function () { return document.getElementById('example_info').innerHTML == 
+			"Showing 1 to 57 of 57 entries"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Pagiantion enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bPaginate": true
+			} );
+		},
+		function () { return document.getElementById('example_paginate') != null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bProcessing.js
@@ -1,1 +1,106 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bProcessing" );
 
+/* It's actually a bit hard to set this one due to the fact that it will only be shown
+ * when DataTables is doing some kind of processing. The server-side processing is a bit
+ * better to test this than here - so we just the interal functions to enable it and check
+ * that it is available
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Processing is off by default",
+		null,
+		function () { return oSettings.oFeatures.bProcessing == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is not in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div cannot be shown",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div cannot be hidden",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, false ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Processing can be enabled",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bProcessing": true
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bProcessing == true; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is hidden by default",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing').style.visibility = "hidden"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div can be shown",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing').style.visibility = "visible"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div can be hidden",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, false ); },
+		function () { return document.getElementById('example_processing').style.visibility = "hidden"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Processing disabled override",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bProcessing": false
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oFeatures.bProcessing == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Processing div is not in the DOM",
+		function () { oTable.oApi._fnProcessingDisplay( oSettings, true ); },
+		function () { return document.getElementById('example_processing') == null; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bServerSide.js
@@ -1,1 +1,21 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bServerSide" );
 
+/* All the other scripts blast the ssp processing */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Server side can be set to on",
+		null,
+		function () { return oSettings.oFeatures.bServerSide == true; }
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bSort.js
@@ -1,1 +1,102 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bSort" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Sorting is on by default",
+		null,
+		function () { return $('#example tbody td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting Asc by default class applied",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass("sorting_asc"); }
+	);
+	
+	oTest.fnWaitTest(
+		"Click on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "All others"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting class removed from first column",
+		null,
+		function () { return $('#example thead th:eq(0)').hasClass("sorting_asc") != true; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting asc class applied to second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc"); }
+	);
+	
+	oTest.fnWaitTest(
+		"Reverse on second column",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(1)').html() == "Seamonkey 1.1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting acs class removed from second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_asc") != true; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting desc class applied to second column",
+		null,
+		function () { return $('#example thead th:eq(1)').hasClass("sorting_desc"); }
+	);
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Pagiantion can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bSort": false
+			} );
+		},
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Click on second column has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Reverse on second column has no effect",
+		function () { $('#example thead th:eq(1)').click(); },
+		function () { return $('#example tbody td:eq(3)').html() == "4"; }
+	);
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Sorting enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bSort": true
+			} );
+		},
+		function () { return $('#example tbody td:eq(1)').html() == "Firefox 1.0"; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/bSortClasses.js
@@ -1,1 +1,135 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "bSortClasses" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Sorting classes are applied by default",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting classes are applied to all required cells",
+		null,
+		function () { return $('#example tbody tr:eq(7) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting classes are not applied to non-sorting columns",
+		null,
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_1') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting multi-column - add column 1",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting multi-column - add column 2",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(2)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting multi-column - add column 3",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(3)')[0], { 'shift': true } );
+		},
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') &&
+						 $('#example tbody tr:eq(0) td:eq(3)').hasClass('sorting_3');
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Remove sorting classes on single column sort",
+		function () { 
+			$('#example thead th:eq(4)').click();
+		},
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') == false &&
+						 $('#example tbody tr:eq(0) td:eq(3)').hasClass('sorting_3') == false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting class 1 was added",
+		null,
+		function () { return $('#example tbody tr:eq(1) td:eq(4)').hasClass('sorting_1'); }
+	);
+	
+	
+	/* Check can disable */
+	oTest.fnWaitTest( 
+		"Sorting classes can be disabled",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bSortClasses": false
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting classes disabled - add column 1 - no effect",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(1)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Sorting classes disabled - add column 2 - no effect",
+		function () { 
+			oDispacher.click( $('#example thead th:eq(2)')[0], { 'shift': true } ); },
+		function () {
+			return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1') == false &&
+						 $('#example tbody tr:eq(0) td:eq(1)').hasClass('sorting_2') == false &&
+						 $('#example tbody tr:eq(0) td:eq(2)').hasClass('sorting_3') == false;
+		}
+	);
+	
+	
+	/* Enable makes no difference */
+	oTest.fnWaitTest( 
+		"Sorting classes enabled override",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bSortClasses": true
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').hasClass('sorting_1'); }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/fnDrawCallback.js
@@ -1,1 +1,89 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnDrawCallback" );
 
+/* Fairly boring function compared to the others! */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnWaitTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnDrawCallback == null; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"One argument passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnDrawCallback": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"That one argument is the settings object",
+		function () {
+			oSession.fnRestore();
+			
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnDrawCallback": function ( oSettings ) {
+					mPass = oSettings;
+				}
+			} );
+		},
+		function () { return oTable.fnSettings() == mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback called once on first draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnDrawCallback": function ( ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback called once on each draw there after as well",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return mPass > 1; }
+	);
+	
+	
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/fnHeaderCallback.js
@@ -1,1 +1,191 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnHeaderCallback" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnWaitTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnHeaderCallback == null; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Five arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnHeaderCallback": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 5; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback called once per draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback called on paging (i.e. another draw)",
+		function () { $('#example_next').click(); },
+		function () { return mPass == 2; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+				}
+			} );
+		},
+		function () { return $('#example thead th:eq(0)').html() == "Displaying 10 records"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"iStart correct on first page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart != 0 )
+					{
+						mPass = false;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"iStart correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iStart == 0 )
+					{
+						mPass = true;
+					}
+				},
+				"fnInitComplete": function () {
+					$('#example_next').click();
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"iEnd correct on second page",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( iEnd == 10 )
+					{
+						mPass = true;
+					}
+				},
+				"fnInitComplete": function () {
+					$('#example_next').click();
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"aiDisplay length is full data when not filtered",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 10 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnWaitTest( 
+		"aiDisplay length is 9 when filtering on 'Mozilla'",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = false;
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnHeaderCallback": function ( nHead, aasData, iStart, iEnd, aiDisplay ) {
+					if ( aiDisplay.length == 9 )
+					{
+						mPass = true;
+					}
+				}
+			} );
+			oTable.fnFilter( "Mozilla" );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/fnInitComplete.js
@@ -1,1 +1,105 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnInitComplete" );
 
+/* Fairly boring function compared to the others! */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnWaitTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnInitComplete == null; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"One argument passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnInitComplete": function ( ) {
+					mPass = arguments.length;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"That one argument is the settings object",
+		function () {
+			oSession.fnRestore();
+			
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnInitComplete": function ( oSettings ) {
+					mPass = oSettings;
+				}
+			} );
+		},
+		function () { return oTable.fnSettings() == mPass; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"fnInitComplete called once on first draw",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"bServerSide": true,
+				"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnInitComplete": function ( ) {
+					mPass++;
+				}
+			} );
+		},
+		function () { return mPass == 1; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnInitComplete never called there after",
+		function () {
+			$('#example_next').click();
+			$('#example_next').click();
+			$('#example_next').click();
+		},
+		function () { return mPass == 1; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"10 rows in the table on complete",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"bServerSide": true,
+				"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnInitComplete": function ( ) {
+					mPass = $('#example tbody tr').length;
+				}
+			} );
+		},
+		function () { return mPass == 10; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/fnRowCallback.js
@@ -1,1 +1,118 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "fnRowCallback" );
 
+/* Note - fnRowCallback MUST return the first arguments (modified or not) */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	var mPass;
+	
+	oTest.fnWaitTest( 
+		"Default should be null",
+		null,
+		function () { return oSettings.fnRowCallback == null; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Four arguments passed",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = -1;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnRowCallback": function ( nTr ) {
+					mPass = arguments.length;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass == 4; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback called once for each drawn row",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = 0;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					mPass++;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"fnRowCallback allows us to alter row information",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					$(nTr).addClass('unit_test');
+					return nTr;
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(1)').hasClass('unit_test'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Data array has length matching columns",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					if ( asData.length != 5 )
+						mPass = false;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Data array has length matching columns",
+		function () {
+			oSession.fnRestore();
+			
+			mPass = true;
+			var iCount = 0;
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"fnRowCallback": function ( nTr, asData, iDrawIndex, iDataIndex ) {
+					if ( iCount != iDrawIndex )
+						mPass = false;
+					iCount++;
+					return nTr;
+				}
+			} );
+		},
+		function () { return mPass; }
+	);
+	
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/iDisplayLength.js
@@ -1,1 +1,85 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "iDisplayLength" );
 
+$(document).ready( function () {
+	/* Check the default */
+	$('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	
+	oTest.fnWaitTest( 
+		"Default length is ten",
+		null,
+		function () { return $('#example tbody tr').length == 10; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Select menu shows 10",
+		null,
+		function () { return $('#example_length select').val() == 10; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Set initial length to 25",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"iDisplayLength": 25
+			} );
+		},
+		function () { return $('#example tbody tr').length == 25; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Select menu shows 25",
+		null,
+		function () { return $('#example_length select').val() == 25; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Set initial length to 100",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"iDisplayLength": 100
+			} );
+		},
+		function () { return $('#example tbody tr').length == 57; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Select menu shows 25",
+		null,
+		function () { return $('#example_length select').val() == 100; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Set initial length to 23 (unknown select menu length)",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"iDisplayLength": 23
+			} );
+		},
+		function () { return $('#example tbody tr').length == 23; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Select menu shows 10 (since 23 is unknow)",
+		null,
+		function () { return $('#example_length select').val() == 10; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.oPaginate.js
@@ -1,1 +1,86 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.oPaginate" );
 
+/* Note that the paging language information only has relevence in full numbers */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+		"sPaginationType": "full_numbers"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"oLanguage.oPaginate defaults",
+		null,
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.oPaginate.sFirst == "First" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "Previous" &&
+				oSettings.oLanguage.oPaginate.sNext == "Next" &&
+				oSettings.oLanguage.oPaginate.sLast == "Last";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate defaults are in the DOM",
+		null,
+		function () {
+			var bReturn = 
+				$('#example_paginate .first').html() == "First" &&
+				$('#example_paginate .previous').html() == "Previous" &&
+				$('#example_paginate .next').html() == "Next" &&
+				$('#example_paginate .last').html() == "Last";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"oLanguage.oPaginate can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sPaginationType": "full_numbers",
+				"oLanguage": {
+					"oPaginate": {
+						"sFirst":    "unit1",
+						"sPrevious": "test2",
+						"sNext":     "unit3",
+						"sLast":     "test4"
+					}
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.oPaginate.sFirst == "unit1" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "test2" &&
+				oSettings.oLanguage.oPaginate.sNext == "unit3" &&
+				oSettings.oLanguage.oPaginate.sLast == "test4";
+			return bReturn;
+		}
+	);
+	
+	oTest.fnTest( 
+		"oLanguage.oPaginate definitions are in the DOM",
+		null,
+		function () {
+			var bReturn = 
+				$('#example_paginate .first').html() == "unit1" &&
+				$('#example_paginate .previous').html() == "test2" &&
+				$('#example_paginate .next').html() == "unit3" &&
+				$('#example_paginate .last').html() == "test4";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.sInfo.js
@@ -1,1 +1,124 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sInfo" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Info language is 'Showing _START_ to _END_ of _TOTAL_ entries' by default",
+		null,
+		function () { return oSettings.oLanguage.sInfo == "Showing _START_ to _END_ of _TOTAL_ entries"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - without any macros",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfo": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sInfo == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "unit test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macro _START_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfo": "unit _START_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macro _END_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfo": "unit _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 10 test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macro _TOTAL_ only",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfo": "unit _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 57 test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macros _START_ and _END_",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfo": "unit _START_ _END_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 10 test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info language can be defined - with macros _START_, _END_ and _TOTAL_",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfo": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "unit 1 10 57 test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.sInfoEmpty.js
@@ -1,1 +1,82 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sInfoEmpty" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Info empty language is 'Showing 0 to 0 of 0 entries' by default",
+		function () { oTable.fnFilter("nothinghere"); },
+		function () { return oSettings.oLanguage.sInfoEmpty == "Showing 0 to 0 of 0 entries"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"Showing 0 to 0 of 0 entries";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Info empty language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfoEmpty": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+			oTable.fnFilter("nothinghere");
+		},
+		function () { return oSettings.oLanguage.sInfoEmpty == "unit test"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"unit test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Macro's not replaced",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfoEmpty": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+			oTable.fnFilter("nothinghere");
+		},
+		function () {
+			var bReturn = document.getElementById('example_info').innerHTML.replace( 
+				' '+oSettings.oLanguage.sInfoFiltered.replace( '_MAX_', '57' ), "" ) ==
+					"unit _START_ _END_ _TOTAL_ test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.sInfoPostFix.js
@@ -1,1 +1,82 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sInfoPostFix" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Info post fix language is '' (blank) by default",
+		null,
+		function () { return oSettings.oLanguage.sInfoPostFix == ""; }
+	);
+	
+	oTest.fnTest( 
+		"Width no post fix, the basic info shows",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Info post fix language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfoPostFix": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sInfoPostFix == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info empty language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries unit test"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Macros have no effect in the post fix",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfoPostFix": "unit _START_ _END_ _TOTAL_ test"
+				}
+			} );
+		},
+		function () { return document.getElementById('example_info').innerHTML = "Showing 1 to 10 of 57 entries unit _START_ _END_ _TOTAL_ test"; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Post fix is applied after fintering info",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sInfoPostFix": "unit test"
+				}
+			} );
+			oTable.fnFilter("nothinghere");
+		},
+		function () { return document.getElementById('example_info').innerHTML = "Showing 0 to 0 of 0 entries unit (filtered from 57 total entries) test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.sLengthMenu.js
@@ -1,1 +1,110 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sLengthMenu" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Menu language is 'Show _MENU_ entries' by default",
+		null,
+		function () { return oSettings.oLanguage.sLengthMenu == "Show _MENU_ entries"; }
+	);
+	
+	oTest.fnTest(
+		"_MENU_ macro is replaced by select menu in DOM",
+		null,
+		function () { return $('select', oSettings.aanFeatures.l[0]).length == 1 }
+	);
+	
+	oTest.fnTest(
+		"Default is put into DOM",
+		null,
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren[0].nodeValue == "Show " &&
+				anChildren[2].nodeValue == " entries";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Menu length language can be defined - no _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sLengthMenu": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sLengthMenu == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Menu length language definition is in the DOM",
+		null,
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			return anChildren[0].nodeValue == "unit test";
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Menu length language can be defined - with _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sLengthMenu": "unit _MENU_ test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren[0].nodeValue == "unit " &&
+				anChildren[2].nodeValue == " test";
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Only the _MENU_ macro",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sLengthMenu": "_MENU_"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var anChildren = oSettings.aanFeatures.l[0].childNodes;
+			var bReturn =
+				anChildren.length == 1 &&
+				$('select', oSettings.aanFeatures.l[0]).length == 1;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.sProcessing.js
@@ -1,1 +1,51 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sProcessing" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+		"bProcessing": true
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Processing language is 'Processing...' by default",
+		null,
+		function () { return oSettings.oLanguage.sProcessing == "Processing..."; }
+	);
+	
+	oTest.fnTest( 
+		"Processing language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_processing').innerHTML = "Processing..."; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Processing language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"bProcessing": true,
+				"oLanguage": {
+					"sProcessing": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sProcessing == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Processing language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_processing').innerHTML = "unit test"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.sSearch.js
@@ -1,1 +1,68 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sSearch" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Search language is 'Search:' by default",
+		null,
+		function () { return oSettings.oLanguage.sSearch == "Search:"; }
+	);
+	
+	oTest.fnTest( 
+		"Search language default is in the DOM",
+		null,
+		function () { return document.getElementById('example_filter').childNodes[0].nodeValue
+		 	== "Search: "; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Search language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sSearch": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sSearch == "unit test"; }
+	);
+	
+	oTest.fnTest( 
+		"Info language definition is in the DOM",
+		null,
+		function () { return document.getElementById('example_filter').childNodes[0].nodeValue
+		 	== "unit test "; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Blank search has no space (separator) inserted",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sSearch": ""
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return document.getElementById('example_filter').childNodes.length == 1; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.sUrl.js
@@ -1,1 +1,64 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sUrl" );
 
+/* Note that we only test the internal storage of language information pulled form a file here
+ * as the other language tests will check it goes into the DOM correctly
+ */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnTest( 
+		"sUrl is blank by default",
+		null,
+		function () { return oSettings.oLanguage.sUrl == ""; }
+	);
+	
+	
+	oTest.fnWaitTest( 
+		"Loading of German file loads language information",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sUrl": "../../../examples/examples_support/de_DE.txt"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			var bReturn = 
+				oSettings.oLanguage.sProcessing == "Bitte warten..." &&
+				oSettings.oLanguage.sLengthMenu == "_MENU_ Einträge anzeigen" &&
+				oSettings.oLanguage.sZeroRecords == "Keine Einträge vorhanden." &&
+				oSettings.oLanguage.sInfo == "_START_ bis _END_ von _TOTAL_ Einträgen" &&
+				oSettings.oLanguage.sInfoEmpty == "0 bis 0 von 0 Einträgen" &&
+				oSettings.oLanguage.sInfoFiltered == "(gefiltert von _MAX_  Einträgen)" &&
+				oSettings.oLanguage.sInfoPostFix == "" &&
+				oSettings.oLanguage.sSearch == "Suchen" &&
+				oSettings.oLanguage.oPaginate.sFirst == "Erster" &&
+				oSettings.oLanguage.oPaginate.sPrevious == "Zurück" &&
+				oSettings.oLanguage.oPaginate.sNext == "Nächster" &&
+				oSettings.oLanguage.oPaginate.sLast == "Letzter";
+				
+			return bReturn;
+		}
+	);
+	
+	/* One DOM check just to ensure that they go into the DOM */
+	oTest.fnTest(
+		"Loaded language goes into the DOM",
+		null,
+		function () { return document.getElementById('example_info').innerHTML = "1 bis 10 von 57 Einträgen"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oLanguage.sZeroRecords.js
@@ -1,1 +1,58 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oLanguage.sZeroRecords" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Zero records language is 'No matching records found' by default",
+		null,
+		function () { return oSettings.oLanguage.sZeroRecords == "No matching records found"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Text is shown when empty table (after filtering)",
+		function () { oTable.fnFilter('nothinghere'); },
+		function () {
+			if ( $('#example tbody tr td').length == 0 )
+				return false;
+			return $('#example tbody tr td')[0].innerHTML == "No matching records found";
+		}
+	);
+	
+	
+	
+	oTest.fnWaitTest( 
+		"Zero records language can be defined",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oLanguage": {
+					"sZeroRecords": "unit test"
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.oLanguage.sZeroRecords == "unit test"; }
+	);
+	
+	oTest.fnWaitTest(
+		"Text is shown when empty table (after filtering)",
+		function () { oTable.fnFilter('nothinghere2'); },
+		function () {
+			if ( $('#example tbody tr td').length == 0 )
+				return false;
+			return $('#example tbody tr td')[0].innerHTML == "unit test"
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/oSearch.js
@@ -1,1 +1,100 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "oSearch" );
 
+/* Note with my server-side scripts the regex option has no effect - this just runs that down */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default values should be blank",
+		null,
+		function () {
+			var bReturn = oSettings.oPreviousSearch.sSearch == "" && 
+			              !oSettings.oPreviousSearch.bRegex;
+			return bReturn;
+		}
+	);
+	
+	/* This test might be considered iffy since the full object isn't given, but it's reasonable to
+	 * expect DataTables to cope with this. It should just assumine regex false
+	 */
+	oTest.fnWaitTest( 
+		"Search term only in object",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oSearch": {
+					"sSearch": "Mozilla"
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(3)').html() == "1"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"New search will kill old one",
+		function () {
+			oTable.fnFilter("Opera");
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Opera 7.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search plain text term and escape regex true",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+				"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oSearch": {
+					"sSearch": "DS",
+					"bRegex": false
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Nintendo DS browser"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search plain text term and escape regex false",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+				"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oSearch": {
+					"sSearch": "Opera",
+					"bRegex": true
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(1)').html() == "Opera 7.0"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Search regex text term and escape regex true",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+				"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"oSearch": {
+					"sSearch": "1.*",
+					"bRegex": false
+				}
+			} );
+		},
+		function () { return $('#example tbody tr:eq(0) td:eq(0)').html() == "No matching records found"; }
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/sAjaxSource.js
@@ -1,1 +1,23 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "sAjaxSource" );
 
+/* Sanitfy check really - all the other tests blast this */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Server side is off by default",
+		null,
+		function () { 
+			return oSettings.sAjaxSource == "../../../examples/examples_support/server_processing.php";
+		}
+	);
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/sDom.js
@@ -1,1 +1,269 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "sDom" );
 
+/* This is going to be brutal on the browser! There is a lot that can be tested here... */
+
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Default DOM varaible",
+		null,
+		function () { return oSettings.sDom == "lfrtip"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Default DOM in document",
+		null,
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				nNodes[4] == nInfo &&
+				nNodes[5] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check example 1 in code propagates",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sDom": '<"wrapper"flipt>'
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () { return oSettings.sDom == '<"wrapper"flipt>'; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Check example 1 in DOM",
+		null,
+		function () {
+			var jqNodes = $('#demo div, #demo table');
+			var nNodes = [];
+			
+			/* Strip the paging nodes */
+			for ( var i=0, iLen=jqNodes.length ; i<iLen ; i++ )
+			{
+				if ( jqNodes[i].getAttribute('id') != "example_previous" &&
+				     jqNodes[i].getAttribute('id') != "example_next" )
+				{
+					nNodes.push( jqNodes[i] );
+				}
+			}
+			
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			var nCustomWrapper = $('div.wrapper')[0];
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nCustomWrapper &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nLength &&
+				nNodes[4] == nInfo &&
+				nNodes[5] == nPaging &&
+				nNodes[6] == nTable;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check example 2 in DOM",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sDom": '<lf<t>ip>'
+			} );
+		},
+		function () {
+			var jqNodes = $('#demo div, #demo table');
+			var nNodes = [];
+			var nCustomWrappers = []
+			
+			/* Strip the paging nodes */
+			for ( var i=0, iLen=jqNodes.length ; i<iLen ; i++ )
+			{
+				if ( jqNodes[i].getAttribute('id') != "example_previous" &&
+				     jqNodes[i].getAttribute('id') != "example_next" )
+				{
+					nNodes.push( jqNodes[i] );
+				}
+				
+				/* Only the two custom divs don't have class names */
+				if ( !jqNodes[i].getAttribute('class') )
+				{
+					nCustomWrappers.push( jqNodes[i] );
+				}
+			}
+			
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nCustomWrappers[0] &&
+				nNodes[2] == nLength &&
+				nNodes[3] == nFilter &&
+				nNodes[4] == nCustomWrappers[1] &&
+				nNodes[5] == nTable &&
+				nNodes[6] == nInfo &&
+				nNodes[7] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check no length element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sDom": 'frtip'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				null == nLength &&
+				nNodes[1] == nFilter &&
+				nNodes[2] == nTable &&
+				nNodes[3] == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check no filter element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sDom": 'lrtip'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				null == nFilter &&
+				nNodes[2] == nTable &&
+				nNodes[3] == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	/* Note we don't test for no table as this is not supported (and it would be fairly daft! */
+	
+	oTest.fnWaitTest( 
+		"Check no info element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sDom": 'lfrtp'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				null == nInfo &&
+				nNodes[4] == nPaging;
+			return bReturn;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check no paging element",
+		function () {
+			oSession.fnRestore();
+			$('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sDom": 'lfrti'
+			} );
+		},
+		function () {
+			var nNodes = $('#demo div, #demo table');
+			var nWrapper = document.getElementById('example_wrapper');
+			var nLength = document.getElementById('example_length');
+			var nFilter = document.getElementById('example_filter');
+			var nInfo = document.getElementById('example_info');
+			var nPaging = document.getElementById('example_paginate');
+			var nTable = document.getElementById('example');
+			
+			var bReturn = 
+				nNodes[0] == nWrapper &&
+				nNodes[1] == nLength &&
+				nNodes[2] == nFilter &&
+				nNodes[3] == nTable &&
+				nNodes[4] == nInfo &&
+				null == nPaging;
+			return bReturn;
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/tests_onhold/4_server-side/sPaginationType.js
@@ -1,1 +1,138 @@
+// DATA_TEMPLATE: empty_table
+oTest.fnStart( "sPaginationType" );
 
+$(document).ready( function () {
+	/* Check the default */
+	var oTable = $('#example').dataTable( {
+		"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php"
+	} );
+	var oSettings = oTable.fnSettings();
+	
+	oTest.fnWaitTest( 
+		"Check two button paging is the default",
+		null,
+		function () { return oSettings.sPaginationType == "two_button"; }
+	);
+	
+	oTest.fnWaitTest( 
+		"Check class is applied",
+		null,
+		function () { return $('#example_paginate').hasClass('paging_two_button'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Two div elements are in the wrapper",
+		null,
+		function () { return $('#example_paginate div').length == 2; }
+	);
+	
+	oTest.fnWaitTest( 
+		"We have the previous button",
+		null,
+		function () { return document.getElementById('example_previous'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"We have the next button",
+		null,
+		function () { return document.getElementById('example_next'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Previous button is disabled",
+		null,
+		function () { return $('#example_previous').hasClass('paginate_disabled_previous'); }
+	);
+	
+	oTest.fnWaitTest( 
+		"Next button is enabled",
+		null,
+		function () { return $('#example_next').hasClass('paginate_enabled_next'); }
+	);
+	
+	/* Don't test paging - that's done by the zero config test script. */
+	
+	
+	/* Two buttons paging */
+	var bComplete = false;
+	oTest.fnWaitTest( 
+		"Can enabled full numbers paging",
+		function () {
+			oSession.fnRestore();
+			oTable = $('#example').dataTable( {
+				"bServerSide": true,
+		"sAjaxSource": "../../../examples/examples_support/server_processing.php",
+				"sPaginationType": "full_numbers",
+				"fnInitComplete": function () {
+					setTimeout( function () {
+						bComplete = true;
+					}, 500 );
+				}
+			} );
+			oSettings = oTable.fnSettings();
+		},
+		function () {
+			if ( bComplete )
+				return oSettings.sPaginationType == "full_numbers";
+			else
+				return false;
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Check full numbers class is applied",
+		null,
+		function () { return $('#example_paginate').hasClass('paging_full_numbers'); }
+	);
+	
+	
+	var nFirst, nPrevious, nNext, nLast;
+	oTest.fnWaitTest( 
+		"Jump to last page",
+		function () {
+			nFirst = $('div.dataTables_paginate span.first');
+			nPrevious = $('div.dataTables_paginate span.previous');
+			nNext = $('div.dataTables_paginate span.next');
+			nLast = $('div.dataTables_paginate span.last');
+			nLast.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 51 to 57 of 57 entries";
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Go to two pages previous",
+		function () {
+			nPrevious.click();
+			nPrevious.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 31 to 40 of 57 entries";
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Next (second last) page",
+		function () {
+			nNext.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 41 to 50 of 57 entries";
+		}
+	);
+	
+	oTest.fnWaitTest( 
+		"Jump to first page",
+		function () {
+			nFirst.click();
+		},
+		function () {
+			return document.getElementById('example_info').innerHTML == "Showing 1 to 10 of 57 entries";
+		}
+	);
+	
+	
+	oTest.fnComplete();
+} );

--- /dev/null
+++ b/media/unit_testing/unit_test.js
@@ -1,1 +1,406 @@
-
+/*
+ * File:        unit_test.js
+ * Version:     0.0.1
+ * CVS:         $Id$
+ * Description: Unit test framework
+ * Author:      Allan Jardine (www.sprymedia.co.uk)
+ * Created:     Sun Mar  8 22:02:49 GMT 2009
+ * Modified:    $Date$ by $Author$
+ * Language:    Javascript
+ * License:     GPL v2 or BSD 3 point style
+ * Project:     DataTables
+ * Contact:     allan.jardine@sprymedia.co.uk
+ * 
+ * Copyright 2009 Allan Jardine, all rights reserved.
+ *
+ * Description:
+ * This is a javascript library suitable for use as a unit testing framework. Employing a queuing
+ * mechanisim to take account of async events in javascript, this library will communicates with
+ * a controller frame (to report individual test status).
+ * 
+ */
+
+
+var oTest = {
+	/* Block further tests from occuring - might be end of tests or due to async wait */
+	bBlock: false,
+	
+	/* Number of times to try retesting for a blocking test */
+	iReTestLimit: 20,
+	
+	/* Amount of time to wait between trying for an async test */
+	iReTestDelay: 150,
+	
+	/* End tests - external control */
+	bEnd: false,
+	
+	/* Internal variables */
+	_aoQueue: [],
+	_iReTest: 0,
+	_bFinished: false,
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Recommened public functions
+	 */
+	
+	/*
+	 * Function: fnTest
+	 * Purpose:  Add a test to the queue
+	 * Returns:  -
+	 * Inputs:   string:sMessage - name of the test
+	 *           function:fnTest - function which will be evaludated to get the test result
+	 */
+	"fnTest": function ( sMessage, fnSetup, fnTest )
+	{
+		this._aoQueue.push( {
+			"sMessage": sMessage,
+			"fnSetup": fnSetup,
+			"fnTest": fnTest,
+			"bPoll": false
+		} );
+		this._fnNext();
+	},
+	
+	/*
+	 * Function: fnWaitTest
+	 * Purpose:  Add a test to the queue which has a re-test cycle
+	 * Returns:  -
+	 * Inputs:   string:sMessage - name of the test
+	 *           function:fnTest - function which will be evaludated to get the test result
+	 */
+	"fnWaitTest": function ( sMessage, fnSetup, fnTest )
+	{
+		this._aoQueue.push( {
+			"sMessage": sMessage,
+			"fnSetup": fnSetup,
+			"fnTest": fnTest,
+			"bPoll": true
+		} );
+		this._fnNext();
+	},
+	
+	/*
+	 * Function: fnStart
+	 * Purpose:  Indicate that this is a new unit and what it is testing (message to end user)
+	 * Returns:  -
+	 * Inputs:   string:sMessage - message to give to the user about this unit
+	 */
+	"fnStart": function ( sMessage )
+	{
+		window.parent.controller.fnStartMessage( sMessage );
+	},
+	
+	/*
+	 * Function: fnComplete
+	 * Purpose:  Tell the controller that we are all done here
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	"fnComplete": function ()
+	{
+		this._bFinished = true;
+		this._fnNext();
+	},
+	
+	/*
+	 * Function: fnCookieDestroy
+	 * Purpose:  Destroy a cookie of a given name
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	"fnCookieDestroy": function ( oTable )
+	{
+		var sName = oTable.fnSettings().sCookiePrefix+oTable.fnSettings().sInstance;
+		var aParts = window.location.pathname.split('/');
+		var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
+		document.cookie = sNameFile+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
+			aParts.join('/') + "/";
+	},
+	
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Internal functions
+	 */
+	
+	
+	"_fnReTest": function ( oTestInfo )
+	{
+		var bResult = oTestInfo.fnTest( );
+		if ( bResult )
+		{
+			/* Test passed on retry */
+			this._fnResult( true );
+			this._fnNext();
+		}
+		else
+		{
+			if ( this._iReTest < this.iReTestLimit )
+			{
+				this._iReTest++;
+				setTimeout( function() {
+					oTest._fnReTest( oTestInfo );
+				}, this.iReTestDelay );
+			}
+			else
+			{
+				this._fnResult( false );
+			}
+		}
+	},
+	
+	"_fnNext": function ()
+	{
+		if ( this.bEnd )
+		{
+			return;
+		}
+		
+		if ( !this.bBlock && this._aoQueue.length > 0 )
+		{
+			var oNextTest = this._aoQueue.shift();
+			window.parent.controller.fnTestStart( oNextTest.sMessage );
+			this.bBlock = true;
+			
+			if ( typeof oNextTest.fnSetup == 'function' )
+			{
+				oNextTest.fnSetup( );
+			}
+			var bResult = oNextTest.fnTest( );
+			//bResult = false;
+			
+			if ( oNextTest.bPoll )
+			{
+				if ( bResult )
+				{
+					this._fnResult( true );
+					this._fnNext();
+				}
+				else
+				{
+					_iReTest = 0;
+					setTimeout( function() {
+						oTest._fnReTest( oNextTest );
+					}, this.iReTestDelay );
+				}
+			}
+			else
+			{
+				this._fnResult( bResult );
+				this._fnNext();
+			}
+		}
+		else if ( !this.bBlock && this._aoQueue.length == 0 && this._bFinished )
+		{
+			window.parent.controller.fnUnitComplete( );
+		}
+	},
+	
+	"_fnResult": function ( b )
+	{
+		window.parent.controller.fnTestResult( b );
+		this.bBlock = false;
+		if ( !b )
+		{
+			this.bEnd = true;
+		}
+	}
+};
+
+
+var oDispacher = {
+	"click": function ( nNode, oSpecial )
+	{
+		var evt = this.fnCreateEvent( 'click', nNode, oSpecial );
+		if ( nNode.dispatchEvent )
+			nNode.dispatchEvent(evt);
+		else
+			nNode.fireEvent('onclick', evt);
+	},
+	
+	"change": function ( nNode )
+	{
+		var evt = this.fnCreateEvent( 'change', nNode );
+		if ( nNode.dispatchEvent )
+		nNode.dispatchEvent(evt);
+		else
+			nNode.fireEvent('onchange', evt);
+	},
+	
+	
+	/*
+	 * Function: fnCreateEvent
+	 * Purpose:  Create an event oject based on the type to trigger an event - x-platform
+	 * Returns:  event:evt
+	 * Inputs:   string:sType - type of event
+	 *           node:nTarget - target node of the event
+	 */
+	fnCreateEvent: function( sType, nTarget, oSpecial )
+	{
+		var evt = null;
+		var oTargetPos = this._fnGetPos( nTarget );
+		var sTypeGroup = this._fnEventTypeGroup( sType );
+		if ( typeof oSpecial == 'undefined' )
+		{
+			oSpecial = {};
+		}
+		
+		var ctrlKey = false;
+		var altKey = false;
+		var shiftKey = (typeof oSpecial.shift != 'undefined') ? oSpecial.shift : false;
+		var metaKey = false;
+		var button = false;
+		
+		if ( document.createEvent )
+		{
+			switch ( sTypeGroup )
+			{
+				case 'mouse':
+					evt = document.createEvent( "MouseEvents" );
+					evt.initMouseEvent( sType, true, true, window, 0, oTargetPos[0], oTargetPos[1], 
+						oTargetPos[0], oTargetPos[1], ctrlKey, altKey, shiftKey, 
+						metaKey, button, null );
+					break;
+				
+				case 'html':
+					evt = document.createEvent( "HTMLEvents" );
+					evt.initEvent( sType, true, true );
+					break;
+					
+				case 'ui':
+					evt = document.createEvent( "UIEvents" );
+					evt.initUIEvent( sType, true, true, window, 0 );
+					break;
+				
+				default:
+					break;
+			}
+		}
+		else if ( document.createEventObject )
+		{
+			switch ( sTypeGroup )
+			{
+				case 'mouse':
+					evt = document.createEventObject();
+					evt.screenX = oTargetPos[0];
+					evt.screenX = oTargetPos[1];
+					evt.clientX = oTargetPos[0];
+					evt.clientY = oTargetPos[1];
+					evt.ctrlKey = ctrlKey;
+					evt.altKey = altKey;
+					evt.shiftKey = shiftKey;
+					evt.metaKey = metaKey;
+					evt.button = button;
+					evt.relatedTarget = null;
+					break;
+				
+				case 'html':
+					/* fall through to basic event object */
+					
+				case 'ui':
+					evt = document.createEventObject();
+					break;
+				
+				default:
+					break;
+			}
+		}
+		
+		return evt;
+	},
+	
+	/* 
+	 * Function: DesignCore.fnGetPos
+	 * Purpose:  Get the position of an element on the page
+	 * Returns:  array[ 0-int:left, 1-int:top ]
+	 * Inputs:   node:obj - node to analyse
+	 */
+	_fnGetPos: function ( obj ) 
+	{
+		var curleft = 0;
+		var curtop = 0;
+		
+		if (obj.offsetParent) 
+		{
+			curleft = obj.offsetLeft;
+			curtop = obj.offsetTop;
+			while (obj = obj.offsetParent ) 
+			{
+				curleft += obj.offsetLeft;
+				curtop += obj.offsetTop;
+			}
+		}
+		return [curleft,curtop];
+	},
+	
+	
+	/*
+	 * Function: _fnEventTypeGroup
+	 * Purpose:  Group the event types as per w3c groupings
+	 * Returns:  -
+	 * Inputs:   string:sType
+	 */
+	_fnEventTypeGroup: function ( sType )
+	{
+		switch ( sType )
+		{
+			case 'click':
+			case 'dblclick':
+			case 'mousedown':
+			case 'mousemove':
+			case 'mouseout':
+			case 'mouseover':
+			case 'mouseup':
+				return 'mouse';
+			
+			case 'change':
+			case 'focus':
+			case 'blur':
+			case 'select':
+			case 'submit':
+				return 'html';
+				
+			case 'keydown':
+			case 'keypress':
+			case 'keyup':
+			case 'load':
+			case 'unload':
+				return 'ui';
+			
+			default:
+				return 'custom';
+		}
+	}
+}
+
+
+var oSession = {
+	nTable: null,
+	
+	fnCache: function ()
+	{
+		this.nTable = document.getElementById('demo').cloneNode(true);
+	},
+	
+	fnRestore: function ()
+	{
+		while( $.fn.dataTableSettings.length > 0 )
+		{
+			$.fn.dataTableSettings[0].oInstance.fnDestroy();
+		}
+		//$.fn.dataTableSettings.splice( 0, $.fn.dataTableSettings.length );
+		var nDemo = document.getElementById('demo');
+		nDemo.innerHTML = "";
+		for ( var i=0, iLen=this.nTable.childNodes.length ; i<iLen ; i++ )
+		{
+			nDemo.appendChild( this.nTable.childNodes[0] );
+		}
+		this.fnCache();
+	}
+}
+
+$(document).ready( function () {
+	oSession.fnCache();
+} );
+

file:a/search.php -> file:b/search.php
--- a/search.php
+++ b/search.php
@@ -1,8 +1,31 @@
-search ABNs

+<?php

+/*

+ search ABNs

 search agency name

 search categories

 search supplier names

 --search supplier postcodes/suburbs/cities--

 search CN number

 search description full text

+*/

+include('./lib/common.inc.php');

+if ($_REQUEST['searchID']) {

+$searchIDParts = explode("-",$_REQUEST['searchID']);

+$type = array_shift($searchIDParts);

+$host  = $_SERVER['HTTP_HOST'];

+$uri   = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');

+

+if ($type == "agency") {

+header("Location: http://$host$uri/displayAgency.php?agency=".implode("-",$searchIDParts));

+}

+if ($type == "supplier") {

+header("Location: http://$host$uri/displaySupplier.php?supplier=".implode("-",$searchIDParts));

+}

+exit;

+} else {

+include_header("Search Results");

+print_r($_REQUEST);

+include_footer();

+}

+?>

 

--- /dev/null
+++ b/search_autosuggest.php
@@ -1,1 +1,62 @@
-
+<?php
+include_once ("./lib/common.inc.php");
+$input = strtolower($_GET['input']);
+$len = strlen($input);
+$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 0;
+$aResults = array();
+$count = 0;
+if ($len) {
+  $query = "SELECT supplierName, supplierABN, supplierName, count(*) as count
+FROM `contractnotice`
+WHERE supplierName LIKE '$input%'
+GROUP BY supplierName
+ORDER BY count DESC
+LIMIT 4;
+";
+  $result = mysql_query($query);
+  while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {
+    $count++;
+    $aResults[] = array(
+      "id" => "supplier-".$row['supplierABN'].'-'.$row['supplierName'],
+      "value" => htmlspecialchars($row['supplierName']) ,
+      "info" => htmlspecialchars("Supplier - ". $row['count']." records")
+    );
+  }
+  $query = "SELECT agencyName, count(*) as count
+FROM `contractnotice`
+WHERE agencyName LIKE '$input%'
+GROUP BY agencyName
+ORDER BY count DESC
+LIMIT 4;";
+  $result = mysql_query($query);
+  while ($row = mysql_fetch_array($result, MYSQL_BOTH)) {
+    $count++;
+    $aResults[] = array(
+      "id" => "agency-".$row['agencyName'],
+      "value" => htmlspecialchars($row['agencyName']) ,
+      "info" => htmlspecialchars("Government Agency - ". $row['count']." records")
+    );
+  }
+}
+header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
+header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
+header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
+header("Pragma: no-cache"); // HTTP/1.0
+if (isset($_REQUEST['json'])) {
+  header("Content-Type: application/json");
+  echo "{\"results\": [";
+  $arr = array();
+  for ($i = 0;$i < count($aResults);$i++) {
+    $arr[] = "{\"id\": \"" . $aResults[$i]['id'] . "\", \"value\": \"" . $aResults[$i]['value'] . "\", \"info\": \"\"}";
+  }
+  echo implode(", ", $arr);
+  echo "]}";
+} else {
+  header("Content-Type: text/xml");
+  echo "<?xml version=\"1.0\" encoding=\"utf-8\" ?><results>";
+  for ($i = 0;$i < count($aResults);$i++) {
+    echo "<rs id=\"" . $aResults[$i]['id'] . "\" info=\"" . $aResults[$i]['info'] . "\">" . $aResults[$i]['value'] . "</rs>";
+  }
+  echo "</results>";
+}
+?>

file:a/style.css -> file:b/style.css
--- a/style.css
+++ b/style.css
@@ -11,17 +11,22 @@
 }
 
 #search, form {
-display: inline;
 float: right;
 margin-top: -1px;
 }
 
 #sitenav {
+
 width: 99%;
 text-align: left;
 padding: 5px;
 border-top:1px solid black;
 border-bottom:1px solid black;
+}
+
+#sitenav.a {
+
+display: inline;
 }
 
 #content {
@@ -40,3 +45,29 @@
 #ft {
 font-size: 66%;
 }
+
+// div collapse from http://roshanbh.com.np/2008/03/expandable-collapsible-toggle-pane-jquery.html
+p {
+padding: 0 0 1em;
+}
+.msg_list {
+margin: 0px;
+padding: 0px;
+width: 383px;
+}
+.msg_head {
+padding: 5px 10px;
+cursor: pointer;
+position: relative;
+background-color:#FFCCCC;
+margin:1px;
+}
+.msg_body {
+padding: 5px 10px 15px;
+background-color:#F4F4F8;
+}
+// div collapse
+
+table {
+    width: 100% !important; 
+}

file:a/todo.txt -> file:b/todo.txt
--- a/todo.txt
+++ b/todo.txt
@@ -3,4 +3,10 @@
 can we merge ABN splitting companies like PWC/Dell Finance?

 

 can we add google news? lobbyist officers?

+

+compile database of file lists

+

+compile database of employees

+

+show metrics about agencies/suppliers eg. extent of contract variations, level of reg 10 commitments, reporting speedyness