PageSourceSearch

https://ciberche.net/histoche/src/jquery.dataTables.js

js ciberche.net collected 2026-09-24 10:02:19 UTC 377,699 bytes, 12,099 lines download raw bytes

1/**
2 * @summary     DataTables
3 * @description Paginate, search and sort HTML tables
4 * @version     1.9.4
5 * @file        jquery.dataTables.js
6 * @author      Allan Jardine (www.sprymedia.co.uk)
7 * @contact     www.sprymedia.co.uk/contact
8 *
9 * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.
10 *
11 * This source file is free software, under either the GPL v2 license or a
12 * BSD style license, available at:
13 *   http://datatables.net/license_gpl2
14 *   http://datatables.net/license_bsd
15 * 
16 * This source file is distributed in the hope that it will be useful, but 
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
19 * 
20 * For details please refer to: http://www.datatables.net
21 */
22
23/*jslint evil: true, undef: true, browser: true */
24/*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_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,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnRender,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns*/
25
26(/** @lends <global> */function( window, document, undefined ) {
27
28(function( factory ) {
29	"use strict";
30
31	// Define as an AMD module if possible
32	if ( typeof define === 'function' && define.amd )
33	{
34		define( ['jquery'], factory );
35	}
36	/* Define using browser globals otherwise
37	 * Prevent multiple instantiations if the script is loaded twice
38	 */
39	else if ( jQuery && !jQuery.fn.dataTable )
40	{
41		factory( jQuery );
42	}
43}
44(/** @lends <global> */function( $ ) {
45	"use strict";
46	/** 
47	 * DataTables is a plug-in for the jQuery Javascript library. It is a 
48	 * highly flexible tool, based upon the foundations of progressive 
49	 * enhancement, which will add advanced interaction controls to any 
50	 * HTML table. For a full list of features please refer to
51	 * <a href="http://datatables.net">DataTables.net</a>.
52	 *
53	 * Note that the <i>DataTable</i> object is not a global variable but is
54	 * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which 
55	 * it may be  accessed.
56	 *
57	 *  @class
58	 *  @param {object} [oInit={}] Configuration object for DataTables. Options
59	 *    are defined by {@link DataTable.defaults}
60	 *  @requires jQuery 1.3+
61	 * 
62	 *  @example
63	 *    // Basic initialisation
64	 *    $(document).ready( function {
65	 *      $('#example').dataTable();
66	 *    } );
67	 *  
68	 *  @example
69	 *    // Initialisation with configuration options - in this case, disable
70	 *    // pagination and sorting.
71	 *    $(document).ready( function {
72	 *      $('#example').dataTable( {
73	 *        "bPaginate": false,
74	 *        "bSort": false 
75	 *      } );
76	 *    } );
77	 */
78	var DataTable = function( oInit )
79	{
80		
81		
82		/**
83		 * Add a column to the list used for the table with default values
84		 *  @param {object} oSettings dataTables settings object
85		 *  @param {node} nTh The th element for this column
86		 *  @memberof DataTable#oApi
87		 */
88		function _fnAddColumn( oSettings, nTh )
89		{
90			var oDefaults = DataTable.defaults.columns;
91			var iCol = oSettings.aoColumns.length;
92			var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
93				"sSortingClass": oSettings.oClasses.sSortable,
94				"sSortingClassJUI": oSettings.oClasses.sSortJUI,
95				"nTh": nTh ? nTh : document.createElement('th'),
96				"sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
97				"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
98				"mData": oDefaults.mData ? oDefaults.oDefaults : iCol
99			} );
100			oSettings.aoColumns.push( oCol );
101			
102			/* Add a column specific filter */
103			if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )
104			{
105				oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );
106			}
107			else
108			{
109				var oPre = oSettings.aoPreSearchCols[ iCol ];
110				
111				/* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */
112				if ( oPre.bRegex === undefined )
113				{
114					oPre.bRegex = true;
115				}
116				
117				if ( oPre.bSmart === undefined )
118				{
119					oPre.bSmart = true;
120				}
121				
122				if ( oPre.bCaseInsensitive === undefined )
123				{
124					oPre.bCaseInsensitive = true;
125				}
126			}
127			
128			/* Use the column options function to initialise classes etc */
129			_fnColumnOptions( oSettings, iCol, null );
130		}
131		
132		
133		/**
134		 * Apply options for a column
135		 *  @param {object} oSettings dataTables settings object
136		 *  @param {int} iCol column index to consider
137		 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
138		 *  @memberof DataTable#oApi
139		 */
140		function _fnColumnOptions( oSettings, iCol, oOptions )
141		{
142			var oCol = oSettings.aoColumns[ iCol ];
143			
144			/* User specified column options */
145			if ( oOptions !== undefined && oOptions !== null )
146			{
147				/* Backwards compatibility for mDataProp */
148				if ( oOptions.mDataProp && !oOptions.mData )
149				{
150					oOptions.mData = oOptions.mDataProp;
151				}
152		
153				if ( oOptions.sType !== undefined )
154				{
155					oCol.sType = oOptions.sType;
156					oCol._bAutoType = false;
157				}
158				
159				$.extend( oCol, oOptions );
160				_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
161		
162				/* iDataSort to be applied (backwards compatibility), but aDataSort will take
163				 * priority if defined
164				 */
165				if ( oOptions.iDataSort !== undefined )
166				{
167					oCol.aDataSort = [ oOptions.iDataSort ];
168				}
169				_fnMap( oCol, oOptions, "aDataSort" );
170			}
171		
172			/* Cache the data get and set functions for speed */
173			var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
174			var mData = _fnGetObjectDataFn( oCol.mData );
175		
176			oCol.fnGetData = function (oData, sSpecific) {
177				var innerData = mData( oData, sSpecific );
178		
179				if ( oCol.mRender && (sSpecific && sSpecific !== '') )
180				{
181					return mRender( innerData, sSpecific, oData );
182				}
183				return innerData;
184			};
185			oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );
186			
187			/* Feature sorting overrides column specific when off */
188			if ( !oSettings.oFeatures.bSort )
189			{
190				oCol.bSortable = false;
191			}
192			
193			/* Check that the class assignment is correct for sorting */
194			if ( !oCol.bSortable ||
195				 ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
196			{
197				oCol.sSortingClass = oSettings.oClasses.sSortableNone;
198				oCol.sSortingClassJUI = "";
199			}
200			else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 )
201			{
202				oCol.sSortingClass = oSettings.oClasses.sSortable;
203				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
204			}
205			else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
206			{
207				oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
208				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
209			}
210			else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
211			{
212				oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
213				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
214			}
215		}
216		
217		
218		/**
219		 * Adjust the table column widths for new data. Note: you would probably want to 
220		 * do a redraw after calling this function!
221		 *  @param {object} oSettings dataTables settings object
222		 *  @memberof DataTable#oApi
223		 */
224		function _fnAdjustColumnSizing ( oSettings )
225		{
226			/* Not interested in doing column width calculation if auto-width is disabled */
227			if ( oSettings.oFeatures.bAutoWidth === false )
228			{
229				return false;
230			}
231			
232			_fnCalculateColumnWidths( oSettings );
233			for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
234			{
235				oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
236			}
237		}
238		
239		
240		/**
241		 * Covert the index of a visible column to the index in the data array (take account
242		 * of hidden columns)
243		 *  @param {object} oSettings dataTables settings object
244		 *  @param {int} iMatch Visible column index to lookup
245		 *  @returns {int} i the data index
246		 *  @memberof DataTable#oApi
247		 */
248		function _fnVisibleToColumnIndex( oSettings, iMatch )
249		{
250			var aiVis = _fnGetColumns( oSettings, 'bVisible' );
251		
252			return typeof aiVis[iMatch] === 'number' ?
253				aiVis[iMatch] :
254				null;
255		}
256		
257		
258		/**
259		 * Covert the index of an index in the data array and convert it to the visible
260		 *   column index (take account of hidden columns)
261		 *  @param {int} iMatch Column index to lookup
262		 *  @param {object} oSettings dataTables settings object
263		 *  @returns {int} i the data index
264		 *  @memberof DataTable#oApi
265		 */
266		function _fnColumnIndexToVisible( oSettings, iMatch )
267		{
268			var aiVis = _fnGetColumns( oSettings, 'bVisible' );
269			var iPos = $.inArray( iMatch, aiVis );
270		
271			return iPos !== -1 ? iPos : null;
272		}
273		
274		
275		/**
276		 * Get the number of visible columns
277		 *  @param {object} oSettings dataTables settings object
278		 *  @returns {int} i the number of visible columns
279		 *  @memberof DataTable#oApi
280		 */
281		function _fnVisbleColumns( oSettings )
282		{
283			return _fnGetColumns( oSettings, 'bVisible' ).length;
284		}
285		
286		
287		/**
288		 * Get an array of column indexes that match a given property
289		 *  @param {object} oSettings dataTables settings object
290		 *  @param {string} sParam Parameter in aoColumns to look for - typically 
291		 *    bVisible or bSearchable
292		 *  @returns {array} Array of indexes with matched properties
293		 *  @memberof DataTable#oApi
294		 */
295		function _fnGetColumns( oSettings, sParam )
296		{
297			var a = [];
298		
299			$.map( oSettings.aoColumns, function(val, i) {
300				if ( val[sParam] ) {
301					a.push( i );
302				}
303			} );
304		
305			return a;
306		}
307		
308		
309		/**
310		 * Get the sort type based on an input string
311		 *  @param {string} sData data we wish to know the type of
312		 *  @returns {string} type (defaults to 'string' if no type can be detected)
313		 *  @memberof DataTable#oApi
314		 */
315		function _fnDetectType( sData )
316		{
317			var aTypes = DataTable.ext.aTypes;
318			var iLen = aTypes.length;
319			
320			for ( var i=0 ; i<iLen ; i++ )
321			{
322				var sType = aTypes[i]( sData );
323				if ( sType !== null )
324				{
325					return sType;
326				}
327			}
328			
329			return 'string';
330		}
331		
332		
333		/**
334		 * Figure out how to reorder a display list
335		 *  @param {object} oSettings dataTables settings object
336		 *  @returns array {int} aiReturn index list for reordering
337		 *  @memberof DataTable#oApi
338		 */
339		function _fnReOrderIndex ( oSettings, sColumns )
340		{
341			var aColumns = sColumns.split(',');
342			var aiReturn = [];
343			
344			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
345			{
346				for ( var j=0 ; j<iLen ; j++ )
347				{
348					if ( oSettings.aoColumns[i].sName == aColumns[j] )
349					{
350						aiReturn.push( j );
351						break;
352					}
353				}
354			}
355			
356			return aiReturn;
357		}
358		
359		
360		/**
361		 * Get the column ordering that DataTables expects
362		 *  @param {object} oSettings dataTables settings object
363		 *  @returns {string} comma separated list of names
364		 *  @memberof DataTable#oApi
365		 */
366		function _fnColumnOrdering ( oSettings )
367		{
368			var sNames = '';
369			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
370			{
371				sNames += oSettings.aoColumns[i].sName+',';
372			}
373			if ( sNames.length == iLen )
374			{
375				return "";
376			}
377			return sNames.slice(0, -1);
378		}
379		
380		
381		/**
382		 * Take the column definitions and static columns arrays and calculate how
383		 * they relate to column indexes. The callback function will then apply the
384		 * definition found for a column to a suitable configuration object.
385		 *  @param {object} oSettings dataTables settings object
386		 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
387		 *  @param {array} aoCols The aoColumns array that defines columns individually
388		 *  @param {function} fn Callback function - takes two parameters, the calculated
389		 *    column index and the definition for that column.
390		 *  @memberof DataTable#oApi
391		 */
392		function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
393		{
394			var i, iLen, j, jLen, k, kLen;
395		
396			// Column definitions with aTargets
397			if ( aoColDefs )
398			{
399				/* Loop over the definitions array - loop in reverse so first instance has priority */
400				for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
401				{
402					/* Each definition can target multiple columns, as it is an array */
403					var aTargets = aoColDefs[i].aTargets;
404					if ( !$.isArray( aTargets ) )
405					{
406						_fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
407					}
408		
409					for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
410					{
411						if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
412						{
413							/* Add columns that we don't yet know about */
414							while( oSettings.aoColumns.length <= aTargets[j] )
415							{
416								_fnAddColumn( oSettings );
417							}
418		
419							/* Integer, basic index */
420							fn( aTargets[j], aoColDefs[i] );
421						}
422						else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
423						{
424							/* Negative integer, right to left column counting */
425							fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );
426						}
427						else if ( typeof aTargets[j] === 'string' )
428						{
429							/* Class name matching on TH element */
430							for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
431							{
432								if ( aTargets[j] == "_all" ||
433								     $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
434								{
435									fn( k, aoColDefs[i] );
436								}
437							}
438						}
439					}
440				}
441			}
442		
443			// Statically defined columns array
444			if ( aoCols )
445			{
446				for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
447				{
448					fn( i, aoCols[i] );
449				}
450			}
451		}
452		
453		/**
454		 * Add a data array to the table, creating DOM node etc. This is the parallel to 
455		 * _fnGatherData, but for adding rows from a Javascript source, rather than a
456		 * DOM source.
457		 *  @param {object} oSettings dataTables settings object
458		 *  @param {array} aData data array to be added
459		 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
460		 *  @memberof DataTable#oApi
461		 */
462		function _fnAddData ( oSettings, aDataSupplied )
463		{
464			var oCol;
465			
466			/* Take an independent copy of the data source so we can bash it about as we wish */
467			var aDataIn = ($.isArray(aDataSupplied)) ?
468				aDataSupplied.slice() :
469				$.extend( true, {}, aDataSupplied );
470			
471			/* Create the object for storing information about this new row */
472			var iRow = oSettings.aoData.length;
473			var oData = $.extend( true, {}, DataTable.models.oRow );
474			oData._aData = aDataIn;
475			oSettings.aoData.push( oData );
476		
477			/* Create the cells */
478			var nTd, sThisType;
479			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
480			{
481				oCol = oSettings.aoColumns[i];
482		
483				/* Use rendered data for filtering / sorting */
484				if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )
485				{
486					_fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
487				}
488				else
489				{
490					_fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
491				}
492				
493				/* See if we should auto-detect the column type */
494				if ( oCol._bAutoType && oCol.sType != 'string' )
495				{
496					/* Attempt to auto detect the type - same as _fnGatherData() */
497					var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
498					if ( sVarType !== null && sVarType !== '' )
499					{
500						sThisType = _fnDetectType( sVarType );
501						if ( oCol.sType === null )
502						{
503							oCol.sType = sThisType;
504						}
505						else if ( oCol.sType != sThisType && oCol.sType != "html" )
506						{
507							/* String is always the 'fallback' option */
508							oCol.sType = 'string';
509						}
510					}
511				}
512			}
513			
514			/* Add to the display array */
515			oSettings.aiDisplayMaster.push( iRow );
516		
517			/* Create the DOM information */
518			if ( !oSettings.oFeatures.bDeferRender )
519			{
520				_fnCreateTr( oSettings, iRow );
521			}
522		
523			return iRow;
524		}
525		
526		
527		/**
528		 * Read in the data from the target table from the DOM
529		 *  @param {object} oSettings dataTables settings object
530		 *  @memberof DataTable#oApi
531		 */
532		function _fnGatherData( oSettings )
533		{
534			var iLoop, i, iLen, j, jLen, jInner,
535			 	nTds, nTrs, nTd, nTr, aLocalData, iThisIndex,
536				iRow, iRows, iColumn, iColumns, sNodeName,
537				oCol, oData;
538			
539			/*
540			 * Process by row first
541			 * Add the data object for the whole table - storing the tr node. Note - no point in getting
542			 * DOM based data if we are going to go and replace it with Ajax source data.
543			 */
544			if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
545			{
546				nTr = oSettings.nTBody.firstChild;
547				while ( nTr )
548				{
549					if ( nTr.nodeName.toUpperCase() == "TR" )
550					{
551						iThisIndex = oSettings.aoData.length;
552						nTr._DT_RowIndex = iThisIndex;
553						oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
554							"nTr": nTr
555						} ) );
556		
557						oSettings.aiDisplayMaster.push( iThisIndex );
558						nTd = nTr.firstChild;
559						jInner = 0;
560						while ( nTd )
561						{
562							sNodeName = nTd.nodeName.toUpperCase();
563							if ( sNodeName == "TD" || sNodeName == "TH" )
564							{
565								_fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );
566								jInner++;
567							}
568							nTd = nTd.nextSibling;
569						}
570					}
571					nTr = nTr.nextSibling;
572				}
573			}
574			
575			/* Gather in the TD elements of the Table - note that this is basically the same as
576			 * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
577			 * setup!
578			 */
579			nTrs = _fnGetTrNodes( oSettings );
580			nTds = [];
581			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
582			{
583				nTd = nTrs[i].firstChild;
584				while ( nTd )
585				{
586					sNodeName = nTd.nodeName.toUpperCase();
587					if ( sNodeName == "TD" || sNodeName == "TH" )
588					{
589						nTds.push( nTd );
590					}
591					nTd = nTd.nextSibling;
592				}
593			}
594			
595			/* Now process by column */
596			for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
597			{
598				oCol = oSettings.aoColumns[iColumn];
599		
600				/* Get the title of the column - unless there is a user set one */
601				if ( oCol.sTitle === null )
602				{
603					oCol.sTitle = oCol.nTh.innerHTML;
604				}
605				
606				var
607					bAutoType = oCol._bAutoType,
608					bRender = typeof oCol.fnRender === 'function',
609					bClass = oCol.sClass !== null,
610					bVisible = oCol.bVisible,
611					nCell, sThisType, sRendered, sValType;
612				
613				/* A single loop to rule them all (and be more efficient) */
614				if ( bAutoType || bRender || bClass || !bVisible )
615				{
616					for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
617					{
618						oData = oSettings.aoData[iRow];
619						nCell = nTds[ (iRow*iColumns) + iColumn ];
620						
621						/* Type detection */
622						if ( bAutoType && oCol.sType != 'string' )
623						{
624							sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
625							if ( sValType !== '' )
626							{
627								sThisType = _fnDetectType( sValType );
628								if ( oCol.sType === null )
629								{
630									oCol.sType = sThisType;
631								}
632								else if ( oCol.sType != sThisType && 
633								          oCol.sType != "html" )
634								{
635									/* String is always the 'fallback' option */
636									oCol.sType = 'string';
637								}
638							}
639						}
640		
641						if ( oCol.mRender )
642						{
643							// mRender has been defined, so we need to get the value and set it
644							nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
645						}
646						else if ( oCol.mData !== iColumn )
647						{
648							// If mData is not the same as the column number, then we need to
649							// get the dev set value. If it is the column, no point in wasting
650							// time setting the value that is already there!
651							nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
652						}
653						
654						/* Rendering */
655						if ( bRender )
656						{
657							sRendered = _fnRender( oSettings, iRow, iColumn );
658							nCell.innerHTML = sRendered;
659							if ( oCol.bUseRendered )
660							{
661								/* Use the rendered data for filtering / sorting */
662								_fnSetCellData( oSettings, iRow, iColumn, sRendered );
663							}
664						}
665						
666						/* Classes */
667						if ( bClass )
668						{
669							nCell.className += ' '+oCol.sClass;
670						}
671						
672						/* Column visibility */
673						if ( !bVisible )
674						{
675							oData._anHidden[iColumn] = nCell;
676							nCell.parentNode.removeChild( nCell );
677						}
678						else
679						{
680							oData._anHidden[iColumn] = null;
681						}
682		
683						if ( oCol.fnCreatedCell )
684						{
685							oCol.fnCreatedCell.call( oSettings.oInstance,
686								nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
687							);
688						}
689					}
690				}
691			}
692		
693			/* Row created callbacks */
694			if ( oSettings.aoRowCreatedCallback.length !== 0 )
695			{
696				for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
697				{
698					oData = oSettings.aoData[i];
699					_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
700				}
701			}
702		}
703		
704		
705		/**
706		 * Take a TR element and convert it to an index in aoData
707		 *  @param {object} oSettings dataTables settings object
708		 *  @param {node} n the TR element to find
709		 *  @returns {int} index if the node is found, null if not
710		 *  @memberof DataTable#oApi
711		 */
712		function _fnNodeToDataIndex( oSettings, n )
713		{
714			return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
715		}
716		
717		
718		/**
719		 * Take a TD element and convert it into a column data index (not the visible index)
720		 *  @param {object} oSettings dataTables settings object
721		 *  @param {int} iRow The row number the TD/TH can be found in
722		 *  @param {node} n The TD/TH element to find
723		 *  @returns {int} index if the node is found, -1 if not
724		 *  @memberof DataTable#oApi
725		 */
726		function _fnNodeToColumnIndex( oSettings, iRow, n )
727		{
728			var anCells = _fnGetTdNodes( oSettings, iRow );
729		
730			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
731			{
732				if ( anCells[i] === n )
733				{
734					return i;
735				}
736			}
737			return -1;
738		}
739		
740		
741		/**
742		 * Get an array of data for a given row from the internal data cache
743		 *  @param {object} oSettings dataTables settings object
744		 *  @param {int} iRow aoData row id
745		 *  @param {string} sSpecific data get type ('type' 'filter' 'sort')
746		 *  @param {array} aiColumns Array of column indexes to get data from
747		 *  @returns {array} Data array
748		 *  @memberof DataTable#oApi
749		 */
750		function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )
751		{
752			var out = [];
753			for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )
754			{
755				out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );
756			}
757			return out;
758		}
759		
760		
761		/**
762		 * Get the data for a given cell from the internal cache, taking into account data mapping
763		 *  @param {object} oSettings dataTables settings object
764		 *  @param {int} iRow aoData row id
765		 *  @param {int} iCol Column index
766		 *  @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
767		 *  @returns {*} Cell data
768		 *  @memberof DataTable#oApi
769		 */
770		function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
771		{
772			var sData;
773			var oCol = oSettings.aoColumns[iCol];
774			var oData = oSettings.aoData[iRow]._aData;
775		
776			if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
777			{
778				if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
779				{
780					_fnLog( oSettings, 0, "Requested unknown parameter "+
781						(typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+
782						" from the data source for row "+iRow );
783					oSettings.iDrawError = oSettings.iDraw;
784				}
785				return oCol.sDefaultContent;
786			}
787		
788			/* When the data source is null, we can use default column data */
789			if ( sData === null && oCol.sDefaultContent !== null )
790			{
791				sData = oCol.sDefaultContent;
792			}
793			else if ( typeof sData === 'function' )
794			{
795				/* If the data source is a function, then we run it and use the return */
796				return sData();
797			}
798		
799			if ( sSpecific == 'display' && sData === null )
800			{
801				return '';
802			}
803			return sData;
804		}
805		
806		
807		/**
808		 * Set the value for a specific cell, into the internal data cache
809		 *  @param {object} oSettings dataTables settings object
810		 *  @param {int} iRow aoData row id
811		 *  @param {int} iCol Column index
812		 *  @param {*} val Value to set
813		 *  @memberof DataTable#oApi
814		 */
815		function _fnSetCellData( oSettings, iRow, iCol, val )
816		{
817			var oCol = oSettings.aoColumns[iCol];
818			var oData = oSettings.aoData[iRow]._aData;
819		
820			oCol.fnSetData( oData, val );
821		}
822		
823		
824		// Private variable that is used to match array syntax in the data property object
825		var __reArray = /\[.*?\]$/;
826		
827		/**
828		 * Return a function that can be used to get data from a source object, taking
829		 * into account the ability to use nested objects as a source
830		 *  @param {string|int|function} mSource The data source for the object
831		 *  @returns {function} Data get function
832		 *  @memberof DataTable#oApi
833		 */
834		function _fnGetObjectDataFn( mSource )
835		{
836			if ( mSource === null )
837			{
838				/* Give an empty string for rendering / sorting etc */
839				return function (data, type) {
840					return null;
841				};
842			}
843			else if ( typeof mSource === 'function' )
844			{
845				return function (data, type, extra) {
846					return mSource( data, type, extra );
847				};
848			}
849			else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
850			{
851				/* If there is a . in the source string then the data source is in a 
852				 * nested object so we loop over the data for each level to get the next
853				 * level down. On each loop we test for undefined, and if found immediately
854				 * return. This allows entire objects to be missing and sDefaultContent to
855				 * be used if defined, rather than throwing an error
856				 */
857				var fetchData = function (data, type, src) {
858					var a = src.split('.');
859					var arrayNotation, out, innerSrc;
860		
861					if ( src !== "" )
862					{
863						for ( var i=0, iLen=a.length ; i<iLen ; i++ )
864						{
865							// Check if we are dealing with an array notation request
866							arrayNotation = a[i].match(__reArray);
867		
868							if ( arrayNotation ) {
869								a[i] = a[i].replace(__reArray, '');
870		
871								// Condition allows simply [] to be passed in
872								if ( a[i] !== "" ) {
873									data = data[ a[i] ];
874								}
875								out = [];
876								
877								// Get the remainder of the nested object to get
878								a.splice( 0, i+1 );
879								innerSrc = a.join('.');
880		
881								// Traverse each entry in the array getting the properties requested
882								for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
883									out.push( fetchData( data[j], type, innerSrc ) );
884								}
885		
886								// If a string is given in between the array notation indicators, that
887								// is used to join the strings together, otherwise an array 
887is returned
888								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
889								data = (join==="") ? out : out.join(join);
890		
891								// The inner call to fetchData has already traversed through the remainder
892								// of the source requested, so we exit from the loop
893								break;
894							}
895		
896							if ( data === null || data[ a[i] ] === undefined )
897							{
898								return undefined;
899							}
900							data = data[ a[i] ];
901						}
902					}
903		
904					return data;
905				};
906		
907				return function (data, type) {
908					return fetchData( data, type, mSource );
909				};
910			}
911			else
912			{
913				/* Array or flat object mapping */
914				return function (data, type) {
915					return data[mSource];	
916				};
917			}
918		}
919		
920		
921		/**
922		 * Return a function that can be used to set data from a source object, taking
923		 * into account the ability to use nested objects as a source
924		 *  @param {string|int|function} mSource The data source for the object
925		 *  @returns {function} Data set function
926		 *  @memberof DataTable#oApi
927		 */
928		function _fnSetObjectDataFn( mSource )
929		{
930			if ( mSource === null )
931			{
932				/* Nothing to do when the data source is null */
933				return function (data, val) {};
934			}
935			else if ( typeof mSource === 'function' )
936			{
937				return function (data, val) {
938					mSource( data, 'set', val );
939				};
940			}
941			else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
942			{
943				/* Like the get, we need to get data from a nested object */
944				var setData = function (data, val, src) {
945					var a = src.split('.'), b;
946					var arrayNotation, o, innerSrc;
947		
948					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
949					{
950						// Check if we are dealing with an array notation request
951						arrayNotation = a[i].match(__reArray);
952		
953						if ( arrayNotation )
954						{
955							a[i] = a[i].replace(__reArray, '');
956							data[ a[i] ] = [];
957							
958							// Get the remainder of the nested object to set so we can recurse
959							b = a.slice();
960							b.splice( 0, i+1 );
961							innerSrc = b.join('.');
962		
963							// Traverse each entry in the array setting the properties requested
964							for ( var j=0, jLen=val.length ; j<jLen ; j++ )
965							{
966								o = {};
967								setData( o, val[j], innerSrc );
968								data[ a[i] ].push( o );
969							}
970		
971							// The inner call to setData has already traversed through the remainder
972							// of the source and has set the data, thus we can exit here
973							return;
974						}
975		
976						// If the nested object doesn't currently exist - since we are
977						// trying to set the value - create it
978						if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
979						{
980							data[ a[i] ] = {};
981						}
982						data = data[ a[i] ];
983					}
984		
985					// If array notation is used, we just want to strip it and use the property name
986					// and assign the value. If it isn't used, then we get the result we want anyway
987					data[ a[a.length-1].replace(__reArray, '') ] = val;
988				};
989		
990				return function (data, val) {
991					return setData( data, val, mSource );
992				};
993			}
994			else
995			{
996				/* Array or flat object mapping */
997				return function (data, val) {
998					data[mSource] = val;	
999				};
1000			}
1001		}
1002		
1003		
1004		/**
1005		 * Return an array with the full table data
1006		 *  @param {object} oSettings dataTables settings object
1007		 *  @returns array {array} aData Master data array
1008		 *  @memberof DataTable#oApi
1009		 */
1010		function _fnGetDataMaster ( oSettings )
1011		{
1012			var aData = [];
1013			var iLen = oSettings.aoData.length;
1014			for ( var i=0 ; i<iLen; i++ )
1015			{
1016				aData.push( oSettings.aoData[i]._aData );
1017			}
1018			return aData;
1019		}
1020		
1021		
1022		/**
1023		 * Nuke the table
1024		 *  @param {object} oSettings dataTables settings object
1025		 *  @memberof DataTable#oApi
1026		 */
1027		function _fnClearTable( oSettings )
1028		{
1029			oSettings.aoData.splice( 0, oSettings.aoData.length );
1030			oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
1031			oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
1032			_fnCalculateEnd( oSettings );
1033		}
1034		
1035		
1036		 /**
1037		 * Take an array of integers (index array) and remove a target integer (value - not 
1038		 * the key!)
1039		 *  @param {array} a Index array to target
1040		 *  @param {int} iTarget value to find
1041		 *  @memberof DataTable#oApi
1042		 */
1043		function _fnDeleteIndex( a, iTarget )
1044		{
1045			var iTargetIndex = -1;
1046			
1047			for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1048			{
1049				if ( a[i] == iTarget )
1050				{
1051					iTargetIndex = i;
1052				}
1053				else if ( a[i] > iTarget )
1054				{
1055					a[i]--;
1056				}
1057			}
1058			
1059			if ( iTargetIndex != -1 )
1060			{
1061				a.splice( iTargetIndex, 1 );
1062			}
1063		}
1064		
1065		
1066		 /**
1067		 * Call the developer defined fnRender function for a given cell (row/column) with
1068		 * the required parameters and return the result.
1069		 *  @param {object} oSettings dataTables settings object
1070		 *  @param {int} iRow aoData index for the row
1071		 *  @param {int} iCol aoColumns index for the column
1072		 *  @returns {*} Return of the developer's fnRender function
1073		 *  @memberof DataTable#oApi
1074		 */
1075		function _fnRender( oSettings, iRow, iCol )
1076		{
1077			var oCol = oSettings.aoColumns[iCol];
1078		
1079			return oCol.fnRender( {
1080				"iDataRow":    iRow,
1081				"iDataColumn": iCol,
1082				"oSettings":   oSettings,
1083				"aData":       oSettings.aoData[iRow]._aData,
1084				"mDataProp":   oCol.mData
1085			}, _fnGetCellData(oSettings, iRow, iCol, 'display') );
1086		}
1087		/**
1088		 * Create a new TR element (and it's TD children) for a row
1089		 *  @param {object} oSettings dataTables settings object
1090		 *  @param {int} iRow Row to consider
1091		 *  @memberof DataTable#oApi
1092		 */
1093		function _fnCreateTr ( oSettings, iRow )
1094		{
1095			var oData = oSettings.aoData[iRow];
1096			var nTd;
1097		
1098			if ( oData.nTr === null )
1099			{
1100				oData.nTr = document.createElement('tr');
1101		
1102				/* Use a private property on the node to allow reserve mapping from the node
1103				 * to the aoData array for fast look up
1104				 */
1105				oData.nTr._DT_RowIndex = iRow;
1106		
1107				/* Special parameters can be given by the data source to be used on the row */
1108				if ( oData._aData.DT_RowId )
1109				{
1110					oData.nTr.id = oData._aData.DT_RowId;
1111				}
1112		
1113				if ( oData._aData.DT_RowClass )
1114				{
1115					oData.nTr.className = oData._aData.DT_RowClass;
1116				}
1117		
1118				/* Process each column */
1119				for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1120				{
1121					var oCol = oSettings.aoColumns[i];
1122					nTd = document.createElement( oCol.sCellType );
1123		
1124					/* Render if needed - if bUseRendered is true then we already have the rendered
1125					 * value in the data source - so can just use that
1126					 */
1127					nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ?
1128						_fnRender( oSettings, iRow, i ) :
1129						_fnGetCellData( oSettings, iRow, i, 'display' );
1130				
1131					/* Add user defined class */
1132					if ( oCol.sClass !== null )
1133					{
1134						nTd.className = oCol.sClass;
1135					}
1136					
1137					if ( oCol.bVisible )
1138					{
1139						oData.nTr.appendChild( nTd );
1140						oData._anHidden[i] = null;
1141					}
1142					else
1143					{
1144						oData._anHidden[i] = nTd;
1145					}
1146		
1147					if ( oCol.fnCreatedCell )
1148					{
1149						oCol.fnCreatedCell.call( oSettings.oInstance,
1150							nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i
1151						);
1152					}
1153				}
1154		
1155				_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );
1156			}
1157		}
1158		
1159		
1160		/**
1161		 * Create the HTML header for the table
1162		 *  @param {object} oSettings dataTables settings object
1163		 *  @memberof DataTable#oApi
1164		 */
1165		function _fnBuildHead( oSettings )
1166		{
1167			var i, nTh, iLen, j, jLen;
1168			var iThs = $('th, td', oSettings.nTHead).length;
1169			var iCorrector = 0;
1170			var jqChildren;
1171			
1172			/* If there is a header in place - then use it - otherwise it's going to get nuked... */
1173			if ( iThs !== 0 )
1174			{
1175				/* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
1176				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1177				{
1178					nTh = oSettings.aoColumns[i].nTh;
1179					nTh.setAttribute('role', 'columnheader');
1180					if ( oSettings.aoColumns[i].bSortable )
1181					{
1182						nTh.setAttribute('tabindex', oSettings.iTabIndex);
1183						nTh.setAttribute('aria-controls', oSettings.sTableId);
1184					}
1185		
1186					if ( oSettings.aoColumns[i].sClass !== null )
1187					{
1188						$(nTh).addClass( oSettings.aoColumns[i].sClass );
1189					}
1190					
1191					/* Set the title of the column if it is user defined (not what was auto detected) */
1192					if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
1193					{
1194						nTh.innerHTML = oSettings.aoColumns[i].sTitle;
1195					}
1196				}
1197			}
1198			else
1199			{
1200				/* We don't have a header in the DOM - so we are going to have to create one */
1201				var nTr = document.createElement( "tr" );
1202				
1203				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1204				{
1205					nTh = oSettings.aoColumns[i].nTh;
1206					nTh.innerHTML = oSettings.aoColumns[i].sTitle;
1207					nTh.setAttribute('tabindex', '0');
1208					
1209					if ( oSettings.aoColumns[i].sClass !== null )
1210					{
1211						$(nTh).addClass( oSettings.aoColumns[i].sClass );
1212					}
1213					
1214					nTr.appendChild( nTh );
1215				}
1216				$(oSettings.nTHead).html( '' )[0].appendChild( nTr );
1217				_fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
1218			}
1219			
1220			/* ARIA role for the rows */	
1221			$(oSettings.nTHead).children('tr').attr('role', 'row');
1222			
1223			/* Add the extra markup needed by jQuery UI's themes */
1224			if ( oSettings.bJUI )
1225			{
1226				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1227				{
1228					nTh = oSettings.aoColumns[i].nTh;
1229					
1230					var nDiv = document.createElement('div');
1231					nDiv.className = oSettings.oClasses.sSortJUIWrapper;
1232					$(nTh).contents().appendTo(nDiv);
1233					
1234					var nSpan = document.createElement('span');
1235					nSpan.className = oSettings.oClasses.sSortIcon;
1236					nDiv.appendChild( nSpan );
1237					nTh.appendChild( nDiv );
1238				}
1239			}
1240			
1241			if ( oSettings.oFeatures.bSort )
1242			{
1243				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
1244				{
1245					if ( oSettings.aoColumns[i].bSortable !== false )
1246					{
1247						_fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
1248					}
1249					else
1250					{
1251						$(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
1252					}
1253				}
1254			}
1255			
1256			/* Deal with the footer - add classes if required */
1257			if ( oSettings.oClasses.sFooterTH !== "" )
1258			{
1259				$(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
1260			}
1261			
1262			/* Cache the footer elements */
1263			if ( oSettings.nTFoot !== null )
1264			{
1265				var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
1266				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1267				{
1268					if ( anCells[i] )
1269					{
1270						oSettings.aoColumns[i].nTf = anCells[i];
1271						if ( oSettings.aoColumns[i].sClass )
1272						{
1273							$(anCells[i]).addClass( oSettings.aoColumns[i].sClass );
1274						}
1275					}
1276				}
1277			}
1278		}
1279		
1280		
1281		/**
1282		 * Draw the header (or footer) element based on the column visibility states. The
1283		 * methodology here is to use the layout array from _fnDetectHeader, modified for
1284		 * the instantaneous column visibility, to construct the new layout. The grid is
1285		 * traversed over cell at a time in a rows x columns grid fashion, although each 
1286		 * cell insert can cover multiple elements in the grid - which is tracks using the
1287		 * aApplied array. Cell inserts in the grid will only occur where there isn't
1288		 * already a cell in that position.
1289		 *  @param {object} oSettings dataTables settings object
1290		 *  @param array {objects} aoSource Layout array from _fnDetectHeader
1291		 *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 
1292		 *  @memberof DataTable#oApi
1293		 */
1294		function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1295		{
1296			var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1297			var aoLocal = [];
1298			var aApplied = [];
1299			var iColumns = oSettings.aoColumns.length;
1300			var iRowspan, iColspan;
1301		
1302			if (  bIncludeHidden === undefined )
1303			{
1304				bIncludeHidden = false;
1305			}
1306		
1307			/* Make a copy of the master layout array, but without the visible columns in it */
1308			for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1309			{
1310				aoLocal[i] = aoSource[i].slice();
1311				aoLocal[i].nTr = aoSource[i].nTr;
1312		
1313				/* Remove any columns which are currently hidden */
1314				for ( j=iColumns-1 ; j>=0 ; j-- )
1315				{
1316					if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1317					{
1318						aoLocal[i].splice( j, 1 );
1319					}
1320				}
1321		
1322				/* Prep the applied array - it needs an element for each row */
1323				aApplied.push( [] );
1324			}
1325		
1326			for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1327			{
1328				nLocalTr = aoLocal[i].nTr;
1329				
1330				/* All cells are going to be replaced, so empty out the row */
1331				if ( nLocalTr )
1332				{
1333					while( (n = nLocalTr.firstChild) )
1334					{
1335						nLocalTr.removeChild( n );
1336					}
1337				}
1338		
1339				for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1340				{
1341					iRowspan = 1;
1342					iColspan = 1;
1343		
1344					/* Check to see if there is already a cell (row/colspan) covering our target
1345					 * insert point. If there is, then there is nothing to do.
1346					 */
1347					if ( aApplied[i][j] === undefined )
1348					{
1349						nLocalTr.appendChild( aoLocal[i][j].cell );
1350						aApplied[i][j] = 1;
1351		
1352						/* Expand the cell to cover as many rows as needed */
1353						while ( aoLocal[i+iRowspan] !== undefined &&
1354						        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1355						{
1356							aApplied[i+iRowspan][j] = 1;
1357							iRowspan++;
1358						}
1359		
1360						/* Expand the cell to cover as many columns as needed */
1361						while ( aoLocal[i][j+iColspan] !== undefined &&
1362						        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1363						{
1364							/* Must update the applied array over the rows for the columns */
1365							for ( k=0 ; k<iRowspan ; k++ )
1366							{
1367								aApplied[i+k][j+iColspan] = 1;
1368							}
1369							iColspan++;
1370						}
1371		
1372						/* Do the actual expansion in the DOM */
1373						aoLocal[i][j].cell.rowSpan = iRowspan;
1374						aoLocal[i][j].cell.colSpan = iColspan;
1375					}
1376				}
1377			}
1378		}
1379		
1380		
1381		/**
1382		 * Insert the required TR nodes into the table for display
1383		 *  @param {object} oSettings dataTables settings object
1384		 *  @memberof DataTable#oApi
1385		 */
1386		function _fnDraw( oSettings )
1387		{
1388			/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1389			var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1390			if ( $.inArray( false, aPreDraw ) !== -1 )
1391			{
1392				_fnProcessingDisplay( oSettings, false );
1393				return;
1394			}
1395			
1396			var i, iLen, n;
1397			var anRows = [];
1398			var iRowCount = 0;
1399			var iStripes = oSettings.asStripeClasses.length;
1400			var iOpenRows = oSettings.aoOpenRows.length;
1401			
1402			oSettings.bDrawing = true;
1403			
1404			/* Check and see if we have an initial draw position from state saving */
1405			if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 )
1406			{
1407				if ( oSettings.oFeatures.bServerSide )
1408				{
1409					oSettings._iDisplayStart = oSettings.iInitDisplayStart;
1410				}
1411				else
1412				{
1413					oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
1414						0 : oSettings.iInitDisplayStart;
1415				}
1416				oSettings.iInitDisplayStart = -1;
1417				_fnCalculateEnd( oSettings );
1418			}
1419			
1420			/* Server-side processing draw intercept */
1421			if ( oSettings.bDeferLoading )
1422			{
1423				oSettings.bDeferLoading = false;
1424				oSettings.iDraw++;
1425			}
1426			else if ( !oSettings.oFeatures.bServerSide )
1427			{
1428				oSettings.iDraw++;
1429			}
1430			else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
1431			{
1432				return;
1433			}
1434			
1435			if ( oSettings.aiDisplay.length !== 0 )
1436			{
1437				var iStart = oSettings._iDisplayStart;
1438				var iEnd = oSettings._iDisplayEnd;
1439				
1440				if ( oSettings.oFeatures.bServerSide )
1441				{
1442					iStart = 0;
1443					iEnd = oSettings.aoData.length;
1444				}
1445				
1446				for ( var j=iStart ; j<iEnd ; j++ )
1447				{
1448					var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
1449					if ( aoData.nTr === null )
1450					{
1451						_fnCreateTr( oSettings, oSettings.aiDisplay[j] );
1452					}
1453		
1454					var nRow = aoData.nTr;
1455					
1456					/* Remove the old striping classes and then add the new one */
1457					if ( iStripes !== 0 )
1458					{
1459						var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];
1460						if ( aoData._sRowStripe != sStripe )
1461						{
1462							$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
1463							aoData._sRowStripe = sStripe;
1464						}
1465					}
1466					
1467					/* Row callback functions - might want to manipulate the row */
1468					_fnCallbackFire( oSettings, 'aoRowCallback', null, 
1469						[nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] );
1470					
1471					anRows.push( nRow );
1472					iRowCount++;
1473					
1474					/* If there is an open row - and it is attached to this parent - attach it on redraw */
1475					if ( iOpenRows !== 0 )
1476					{
1477						for ( var k=0 ; k<iOpenRows ; k++ )
1478						{
1479							if ( nRow == oSettings.aoOpenRows[k].nParent )
1480							{
1481								anRows.push( oSettings.aoOpenRows[k].nTr );
1482								break;
1483							}
1484						}
1485					}
1486				}
1487			}
1488			else
1489			{
1490				/* Table is empty - create a row with an empty message in it */
1491				anRows[ 0 ] = document.createElement( 'tr' );
1492				
1493				if ( oSettings.asStripeClasses[0] )
1494				{
1495					anRows[ 0 ].className = oSettings.asStripeClasses[0];
1496				}
1497		
1498				var oLang = oSettings.oLanguage;
1499				var sZero = oLang.sZeroRecords;
1500				if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
1501				{
1502					sZero = oLang.sLoadingRecords;
1503				}
1504				else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
1505				{
1506					sZero = oLang.sEmptyTable;
1507				}
1508		
1509				var nTd = document.createElement( 'td' );
1510				nTd.setAttribute( 'valign', "top" );
1511				nTd.colSpan = _fnVisbleColumns( oSettings );
1512				nTd.className = oSettings.oClasses.sRowEmpty;
1513				nTd.innerHTML = _fnInfoMacros( oSettings, sZero );
1514				
1515				anRows[ iRowCount ].appendChild( nTd );
1516			}
1517			
1518			/* Header and footer callbacks */
1519			_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 
1520				_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
1521			
1522			_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 
1523				_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
1524			
1525			/* 
1526			 * Need to remove any old row from the display - note we can't just empty the tbody using
1527			 * $().html('') since this will unbind the jQuery event handlers (even although the node 
1528			 * still exists!) - equally we can't use innerHTML, since IE throws an exception.
1529			 */
1530			var
1531				nAddFrag = document.createDocumentFragment(),
1532				nRemoveFrag = document.createDocumentFragment(),
1533				nBodyPar, nTrs;
1534			
1535			if ( oSettings.nTBody )
1536			{
1537				nBodyPar = oSettings.nTBody.parentNode;
1538				nRemoveFrag.appendChild( oSettings.nTBody );
1539				
1540				/* When doing infinite scrolling, only remove child rows when sorting, filtering or start
1541				 * up. When not infinite scroll, always do it.
1542				 */
1543				if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
1544				 	oSettings.bSorted || oSettings.bFiltered )
1545				{
1546					while( (n = oSettings.nTBody.firstChild) )
1547					{
1548						oSettings.nTBody.removeChild( n );
1549					}
1550				}
1551				
1552				/* Put the draw table into the dom */
1553				for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
1554				{
1555					nAddFrag.appendChild( anRows[i] );
1556				}
1557				
1558				oSettings.nTBody.appendChild( nAddFrag );
1559				if ( nBodyPar !== null )
1560				{
1561					nBodyPar.appendChild( oSettings.nTBody );
1562				}
1563			}
1564			
1565			/* Call all required callback functions for the end of a draw */
1566			_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
1567			
1568			/* Draw is complete, sorting and filtering must be as well */
1569			oSettings.bSorted = false;
1570			oSettings.bFiltered = false;
1571			oSettings.bDrawing = false;
1572			
1573			if ( oSettings.oFeatures.bServerSide )
1574			{
1575				_fnProcessingDisplay( oSettings, false );
1576				if ( !oSettings._bInitComplete )
1577				{
1578					_fnInitComplete( oSettings );
1579				}
1580			}
1581		}
1582		
1583		
1584		/**
1585		 * Redraw the table - taking account of the various features which are enabled
1586		 *  @param {object} oSettings dataTables settings object
1587		 *  @memberof DataTable#oApi
1588		 */
1589		function _fnReDraw( oSettings )
1590		{
1591			if ( oSettings.oFeatures.bSort )
1592			{
1593				/* Sorting will refilter and draw for us */
1594				_fnSort( oSettings, oSettings.oPreviousSearch );
1595			}
1596			else if ( oSettings.oFeatures.bFilter )
1597			{
1598				/* Filtering will redraw for us */
1599				_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
1600			}
1601			else
1602			{
1603				_fnCalculateEnd( oSettings );
1604				_fnDraw( oSettings );
1605			}
1606		}
1607		
1608		
1609		/**
1610		 * Add the options to the page HTML for the table
1611		 *  @param {object} oSettings dataTables settings object
1612		 *  @memberof DataTable#oApi
1613		 */
1614		function _fnAddOptionsHtml ( oSettings )
1615		{
1616			/*
1617			 * Create a temporary, empty, div which we can later on replace with what we have generated
1618			 * we do it this way to rendering the 'options' html offline - speed :-)
1619			 */
1620			var nHolding = $('<div></div>')[0];
1621			oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
1622			
1623			/* 
1624			 * All DataTables are wrapped in a div
1625			 */
1626			oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0];
1627			oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
1628		
1629			/* Track where we want to insert the option */
1630			var nInsertNode = oSettings.nTableWrapper;
1631			
1632			/* Loop over the user set positioning and place the elements as needed */
1633			var aDom = oSettings.sDom.split('');
1634			var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
1635			for ( var i=0 ; i<aDom.length ; i++ )
1636			{
1637				iPushFeature = 0;
1638				cOption = aDom[i];
1639				
1640				if ( cOption == '<' )
1641				{
1642					/* New container div */
1643					nNewNode = $('<div></div>')[0];
1644					
1645					/* Check to see if we should append an id and/or a class name to the container */
1646					cNext = aDom[i+1];
1647					if ( cNext == "'" || cNext == '"' )
1648					{
1649						sAttr = "";
1650						j = 2;
1651						while ( aDom[i+j] != cNext )
1652						{
1653							sAttr += aDom[i+j];
1654							j++;
1655						}
1656						
1657						/* Replace jQuery UI constants */
1658						if ( sAttr == "H" )
1659						{
1660							sAttr = oSettings.oClasses.sJUIHeader;
1661						}
1662						else if ( sAttr == "F" )
1663						{
1664							sAttr = oSettings.oClasses.sJUIFooter;
1665						}
1666						
1667						/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
1668						 * breaks the string into parts and applies them as needed
1669						 */
1670						if ( sAttr.indexOf('.') != -1 )
1671						{
1672							var aSplit = sAttr.split('.');
1673							nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
1674							nNewNode.className = aSplit[1];
1675						}
1676						else if ( sAttr.charAt(0) == "#" )
1677						{
1678							nNewNode.id = sAttr.substr(1, sAttr.length-1);
1679						}
1680						else
1681						{
1682							nNewNode.className = sAttr;
1683						}
1684						
1685						i += j; /* Move along the position array */
1686					}
1687					
1688					nInsertNode.appendChild( nNewNode );
1689					nInsertNode = nNewNode;
1690				}
1691				else if ( cOption == '>' )
1692				{
1693					/* End container div */
1694					nInsertNode = nInsertNode.parentNode;
1695				}
1696				else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
1697				{
1698					/* Length */
1699					nTmp = _fnFeatureHtmlLength( oSettings );
1700					iPushFeature = 1;
1701				}
1702				else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
1703				{
1704					/* Filter */
1705					nTmp = _fnFeatureHtmlFilter( oSettings );
1706					iPushFeature = 1;
1707				}
1708				else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
1709				{
1710					/* pRocessing */
1711					nTmp = _fnFeatureHtmlProcessing( oSettings );
1712					iPushFeature = 1;
1713				}
1714				else if ( cOption == 't' )
1715				{
1716					/* Table */
1717					nTmp = _fnFeatureHtmlTable( oSettings );
1718					iPushFeature = 1;
1719				}
1720				else if ( cOption ==  'i' && oSettings.oFeatures.bInfo )
1721				{
1722					/* Info */
1723					nTmp = _fnFeatureHtmlInfo( oSettings );
1724					iPushFeature = 1;
1725				}
1726				else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
1727				{
1728					/* Pagination */
1729					nTmp = _fnFeatureHtmlPaginate( oSettings );
1730					iPushFeature = 1;
1731				}
1732				else if ( DataTable.ext.aoFeatures.length !== 0 )
1733				{
1734					/* Plug-in features */
1735					var aoFeatures = DataTable.ext.aoFeatures;
1736					for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
1737					{
1738						if ( cOption == aoFeatures[k].cFeature )
1739						{
1740							nTmp = aoFeatures[k].fnInit( oSettings );
1741							if ( nTmp )
1742							{
1743								iPushFeature = 1;
1744							}
1745							break;
1746						}
1747					}
1748				}
1749				
1750				/* Add to the 2D features array */
1751				if ( iPushFeature == 1 && nTmp !== null )
1752				{
1753					if ( typeof oSettings.aanFeatures[cOption] !== 'object' )
1754					{
1755						oSettings.aanFeatures[cOption] = [];
1756					}
1757					oSettings.aanFeatures[cOption].push( nTmp );
1758					nInsertNode.appendChild( nTmp );
1759				}
1760			}
1761			
1762			/* Built our DOM structure - replace the holding div with what we want */
1763			nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
1764		}
1765		
1766		
1767		/**
1768		 * Use the DOM source to create up an array of header cells. The idea here is to
1769		 * create a layout grid (array) of rows x columns, which contains a reference
1770		 * to the cell that that point in the grid (regardless of col/rowspan), such that
1771		 * any column / row could be removed and the new grid constructed
1772		 *  @param array {object} aLayout Array to store the calculated layout in
1773		 *  @param {node} nThead The header/footer element for the table
1774		 *  @memberof DataTable#oApi
1775		 */
1776		function _fnDetectHeader ( aLayout, nThead )
1777		{
1778			var nTrs = $(nThead).children('tr');
1779			var nTr, nCell;
1780			var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
1781			var bUnique;
1782			var fnShiftCol = function ( a, i, j ) {
1783				var k = a[i];
1784		                while ( k[j] ) {
1785					j++;
1786				}
1787				return j;
1788			};
1789		
1790			aLayout.splice( 0, aLayout.length );
1791			
1792			/* We know how many rows there are in the layout - so prep it */
1793			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
1794			{
1795				aLayout.push( [] );
1796			}
1797			
1798			/* Calculate a layout array */
1799			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
1800			{
1801				nTr = nTrs[i];
1802				iColumn = 0;
1803				
1804				/* For every cell in the row... */
1805				nCell = nTr.firstChild;
1806				while ( nCell ) {
1807					if ( nCell.nodeName.toUpperCase() == "TD" ||
1808					     nCell.nodeName.toUpperCase() == "TH" )
1809					{
1810						/* Get the col and rowspan attributes from the DOM and sanitise them */
1811						iColspan = nCell.getAttribute('colspan') * 1;
1812						iRowspan = nCell.getAttribute('rowspan') * 1;
1813						iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
1814						iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
1815		
1816						/* There might be colspan cells already in this row, so shift our target 
1817						 * accordingly
1818						 */
1819						iColShifted = fnShiftCol( aLayout, i, iColumn );
1820						
1821						/* Cache calculation for unique columns */
1822						bUnique = iColspan === 1 ? true : false;
1823						
1824						/* If there is col / rowspan, copy the information into the layout grid */
1825						for ( l=0 ; l<iColspan ; l++ )
1826						{
1827							for ( k=0 ; k<iRowspan ; k++ )
1828							{
1829								aLayout[i+k][iColShifted+l] = {
1830									"cell": nCell,
1831									"unique": bUnique
1832								};
1833								aLayout[i+k].nTr = nTr;
1834							}
1835						}
1836					}
1837					nCell = nCell.nextSibling;
1838				}
1839			}
1840		}
1841		
1842		
1843		/**
1844		 * Get an array of unique th elements, one for each column
1845		 *  @param {object} oSettings dataTables settings object
1846		 *  @param {node} nHeader automatically detect the layout from this node - optional
1847		 *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
1848		 *  @returns array {node} aReturn list of unique th's
1849		 *  @memberof DataTable#oApi
1850		 */
1851		function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
1852		{
1853			var aReturn = [];
1854			if ( !aLayout )
1855			{
1856				aLayout = oSettings.aoHeader;
1857				if ( nHeader )
1858				{
1859					aLayout = [];
1860					_fnDetectHeader( aLayout, nHeader );
1861				}
1862			}
1863		
1864			for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
1865			{
1866				for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
1867				{
1868					if ( aLayout[i][j].unique && 
1869						 (!aReturn[j] || !oSettings.bSortCellsTop) )
1870					{
1871						aReturn[j] = aLayout[i][j].cell;
1872					}
1873				}
1874			}
1875			
1876			return aReturn;
1877		}
1878		
1879		
1880		
1881		/**
1882		 * Update the table using an Ajax call
1883		 *  @param {object} oSettings dataTables settings object
1884		 *  @returns {boolean} Block the table drawing or not
1885		 *  @memberof DataTable#oApi
1886		 */
1887		function _fnAjaxUpdate( oSettings )
1888		{
1889			if ( oSettings.bAjaxDataGet )
1890			{
1891				oSettings.iDraw++;
1892				_fnProcessingDisplay( oSettings, true );
1893				var iColumns = oSettings.aoColumns.length;
1894				var aoData = _fnAjaxParameters( oSettings );
1895				_fnServerParams( oSettings, aoData );
1896				
1897				oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, ao
1897Data,
1898					function(json) {
1899						_fnAjaxUpdateDraw( oSettings, json );
1900					}, oSettings );
1901				return false;
1902			}
1903			else
1904			{
1905				return true;
1906			}
1907		}
1908		
1909		
1910		/**
1911		 * Build up the parameters in an object needed for a server-side processing request
1912		 *  @param {object} oSettings dataTables settings object
1913		 *  @returns {bool} block the table drawing or not
1914		 *  @memberof DataTable#oApi
1915		 */
1916		function _fnAjaxParameters( oSettings )
1917		{
1918			var iColumns = oSettings.aoColumns.length;
1919			var aoData = [], mDataProp, aaSort, aDataSort;
1920			var i, j;
1921			
1922			aoData.push( { "name": "sEcho",          "value": oSettings.iDraw } );
1923			aoData.push( { "name": "iColumns",       "value": iColumns } );
1924			aoData.push( { "name": "sColumns",       "value": _fnColumnOrdering(oSettings) } );
1925			aoData.push( { "name": "iDisplayStart",  "value": oSettings._iDisplayStart } );
1926			aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
1927				oSettings._iDisplayLength : -1 } );
1928				
1929			for ( i=0 ; i<iColumns ; i++ )
1930			{
1931			  mDataProp = oSettings.aoColumns[i].mData;
1932				aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } );
1933			}
1934			
1935			/* Filtering */
1936			if ( oSettings.oFeatures.bFilter !== false )
1937			{
1938				aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
1939				aoData.push( { "name": "bRegex",  "value": oSettings.oPreviousSearch.bRegex } );
1940				for ( i=0 ; i<iColumns ; i++ )
1941				{
1942					aoData.push( { "name": "sSearch_"+i,     "value": oSettings.aoPreSearchCols[i].sSearch } );
1943					aoData.push( { "name": "bRegex_"+i,      "value": oSettings.aoPreSearchCols[i].bRegex } );
1944					aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
1945				}
1946			}
1947			
1948			/* Sorting */
1949			if ( oSettings.oFeatures.bSort !== false )
1950			{
1951				var iCounter = 0;
1952		
1953				aaSort = ( oSettings.aaSortingFixed !== null ) ?
1954					oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
1955					oSettings.aaSorting.slice();
1956				
1957				for ( i=0 ; i<aaSort.length ; i++ )
1958				{
1959					aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort;
1960					
1961					for ( j=0 ; j<aDataSort.length ; j++ )
1962					{
1963						aoData.push( { "name": "iSortCol_"+iCounter,  "value": aDataSort[j] } );
1964						aoData.push( { "name": "sSortDir_"+iCounter,  "value": aaSort[i][1] } );
1965						iCounter++;
1966					}
1967				}
1968				aoData.push( { "name": "iSortingCols",   "value": iCounter } );
1969				
1970				for ( i=0 ; i<iColumns ; i++ )
1971				{
1972					aoData.push( { "name": "bSortable_"+i,  "value": oSettings.aoColumns[i].bSortable } );
1973				}
1974			}
1975			
1976			return aoData;
1977		}
1978		
1979		
1980		/**
1981		 * Add Ajax parameters from plug-ins
1982		 *  @param {object} oSettings dataTables settings object
1983		 *  @param array {objects} aoData name/value pairs to send to the server
1984		 *  @memberof DataTable#oApi
1985		 */
1986		function _fnServerParams( oSettings, aoData )
1987		{
1988			_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] );
1989		}
1990		
1991		
1992		/**
1993		 * Data the data from the server (nuking the old) and redraw the table
1994		 *  @param {object} oSettings dataTables settings object
1995		 *  @param {object} json json data return from the server.
1996		 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
1997		 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
1998		 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
1999		 *  @param {array} json.aaData The data to display on this page
2000		 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
2001		 *  @memberof DataTable#oApi
2002		 */
2003		function _fnAjaxUpdateDraw ( oSettings, json )
2004		{
2005			if ( json.sEcho !== undefined )
2006			{
2007				/* Protect against old returns over-writing a new one. Possible when you get
2008				 * very fast interaction, and later queries are completed much faster
2009				 */
2010				if ( json.sEcho*1 < oSettings.iDraw )
2011				{
2012					return;
2013				}
2014				else
2015				{
2016					oSettings.iDraw = json.sEcho * 1;
2017				}
2018			}
2019			
2020			if ( !oSettings.oScroll.bInfinite ||
2021				   (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
2022			{
2023				_fnClearTable( oSettings );
2024			}
2025			oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10);
2026			oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10);
2027			
2028			/* Determine if reordering is required */
2029			var sOrdering = _fnColumnOrdering(oSettings);
2030			var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering );
2031			var aiIndex;
2032			if ( bReOrder )
2033			{
2034				aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
2035			}
2036			
2037			var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json );
2038			for ( var i=0, iLen=aData.length ; i<iLen ; i++ )
2039			{
2040				if ( bReOrder )
2041				{
2042					/* If we need to re-order, then create a new array with the correct order and add it */
2043					var aDataSorted = [];
2044					for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
2045					{
2046						aDataSorted.push( aData[i][ aiIndex[j] ] );
2047					}
2048					_fnAddData( oSettings, aDataSorted );
2049				}
2050				else
2051				{
2052					/* No re-order required, sever got it "right" - just straight add */
2053					_fnAddData( oSettings, aData[i] );
2054				}
2055			}
2056			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2057			
2058			oSettings.bAjaxDataGet = false;
2059			_fnDraw( oSettings );
2060			oSettings.bAjaxDataGet = true;
2061			_fnProcessingDisplay( oSettings, false );
2062		}
2063		
2064		
2065		
2066		/**
2067		 * Generate the node required for filtering text
2068		 *  @returns {node} Filter control element
2069		 *  @param {object} oSettings dataTables settings object
2070		 *  @memberof DataTable#oApi
2071		 */
2072		function _fnFeatureHtmlFilter ( oSettings )
2073		{
2074			var oPreviousSearch = oSettings.oPreviousSearch;
2075			
2076			var sSearchStr = oSettings.oLanguage.sSearch;
2077			sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ?
2078			  sSearchStr.replace('_INPUT_', '<input type="text" style="width:200px; height:25px; font-size:8pt;" />') :
2079			  sSearchStr==="" ? '<input type="text" style="width:200px; height:25px; font-size:8pt;"  />' : sSearchStr+' <input type="text" style="width:200px; height:25px; font-size:8pt;" />';
2080			
2081			var nFilter = document.createElement( 'div' );
2082			nFilter.className = oSettings.oClasses.sFilter;
2083			nFilter.innerHTML = '<label>'+sSearchStr+'</label>';
2084			if ( !oSettings.aanFeatures.f )
2085			{
2086				nFilter.id = oSettings.sTableId+'_filter';
2087			}
2088			
2089			var jqFilter = $('input[type="text"]', nFilter);
2090		
2091			// Store a reference to the input element, so other input elements could be
2092			// added to the filter wrapper if needed (submit button for example)
2093			nFilter._DT_Input = jqFilter[0];
2094		
2095			jqFilter.val( oPreviousSearch.sSearch.replace('"','&quot;') );
2096			jqFilter.bind( 'keyup.DT', function(e) {
2097				/* Update all other filter input elements for the new display */
2098				var n = oSettings.aanFeatures.f;
2099				var val = this.value==="" ? "" : this.value; // mental IE8 fix :-(
2100		
2101				for ( var i=0, iLen=n.length ; i<iLen ; i++ )
2102				{
2103					if ( n[i] != $(this).parents('div.dataTables_filter')[0] )
2104					{
2105						$(n[i]._DT_Input).val( val );
2106					}
2107				}
2108				
2109				/* Now do the filter */
2110				if ( val != oPreviousSearch.sSearch )
2111				{
2112					_fnFilterComplete( oSettings, { 
2113						"sSearch": val, 
2114						"bRegex": oPreviousSearch.bRegex,
2115						"bSmart": oPreviousSearch.bSmart ,
2116						"bCaseInsensitive": oPreviousSearch.bCaseInsensitive 
2117					} );
2118				}
2119			} );
2120		
2121			jqFilter
2122				.attr('aria-controls', oSettings.sTableId)
2123				.bind( 'keypress.DT', function(e) {
2124					/* Prevent form submission */
2125					if ( e.keyCode == 13 )
2126					{
2127						return false;
2128					}
2129				}
2130			);
2131			
2132			return nFilter;
2133		}
2134		
2135		
2136		/**
2137		 * Filter the table using both the global filter and column based filtering
2138		 *  @param {object} oSettings dataTables settings object
2139		 *  @param {object} oSearch search information
2140		 *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2141		 *  @memberof DataTable#oApi
2142		 */
2143		function _fnFilterComplete ( oSettings, oInput, iForce )
2144		{
2145			var oPrevSearch = oSettings.oPreviousSearch;
2146			var aoPrevSearch = oSettings.aoPreSearchCols;
2147			var fnSaveFilter = function ( oFilter ) {
2148				/* Save the filtering values */
2149				oPrevSearch.sSearch = oFilter.sSearch;
2150				oPrevSearch.bRegex = oFilter.bRegex;
2151				oPrevSearch.bSmart = oFilter.bSmart;
2152				oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2153			};
2154		
2155			/* In server-side processing all filtering is done by the server, so no point hanging around here */
2156			if ( !oSettings.oFeatures.bServerSide )
2157			{
2158				/* Global filter */
2159				_fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );
2160				fnSaveFilter( oInput );
2161		
2162				/* Now do the individual column filter */
2163				for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
2164				{
2165					_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex, 
2166						aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2167				}
2168				
2169				/* Custom filtering */
2170				_fnFilterCustom( oSettings );
2171			}
2172			else
2173			{
2174				fnSaveFilter( oInput );
2175			}
2176			
2177			/* Tell the draw function we have been filtering */
2178			oSettings.bFiltered = true;
2179			$(oSettings.oInstance).trigger('filter', oSettings);
2180			
2181			/* Redraw the table */
2182			oSettings._iDisplayStart = 0;
2183			_fnCalculateEnd( oSettings );
2184			_fnDraw( oSettings );
2185			
2186			/* Rebuild search array 'offline' */
2187			_fnBuildSearchArray( oSettings, 0 );
2188		}
2189		
2190		
2191		/**
2192		 * Apply custom filtering functions
2193		 *  @param {object} oSettings dataTables settings object
2194		 *  @memberof DataTable#oApi
2195		 */
2196		function _fnFilterCustom( oSettings )
2197		{
2198			var afnFilters = DataTable.ext.afnFiltering;
2199			var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
2200		
2201			for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
2202			{
2203				var iCorrector = 0;
2204				for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
2205				{
2206					var iDisIndex = oSettings.aiDisplay[j-iCorrector];
2207					var bTest = afnFilters[i](
2208						oSettings,
2209						_fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),
2210						iDisIndex
2211					);
2212					
2213					/* Check if we should use this row based on the filtering function */
2214					if ( !bTest )
2215					{
2216						oSettings.aiDisplay.splice( j-iCorrector, 1 );
2217						iCorrector++;
2218					}
2219				}
2220			}
2221		}
2222		
2223		
2224		/**
2225		 * Filter the table on a per-column basis
2226		 *  @param {object} oSettings dataTables settings object
2227		 *  @param {string} sInput string to filter on
2228		 *  @param {int} iColumn column to filter
2229		 *  @param {bool} bRegex treat search string as a regular expression or not
2230		 *  @param {bool} bSmart use smart filtering or not
2231		 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
2232		 *  @memberof DataTable#oApi
2233		 */
2234		function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive )
2235		{
2236			if ( sInput === "" )
2237			{
2238				return;
2239			}
2240			
2241			var iIndexCorrector = 0;
2242			var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
2243			
2244			for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
2245			{
2246				var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ),
2247					oSettings.aoColumns[iColumn].sType );
2248				if ( ! rpSearch.test( sData ) )
2249				{
2250					oSettings.aiDisplay.splice( i, 1 );
2251					iIndexCorrector++;
2252				}
2253			}
2254		}
2255		
2256		
2257		/**
2258		 * Filter the data table based on user input and draw the table
2259		 *  @param {object} oSettings dataTables settings object
2260		 *  @param {string} sInput string to filter on
2261		 *  @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0)
2262		 *  @param {bool} bRegex treat as a regular expression or not
2263		 *  @param {bool} bSmart perform smart filtering or not
2264		 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
2265		 *  @memberof DataTable#oApi
2266		 */
2267		function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive )
2268		{
2269			var i;
2270			var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
2271			var oPrevSearch = oSettings.oPreviousSearch;
2272			
2273			/* Check if we are forcing or not - optional parameter */
2274			if ( !iForce )
2275			{
2276				iForce = 0;
2277			}
2278			
2279			/* Need to take account of custom filtering functions - always filter */
2280			if ( DataTable.ext.afnFiltering.length !== 0 )
2281			{
2282				iForce = 1;
2283			}
2284			
2285			/*
2286			 * If the input is blank - we want the full data set
2287			 */
2288			if ( sInput.length <= 0 )
2289			{
2290				oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
2291				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2292			}
2293			else
2294			{
2295				/*
2296				 * We are starting a new search or the new search string is smaller 
2297				 * then the old one (i.e. delete). Search from the master array
2298			 	 */
2299				if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
2300					   oPrevSearch.sSearch.length > sInput.length || iForce == 1 ||
2301					   sInput.indexOf(oPrevSearch.sSearch) !== 0 )
2302				{
2303					/* Nuke the old display array - we are going to rebuild it */
2304					oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
2305					
2306					/* Force a rebuild of the search array */
2307					_fnBuildSearchArray( oSettings, 1 );
2308					
2309					/* Search through all records to populate the search array
2310					 * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 
2311					 * mapping
2312					 */
2313					for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
2314					{
2315						if ( rpSearch.test(oSettings.asDataSearch[i]) )
2316						{
2317							oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
2318						}
2319					}
2320			  }
2321			  else
2322				{
2323			  	/* Using old search array - refine it - do it this way for speed
2324			  	 * Don't have to search the whole master array again
2325					 */
2326			  	var iIndexCorrector = 0;
2327			  	
2328			  	/* Search the current results */
2329			  	for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
2330					{
2331			  		if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
2332						{
2333			  			oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
2334			  			iIndexCorrector++;
2335			  		}
2336			  	}
2337			  }
2338			}
2339		}
2340		
2341		
2342		/**
2343		 * Create an array which can be quickly search through
2344		 *  @param {object} oSettings dataTables settings object
2345		 *  @param {int} iMaster use the master data array - optional
2346		 *  @memberof DataTable#oApi
2347		 */
2348		function _fnBuildSearchArray ( oSettings, iMaster )
2349		{
2350			if ( !oSettings.oFeatures.bServerSide )
2351			{
2352				/* Clear out the old data */
2353				oSettings.asDataSearch = [];
2354		
2355				var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
2356				var aiIndex = (iMaster===1) ?
2357				 	oSettings.aiDisplayMaster :
2358				 	oSettings.aiDisplay;
2359				
2360				for ( var i=0, iLen=aiIndex.length ; i<iLen ; i++ )
2361				{
2362					oSettings.asDataSearch[i] = _fnBuildSearchRow(
2363						oSettings,
2364						_fnGetRowData( oSettings, aiIndex[i], 'filter', aiFilterColumns )
2365					);
2366				}
2367			}
2368		}
2369		
2370		
2371		/**
2372		 * Create a searchable string from a single data row
2373		 *  @param {object} oSettings dataTables settings object
2374		 *  @param {array} aData Row data array to use for the data to search
2375		 *  @memberof DataTable#oApi
2376		 */
2377		function _fnBuildSearchRow( oSettings, aData )
2378		{
2379			var sSearch = aData.join('  ');
2380			
2381			/* If it looks like there is an HTML entity in the string, attempt to decode it */
2382			if ( sSearch.indexOf('&') !== -1 )
2383			{
2384				sSearch = $('<div>').html(sSearch).text();
2385			}
2386			
2387			// Strip newline characters
2388			return sSearch.replace( /[\n\r]/g, " " );
2389		}
2390		
2391		/**
2392		 * Build a regular expression object suitable for searching a table
2393		 *  @param {string} sSearch string to search for
2394		 *  @param {bool} bRegex treat as a regular expression or not
2395		 *  @param {bool} bSmart perform smart filtering or not
2396		 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
2397		 *  @returns {RegExp} constructed object
2398		 *  @memberof DataTable#oApi
2399		 */
2400		function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )
2401		{
2402			var asSearch, sRegExpString;
2403			
2404			if ( bSmart )
2405			{
2406				/* Generate the regular expression to use. Something along the lines of:
2407				 * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
2408				 */
2409				asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
2410				sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
2411				return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" );
2412			}
2413			else
2414			{
2415				sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
2416				return new RegExp( sSearch, bCaseInsensitive ? "i" : "" );
2417			}
2418		}
2419		
2420		
2421		/**
2422		 * Convert raw data into something that the user can search on
2423		 *  @param {string} sData data to be modified
2424		 *  @param {string} sType data type
2425		 *  @returns {string} search string
2426		 *  @memberof DataTable#oApi
2427		 */
2428		function _fnDataToSearch ( sData, sType )
2429		{
2430			if ( typeof DataTable.ext.ofnSearch[sType] === "function" )
2431			{
2432				return DataTable.ext.ofnSearch[sType]( sData );
2433			}
2434			else if ( sData === null )
2435			{
2436				return '';
2437			}
2438			else if ( sType == "html" )
2439			{
2440				return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );
2441			}
2442			else if ( typeof sData === "string" )
2443			{
2444				return sData.replace(/[\r\n]/g," ");
2445			}
2446			return sData;
2447		}
2448		
2449		
2450		/**
2451		 * scape a string such that it can be used in a regular expression
2452		 *  @param {string} sVal string to escape
2453		 *  @returns {string} escaped string
2454		 *  @memberof DataTable#oApi
2455		 */
2456		function _fnEscapeRegex ( sVal )
2457		{
2458			var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ];
2459			var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
2460			return sVal.replace(reReplace, '\\$1');
2461		}
2462		
2463		
2464		/**
2465		 * Generate the node required for the info display
2466		 *  @param {object} oSettings dataTables settings object
2467		 *  @returns {node} Information element
2468		 *  @memberof DataTable#oApi
2469		 */
2470		function _fnFeatureHtmlInfo ( oSettings )
2471		{
2472			var nInfo = document.createElement( 'div' );
2473			nInfo.className = oSettings.oClasses.sInfo;
2474			
2475			/* Actions that are to be taken once only for this feature */
2476			if ( !oSettings.aanFeatures.i )
2477			{
2478				/* Add draw callback */
2479				oSettings.aoDrawCallback.push( {
2480					"fn": _fnUpdateInfo,
2481					"sName": "information"
2482				} );
2483				
2484				/* Add id */
2485				nInfo.id = oSettings.sTableId+'_info';
2486			}
2487			oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' );
2488			
2489			return nInfo;
2490		}
2491		
2492		
2493		/**
2494		 * Update the information elements in the display
2495		 *  @param {object} oSettings dataTables settings object
2496		 *  @memberof DataTable#oApi
2497		 */
2498		function _fnUpdateInfo ( oSettings )
2499		{
2500			/* Show information about the table */
2501			if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
2502			{
2503				return;
2504			}
2505			
2506			var
2507				oLang = oSettings.oLanguage,
2508				iStart = oSettings._iDisplayStart+1,
2509				iEnd = oSettings.fnDisplayEnd(),
2510				iMax = oSettings.fnRecordsTotal(),
2511				iTotal = oSettings.fnRecordsDisplay(),
2512				sOut;
2513			
2514			if ( iTotal === 0 )
2515			{
2516				/* Empty record set */
2517				sOut = oLang.sInfoEmpty;
2518			}
2519			else {
2520				/* Normal record set */
2521				sOut = oLang.sInfo;
2522			}
2523		
2524			if ( iTotal != iMax )
2525			{
2526				/* Record set after filtering */
2527				sOut += ' ' + oLang.sInfoFiltered;
2528			}
2529		
2530			// Convert the macros
2531			sOut += oLang.sInfoPostFix;
2532			sOut = _fnInfoMacros( oSettings, sOut );
2533			
2534			if ( oLang.fnInfoCallback !== null )
2535			{
2536				sOut = oLang.fnInfoCallback.call( oSettings.oInstance, 
2537					oSettings, iStart, iEnd, iMax, iTotal, sOut );
2538			}
2539			
2540			var n = oSettings.aanFeatures.i;
2541			for ( var i=0, iLen=n.length ; i<iLen ; i++ )
2542			{
2543				$(n[i]).html( sOut );
2544			}
2545		}
2546		
2547		
2548		function _fnInfoMacros ( oSettings, str )
2549		{
2550			var
2551				iStart = oSettings._iDisplayStart+1,
2552				sStart = oSettings.fnFormatNumber( iStart ),
2553				iEnd = oSettings.fnDisplayEnd(),
2554				sEnd = oSettings.fnFormatNumber( iEnd ),
2555				iTotal = oSettings.fnRecordsDisplay(),
2556				sTotal = oSettings.fnFormatNumber( iTotal ),
2557				iMax = oSettings.fnRecordsTotal(),
2558				sMax = oSettings.fnFormatNumber( iMax );
2559		
2560			// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
2561			// internally
2562			if ( oSettings.oScroll.bInfinite )
2563			{
2564				sStart = oSettings.fnFormatNumber( 1 );
2565			}
2566		
2567			return str.
2568				replace(/_START_/g, sStart).
2569				replace(/_END_/g,   sEnd).
2570				replace(/_TOTAL_/g, sTotal).
2571				replace(/_MAX_/g,   sMax);
2572		}
2573		
2574		
2575		
2576		/**
2577		 * Draw the table for the first time, adding all required features
2578		 *  @param {object} oSettings dataTables settings object
2579		 *  @memberof DataTable#oApi
2580		 */
2581		function _fnInitialise ( oSettings )
2582		{
2583			var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;
2584			
2585			/* Ensure that the table data is fully initialised */
2586			if ( oSettings.bInitialised === false )
2587			{
2588				setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );
2589				return;
2590			}
2591			
2592			/* Show the display HTML options */
2593			_fnAddOptionsHtml( oSettings );
2594			
2595			/* Build and draw the header / footer for the table */
2596			_fnBuildHead( oSettings );
2597			_fnDrawHead( oSettings, oSettings.aoHeader );
2598			if ( oSettings.nTFoot )
2599			{
2600				_fnDrawHead( oSettings, oSettings.aoFooter );
2601			}
2602		
2603			/* Okay to show that something is going on now */
2604			_fnProcessingDisplay( oSettings, true );
2605			
2606			/* Calculate sizes for columns */
2607			if ( oSettings.oFeatures.bAutoWidth )
2608			{
2609				_fnCalculateColumnWidths( oSettings );
2610			}
2611			
2612			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2613			{
2614				if ( oSettings.aoColumns[i].sWidth !== null )
2615				{
2616					oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
2617				}
2618			}
2619			
2620			/* If there is default sorting required - let's do it. The sort function will do the
2621			 * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
2622			 * the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
2623			 */
2624			if ( oSettings.oFeatures.bSort )
2625			{
2626				_fnSort( oSettings );
2627			}
2628			else if ( oSettings.oFeatures.bFilter )
2629			{
2630				_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
2631			}
2632			else
2633			{
2634				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2635				_fnCalculateEnd( oSettings );
2636				_fnDraw( oSettings );
2637			}
2638			
2639			/* if there is an ajax source load the data */
2640			if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
2641			{
2642				var aoData = [];
2643				_fnServerParams( oSettings, aoData );
2644				oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) {
2645					var aData = (oSettings.sAjaxDataProp !== "") ?
2646					 	_fnGetObjectDataFn( oSettings.sAjaxDataProp )(json) : json;
2647		
2648					/* Got the data - add it to the table */
2649					for ( i=0 ; i<aData.length ; i++ )
2650					{
2651						_fnAddData( oSettings, aData[i] );
2652					}
2653					
2654					/* Reset the init display for cookie saving. We've already done a filter, and
2655					 * therefore cleared it before. So we need to make it appear 'fresh'
2656					 */
2657					oSettings.iInitDisplayStart = iAjaxStart;
2658					
2659					if ( oSettings.oFeatures.bSort )
2660					{
2661						_fnSort( oSettings );
2662					}
2663					else
2664					{
2665						oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2666						_fnCalculateEnd( oSettings );
2667						_fnDraw( oSettings );
2668					}
2669					
2670					_fnProcessingDisplay( oSettings, false );
2671					_fnInitComplete( oSettings, json );
2672				}, oSettings );
2673				return;
2674			}
2675			
2676			/* Server-side processing initialisation complete is done at the end of _fnDraw */
2677			if ( !oSettings.oFeatures.bServerSide )
2678			{
2679				_fnProcessingDisplay( oSettings, false );
2680				_fnInitComplete( oSettings );
2681			}
2682		}
2683		
2684		
2685		/**
2686		 * Draw the table for the first time, adding all required features
2687		 *  @param {object} oSettings dataTables settings object
2688		 *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
2689		 *    with client-side processing (optional)
2690		 *  @memberof DataTable#oApi
2691		 */
2692		function _fnInitComplete ( oSettings, json )
2693		{
2694			oSettings._bInitComplete = true;
2695			_fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] );
2696		}
2697		
2698		
2699		/**
2700		 * Language compatibility - when certain options are given, and others aren't, we
2701		 * need to duplicate the values over, in order to provide backwards compatibility
2702		 * with older language files.
2703		 *  @param {object} oSettings dataTables settings object
2704		 *  @memberof DataTable#oApi
2705		 */
2706		function _fnLanguageCompat( oLanguage )
2707		{
2708			var oDefaults = DataTable.defaults.oLanguage;
2709		
2710			/* Backwards compatibility - if there is no sEmptyTable given, then use the same as
2711			 * sZeroRecords - assuming that is given.
2712			 */
2713			if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords &&
2714				oDefaults.sEmptyTable === "No data available in table" )
2715			{
2716				_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
2717			}
2718		
2719			/* Likewise with loading records */
2720			if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords &&
2721				oDefaults.sLoadingRecords === "Loading..." )
2722			{
2723				_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
2724			}
2725		}
2726		
2727		
2728		
2729		/**
2730		 * Generate the node required for user display length changing
2731		 *  @param {object} oSettings dataTables settings object
2732		 *  @returns {node} Display length feature node
2733		 *  @memberof DataTable#oApi
2734		 */
2735		function _fnFeatureHtmlLength ( oSettings )
2736		{
2737			if ( oSettings.oScroll.bInfinite )
2738			{
2739				return null;
2740			}
2741			
2742			/* This can be overruled by not using the _MENU_ var/macro in the language variable */
2743			var sName = 'name="'+oSettings.sTableId+'_length"';
2744			var sStdMenu = '<select size="1"  style="width:50px; height:25px;" '+sName+'>';
2745			var i, iLen;
2746			var aLengthMenu = oSettings.aLengthMenu;
2747			
2748			if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && 
2749					typeof aLengthMenu[1] === 'object' )
2750			{
2751				for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ )
2752				{
2753					sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>';
2754				}
2755			}
2756			else
2757			{
2758				for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ )
2759				{
2760					sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>';
2761				}
2762			}
2763			sStdMenu += '</select>';
2764			
2765			var nLength = document.createElement( 'div' );
2766			if ( !oSettings.aanFeatures.l )
2767			{
2768				nLength.id = oSettings.sTableId+'_length';
2769			}
2770			nLength.className = oSettings.oClasses.sLength;
2771			nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';
2772			
2773			/*
2774			 * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
2775			 * and Stefan Skopnik for fixing the fix!
2776			 */
2777			$('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true);
2778			
2779			$('select', nLength).bind( 'change.DT', function(e) {
2780				var iVal = $(this).val();
2781				
2782				/* Update all other length options for the new display */
2783				var n = oSettings.aanFeatures.l;
2784				for ( i=0, iLen=n.length ; i<iLen ; i++ )
2785				{
2786					if ( n[i] != this.parentNode )
2787					{
2788						$('select', n[i]).val( iVal );
2789					}
2790				}
2791				
2792				/* Redraw the table */
2793				oSettings._iDisplayLength = parseInt(iVal, 10);
2794				_fnCalculateEnd( oSettings );
2795				
2796				/* If we have space to show extra rows (backing up from the end point - then do so */
2797				if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
2798				{
2799					oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
2800					if ( oSettings._iDisplayStart < 0 )
2801					{
2802						oSettings._iDisplayStart = 0;
2803					}
2804				}
2805				
2806				if ( oSettings._iDisplayLength == -1 )
2807				{
2808					oSettings._iDisplayStart = 0;
2809				}
2810				
2811				_fnDraw( oSettings );
2812			} );
2813		
2814		
2815			$('select', nLength).attr('aria-controls', oSettings.sTableId);
2816			
2817			return nLength;
2818		}
2819		
2820		
2821		/**
2822		 * Recalculate the end point based on the start point
2823		 *  @param {object} oSettings dataTables settings object
2824		 *  @memberof DataTable#oApi
2825		 */
2826		function _fnCalculateEnd( oSettings )
2827		{
2828			if ( oSettings.oFeatures.bPaginate === false )
2829			{
2830				oSettings._iDisplayEnd = oSettings.aiDisplay.length;
2831			}
2832			else
2833			{
2834				/* Set the end point of the display - based on how many elements there are
2835				 * still to display
2836				 */
2837				if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
2838					   oSettings._iDisplayLength == -1 )
2839				{
2840					oSettings._iDisplayEnd = oSettings.aiDisplay.length;
2841				}
2842				else
2843				{
2844					oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
2845				}
2846			}
2847		}
2848		
2849		
2850		
2851		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2852		 * Note that most of the paging logic is done in 
2853		 * DataTable.ext.oPagination
2854		 */
2855		
2856		/**
2857		 * Generate the node required for default pagination
2858		 *  @param {object} oSettings dataTables settings object
2859		 *  @returns {node} Pagination feature node
2860		 *  @memberof DataTable#oApi
2861		 */
2862		function _fnFeatureHtmlPaginate ( oSettings )
2863		{
2864			if ( oSettings.oScroll.bInfinite )
2865			{
2866				return null;
2867			}
2868			
2869			var nPaginate = document.createElement( 'div' );
2870			nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
2871			
2872			DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, 
2873				function( oSettings ) {
2874					_fnCalculateEnd( oSettings );
2875					_fnDraw( oSettings );
2876				}
2877			);
2878			
2879			/* Add a draw callback for the pagination on first instance, to update the paging display */
2880			if ( !oSettings.aanFeatures.p )
2881			{
2882				oSettings.aoDrawCallback.push( {
2883					"fn": function( oSettings ) {
2884						DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
2885							_fnCalculateEnd( oSettings );
2886							_fnDraw( oSettings );
2887						} );
2888					},
2889					"sName": "pagination"
2890				} );
2891			}
2892			return nPaginate;
2893		}
2894		
2895		
2896		/**
2897		 * Alter the display settings to change the page
2898		 *  @param {object} oSettings dataTables settings object
2899		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
2900		 *    or page number to jump to (integer)
2901		 *  @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1
2902		 *  @memberof DataTable#oApi
2903		 */
2904		function _fnPageChange ( oSettings, mAction )
2905		{
2906			var iOldStart = oSettings._iDisplayStart;
2907			
2908			if ( typeof mAction === "number" )
2909			{
2910				oSettings._iDisplayStart = mAction * oSettings._iDisplayLength;
2911				if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() )
2912				{
2913					oSettings._iDisplayStart = 0;
2914				}
2915			}
2916			else if ( mAction == "first" )
2917			{
2918				oSettings._iDisplayStart = 0;
2919			}
2920			else if ( mAction == "previous" )
2921			{
2922				oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
2923					oSettings._iDisplayStart - oSettings._iDisplayLength :
2924					0;
2925				
2926				/* Correct for under-run */
2927				if ( oSettings._iDisplayStart < 0 )
2928				{
2929				  oSettings._iDisplayStart = 0;
2930				}
2931			}
2932			else if ( mAction == "next" )
2933			{
2934				if ( oSettings._iDisplayLength >= 0 )
2935				{
2936					/* Make sure we are not over running the display array */
2937					if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
2938					{
2939						oSettings._iDisplayStart += oSettings._iDisplayLength;
2940					}
2941				}
2942				else
2943				{
2944					oSettings._iDisplayStart = 0;
2945				}
2946			}
2947			else if ( mAction == "last" )
2948			{
2949				if ( oSettings._iDisplayLength >= 0 )
2950				{
2951					var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
2952					oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
2953				}
2954				else
2955				{
2956					oSettings._iDisplayStart = 0;
2957				}
2958			}
2959			else
2960			{
2961				_fnLog( oSettings, 0, "Unknown paging action: "+mAction );
2962			}
2963			$(oSettings.oInstance).trigger('page', oSettings);
2964			
2965			return iOldStart != oSettings._iDisplayStart;
2966		}
2967		
2968		
2969		
2970		/**
2971		 * Generate the node required for the processing node
2972		 *  @param {object} oSettings dataTables settings object
2973		 *  @returns {node} Processing element
2974		 *  @memberof DataTable#oApi
2975		 */
2976		function _fnFeatureHtmlProcessing ( oSettings )
2977		{
2978			var nProcessing = document.createElement( 'div' );
2979			
2980			if ( !oSettings.aanFeatures.r )
2981			{
2982				nProcessing.id = oSettings.sTableId+'_processing';
2983			}
2984			nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
2985			nProcessing.className = oSettings.oClasses.sProcessing;
2986			oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
2987			
2988			return nProcessing;
2989		}
2990		
2991		
2992		/**
2993		 * Display or hide the processing indicator
2994		 *  @param {object} oSettings dataTables settings object
2995		 *  @param {bool} bShow Show the processing indicator (true) or not (false)
2996		 *  @memberof DataTable#oApi
2997		 */
2998		function _fnProcessingDisplay ( oSettings, bShow )
2999		{
3000			if ( oSettings.oFeatures.bProcessing )
3001			{
3002				var an = oSettings.aanFeatures.r;
3003				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
3004				{
3005					an[i].style.visibility = bShow ? "visible" : "hidden";
3006				}
3007			}
3008		
3009			$(oSettings.oInstance).trigger('processing', [oSettings, bShow]);
3010		}
3011		
3012		/**
3013		 * Add any control elements for the table - specifically scrolling
3014		 *  @param {object} oSettings dataTables settings object
3015		 *  @returns {node} Node to add to the DOM
3016		 *  @memberof DataTable#oApi
3017		 */
3018		function _fnFeatureHtmlTable ( oSettings )
3019		{
3020			/* Check if scrolling is enabled or not - if not then leave the DOM unaltered */
3021			if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
3022			{
3023				return oSettings.nTable;
3024			}
3025			
3026			/*
3027			 * The HTML structure that we want to generate in this function is:
3028			 *  div - nScroller
3029			 *    div - nScrollHead
3030			 *      div - nScrollHeadInner
3031			 *        table - nScrollHeadTable
3032			 *          thead - nThead
3033			 *    div - nScrollBody
3034			 *      table - oSettings.nTable
3035			 *        thead - nTheadSize
3036			 *        tbody - nTbody
3037			 *    div - nScrollFoot
3038			 *      div - nScrollFootInner
3039			 *        table - nScrollFootTable
3040			 *          tfoot - nTfoot
3041			 */
3042			var
3043			 	nScroller = document.createElement('div'),
3044			 	nScrollHead = document.createElement('div'),
3045			 	nScrollHeadInner = document.createElement('div'),
3046			 	nScrollBody = document.createElement('div'),
3047			 	nScrollFoot = document.createElement('div'),
3048			 	nScrollFootInner = document.createElement('div'),
3049			 	nScrollHeadTable = oSettings.nTable.cloneNode(false),
3050			 	nScrollFootTable = oSettings.nTable.cloneNode(false),
3051				nThead = oSettings.nTable.getElementsByTagName('thead')[0],
3052			 	nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null : 
3053					oSettings.nTable.getElementsByTagName('tfoot')[0],
3054				oClasses = oSettings.oClasses;
3055			
3056			nScrollHead.appendChild( nScrollHeadInner );
3057			nScrollFoot.appendChild( nScrollFootInner );
3058			nScrollBody.appendChild( oSettings.nTable );
3059			nScroller.appendChild( nScrollHead );
3060			nScroller.appendChild( nScrollBody );
3061			nScrollHeadInner.appendChild( nScrollHeadTable );
3062			nScrollHeadTable.appendChild( nThead );
3063			if ( nTfoot !== null )
3064			{
3065				nScroller.appendChild( nScrollFoot );
3066				nScrollFootInner.appendChild( nScrollFootTable );
3067				nScrollFootTable.appendChild( nTfoot );
3068			}
3069			
3070			nScroller.className = oClasses.sScrollWrapper;
3071			nScrollHead.className = oClasses.sScrollHead;
3072			nScrollHeadInner.className = oClasses.sScrollHeadInner;
3073			nScrollBody.className = oClasses.sScrollBody;
3074			nScrollFoot.className = oClasses.sScrollFoot;
3075			nScrollFootInner.className = oClasses.sScrollFootInner;
3076			
3077			if ( oSettings.oScroll.bAutoCss )
3078			{
3079				nScrollHead.style.overflow = "hidden";
3080				nScrollHead.style.position = "relative";
3081				nScrollFoot.style.overflow = "hidden";
3082				nScrollBody.style.overflow = "auto";
3083			}
3084			
3085			nScrollHead.style.border = "0";
3086			nScrollHead.style.width = "100%";
3087			nScrollFoot.style.border = "0";
3088			nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ?
3089				oSettings.oScroll.sXInner : "100%"; /* will be overwritten */
3090			
3091			/* Modify attributes to respect the clones */
3092			nScrollHeadTable.removeAttribute('id');
3093			nScrollHeadTable.style.marginLeft = "0";
3094			oSettings.nTable.style.marginLeft = "0";
3095			if ( nTfoot !== null )
3096			{
3097				nScrollFootTable.removeAttribute('id');
3098				nScrollFootTable.style.marginLeft = "0";
3099			}
3100			
3101			/* Move caption elements from the body to the header, footer or leave where it is
3102			 * depending on the configuration. Note that the DTD says there can be only one caption */
3103			var nCaption = $(oSettings.nTable).children('caption');
3104			if ( nCaption.length > 0 )
3105			{
3106				nCaption = nCaption[0];
3107				if ( nCaption._captionSide === "top" )
3108				{
3109					nScrollHeadTable.appendChild( nCaption );
3110				}
3111				else if ( nCaption._captionSide === "bottom" && nTfoot )
3112				{
3113					nScrollFootTable.appendChild( nCaption );
3114				}
3115			}
3116			
3117			/*
3118			 * Sizing
3119			 */
3120			/* When x-scrolling add the width and a scroller to move the header with the body */
3121			if ( oSettings.oScroll.sX !== "" )
3122			{
3123				nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
3124				nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
3125				
3126				if ( nTfoot !== null )
3127				{
3128					nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );	
3129				}
3130				
3131				/* When the body is scrolled, then we also want to scroll the headers */
3132				$(nScrollBody).scroll( function (e) {
3133					nScrollHead.scrollLeft = this.scrollLeft;
3134					
3135					if ( nTfoot !== null )
3136					{
3137						nScrollFoot.scrollLeft = this.scrollLeft;
3138					}
3139				} );
3140			}
3141			
3142			/* When yscrolling, add the height */
3143			if ( oSettings.oScroll.sY !== "" )
3144			{
3145				nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
3146			}
3147			
3148			/* Redraw - align columns across the tables */
3149			oSettings.aoDrawCallback.push( {
3150				"fn": _fnScrollDraw,
3151				"sName": "scrolling"
3152			} );
3153			
3154			/* Infinite scrolling event handlers */
3155			if ( oSettings.oScroll.bInfinite )
3156			{
3157				$(nScrollBody).scroll( function() {
3158					/* Use a blocker to stop scrolling from loading more data while other data is still loading */
3159					if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 )
3160					{
3161						/* Check if we should load the next data set */
3162						if ( $(this).scrollTop() + $(this).height() > 
3163							$(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
3164						{
3165							/* Only do the redraw if we have to - we might be at the end of the data */
3166							if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
3167							{
3168								_fnPageChange( oSettings, 'next' );
3169								_fnCalculateEnd( oSettings );
3170								_fnDraw( oSettings );
3171							}
3172						}
3173					}
3174				} );
3175			}
3176			
3177			oSettings.nScrollHead = nScrollHead;
3178			oSettings.nScrollFoot = nScrollFoot;
3179			
3180			return nScroller;
3181		}
3182		
3183		
3184		/**
3185		 * Update the various tables for resizing. It's a bit of a pig this function, but
3186		 * basically the idea to:
3187		 *   1. Re-create the table inside the scrolling div
3188		 *   2. Take live measurements from the DOM
3189		 *   3. Apply the measurements
3190		 *   4. Clean up
3191		 *  @param {object} o dataTables settings object
3192		 *  @returns {node} Node to add to the DOM
3193		 *  @memberof DataTable#oApi
3194		 */
3195		function _fnScrollDraw ( o )
3196		{
3197			var
3198				nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
3199				nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
3200				nScrollBody = o.nTable.parentNode,
3201				i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
3202				nTheadSize, nTfootSize,
3203				iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth,
3204				nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
3205				nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
3206				ie67 = o.oBrowser.bScrollOversize,
3207				zeroOut = function(nSizer) {
3208					oStyle = nSizer.style;
3209					oStyle.paddingTop = "0";
3210					oStyle.paddingBottom = "0";
3211					oStyle.borderTopWidth = "0";
3212					oStyle.borderBottomWidth = "0";
3213					oStyle.height = 0;
3214				};
3215			
3216			/*
3217			 * 1. Re-create the table inside the scrolling div
3218			 */
3219			
3220			/* Remove the old minimised thead and tfoot elements in the inner table */
3221			$(o.nTable).children('thead, tfoot').remove();
3222		
3223			/* Clone the current header and footer elements and then place it into the inner table */
3224			nTheadSize = $(o.nTHead).clone()[0];
3225			o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
3226			anHeadToSize = o.nTHead.getElementsByTagName('tr');
3227			anHeadSizers = nTheadSize.getElementsByTagName('tr');
3228			
3229			if ( o.nTFoot !== null )
3230			{
3231				nTfootSize = $(o.nTFoot).clone()[0];
3232				o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
3233				anFootToSize = o.nTFoot.getElementsByTagName('tr');
3234				anFootSizers = nTfootSize.getElementsByTagName('tr');
3235			}
3236			
3237			/*
3238			 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3239			 */
3240			
3241			/* Remove old sizing and apply the calculated column widths
3242			 * Get the unique column headers in the newly created (cloned) header. We want to apply the
3243			 * calculated sizes to this header
3244			 */
3245			if ( o.oScroll.sX === "" )
3246			{
3247				nScrollBody.style.width = '100%';
3248				nScrollHeadInner.parentNode.style.width = '100%';
3249			}
3250			
3251			var nThs = _fnGetUniqueThs( o, nTheadSize );
3252			for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
3253			{
3254				iVis = _fnVisibleToColumnIndex( o, i );
3255				nThs[i].style.width = o.aoColumns[iVis].sWidth;
3256			}
3257			
3258			if ( o.nTFoot !== null )
3259			{
3260				_fnApplyToChildren( function(n) {
3261					n.style.width = "";
3262				}, anFootSizers );
3263			}
3264		
3265			// If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3266			// will end up forcing the scrollbar to appear, making our measurements wrong for when we
3267			// then hide it (end of this function), so add the header height to the body scroller.
3268			if ( o.oScroll.bCollapse && o.oScroll.sY !== "" )
3269			{
3270				nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px";
3271			}
3272			
3273			/* Size the table as a whole */
3274			iSanityWidth = $(o.nTable).outerWidth();
3275			if ( o.oScroll.sX === "" )
3276			{
3277				/* No x scrolling */
3278				o.nTable.style.width = "100%";
3279				
3280				/* I know this is rubbish - but IE7 will make the width of the table when 100% include
3281				 * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this
3282				 * into account.
3283				 */
3284				if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || 
3285					$(nScrollBody).css('overflow-y') == "scroll")  )
3286				{
3287					o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);
3288				}
3289			}
3290			else
3291			{
3292				if ( o.oScroll.sXInner !== "" )
3293				{
3294					/* x scroll inner has been given - use it */
3295					o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
3296				}
3297				else if ( iSanityWidth == $(nScrollBody).width() &&
3298				   $(nScrollBody).height() < $(o.nTable).height() )
3299				{
3300					/* There is y-scrolling - try to take account of the y scroll bar */
3301					o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
3302					if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
3303					{
3304						/* Not possible to take account of it */
3305						o.nTable.style.width = _fnStringToCss( iSanityWidth );
3306					}
3307				}
3308				else
3309				{
3310					/* All else fails */
3311					o.nTable.style.width = _fnStringToCss( iSanityWidth );
3312				}
3313			}
3314			
3315			/* Recalculate the sanity width - now that we've applied the required width, before it was
3316			 * a temporary variable. This is required because the column width calculation is done
3317			 * before this table DOM is created.
3318			 */
3319			iSanityWidth = $(o.nTable).outerWidth();
3320			
3321			/* We want the hidden header to have zero height, so remove padding and borders. Then
3322			 * set the width based on the real headers
3323			 */
3324			
3325			// Apply all styles in one pass. Invalidates layout only once because we don't read any 
3326			// DOM properties.
3327			_fnApplyToChildren( zeroOut, anHeadSizers );
3328			 
3329			// Read all widths in next pass. Forces layout only once because we do not change 
3330			// any DOM properties.
3331			_fnApplyToChildren( function(nSizer) {
3332				aApplied.push( _fnStringToCss( $(nSizer).width() ) );
3333			}, anHeadSizers );
3334			 
3335			// Apply all widths in final pass. Invalidates layout only once because we do not
3336			// read any DOM properties.
3337			_fnApplyToChildren( function(nToSize, i) {
3338				nToSize.style.width = aApplied[i];
3339			}, anHeadToSize );
3340		
3341			$(anHeadSizers).height(0);
3342			
3343			/* Same again with the footer if we have one */
3344			if ( o.nTFoot !== null )
3345			{
3346				_fnApplyToChildren( zeroOut, anFootSizers );
3347				 
3348				_fnApplyToChildren( function(nSizer) {
3349					aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) );
3350				}, anFootSizers );
3351				 
3352				_fnApplyToChildren( function(nToSize, i) {
3353					nToSize.style.width = aAppliedFooter[i];
3354				}, anFootToSize );
3355		
3356				$(anFootSizers).height(0);
3357			}
3358			
3359			/*
3360			 * 3. Apply the measurements
3361			 */
3362			
3363			/* "Hide" the header and footer that we used for the sizing. We want to also fix their width
3364			 * to what they currently are
3365			 */
3366			_fnApplyToChildren( function(nSizer, i) {
3367				nSizer.innerHTML = "";
3368				nSizer.style.width = aApplied[i];
3369			}, anHeadSizers );
3370			
3371			if ( o.nTFoot !== null )
3372			{
3373				_fnApplyToChildren( function(nSizer, i) {
3374					nSizer.innerHTML = "";
3375					nSizer.style.width = aAppliedFooter[i];
3376				}, anFootSizers );
3377			}
3378			
3379			/* Sanity check that the table is of a sensible width. If not then we are going to get
3380			 * misalignment - try to prevent this by not allowing the table to shrink below its min width
3381			 */
3382			if ( $(o.nTable).outerWidth() < iSanityWidth )
3383			{
3384				/* The min width depends upon if we have a vertical scrollbar visible or not */
3385				var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || 
3386					$(nScrollBody).css('overflow-y') == "scroll")) ?
3387						iSanityWidth+o.oScroll.iBarWidth : iSanityWidth;
3388				
3389				/* IE6/7 are a law unto themselves... */
3390				if ( ie67 && (nScrollBody.scrollHeight > 
3391					nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll")  )
3392				{
3393					o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );
3394				}
3395				
3396				/* Apply the calculated minimum width to the table wrappers */
3397				nScrollBody.style.width = _fnStringToCss( iCorrection );
3398				o.nScrollHead.style.width = _fnStringToCss( iCorrection );
3399				
3400				if ( o.nTFoot !== null )
3401				{
3402					o.nScrollFoot.style.width = _fnStringToCss( iCorrection );
3403				}
3404				
3405				/* And give the user a warning that we've stopped the table getting too small */
3406				if ( o.oScroll.sX === "" )
3407				{
3408					_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
3409						" misalignment. The table has been drawn at its minimum possible width." );
3410				}
3411				else if ( o.oScroll.sXInner !== "" )
3412				{
3413					_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
3414						" misalignment. Increase the sScrollXInner value or remove it to allow automatic"+
3415						" calculation" );
3416				}
3417			}
3418			else
3419			{
3420				nScrollBody.style.width = _fnStringToCss( '100%' );
3421				o.nScrollHead.style.width = _fnStringToCss( '100%' );
3422				
3423				if ( o.nTFoot !== null )
3424				{
3425					o.nScrollFoot.style.width = _fnStringToCss( '100%' );
3426				}
3427			}
3428			
3429			
3430			/*
3431			 * 4. Clean up
3432			 */
3433			if ( o.oScroll.sY === "" )
3434			{
3435				/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
3436				 * the scrollbar height from the visible display, rather than adding it on. We need to
3437				 * set the height in order to sort this. Don't want to do it in any other browsers.
3438				 */
3439				if ( ie67 )
3440				{
3441					nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
3442				}
3443			}
3444			
3445			if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
3446			{
3447				nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
3448				
3449				var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
3450				 	o.oScroll.iBarWidth : 0;
3451				if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
3452				{
3453					nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );
3454				}
3455			}
3456			
3457			/* Finally set the width's of the header and footer tables */
3458			var iOuterWidth = $(o.nTable).outerWidth();
3459			nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
3460			nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth );
3461		
3462			// Figure out if there are scrollbar present - if so then we need a the header and footer to
3463			// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
3464			var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll";
3465			nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
3466			
3467			if ( o.nTFoot !== null )
3468			{
3469				nScrollFootTable.style.width = _fnStringToCss( iOuterWidth );
3470				nScrollFootInner.style.width = _fnStringToCss( iOuterWidth );
3471				nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
3472			}
3473		
3474			/* Adjust the position of the header in case we loose the y-scrollbar */
3475			$(nScrollBody).scroll();
3476			
3477			/* If sorting or filtering has occurred, jump the scrolling back to the top */
3478			if ( o.bSorted || o.bFiltered )
3479			{
3480				nScrollBody.scrollTop = 0;
3481			}
3482		}
3483		
3484		
3485		/**
3486		 * Apply a given function to the display child nodes of an element array (typically
3487		 * TD children of TR rows
3488		 *  @param {function} fn Method to apply to the objects
3489		 *  @param array {nodes} an1 List of elements to look through for display children
3490		 *  @param array {nodes} an2 Another list (identical structure to the first) - optional
3491		 *  @memberof DataTable#oApi
3492		 */
3493		function _fnApplyToChildren( fn, an1, an2 )
3494		{
3495			var index=0, i=0, iLen=an1.length;
3496			var nNode1, nNode2;
3497		
3498			while ( i < iLen )
3499			{
3500				nNode1 = an1[i].firstChild;
3501				nNode2 = an2 ? an2[i].firstChild : null;
3502				while ( nNode1 )
3503				{
3504					if ( nNode1.nodeType === 1 )
3505					{
3506						if ( an2 )
3507						{
3508							fn( nNode1, nNode2, index );
3509						}
3510						else
3511						{
3512							fn( nNode1, index );
3513						}
3514						index++;
3515					}
3516					nNode1 = nNode1.nextSibling;
3517					nNode2 = an2 ? nNode2.nextSibling : null;
3518				}
3519				i++;
3520			}
3521		}
3522		
3523		/**
3524		 * Convert a CSS unit width to pixels (e.g. 2em)
3525		 *  @param {string} sWidth width to be converted
3526		 *  @param {node} nParent parent to get the with for (required for relative widths) - optional
3527		 *  @returns {int} iWidth width in pixels
3528		 *  @memberof DataTable#oApi
3529		 */
3530		function _fnConvertToWidth ( sWidth, nParent )
3531		{
3532			if ( !sWidth || sWidth === null || sWidth === '' )
3533			{
3534				return 0;
3535			}
3536			
3537			if ( !nParent )
3538			{
3539				nParent = document.body;
3540			}
3541			
3542			var iWidth;
3543			var nTmp = document.createElement( "div" );
3544			nTmp.style.width = _fnStringToCss( sWidth );
3545			
3546			nParent.appendChild( nTmp );
3547			iWidth = nTmp.offsetWidth;
3548			nParent.removeChild( nTmp );
3549			
3550			return ( iWidth );
3551		}
3552		
3553		
3554		/**
3555		 * Calculate the width of columns for the table
3556		 *  @param {object} oSettings dataTables settings object
3557		 *  @memberof DataTable#oApi
3558		 */
3559		function _fnCalculateColumnWidths ( oSettings )
3560		{
3561			var iTableWidth = oSettings.nTable.offsetWidth;
3562			var iUserInputs = 0;
3563			var iTmpWidth;
3564			var iVisibleColumns = 0;
3565			var iColums = oSettings.aoColumns.length;
3566			var i, iIndex, iCorrector, iWidth;
3567			var oHeaders = $('th', oSettings.nTHead);
3568			var widthAttr = oSettings.nTable.getAttribute('width');
3569			var nWrapper = oSettings.nTable.parentNode;
3570			
3571			/* Convert any user input sizes into pixel sizes */
3572			for ( i=0 ; i<iColums ; i++ )
3573			{
3574				if ( oSettings.aoColumns[i].bVisible )
3575				{
3576					iVisibleColumns++;
3577					
3578					if ( oSettings.aoColumns[i].sWidth !== null )
3579					{
3580						iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig, 
3581							nWrapper );
3582						if ( iTmpWidth !== null )
3583						{
3584							oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
3585						}
3586							
3587						iUserInputs++;
3588					}
3589				}
3590			}
3591			
3592			/* If the number of columns in the DOM equals the number that we have to process in 
3593			 * DataTables, then we can use the offsets that are created by the web-browser. No custom 
3594			 * sizes can be set in order for this to happen, nor scrolling used
3595			 */
3596			if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
3597				oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
3598			{
3599				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
3600				{
3601					iTmpWidth = $(oHeaders[i]).width();
3602					if ( iTmpWidth !== null )
3603					{
3604						oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
3605					}
3606				}
3607			}
3608			else
3609			{
3610				/* Otherwise we are going to have to do some calculations to get the width of each column.
3611				 * Construct a 1 row table with the widest node in the data, and any user defined widths,
3612				 * then insert it into the DOM and allow the browser to do all the hard work of
3613				 * calculating table widths.
3614				 */
3615				var
3616					nCalcTmp = oSettings.nTable.cloneNode( false ),
3617					nTheadClone = oSettings.nTHead.cloneNode(true),
3618					nBody = document.createElement( 'tbody' ),
3619					nTr = document.createElement( 'tr' ),
3620					nDivSizing;
3621				
3622				nCalcTmp.removeAttribute( "id" );
3623				nCalcTmp.appendChild( nTheadClone );
3624				if ( oSettings.nTFoot !== null )
3625				{
3626					nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
3627					_fnApplyToChildren( function(n) {
3628						n.style.width = "";
3629					}, nCalcTmp.getElementsByTagName('tr') );
3630				}
3631				
3632				nCalcTmp.appendChild( nBody );
3633				nBody.appendChild( nTr );
3634				
3635				/* Remove any sizing that was previously applied by the styles */
3636				var jqColSizing = $('thead th', nCalcTmp);
3637				if ( jqColSizing.length === 0 )
3638				{
3639					jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
3640				}
3641		
3642				/* Apply custom sizing to the cloned header */
3643				var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
3644				iCorrector = 0;
3645				for ( i=0 ; i<iColums ; i++ )
3646				{
3647					var oColumn = oSettings.aoColumns[i];
3648					if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
3649					{
3650						nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
3651					}
3652					else if ( oColumn.bVisible )
3653					{
3654						nThs[i-iCorrector].style.width = "";
3655					}
3656					else
3657					{
3658						iCorrector++;
3659					}
3660				}
3661		
3662				/* Find the biggest td for each column and put it into the table */
3663				for ( i=0 ; i<iColums ; i++ )
3664				{
3665					if ( oSettings.aoColumns[i].bVisible )
3666					{
3667						var nTd = _fnGetWidestNode( oSettings, i );
3668						if ( nTd !== null )
3669						{
3670							nTd = nTd.cloneNode(true);
3671							if ( oSettings.aoColumns[i].sContentPadding !== "" )
3672							{
3673								nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
3674							}
3675							nTr.appendChild( nTd );
3676						}
3677					}
3678				}
3679				
3680				/* Build the table and 'display' it */
3681				nWrapper.appendChild( nCalcTmp );
3682				
3683				/* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
3684				 * when not scrolling leave the table width as it is. This results in slightly different,
3685				 * but I think correct behaviour
3686				 */
3687				if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
3688				{
3689					nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
3690				}
3691				else if ( oSettings.oScroll.sX !== "" )
3692				{
3693					nCalcTmp.style.width = "";
3694					if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
3695					{
3696						nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
3697					}
3698				}
3699				else if ( oSettings.oScroll.sY !== "" )
3700				{
3701					nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
3702				}
3703				else if ( widthAttr )
3704				{
3705					nCalcTmp.style.width = _fnStringToCss( widthAttr );
3706				}
3707				nCalcTmp.style.visibility = "hidden";
3708				
3709				/* Scrolling considerations */
3710				_fnScrollingWidthAdjust( oSettings, nCalcTmp );
3711				
3712				/* Read the width's calculated by the browser and store them for use by the caller. We
3713				 * first of all try to use the elements in the body, but it is possible that there are
3714				 * no elements there, under which circumstances we use the header elements
3715				 */
3716				var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
3717				if ( oNodes.length === 0 )
3718				{
3719					oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
3720				}
3721		
3722				/* Browsers need a bit of a hand when a width is assigned to any columns when 
3723				 * x-scrolling as they tend to collapse the table to the min-width, even if
3724				 * we sent the column widths. So we need to keep track of what the table width
3725				 * should be by summing the user given values, and the automatic values
3726				 */
3727				if ( oSettings.oScroll.sX !== "" )
3728				{
3729					var iTotal = 0;
3730					iCorrector = 0;
3731					for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
3732					{
3733						if ( oSettings.aoColumns[i].bVisible )
3734						{
3735							if ( oSettings.aoColumns[i].sWidthOrig === null )
3736							{
3737								iTotal += $(oNodes[iCorrector]).outerWidth();
3738							}
3739							else
3740							{
3741								iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
3742									($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
3743							}
3744							iCorrector++;
3745						}
3746					}
3747					
3748					nCalcTmp.style.width = _fnStringToCss( iTotal );
3749					oSettings.nTable.style.width = _fnStringToCss( iTotal );
3750				}
3751		
3752				iCorrector = 0;
3753				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
3754				{
3755					if ( oSettings.aoColumns[i].bVisible )
3756					{
3757						iWidth = $(oNodes[iCorrector]).width();
3758						if ( iWidth !== null && iWidth > 0 )
3759						{
3760							oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
3761						}
3762						iCorrector++;
3763					}
3764				}
3765		
3766				var cssWidth = $(nCalcTmp).css('width');
3767				oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ?
3768				    cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() );
3769				nCalcTmp.parentNode.removeChild( nCalcTmp );
3770			}
3771		
3772			if ( widthAttr )
3773			{
3774				oSettings.nTable.style.width = _fnStringToCss( widthAttr );
3775			}
3776		}
3777		
3778		
3779		/**
3780		 * Adjust a table's width to take account of scrolling
3781		 *  @param {object} oSettings dataTables settings object
3782		 *  @param {node} n table node
3783		 *  @memberof DataTable#oApi
3784		 */
3785		function _fnScrollingWidthAdjust ( oSettings, n )
3786		{
3787			if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
3788			{
3789				/* When y-scrolling only, we want to remove the width of the scroll bar so the table
3790				 * + scroll bar will fit into the area avaialble.
3791				 */
3792				var iOrigWidth = $(n).width();
3793				n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
3794			}
3795			else if ( oSettings.oScroll.sX !== "" )
3796			{
3797				/* When x-scrolling both ways, fix the table at it's current size, without adjusting */
3798				n.style.width = _fnStringToCss( $(n).outerWidth() );
3799			}
3800		}
3801		
3802		
3803		/**
3804		 * Get the widest node
3805		 *  @param {object} oSettings dataTables settings object
3806		 *  @param {int} iCol column of interest
3807		 *  @returns {node} widest table node
3808		 *  @memberof DataTable#oApi
3809		 */
3810		function _fnGetWidestNode( oSettings, iCol )
3811		{
3812			var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
3813			if ( iMaxIndex < 0 )
3814			{
3815				return null;
3816			}
3817		
3818			if ( oSettings.aoData[iMaxIndex].nTr === null )
3819			{
3820				var n = document.createElement('td');
3821				n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
3822				return n;
3823			}
3824			return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
3825		}
3826		
3827		
3828		/**
3829		 * Get the maximum strlen for each data column
3830		 *  @param {object} oSettings dataTables settings object
3831		 *  @param {int} iCol column of interest
3832		 *  @returns {string} max string length for each column
3833		 *  @memberof DataTable#oApi
3834		 */
3835		function _fnGetMaxLenString( oSettings, iCol )
3836		{
3837			var iMax = -1;
3838			var iMaxIndex = -1;
3839			
3840			for ( var i=0 ; i<oSettings.aoData.length ; i++ )
3841			{
3842				var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
3843				s = s.replace( /<.*?>/g, "" );
3844				if ( s.length > iMax )
3845				{
3846					iMax = s.length;
3847					iMaxIndex = i;
3848				}
3849			}
3850			
3851			return iMaxIndex;
3852		}
3853		
3854		
3855		/**
3856		 * Append a CSS unit (only if required) to a string
3857		 *  @param {array} aArray1 first array
3858		 *  @param {array} aArray2 second array
3859		 *  @returns {int} 0 if match, 1 if length is different, 2 if no match
3860		 *  @memberof DataTable#oApi
3861		 */
3862		function _fnStringToCss( s )
3863		{
3864			if ( s === null )
3865			{
3866				return "0px";
3867			}
3868			
3869			if ( typeof s == 'number' )
3870			{
3871				if ( s < 0 )
3872				{
3873					return "0px";
3874				}
3875				return s+"px";
3876			}
3877			
3878			/* Check if the last character is not 0-9 */
3879			var c = s.charCodeAt( s.length-1 );
3880			if (c < 0x30 || c > 0x39)
3881			{
3882				return s;
3883			}
3884			return s+"px";
3885		}
3886		
3887		
3888		/**
3889		 * Get the width of a scroll bar in this browser being used
3890		 *  @returns {int} width in pixels
3891		 *  @memberof DataTable#oApi
3892		 */
3893		function _fnScrollBarWidth ()
3894		{  
3895			var inner = document.createElement('p');
3896			var style = inner.style;
3897			style.width = "100%";
3898			style.height = "200px";
3899			style.padding = "0px";
3900			
3901			var outer = document.createElement('div');
3902			style = outer.style;
3903			style.position = "absolute";
3904			style.top = "0px";
3905			style.left = "0px";
3906			style.visibility = "hidden";
3907			style.width = "200px";
3908			style.height = "150px";
3909			style.padding = "0px";
3910			style.overflow = "hidden";
3911			outer.appendChild(inner);
3912			
3913			document.body.appendChild(outer);
3914			var w1 = inner.offsetWidth;
3915			outer.style.overflow = 'scroll';
3916			var w2 = inner.offsetWidth;
3917			if ( w1 == w2 )
3918			{
3919				w2 = outer.clientWidth;
3920			}
3921			
3922			document.body.removeChild(outer);
3923			return (w1 - w2);  
3924		}
3925		
3926		/**
3927		 * Change the order of the table
3928		 *  @param {object} oSettings dataTables settings object
3929		 *  @param {bool} bApplyClasses optional - should we apply classes or not
3930		 *  @memberof DataTable#oApi
3931		 */
3932		function _fnSort ( oSettings, bApplyClasses )
3933		{
3934			var
3935				i, iLen, j, jLen, k, kLen,
3936				sDataType, nTh,
3937				aaSort = [],
3938			 	aiOrig = [],
3939				oSort = DataTable.ext.oSort,
3940				aoData = oSettings.aoData,
3941				aoColumns = oSettings.aoColumns,
3942				oAria = oSettings.oLanguage.oAria;
3943			
3944			/* No sorting required if server-side or no sorting array */
3945			if ( !oSettings.oFeatures.bServerSide && 
3946				(oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
3947			{
3948				aaSort = ( oSettings.aaSortingFixed !== null ) ?
3949					oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
3950					oSettings.aaSorting.slice();
3951				
3952				/* If there is a sorting data type, and a function belonging to it, then we need to
3953				 * get the data from the developer's function and apply it for this column
3954				 */
3955				for ( i=0 ; i<aaSort.length ; i++ )
3956				{
3957					var iColumn = aaSort[i][0];
3958					var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
3959					sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
3960					if ( DataTable.ext.afnSortData[sDataType] )
3961					{
3962						var aData = DataTable.ext.afnSortData[sDataType].call( 
3963							oSettings.oInstance, oSettings, iColumn, iVisColumn
3964						);
3965						if ( aData.length === aoData.length )
3966						{
3967							for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
3968							{
3969								_fnSetCellData( oSettings, j, iColumn, aData[j] );
3970							}
3971						}
3972						else
3973						{
3974							_fnLog( oSettings, 0, "Returned data sort array (col "+iColumn+") is the wrong length" );
3975						}
3976					}
3977				}
3978				
3979				/* Create a value - key array of the current row positions such that we can use their
3980				 * current position during the sort, if values match, in order to perform stable sorting
3981				 */
3982				for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
3983				{
3984					aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
3985				}
3986		
3987				/* Build an internal data array which is specific to the sort, so we can get and prep
3988				 * the data to be sorted only once, rather than needing to do it every time the sorting
3989				 * function runs. This make the sorting function a very simple comparison
3990				 */
3991				var iSortLen = aaSort.length;
3992				var fnSortFormat, aDataSort;
3993				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
3994				{
3995					for ( j=0 ; j<iSortLen ; j++ )
3996					{
3997						aDataSort = aoColumns[ aaSort[j][0] ].aDataSort;
3998		
3999						for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4000						{
4001							sDataType = aoColumns[ aDataSort[k] ].sType;
4002							fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ];
4003							
4004							aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ?
4005								fnSortFormat( _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ) ) :
4006								_fnGetCellData( oSettings, i, aDataSort[k], 'sort' );
4007						}
4008					}
4009				}
4010				
4011				/* Do the sort - here we want multi-column sorting based on a given data source (column)
4012				 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4013				 * follow on it's own, but this is what we want (example two column sorting):
4014				 *  fnLocalSorting = function(a,b){
4015				 *  	var iTest;
4016				 *  	iTest = oSort['string-asc']('data11', 'data12');
4017				 *  	if (iTest !== 0)
4018				 *  		return iTest;
4019				 *    iTest = oSort['numeric-desc']('data21', 'data22');
4020				 *    if (iTest !== 0)
4021				 *  		return iTest;
4022				 *  	return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4023				 *  }
4024				 * Basically we have a test for each sorting column, if the data in that column is equal,
4025				 * test the next column. If all columns match, then we use a numeric sort on the row 
4026				 * positions in the original data array to provide a stable sort.
4027				 */
4028				oSettings.aiDisplayMaster.sort( function ( a, b ) {
4029					var k, l, lLen, iTest, aDataSort, sDataType;
4030					for ( k=0 ; k<iSortLen ; k++ )
4031					{
4032						aDataSort = aoColumns[ aaSort[k][0] ].aDataSort;
4033		
4034						for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ )
4035						{
4036							sDataType = aoColumns[ aDataSort[l] ].sType;
4037							
4038							iTest = oSort[ (sDataType ? sDataType : 'string')+"-"+aaSort[k][1] ](
4039								aoData[a]._aSortData[ aDataSort[l] ],
4040								aoData[b]._aSortData[ aDataSort[l] ]
4041							);
4042						
4043							if ( iTest !== 0 )
4044							{
4045								return iTest;
4046							}
4047						}
4048					}
4049					
4050					return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4051				} );
4052			}
4053			
4054			/* Alter the sorting classes to take account of the changes */
4055			if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender )
4056			{
4057				_fnSortingClasses( oSettings );
4058			}
4059		
4060			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
4061			{
4062				var sTitle = aoColumns[i].sTitle.replace( /<.*?>/g, "" );
4063				nTh = aoColumns[i].nTh;
4064				nTh.removeAttribute('aria-sort');
4065				nTh.removeAttribute('aria-label');
4066				
4067				/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4068				if ( aoColumns[i].bSortable )
4069				{
4070					if ( aaSort.length > 0 && aaSort[0][0] == i )
4071					{
4072						nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" );
4073						
4074						var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ? 
4075							aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0];
4076						nTh.setAttribute('aria-label', sTitle+
4077							(nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
4078					}
4079					else
4080					{
4081						nTh.setAttribute('aria-label', sTitle+
4082							(aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
4083					}
4084				}
4085				else
4086				{
4087					nTh.setAttribute('aria-label', sTitle);
4088				}
4089			}
4090			
4091			/* Tell the draw function that we have sorted the data */
4092			oSettings.bSorted = true;
4093			$(oSettings.oInstance).trigger('sort', oSettings);
4094			
4095			/* Copy the master data into the draw array and re-draw */
4096			if ( oSettings.oFeatures.bFilter )
4097			{
4098				/* _fnFilter() will redraw the table for us */
4099				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
4100			}
4101			else
4102			{
4103				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
4104				oSettings._iDisplayStart = 0; /* reset display back to page 0 */
4105				_fnCalculateEnd( oSettings );
4106				_fnDraw( oSettings );
4107			}
4108		}
4109		
4110		
4111		/**
4112		 * Attach a sort handler (click) to a node
4113		 *  @param {object} oSettings dataTables settings object
4114		 *  @param {node} nNode node to attach the handler to
4115		 *  @param {int} iDataIndex column sorting index
4116		 *  @param {function} [fnCallback] callback function
4117		 *  @memberof DataTable#oApi
4118		 */
4119		function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
4120		{
4121			_fnBindAction( nNode, {}, function (e) {
4122				/* If the column is not sortable - don't to anything */
4123				if ( oSettings.aoColumns[iDataIndex].bSortable === false )
4124				{
4125					return;
4126				}
4127				
4128				/*
4129				 * This is a little bit odd I admit... I declare a temporary function inside the scope of
4130				 * _fnBuildHead and the click handler in order that the code presented here can be used 
4131				 * twice - once for when bProcessing is enabled, and another time for when it is 
4132				 * disabled, as we need to perform slightly different actions.
4133				 *   Basically the issue here is that the Javascript engine in modern browsers don't 
4134				 * appear to allow the rendering engine to update the display while it is still executing
4135				 * it's thread (well - it does but only after long intervals). This means that the 
4136				 * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
4137				 * I force an execution break by using setTimeout - but this breaks the expected 
4138				 * thread continuation for the end-developer's point of view (their code would execute
4139				 * too early), so we only do it when we absolutely have to.
4140				 */
4141				var fnInnerSorting = function () {
4142					var iColumn, iNextSort;
4143					
4144					/* If the shift key is pressed then we are multiple column sorting */
4145					if ( e.shiftKey )
4146					{
4147						/* Are we already doing some kind of sort on this column? */
4148						var bFound = false;
4149						for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
4150						{
4151							if ( oSettings.aaSorting[i][0] == iDataIndex )
4152							{
4153								bFound = true;
4154								iColumn = oSettings.aaSorting[i][0];
4155								iNextSort = oSettings.aaSorting[i][2]+1;
4156								
4157								if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
4158								{
4159									/* Reached the end of the sorting options, remove from multi-col sort */
4160									oSettings.aaSorting.splice( i, 1 );
4161								}
4162								else
4163								{
4164									/* Move onto next sorting direction */
4165									oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
4166									oSettings.aaSorting[i][2] = iNextSort;
4167								}
4168								break;
4169							}
4170						}
4171						
4172						/* No sort yet - add it in */
4173						if ( bFound === false )
4174						{
4175							oSettings.aaSorting.push( [ iDataIndex, 
4176								oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
4177						}
4178					}
4179					else
4180					{
4181						/* If no shift key then single column sort */
4182						if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
4183						{
4184							iColumn = oSettings.aaSorting[0][0];
4185							iNextSort = oSettings.aaSorting[0][2]+1;
4186							if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
4187							{
4188								iNextSort = 0;
4189							}
4190							oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
4191							oSettings.aaSorting[0][2] = iNextSort;
4192						}
4193						else
4194						{
4195							oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
4196							oSettings.aaSorting.push( [ iDataIndex, 
4197								oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
4198						}
4199					}
4200					
4201					/* Run the sort */
4202					_fnSort( oSettings );
4203				}; /* /fnInnerSorting */
4204				
4205				if ( !oSettings.oFeatures.bProcessing )
4206				{
4207					fnInnerSorting();
4208				}
4209				else
4210				{
4211					_fnProcessingDisplay( oSettings, true );
4212					setTimeout( function() {
4213						fnInnerSorting();
4214						if ( !oSettings.oFeatures.bServerSide )
4215						{
4216							_fnProcessingDisplay( oSettings, false );
4217						}
4218					}, 0 );
4219				}
4220				
4221				/* Call the user specified callback function - used for async user interaction */
4222				if ( typeof fnCallback == 'function' )
4223				{
4224					fnCallback( oSettings );
4225				}
4226			} );
4227		}
4228		
4229		
4230		/**
4231		 * Set the sorting classes on the header, Note: it is safe to call this function 
4232		 * when bSort and bSortClasses are false
4233		 *  @param {object} oSettings dataTables settings object
4234		 *  @memberof DataTable#oApi
4235		 */
4236		function _fnSortingClasses( oSettings )
4237		{
4238			var i, iLen, j, jLen, iFound;
4239			var aaSort, sClass;
4240			var iColumns = oSettings.aoColumns.length;
4241			var oClasses = oSettings.oClasses;
4242			
4243			for ( i=0 ; i<iColumns ; i++ )
4244			{
4245				if ( oSettings.aoColumns[i].bSortable )
4246				{
4247					$(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
4248						" "+ oSettings.aoColumns[i].sSortingClass );
4249				}
4250			}
4251			
4252			if ( oSettings.aaSortingFixed !== null )
4253			{
4254				aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
4255			}
4256			else
4257			{
4258				aaSort = oSettings.aaSorting.slice();
4259			}
4260			
4261			/* Apply the required classes to the header */
4262			for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
4263			{
4264				if ( oSettings.aoColumns[i].bSortable )
4265				{
4266					sClass = oSettings.aoColumns[i].sSortingClass;
4267					iFound = -1;
4268					for ( j=0 ; j<aaSort.length ; j++ )
4269					{
4270						if ( aaSort[j][0] == i )
4271						{
4272							sClass = ( aaSort[j][1] == "asc" ) ?
4273								oClasses.sSortAsc : oClasses.sSortDesc;
4274							iFound = j;
4275							break;
4276						}
4277					}
4278					$(oSettings.aoColumns[i].nTh).addClass( sClass );
4279					
4280					if ( oSettings.bJUI )
4281					{
4282						/* jQuery UI uses extra markup */
4283						var jqSpan = $("span."+oClasses.sSortIcon,  oSettings.aoColumns[i].nTh);
4284						jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+ 
4285							oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
4286						
4287						var sSpanClass;
4288						if ( iFound == -1 )
4289						{
4290						 	sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
4291						}
4292						else if ( aaSort[iFound][1] == "asc" )
4293						{
4294							sSpanClass = oClasses.sSortJUIAsc;
4295						}
4296						else
4297						{
4298							sSpanClass = oClasses.sSortJUIDesc;
4299						}
4300						
4301						jqSpan.addClass( sSpanClass );
4302					}
4303				}
4304				else
4305				{
4306					/* No sorting on this column, so add the base class. This will have been assigned by
4307					 * _fnAddColumn
4308					 */
4309					$(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
4310				}
4311			}
4312			
4313			/* 
4314			 * Apply the required classes to the table body
4315			 * Note that this is given as a feature switch since it can significantly slow down a sort
4316			 * on large data sets (adding and removing of classes is always slow at the best of times..)
4317			 * Further to this, note that this code is admittedly fairly ugly. It could be made a lot 
4318			 * simpler using jQuery selectors and add/removeClass, but that is significantly slower
4319			 * (on the order of 5 times slower) - hence the direct DOM manipulation here.
4320			 * Note that for deferred drawing we do use jQuery - the reason being that taking the first
4321			 * row found to see if the whole column needs processed can miss classes since the first
4322			 * column might be new.
4323			 */
4324			sClass = oClasses.sSortColumn;
4325			
4326			if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
4327			{
4328				var nTds = _fnGetTdNodes( oSettings );
4329				
4330				/* Determine what the sorting class for each column should be */
4331				var iClass, iTargetCol;
4332				var asClasses = [];
4333				for (i = 0; i < iColumns; i++)
4334				{
4335					asClasses.push("");
4336				}
4337				for (i = 0, iClass = 1; i < aaSort.length; i++)
4338				{
4339					iTargetCol = parseInt( aaSort[i][0], 10 );
4340					asClasses[iTargetCol] = sClass + iClass;
4341					
4342					if ( iClass < 3 )
4343					{
4344						iClass++;
4345					}
4346				}
4347				
4348				/* Make changes to the classes for each cell as needed */
4349				var reClass = new RegExp(sClass + "[123]");
4350				var sTmpClass, sCurrentClass, sNewClass;
4351				for ( i=0, iLen=nTds.length; i<iLen; i++ )
4352				{
4353					/* Determine which column we're looking at */
4354					iTargetCol = i % iColumns;
4355					
4356					/* What is the full list of classes now */
4357					sCurrentClass = nTds[i].className;
4358					/* What sorting class should be applied? */
4359					sNewClass = asClasses[iTargetCol];
4360					/* What would the new full list be if we did a replacement? */
4361					sTmpClass = sCurrentClass.replace(reClass, sNewClass);
4362					
4363					if ( sTmpClass != sCurrentClass )
4364					{
4365						/* We changed something */
4366						nTds[i].className = $.trim( sTmpClass );
4367					}
4368					else if ( sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1 )
4369					{
4370						/* We need to add a class */
4371						nTds[i].className = sCurrentClass + " " + sNewClass;
4372					}
4373				}
4374			}
4375		}
4376		
4377		
4378		
4379		/**
4380		 * Save the state of a table in a cookie such that the page can be reloaded
4381		 *  @param {object} oSettings dataTables settings object
4382		 *  @memberof DataTable#oApi
4383		 */
4384		function _fnSaveState ( oSettings )
4385		{
4386			if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
4387			{
4388				return;
4389			}
4390		
4391			/* Store the interesting variables */
4392			var i, iLen, bInfinite=oSettings.oScroll.bInfinite;
4393			var oState = {
4394				"iCreate":      new Date().getTime(),
4395				"iStart":       (bInfinite ? 0 : oSettings._iDisplayStart),
4396				"iEnd":         (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd),
4397				"iLength":      oSettings._iDisplayLength,
4398				"aaSorting":    $.extend( true, [], oSettings.aaSorting ),
4399				"oSearch":      $.extend( true, {}, oSettings.oPreviousSearch ),
4400				"aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
4401				"abVisCols":    []
4402			};
4403		
4404			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
4405			{
4406				oState.abVisCols.push( oSettings.aoColumns[i].bVisible );
4407			}
4408		
4409			_fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
4410			
4411			oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );
4412		}
4413		
4414		
4415		/**
4416		 * Attempt to load a saved table state from a cookie
4417		 *  @param {object} oSettings dataTables settings object
4418		 *  @param {object} oInit DataTables init object so we can override settings
4419		 *  @memberof DataTable#oApi
4420		 */
4421		function _fnLoadState ( oSettings, oInit )
4422		{
4423			if ( !oSettings.oFeatures.bStateSave )
4424			{
4425				return;
4426			}
4427		
4428			var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );
4429			if ( !oData )
4430			{
4431				return;
4432			}
4433			
4434			/* Allow custom and plug-in manipulation functions to alter the saved data set and
4435			 * cancelling of loading by returning false
4436			 */
4437			var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
4438			if ( $.inArray( false, abStateLoad ) !== -1 )
4439			{
4440				return;
4441			}
4442			
4443			/* Store the saved state so it might be accessed at any time */
4444			oSettings.oLoadedState = $.extend( true, {}, oData );
4445			
4446			/* Restore key features */
4447			oSettings._iDisplayStart    = oData.iStart;
4448			oSettings.iInitDisplayStart = oData.iStart;
4449			oSettings._iDisplayEnd      = oData.iEnd;
4450			oSettings._iDisplayLength   = oData.iLength;
4451			oSettings.aaSorting         = oData.aaSorting.slice();
4452			oSettings.saved_aaSorting   = oData.aaSorting.slice();
4453			
4454			/* Search filtering  */
4455			$.extend( oSettings.oPreviousSearch, oData.oSearch );
4456			$.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
4457			
4458			/* Column visibility state
4459			 * Pass back visibility settings to the init handler, but to do not here override
4460			 * the init object that the user might have passed in
4461			 */
4462			oInit.saved_aoColumns = [];
4463			for ( var i=0 ; i<oData.abVisCols.length ; i++ )
4464			{
4465				oInit.saved_aoColumns[i] = {};
4466				oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
4467			}
4468		
4469			_fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
4470		}
4471		
4472		
4473		/**
4474		 * Create a new cookie with a value to store the state of a table
4475		 *  @param {string} sName name of the cookie to create
4476		 *  @param {string} sValue the value the cookie should take
4477		 *  @param {int} iSecs duration of the cookie
4478		 *  @param {string} sBaseName sName is made up of the base + file name - this is the base
4479		 *  @param {function} fnCallback User definable function to modify the cookie
4480		 *  @memberof DataTable#oApi
4481		 */
4482		function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
4483		{
4484			var date = new Date();
4485			date.setTime( date.getTime()+(iSecs*1000) );
4486			
4487			/* 
4488			 * Shocking but true - it would appear IE has major issues with having the path not having
4489			 * a trailing slash on it. We need the cookie to be available based on the path, so we
4490			 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
4491			 * patch to use at least some of the path
4492			 */
4493			var aParts = window.location.pathname.split('/');
4494			var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
4495			var sFullCookie, oData;
4496			
4497			if ( fnCallback !== null )
4498			{
4499				oData = (typeof $.parseJSON === 'function') ? 
4500					$.parseJSON( sValue ) : eval( '('+sValue+')' );
4501				sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
4502					aParts.join('/')+"/" );
4503			}
4504			else
4505			{
4506				sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
4507					"; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
4508			}
4509			
4510			/* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
4511			 * belonging to DataTables.
4512			 */
4513			var
4514				aCookies =document.cookie.split(';'),
4515				iNewCookieLen = sFullCookie.split(';')[0].length,
4516				aOldCookies = [];
4517			
4518			if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */
4519			{
4520				for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
4521				{
4522					if ( aCookies[i].indexOf( sBaseName ) != -1 )
4523					{
4524						/* It's a DataTables cookie, so eval it and check the time stamp */
4525						var aSplitCookie = aCookies[i].split('=');
4526						try {
4527							oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );
4528		
4529							if ( oData && oData.iCreate )
4530							{
4531								aOldCookies.push( {
4532									"name": aSplitCookie[0],
4533									"time": oData.iCreate
4534								} );
4535							}
4536						}
4537						catch( e ) {}
4538					}
4539				}
4540		
4541				// Make sure we delete the oldest ones first
4542				aOldCookies.sort( function (a, b) {
4543					return b.time - a.time;
4544				} );
4545		
4546				// Eliminate as many old DataTables cookies as we need to
4547				while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) {
4548					if ( aOldCookies.length === 0 ) {
4549						// Deleted all DT cookies and still not enough space. Can't state save
4550						return;
4551					}
4552					
4553					var old = aOldCookies.pop();
4554					document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
4555						aParts.join('/') + "/";
4556				}
4557			}
4558			
4559			document.cookie = sFullCookie;
4560		}
4561		
4562		
4563		/**
4564		 * Read an old cookie to get a cookie with an old table state
4565		 *  @param {string} sName name of the cookie to read
4566		 *  @returns {string} contents of the cookie - or null if no cookie with that name found
4567		 *  @memberof DataTable#oApi
4568		 */
4569		function _fnReadCookie ( sName )
4570		{
4571			var
4572				aParts = window.location.pathname.split('/'),
4573				sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
4574			 	sCookieContents = document.cookie.split(';');
4575			
4576			for( var i=0 ; i<sCookieContents.length ; i++ )
4577			{
4578				var c = sCookieContents[i];
4579				
4580				while (c.charAt(0)==' ')
4581				{
4582					c = c.substring(1,c.length);
4583				}
4584				
4585				if (c.indexOf(sNameEQ) === 0)
4586				{
4587					return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
4588				}
4589			}
4590			return null;
4591		}
4592		
4593		
4594		/**
4595		 * Return the settings object for a particular table
4596		 *  @param {node} nTable table we are using as a dataTable
4597		 *  @returns {object} Settings object - or null if not found
4598		 *  @memberof DataTable#oApi
4599		 */
4600		function _fnSettingsFromNode ( nTable )
4601		{
4602			for ( var i=0 ; i<DataTable.settings.length ; i++ )
4603			{
4604				if ( DataTable.settings[i].nTable === nTable )
4605				{
4606					return DataTable.settings[i];
4607				}
4608			}
4609			
4610			return null;
4611		}
4612		
4613		
4614		/**
4615		 * Return an array with the TR nodes for the table
4616		 *  @param {object} oSettings dataTables settings object
4617		 *  @returns {array} TR array
4618		 *  @memberof DataTable#oApi
4619		 */
4620		function _fnGetTrNodes ( oSettings )
4621		{
4622			var aNodes = [];
4623			var aoData = oSettings.aoData;
4624			for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
4625			{
4626				if ( aoData[i].nTr !== null )
4627				{
4628					aNodes.push( aoData[i].nTr );
4629				}
4630			}
4631			return aNodes;
4632		}
4633		
4634		
4635		/**
4636		 * Return an flat array with all TD nodes for the table, or row
4637		 *  @param {object} oSettings dataTables settings object
4638		 *  @param {int} [iIndividualRow] aoData index to get the nodes for - optional 
4639		 *    if not given then the return array will contain all nodes for the table
4640		 *  @returns {array} TD array
4641		 *  @memberof DataTable#oApi
4642		 */
4643		function _fnGetTdNodes ( oSettings, iIndividualRow )
4644		{
4645			var anReturn = [];
4646			var iCorrector;
4647			var anTds, nTd;
4648			var iRow, iRows=oSettings.aoData.length,
4649				iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
4650			
4651			/* Allow the collection to be limited to just one row */
4652			if ( iIndividualRow !== undefined )
4653			{
4654				iStart = iIndividualRow;
4655				iEnd = iIndividualRow+1;
4656			}
4657		
4658			for ( iRow=iStart ; iRow<iEnd ; iRow++ )
4659			{
4660				oData = oSettings.aoData[iRow];
4661				if ( oData.nTr !== null )
4662				{
4663					/* get the TD child nodes - taking into account text etc nodes */
4664					anTds = [];
4665					nTd = oData.nTr.firstChild;
4666					while ( nTd )
4667					{
4668						sNodeName = nTd.nodeName.toLowerCase();
4669						if ( sNodeName == 'td' || sNodeName == 'th' )
4670						{
4671							anTds.push( nTd );
4672						}
4673						nTd = nTd.nextSibling;
4674					}
4675		
4676					iCorrector = 0;
4677					for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
4678					{
4679						if ( oSettings.aoColumns[iColumn].bVisible )
4680						{
4681							anReturn.push( anTds[iColumn-iCorrector] );
4682						}
4683						else
4684						{
4685							anReturn.push( oData._anHidden[iColumn] );
4686							iCorrector++;
4687						}
4688					}
4689				}
4690			}
4691		
4692			return anReturn;
4693		}
4694		
4695		
4696		/**
4697		 * Log an error message
4698		 *  @param {object} oSettings dataTables settings object
4699		 *  @param {int} iLevel log error messages, or display them to the user
4700		 *  @param {string} sMesg error message
4701		 *  @memberof DataTable#oApi
4702		 */
4703		function _fnLog( oSettings, iLevel, sMesg )
4704		{
4705			var sAlert = (oSettings===null) ?
4706				"DataTables warning: "+sMesg :
4707				"DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
4708			
4709			if ( iLevel === 0 )
4710			{
4711				if ( DataTable.ext.sErrMode == 'alert' )
4712				{
4713					alert( sAlert );
4714				}
4715				else
4716				{
4717					throw new Error(sAlert);
4718				}
4719				return;
4720			}
4721			else if ( window.console && console.log )
4722			{
4723				console.log( sAlert );
4724			}
4725		}
4726		
4727		
4728		/**
4729		 * See if a property is defined on one object, if so assign it to the other object
4730		 *  @param {object} oRet target object
4731		 *  @param {object} oSrc source object
4732		 *  @param {string} sName property
4733		 *  @param {string} [sMappedName] name to map too - optional, sName used if not given
4734		 *  @memberof DataTable#oApi
4735		 */
4736		function _fnMap( oRet, oSrc, sName, sMappedName )
4737		{
4738			if ( sMappedName === undefined )
4739			{
4740				sMappedName = sName;
4741			}
4742			if ( oSrc[sName] !== undefined )
4743			{
4744				oRet[sMappedName] = oSrc[sName];
4745			}
4746		}
4747		
4748		
4749		/**
4750		 * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
4751		 * copy arrays. The reason we need to do this, is that we don't want to deep copy array
4752		 * init values (such as aaSorting) since the dev wouldn't be able to override them, but
4753		 * we do want to deep copy arrays.
4754		 *  @param {object} oOut Object to extend
4755		 *  @param {object} oExtender Object from which the properties will be applied to oOut
4756		 *  @returns {object} oOut Reference, just for convenience - oOut === the return.
4757		 *  @memberof DataTable#oApi
4758		 *  @todo This doesn't take account of arrays inside the deep copied objects.
4759		 */
4760		function _fnExtend( oOut, oExtender )
4761		{
4762			var val;
4763			
4764			for ( var prop in oExtender )
4765			{
4766				if ( oExtender.hasOwnProperty(prop) )
4767				{
4768					val = oExtender[prop];
4769		
4770					if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
4771					{
4772						$.extend( true, oOut[prop], val );
4773					}
4774					else
4775					{
4776						oOut[prop] = val;
4777					}
4778				}
4779			}
4780		
4781			return oOut;
4782		}
4783		
4784		
4785		/**
4786		 * Bind an event handers to allow a click or return key to activate the callback.
4787		 * This is good for accessibility since a return on the keyboard will have the
4788		 * same effect as a click, if the element has focus.
4789		 *  @param {element} n Element to bind the action to
4790		 *  @param {object} oData Data object to pass to the triggered function
4791		 *  @param {function} fn Callback function for when the event is triggered
4792		 *  @memberof DataTable#oApi
4793		 */
4794		function _fnBindAction( n, oData, fn )
4795		{
4796			$(n)
4797				.bind( 'click.DT', oData, function (e) {
4798						n.blur(); // Remove focus outline for mouse users
4799						fn(e);
4800					} )
4801				.bind( 'keypress.DT', oData, function (e){
4802					if ( e.which === 13 ) {
4803						fn(e);
4804					} } )
4805				.bind( 'selectstart.DT', function () {
4806					/* Take the brutal approach to cancelling text selection */
4807					return false;
4808					} );
4809		}
4810		
4811		
4812		/**
4813		 * Register a callback function. Easily allows a callback function to be added to
4814		 * an array store of callback functions that can then all be called together.
4815		 *  @param {object} oSettings dataTables settings object
4816		 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
4817		 *  @param {function} fn Function to be called back
4818		 *  @param {string} sName Identifying name for the callback (i.e. a label)
4819		 *  @memberof DataTable#oApi
4820		 */
4821		function _fnCallbackReg( oSettings, sStore, fn, sName )
4822		{
4823			if ( fn )
4824			{
4825				oSettings[sStore].push( {
4826					"fn": fn,
4827					"sName": sName
4828				} );
4829			}
4830		}
4831		
4832		
4833		/**
4834		 * Fire callback functions and trigger events. Note that the loop over the callback
4835		 * array store is done backwards! Further note that you do not want to fire off triggers
4836		 * in time sensitive applications (for example cell creation) as its slow.
4837		 *  @param {object} oSettings dataTables settings object
4838		 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
4839		 *  @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
4840		 *    is fired
4841		 *  @param {array} aArgs Array of arguments to pass to the callback function / trigger
4842		 *  @memberof DataTable#oApi
4843		 */
4844		function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
4845		{
4846			var aoStore = oSettings[sStore];
4847			var aRet =[];
4848		
4849			for ( var i=aoStore.length-1 ; i>=0 ; i-- )
4850			{
4851				aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
4852			}
4853		
4854			if ( sTrigger !== null )
4855			{
4856				$(oSettings.oInstance).trigger(sTrigger, aArgs);
4857			}
4858		
4859			return aRet;
4860		}
4861		
4862		
4863		/**
4864		 * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
4865		 * library, then we use that as it is fast, safe and accurate. If the function isn't 
4866		 * available then we need to built it ourselves - the inspiration for this function comes
4867		 * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
4868		 * not perfect and absolutely should not be used as a replacement to json2.js - but it does
4869		 * do what we need, without requiring a dependency for DataTables.
4870		 *  @param {object} o JSON object to be converted
4871		 *  @returns {string} JSON string
4872		 *  @memberof DataTable#oApi
4873		 */
4874		var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
4875		{
4876			/* Not an object or array */
4877			var sType = typeof o;
4878			if (sType !== "object" || o === null)
4879			{
4880				// simple data type
4881				if (sType === "string")
4882				{
4883					o = '"'+o+'"';
4884				}
4885				return o+"";
4886			}
4887		
4888			/* If object or array, need to recurse over it */
4889			var
4890				sProp, mValue,
4891				json = [],
4892				bArr = $.isArray(o);
4893			
4894			for (sProp in o)
4895			{
4896				mValue = o[sProp];
4897				sType = typeof mValue;
4898		
4899				if (sType === "string")
4900				{
4901					mValue = '"'+mValue+'"';
4902				}
4903				else if (sType === "object" && mValue !== null)
4904				{
4905					mValue = _fnJsonString(mValue);
4906				}
4907		
4908				json.push((bArr ? "" : '"'+sProp+'":') + mValue);
4909			}
4910		
4911			return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
4912		};
4913		
4914		
4915		/**
4916		 * From some browsers (specifically IE6/7) we need special handling to work around browser
4917		 * bugs - this function is used to detect when these workarounds are needed.
4918		 *  @param {object} oSettings dataTables settings object
4919		 *  @memberof DataTable#oApi
4920		 */
4921		function _fnBrowserDetect( oSettings )
4922		{
4923			/* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
4924			 * width of the scrollbar, while other browsers ensure the inner element is contained
4925			 * without forcing scrolling
4926			 */
4927			var n = $(
4928				'<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+
4929					'<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+
4930						'<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+
4931					'</div>'+
4932				'</div>')[0];
4933		
4934			document.body.appendChild( n );
4935			oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
4936			document.body.removeChild( n );
4937		}
4938		
4939
4940		/**
4941		 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
4942		 * return the resulting jQuery object.
4943		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
4944		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
4945		 *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
4946		 *    criterion ("applied") or all TR elements (i.e. no filter).
4947		 *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
4948		 *    Can be either 'current', whereby the current sorting of the table is used, or
4949		 *    'original' whereby the original order the data was read into the table is used.
4950		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
4951		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
4952		 *    'current' and filter is 'applied', regardless of what they might be given as.
4953		 *  @returns {object} jQuery object, filtered by the given selector.
4954		 *  @dtopt API
4955		 *
4956		 *  @example
4957		 *    $(document).ready(function() {
4958		 *      var oTable = $('#example').dataTable();
4959		 *
4960		 *      // Highlight every second row
4961		 *      oTable.$('tr:odd').css('backgroundColor', 'blue');
4962		 *    } );
4963		 *
4964		 *  @example
4965		 *    $(document).ready(function() {
4966		 *      var oTable = $('#example').dataTable();
4967		 *
4968		 *      // Filter to rows with 'Webkit' in them, add a background colour and then
4969		 *      // remove the filter, thus highlighting the 'Webkit' rows only.
4970		 *      oTable.fnFilter('Webkit');
4971		 *      oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
4972		 *      oTable.fnFilter('');
4973		 *    } );
4974		 */
4975		this.$ = function ( sSelector, oOpts )
4976		{
4977			var i, iLen, a = [], tr;
4978			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
4979			var aoData = oSettings.aoData;
4980			var aiDisplay = oSettings.aiDisplay;
4981			var aiDisplayMaster = oSettings.aiDisplayMaster;
4982		
4983			if ( !oOpts )
4984			{
4985				oOpts = {};
4986			}
4987		
4988			oOpts = $.extend( {}, {
4989				"filter": "none", // applied
4990				"order": "current", // "original"
4991				"page": "all" // current
4992			}, oOpts );
4993		
4994			// Current page implies that order=current and fitler=applied, since it is fairly
4995			// senseless otherwise
4996			if ( oOpts.page == 'current' )
4997			{
4998				for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
4999				{
5000					tr = aoData[ aiDisplay[i] ].nTr;
5001					if ( tr )
5002					{
5003						a.push( tr );
5004					}
5005				}
5006			}
5007			else if ( oOpts.order == "current" && oOpts.filter == "none" )
5008			{
5009				for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )
5010				{
5011					tr = aoData[ aiDisplayMaster[i] ].nTr;
5012					if ( tr )
5013					{
5014						a.push( tr );
5015					}
5016				}
5017			}
5018			else if ( oOpts.order == "current" && oOpts.filter == "applied" )
5019			{
5020				for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )
5021				{
5022					tr = aoData[ aiDisplay[i] ].nTr;
5023					if ( tr )
5024					{
5025						a.push( tr );
5026					}
5027				}
5028			}
5029			else if ( oOpts.order == "original" && oOpts.filter == "none" )
5030			{
5031				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
5032				{
5033					tr = aoData[ i ].nTr ;
5034					if ( tr )
5035					{
5036						a.push( tr );
5037					}
5038				}
5039			}
5040			else if ( oOpts.order == "original" && oOpts.filter == "applied" )
5041			{
5042				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
5043				{
5044					tr = aoData[ i ].nTr;
5045					if ( $.inArray( i, aiDisplay ) !== -1 && tr )
5046					{
5047						a.push( tr );
5048					}
5049				}
5050			}
5051			else
5052			{
5053				_fnLog( oSettings, 1, "Unknown selection options" );
5054			}
5055		
5056			/* We need to filter on the TR elements and also 'find' in their descendants
5057			 * to make the selector act like it would in a full table - so we need
5058			 * to build both results and then combine them together
5059			 */
5060			var jqA = $(a);
5061			var jqTRs = jqA.filter( sSelector );
5062			var jqDescendants = jqA.find( sSelector );
5063		
5064			return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
5065		};
5066		
5067		
5068		/**
5069		 * Almost identical to $ in operation, but in this case returns the data for the matched
5070		 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5071		 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5072		 * rows are found, the data returned is the original data array/object that was used to  
5073		 * create the row (or a generated array if from a DOM source).
5074		 *
5075		 * This method is often useful in-combination with $ where both functions are given the
5076		 * same parameters and the array indexes will match identically.
5077		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5078		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
5079		 *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
5080		 *    criterion ("applied") or all elements (i.e. no filter).
5081		 *  @param {string} [oOpts.order=current] Order of the data in the processed array.
5082		 *    Can be either 'current', whereby the current sorting of the table is used, or
5083		 *    'original' whereby the original order the data was read into the table is used.
5084		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5085		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
5086		 *    'current' and filter is 'applied', regardless of what they might be given as.
5087		 *  @returns {array} Data for the matched elements. If any elements, as a result of the
5088		 *    selector, were not TR, TD or TH elements in the DataTable, they will have a null 
5089		 *    entry in the array.
5090		 *  @dtopt API
5091		 *
5092		 *  @example
5093		 *    $(document).ready(function() {
5094		 *      var oTable = $('#example').dataTable();
5095		 *
5096		 *      // Get the data from the first row in the table
5097		 *      var data = oTable._('tr:first');
5098		 *
5099		 *      // Do something useful with the data
5100		 *      alert( "First cell is: "+data[0] );
5101		 *    } );
5102		 *
5103		 *  @example
5104		 *    $(document).ready(function() {
5105		 *      var oTable = $('#example').dataTable();
5106		 *
5107		 *      // Filter to 'Webkit' and get all data for 
5108		 *      oTable.fnFilter('Webkit');
5109		 *      var data = oTable._('tr', {"filter": "applied"});
5110		 *      
5111		 *      // Do something with the data
5112		 *      alert( data.length+" rows matched the filter" );
5113		 *    } );
5114		 */
5115		this._ = function ( sSelector, oOpts )
5116		{
5117			var aOut = [];
5118			var i, iLen, iIndex;
5119			var aTrs = this.$( sSelector, oOpts );
5120		
5121			for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
5122			{
5123				aOut.push( this.fnGetData(aTrs[i]) );
5124			}
5125		
5126			return aOut;
5127		};
5128		
5129		
5130		/**
5131		 * Add a single new row or multiple rows of data to the table. Please note
5132		 * that this is suitable for client-side processing only - if you are using 
5133		 * server-side processing (i.e. "bServerSide": true), then to add data, you
5134		 * must add it to the data source, i.e. the server-side, through an Ajax call.
5135		 *  @param {array|object} mData The data to be added to the table. This can be:
5136		 *    <ul>
5137		 *      <li>1D array of data - add a single row with the data provided</li>
5138		 *      <li>2D array of arrays - add multiple rows in a single call</li>
5139		 *      <li>object - data object when using <i>mData</i></li>
5140		 *      <li>array of objects - multiple data objects when using <i>mData</i></li>
5141		 *    </ul>
5142		 *  @param {bool} [bRedraw=true] redraw the table or not
5143		 *  @returns {array} An array of integers, representing the list of indexes in 
5144		 *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 
5145		 *    the table.
5146		 *  @dtopt API
5147		 *
5148		 *  @example
5149		 *    // Global var for counter
5150		 *    var giCount = 2;
5151		 *    
5152		 *    $(document).ready(function() {
5153		 *      $('#example').dataTable();
5154		 *    } );
5155		 *    
5156		 *    function fnClickAddRow() {
5157		 *      $('#example').dataTable().fnAddData( [
5158		 *        giCount+".1",
5159		 *        giCount+".2",
5160		 *        giCount+".3",
5161		 *        giCount+".4" ]
5162		 *      );
5163		 *        
5164		 *      giCount++;
5165		 *    }
5166		 */
5167		this.fnAddData = function( mData, bRedraw )
5168		{
5169			if ( mData.length === 0 )
5170			{
5171				return [];
5172			}
5173			
5174			var aiReturn = [];
5175			var iTest;
5176			
5177			/* Find settings from table node */
5178			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5179			
5180			/* Check if we want to add multiple rows or not */
5181			if ( typeof mData[0] === "object" && mData[0] !== null )
5182			{
5183				for ( var i=0 ; i<mData.length ; i++ )
5184				{
5185					iTest = _fnAddData( oSettings, mData[i] );
5186					if ( iTest == -1 )
5187					{
5188						return aiReturn;
5189					}
5190					aiReturn.push( iTest );
5191				}
5192			}
5193			else
5194			{
5195				iTest = _fnAddData( oSettings, mData );
5196				if ( iTest == -1 )
5197				{
5198					return aiReturn;
5199				}
5200				aiReturn.push( iTest );
5201			}
5202			
5203			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
5204			
5205			if ( bRedraw === undefined || bRedraw )
5206			{
5207				_fnReDraw( oSettings );
5208			}
5209			return aiReturn;
5210		};
5211		
5212		
5213		/**
5214		 * This function will make DataTables recalculate the column sizes, based on the data 
5215		 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 
5216		 * through the sWidth parameter). This can be useful when the width of the table's 
5217		 * parent element changes (for example a window resize).
5218		 *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5219		 *  @dtopt API
5220		 *
5221		 *  @example
5222		 *    $(document).ready(function() {
5223		 *      var oTable = $('#example').dataTable( {
5224		 *        "sScrollY": "200px",
5225		 *        "bPaginate": false
5226		 *      } );
5227		 *      
5228		 *      $(window).bind('resize', function () {
5229		 *        oTable.fnAdjustColumnSizing();
5230		 *      } );
5231		 *    } );
5232		 */
5233		this.fnAdjustColumnSizing = function ( bRedraw )
5234		{
5235			var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
5236			_fnAdjustColumnSizing( oSettings );
5237			
5238			if ( bRedraw === undefined || bRedraw )
5239			{
5240				this.fnDraw( false );
5241			}
5242			else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
5243			{
5244				/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5245				this.oApi._fnScrollDraw(oSettings);
5246			}
5247		};
5248		
5249		
5250		/**
5251		 * Quickly and simply clear a table
5252		 *  @param {bool} [bRedraw=true] redraw the table or not
5253		 *  @dtopt API
5254		 *
5255		 *  @example
5256		 *    $(document).ready(function() {
5257		 *      var oTable = $('#example').dataTable();
5258		 *      
5259		 *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5260		 *      oTable.fnClearTable();
5261		 *    } );
5262		 */
5263		this.fnClearTable = function( bRedraw )
5264		{
5265			/* Find settings from table node */
5266			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5267			_fnClearTable( oSettings );
5268			
5269			if ( bRedraw === undefined || bRedraw )
5270			{
5271				_fnDraw( oSettings );
5272			}
5273		};
5274		
5275		
5276		/**
5277		 * The exact opposite of 'opening' a row, this function will close any rows which 
5278		 * are currently 'open'.
5279		 *  @param {node} nTr the table row to 'close'
5280		 *  @returns {int} 0 on success, or 1 if failed (can't find the row)
5281		 *  @dtopt API
5282		 *
5283		 *  @example
5284		 *    $(document).ready(function() {
5285		 *      var oTable;
5286		 *      
5287		 *      // 'open' an information row when a row is clicked on
5288		 *      $('#example tbody tr').click( function () {
5289		 *        if ( oTable.fnIsOpen(this) ) {
5290		 *          oTable.fnClose( this );
5291		 *        } else {
5292		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5293		 *        }
5294		 *      } );
5295		 *      
5296		 *      oTable = $('#example').dataTable();
5297		 *    } );
5298		 */
5299		this.fnClose = function( nTr )
5300		{
5301			/* Find settings from table node */
5302			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5303			
5304			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
5305			{
5306				if ( oSettings.aoOpenRows[i].nParent == nTr )
5307				{
5308					var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
5309					if ( nTrParent )
5310					{
5311						/* Remove it if it is currently on display */
5312						nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
5313					}
5314					oSettings.aoOpenRows.splice( i, 1 );
5315					return 0;
5316				}
5317			}
5318			return 1;
5319		};
5320		
5321		
5322		/**
5323		 * Remove a row for the table
5324		 *  @param {mixed} mTarget The index of the row from aoData to be deleted, or
5325		 *    the TR element you want to delete
5326		 *  @param {function|null} [fnCallBack] Callback function
5327		 *  @param {bool} [bRedraw=true] Redraw the table or not
5328		 *  @returns {array} The row that was deleted
5329		 *  @dtopt API
5330		 *
5331		 *  @example
5332		 *    $(document).ready(function() {
5333		 *      var oTable = $('#example').dataTable();
5334		 *      
5335		 *      // Immediately remove the first row
5336		 *      oTable.fnDeleteRow( 0 );
5337		 *    } );
5338		 */
5339		this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
5340		{
5341			/* Find settings from table node */
5342			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5343			var i, iLen, iAODataIndex;
5344			
5345			iAODataIndex = (typeof mTarget === 'object') ? 
5346				_fnNodeToDataIndex(oSettings, mTarget) : mTarget;
5347			
5348			/* Return the data array from this row */
5349			var oData = oSettings.aoData.splice( iAODataIndex, 1 );
5350		
5351			/* Update the _DT_RowIndex parameter */
5352			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
5353			{
5354				if ( oSettings.aoData[i].nTr !== null )
5355				{
5356					oSettings.aoData[i].nTr._DT_RowIndex = i;
5357				}
5358			}
5359			
5360			/* Remove the target row from the search array */
5361			var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
5362			oSettings.asDataSearch.splice( iDisplayIndex, 1 );
5363			
5364			/* Delete from the display arrays */
5365			_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
5366			_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
5367			
5368			/* If there is a user callback function - call it */
5369			if ( typeof fnCallBack === "function" )
5370			{
5371				fnCallBack.call( this, oSettings, oData );
5372			}
5373			
5374			/* Check for an 'overflow' they case for displaying the table */
5375			if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
5376			{
5377				oSettings._iDisplayStart -= oSettings._iDisplayLength;
5378				if ( oSettings._iDisplayStart < 0 )
5379				{
5380					oSettings._iDisplayStart = 0;
5381				}
5382			}
5383			
5384			if ( bRedraw === undefined || bRedraw )
5385			{
5386				_fnCalculateEnd( oSettings );
5387				_fnDraw( oSettings );
5388			}
5389			
5390			return oData;
5391		};
5392		
5393		
5394		/**
5395		 * Restore the table to it's original state in the DOM by removing all of DataTables 
5396		 * enhancements, alterations to the DOM structure of the table and event listeners.
5397		 *  @param {boolean} [bRemove=false] Completely remove the table from the DOM
5398		 *  @dtopt API
5399		 *
5400		 *  @example
5401		 *    $(document).ready(function() {
5402		 *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
5403		 *      var oTable = $('#example').dataTable();
5404		 *      oTable.fnDestroy();
5405		 *    } );
5406		 */
5407		this.fnDestroy = function ( bRemove )
5408		{
5409			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5410			var nOrig = oSettings.nTableWrapper.parentNode;
5411			var nBody = oSettings.nTBody;
5412			var i, iLen;
5413		
5414			bRemove = (bRemove===undefined) ? false : bRemove;
5415			
5416			/* Flag to note that the table is currently being destroyed - no action should be taken */
5417			oSettings.bDestroying = true;
5418			
5419			/* Fire off the destroy callbacks for plug-ins etc */
5420			_fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );
5421		
5422			/* If the table is not being removed, restore the hidden columns */
5423			if ( !bRemove )
5424			{
5425				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
5426				{
5427					if ( oSettings.aoColumns[i].bVisible === false )
5428					{
5429						this.fnSetColumnVis( i, true );
5430					}
5431				}
5432			}
5433			
5434			/* Blitz all DT events */
5435			$(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
5436			
5437			/* If there is an 'empty' indicator row, remove it */
5438			$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
5439			
5440			/* When scrolling we had to break the table up - restore it */
5441			if ( oSettings.nTable != oSettings.nTHead.parentNode )
5442			{
5443				$(oSettings.nTable).children('thead').remove();
5444				oSettings.nTable.appendChild( oSettings.nTHead );
5445			}
5446			
5447			if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
5448			{
5449				$(oSettings.nTable).children('tfoot').remove();
5450				oSettings.nTable.appendChild( oSettings.nTFoot );
5451			}
5452			
5453			/* Remove the DataTables generated nodes, events and classes */
5454			oSettings.nTable.parentNode.removeChild( oSettings.nTable );
5455			$(oSettings.nTableWrapper).remove();
5456			
5457			oSettings.aaSorting = [];
5458			oSettings.aaSortingFixed = [];
5459			_fnSortingClasses( oSettings );
5460			
5461			$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
5462			
5463			$('th, td', oSettings.nTHead).removeClass( [
5464				oSettings.oClasses.sSortable,
5465				oSettings.oClasses.sSortableAsc,
5466				oSettings.oClasses.sSortableDesc,
5467				oSettings.oClasses.sSortableNone ].join(' ')
5468			);
5469			if ( oSettings.bJUI )
5470			{
5471				$('th span.'+oSettings.oClasses.sSortIcon
5472					+ ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
5473		
5474				$('th, td', oSettings.nTHead).each( function () {
5475					var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
5476					var kids = jqWrapper.contents();
5477					$(this).append( kids );
5478					jqWrapper.remove();
5479				} );
5480			}
5481			
5482			/* Add the TR elements back into the table in their original order */
5483			if ( !bRemove && oSettings.nTableReinsertBefore )
5484			{
5485				nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
5486			}
5487			else if ( !bRemove )
5488			{
5489				nOrig.appendChild( oSettings.nTable );
5490			}
5491		
5492			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
5493			{
5494				if ( oSettings.aoData[i].nTr !== null )
5495				{
5496					nBody.appendChild( oSettings.aoData[i].nTr );
5497				}
5498			}
5499			
5500			/* Restore the width of the original table */
5501			if ( oSettings.oFeatures.bAutoWidth === true )
5502			{
5503			  oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
5504			}
5505			
5506			/* If the were originally stripe classes - then we add them back here. Note
5507			 * this is not fool proof (for example if not all rows had stripe classes - but
5508			 * it's a good effort without getting carried away
5509			 */
5510			iLen = oSettings.asDestroyStripes.length;
5511			if (iLen)
5512			{
5513				var anRows = $(nBody).children('tr');
5514				for ( i=0 ; i<iLen ; i++ )
5515				{
5516					anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );
5517				}
5518			}
5519			
5520			/* Remove the settings object from the settings array */
5521			for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
5522			{
5523				if ( DataTable.settings[i] == oSettings )
5524				{
5525					DataTable.settings.splice( i, 1 );
5526				}
5527			}
5528			
5529			/* End it all */
5530			oSettings = null;
5531			oInit = null;
5532		};
5533		
5534		
5535		/**
5536		 * Redraw the table
5537		 *  @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
5538		 *  @dtopt API
5539		 *
5540		 *  @example
5541		 *    $(document).ready(function() {
5542		 *      var oTable = $('#example').dataTable();
5543		 *      
5544		 *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5545		 *      oTable.fnDraw();
5546		 *    } );
5547		 */
5548		this.fnDraw = function( bComplete )
5549		{
5550			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5551			if ( bComplete === false )
5552			{
5553				_fnCalculateEnd( oSettings );
5554				_fnDraw( oSettings );
5555			}
5556			else
5557			{
5558				_fnReDraw( oSettings );
5559			}
5560		};
5561		
5562		
5563		/**
5564		 * Filter the input based on data
5565		 *  @param {string} sInput String to filter the table on
5566		 *  @param {int|null} [iColumn] Column to limit filtering to
5567		 *  @param {bool} [bRegex=false] Treat as regular expression or not
5568		 *  @param {bool} [bSmart=true] Perform smart filtering or not
5569		 *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5570		 *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5571		 *  @dtopt API
5572		 *
5573		 *  @example
5574		 *    $(document).ready(function() {
5575		 *      var oTable = $('#example').dataTable();
5576		 *      
5577		 *      // Sometime later - filter...
5578		 *      oTable.fnFilter( 'test string' );
5579		 *    } );
5580		 */
5581		this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5582		{
5583			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5584			
5585			if ( !oSettings.oFeatures.bFilter )
5586			{
5587				return;
5588			}
5589			
5590			if ( bRegex === undefined || bRegex === null )
5591			{
5592				bRegex = false;
5593			}
5594			
5595			if ( bSmart === undefined || bSmart === null )
5596			{
5597				bSmart = true;
5598			}
5599			
5600			if ( bShowGlobal === undefined || bShowGlobal === null )
5601			{
5602				bShowGlobal = true;
5603			}
5604			
5605			if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
5606			{
5607				bCaseInsensitive = true;
5608			}
5609			
5610			if ( iColumn === undefined || iColumn === null )
5611			{
5612				/* Global filter */
5613				_fnFilterComplete( oSettings, {
5614					"sSearch":sInput+"",
5615					"bRegex": bRegex,
5616					"bSmart": bSmart,
5617					"bCaseInsensitive": bCaseInsensitive
5618				}, 1 );
5619				
5620				if ( bShowGlobal && oSettings.aanFeatures.f )
5621				{
5622					var n = oSettings.aanFeatures.f;
5623					for ( var i=0, iLen=n.length ; i<iLen ; i++ )
5624					{
5625						// IE9 throws an 'unknown error' if document.activeElement is used
5626						// inside an iframe or frame...
5627						try {
5628							if ( n[i]._DT_Input != document.activeElement )
5629							{
5630								$(n[i]._DT_Input).val( sInput );
5631							}
5632						}
5633						catch ( e ) {
5634							$(n[i]._DT_Input).val( sInput );
5635						}
5636					}
5637				}
5638			}
5639			else
5640			{
5641				/* Single column filter */
5642				$.extend( oSettings.aoPreSearchCols[ iColumn ], {
5643					"sSearch": sInput+"",
5644					"bRegex": bRegex,
5645					"bSmart": bSmart,
5646					"bCaseInsensitive": bCaseInsensitive
5647				} );
5648				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
5649			}
5650		};
5651		
5652		
5653		/**
5654		 * Get the data for the whole table, an individual row or an individual cell based on the 
5655		 * provided parameters.
5656		 *  @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
5657		 *    a TR node then the data source for the whole row will be returned. If given as a
5658		 *    TD/TH cell node then iCol will be automatically calculated and the data for the
5659		 *    cell returned. If given as an integer, then this is treated as the aoData internal
5660		 *    data index for the row (see fnGetPosition) and the data for that row used.
5661		 *  @param {int} [iCol] Optional column index that you want the data of.
5662		 *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
5663		 *    returned. If mRow is defined, just data for that row, and is iCol is
5664		 *    defined, only data for the designated cell is returned.
5665		 *  @dtopt API
5666		 *
5667		 *  @example
5668		 *    // Row data
5669		 *    $(document).ready(function() {
5670		 *      oTable = $('#example').dataTable();
5671		 *
5672		 *      oTable.$('tr').click( function () {
5673		 *        var data = oTable.fnGetData( this );
5674		 *        // ... do something with the array / object of data for the row
5675		 *      } );
5676		 *    } );
5677		 *
5678		 *  @example
5679		 *    // Individual cell data
5680		 *    $(document).ready(function() {
5681		 *      oTable = $('#example').dataTable();
5682		 *
5683		 *      oTable.$('td').click( function () {
5684		 *        var sData = oTable.fnGetData( this );
5685		 *        alert( 'The cell clicked on had the value of '+sData );
5686		 *      } );
5687		 *    } );
5688		 */
5689		this.fnGetData = function( mRow, iCol )
5690		{
5691			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5692			
5693			if ( mRow !== undefined )
5694			{
5695				var iRow = mRow;
5696				if ( typeof mRow === 'object' )
5697				{
5698					var sNode = mRow.nodeName.toLowerCase();
5699					if (sNode === "tr" )
5700					{
5701						iRow = _fnNodeToDataIndex(oSettings, mRow);
5702					}
5703					else if ( sNode === "td" )
5704					{
5705						iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
5706						iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
5707					}
5708				}
5709		
5710				if ( iCol !== undefined )
5711				{
5712					return _fnGetCellData( oSettings, iRow, iCol, '' );
5713				}
5714				return (oSettings.aoData[iRow]!==undefined) ?
5715					oSettings.aoData[iRow]._aData : null;
5716			}
5717			return _fnGetDataMaster( oSettings );
5718		};
5719		
5720		
5721		/**
5722		 * Get an array of the TR nodes that are used in the table's body. Note that you will 
5723		 * typically want to use the '$' API method in preference to this as it is more 
5724		 * flexible.
5725		 *  @param {int} [iRow] Optional row index for the TR element you want
5726		 *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
5727		 *    in the table's body, or iRow is defined, just the TR element requested.
5728		 *  @dtopt API
5729		 *
5730		 *  @example
5731		 *    $(document).ready(function() {
5732		 *      var oTable = $('#example').dataTable();
5733		 *      
5734		 *      // Get the nodes from the table
5735		 *      var nNodes = oTable.fnGetNodes( );
5736		 *    } );
5737		 */
5738		this.fnGetNodes = function( iRow )
5739		{
5740			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5741			
5742			if ( iRow !== undefined ) {
5743				return (oSettings.aoData[iRow]!==undefined) ?
5744					oSettings.aoData[iRow].nTr : null;
5745			}
5746			return _fnGetTrNodes( oSettings );
5747		};
5748		
5749		
5750		/**
5751		 * Get the array indexes of a particular cell from it's DOM element
5752		 * and column index including hidden columns
5753		 *  @param {node} nNode this can either be a TR, TD or TH in the table's body
5754		 *  @returns {int} If nNode is given as a TR, then a single index is returned, or
5755		 *    if given as a cell, an array of [row index, column index (visible), 
5756		 *    column index (all)] is given.
5757		 *  @dtopt API
5758		 *
5759		 *  @example
5760		 *    $(document).ready(function() {
5761		 *      $('#example tbody td').click( function () {
5762		 *        // Get the position of the current data from the node
5763		 *        var aPos = oTable.fnGetPosition( this );
5764		 *        
5765		 *        // Get the data array for this row
5766		 *        var aData = oTable.fnGetData( aPos[0] );
5767		 *        
5768		 *        // Update the data array and return the value
5769		 *        aData[ aPos[1] ] = 'clicked';
5770		 *        this.innerHTML = 'clicked';
5771		 *      } );
5772		 *      
5773		 *      // Init DataTables
5774		 *      oTable = $('#example').dataTable();
5775		 *    } );
5776		 */
5777		this.fnGetPosition = function( nNode )
5778		{
5779			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5780			var sNodeName = nNode.nodeName.toUpperCase();
5781			
5782			if ( sNodeName == "TR" )
5783			{
5784				return _fnNodeToDataIndex(oSettings, nNode);
5785			}
5786			else if ( sNodeName == "TD" || sNodeName == "TH" )
5787			{
5788				var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
5789				var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
5790				return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
5791			}
5792			return null;
5793		};
5794		
5795		
5796		/**
5797		 * Check to see if a row is 'open' or not.
5798		 *  @param {node} nTr the table row to check
5799		 *  @returns {boolean} true if the row is currently open, false otherwise
5800		 *  @dtopt API
5801		 *
5802		 *  @example
5803		 *    $(document).ready(function() {
5804		 *      var oTable;
5805		 *      
5806		 *      // 'open' an information row when a row is clicked on
5807		 *      $('#example tbody tr').click( function () {
5808		 *        if ( oTable.fnIsOpen(this) ) {
5809		 *          oTable.fnClose( this );
5810		 *        } else {
5811		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5812		 *        }
5813		 *      } );
5814		 *      
5815		 *      oTable = $('#example').dataTable();
5816		 *    } );
5817		 */
5818		this.fnIsOpen = function( nTr )
5819		{
5820			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5821			var aoOpenRows = oSettings.aoOpenRows;
5822			
5823			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
5824			{
5825				if ( oSettings.aoOpenRows[i].nParent == nTr )
5826				{
5827					return true;
5828				}
5829			}
5830			return false;
5831		};
5832		
5833		
5834		/**
5835		 * This function will place a new row directly after a row which is currently 
5836		 * on display on the page, with the HTML contents that is passed into the 
5837		 * function. This can be used, for example, to ask for confirmation that a 
5838		 * particular record should be deleted.
5839		 *  @param {node} nTr The table row to 'open'
5840		 *  @param {string|node|jQuery} mHtml The HTML to put into the row
5841		 *  @param {string} sClass Class to give the new TD cell
5842		 *  @returns {node} The row opened. Note that if the table row passed in as the
5843		 *    first parameter, is not found in the table, this method will silently
5844		 *    return.
5845		 *  @dtopt API
5846		 *
5847		 *  @example
5848		 *    $(document).ready(function() {
5849		 *      var oTable;
5850		 *      
5851		 *      // 'open' an information row when a row is clicked on
5852		 *      $('#example tbody tr').click( function () {
5853		 *        if ( oTable.fnIsOpen(this) ) {
5854		 *          oTable.fnClose( this );
5855		 *        } else {
5856		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5857		 *        }
5858		 *      } );
5859		 *      
5860		 *      oTable = $('#example').dataTable();
5861		 *    } );
5862		 */
5863		this.fnOpen = function( nTr, mHtml, sClass )
5864		{
5865			/* Find settings from table node */
5866			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5867		
5868			/* Check that the row given is in the table */
5869			var nTableRows = _fnGetTrNodes( oSettings );
5870			if ( $.inArray(nTr, nTableRows) === -1 )
5871			{
5872				return;
5873			}
5874			
5875			/* the old open one if there is one */
5876			this.fnClose( nTr );
5877			
5878			var nNewRow = document.createElement("tr");
5879			var nNewCell = document.createElement("td");
5880			nNewRow.appendChild( nNewCell );
5881			nNewCell.className = sClass;
5882			nNewCell.colSpan = _fnVisbleColumns( oSettings );
5883		
5884			if (typeof mHtml === "string")
5885			{
5886				nNewCell.innerHTML = mHtml;
5887			}
5888			else
5889			{
5890				$(nNewCell).html( mHtml );
5891			}
5892		
5893			/* If the nTr isn't on the page at the moment - then we don't insert at the moment */
5894			var nTrs = $('tr', oSettings.nTBody);
5895			if ( $.inArray(nTr, nTrs) != -1  )
5896			{
5897				$(nNewRow).insertAfter(nTr);
5898			}
5899			
5900			oSettings.aoOpenRows.push( {
5901				"nTr": nNewRow,
5902				"nParent": nTr
5903			} );
5904			
5905			return nNewRow;
5906		};
5907		
5908		
5909		/**
5910		 * Change the pagination - provides the internal logic for pagination in a simple API 
5911		 * function. With this function you can have a DataTables table go to the next, 
5912		 * previous, first or last pages.
5913		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5914		 *    or page number to jump to (integer), note that page 0 is the first page.
5915		 *  @param {bool} [bRedraw=true] Redraw the table or not
5916		 *  @dtopt API
5917		 *
5918		 *  @example
5919		 *    $(document).ready(function() {
5920		 *      var oTable = $('#example').dataTable();
5921		 *      oTable.fnPageChange( 'next' );
5922		 *    } );
5923		 */
5924		this.fnPageChange = function ( mAction, bRedraw )
5925		{
5926			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5927			_fnPageChange( oSettings, mAction );
5928			_fnCalculateEnd( oSettings );
5929			
5930			if ( bRedraw === undefined || bRedraw )
5931			{
5932				_fnDraw( oSettings );
5933			}
5934		};
5935		
5936		
5937		/**
5938		 * Show a particular column
5939		 *  @param {int} iCol The column whose display should be changed
5940		 *  @param {bool} bShow Show (true) or hide (false) the column
5941		 *  @param {bool} [bRedraw=true] Redraw the table or not
5942		 *  @dtopt API
5943		 *
5944		 *  @example
5945		 *    $(document).ready(function() {
5946		 *      var oTable = $('#example').dataTable();
5947		 *      
5948		 *      // Hide the second column after initialisation
5949		 *      oTable.fnSetColumnVis( 1, false );
5950		 *    } );
5951		 */
5952		this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5953		{
5954			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5955			var i, iLen;
5956			var aoColumns = oSettings.aoColumns;
5957			var aoData = oSettings.aoData;
5958			var nTd, bAppend, iBefore;
5959			
5960			/* No point in doing anything if we are requesting what is already true */
5961			if ( aoColumns[iCol].bVisible == bShow )
5962			{
5963				return;
5964			}
5965			
5966			/* Show the column */
5967			if ( bShow )
5968			{
5969				var iInsert = 0;
5970				for ( i=0 ; i<iCol ; i++ )
5971				{
5972					if ( aoColumns[i].bVisible )
5973					{
5974						iInsert++;
5975					}
5976				}
5977				
5978				/* Need to decide if we should use appendChild or insertBefore */
5979				bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
5980		
5981				/* Which coloumn should we be inserting before? */
5982				if ( !bAppend )
5983				{
5984					for ( i=iCol ; i<aoColumns.length ; i++ )
5985					{
5986						if ( aoColumns[i].bVisible )
5987						{
5988							iBefore = i;
5989							break;
5990						}
5991					}
5992				}
5993		
5994				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
5995				{
5996					if ( aoData[i].nTr !== null )
5997					{
5998						if ( bAppend )
5999						{
6000							aoData[i].nTr.appendChild( 
6001								aoData[i]._anHidden[iCol]
6002							);
6003						}
6004						else
6005						{
6006							aoData[i].nTr.insertBefore(
6007								aoData[i]._anHidden[iCol], 
6008								_fnGetTdNodes( oSettings, i )[iBefore] );
6009						}
6010					}
6011				}
6012			}
6013			else
6014			{
6015				/* Remove a column from display */
6016				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
6017				{
6018					if ( aoData[i].nTr !== null )
6019					{
6020						nTd = _fnGetTdNodes( oSettings, i )[iCol];
6021						aoData[i]._anHidden[iCol] = nTd;
6022						nTd.parentNode.removeChild( nTd );
6023					}
6024				}
6025			}
6026		
6027			/* Clear to set the visible flag */
6028			aoColumns[iCol].bVisible = bShow;
6029		
6030			/* Redraw the header and footer based on the new column visibility */
6031			_fnDrawHead( oSettings, oSettings.aoHeader );
6032			if ( oSettings.nTFoot )
6033			{
6034				_fnDrawHead( oSettings, oSettings.aoFooter );
6035			}
6036			
6037			/* If there are any 'open' rows, then we need to alter the colspan for this col change */
6038			for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
6039			{
6040				oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
6041			}
6042			
6043			/* Do a redraw incase anything depending on the table columns needs it 
6044			 * (built-in: scrolling) 
6045			 */
6046			if ( bRedraw === undefined || bRedraw )
6047			{
6048				_fnAdjustColumnSizing( oSettings );
6049				_fnDraw( oSettings );
6050			}
6051			
6052			_fnSaveState( oSettings );
6053		};
6054		
6055		
6056		/**
6057		 * Get the settings for a particular table for external manipulation
6058		 *  @returns {object} DataTables settings object. See 
6059		 *    {@link DataTable.models.oSettings}
6060		 *  @dtopt API
6061		 *
6062		 *  @example
6063		 *    $(document).ready(function() {
6064		 *      var oTable = $('#example').dataTable();
6065		 *      var oSettings = oTable.fnSettings();
6066		 *      
6067		 *      // Show an example parameter from the settings
6068		 *      alert( oSettings._iDisplayStart );
6069		 *    } );
6070		 */
6071		this.fnSettings = function()
6072		{
6073			return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
6074		};
6075		
6076		
6077		/**
6078		 * Sort the table by a particular column
6079		 *  @param {int} iCol the data index to sort on. Note that this will not match the 
6080		 *    'display index' if you have hidden data entries
6081		 *  @dtopt API
6082		 *
6083		 *  @example
6084		 *    $(document).ready(function() {
6085		 *      var oTable = $('#example').dataTable();
6086		 *      
6087		 *      // Sort immediately with columns 0 and 1
6088		 *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
6089		 *    } );
6090		 */
6091		this.fnSort = function( aaSort )
6092		{
6093			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
6094			oSettings.aaSorting = aaSort;
6095			_fnSort( oSettings );
6096		};
6097		
6098		
6099		/**
6100		 * Attach a sort listener to an element for a given column
6101		 *  @param {node} nNode the element to attach the sort listener to
6102		 *  @param {int} iColumn the column that a click on this node will sort on
6103		 *  @param {function} [fnCallback] callback function when sort is run
6104		 *  @dtopt API
6105		 *
6106		 *  @example
6107		 *    $(document).ready(function() {
6108		 *      var oTable = $('#example').dataTable();
6109		 *      
6110		 *      // Sort on column 1, when 'sorter' is clicked on
6111		 *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
6112		 *    } );
6113		 */
6114		this.fnSortListener = function( nNode, iColumn, fnCallback )
6115		{
6116			_fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
6117			 	fnCallback );
6118		};
6119		
6120		
6121		/**
6122		 * Update a table cell or row - this method will accept either a single value to
6123		 * update the cell with, an array of values with one element for each column or
6124		 * an object in the same format as the original data source. The function is
6125		 * self-referencing in order to make the multi column updates easier.
6126		 *  @param {object|array|string} mData Data to update the cell/row with
6127		 *  @param {node|int} mRow TR element you want to update or the aoData index
6128		 *  @param {int} [iColumn] The column to update (not used of mData is an array or object)
6129		 *  @param {bool} [bRedraw=true] Redraw the table or not
6130		 *  @param {bool} [bAction=true] Perform pre-draw actions or not
6131		 *  @returns {int} 0 on success, 1 on error
6132		 *  @dtopt API
6133		 *
6134		 *  @example
6135		 *    $(document).ready(function() {
6136		 *      var oTable = $('#example').dataTable();
6137		 *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
6138		 *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
6139		 *    } );
6140		 */
6141		this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
6142		{
6143			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
6144			var i, iLen, sDisplay;
6145			var iRow = (typeof mRow === 'object') ? 
6146				_fnNodeToDataIndex(oSettings, mRow) : mRow;
6147			
6148			if ( $.isArray(mData) && iColumn === undefined )
6149			{
6150				/* Array update - update the whole row */
6151				oSettings.aoData[iRow]._aData = mData.slice();
6152				
6153				/* Flag to the function that we are recursing */
6154				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
6155				{
6156					this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
6157				}
6158			}
6159			else if ( $.isPlainObject(mData) && iColumn === undefined )
6160			{
6161				/* Object update - update the whole row - assume the developer gets the object right */
6162				oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
6163		
6164				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
6165				{
6166					this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
6167				}
6168			}
6169			else
6170			{
6171				/* Individual cell update */
6172				_fnSetCellData( oSettings, iRow, iColumn, mData );
6173				sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
6174				
6175				var oCol = oSettings.aoColumns[iColumn];
6176				if ( oCol.fnRender !== null )
6177				{
6178					sDisplay = _fnRender( oSettings, iRow, iColumn );
6179					if ( oCol.bUseRendered )
6180					{
6181						_fnSetCellData( oSettings, iRow, iColumn, sDisplay );
6182					}
6183				}
6184				
6185				if ( oSettings.aoData[iRow].nTr !== null )
6186				{
6187					/* Do the actual HTML update */
6188					_fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
6189				}
6190			}
6191			
6192			/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
6193			 * will rebuild the search array - however, the redraw might be disabled by the user)
6194			 */
6195			var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
6196			oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(
6197				oSettings, 
6198				_fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )
6199			);
6200			
6201			/* Perform pre-draw actions */
6202			if ( bAction === undefined || bAction )
6203			{
6204				_fnAdjustColumnSizing( oSettings );
6205			}
6206			
6207			/* Redraw the table */
6208			if ( bRedraw === undefined || bRedraw )
6209			{
6210				_fnReDraw( oSettings );
6211			}
6212			return 0;
6213		};
6214		
6215		
6216		/**
6217		 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6218		 * to ensure compatibility.
6219		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6220		 *    formats "X" and "X.Y" are also acceptable.
6221		 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
6222		 *    version, or false if this version of DataTales is not suitable
6223		 *  @method
6224		 *  @dtopt API
6225		 *
6226		 *  @example
6227		 *    $(document).ready(function() {
6228		 *      var oTable = $('#example').dataTable();
6229		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
6230		 *    } );
6231		 */
6232		this.fnVersionCheck = DataTable.ext.fnVersionCheck;
6233		
6234		
6235		/*
6236		 * This is really a good bit rubbish this method of exposing the internal methods
6237		 * publicly... - To be fixed in 2.0 using methods on the prototype
6238		 */
6239		
6240		
6241		/**
6242		 * Create a wrapper function for exporting an internal functions to an external API.
6243		 *  @param {string} sFunc API function name
6244		 *  @returns {function} wrapped function
6245		 *  @memberof DataTable#oApi
6246		 */
6247		function _fnExternApiFunc (sFunc)
6248		{
6249			return function() {
6250				var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat( 
6251					Array.prototype.slice.call(arguments) );
6252				return DataTable.ext.oApi[sFunc].apply( this, aArgs );
6253			};
6254		}
6255		
6256		
6257		/**
6258		 * Reference to internal functions for use by plug-in developers. Note that these
6259		 * methods are references to internal functions and are considered to be private.
6260		 * If you use these methods, be aware that they are liable to change between versions
6261		 * (check the upgrade notes).
6262		 *  @namespace
6263		 */
6264		this.oApi = {
6265			"_fnExternApiFunc": _fnExternApiFunc,
6266			"_fnInitialise": _fnInitialise,
6267			"_fnInitComplete": _fnInitComplete,
6268			"_fnLanguageCompat": _fnLanguageCompat,
6269			"_fnAddColumn": _fnAddColumn,
6270			"_fnColumnOptions": _fnColumnOptions,
6271			"_fnAddData": _fnAddData,
6272			"_fnCreateTr": _fnCreateTr,
6273			"_fnGatherData": _fnGatherData,
6274			"_fnBuildHead": _fnBuildHead,
6275			"_fnDrawHead": _fnDrawHead,
6276			"_fnDraw": _fnDraw,
6277			"_fnReDraw": _fnReDraw,
6278			"_fnAjaxUpdate": _fnAjaxUpdate,
6279			"_fnAjaxParameters": _fnAjaxParameters,
6280			"_fnAjaxUpdateDraw": _fnAjaxUpdateDraw,
6281			"_fnServerParams": _fnServerParams,
6282			"_fnAddOptionsHtml": _fnAddOptionsHtml,
6283			"_fnFeatureHtmlTable": _fnFeatureHtmlTable,
6284			"_fnScrollDraw": _fnScrollDraw,
6285			"_fnAdjustColumnSizing": _fnAdjustColumnSizing,
6286			"_fnFeatureHtmlFilter": _fnFeatureHtmlFilter,
6287			"_fnFilterComplete": _fnFilterComplete,
6288			"_fnFilterCustom": _fnFilterCustom,
6289			"_fnFilterColumn": _fnFilterColumn,
6290			"_fnFilter": _fnFilter,
6291			"_fnBuildSearchArray": _fnBuildSearchArray,
6292			"_fnBuildSearchRow": _fnBuildSearchRow,
6293			"_fnFilterCreateSearch": _fnFilterCreateSearch,
6294			"_fnDataToSearch": _fnDataToSearch,
6295			"_fnSort": _fnSort,
6296			"_fnSortAttachListener": _fnSortAttachListener,
6297			"_fnSortingClasses": _fnSortingClasses,
6298			"_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate,
6299			"_fnPageChange": _fnPageChange,
6300			"_fnFeatureHtmlInfo": _fnFeatureHtmlInfo,
6301			"_fnUpdateInfo": _fnUpdateInfo,
6302			"_fnFeatureHtmlLength": _fnFeatureHtmlLength,
6303			"_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing,
6304			"_fnProcessingDisplay": _fnProcessingDisplay,
6305			"_fnVisibleToColumnIndex": _fnVisibleToColumnIndex,
6306			"_fnColumnIndexToVisible": _fnColumnIndexToVisible,
6307			"_fnNodeToDataIndex": _fnNodeToDataIndex,
6308			"_fnVisbleColumns": _fnVisbleColumns,
6309			"_fnCalculateEnd": _fnCalculateEnd,
6310			"_fnConvertToWidth": _fnConvertToWidth,
6311			"_fnCalculateColumnWidths": _fnCalculateColumnWidths,
6312			"_fnScrollingWidthAdjust": _fnScrollingWidthAdjust,
6313			"_fnGetWidestNode": _fnGetWidestNode,
6314			"_fnGetMaxLenString": _fnGetMaxLenString,
6315			"_fnStringToCss": _fnStringToCss,
6316			"_fnDetectType": _fnDetectType,
6317			"_fnSettingsFromNode": _fnSettingsFromNode,
6318			"_fnGetDataMaster": _fnGetDataMaster,
6319			"_fnGetTrNodes": _fnGetTrNodes,
6320			"_fnGetTdNodes": _fnGetTdNodes,
6321			"_fnEscapeRegex": _fnEscapeRegex,
6322			"_fnDeleteIndex": _fnDeleteIndex,
6323			"_fnReOrderIndex": _fnReOrderIndex,
6324			"_fnColumnOrdering": _fnColumnOrdering,
6325			"_fnLog": _fnLog,
6326			"_fnClearTable": _fnClearTable,
6327			"_fnSaveState": _fnSaveState,
6328			"_fnLoadState": _fnLoadState,
6329			"_fnCreateCookie": _fnCreateCookie,
6330			"_fnReadCookie": _fnReadCookie,
6331			"_fnDetectHeader": _fnDetectHeader,
6332			"_fnGetUniqueThs": _fnGetUniqueThs,
6333			"_fnScrollBarWidth": _fnScrollBarWidth,
6334			"_fnApplyToChildren": _fnApplyToChildren,
6335			"_fnMap": _fnMap,
6336			"_fnGetRowData": _fnGetRowData,
6337			"_fnGetCellData": _fnGetCellData,
6338			"_fnSetCellData": _fnSetCellData,
6339			"_fnGetObjectDataFn": _fnGetObjectDataFn,
6340			"_fnSetObjectDataFn": _fnSetObjectDataFn,
6341			"_fnApplyColumnDefs": _fnApplyColumnDefs,
6342			"_fnBindAction": _fnBindAction,
6343			"_fnExtend": _fnExtend,
6344			"_fnCallbackReg": _fnCallbackReg,
6345			"_fnCallbackFire": _fnCallbackFire,
6346			"_fnJsonString": _fnJsonString,
6347			"_fnRender": _fnRender,
6348			"_fnNodeToColumnIndex": _fnNodeToColumnIndex,
6349			"_fnInfoMacros": _fnInfoMacros,
6350			"_fnBrowserDetect": _fnBrowserDetect,
6351			"_fnGetColumns": _fnGetColumns
6352		};
6353		
6354		$.extend( DataTable.ext.oApi, this.oApi );
6355		
6356		for ( var sFunc in DataTable.ext.oApi )
6357		{
6358			if ( sFunc )
6359			{
6360				this[sFunc] = _fnExternApiFunc(sFunc);
6361			}
6362		}
6363		
6364		
6365		var _that = this;
6366		this.each(function() {
6367			var i=0, iLen, j, jLen, k, kLen;
6368			var sId = this.getAttribute( 'id' );
6369			var bInitHandedOff = false;
6370			var bUsePassedData = false;
6371			
6372			
6373			/* Sanity check */
6374			if ( this.nodeName.toLowerCase() != 'table' )
6375			{
6376				_fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+
6377					"table: "+this.nodeName );
6378				return;
6379			}
6380			
6381			/* Check to see if we are re-initialising a table */
6382			for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
6383			{
6384				/* Base check on table node */
6385				if ( DataTable.settings[i].nTable == this )
6386				{
6387					if ( oInit === undefined || oInit.bRetrieve )
6388					{
6389						return DataTable.settings[i].oInstance;
6390					}
6391					else if ( oInit.bDestroy )
6392					{
6393						DataTable.settings[i].oInstance.fnDestroy();
6394						break;
6395					}
6396					else
6397					{
6398						/*_fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+
6399							"To retrieve the DataTables object for this table, pass no arguments or see "+
6400							"the docs for bRetrieve and bDestroy" );*/
6401						return;
6402					}
6403				}
6404				
6405				/* If the element we are initialising has the same ID as a table which was previously
6406				 * initialised, but the table nodes don't match (from before) then we destroy the old
6407				 * instance by simply deleting it. This is under the assumption that the table has been
6408				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6409				 */
6410				if ( DataTable.settings[i].sTableId == this.id )
6411				{
6412					DataTable.settings.splice( i, 1 );
6413					break;
6414				}
6415			}
6416			
6417			/* Ensure the table has an ID - required for accessibility */
6418			if ( sId === null || sId === "" )
6419			{
6420				sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);
6421				this.id = sId;
6422			}
6423			
6424			/* Create the settings object for this table and set some of the default parameters */
6425			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6426				"nTable":        this,
6427				"oApi":          _that.oApi,
6428				"oInit":         oInit,
6429				"sDestroyWidth": $(this).width(),
6430				"sInstance":     sId,
6431				"sTableId":      sId
6432			} );
6433			DataTable.settings.push( oSettings );
6434			
6435			// Need to add the instance after the instance after the settings object has been added
6436			// to the settings array, so we can self reference the table instance if more than one
6437			oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6438			
6439			/* Setting up the initialisation object */
6440			if ( !oInit )
6441			{
6442				oInit = {};
6443			}
6444			
6445			// Backwards compatibility, before we apply all the defaults
6446			if ( oInit.oLanguage )
6447			{
6448				_fnLanguageCompat( oInit.oLanguage );
6449			}
6450			
6451			oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );
6452			
6453			// Map the initialisation options onto the settings object
6454			_fnMap( oSettings.oFeatures, oInit, "bPaginate" );
6455			_fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
6456			_fnMap( oSettings.oFeatures, oInit, "bFilter" );
6457			_fnMap( oSettings.oFeatures, oInit, "bSort" );
6458			_fnMap( oSettings.oFeatures, oInit, "bInfo" );
6459			_fnMap( oSettings.oFeatures, oInit, "bProcessing" );
6460			_fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
6461			_fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
6462			_fnMap( oSettings.oFeatures, oInit, "bServerSide" );
6463			_fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
6464			_fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
6465			_fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
6466			_fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
6467			_fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
6468			_fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
6469			_fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
6470			_fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
6471			_fnMap( oSettings, oInit, "asStripeClasses" );
6472			_fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
6473			_fnMap( oSettings, oInit, "fnServerData" );
6474			_fnMap( oSettings, oInit, "fnFormatNumber" );
6475			_fnMap( oSettings, oInit, "sServerMethod" );
6476			_fnMap( oSettings, oInit, "aaSorting" );
6477			_fnMap( oSettings, oInit, "aaSortingFixed" );
6478			_fnMap( oSettings, oInit, "aLengthMenu" );
6479			_fnMap( oSettings, oInit, "sPaginationType" );
6480			_fnMap( oSettings, oInit, "sAjaxSource" );
6481			_fnMap( oSettings, oInit, "sAjaxDataProp" );
6482			_fnMap( oSettings, oInit, "iCookieDuration" );
6483			_fnMap( oSettings, oInit, "sCookiePrefix" );
6484			_fnMap( oSettings, oInit, "sDom" );
6485			_fnMap( oSettings, oInit, "bSortCellsTop" );
6486			_fnMap( oSettings, oInit, "iTabIndex" );
6487			_fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
6488			_fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
6489			_fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
6490			_fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
6491			_fnMap( oSettings, oInit, "fnCookieCallback" );
6492			_fnMap( oSettings, oInit, "fnStateLoad" );
6493			_fnMap( oSettings, oInit, "fnStateSave" );
6494			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6495			
6496			/* Callback functions which are array driven */
6497			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
6498			_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
6499			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
6500			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
6501			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
6502			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
6503			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
6504			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
6505			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
6506			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
6507			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
6508			
6509			if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
6510				   oSettings.oFeatures.bSortClasses )
6511			{
6512				/* Enable sort classes for server-side processing. Safe to do it here, since server-side
6513				 * processing must be enabled by the developer
6514				 */
6515				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );
6516			}
6517			else if ( oSettings.oFeatures.bDeferRender )
6518			{
6519				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );
6520			}
6521			
6522			if ( oInit.bJQueryUI )
6523			{
6524				/* Use the JUI classes object for display. You could clone the oStdClasses object if 
6525				 * you want to have multiple tables with multiple independent classes 
6526				 */
6527				$.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );
6528				
6529				if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )
6530				{
6531					/* Set the DOM to use a layout suitable for jQuery UI's theming */
6532					oSettings.sDom = '<"H"lfr>t<"F"ip>';
6533				}
6534			}
6535			else
6536			{
6537				$.extend( oSettings.oClasses, DataTable.ext.oStdClasses );
6538			}
6539			$(this).addClass( oSettings.oClasses.sTable );
6540			
6541			/* Calculate the scroll bar width and cache it for use later on */
6542			if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6543			{
6544				oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6545			}
6546			
6547			if ( oSettings.iInitDisplayStart === undefined )
6548			{
6549				/* Display start point, taking into account the save saving */
6550				oSettings.iInitDisplayStart = oInit.iDisplayStart;
6551				oSettings._iDisplayStart = oInit.iDisplayStart;
6552			}
6553			
6554			/* Must be done after everything which can be overridden by a cookie! */
6555			if ( oInit.bStateSave )
6556			{
6557				oSettings.oFeatures.bStateSave = true;
6558				_fnLoadState( oSettings, oInit );
6559				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6560			}
6561			
6562			if ( oInit.iDeferLoading !== null )
6563			{
6564				oSettings.bDeferLoading = true;
6565				var tmp = $.isArray( oInit.iDeferLoading );
6566				oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6567				oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6568			}
6569			
6570			if ( oInit.aaData !== null )
6571			{
6572				bUsePassedData = true;
6573			}
6574			
6575			/* Language definitions */
6576			if ( oInit.oLanguage.sUrl !== "" )
6577			{
6578				/* Get the language definitions from a file - because this Ajax call makes the language
6579				 * get async to the remainder of this function we use bInitHandedOff to indicate that 
6580				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6581				 */
6582				oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
6583				$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
6584					_fnLanguageCompat( json );
6585					$.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
6586					_fnInitialise( oSettings );
6587				} );
6588				bInitHandedOff = true;
6589			}
6590			else
6591			{
6592				$.extend( true, oSettings.oLanguage, oInit.oLanguage );
6593			}
6594			
6595			
6596			/*
6597			 * Stripes
6598			 */
6599			if ( oInit.asStripeClasses === null )
6600			{
6601				oSettings.asStripeClasses =[
6602					oSettings.oClasses.sStripeOdd,
6603					oSettings.oClasses.sStripeEven
6604				];
6605			}
6606			
6607			/* Remove row stripe classes if they are already on the table row */
6608			iLen=oSettings.asStripeClasses.length;
6609			oSettings.asDestroyStripes = [];
6610			if (iLen)
6611			{
6612				var bStripeRemove = false;
6613				var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')');
6614				for ( i=0 ; i<iLen ; i++ )
6615				{
6616					if ( anRows.hasClass( oSettings.asStripeClasses[i] ) )
6617					{
6618						bStripeRemove = true;
6619						
6620						/* Store the classes which we are about to remove so they can be re-added on destroy */
6621						oSettings.asDestroyStripes.push( oSettings.asStripeClasses[i] );
6622					}
6623				}
6624				
6625				if ( bStripeRemove )
6626				{
6627					anRows.removeClass( oSettings.asStripeClasses.join(' ') );
6628				}
6629			}
6630			
6631			/*
6632			 * Columns
6633			 * See if we should load columns automatically or use defined ones
6634			 */
6635			var anThs = [];
6636			var aoColumnsInit;
6637			var nThead = this.getElementsByTagName('thead');
6638			if ( nThead.length !== 0 )
6639			{
6640				_fnDetectHeader( oSettings.aoHeader, nThead[0] );
6641				anThs = _fnGetUniqueThs( oSettings );
6642			}
6643			
6644			/* If not given a column array, generate one with nulls */
6645			if ( oInit.aoColumns === null )
6646			{
6647				aoColumnsInit = [];
6648				for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6649				{
6650					aoColumnsInit.push( null );
6651				}
6652			}
6653			else
6654			{
6655				aoColumnsInit = oInit.aoColumns;
6656			}
6657			
6658			/* Add the columns */
6659			for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6660			{
6661				/* Short cut - use the loop to check if we have column visibility state to restore */
6662				if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen )
6663				{
6664					if ( aoColumnsInit[i] === null )
6665					{
6666						aoColumnsInit[i] = {};
6667					}
6668					aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
6669				}
6670				
6671				_fnAddColumn( oSettings, anThs ? anThs[i] : null );
6672			}
6673			
6674			/* Apply the column definitions */
6675			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6676				_fnColumnOptions( oSettings, iCol, oDef );
6677			} );
6678			
6679			
6680			/*
6681			 * Sorting
6682			 * Check the aaSorting array
6683			 */
6684			for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
6685			{
6686				if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
6687				{
6688					oSettings.aaSorting[i][0] = 0;
6689				}
6690				var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
6691				
6692				/* Add a default sorting index */
6693				if ( oSettings.aaSorting[i][2] === undefined )
6694				{
6695					oSettings.aaSorting[i][2] = 0;
6696				}
6697				
6698				/* If aaSorting is not defined, then we use the first indicator in asSorting */
6699				if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined )
6700				{
6701					oSettings.aaSorting[i][1] = oColumn.asSorting[0];
6702				}
6703				
6704				/* Set the current sorting index based on aoColumns.asSorting */
6705				for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
6706				{
6707					if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
6708					{
6709						oSettings.aaSorting[i][2] = j;
6710						break;
6711					}
6712				}
6713			}
6714				
6715			/* Do a first pass on the sorting classes (allows any size changes to be taken into
6716			 * account, and also will apply sorting disabled classes if disabled
6717			 */
6718			_fnSortingClasses( oSettings );
6719			
6720			
6721			/*
6722			 * Final init
6723			 * Cache the header, body and footer as required, creating them if needed
6724			 */
6725			
6726			/* Browser support detection */
6727			_fnBrowserDetect( oSettings );
6728			
6729			// Work around for Webkit bug 83867 - store the caption-side before removing from doc
6730			var captions = $(this).children('caption').each( function () {
6731				this._captionSide = $(this).css('caption-side');
6732			} );
6733			
6734			var thead = $(this).children('thead');
6735			if ( thead.length === 0 )
6736			{
6737				thead = [ document.createElement( 'thead' ) ];
6738				this.appendChild( thead[0] );
6739			}
6740			oSettings.nTHead = thead[0];
6741			
6742			var tbody = $(this).children('tbody');
6743			if ( tbody.length === 0 )
6744			{
6745				tbody = [ document.createElement( 'tbody' ) ];
6746				this.appendChild( tbody[0] );
6747			}
6748			oSettings.nTBody = tbody[0];
6749			oSettings.nTBody.setAttribute( "role", "alert" );
6750			oSettings.nTBody.setAttribute( "aria-live", "polite" );
6751			oSettings.nTBody.setAttribute( "aria-relevant", "all" );
6752			
6753			var tfoot = $(this).children('tfoot');
6754			if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6755			{
6756				// If we are a scrolling table, and no footer has been given, then we need to create
6757				// a tfoot element for the caption element to be appended to
6758				tfoot = [ document.createElement( 'tfoot' ) ];
6759				this.appendChild( tfoot[0] );
6760			}
6761			
6762			if ( tfoot.length > 0 )
6763			{
6764				oSettings.nTFoot = tfoot[0];
6765				_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6766			}
6767			
6768			/* Check if there is data passing into the constructor */
6769			if ( bUsePassedData )
6770			{
6771				for ( i=0 ; i<oInit.aaData.length ; i++ )
6772				{
6773					_fnAddData( oSettings, oInit.aaData[ i ] );
6774				}
6775			}
6776			else
6777			{
6778				/* Grab the data from the page */
6779				_fnGatherData( oSettings );
6780			}
6781			
6782			/* Copy the data index array */
6783			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6784			
6785			/* Initialisation complete - table can be drawn */
6786			oSettings.bInitialised = true;
6787			
6788			/* Check if we need to initialise the table (it might not have been handed off to the
6789			 * language processor)
6790			 */
6791			if ( bInitHandedOff === false )
6792			{
6793				_fnInitialise( oSettings );
6794			}
6795		} );
6796		_that = null;
6797		return this;
6798	};
6799
6800	
6801	
6802	/**
6803	 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6804	 * to ensure compatibility.
6805	 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6806	 *    formats "X" and "X.Y" are also acceptable.
6807	 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
6808	 *    version, or false if this version of DataTales is not suitable
6809	 *  @static
6810	 *  @dtopt API-Static
6811	 *
6812	 *  @example
6813	 *    alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );
6814	 */
6815	DataTable.fnVersionCheck = function( sVersion )
6816	{
6817		/* This is cheap, but effective */
6818		var fnZPad = function (Zpad, count)
6819		{
6820			while(Zpad.length < count) {
6821				Zpad += '0';
6822			}
6823			return Zpad;
6824		};
6825		var aThis = DataTable.ext.sVersion.split('.');
6826		var aThat = sVersion.split('.');
6827		var sThis = '', sThat = '';
6828		
6829		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
6830		{
6831			sThis += fnZPad( aThis[i], 3 );
6832			sThat += fnZPad( aThat[i], 3 );
6833		}
6834		
6835		return parseInt(sThis, 10) >= parseInt(sThat, 10);
6836	};
6837	
6838	
6839	/**
6840	 * Check if a TABLE node is a DataTable table already or not.
6841	 *  @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other
6842	 *    node types can be passed in, but will always return false).
6843	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
6844	 *  @static
6845	 *  @dtopt API-Static
6846	 *
6847	 *  @example
6848	 *    var ex = document.getElementById('example');
6849	 *    if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {
6850	 *      $(ex).dataTable();
6851	 *    }
6852	 */
6853	DataTable.fnIsDataTable = function ( nTable )
6854	{
6855		var o = DataTable.settings;
6856	
6857		for ( var i=0 ; i<o.length ; i++ )
6858		{
6859			if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable )
6860			{
6861				return true;
6862			}
6863		}
6864	
6865		return false;
6866	};
6867	
6868	
6869	/**
6870	 * Get all DataTable tables that have been initialised - optionally you can select to
6871	 * get only currently visible tables.
6872	 *  @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or 
6873	 *    visible tables only.
6874	 *  @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables
6875	 *  @static
6876	 *  @dtopt API-Static
6877	 *
6878	 *  @example
6879	 *    var table = $.fn.dataTable.fnTables(true);
6880	 *    if ( table.length > 0 ) {
6881	 *      $(table).dataTable().fnAdjustColumnSizing();
6882	 *    }
6883	 */
6884	DataTable.fnTables = function ( bVisible )
6885	{
6886		var out = [];
6887	
6888		jQuery.each( DataTable.settings, function (i, o) {
6889			if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )
6890			{
6891				out.push( o.nTable );
6892			}
6893		} );
6894	
6895		return out;
6896	};
6897	
6898
6899	/**
6900	 * Version string for plug-ins to check compatibility. Allowed format is
6901	 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
6902	 * e are optional
6903	 *  @member
6904	 *  @type string
6905	 *  @default Version number
6906	 */
6907	DataTable.version = "1.9.4";
6908
6909	/**
6910	 * Private data store, containing all of the settings objects that are created for the
6911	 * tables on a given page.
6912	 * 
6913	 * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i> 
6914	 * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>.
6915	 *  @member
6916	 *  @type array
6917	 *  @default []
6918	 *  @private
6919	 */
6920	DataTable.settings = [];
6921
6922	/**
6923	 * Object models container, for the various models that DataTables has available
6924	 * to it. These models define the objects that are used to hold the active state 
6925	 * and configuration of the table.
6926	 *  @namespace
6927	 */
6928	DataTable.models = {};
6929	
6930	
6931	/**
6932	 * DataTables extension options and plug-ins. This namespace acts as a collection "area"
6933	 * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
6934	 * of the build in methods use this method to provide their own capabilities (sorting methods
6935	 * for example).
6936	 * 
6937	 * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed
6938	 * and modified by plug-ins.
6939	 *  @namespace
6940	 */
6941	DataTable.models.ext = {
6942		/**
6943		 * Plug-in filtering functions - this method of filtering is complimentary to the default
6944		 * type based filtering, and a lot more comprehensive as it allows you complete control
6945		 * over the filtering logic. Each element in this array is a function (parameters
6946		 * described below) that is called for every row in the table, and your logic decides if
6947		 * it should be included in the filtered data set or not.
6948		 *   <ul>
6949		 *     <li>
6950		 *       Function input parameters:
6951		 *       <ul>
6952		 *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
6953		 *         <li>{array|object} Data for the row to be processed (same as the original format
6954		 *           that was passed in as the data source, or an array from a DOM data source</li>
6955		 *         <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can
6956		 *           be useful to retrieve the TR element if you need DOM interaction.</li>
6957		 *       </ul>
6958		 *     </li>
6959		 *     <li>
6960		 *       Function return:
6961		 *       <ul>
6962		 *         <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>
6963		 *       </ul>
6964		 *     </il>
6965		 *   </ul>
6966		 *  @type array
6967		 *  @default []
6968		 *
6969		 *  @example
6970		 *    // The following example shows custom filtering being applied to the fourth column (i.e.
6971		 *    // the aData[3] index) based on two input values from the end-user, matching the data in 
6972		 *    // a certain range.
6973		 *    $.fn.dataTableExt.afnFiltering.push(
6974		 *      function( oSettings, aData, iDataIndex ) {
6975		 *        var iMin = document.getElementById('min').value * 1;
6976		 *        var iMax = document.getElementById('max').value * 1;
6977		 *        var iVersion = aData[3] == "-" ? 0 : aData[3]*1;
6978		 *        if ( iMin == "" && iMax == "" ) {
6979		 *          return true;
6980		 *        }
6981		 *        else if ( iMin == "" && iVersion < iMax ) {
6982		 *          return true;
6983		 *        }
6984		 *        else if ( iMin < iVersion && "" == iMax ) {
6985		 *          return true;
6986		 *        }
6987		 *        else if ( iMin < iVersion && iVersion < iMax ) {
6988		 *          return true;
6989		 *        }
6990		 *        return false;
6991		 *      }
6992		 *    );
6993		 */
6994		"afnFiltering": [],
6995	
6996	
6997		/**
6998		 * Plug-in sorting functions - this method of sorting is complimentary to the default type
6999		 * based sorting that DataTables does automatically, allowing much greater control over the
7000		 * the data that is being used to sort a column. This is useful if you want to do sorting
7001		 * based on live data (for example the contents of an 'input' element) rather than just the
7002		 * static string that DataTables knows of. The way these plug-ins work is that you create
7003		 * an array of the values you wish to be sorted for the column in question and then return
7004		 * that array. Which pre-sorting function is run here depends on the sSortDataType parameter
7005		 * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort 
7006		 * data.
7007		 *   <ul>
7008	     *     <li>
7009	     *       Function input parameters:
7010	     *       <ul>
7011		 *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
7012	     *         <li>{int} Target column index</li>
7013	     *       </ul>
7014	     *     </li>
7015		 *     <li>
7016		 *       Function return:
7017		 *       <ul>
7018		 *         <li>{array} Data for the column to be sorted upon</li>
7019		 *       </ul>
7020		 *     </il>
7021		 *   </ul>
7022		 *  
7023		 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
7024		 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
7025		 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
7026		 * prepare the data as required for the different types. As such, this method is deprecated.
7027		 *  @type array
7028		 *  @default []
7029		 *  @deprecated
7030		 *
7031		 *  @example
7032		 *    // Updating the cached sorting information with user entered values in HTML input elements
7033		 *    jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
7034		 *    {
7035		 *      var aData = [];
7036		 *      $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
7037		 *        aData.push( this.value );
7038		 *      } );
7039		 *      return aData;
7040		 *    }
7041		 */
7042		"afnSortData": [],
7043	
7044	
7045		/**
7046		 * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are
7047		 * available to DataTables. These feature plug-ins are accessible through the sDom initialisation
7048		 * option. As such, each feature plug-in must describe a function that is used to initialise
7049		 * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name
7050		 * of the feature (sFeature). Thus the objects attached to this method must provide:
7051		 *   <ul>
7052		 *     <li>{function} fnInit Initialisation of the plug-in
7053		 *       <ul>
7054	     *         <li>
7055	     *           Function input parameters:
7056	     *           <ul>
7057		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
7058	     *           </ul>
7059	     *         </li>
7060		 *         <li>
7061		 *           Function return:
7062		 *           <ul>
7063		 *             <li>{node|null} The element which contains your feature. Note that the return
7064		 *                may also be void if your plug-in does not require to inject any DOM elements 
7065		 *                into DataTables control (sDom) - for example this might be useful when 
7066		 *                developing a plug-in which allows table control via keyboard entry.</li>
7067		 *           </ul>
7068		 *         </il>
7069		 *       </ul>
7070		 *     </li>
7071		 *     <li>{character} cFeature Character that will be matched in sDom - case sensitive</li>
7072		 *     <li>{string} sFeature Feature name</li>
7073		 *   </ul>
7074		 *  @type array
7075		 *  @default []
7076		 * 
7077		 *  @example
7078		 *    // How TableTools initialises itself.
7079		 *    $.fn.dataTableExt.aoFeatures.push( {
7080		 *      "fnInit": function( oSettings ) {
7081		 *        return new TableTools( { "oDTSettings": oSettings } );
7082		 *      },
7083		 *      "cFeature": "T",
7084		 *      "sFeature": "TableTools"
7085		 *    } );
7086		 */
7087		"aoFeatures": [],
7088	
7089	
7090		/**
7091		 * Type detection plug-in functions - DataTables utilises types to define how sorting and
7092		 * filtering behave, and types can be either  be defined by the developer (sType for the
7093		 * column) or they can be automatically detected by the methods in this array. The functions
7094		 * defined in the array are quite simple, taking a single parameter (the data to analyse) 
7095		 * and returning the type if it is a known type, or null otherwise.
7096		 *   <ul>
7097	     *     <li>
7098	     *       Function input parameters:
7099	     *       <ul>
7100		 *         <li>{*} Data from the column cell to be analysed</li>
7101	     *       </ul>
7102	     *     </li>
7103		 *     <li>
7104		 *       Function return:
7105		 *       <ul>
7106		 *         <li>{string|null} Data type detected, or null if unknown (and thus pass it
7107		 *           on to the other type detection functions.</li>
7108		 *       </ul>
7109		 *     </il>
7110		 *   </ul>
7111		 *  @type array
7112		 *  @default []
7113		 *  
7114		 *  @example
7115		 *    // Currency type detection plug-in:
7116		 *    jQuery.fn.dataTableExt.aTypes.push(
7117		 *      function ( sData ) {
7118		 *        var sValidChars = "0123456789.-";
7119		 *        var Char;
7120		 *        
7121		 *        // Check the numeric part
7122		 *        for ( i=1 ; i<sData.length ; i++ ) {
7123		 *          Char = sData.charAt(i); 
7124		 *          if (sValidChars.indexOf(Char) == -1) {
7125		 *            return null;
7126		 *          }
7127		 *        }
7128		 *        
7129		 *        // Check prefixed by currency
7130		 *        if ( sData.charAt(0) == '$' || sData.charAt(0) == '&pound;' ) {
7131		 *          return 'currency';
7132		 *        }
7133		 *        return null;
7134		 *      }
7135		 *    );
7136		 */
7137		"aTypes": [],
7138	
7139	
7140		/**
7141		 * Provide a common method for plug-ins to check the version of DataTables being used, 
7142		 * in order to ensure compatibility.
7143		 *  @type function
7144		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note 
7145		 *    that the formats "X" and "X.Y" are also acceptable.
7146		 *  @returns {boolean} true if this version of DataTables is greater or equal to the 
7147		 *    required version, or false if this version of DataTales is not suitable
7148		 *
7149		 *  @example
7150		 *    $(document).ready(function() {
7151		 *      var oTable = $('#example').dataTable();
7152		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
7153		 *    } );
7154		 */
7155		"fnVersionCheck": DataTable.fnVersionCheck,
7156	
7157	
7158		/**
7159		 * Index for what 'this' index API functions should use
7160		 *  @type int
7161		 *  @default 0
7162		 */
7163		"iApiIndex": 0,
7164	
7165	
7166		/**
7167		 * Pre-processing of filtering data plug-ins - When you assign the sType for a column
7168		 * (or have it automatically detected for you by DataTables or a type detection plug-in), 
7169		 * you will typically be using this for custom sorting, but it can also be used to provide 
7170		 * custom filtering by allowing you to pre-processing the data and returning the data in
7171		 * the format that should be filtered upon. This is done by adding functions this object 
7172		 * with a parameter name which matches the sType for that target column. This is the
7173		 * corollary of <i>afnSortData</i> for filtering data.
7174		 *   <ul>
7175	     *     <li>
7176	     *       Function input parameters:
7177	     *       <ul>
7178		 *         <li>{*} Data from the column cell to be prepared for filtering</li>
7179	     *       </ul>
7180	     *     </li>
7181		 *     <li>
7182		 *       Function return:
7183		 *       <ul>
7184		 *         <li>{string|null} Formatted string that will be used for the filtering.</li>
7185		 *       </ul>
7186		 *     </il>
7187		 *   </ul>
7188		 * 
7189		 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
7190		 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
7191		 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
7192		 * prepare the data as required for the different types. As such, this method is deprecated.
7193		 *  @type object
7194		 *  @default {}
7195		 *  @deprecated
7196		 *
7197		 *  @example
7198		 *    $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {
7199		 *      return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
7200		 *    }
7201		 */
7202		"ofnSearch": {},
7203	
7204	
7205		/**
7206		 * Container for all private functions in DataTables so they can be exposed externally
7207		 *  @type object
7208		 *  @default {}
7209		 */
7210		"oApi": {},
7211	
7212	
7213		/**
7214		 * Storage for the various classes that DataTables uses
7215		 *  @type object
7216		 *  @default {}
7217		 */
7218		"oStdClasses": {},
7219		
7220	
7221		/**
7222		 * Storage for the various classes that DataTables uses - jQuery UI suitable
7223		 *  @type object
7224		 *  @default {}
7225		 */
7226		"oJUIClasses": {},
7227	
7228	
7229		/**
7230		 * Pagination plug-in methods - The style and controls of the pagination can significantly 
7231		 * impact on how the end user interacts with the data in your table, and DataTables allows 
7232		 * the addition of pagination controls by extending this object, which can then be enabled
7233		 * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that
7234		 * is added is an object (the property name of which is what <i>sPaginationType</i> refers
7235		 * to) that has two properties, both methods that are used by DataTables to update the
7236		 * control's state.
7237		 *   <ul>
7238		 *     <li>
7239		 *       fnInit -  Initialisation of the paging controls. Called only during initialisation 
7240		 *         of the table. It is expected that this function will add the required DOM elements 
7241		 *         to the page for the paging controls to work. The element pointer 
7242		 *         'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging 
7243		 *         controls (note that this is a 2D array to allow for multiple instances of each 
7244		 *         DataTables DOM element). It is suggested that you add the controls to this element 
7245		 *         as children
7246		 *       <ul>
7247	     *         <li>
7248	     *           Function input parameters:
7249	     *           <ul>
7250		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
7251		 *             <li>{node} Container into which the pagination controls must be inserted</li>
7252		 *             <li>{function} Draw callback function - whenever the controls cause a page
7253		 *               change, this method must be called to redraw the table.</li>
7254	     *           </ul>
7255	     *         </li>
7256		 *         <li>
7257		 *           Function return:
7258		 *           <ul>
7259		 *             <li>No return required</li>
7260		 *           </ul>
7261		 *         </il>
7262		 *       </ul>
7263		 *     </il>
7264		 *     <li>
7265		 *       fnInit -  This function is called whenever the paging status of the table changes and is
7266		 *         typically used to update classes and/or text of the paging controls to reflex the new 
7267		 *         status.
7268		 *       <ul>
7269	     *         <li>
7270	     *           Function input parameters:
7271	     *           <ul>
7272		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
7273		 *             <li>{function} Draw callback function - in case you need to redraw the table again
7274		 *               or attach new event listeners</li>
7275	     *           </ul>
7276	     *         </li>
7277		 *         <li>
7278		 *           Function return:
7279		 *           <ul>
7280		 *             <li>No return required</li>
7281		 *           </ul>
7282		 *         </il>
7283		 *       </ul>
7284		 *     </il>
7285		 *   </ul>
7286		 *  @type object
7287		 *  @default {}
7288		 *
7289		 *  @example
7290		 *    $.fn.dataTableExt.oPagination.four_button = {
7291		 *      "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) {
7292		 *        nFirst = document.createElement( 'span' );
7293		 *        nPrevious = document.createElement( 'span' );
7294		 *        nNext = document.createElement( 'span' );
7295		 *        nLast = document.createElement( 'span' );
7296		 *        
7297		 *        nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
7298		 *        nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
7299		 *        nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
7300		 *        nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );
7301		 *        
7302		 *        nFirst.className = "paginate_button first";
7303		 *        nPrevious.className = "paginate_button previous";
7304		 *        nNext.className="paginate_button next";
7305		 *        nLast.className = "paginate_button last";
7306		 *        
7307		 *        nPaging.appendChild( nFirst );
7308		 *        nPaging.appendChild( nPrevious );
7309		 *        nPaging.appendChild( nNext );
7310		 *        nPaging.appendChild( nLast );
7311		 *        
7312		 *        $(nFirst).click( function () {
7313		 *          oSettings.oApi._fnPageChange( oSettings, "first" );
7314		 *          fnCallbackDraw( oSettings );
7315		 *        } );
7316		 *        
7317		 *        $(nPrevious).click( function() {
7318		 *          oSettings.oApi._fnPageChange( oSettings, "previous" );
7319		 *          fnCallbackDraw( oSettings );
7320		 *        } );
7321		 *        
7322		 *        $(nNext).click( function() {
7323		 *          oSettings.oApi._fnPageChange( oSettings, "next" );
7324		 *          fnCallbackDraw( oSettings );
7325		 *        } );
7326		 *        
7327		 *        $(nLast).click( function() {
7328		 *          oSettings.oApi._fnPageChange( oSettings, "last" );
7329		 *          fnCallbackDraw( oSettings );
7330		 *        } );
7331		 *        
7332		 *        $(nFirst).bind( 'selectstart', function () { return false; } );
7333		 *        $(nPrevious).bind( 'selectstart', function () { return false; } );
7334		 *        $(nNext).bind( 'selectstart', function () { return false; } );
7335		 *        $(nLast).bind( 'selectstart', function () { return false; } );
7336		 *      },
7337		 *      
7338		 *      "fnUpdate": function ( oSettings, fnCallbackDraw ) {
7339		 *        if ( !oSettings.aanFeatures.p ) {
7340		 *          return;
7341		 *        }
7342		 *        
7343		 *        // Loop over each instance of the pager
7344		 *        var an = oSettings.aanFeatures.p;
7345		 *        for ( var i=0, iLen=an.length ; i<iLen ; i++ ) {
7346		 *          var buttons = an[i].getElementsByTagName('span');
7347		 *          if ( oSettings._iDisplayStart === 0 ) {
7348		 *            buttons[0].className = "paginate_disabled_previous";
7349		 *            buttons[1].className = "paginate_disabled_previous";
7350		 *          }
7351		 *          else {
7352		 *            buttons[0].className = "paginate_enabled_previous";
7353		 *            buttons[1].className = "paginate_enabled_previous";
7354		 *          }
7355		 *          
7356		 *          if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {
7357		 *            buttons[2].className = "paginate_disabled_next";
7358		 *            buttons[3].className = "paginate_disabled_next";
7359		 *          }
7360		 *          else {
7361		 *            buttons[2].className = "paginate_enabled_next";
7362		 *            buttons[3].className = "paginate_enabled_next";
7363		 *          }
7364		 *        }
7365		 *      }
7366		 *    };
7367		 */
7368		"oPagination": {},
7369	
7370	
7371		/**
7372		 * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the
7373		 * data column (you can add your own type detection functions, or override automatic 
7374		 * detection using sType). With this specific type given to the column, DataTables will 
7375		 * apply the required sort from the functions in the object. Each sort type must provide
7376		 * two mandatory methods, one each for ascending and descending sorting, and can optionally
7377		 * provide a pre-formatting method that will help speed up sorting by allowing DataTables
7378		 * to pre-format the sort data only once (rather than every time the actual sort functions
7379		 * are run). The two sorting functions are typical Javascript sort methods:
7380		 *   <ul>
7381	     *     <li>
7382	     *       Function input parameters:
7383	     *       <ul>
7384		 *         <li>{*} Data to compare to the second parameter</li>
7385		 *         <li>{*} Data to compare to the first parameter</li>
7386	     *       </ul>
7387	     *     </li>
7388		 *     <li>
7389		 *       Function return:
7390		 *       <ul>
7391		 *         <li>{int} Sorting match: <0 if first parameter should be sorted lower than
7392		 *           the second parameter, ===0 if the two parameters are equal and >0 if
7393		 *           the first parameter should be sorted height than the second parameter.</li>
7394		 *       </ul>
7395		 *     </il>
7396		 *   </ul>
7397		 *  @type object
7398		 *  @default {}
7399		 *
7400		 *  @example
7401		 *    // Case-sensitive string sorting, with no pre-formatting method
7402		 *    $.extend( $.fn.dataTableExt.oSort, {
7403		 *      "string-case-asc": function(x,y) {
7404		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
7405		 *      },
7406		 *      "string-case-desc": function(x,y) {
7407		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
7408		 *      }
7409		 *    } );
7410		 *
7411		 *  @example
7412		 *    // Case-insensitive string sorting, with pre-formatting
7413		 *    $.extend( $.fn.dataTableExt.oSort, {
7414		 *      "string-pre": function(x) {
7415		 *        return x.toLowerCase();
7416		 *      },
7417		 *      "string-asc": function(x,y) {
7418		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
7419		 *      },
7420		 *      "string-desc": function(x,y) {
7421		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
7422		 *      }
7423		 *    } );
7424		 */
7425		"oSort": {},
7426	
7427	
7428		/**
7429		 * Version string for plug-ins to check compatibility. Allowed format is
7430		 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
7431		 * e are optional
7432		 *  @type string
7433		 *  @default Version number
7434		 */
7435		"sVersion": DataTable.version,
7436	
7437	
7438		/**
7439		 * How should DataTables report an error. Can take the value 'alert' or 'throw'
7440		 *  @type string
7441		 *  @default alert
7442		 */
7443		"sErrMode": "alert",
7444	
7445	
7446		/**
7447		 * Store information for DataTables to access globally about other instances
7448		 *  @namespace
7449		 *  @private
7450		 */
7451		"_oExternConfig": {
7452			/* int:iNextUnique - next unique number for an instance */
7453			"iNextUnique": 0
7454		}
7455	};
7456	
7457	
7458	
7459	
7460	/**
7461	 * Template object for the way in which DataTables holds information about
7462	 * search information for the global filter and individual column filters.
7463	 *  @namespace
7464	 */
7465	DataTable.models.oSearch = {
7466		/**
7467		 * Flag to indicate if the filtering should be case insensitive or not
7468		 *  @type boolean
7469		 *  @default true
7470		 */
7471		"bCaseInsensitive": true,
7472	
7473		/**
7474		 * Applied search term
7475		 *  @type string
7476		 *  @default <i>Empty string</i>
7477		 */
7478		"sSearch": "",
7479	
7480		/**
7481		 * Flag to indicate if the search term should be interpreted as a
7482		 * regular expression (true) or not (false) and therefore and special
7483		 * regex characters escaped.
7484		 *  @type boolean
7485		 *  @default false
7486		 */
7487		"bRegex": false,
7488	
7489		/**
7490		 * Flag to indicate if DataTables is to use its smart filtering or not.
7491		 *  @type boolean
7492		 *  @default true
7493		 */
7494		"bSmart": true
7495	};
7496	
7497	
7498	
7499	
7500	/**
7501	 * Template object for the way in which DataTables holds information about
7502	 * each individual row. This is the object format used for the settings 
7503	 * aoData array.
7504	 *  @namespace
7505	 */
7506	DataTable.models.oRow = {
7507		/**
7508		 * TR element for the row
7509		 *  @type node
7510		 *  @default null
7511		 */
7512		"nTr": null,
7513	
7514		/**
7515		 * Data object from the original data source for the row. This is either
7516		 * an array if using the traditional form of DataTables, or an object if
7517		 * using mData options. The exact type will depend on the passed in
7518		 * data from the data source, or will be an array if using DOM a data 
7519		 * source.
7520		 *  @type array|object
7521		 *  @default []
7522		 */
7523		"_aData": [],
7524	
7525		/**
7526		 * Sorting data cache - this array is ostensibly the same length as the
7527		 * number of columns (although each index is generated only as it is 
7528		 * needed), and holds the data that is used for sorting each column in the
7529		 * row. We do this cache generation at the start of the sort in order that
7530		 * the formatting of the sort data need be done only once for each cell
7531		 * per sort. This array should not be read from or written to by anything
7532		 * other than the master sorting methods.
7533		 *  @type array
7534		 *  @default []
7535		 *  @private
7536		 */
7537		"_aSortData": [],
7538	
7539		/**
7540		 * Array of TD elements that are cached for hidden rows, so they can be
7541		 * reinserted into the table if a column is made visible again (or to act
7542		 * as a store if a column is made hidden). Only hidden columns have a 
7543		 * reference in the array. For non-hidden columns the value is either
7544		 * undefined or null.
7545		 *  @type array nodes
7546		 *  @default []
7547		 *  @private
7548		 */
7549		"_anHidden": [],
7550	
7551		/**
7552		 * Cache of the class name that DataTables has applied to the row, so we
7553		 * can quickly look at this variable rather than needing to do a DOM check
7554		 * on className for the nTr property.
7555		 *  @type string
7556		 *  @default <i>Empty string</i>
7557		 *  @private
7558		 */
7559		"_sRowStripe": ""
7560	};
7561	
7562	
7563	
7564	/**
7565	 * Template object for the column information object in DataTables. This object
7566	 * is held in the settings aoColumns array and contains all the information that
7567	 * DataTables needs about each individual column.
7568	 * 
7569	 * Note that this object is related to {@link DataTable.defaults.columns} 
7570	 * but this one is the internal data store for DataTables's cache of columns.
7571	 * It should NOT be manipulated outside of DataTables. Any configuration should
7572	 * be done through the initialisation options.
7573	 *  @namespace
7574	 */
7575	DataTable.models.oColumn = {
7576		/**
7577		 * A list of the columns that sorting should occur on when this column
7578		 * is sorted. That this property is an array allows multi-column sorting
7579		 * to be defined for a column (for example first name / last name columns
7580		 * would benefit from this). The values are integers pointing to the
7581		 * columns to be sorted on (typically it will be a single integer pointing
7582		 * at itself, but that doesn't need to be the case).
7583		 *  @type array
7584		 */
7585		"aDataSort": null,
7586	
7587		/**
7588		 * Define the sorting directions that are applied to the column, in sequence
7589		 * as the column is repeatedly sorted upon - i.e. the first value is used
7590		 * as the sorting direction when the column if first sorted (clicked on).
7591		 * Sort it again (click again) and it will move on to the next index.
7592		 * Repeat until loop.
7593		 *  @type array
7594		 */
7595		"asSorting": null,
7596		
7597		/**
7598		 * Flag to indicate if the column is searchable, and thus should be included
7599		 * in the filtering or not.
7600		 *  @type boolean
7601		 */
7602		"bSearchable": null,
7603		
7604		/**
7605		 * Flag to indicate if the column is sortable or not.
7606		 *  @type boolean
7607		 */
7608		"bSortable": null,
7609		
7610		/**
7611		 * <code>Deprecated</code> When using fnRender, you have two options for what 
7612		 * to do with the data, and this property serves as the switch. Firstly, you 
7613		 * can have the sorting and filtering use the rendered value (true - default), 
7614		 * or you can have the sorting and filtering us the original value (false).
7615		 *
7616		 * Please note that this option has now been deprecated and will be removed
7617		 * in the next version of DataTables. Please use mRender / mData rather than
7618		 * fnRender.
7619		 *  @type boolean
7620		 *  @deprecated
7621		 */
7622		"bUseRendered": null,
7623		
7624		/**
7625		 * Flag to indicate if the column is currently visible in the table or not
7626		 *  @type boolean
7627		 */
7628		"bVisible": null,
7629		
7630		/**
7631		 * Flag to indicate to the type detection method if the automatic type
7632		 * detection should be used, or if a column type (sType) has been specified
7633		 *  @type boolean
7634		 *  @default true
7635		 *  @private
7636		 */
7637		"_bAutoType": true,
7638		
7639		/**
7640		 * Developer definable function that is called whenever a cell is created (Ajax source,
7641		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
7642		 * allowing you to modify the DOM element (add background colour for example) when the
7643		 * element is available.
7644		 *  @type function
7645		 *  @param {element} nTd The TD node that has been created
7646		 *  @param {*} sData The Data for the cell
7647		 *  @param {array|object} oData The data for the whole row
7648		 *  @param {int} iRow The row index for the aoData data store
7649		 *  @default null
7650		 */
7651		"fnCreatedCell": null,
7652		
7653		/**
7654		 * Function to get data from a cell in a column. You should <b>never</b>
7655		 * access data directly through _aData internally in DataTables - always use
7656		 * the method attached to this property. It allows mData to function as
7657		 * required. This function is automatically assigned by the column 
7658		 * initialisation method
7659		 *  @type function
7660		 *  @param {array|object} oData The data array/object for the array 
7661		 *    (i.e. aoData[]._aData)
7662		 *  @param {string} sSpecific The specific data type you want to get - 
7663		 *    'display', 'type' 'filter' 'sort'
7664		 *  @returns {*} The data for the cell from the given row's data
7665		 *  @default null
7666		 */
7667		"fnGetData": null,
7668		
7669		/**
7670		 * <code>Deprecated</code> Custom display function that will be called for the 
7671		 * display of each cell in this column.
7672		 *
7673		 * Please note that this option has now been deprecated and will be removed
7674		 * in the next version of DataTables. Please use mRender / mData rather than
7675		 * fnRender.
7676		 *  @type function
7677		 *  @param {object} o Object with the following parameters:
7678		 *  @param {int}    o.iDataRow The row in aoData
7679		 *  @param {int}    o.iDataColumn The column in question
7680		 *  @param {array}  o.aData The data for the row in question
7681		 *  @param {object} o.oSettings The settings object for this DataTables instance
7682		 *  @returns {string} The string you which to use in the display
7683		 *  @default null
7684		 *  @deprecated
7685		 */
7686		"fnRender": null,
7687		
7688		/**
7689		 * Function to set data for a cell in the column. You should <b>never</b> 
7690		 * set the data directly to _aData internally in DataTables - always use
7691		 * this method. It allows mData to function as required. This function
7692		 * is automatically assigned by the column initialisation method
7693		 *  @type function
7694		 *  @param {array|object} oData The data array/object for the array 
7695		 *    (i.e. aoData[]._aData)
7696		 *  @param {*} sValue Value to set
7697		 *  @default null
7698		 */
7699		"fnSetData": null,
7700		
7701		/**
7702		 * Property to read the value for the cells in the column from the data 
7703		 * source array / object. If null, then the default content is used, if a
7704		 * function is given then the return from the function is used.
7705		 *  @type function|int|string|null
7706		 *  @default null
7707		 */
7708		"mData": null,
7709		
7710		/**
7711		 * Partner property to mData which is used (only when defined) to get
7712		 * the data - i.e. it is basically the same as mData, but without the
7713		 * 'set' option, and also the data fed to it is the result from mData.
7714		 * This is the rendering method to match the data method of mData.
7715		 *  @type function|int|string|null
7716		 *  @default null
7717		 */
7718		"mRender": null,
7719		
7720		/**
7721		 * Unique header TH/TD element for this column - this is what the sorting
7722		 * listener is attached to (if sorting is enabled.)
7723		 *  @type node
7724		 *  @default null
7725		 */
7726		"nTh": null,
7727		
7728		/**
7729		 * Unique footer TH/TD element for this column (if there is one). Not used 
7730		 * in DataTables as such, but can be used for plug-ins to reference the 
7731		 * footer for each column.
7732		 *  @type node
7733		 *  @default null
7734		 */
7735		"nTf": null,
7736		
7737		/**
7738		 * The class to apply to all TD elements in the table's TBODY for the column
7739		 *  @type string
7740		 *  @default null
7741		 */
7742		"sClass": null,
7743		
7744		/**
7745		 * When DataTables calculates the column widths to assign to each column,
7746		 * it finds the longest string in each column and then constructs a
7747		 * temporary table and reads the widths from that. The problem with this
7748		 * is that "mmm" is much wider then "iiii", but the latter is a longer 
7749		 * string - thus the calculation can go wrong (doing it properly and putting
7750		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
7751		 * a "work around" we provide this option. It will append its value to the
7752		 * text that is found to be the longest string for the column - i.e. padding.
7753		 *  @type string
7754		 */
7755		"sContentPadding": null,
7756		
7757		/**
7758		 * Allows a default value to be given for a column's data, and will be used
7759		 * whenever a null data source is encountered (this can be because mData
7760		 * is set to null, or because the data source itself is null).
7761		 *  @type string
7762		 *  @default null
7763		 */
7764		"sDefaultContent": null,
7765		
7766		/**
7767		 * Name for the column, allowing reference to the column by name as well as
7768		 * by index (needs a lookup to work by name).
7769		 *  @type string
7770		 */
7771		"sName": null,
7772		
7773		/**
7774		 * Custom sorting data type - defines which of the available plug-ins in
7775		 * afnSortData the custom sorting will use - if any is defined.
7776		 *  @type string
7777		 *  @default std
7778		 */
7779		"sSortDataType": 'std',
7780		
7781		/**
7782		 * Class to be applied to the header element when sorting on this column
7783		 *  @type string
7784		 *  @default null
7785		 */
7786		"sSortingClass": null,
7787		
7788		/**
7789		 * Class to be applied to the header element when sorting on this column -
7790		 * when jQuery UI theming is used.
7791		 *  @type string
7792		 *  @default null
7793		 */
7794		"sSortingClassJUI": null,
7795		
7796		/**
7797		 * Title of the column - what is seen in the TH element (nTh).
7798		 *  @type string
7799		 */
7800		"sTitle": null,
7801		
7802		/**
7803		 * Column sorting and filtering type
7804		 *  @type string
7805		 *  @default null
7806		 */
7807		"sType": null,
7808		
7809		/**
7810		 * Width of the column
7811		 *  @type string
7812		 *  @default null
7813		 */
7814		"sWidth": null,
7815		
7816		/**
7817		 * Width of the column when it was first "encountered"
7818		 *  @type string
7819		 *  @default null
7820		 */
7821		"sWidthOrig": null
7822	};
7823	
7824	
7825	
7826	/**
7827	 * Initialisation options that can be given to DataTables at initialisation 
7828	 * time.
7829	 *  @namespace
7830	 */
7831	DataTable.defaults = {
7832		/**
7833		 * An array of data to use for the table, passed in at initialisation which 
7834		 * will be used in preference to any data which is already in the DOM. This is
7835		 * particularly useful for constructing tables purely in Javascript, for
7836		 * example with a custom Ajax call.
7837		 *  @type array
7838		 *  @default null
7839		 *  @dtopt Option
7840		 * 
7841		 *  @example
7842		 *    // Using a 2D array data source
7843		 *    $(document).ready( function () {
7844		 *      $('#example').dataTable( {
7845		 *        "aaData": [
7846		 *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
7847		 *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
7848		 *        ],
7849		 *        "aoColumns": [
7850		 *          { "sTitle": "Engine" },
7851		 *          { "sTitle": "Browser" },
7852		 *          { "sTitle": "Platform" },
7853		 *          { "sTitle": "Version" },
7854		 *          { "sTitle": "Grade" }
7855		 *        ]
7856		 *      } );
7857		 *    } );
7858		 *    
7859		 *  @example
7860		 *    // Using an array of objects as a data source (mData)
7861		 *    $(document).ready( function () {
7862		 *      $('#example').dataTable( {
7863		 *        "aaData": [
7864		 *          {
7865		 *            "engine":   "Trident",
7866		 *            "browser":  "Internet Explorer 4.0",
7867		 *            "platform": "Win 95+",
7868		 *            "version":  4,
7869		 *            "grade":    "X"
7870		 *          },
7871		 *          {
7872		 *            "engine":   "Trident",
7873		 *            "browser":  "Internet Explorer 5.0",
7874		 *            "platform": "Win 95+",
7875		 *            "version":  5,
7876		 *            "grade":    "C"
7877		 *          }
7878		 *        ],
7879		 *        "aoColumns": [
7880		 *          { "sTitle": "Engine",   "mData": "engine" },
7881		 *          { "sTitle": "Browser",  "mData": "browser" },
7882		 *          { "sTitle": "Platform", "mData": "platform" },
7883		 *          { "sTitle": "Version",  "mData": "version" },
7884		 *          { "sTitle": "Grade",    "mData": "grade" }
7885		 *        ]
7886		 *      } );
7887		 *    } );
7888		 */
7889		"aaData": null,
7890	
7891	
7892		/**
7893		 * If sorting is enabled, then DataTables will perform a first pass sort on 
7894		 * initialisation. You can define which column(s) the sort is performed upon, 
7895		 * and the sorting direction, with this variable. The aaSorting array should 
7896		 * contain an array for each column to be sorted initially containing the 
7897		 * column's index and a direction string ('asc' or 'desc').
7898		 *  @type array
7899		 *  @default [[0,'asc']]
7900		 *  @dtopt Option
7901		 * 
7902		 *  @example
7903		 *    // Sort by 3rd column first, and then 4th column
7904		 *    $(document).ready( function() {
7905		 *      $('#example').dataTable( {
7906		 *        "aaSorting": [[2,'asc'], [3,'desc']]
7907		 *      } );
7908		 *    } );
7909		 *    
7910		 *    // No initial sorting
7911		 *    $(document).ready( function() {
7912		 *      $('#example').dataTable( {
7913		 *        "aaSorting": []
7914		 *      } );
7915		 *    } );
7916		 */
7917		"aaSorting": [[0,'asc']],
7918	
7919	
7920		/**
7921		 * This parameter is basically identical to the aaSorting parameter, but 
7922		 * cannot be overridden by user interaction with the table. What this means 
7923		 * is that you could have a column (visible or hidden) which the sorting will 
7924		 * always be forced on first - any sorting after that (from the user) will 
7925		 * then be performed as required. This can be useful for grouping rows 
7926		 * together.
7927		 *  @type array
7928		 *  @default null
7929		 *  @dtopt Option
7930		 * 
7931		 *  @example
7932		 *    $(document).ready( function() {
7933		 *      $('#example').dataTable( {
7934		 *        "aaSortingFixed": [[0,'asc']]
7935		 *      } );
7936		 *    } )
7937		 */
7938		"aaSortingFixed": null,
7939	
7940	
7941		/**
7942		 * This parameter allows you to readily specify the entries in the length drop
7943		 * down menu that DataTables shows when pagination is enabled. It can be 
7944		 * either a 1D array of options which will be used for both the displayed 
7945		 * option and the value, or a 2D array which will use the array in the first 
7946		 * position as the value, and the array in the second position as the 
7947		 * displayed options (useful for language strings such as 'All').
7948		 *  @type array
7949		 *  @default [ 10, 25, 50, 100 ]
7950		 *  @dtopt Option
7951		 * 
7952		 *  @example
7953		 *    $(document).ready( function() {
7954		 *      $('#example').dataTable( {
7955		 *        "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
7956		 *      } );
7957		 *    } );
7958		 *  
7959		 *  @example
7960		 *    // Setting the default display length as well as length menu
7961		 *    // This is likely to be wanted if you remove the '10' option which
7962		 *    // is the iDisplayLength default.
7963		 *    $(document).ready( function() {
7964		 *      $('#example').dataTable( {
7965		 *        "iDisplayLength": 25,
7966		 *        "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
7967		 *      } );
7968		 *    } );
7969		 */
7970		"aLengthMenu": [ 10, 25, 50, 100 ],
7971	
7972	
7973		/**
7974		 * The aoColumns option in the initialisation parameter allows you to define
7975		 * details about the way individual columns behave. For a full list of
7976		 * column options that can be set, please see 
7977		 * {@link DataTable.defaults.columns}. Note that if you use aoColumns to
7978		 * define your columns, you must have an entry in the array for every single
7979		 * column that you have in your table (these can be null if you don't which
7980		 * to specify any options).
7981		 *  @member
7982		 */
7983		"aoColumns": null,
7984	
7985		/**
7986		 * Very similar to aoColumns, aoColumnDefs allows you to target a specific 
7987		 * column, multiple columns, or all columns, using the aTargets property of 
7988		 * each object in the array. This allows great flexibility when creating 
7989		 * tables, as the aoColumnDefs arrays can be of any length, targeting the 
7990		 * columns you specifically want. aoColumnDefs may use any of the column 
7991		 * options available: {@link DataTable.defaults.columns}, but it _must_
7992		 * have aTargets defined in each object in the array. Values in the aTargets
7993		 * array may be:
7994		 *   <ul>
7995		 *     <li>
7995a string - class name will be matched on the TH for the column</li>
7996		 *     <li>0 or a positive integer - column index counting from the left</li>
7997		 *     <li>a negative integer - column index counting from the right</li>
7998		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
7999		 *   </ul>
8000		 *  @member
8001		 */
8002		"aoColumnDefs": null,
8003	
8004	
8005		/**
8006		 * Basically the same as oSearch, this parameter defines the individual column
8007		 * filtering state at initialisation time. The array must be of the same size 
8008		 * as the number of columns, and each element be an object with the parameters
8009		 * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also
8010		 * accepted and the default will be used.
8011		 *  @type array
8012		 *  @default []
8013		 *  @dtopt Option
8014		 * 
8015		 *  @example
8016		 *    $(document).ready( function() {
8017		 *      $('#example').dataTable( {
8018		 *        "aoSearchCols": [
8019		 *          null,
8020		 *          { "sSearch": "My filter" },
8021		 *          null,
8022		 *          { "sSearch": "^[0-9]", "bEscapeRegex": false }
8023		 *        ]
8024		 *      } );
8025		 *    } )
8026		 */
8027		"aoSearchCols": [],
8028	
8029	
8030		/**
8031		 * An array of CSS classes that should be applied to displayed rows. This 
8032		 * array may be of any length, and DataTables will apply each class 
8033		 * sequentially, looping when required.
8034		 *  @type array
8035		 *  @default null <i>Will take the values determined by the oClasses.sStripe*
8036		 *    options</i>
8037		 *  @dtopt Option
8038		 * 
8039		 *  @example
8040		 *    $(document).ready( function() {
8041		 *      $('#example').dataTable( {
8042		 *        "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]
8043		 *      } );
8044		 *    } )
8045		 */
8046		"asStripeClasses": null,
8047	
8048	
8049		/**
8050		 * Enable or disable automatic column width calculation. This can be disabled
8051		 * as an optimisation (it takes some time to calculate the widths) if the
8052		 * tables widths are passed in using aoColumns.
8053		 *  @type boolean
8054		 *  @default true
8055		 *  @dtopt Features
8056		 * 
8057		 *  @example
8058		 *    $(document).ready( function () {
8059		 *      $('#example').dataTable( {
8060		 *        "bAutoWidth": false
8061		 *      } );
8062		 *    } );
8063		 */
8064		"bAutoWidth": true,
8065	
8066	
8067		/**
8068		 * Deferred rendering can provide DataTables with a huge speed boost when you
8069		 * are using an Ajax or JS data source for the table. This option, when set to
8070		 * true, will cause DataTables to defer the creation of the table elements for
8071		 * each row until they are needed for a draw - saving a significant amount of
8072		 * time.
8073		 *  @type boolean
8074		 *  @default false
8075		 *  @dtopt Features
8076		 * 
8077		 *  @example
8078		 *    $(document).ready( function() {
8079		 *      var oTable = $('#example').dataTable( {
8080		 *        "sAjaxSource": "sources/arrays.txt",
8081		 *        "bDeferRender": true
8082		 *      } );
8083		 *    } );
8084		 */
8085		"bDeferRender": false,
8086	
8087	
8088		/**
8089		 * Replace a DataTable which matches the given selector and replace it with 
8090		 * one which has the properties of the new initialisation object passed. If no
8091		 * table matches the selector, then the new DataTable will be constructed as
8092		 * per normal.
8093		 *  @type boolean
8094		 *  @default false
8095		 *  @dtopt Options
8096		 * 
8097		 *  @example
8098		 *    $(document).ready( function() {
8099		 *      $('#example').dataTable( {
8100		 *        "sScrollY": "200px",
8101		 *        "bPaginate": false
8102		 *      } );
8103		 *      
8104		 *      // Some time later....
8105		 *      $('#example').dataTable( {
8106		 *        "bFilter": false,
8107		 *        "bDestroy": true
8108		 *      } );
8109		 *    } );
8110		 */
8111		"bDestroy": false,
8112	
8113	
8114		/**
8115		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
8116		 * that it allows the end user to input multiple words (space separated) and
8117		 * will match a row containing those words, even if not in the order that was
8118		 * specified (this allow matching across multiple columns). Note that if you
8119		 * wish to use filtering in DataTables this must remain 'true' - to remove the
8120		 * default filtering input box and retain filtering abilities, please use
8121		 * {@link DataTable.defaults.sDom}.
8122		 *  @type boolean
8123		 *  @default true
8124		 *  @dtopt Features
8125		 * 
8126		 *  @example
8127		 *    $(document).ready( function () {
8128		 *      $('#example').dataTable( {
8129		 *        "bFilter": false
8130		 *      } );
8131		 *    } );
8132		 */
8133		"bFilter": true,
8134	
8135	
8136		/**
8137		 * Enable or disable the table information display. This shows information 
8138		 * about the data that is currently visible on the page, including information
8139		 * about filtered data if that action is being performed.
8140		 *  @type boolean
8141		 *  @default true
8142		 *  @dtopt Features
8143		 * 
8144		 *  @example
8145		 *    $(document).ready( function () {
8146		 *      $('#example').dataTable( {
8147		 *        "bInfo": false
8148		 *      } );
8149		 *    } );
8150		 */
8151		"bInfo": true,
8152	
8153	
8154		/**
8155		 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
8156		 * slightly different and additional mark-up from what DataTables has
8157		 * traditionally used).
8158		 *  @type boolean
8159		 *  @default false
8160		 *  @dtopt Features
8161		 * 
8162		 *  @example
8163		 *    $(document).ready( function() {
8164		 *      $('#example').dataTable( {
8165		 *        "bJQueryUI": true
8166		 *      } );
8167		 *    } );
8168		 */
8169		"bJQueryUI": false,
8170	
8171	
8172		/**
8173		 * Allows the end user to select the size of a formatted page from a select
8174		 * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate).
8175		 *  @type boolean
8176		 *  @default true
8177		 *  @dtopt Features
8178		 * 
8179		 *  @example
8180		 *    $(document).ready( function () {
8181		 *      $('#example').dataTable( {
8182		 *        "bLengthChange": false
8183		 *      } );
8184		 *    } );
8185		 */
8186		"bLengthChange": true,
8187	
8188	
8189		/**
8190		 * Enable or disable pagination.
8191		 *  @type boolean
8192		 *  @default true
8193		 *  @dtopt Features
8194		 * 
8195		 *  @example
8196		 *    $(document).ready( function () {
8197		 *      $('#example').dataTable( {
8198		 *        "bPaginate": false
8199		 *      } );
8200		 *    } );
8201		 */
8202		"bPaginate": true,
8203	
8204	
8205		/**
8206		 * Enable or disable the display of a 'processing' indicator when the table is
8207		 * being processed (e.g. a sort). This is particularly useful for tables with
8208		 * large amounts of data where it can take a noticeable amount of time to sort
8209		 * the entries.
8210		 *  @type boolean
8211		 *  @default false
8212		 *  @dtopt Features
8213		 * 
8214		 *  @example
8215		 *    $(document).ready( function () {
8216		 *      $('#example').dataTable( {
8217		 *        "bProcessing": true
8218		 *      } );
8219		 *    } );
8220		 */
8221		"bProcessing": false,
8222	
8223	
8224		/**
8225		 * Retrieve the DataTables object for the given selector. Note that if the
8226		 * table has already been initialised, this parameter will cause DataTables
8227		 * to simply return the object that has already been set up - it will not take
8228		 * account of any changes you might have made to the initialisation object
8229		 * passed to DataTables (setting this parameter to true is an acknowledgement
8230		 * that you understand this). bDestroy can be used to reinitialise a table if
8231		 * you need.
8232		 *  @type boolean
8233		 *  @default false
8234		 *  @dtopt Options
8235		 * 
8236		 *  @example
8237		 *    $(document).ready( function() {
8238		 *      initTable();
8239		 *      tableActions();
8240		 *    } );
8241		 *    
8242		 *    function initTable ()
8243		 *    {
8244		 *      return $('#example').dataTable( {
8245		 *        "sScrollY": "200px",
8246		 *        "bPaginate": false,
8247		 *        "bRetrieve": true
8248		 *      } );
8249		 *    }
8250		 *    
8251		 *    function tableActions ()
8252		 *    {
8253		 *      var oTable = initTable();
8254		 *      // perform API operations with oTable 
8255		 *    }
8256		 */
8257		"bRetrieve": false,
8258	
8259	
8260		/**
8261		 * Indicate if DataTables should be allowed to set the padding / margin
8262		 * etc for the scrolling header elements or not. Typically you will want
8263		 * this.
8264		 *  @type boolean
8265		 *  @default true
8266		 *  @dtopt Options
8267		 * 
8268		 *  @example
8269		 *    $(document).ready( function() {
8270		 *      $('#example').dataTable( {
8271		 *        "bScrollAutoCss": false,
8272		 *        "sScrollY": "200px"
8273		 *      } );
8274		 *    } );
8275		 */
8276		"bScrollAutoCss": true,
8277	
8278	
8279		/**
8280		 * When vertical (y) scrolling is enabled, DataTables will force the height of
8281		 * the table's viewport to the given height at all times (useful for layout).
8282		 * However, this can look odd when filtering data down to a small data set,
8283		 * and the footer is left "floating" further down. This parameter (when
8284		 * enabled) will cause DataTables to collapse the table's viewport down when
8285		 * the result set will fit within the given Y height.
8286		 *  @type boolean
8287		 *  @default false
8288		 *  @dtopt Options
8289		 * 
8290		 *  @example
8291		 *    $(document).ready( function() {
8292		 *      $('#example').dataTable( {
8293		 *        "sScrollY": "200",
8294		 *        "bScrollCollapse": true
8295		 *      } );
8296		 *    } );
8297		 */
8298		"bScrollCollapse": false,
8299	
8300	
8301		/**
8302		 * Enable infinite scrolling for DataTables (to be used in combination with
8303		 * sScrollY). Infinite scrolling means that DataTables will continually load
8304		 * data as a user scrolls through a table, which is very useful for large
8305		 * dataset. This cannot be used with pagination, which is automatically
8306		 * disabled. Note - the Scroller extra for DataTables is recommended in
8307		 * in preference to this option.
8308		 *  @type boolean
8309		 *  @default false
8310		 *  @dtopt Features
8311		 * 
8312		 *  @example
8313		 *    $(document).ready( function() {
8314		 *      $('#example').dataTable( {
8315		 *        "bScrollInfinite": true,
8316		 *        "bScrollCollapse": true,
8317		 *        "sScrollY": "200px"
8318		 *      } );
8319		 *    } );
8320		 */
8321		"bScrollInfinite": false,
8322	
8323	
8324		/**
8325		 * Configure DataTables to use server-side processing. Note that the
8326		 * sAjaxSource parameter must also be given in order to give DataTables a
8327		 * source to obtain the required data for each draw.
8328		 *  @type boolean
8329		 *  @default false
8330		 *  @dtopt Features
8331		 *  @dtopt Server-side
8332		 * 
8333		 *  @example
8334		 *    $(document).ready( function () {
8335		 *      $('#example').dataTable( {
8336		 *        "bServerSide": true,
8337		 *        "sAjaxSource": "xhr.php"
8338		 *      } );
8339		 *    } );
8340		 */
8341		"bServerSide": false,
8342	
8343	
8344		/**
8345		 * Enable or disable sorting of columns. Sorting of individual columns can be
8346		 * disabled by the "bSortable" option for each column.
8347		 *  @type boolean
8348		 *  @default true
8349		 *  @dtopt Features
8350		 * 
8351		 *  @example
8352		 *    $(document).ready( function () {
8353		 *      $('#example').dataTable( {
8354		 *        "bSort": false
8355		 *      } );
8356		 *    } );
8357		 */
8358		"bSort": true,
8359	
8360	
8361		/**
8362		 * Allows control over whether DataTables should use the top (true) unique
8363		 * cell that is found for a single column, or the bottom (false - default).
8364		 * This is useful when using complex headers.
8365		 *  @type boolean
8366		 *  @default false
8367		 *  @dtopt Options
8368		 * 
8369		 *  @example
8370		 *    $(document).ready( function() {
8371		 *      $('#example').dataTable( {
8372		 *        "bSortCellsTop": true
8373		 *      } );
8374		 *    } );
8375		 */
8376		"bSortCellsTop": false,
8377	
8378	
8379		/**
8380		 * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and
8381		 * 'sorting_3' to the columns which are currently being sorted on. This is
8382		 * presented as a feature switch as it can increase processing time (while
8383		 * classes are removed and added) so for large data sets you might want to
8384		 * turn this off.
8385		 *  @type boolean
8386		 *  @default true
8387		 *  @dtopt Features
8388		 * 
8389		 *  @example
8390		 *    $(document).ready( function () {
8391		 *      $('#example').dataTable( {
8392		 *        "bSortClasses": false
8393		 *      } );
8394		 *    } );
8395		 */
8396		"bSortClasses": true,
8397	
8398	
8399		/**
8400		 * Enable or disable state saving. When enabled a cookie will be used to save
8401		 * table display information such as pagination information, display length,
8402		 * filtering and sorting. As such when the end user reloads the page the
8403		 * display display will match what thy had previously set up.
8404		 *  @type boolean
8405		 *  @default false
8406		 *  @dtopt Features
8407		 * 
8408		 *  @example
8409		 *    $(document).ready( function () {
8410		 *      $('#example').dataTable( {
8411		 *        "bStateSave": true
8412		 *      } );
8413		 *    } );
8414		 */
8415		"bStateSave": false,
8416	
8417	
8418		/**
8419		 * Customise the cookie and / or the parameters being stored when using
8420		 * DataTables with state saving enabled. This function is called whenever
8421		 * the cookie is modified, and it expects a fully formed cookie string to be
8422		 * returned. Note that the data object passed in is a Javascript object which
8423		 * must be converted to a string (JSON.stringify for example).
8424		 *  @type function
8425		 *  @param {string} sName Name of the cookie defined by DataTables
8426		 *  @param {object} oData Data to be stored in the cookie
8427		 *  @param {string} sExpires Cookie expires string
8428		 *  @param {string} sPath Path of the cookie to set
8429		 *  @returns {string} Cookie formatted string (which should be encoded by
8430		 *    using encodeURIComponent())
8431		 *  @dtopt Callbacks
8432		 * 
8433		 *  @example
8434		 *    $(document).ready( function () {
8435		 *      $('#example').dataTable( {
8436		 *        "fnCookieCallback": function (sName, oData, sExpires, sPath) {
8437		 *          // Customise oData or sName or whatever else here
8438		 *          return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath;
8439		 *        }
8440		 *      } );
8441		 *    } );
8442		 */
8443		"fnCookieCallback": null,
8444	
8445	
8446		/**
8447		 * This function is called when a TR element is created (and all TD child
8448		 * elements have been inserted), or registered if using a DOM source, allowing
8449		 * manipulation of the TR element (adding classes etc).
8450		 *  @type function
8451		 *  @param {node} nRow "TR" element for the current row
8452		 *  @param {array} aData Raw data array for this row
8453		 *  @param {int} iDataIndex The index of this row in aoData
8454		 *  @dtopt Callbacks
8455		 * 
8456		 *  @example
8457		 *    $(document).ready( function() {
8458		 *      $('#example').dataTable( {
8459		 *        "fnCreatedRow": function( nRow, aData, iDataIndex ) {
8460		 *          // Bold the grade for all 'A' grade browsers
8461		 *          if ( aData[4] == "A" )
8462		 *          {
8463		 *            $('td:eq(4)', nRow).html( '<b>A</b>' );
8464		 *          }
8465		 *        }
8466		 *      } );
8467		 *    } );
8468		 */
8469		"fnCreatedRow": null,
8470	
8471	
8472		/**
8473		 * This function is called on every 'draw' event, and allows you to
8474		 * dynamically modify any aspect you want about the created DOM.
8475		 *  @type function
8476		 *  @param {object} oSettings DataTables settings object
8477		 *  @dtopt Callbacks
8478		 * 
8479		 *  @example
8480		 *    $(document).ready( function() {
8481		 *      $('#example').dataTable( {
8482		 *        "fnDrawCallback": function( oSettings ) {
8483		 *          alert( 'DataTables has redrawn the table' );
8484		 *        }
8485		 *      } );
8486		 *    } );
8487		 */
8488		"fnDrawCallback": null,
8489	
8490	
8491		/**
8492		 * Identical to fnHeaderCallback() but for the table footer this function
8493		 * allows you to modify the table footer on every 'draw' even.
8494		 *  @type function
8495		 *  @param {node} nFoot "TR" element for the footer
8496		 *  @param {array} aData Full table data (as derived from the original HTML)
8497		 *  @param {int} iStart Index for the current display starting point in the 
8498		 *    display array
8499		 *  @param {int} iEnd Index for the current display ending point in the 
8500		 *    display array
8501		 *  @param {array int} aiDisplay Index array to translate the visual position
8502		 *    to the full data array
8503		 *  @dtopt Callbacks
8504		 * 
8505		 *  @example
8506		 *    $(document).ready( function() {
8507		 *      $('#example').dataTable( {
8508		 *        "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) {
8509		 *          nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart;
8510		 *        }
8511		 *      } );
8512		 *    } )
8513		 */
8514		"fnFooterCallback": null,
8515	
8516	
8517		/**
8518		 * When rendering large numbers in the information element for the table
8519		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
8520		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
8521		 * rendered as "1,000,000") to help readability for the end user. This
8522		 * function will override the default method DataTables uses.
8523		 *  @type function
8524		 *  @member
8525		 *  @param {int} iIn number to be formatted
8526		 *  @returns {string} formatted string for DataTables to show the number
8527		 *  @dtopt Callbacks
8528		 * 
8529		 *  @example
8530		 *    $(document).ready( function() {
8531		 *      $('#example').dataTable( {
8532		 *        "fnFormatNumber": function ( iIn ) {
8533		 *          if ( iIn &lt; 1000 ) {
8534		 *            return iIn;
8535		 *          } else {
8536		 *            var 
8537		 *              s=(iIn+""), 
8538		 *              a=s.split(""), out="", 
8539		 *              iLen=s.length;
8540		 *            
8541		 *            for ( var i=0 ; i&lt;iLen ; i++ ) {
8542		 *              if ( i%3 === 0 &amp;&amp; i !== 0 ) {
8543		 *                out = "'"+out;
8544		 *              }
8545		 *              out = a[iLen-i-1]+out;
8546		 *            }
8547		 *          }
8548		 *          return out;
8549		 *        };
8550		 *      } );
8551		 *    } );
8552		 */
8553		"fnFormatNumber": function ( iIn ) {
8554			if ( iIn < 1000 )
8555			{
8556				// A small optimisation for what is likely to be the majority of use cases
8557				return iIn;
8558			}
8559	
8560			var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
8561			
8562			for ( var i=0 ; i<iLen ; i++ )
8563			{
8564				if ( i%3 === 0 && i !== 0 )
8565				{
8566					out = this.oLanguage.sInfoThousands+out;
8567				}
8568				out = a[iLen-i-1]+out;
8569			}
8570			return out;
8571		},
8572	
8573	
8574		/**
8575		 * This function is called on every 'draw' event, and allows you to
8576		 * dynamically modify the header row. This can be used to calculate and
8577		 * display useful information about the table.
8578		 *  @type function
8579		 *  @param {node} nHead "TR" element for the header
8580		 *  @param {array} aData Full table data (as derived from the original HTML)
8581		 *  @param {int} iStart Index for the current display starting point in the
8582		 *    display array
8583		 *  @param {int} iEnd Index for the current display ending point in the
8584		 *    display array
8585		 *  @param {array int} aiDisplay Index array to translate the visual position
8586		 *    to the full data array
8587		 *  @dtopt Callbacks
8588		 * 
8589		 *  @example
8590		 *    $(document).ready( function() {
8591		 *      $('#example').dataTable( {
8592		 *        "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) {
8593		 *          nHead.getElementsByTagName('th')[0].innerHTML = "Dis
8593playing "+(iEnd-iStart)+" records";
8594		 *        }
8595		 *      } );
8596		 *    } )
8597		 */
8598		"fnHeaderCallback": null,
8599	
8600	
8601		/**
8602		 * The information element can be used to convey information about the current
8603		 * state of the table. Although the internationalisation options presented by
8604		 * DataTables are quite capable of dealing with most customisations, there may
8605		 * be times where you wish to customise the string further. This callback
8606		 * allows you to do exactly that.
8607		 *  @type function
8608		 *  @param {object} oSettings DataTables settings object
8609		 *  @param {int} iStart Starting position in data for the draw
8610		 *  @param {int} iEnd End position in data for the draw
8611		 *  @param {int} iMax Total number of rows in the table (regardless of
8612		 *    filtering)
8613		 *  @param {int} iTotal Total number of rows in the data set, after filtering
8614		 *  @param {string} sPre The string that DataTables has formatted using it's
8615		 *    own rules
8616		 *  @returns {string} The string to be displayed in the information element.
8617		 *  @dtopt Callbacks
8618		 * 
8619		 *  @example
8620		 *    $('#example').dataTable( {
8621		 *      "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
8622		 *        return iStart +" to "+ iEnd;
8623		 *      }
8624		 *    } );
8625		 */
8626		"fnInfoCallback": null,
8627	
8628	
8629		/**
8630		 * Called when the table has been initialised. Normally DataTables will
8631		 * initialise sequentially and there will be no need for this function,
8632		 * however, this does not hold true when using external language information
8633		 * since that is obtained using an async XHR call.
8634		 *  @type function
8635		 *  @param {object} oSettings DataTables settings object
8636		 *  @param {object} json The JSON object request from the server - only
8637		 *    present if client-side Ajax sourced data is used
8638		 *  @dtopt Callbacks
8639		 * 
8640		 *  @example
8641		 *    $(document).ready( function() {
8642		 *      $('#example').dataTable( {
8643		 *        "fnInitComplete": function(oSettings, json) {
8644		 *          alert( 'DataTables has finished its initialisation.' );
8645		 *        }
8646		 *      } );
8647		 *    } )
8648		 */
8649		"fnInitComplete": null,
8650	
8651	
8652		/**
8653		 * Called at the very start of each table draw and can be used to cancel the
8654		 * draw by returning false, any other return (including undefined) results in
8655		 * the full draw occurring).
8656		 *  @type function
8657		 *  @param {object} oSettings DataTables settings object
8658		 *  @returns {boolean} False will cancel the draw, anything else (including no
8659		 *    return) will allow it to complete.
8660		 *  @dtopt Callbacks
8661		 * 
8662		 *  @example
8663		 *    $(document).ready( function() {
8664		 *      $('#example').dataTable( {
8665		 *        "fnPreDrawCallback": function( oSettings ) {
8666		 *          if ( $('#test').val() == 1 ) {
8667		 *            return false;
8668		 *          }
8669		 *        }
8670		 *      } );
8671		 *    } );
8672		 */
8673		"fnPreDrawCallback": null,
8674	
8675	
8676		/**
8677		 * This function allows you to 'post process' each row after it have been
8678		 * generated for each table draw, but before it is rendered on screen. This
8679		 * function might be used for setting the row class name etc.
8680		 *  @type function
8681		 *  @param {node} nRow "TR" element for the current row
8682		 *  @param {array} aData Raw data array for this row
8683		 *  @param {int} iDisplayIndex The display index for the current table draw
8684		 *  @param {int} iDisplayIndexFull The index of the data in the full list of
8685		 *    rows (after filtering)
8686		 *  @dtopt Callbacks
8687		 * 
8688		 *  @example
8689		 *    $(document).ready( function() {
8690		 *      $('#example').dataTable( {
8691		 *        "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
8692		 *          // Bold the grade for all 'A' grade browsers
8693		 *          if ( aData[4] == "A" )
8694		 *          {
8695		 *            $('td:eq(4)', nRow).html( '<b>A</b>' );
8696		 *          }
8697		 *        }
8698		 *      } );
8699		 *    } );
8700		 */
8701		"fnRowCallback": null,
8702	
8703	
8704		/**
8705		 * This parameter allows you to override the default function which obtains
8706		 * the data from the server ($.getJSON) so something more suitable for your
8707		 * application. For example you could use POST data, or pull information from
8708		 * a Gears or AIR database.
8709		 *  @type function
8710		 *  @member
8711		 *  @param {string} sSource HTTP source to obtain the data from (sAjaxSource)
8712		 *  @param {array}
8712 aoData A key/value pair object containing the data to send
8713		 *    to the server
8714		 *  @param {function} fnCallback to be called on completion of the data get
8715		 *    process that will draw the data on the page.
8716		 *  @param {object} oSettings DataTables settings object
8717		 *  @dtopt Callbacks
8718		 *  @dtopt Server-side
8719		 * 
8720		 *  @example
8721		 *    // POST data to server
8722		 *    $(document).ready( function() {
8723		 *      $('#example').dataTable( {
8724		 *        "bProcessing": true,
8725		 *        "bServerSide": true,
8726		 *        "sAjaxSource": "xhr.php",
8727		 *        "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
8728		 *          oSettings.jqXHR = $.ajax( {
8729		 *            "dataType": 'json', 
8730		 *            "type": "POST", 
8731		 *            "url": sSource, 
8732		 *            "data": aoData, 
8733		 *            "success": fnCallback
8734		 *          } );
8735		 *        }
8736		 *      } );
8737		 *    } );
8738		 */
8739		"fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {
8740			oSettings.jqXHR = $.ajax( {
8741				"url":  sUrl,
8742				"data": aoData,
8743				"success": function (json) {
8744					if ( json.sError ) {
8745						oSettings.oApi._fnLog( oSettings, 0, json.sError );
8746					}
8747					
8748					$(oSettings.oInstance).trigger('xhr', [oSettings, json]);
8749					fnCallback( json );
8750				},
8751				"dataType": "json",
8752				"cache": false,
8753				"type": oSettings.sServerMethod,
8754				"error": function (xhr, error, thrown) {
8755					if ( error == "parsererror" ) {
8756						oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+
8757							"server could not be parsed. This is caused by a JSON formatting error." );
8758					}
8759				}
8760			} );
8761		},
8762	
8763	
8764		/**
8765		 * It is often useful to send extra data to the server when making an Ajax
8766		 * request - for example custom filtering information, and this callback
8767		 * function makes it trivial to send extra information to the server. The
8768		 * passed in parameter is the data set that has been constructed by
8769		 * DataTables, and you can add to this or modify it as you require.
8770		 *  @type function
8771		 *  @param {array} aoData Data array (array of objects which are name/value
8772		 *    pairs) that has been constructed by DataTables and will be sent to the
8773		 *    server. In the case of Ajax sourced data with server-side processing
8774		 *    this will be an empty array, for server-side processing there will be a
8775		 *    significant number of parameters!
8776		 *  @returns {undefined} Ensure that you modify the aoData array passed in,
8777		 *    as this is passed by reference.
8778		 *  @dtopt Callbacks
8779		 *  @dtopt Server-side
8780		 * 
8781		 *  @example
8782		 *    $(document).ready( function() {
8783		 *      $('#example').dataTable( {
8784		 *        "bProcessing": true,
8785		 *        "bServerSide": true,
8786		 *        "sAjaxSource": "scripts/server_processing.php",
8787		 *        "fnServerParams": function ( aoData ) {
8788		 *          aoData.push( { "name": "more_data", "value": "my_value" } );
8789		 *        }
8790		 *      } );
8791		 *    } );
8792		 */
8793		"fnServerParams": null,
8794	
8795	
8796		/**
8797		 * Load the table state. With this function you can define from where, and how, the
8798		 * state of a table is loaded. By default DataTables will load from its state saving
8799		 * cookie, but you might wish to use local storage (HTML5) or a server-side database.
8800		 *  @type function
8801		 *  @member
8802		 *  @param {object} oSettings DataTables settings object
8803		 *  @return {object} The DataTables state object to be loaded
8804		 *  @dtopt Callbacks
8805		 * 
8806		 *  @example
8807		 *    $(document).ready( function() {
8808		 *      $('#example').dataTable( {
8809		 *        "bStateSave": true,
8810		 *        "fnStateLoad": function (oSettings) {
8811		 *          var o;
8812		 *          
8813		 *          // Send an Ajax request to the server to get the data. Note that
8814		 *          // this is a synchronous request.
8815		 *          $.ajax( {
8816		 *            "url": "/state_load",
8817		 *            "async": false,
8818		 *            "dataType": "json",
8819		 *            "success": function (json) {
8820		 *              o = json;
8821		 *            }
8822		 *          } );
8823		 *          
8824		 *          return o;
8825		 *        }
8826		 *      } );
8827		 *    } );
8828		 */
8829		"fnStateLoad": function ( oSettings ) {
8830			var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
8831			var oData;
8832	
8833			try {
8834				oData = (typeof $.parseJSON === 'function') ? 
8835					$.parseJSON(sData) : eval( '('+sData+')' );
8836			} catch (e) {
8837				oData = null;
8838			}
8839	
8840			return oData;
8841		},
8842	
8843	
8844		/**
8845		 * Callback which allows modification of the saved state prior to loading that state.
8846		 * This callback is called when the table is loading state from the stored data, but
8847		 * prior to the settings object being modified by the saved state. Note that for 
8848		 * plug-in authors, you should use the 'stateLoadParams' event to load parameters for 
8849		 * a plug-in.
8850		 *  @type function
8851		 *  @param {object} oSettings DataTables settings object
8852		 *  @param {object} oData The state object that is to be loaded
8853		 *  @dtopt Callbacks
8854		 * 
8855		 *  @example
8856		 *    // Remove a saved filter, so filtering is never loaded
8857		 *    $(document).ready( function() {
8858		 *      $('#example').dataTable( {
8859		 *        "bStateSave": true,
8860		 *        "fnStateLoadParams": function (oSettings, oData) {
8861		 *          oData.oSearch.sSearch = "";
8862		 *        }
8863		 *      } );
8864		 *    } );
8865		 * 
8866		 *  @example
8867		 *    // Disallow state loading by returning false
8868		 *    $(document).ready( function() {
8869		 *      $('#example').dataTable( {
8870		 *        "bStateSave": true,
8871		 *        "fnStateLoadParams": function (oSettings, oData) {
8872		 *          return false;
8873		 *        }
8874		 *      } );
8875		 *    } );
8876		 */
8877		"fnStateLoadParams": null,
8878	
8879	
8880		/**
8881		 * Callback that is called when the state has been loaded from the state saving method
8882		 * and the DataTables settings object has been modified as a result of the loaded state.
8883		 *  @type function
8884		 *  @param {object} oSettings DataTables settings object
8885		 *  @param {object} oData The state object that was loaded
8886		 *  @dtopt Callbacks
8887		 * 
8888		 *  @example
8889		 *    // Show an alert with the filtering value that was saved
8890		 *    $(document).ready( function() {
8891		 *      $('#example').dataTable( {
8892		 *        "bStateSave": true,
8893		 *        "fnStateLoaded": function (oSettings, oData) {
8894		 *          alert( 'Saved filter was: '+oData.oSearch.sSearch );
8895		 *        }
8896		 *      } );
8897		 *    } );
8898		 */
8899		"fnStateLoaded": null,
8900	
8901	
8902		/**
8903		 * Save the table state. This function allows you to define where and how the state
8904		 * information for the table is stored - by default it will use a cookie, but you
8905		 * might want to use local storage (HTML5) or a server-side database.
8906		 *  @type function
8907		 *  @member
8908		 *  @param {object} oSettings DataTables settings object
8909		 *  @param {object} oData The state object to be saved
8910		 *  @dtopt Callbacks
8911		 * 
8912		 *  @example
8913		 *    $(document).ready( function() {
8914		 *      $('#example').dataTable( {
8915		 *        "bStateSave": true,
8916		 *        "fnStateSave": function (oSettings, oData) {
8917		 *          // Send an Ajax request to the server with the state object
8918		 *          $.ajax( {
8919		 *            "url": "/state_save",
8920		 *            "data": oData,
8921		 *            "dataType": "json",
8922		 *            "method": "POST"
8923		 *            "success": function () {}
8924		 *          } );
8925		 *        }
8926		 *      } );
8927		 *    } );
8928		 */
8929		"fnStateSave": function ( oSettings, oData ) {
8930			this.oApi._fnCreateCookie( 
8931				oSettings.sCookiePrefix+oSettings.sInstance, 
8932				this.oApi._fnJsonString(oData), 
8933				oSettings.iCookieDuration, 
8934				oSettings.sCookiePrefix, 
8935				oSettings.fnCookieCallback
8936			);
8937		},
8938	
8939	
8940		/**
8941		 * Callback which allows modification of the state to be saved. Called when the table 
8942		 * has changed state a new state save is required. This method allows modification of
8943		 * the state saving object prior to actually doing the save, including addition or 
8944		 * other state properties or modification. Note that for plug-in authors, you should 
8945		 * use the 'stateSaveParams' event to save parameters for a plug-in.
8946		 *  @type function
8947		 *  @param {object} oSettings DataTables settings object
8948		 *  @param {object} oData The state object to be saved
8949		 *  @dtopt Callbacks
8950		 * 
8951		 *  @example
8952		 *    // Remove a saved filter, so filtering is never saved
8953		 *    $(document).ready( function() {
8954		 *      $('#example').dataTable( {
8955		 *        "bStateSave": true,
8956		 *        "fnStateSaveParams": function (oSettings, oData) {
8957		 *          oData.oSearch.sSearch = "";
8958		 *        }
8959		 *      } );
8960		 *    } );
8961		 */
8962		"fnStateSaveParams": null,
8963	
8964	
8965		/**
8966		 * Duration of the cookie which is used for storing session information. This
8967		 * value is given in seconds.
8968		 *  @type int
8969		 *  @default 7200 <i>(2 hours)</i>
8970		 *  @dtopt Options
8971		 * 
8972		 *  @example
8973		 *    $(document).ready( function() {
8974		 *      $('#example').dataTable( {
8975		 *        "iCookieDuration": 60*60*24; // 1 day
8976		 *      } );
8977		 *    } )
8978		 */
8979		"iCookieDuration": 7200,
8980	
8981	
8982		/**
8983		 * When enabled DataTables will not make a request to the server for the first
8984		 * page draw - rather it will use the data already on the page (no sorting etc
8985		 * will be applied to it), thus saving on an XHR at load time. iDeferLoading
8986		 * is used to indicate that deferred loading is required, but it is also used
8987		 * to tell DataTables how many records there are in the full table (allowing
8988		 * the information element and pagination to be displayed correctly). In the case
8989		 * where a filtering is applied to the table on initial load, this can be
8990		 * indicated by giving the parameter as an array, where the first element is
8991		 * the number of records available after filtering and the second element is the
8992		 * number of records without filtering (allowing the table information element
8993		 * to be shown correctly).
8994		 *  @type int | array
8995		 *  @default null
8996		 *  @dtopt Options
8997		 * 
8998		 *  @example
8999		 *    // 57 records available in the table, no filtering applied
9000		 *    $(document).ready( function() {
9001		 *      $('#example').dataTable( {
9002		 *        "bServerSide": true,
9003		 *        "sAjaxSource": "scripts/server_processing.php",
9004		 *        "iDeferLoading": 57
9005		 *      } );
9006		 *    } );
9007		 * 
9008		 *  @example
9009		 *    // 57 records after filtering, 100 without filtering (an initial filter applied)
9010		 *    $(document).ready( function() {
9011		 *      $('#example').dataTable( {
9012		 *        "bServerSide": true,
9013		 *        "sAjaxSource": "scripts/server_processing.php",
9014		 *        "iDeferLoading": [ 57, 100 ],
9015		 *        "oSearch": {
9016		 *          "sSearch": "my_filter"
9017		 *        }
9018		 *      } );
9019		 *    } );
9020		 */
9021		"iDeferLoading": null,
9022	
9023	
9024		/**
9025		 * Number of rows to display on a single page when using pagination. If
9026		 * feature enabled (bLengthChange) then the end user will be able to override
9027		 * this to a custom setting using a pop-up menu.
9028		 *  @type int
9029		 *  @default 10
9030		 *  @dtopt Options
9031		 * 
9032		 *  @example
9033		 *    $(document).ready( function() {
9034		 *      $('#example').dataTable( {
9035		 *        "iDisplayLength": 50
9036		 *      } );
9037		 *    } )
9038		 */
9039		"iDisplayLength": 10,
9040	
9041	
9042		/**
9043		 * Define the starting point for data display when using DataTables with
9044		 * pagination. Note that this parameter is the number of records, rather than
9045		 * the page number, so if you have 10 records per page and want to start on
9046		 * the third page, it should be "20".
9047		 *  @type int
9048		 *  @default 0
9049		 *  @dtopt Options
9050		 * 
9051		 *  @example
9052		 *    $(document).ready( function() {
9053		 *      $('#example').dataTable( {
9054		 *        "iDisplayStart": 20
9055		 *      } );
9056		 *    } )
9057		 */
9058		"iDisplayStart": 0,
9059	
9060	
9061		/**
9062		 * The scroll gap is the amount of scrolling that is left to go before
9063		 * DataTables will load the next 'page' of data automatically. You typically
9064		 * want a gap which is big enough that the scrolling will be smooth for the
9065		 * user, while not so large that it will load more data than need.
9066		 *  @type int
9067		 *  @default 100
9068		 *  @dtopt Options
9069		 * 
9070		 *  @example
9071		 *    $(document).ready( function() {
9072		 *      $('#example').dataTable( {
9073		 *        "bScrollInfinite": true,
9074		 *        "bScrollCollapse": true,
9075		 *        "sScrollY": "200px",
9076		 *        "iScrollLoadGap": 50
9077		 *      } );
9078		 *    } );
9079		 */
9080		"iScrollLoadGap": 100,
9081	
9082	
9083		/**
9084		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
9085		 * and filtering) by adding a tabindex attribute to the required elements. This
9086		 * allows you to tab through the controls and press the enter key to activate them.
9087		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
9088		 * You can overrule this using this parameter if you wish. Use a value of -1 to
9089		 * disable built-in keyboard navigation.
9090		 *  @type int
9091		 *  @default 0
9092		 *  @dtopt Options
9093		 * 
9094		 *  @example
9095		 *    $(document).ready( function() {
9096		 *      $('#example').dataTable( {
9097		 *        "iTabIndex": 1
9098		 *      } );
9099		 *    } );
9100		 */
9101		"iTabIndex": 0,
9102	
9103	
9104		/**
9105		 * All strings that DataTables uses in the user interface that it creates
9106		 * are defined in this object, allowing you to modified them individually or
9107		 * completely replace them all as required.
9108		 *  @namespace
9109		 */
9110		"oLanguage": {
9111			/**
9112			 * Strings that are used for WAI-ARIA labels and controls only (these are not
9113			 * actually visible on the page, but will be read by screenreaders, and thus
9114			 * must be internationalised as well).
9115			 *  @namespace
9116			 */
9117			"oAria": {
9118				/**
9119				 * ARIA label that is added to the table headers when the column may be
9120				 * sorted ascending by activing the column (click or return when focused).
9121				 * Note that the column header is prefixed to this string.
9122				 *  @type string
9123				 *  @default : activate to sort column ascending
9124				 *  @dtopt Language
9125				 * 
9126				 *  @example
9127				 *    $(document).ready( function() {
9128				 *      $('#example').dataTable( {
9129				 *        "oLanguage": {
9130				 *          "oAria": {
9131				 *            "sSortAscending": " - click/return to sort ascending"
9132				 *          }
9133				 *        }
9134				 *      } );
9135				 *    } );
9136				 */
9137				"sSortAscending": ": activate to sort column ascending",
9138	
9139				/**
9140				 * ARIA label that is added to the table headers when the column may be
9141				 * sorted descending by activing the column (click or return when focused).
9142				 * Note that the column header is prefixed to this string.
9143				 *  @type string
9144				 *  @default : activate to sort column ascending
9145				 *  @dtopt Language
9146				 * 
9147				 *  @example
9148				 *    $(document).ready( function() {
9149				 *      $('#example').dataTable( {
9150				 *        "oLanguage": {
9151				 *          "oAria": {
9152				 *            "sSortDescending": " - click/return to sort descending"
9153				 *          }
9154				 *        }
9155				 *      } );
9156				 *    } );
9157				 */
9158				"sSortDescending": ": activate to sort column descending"
9159			},
9160	
9161			/**
9162			 * Pagination string used by DataTables for the two built-in pagination
9163			 * control types ("two_button" and "full_numbers")
9164			 *  @namespace
9165			 */
9166			"oPaginate": {
9167				/**
9168				 * Text to use when using the 'full_numbers' type of pagination for the
9169				 * button to take the user to the first page.
9170				 *  @type string
9171				 *  @default First
9172				 *  @dtopt Language
9173				 * 
9174				 *  @example
9175				 *    $(document).ready( function() {
9176				 *      $('#example').dataTable( {
9177				 *        "oLanguage": {
9178				 *          "oPaginate": {
9179				 *            "sFirst": "First page"
9180				 *          }
9181				 *        }
9182				 *      } );
9183				 *    } );
9184				 */
9185				"sFirst": "Primero",
9186			
9187			
9188				/**
9189				 * Text to use when using the 'full_numbers' type of pagination for the
9190				 * button to take the user to the last page.
9191				 *  @type string
9192				 *  @default Last
9193				 *  @dtopt Language
9194				 * 
9195				 *  @example
9196				 *    $(document).ready( function() {
9197				 *      $('#example').dataTable( {
9198				 *        "oLanguage": {
9199				 *          "oPaginate": {
9200				 *            "sLast": "Last page"
9201				 *          }
9202				 *        }
9203				 *      } );
9204				 *    } );
9205				 */
9206				"sLast": "Último",
9207			
9208			
9209				/**
9210				 * Text to use for the 'next' pagination button (to take the user to the 
9211				 * next page).
9212				 *  @type string
9213				 *  @default Next
9214				 *  @dtopt Language
9215				 * 
9216				 *  @example
9217				 *    $(document).ready( function() {
9218				 *      $('#example').dataTable( {
9219				 *        "oLanguage": {
9220				 *          "oPaginate": {
9221				 *            "sNext": "Next page"
9222				 *          }
9223				 *        }
9224				 *      } );
9225				 *    } );
9226				 */
9227				"sNext": "Siguiente",
9228			
9229			
9230				/**
9231				 * Text to use for the 'previous' pagination button (to take the user to  
9232				 * the previous page).
9233				 *  @type string
9234				 *  @default Previous
9235				 *  @dtopt Language
9236				 * 
9237				 *  @example
9238				 *    $(document).ready( function() {
9239				 *      $('#example').dataTable( {
9240				 *        "oLanguage": {
9241				 *          "oPaginate": {
9242				 *            "sPrevious": "Previous page"
9243				 *          }
9244				 *        }
9245				 *      } );
9246				 *    } );
9247				 */
9248				"sPrevious": "Anterior"
9249			},
9250		
9251			/**
9252			 * This string is shown in preference to sZeroRecords when the table is
9253			 * empty of data (regardless of filtering). Note that this is an optional
9254			 * parameter - if it is not given, the value of sZeroRecords will be used
9255			 * instead (either the default or given value).
9256			 *  @type string
9257			 *  @default No data available in table
9258			 *  @dtopt Language
9259			 * 
9260			 *  @example
9261			 *    $(document).ready( function() {
9262			 *      $('#example').dataTable( {
9263			 *        "oLanguage": {
9264			 *          "sEmptyTable": "No data available in table"
9265			 *        }
9266			 *      } );
9267			 *    } );
9268			 */
9269			"sEmptyTable": "Ningún dato disponible",
9270		
9271		
9272			/**
9273			 * This string gives information to the end user about the information that 
9274			 * is current on display on the page. The _START_, _END_ and _TOTAL_ 
9275			 * variables are all dynamically replaced as the table display updates, and 
9276			 * can be freely moved or removed as the language requirements change.
9277			 *  @type string
9278			 *  @default Showing _START_ to _END_ of _TOTAL_ entries
9279			 *  @dtopt Language
9280			 * 
9281			 *  @example
9282			 *    $(document).ready( function() {
9283			 *      $('#example').dataTable( {
9284			 *        "oLanguage": {
9285			 *          "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"
9286			 *        }
9287			 *      } );
9288			 *    } );
9289			 */
9290			"sInfo": "Mostrando _START_ a _END_ de _TOTAL_ totales",
9291		
9292		
9293			/**
9294			 * Display information string for when the table is empty. Typically the 
9295			 * format of this string should match sInfo.
9296			 *  @type string
9297			 *  @default Showing 0 to 0 of 0 entries
9298			 *  @dtopt Language
9299			 * 
9300			 *  @example
9301			 *    $(document).ready( function() {
9302			 *      $('#example').dataTable( {
9303			 *        "oLanguage": {
9304			 *          "sInfoEmpty": "No entries to show"
9305			 *        }
9306			 *      } );
9307			 *    } );
9308			 */
9309			"sInfoEmpty": "Mostrando 0 a 0 de 0 totales",
9310		
9311		
9312			/**
9313			 * When a user filters the information in a table, this string is appended 
9314			 * to the information (sInfo) to give an idea of how strong the filtering 
9315			 * is. The variable _MAX_ is dynamically updated.
9316			 *  @type string
9317			 *  @default (filtered from _MAX_ total entries)
9318			 *  @dtopt Language
9319			 * 
9320			 *  @example
9321			 *    $(document).ready( function() {
9322			 *      $('#example').dataTable( {
9323			 *        "oLanguage": {
9324			 *          "sInfoFiltered": " - filtering from _MAX_ records"
9325			 *        }
9326			 *      } );
9327			 *    } );
9328			 */
9329			"sInfoFiltered": "(filtrados de _MAX_ totales)",
9330		
9331		
9332			/**
9333			 * If can be useful to append extra information to the info string at times,
9334			 * and this variable does exactly that. This information will be appended to
9335			 * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are
9336			 * being used) at all times.
9337			 *  @type string
9338			 *  @default <i>Empty string</i>
9339			 *  @dtopt Language
9340			 * 
9341			 *  @example
9342			 *    $(document).ready( function() {
9343			 *      $('#example').dataTable( {
9344			 *        "oLanguage": {
9345			 *          "sInfoPostFix": "All records shown are derived from real information."
9346			 *        }
9347			 *      } );
9348			 *    } );
9349			 */
9350			"sInfoPostFix": "",
9351		
9352		
9353			/**
9354			 * DataTables has a build in number formatter (fnFormatNumber) which is used
9355			 * to format large numbers that are used in the table information. By
9356			 * default a comma is used, but this can be trivially changed to any
9357			 * character you wish with this parameter.
9358			 *  @type string
9359			 *  @default ,
9360			 *  @dtopt Language
9361			 * 
9362			 *  @example
9363			 *    $(document).ready( function() {
9364			 *      $('#example').dataTable( {
9365			 *        "oLanguage": {
9366			 *          "sInfoThousands": "'"
9367			 *        }
9368			 *      } );
9369			 *    } );
9370			 */
9371			"sInfoThousands": ",",
9372		
9373		
9374			/**
9375			 * Detail the action that will be taken when the drop down menu for the
9376			 * pagination length option is changed. The '_MENU_' variable is replaced
9377			 * with a default select list of 10, 25, 50 and 100, and can be replaced
9378			 * with a custom select box if required.
9379			 *  @type string
9380			 *  @default Show _MENU_ entries
9381			 *  @dtopt Language
9382			 * 
9383			 *  @example
9384			 *    // Language change only
9385			 *    $(document).ready( function() {
9386			 *      $('#example').dataTable( {
9387			 *        "oLanguage": {
9388			 *          "sLengthMenu": "Display _MENU_ records"
9389			 *        }
9390			 *      } );
9391			 *    } );
9392			 *    
9393			 *  @example
9394			 *    // Language and options change
9395			 *    $(document).ready( function() {
9396			 *      $('#example').dataTable( {
9397			 *        "oLanguage": {
9398			 *          "sLengthMenu": 'Display <select>'+
9399			 *            '<option value="10">10</option>'+
9400			 *            '<option value="20">20</option>'+
9401			 *            '<option value="30">30</option>'+
9402			 *            '<option value="40">40</option>'+
9403			 *            '<option value="50">50</option>'+
9404			 *            '<option value="-1">All</option>'+
9405			 *            '</select> records'
9406			 *        }
9407			 *      } );
9408			 *    } );
9409			 */
9410			"sLengthMenu": "Mostrar _MENU_ filas",
9411		
9412		
9413			/**
9414			 * When using Ajax sourced data and during the first draw when DataTables is
9415			 * gathering the data, this message is shown in an empty row in the table to
9416			 * indicate to the end user the the data is being loaded. Note that this
9417			 * parameter is not used when loading data by server-side processing, just
9418			 * Ajax sourced data with client-side processing.
9419			 *  @type string
9420			 *  @default Loading...
9421			 *  @dtopt Language
9422			 * 
9423			 *  @example
9424			 *    $(document).ready( function() {
9425			 *      $('#example').dataTable( {
9426			 *        "oLanguage": {
9427			 *          "sLoadingRecords": "Please wait - loading..."
9428			 *        }
9429			 *      } );
9430			 *    } );
9431			 */
9432			"sLoadingRecords": "Cargando...",
9433		
9434		
9435			/**
9436			 * Text which is displayed when the table is processing a user action
9437			 * (usually a sort command or similar).
9438			 *  @type string
9439			 *  @default Processing...
9440			 *  @dtopt Language
9441			 * 
9442			 *  @example
9443			 *    $(document).ready( function() {
9444			 *      $('#example').dataTable( {
9445			 *        "oLanguage": {
9446			 *          "sProcessing": "DataTables is currently busy"
9447			 *        }
9448			 *      } );
9449			 *    } );
9450			 */
9451			"sProcessing": "Procesando...",
9452		
9453		
9454			/**
9455			 * Details the actions that will be taken when the user types into the
9456			 * filtering input text box. The variable "_INPUT_", if used in the string,
9457			 * is replaced with the HTML text box for the filtering input allowing
9458			 * control over where it appears in the string. If "_INPUT_" is not given
9459			 * then the input box is appended to the string automatically.
9460			 *  @type string
9461			 *  @default Search:
9462			 *  @dtopt Language
9463			 * 
9464			 *  @example
9465			 *    // Input text box will be appended at the end automatically
9466			 *    $(document).ready( function() {
9467			 *      $('#example').dataTable( {
9468			 *        "oLanguage": {
9469			 *          "sSearch": "Filter records:"
9470			 *        }
9471			 *      } );
9472			 *    } );
9473			 *    
9474			 *  @example
9475			 *    // Specify where the filter should appear
9476			 *    $(document).ready( function() {
9477			 *      $('#example').dataTable( {
9478			 *        "oLanguage": {
9479			 *          "sSearch": "Apply filter _INPUT_ to table"
9480			 *        }
9481			 *      } );
9482			 *    } );
9483			 */
9484			"sSearch": "Filtrar:",
9485		
9486		
9487			/**
9488			 * All of the language information can be stored in a file on the
9489			 * server-side, which DataTables will look up if this parameter is passed.
9490			 * It must store the URL of the language file, which is in a JSON format,
9491			 * and the object has the same properties as the oLanguage object in the
9492			 * initialiser object (i.e. the above parameters). Please refer to one of
9493			 * the example language files to see how this works in action.
9494			 *  @type string
9495			 *  @default <i>Empty string - i.e. disabled</i>
9496			 *  @dtopt Language
9497			 * 
9498			 *  @example
9499			 *    $(document).ready( function() {
9500			 *      $('#example').dataTable( {
9501			 *        "oLanguage": {
9502			 *          "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"
9503			 *        }
9504			 *      } );
9505			 *    } );
9506			 */
9507			"sUrl": "",
9508		
9509		
9510			/**
9511			 * Text shown inside the table records when the is no information to be
9512			 * displayed after filtering. sEmptyTable is shown when there is simply no
9513			 * information in the table at all (regardless of filtering).
9514			 *  @type string
9515			 *  @default No matching records found
9516			 *  @dtopt Language
9517			 * 
9518			 *  @example
9519			 *    $(document).ready( function() {
9520			 *      $('#example').dataTable( {
9521			 *        "oLanguage": {
9522			 *          "sZeroRecords": "No records to display"
9523			 *        }
9524			 *      } );
9525			 *    } );
9526			 */
9527			"sZeroRecords": "No matching records found"
9528		},
9529	
9530	
9531		/**
9532		 * This parameter allows you to have define the global filtering state at
9533		 * initialisation time. As an object the "sSearch" parameter must be
9534		 * defined, but all other parameters are optional. When "bRegex" is true,
9535		 * the search string will be treated as a regular expression, when false
9536		 * (default) it will be treated as a straight string. When "bSmart"
9537		 * DataTables will use it's smart filtering methods (to word match at
9538		 * any point in the data), when false this will not be done.
9539		 *  @namespace
9540		 *  @extends DataTable.models.oSearch
9541		 *  @dtopt Options
9542		 * 
9543		 *  @example
9544		 *    $(document).ready( function() {
9545		 *      $('#example').dataTable( {
9546		 *        "oSearch": {"sSearch": "Initial search"}
9547		 *      } );
9548		 *    } )
9549		 */
9550		"oSearch": $.extend( {}, DataTable.models.oSearch ),
9551	
9552	
9553		/**
9554		 * By default DataTables will look for the property 'aaData' when obtaining
9555		 * data from an Ajax source or for server-side processing - this parameter
9556		 * allows that property to be changed. You can use Javascript dotted object
9557		 * notation to get a data source for multiple levels of nesting.
9558		 *  @type string
9559		 *  @default aaData
9560		 *  @dtopt Options
9561		 *  @dtopt Server-side
9562		 * 
9563		 *  @example
9564		 *    // Get data from { "data": [...] }
9565		 *    $(document).ready( function() {
9566		 *      var oTable = $('#example').dataTable( {
9567		 *        "sAjaxSource": "sources/data.txt",
9568		 *        "sAjaxDataProp": "data"
9569		 *      } );
9570		 *    } );
9571		 *    
9572		 *  @example
9573		 *    // Get data from { "data": { "inner": [...] } }
9574		 *    $(document).ready( function() {
9575		 *      var oTable = $('#example').dataTable( {
9576		 *        "sAjaxSource": "sources/data.txt",
9577		 *        "sAjaxDataProp": "data.inner"
9578		 *      } );
9579		 *    } );
9580		 */
9581		"sAjaxDataProp": "aaData",
9582	
9583	
9584		/**
9585		 * You can instruct DataTables to load data from an external source using this
9586		 * parameter (use aData if you want to pass data in you already have). Simply
9587		 * provide a url a JSON object can be obtained from. This object must include
9588		 * the parameter 'aaData' which is the data source for the table.
9589		 *  @type string
9590		 *  @default null
9591		 *  @dtopt Options
9592		 *  @dtopt Server-side
9593		 * 
9594		 *  @example
9595		 *    $(document).ready( function() {
9596		 *      $('#example').dataTable( {
9597		 *        "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"
9598		 *      } );
9599		 *    } )
9600		 */
9601		"sAjaxSource": null,
9602	
9603	
9604		/**
9605		 * This parameter can be used to override the default prefix that DataTables
9606		 * assigns to a cookie when state saving is enabled.
9607		 *  @type string
9608		 *  @default SpryMedia_DataTables_
9609		 *  @dtopt Options
9610		 * 
9611		 *  @example
9612		 *    $(document).ready( function() {
9613		 *      $('#example').dataTable( {
9614		 *        "sCookiePrefix": "my_datatable_",
9615		 *      } );
9616		 *    } );
9617		 */
9618		"sCookiePrefix": "SpryMedia_DataTables_",
9619	
9620	
9621		/**
9622		 * This initialisation variable allows you to specify exactly where in the
9623		 * DOM you want DataTables to inject the various controls it adds to the page
9624		 * (for example you might want the pagination controls at the top of the
9625		 * table). DIV elements (with or without a custom class) can also be added to
9626		 * aid styling. The follow syntax is used:
9627		 *   <ul>
9628		 *     <li>The following options are allowed:	
9629		 *       <ul>
9630		 *         <li>'l' - Length changing</li
9631		 *         <li>'f' - Filtering input</li>
9632		 *         <li>'t' - The table!</li>
9633		 *         <li>'i' - Information</li>
9634		 *         <li>'p' - Pagination</li>
9635		 *         <li>'r' - pRocessing</li>
9636		 *       </ul>
9637		 *     </li>
9638		 *     <li>The following constants are allowed:
9639		 *       <ul>
9640		 *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
9641		 *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
9642		 *       </ul>
9643		 *     </li>
9644		 *     <li>The following syntax is expected:
9645		 *       <ul>
9646		 *         <li>'&lt;' and '&gt;' - div elements</li>
9647		 *         <li>'&lt;"class" and '&gt;' - div with a class</li>
9648		 *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
9649		 *       </ul>
9650		 *     </li>
9651		 *     <li>Examples:
9652		 *       <ul>
9653		 *         <li>'&lt;"wrapper"flipt&gt;'</li>
9654		 *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
9655		 *       </ul>
9656		 *     </li>
9657		 *   </ul>
9658		 *  @type string
9659		 *  @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b> 
9660		 *    <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i>
9661		 *  @dtopt Options
9662		 * 
9663		 *  @example
9664		 *    $(document).ready( function() {
9665		 *      $('#example').dataTable( {
9666		 *        "sDom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
9667		 *      } );
9668		 *    } );
9669		 */
9670		"sDom": "lfrtip",
9671	
9672	
9673		/**
9674		 * DataTables features two different built-in pagination interaction methods
9675		 * ('two_button' or 'full_numbers') which present different page controls to
9676		 * the end user. Further methods can be added using the API (see below).
9677		 *  @type string
9678		 *  @default two_button
9679		 *  @dtopt Options
9680		 * 
9681		 *  @example
9682		 *    $(document).ready( function() {
9683		 *      $('#example').dataTable( {
9684		 *        "sPaginationType": "full_numbers"
9685		 *      } );
9686		 *    } )
9687		 */
9688		"sPaginationType": "two_button",
9689	
9690	
9691		/**
9692		 * Enable horizontal scrolling. When a table is too wide to fit into a certain
9693		 * layout, or you have a large number of columns in the table, you can enable
9694		 * x-scrolling to show the table in a viewport, which can be scrolled. This
9695		 * property can be any CSS unit, or a number (in which case it will be treated
9696		 * as a pixel measurement).
9697		 *  @type string
9698		 *  @default <i>blank string - i.e. disabled</i>
9699		 *  @dtopt Features
9700		 * 
9701		 *  @example
9702		 *    $(document).ready( function() {
9703		 *      $('#example').dataTable( {
9704		 *        "sScrollX": "100%",
9705		 *        "bScrollCollapse": true
9706		 *      } );
9707		 *    } );
9708		 */
9709		"sScrollX": "",
9710	
9711	
9712		/**
9713		 * This property can be used to force a DataTable to use more width than it
9714		 * might otherwise do when x-scrolling is enabled. For example if you have a
9715		 * table which requires to be well spaced, this parameter is useful for
9716		 * "over-sizing" the table, and thus forcing scrolling. This property can by
9717		 * any CSS unit, or a number (in which case it will be treated as a pixel
9718		 * measurement).
9719		 *  @type string
9720		 *  @default <i>blank string - i.e. disabled</i>
9721		 *  @dtopt Options
9722		 * 
9723		 *  @example
9724		 *    $(document).ready( function() {
9725		 *      $('#example').dataTable( {
9726		 *        "sScrollX": "100%",
9727		 *        "sScrollXInner": "110%"
9728		 *      } );
9729		 *    } );
9730		 */
9731		"sScrollXInner": "",
9732	
9733	
9734		/**
9735		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
9736		 * to the given height, and enable scrolling for any data which overflows the
9737		 * current viewport. This can be used as an alternative to paging to display
9738		 * a lot of data in a small area (although paging and scrolling can both be
9739		 * enabled at the same time). This property can be any CSS unit, or a number
9740		 * (in which case it will be treated as a pixel measurement).
9741		 *  @type string
9742		 *  @default <i>blank string - i.e. disabled</i>
9743		 *  @dtopt Features
9744		 * 
9745		 *  @example
9746		 *    $(document).ready( function() {
9747		 *      $('#example').dataTable( {
9748		 *        "sScrollY": "200px",
9749		 *        "bPaginate": false
9750		 *      } );
9751		 *    } );
9752		 */
9753		"sScrollY": "",
9754	
9755	
9756		/**
9757		 * Set the HTTP method that is used to make the Ajax call for server-side
9758		 * processing or Ajax sourced data.
9759		 *  @type string
9760		 *  @default GET
9761		 *  @dtopt Options
9762		 *  @dtopt Server-side
9763		 * 
9764		 *  @example
9765		 *    $(document).ready( function() {
9766		 *      $('#example').dataTable( {
9767		 *        "bServerSide": true,
9768		 *        "sAjaxSource": "scripts/post.php",
9769		 *        "sServerMethod": "POST"
9770		 *      } );
9771		 *    } );
9772		 */
9773		"sServerMethod": "GET"
9774	};
9775	
9776	
9777	
9778	/**
9779	 * Column options that can be given to DataTables at initialisation time.
9780	 *  @namespace
9781	 */
9782	DataTable.defaults.columns = {
9783		/**
9784		 * Allows a column's sorting to take multiple columns into account when 
9785		 * doing a sort. For example first name / last name columns make sense to 
9786		 * do a multi-column sort over the two columns.
9787		 *  @type array
9788		 *  @default null <i>Takes the value of the column index automatically</i>
9789		 *  @dtopt Columns
9790		 * 
9791		 *  @example
9792		 *    // Using aoColumnDefs
9793		 *    $(document).ready( function() {
9794		 *      $('#example').dataTable( {
9795		 *        "aoColumnDefs": [
9796		 *          { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] },
9797		 *          { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] },
9798		 *          { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] }
9799		 *        ]
9800		 *      } );
9801		 *    } );
9802		 *    
9803		 *  @example
9804		 *    // Using aoColumns
9805		 *    $(document).ready( function() {
9806		 *      $('#example').dataTable( {
9807		 *        "aoColumns": [
9808		 *          { "aDataSort": [ 0, 1 ] },
9809		 *          { "aDataSort": [ 1, 0 ] },
9810		 *          { "aDataSort": [ 2, 3, 4 ] },
9811		 *          null,
9812		 *          null
9813		 *        ]
9814		 *      } );
9815		 *    } );
9816		 */
9817		"aDataSort": null,
9818	
9819	
9820		/**
9821		 * You can control the default sorting direction, and even alter the behaviour
9822		 * of the sort handler (i.e. only allow ascending sorting etc) using this
9823		 * parameter.
9824		 *  @type array
9825		 *  @default [ 'asc', 'desc' ]
9826		 *  @dtopt Columns
9827		 * 
9828		 *  @example
9829		 *    // Using aoColumnDefs
9830		 *    $(document).ready( function() {
9831		 *      $('#example').dataTable( {
9832		 *        "aoColumnDefs": [
9833		 *          { "asSorting": [ "asc" ], "aTargets": [ 1 ] },
9834		 *          { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] },
9835		 *          { "asSorting": [ "desc" ], "aTargets": [ 3 ] }
9836		 *        ]
9837		 *      } );
9838		 *    } );
9839		 *    
9840		 *  @example
9841		 *    // Using aoColumns
9842		 *    $(document).ready( function() {
9843		 *      $('#example').dataTable( {
9844		 *        "aoColumns": [
9845		 *          null,
9846		 *          { "asSorting": [ "asc" ] },
9847		 *          { "asSorting": [ "desc", "asc", "asc" ] },
9848		 *          { "asSorting": [ "desc" ] },
9849		 *          null
9850		 *        ]
9851		 *      } );
9852		 *    } );
9853		 */
9854		"asSorting": [ 'asc', 'desc' ],
9855	
9856	
9857		/**
9858		 * Enable or disable filtering on the data in this column.
9859		 *  @type boolean
9860		 *  @default true
9861		 *  @dtopt Columns
9862		 * 
9863		 *  @example
9864		 *    // Using aoColumnDefs
9865		 *    $(document).ready( function() {
9866		 *      $('#example').dataTable( {
9867		 *        "aoColumnDefs": [ 
9868		 *          { "bSearchable": false, "aTargets": [ 0 ] }
9869		 *        ] } );
9870		 *    } );
9871		 *    
9872		 *  @example
9873		 *    // Using aoColumns
9874		 *    $(document).ready( function() {
9875		 *      $('#example').dataTable( {
9876		 *        "aoColumns": [ 
9877		 *          { "bSearchable": false },
9878		 *          null,
9879		 *          null,
9880		 *          null,
9881		 *          null
9882		 *        ] } );
9883		 *    } );
9884		 */
9885		"bSearchable": true,
9886	
9887	
9888		/**
9889		 * Enable or disable sorting on this column.
9890		 *  @type boolean
9891		 *  @default true
9892		 *  @dtopt Columns
9893		 * 
9894		 *  @example
9895		 *    // Using aoColumnDefs
9896		 *    $(document).ready( function() {
9897		 *      $('#example').dataTable( {
9898		 *        "aoColumnDefs": [ 
9899		 *          { "bSortable": false, "aTargets": [ 0 ] }
9900		 *        ] } );
9901		 *    } );
9902		 *    
9903		 *  @example
9904		 *    // Using aoColumns
9905		 *    $(document).ready( function() {
9906		 *      $('#example').dataTable( {
9907		 *        "aoColumns": [ 
9908		 *          { "bSortable": false },
9909		 *          null,
9910		 *          null,
9911		 *          null,
9912		 *          null
9913		 *        ] } );
9914		 *    } );
9915		 */
9916		"bSortable": true,
9917	
9918	
9919		/**
9920		 * <code>Deprecated</code> When using fnRender() for a column, you may wish 
9921		 * to use the original data (before rendering) for sorting and filtering 
9922		 * (the default is to used the rendered data that the user can see). This 
9923		 * may be useful for dates etc.
9924		 * 
9925		 * Please note that this option has now been deprecated and will be removed
9926		 * in the next version of DataTables. Please use mRender / mData rather than
9927		 * fnRender.
9928		 *  @type boolean
9929		 *  @default true
9930		 *  @dtopt Columns
9931		 *  @deprecated
9932		 */
9933		"bUseRendered": true,
9934	
9935	
9936		/**
9937		 * Enable or disable the display of this column.
9938		 *  @type boolean
9939		 *  @default true
9940		 *  @dtopt Columns
9941		 * 
9942		 *  @example
9943		 *    // Using aoColumnDefs
9944		 *    $(document).ready( function() {
9945		 *      $('#example').dataTable( {
9946		 *        "aoColumnDefs": [ 
9947		 *          { "bVisible": false, "aTargets": [ 0 ] }
9948		 *        ] } );
9949		 *    } );
9950		 *    
9951		 *  @example
9952		 *    // Using aoColumns
9953		 *    $(document).ready( function() {
9954		 *      $('#example').dataTable( {
9955		 *        "aoColumns": [ 
9956		 *          { "bVisible": false },
9957		 *          null,
9958		 *          null,
9959		 *          null,
9960		 *          null
9961		 *        ] } );
9962		 *    } );
9963		 */
9964		"bVisible": true,
9965		
9966		
9967		/**
9968		 * Developer definable function that is called whenever a cell is created (Ajax source,
9969		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9970		 * allowing you to modify the DOM element (add background colour for example) when the
9971		 * element is available.
9972		 *  @type function
9973		 *  @param {element} nTd The TD node that has been created
9974		 *  @param {*} sData The Data for the cell
9975		 *  @param {array|object} oData The data for the whole row
9976		 *  @param {int} iRow The row index for the aoData data store
9977		 *  @param {int} iCol The column index for aoColumns
9978		 *  @dtopt Columns
9979		 * 
9980		 *  @example
9981		 *    $(document).ready( function() {
9982		 *      $('#example').dataTable( {
9983		 *        "aoColumnDefs": [ {
9984		 *          "aTargets": [3],
9985		 *          "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
9986		 *            if ( sData == "1.7" ) {
9987		 *              $(nTd).css('color', 'blue')
9988		 *            }
9989		 *          }
9990		 *        } ]
9991		 *      });
9992		 *    } );
9993		 */
9994		"fnCreatedCell": null,
9995	
9996	
9997		/**
9998		 * <code>Deprecated</code> Custom display function that will be called for the 
9999		 * display of each cell in this column.
10000		 *
10001		 * Please note that this option has now been deprecated and will be removed
10002		 * in the next version of DataTables. Please use mRender / mData rather than
10003		 * fnRender.
10004		 *  @type function
10005		 *  @param {object} o Object with the following parameters:
10006		 *  @param {int}    o.iDataRow The row in aoData
10007		 *  @param {int}    o.iDataColumn The column in question
10008		 *  @param {array}  o.aData The data for the row in question
10009		 *  @param {object} o.oSettings The settings object for this DataTables instance
10010		 *  @param {object} o.mDataProp The data property used for this column
10011		 *  @param {*}      val The current cell value
10012		 *  @returns {string} The string you which to use in the display
10013		 *  @dtopt Columns
10014		 *  @deprecated
10015		 */
10016		"fnRender": null,
10017	
10018	
10019		/**
10020		 * The column index (starting from 0!) that you wish a sort to be performed
10021		 * upon when this column is selected for sorting. This can be used for sorting
10022		 * on hidden columns for example.
10023		 *  @type int
10024		 *  @default -1 <i>Use automatically calculated column index</i>
10025		 *  @dtopt Columns
10026		 * 
10027		 *  @example
10028		 *    // Using aoColumnDefs
10029		 *    $(document).ready( function() {
10030		 *      $('#example').dataTable( {
10031		 *        "aoColumnDefs": [ 
10032		 *          { "iDataSort": 1, "aTargets": [ 0 ] }
10033		 *        ]
10034		 *      } );
10035		 *    } );
10036		 *    
10037		 *  @example
10038		 *    // Using aoColumns
10039		 *    $(document).ready( function() {
10040		 *      $('#example').dataTable( {
10041		 *        "aoColumns": [ 
10042		 *          { "iDataSort": 1 },
10043		 *          null,
10044		 *          null,
10045		 *          null,
10046		 *          null
10047		 *        ]
10048		 *      } );
10049		 *    } );
10050		 */
10051		"iDataSort": -1,
10052	
10053	
10054		/**
10055		 * This parameter has been replaced by mData in DataTables to ensure naming
10056		 * consistency. mDataProp can still be used, as there is backwards compatibility
10057		 * in DataTables for this option, but it is strongly recommended that you use
10058		 * mData in preference to mDataProp.
10059		 *  @name DataTable.defaults.columns.mDataProp
10060		 */
10061	
10062	
10063		/**
10064		 * This property can be used to read data from any JSON data source property,
10065		 * including deeply nested objects / properties. mData can be given in a
10066		 * number of different ways which effect its behaviour:
10067		 *   <ul>
10068		 *     <li>integer - treated as an array index for the data source. This is the
10069		 *       default that DataTables uses (incrementally increased for each column).</li>
10070		 *     <li>string - read an object property from the data source. Note that you can
10071		 *       use Javascript dotted notation to read deep properties / arrays from the
10072		 *       data source.</li>
10073		 *     <li>null - the sDefaultContent option will be used for the cell (null
10074		 *       by default, so you will need to specify the default content you want -
10075		 *       typically an empty string). This can be useful on generated columns such 
10076		 *       as edit / delete action columns.</li>
10077		 *     <li>function - the function given will be executed whenever DataTables 
10078		 *       needs to set or get the data for a cell in the column. The function 
10079		 *       takes three parameters:
10080		 *       <ul>
10081		 *         <li>{array|object} The data source for the row</li>
10082		 *         <li>{string} The type call data requested - this will be 'set' when
10083		 *           setting data or 'filter', 'display', 'type', 'sort' or undefined when 
10084		 *           gathering data. Note that when <i>undefined</i> is given for the type
10085		 *           DataTables expects to get the raw data for the object back</li>
10086		 *         <li>{*} Data to set when the second parameter is 'set'.</li>
10087		 *       </ul>
10088		 *       The return value from the function is not required when 'set' is the type
10089		 *       of call, but otherwise the return is what will be used for the data
10090		 *       requested.</li>
10091		 *    </ul>
10092		 *
10093		 * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change
10094		 * reflects the flexibility of this property and is consistent with the naming of
10095		 * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as
10096		 * it automatically maps the old name to the new if required.
10097		 *  @type string|int|function|null
10098		 *  @default null <i>Use automatically calculated column index</i>
10099		 *  @dtopt Columns
10100		 * 
10101		 *  @example
10102		 *    // Read table data from objects
10103		 *    $(document).ready( function() {
10104		 *      var oTable = $('#example').dataTable( {
10105		 *        "sAjaxSource": "sources/deep.txt",
10106		 *        "aoColumns": [
10107		 *          { "mData": "engine" },
10108		 *          { "mData": "browser" },
10109		 *          { "mData": "platform.inner" },
10110		 *          { "mData": "platform.details.0" },
10111		 *          { "mData": "platform.details.1" }
10112		 *        ]
10113		 *      } );
10114		 *    } );
10115		 * 
10116		 *  @example
10117		 *    // Using mData as a function to provide different information for
10118		 *    // sorting, filtering and display. In this case, currency (price)
10119		 *    $(document).ready( function() {
10120		 *      var oTable = $('#example').dataTable( {
10121		 *        "aoColumnDefs": [ {
10122		 *          "aTargets": [ 0 ],
10123		 *          "mData": function ( source, type, val ) {
10124		 *            if (type === 'set') {
10125		 *              source.price = val;
10126		 *              // Store the computed dislay and filter values for efficiency
10127		 *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
10128		 *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
10129		 *              return;
10130		 *            }
10131		 *            else if (type === 'display') {
10132		 *              return source.price_display;
10133		 *            }
10134		 *            else if (type === 'filter') {
10135		 *              return source.price_filter;
10136		 *            }
10137		 *            // 'sort', 'type' and undefined all just use the integer
10138		 *            return source.price;
10139		 *          }
10140		 *        } ]
10141		 *      } );
10142		 *    } );
10143		 */
10144		"mData": null,
10145	
10146	
10147		/**
10148		 * This property is the rendering partner to mData and it is suggested that
10149		 * when you want to manipulate data for display (including filtering, sorting etc)
10150		 * but not altering the underlying data for the table, use this property. mData
10151		 * can actually do everything this property can and more, but this parameter is
10152		 * easier to use since there is no 'set' option. Like mData is can be given
10153		 * in a number of different ways to effect its behaviour, with the addition of 
10154		 * supporting array syntax for easy outputting of arrays (including arrays of
10155		 * objects):
10156		 *   <ul>
10157		 *     <li>integer - treated as an array index for the data source. This is the
10158		 *       default that DataTables uses (incrementally increased for each column).</li>
10159		 *     <li>string - read an object property from the data source. Note that you can
10160		 *       use Javascript dotted notation to read deep properties / arrays from the
10161		 *       data source and also array brackets to indicate that the data reader should
10162		 *       loop over the data source array. When characters are given between the array
10163		 *       brackets, these characters are used to join the data source array together.
10164		 *       For example: "accounts[, ].name" would result in a comma separated list with
10165		 *       the 'name' value from the 'accounts' array of objects.</li>
10166		 *     <li>function - the function given will be executed whenever DataTables 
10167		 *       needs to set or get the data for a cell in the column. The function 
10168		 *       takes three parameters:
10169		 *       <ul>
10170		 *         <li>{array|object} The data source for the row (based on mData)</li>
10171		 *         <li>{string} The type call data requested - this will be 'filter', 'display', 
10172		 *           'type' or 'sort'.</li>
10173		 *         <li>{array|object} The full data source for the row (not based on mData)</li>
10174		 *       </ul>
10175		 *       The return value from the function is what will be used for the data
10176		 *       requested.</li>
10177		 *    </ul>
10178		 *  @type string|int|function|null
10179		 *  @default null <i>Use mData</i>
10180		 *  @dtopt Columns
10181		 * 
10182		 *  @example
10183		 *    // Create a comma separated list from an array of objects
10184		 *    $(document).ready( function() {
10185		 *      var oTable = $('#example').dataTable( {
10186		 *        "sAjaxSource": "sources/deep.txt",
10187		 *        "aoColumns": [
10188		 *          { "mData": "engine" },
10189		 *          { "mData": "browser" },
10190		 *          {
10191		 *            "mData": "platform",
10192		 *            "mRender": "[, ].name"
10193		 *          }
10194		 *        ]
10195		 *      } );
10196		 *    } );
10197		 * 
10198		 *  @example
10199		 *    // Use as a function to create a link from the data source
10200		 *    $(document).ready( function() {
10201		 *      var oTable = $('#example').dataTable( {
10202		 *        "aoColumnDefs": [
10203		 *        {
10204		 *          "aTargets": [ 0 ],
10205		 *          "mData": "download_link",
10206		 *          "mRender": function ( data, type, full ) {
10207		 *            return '<a href="'+data+'">Download</a>';
10208		 *          }
10209		 *        ]
10210		 *      } );
10211		 *    } );
10212		 */
10213		"mRender": null,
10214	
10215	
10216		/**
10217		 * Change the cell type created for the column - either TD cells or TH cells. This
10218		 * can be useful as TH cells have semantic meaning in the table body, allowing them
10219		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
10220		 *  @type string
10221		 *  @default td
10222		 *  @dtopt Columns
10223		 * 
10224		 *  @example
10225		 *    // Make the first column use TH cells
10226		 *    $(document).ready( function() {
10227		 *      var oTable = $('#example').dataTable( {
10228		 *        "aoColumnDefs": [ {
10229		 *          "aTargets": [ 0 ],
10230		 *          "sCellType": "th"
10231		 *        } ]
10232		 *      } );
10233		 *    } );
10234		 */
10235		"sCellType": "td",
10236	
10237	
10238		/**
10239		 * Class to give to each cell in this column.
10240		 *  @type string
10241		 *  @default <i>Empty string</i>
10242		 *  @dtopt Columns
10243		 * 
10244		 *  @example
10245		 *    // Using aoColumnDefs
10246		 *    $(document).ready( function() {
10247		 *      $('#example').dataTable( {
10248		 *        "aoColumnDefs": [ 
10249		 *          { "sClass": "my_class", "aTargets": [ 0 ] }
10250		 *        ]
10251		 *      } );
10252		 *    } );
10253		 *    
10254		 *  @example
10255		 *    // Using aoColumns
10256		 *    $(document).ready( function() {
10257		 *      $('#example').dataTable( {
10258		 *        "aoColumns": [ 
10259		 *          { "sClass": "my_class" },
10260		 *          null,
10261		 *          null,
10262		 *          null,
10263		 *          null
10264		 *        ]
10265		 *      } );
10266		 *    } );
10267		 */
10268		"sClass": "",
10269		
10270		/**
10271		 * When DataTables calculates the column widths to assign to each column,
10272		 * it finds the longest string in each column and then constructs a
10273		 * temporary table and reads the widths from that. The problem with this
10274		 * is that "mmm" is much wider then "iiii", but the latter is a longer 
10275		 * string - thus the calculation can go wrong (doing it properly and putting
10276		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
10277		 * a "work around" we provide this option. It will append its value to the
10278		 * text that is found to be the longest string for the column - i.e. padding.
10279		 * Generally you shouldn't need this, and it is not documented on the 
10280		 * general DataTables.net documentation
10281		 *  @type string
10282		 *  @default <i>Empty string<i>
10283		 *  @dtopt Columns
10284		 *    
10285		 *  @example
10286		 *    // Using aoColumns
10287		 *    $(document).ready( function() {
10288		 *      $('#example').dataTable( {
10289		 *        "aoColumns": [ 
10290		 *          null,
10291		 *          null,
10292		 *          null,
10293		 *          {
10294		 *            "sContentPadding": "mmm"
10295		 *          }
10296		 *        ]
10297		 *      } );
10298		 *    } );
10299		 */
10300		"sContentPadding": "",
10301	
10302	
10303		/**
10304		 * Allows a default value to be given for a column's data, and will be used
10305		 * whenever a null data source is encountered (this can be because mData
10306		 * is set to null, or because the data source itself is null).
10307		 *  @type string
10308		 *  @default null
10309		 *  @dtopt Columns
10310		 * 
10311		 *  @example
10312		 *    // Using aoColumnDefs
10313		 *    $(document).ready( function() {
10314		 *      $('#example').dataTable( {
10315		 *        "aoColumnDefs": [ 
10316		 *          {
10317		 *            "mData": null,
10318		 *            "sDefaultContent": "Edit",
10319		 *            "aTargets": [ -1 ]
10320		 *          }
10321		 *        ]
10322		 *      } );
10323		 *    } );
10324		 *    
10325		 *  @example
10326		 *    // Using aoColumns
10327		 *    $(document).ready( function() {
10328		 *      $('#example').dataTable( {
10329		 *        "aoColumns": [ 
10330		 *          null,
10331		 *          null,
10332		 *          null,
10333		 *          {
10334		 *            "mData": null,
10335		 *            "sDefaultContent": "Edit"
10336		 *          }
10337		 *        ]
10338		 *      } );
10339		 *    } );
10340		 */
10341		"sDefaultContent": null,
10342	
10343	
10344		/**
10345		 * This parameter is only used in DataTables' server-side processing. It can
10346		 * be exceptionally useful to know what columns are being displayed on the
10347		 * client side, and to map these to database fields. When defined, the names
10348		 * also allow DataTables to reorder information from the server if it comes
10349		 * back in an unexpected order (i.e. if you switch your columns around on the
10350		 * client-side, your server-side code does not also need updating).
10351		 *  @type string
10352		 *  @default <i>Empty string</i>
10353		 *  @dtopt Columns
10354		 * 
10355		 *  @example
10356		 *    // Using aoColumnDefs
10357		 *    $(document).ready( function() {
10358		 *      $('#example').dataTable( {
10359		 *        "aoColumnDefs": [ 
10360		 *          { "sName": "engine", "aTargets": [ 0 ] },
10361		 *          { "sName": "browser", "aTargets": [ 1 ] },
10362		 *          { "sName": "platform", "aTargets": [ 2 ] },
10363		 *          { "sName": "version", "aTargets": [ 3 ] },
10364		 *          { "sName": "grade", "aTargets": [ 4 ] }
10365		 *        ]
10366		 *      } );
10367		 *    } );
10368		 *    
10369		 *  @example
10370		 *    // Using aoColumns
10371		 *    $(document).ready( function() {
10372		 *      $('#example').dataTable( {
10373		 *        "aoColumns": [ 
10374		 *          { "sName": "engine" },
10375		 *          { "sName": "browser" },
10376		 *          { "sName": "platform" },
10377		 *          { "sName": "version" },
10378		 *          { "sName": "grade" }
10379		 *        ]
10380		 *      } );
10381		 *    } );
10382		 */
10383		"sName": "",
10384	
10385	
10386		/**
10387		 * Defines a data source type for the sorting which can be used to read
10388		 * real-time information from the table (updating the internally cached
10389		 * version) prior to sorting. This allows sorting to occur on user editable
10390		 * elements such as form inputs.
10391		 *  @type string
10392		 *  @default std
10393		 *  @dtopt Columns
10394		 * 
10395		 *  @example
10396		 *    // Using aoColumnDefs
10397		 *    $(document).ready( function() {
10398		 *      $('#example').dataTable( {
10399		 *        "aoColumnDefs": [
10400		 *          { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] },
10401		 *          { "sType": "numeric", "aTargets": [ 3 ] },
10402		 *          { "sSortDataType": "dom-select", "aTargets": [ 4 ] },
10403		 *          { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] }
10404		 *        ]
10405		 *      } );
10406		 *    } );
10407		 *    
10408		 *  @example
10409		 *    // Using aoColumns
10410		 *    $(document).ready( function() {
10411		 *      $('#example').dataTable( {
10412		 *        "aoColumns": [
10413		 *          null,
10414		 *          null,
10415		 *          { "sSortDataType": "dom-text" },
10416		 *          { "sSortDataType": "dom-text", "sType": "numeric" },
10417		 *          { "sSortDataType": "dom-select" },
10418		 *          { "sSortDataType": "dom-checkbox" }
10419		 *        ]
10420		 *      } );
10421		 *    } );
10422		 */
10423		"sSortDataType": "std",
10424	
10425	
10426		/**
10427		 * The title of this column.
10428		 *  @type string
10429		 *  @default null <i>Derived from the 'TH' value for this column in the 
10430		 *    original HTML table.</i>
10431		 *  @dtopt Columns
10432		 * 
10433		 *  @example
10434		 *    // Using aoColumnDefs
10435		 *    $(document).ready( function() {
10436		 *      $('#example').dataTable( {
10437		 *        "aoColumnDefs": [ 
10438		 *          { "sTitle": "My column title", "aTargets": [ 0 ] }
10439		 *        ]
10440		 *      } );
10441		 *    } );
10442		 *    
10443		 *  @example
10444		 *    // Using aoColumns
10445		 *    $(document).ready( function() {
10446		 *      $('#example').dataTable( {
10447		 *        "aoColumns": [ 
10448		 *          { "sTitle": "My column title" },
10449		 *          null,
10450		 *          null,
10451		 *          null,
10452		 *          null
10453		 *        ]
10454		 *      } );
10455		 *    } );
10456		 */
10457		"sTitle": null,
10458	
10459	
10460		/**
10461		 * The type allows you to specify how the data for this column will be sorted.
10462		 * Four types (string, numeric, date and html (which will strip HTML tags
10463		 * before sorting)) are currently available. Note that only date formats
10464		 * understood by Javascript's Date() object will be accepted as type date. For
10465		 * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric',
10466		 * 'date' or 'html' (by default). Further types can be adding through
10467		 * plug-ins.
10468		 *  @type string
10469		 *  @default null <i>Auto-detected from raw data</i>
10470		 *  @dtopt Columns
10471		 * 
10472		 *  @example
10473		 *    // Using aoColumnDefs
10474		 *    $(document).ready( function() {
10475		 *      $('#example').dataTable( {
10476		 *        "aoColumnDefs": [ 
10477		 *          { "sType": "html", "aTargets": [ 0 ] }
10478		 *        ]
10479		 *      } );
10480		 *    } );
10481		 *    
10482		 *  @example
10483		 *    // Using aoColumns
10484		 *    $(document).ready( function() {
10485		 *      $('#example').dataTable( {
10486		 *        "aoColumns": [ 
10487		 *          { "sType": "html" },
10488		 *          null,
10489		 *          null,
10490		 *          null,
10491		 *          null
10492		 *        ]
10493		 *      } );
10494		 *    } );
10495		 */
10496		"sType": null,
10497	
10498	
10499		/**
10500		 * Defining the width of the column, this parameter may take any CSS value
10501		 * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not
10502		 * been given a specific width through this interface ensuring that the table
10503		 * remains readable.
10504		 *  @type string
10505		 *  @default null <i>Automatic</i>
10506		 *  @dtopt Columns
10507		 * 
10508		 *  @example
10509		 *    // Using aoColumnDefs
10510		 *    $(document).ready( function() {
10511		 *      $('#example').dataTable( {
10512		 *        "aoColumnDefs": [ 
10513		 *          { "sWidth": "20%", "aTargets": [ 0 ] }
10514		 *        ]
10515		 *      } );
10516		 *    } );
10517		 *    
10518		 *  @example
10519		 *    // Using aoColumns
10520		 *    $(document).ready( function() {
10521		 *      $('#example').dataTable( {
10522		 *        "aoColumns": [ 
10523		 *          { "sWidth": "20%" },
10524		 *          null,
10525		 *          null,
10526		 *          null,
10527		 *          null
10528		 *        ]
10529		 *      } );
10530		 *    } );
10531		 */
10532		"sWidth": null
10533	};
10534	
10535	
10536	
10537	/**
10538	 * DataTables settings object - this holds all the information needed for a
10539	 * given table, including configuration, data and current application of the
10540	 * table options. DataTables does not have a single instance for each DataTable
10541	 * with the settings attached to that instance, but rather instances of the
10542	 * DataTable "class" are created on-the-fly as needed (typically by a 
10543	 * $().dataTable() call) and the settings object is then applied to that
10544	 * instance.
10545	 * 
10546	 * Note that this object is related to {@link DataTable.defaults} but this 
10547	 * one is the internal data store for DataTables's cache of columns. It should
10548	 * NOT be manipulated outside of DataTables. Any configuration should be done
10549	 * through the initialisation options.
10550	 *  @namespace
10551	 *  @todo Really should attach the settings object to individual instances so we
10552	 *    don't need to create new instances on each $().dataTable() call (if the
10553	 *    table already exists). It would also save passing oSettings around and
10554	 *    into every single function. However, this is a very significant 
10555	 *    architecture change for DataTables and will almost certainly break
10556	 *    backwards compatibility with older installations. This is something that
10557	 *    will be done in 2.0.
10558	 */
10559	DataTable.models.oSettings = {
10560		/**
10561		 * Primary features of DataTables and their enablement state.
10562		 *  @namespace
10563		 */
10564		"oFeatures": {
10565			
10566			/**
10567			 * Flag to say if DataTables should automatically try to calculate the
10568			 * optimum table and columns widths (true) or not (false).
10569			 * Note that this parameter will be set by the initialisation routine. To
10570			 * set a default use {@link DataTable.defaults}.
10571			 *  @type boolean
10572			 */
10573			"bAutoWidth": null,
10574	
10575			/**
10576			 * Delay the creation of TR and TD elements until they are actually
10577			 * needed by a driven page draw. This can give a significant speed
10578			 * increase for Ajax source and Javascript source data, but makes no
10579			 * difference at all fro DOM and server-side processing tables.
10580			 * Note that this parameter will be set by the initialisation routine. To
10581			 * set a default use {@link DataTable.defaults}.
10582			 *  @type boolean
10583			 */
10584			"bDeferRender": null,
10585			
10586			/**
10587			 * Enable filtering on the table or not. Note that if this is disabled
10588			 * then there is no filtering at all on the table, including fnFilter.
10589			 * To just remove the filtering input use sDom and remove the 'f' option.
10590			 * Note that this parameter will be set by the initialisation routine. To
10591			 * set a default use {@link DataTable.defaults}.
10592			 *  @type boolean
10593			 */
10594			"bFilter": null,
10595			
10596			/**
10597			 * Table information element (the 'Showing x of y records' div) enable
10598			 * flag.
10599			 * Note that this parameter will be set by the initialisation routine. To
10600			 * set a default use {@link DataTable.defaults}.
10601			 *  @type boolean
10602			 */
10603			"bInfo": null,
10604			
10605			/**
10606			 * Present a user control allowing the end user to change the page size
10607			 * when pagination is enabled.
10608			 * Note that this parameter will be set by the initialisation routine. To
10609			 * set a default use {@link DataTable.defaults}.
10610			 *  @type boolean
10611			 */
10612			"bLengthChange": null,
10613	
10614			/**
10615			 * Pagination enabled or not. Note that if this is disabled then length
10616			 * changing must also be disabled.
10617			 * Note that this parameter will be set by the initialisation routine. To
10618			 * set a default use {@link DataTable.defaults}.
10619			 *  @type boolean
10620			 */
10621			"bPaginate": null,
10622			
10623			/**
10624			 * Processing indicator enable flag whenever DataTables is enacting a
10625			 * user request - typically an Ajax request for server-side processing.
10626			 * Note that this parameter will be set by the initialisation routine. To
10627			 * set a default use {@link DataTable.defaults}.
10628			 *  @type boolean
10629			 */
10630			"bProcessing": null,
10631			
10632			/**
10633			 * Server-side processing enabled flag - when enabled DataTables will
10634			 * get all data from the server for every draw - there is no filtering,
10635			 * sorting or paging done on the client-side.
10636			 * Note that this parameter will be set by the initialisation routine. To
10637			 * set a default use {@link DataTable.defaults}.
10638			 *  @type boolean
10639			 */
10640			"bServerSide": null,
10641			
10642			/**
10643			 * Sorting enablement flag.
10644			 * Note that this parameter will be set by the initialisation routine. To
10645			 * set a default use {@link DataTable.defaults}.
10646			 *  @type boolean
10647			 */
10648			"bSort": null,
10649			
10650			/**
10651			 * Apply a class to the columns which are being sorted to provide a
10652			 * visual highlight or not. This can slow things down when enabled since
10653			 * there is a lot of DOM interaction.
10654			 * Note that this parameter will be set by the initialisation routine. To
10655			 * set a default use {@link DataTable.defaults}.
10656			 *  @type boolean
10657			 */
10658			"bSortClasses": null,
10659			
10660			/**
10661			 * State saving enablement flag.
10662			 * Note that this parameter will be set by the initialisation routine. To
10663			 * set a default use {@link DataTable.defaults}.
10664			 *  @type boolean
10665			 */
10666			"bStateSave": null
10667		},
10668		
10669	
10670		/**
10671		 * Scrolling settings for a table.
10672		 *  @namespace
10673		 */
10674		"oScroll": {
10675			/**
10676			 * Indicate if DataTables should be allowed to set the padding / margin
10677			 * etc for the scrolling header elements or not. Typically you will want
10678			 * this.
10679			 * Note that this parameter will be set by the initialisation routine. To
10680			 * set a default use {@link DataTable.defaults}.
10681			 *  @type boolean
10682			 */
10683			"bAutoCss": null,
10684			
10685			/**
10686			 * When the table is shorter in height than sScrollY, collapse the
10687			 * table container down to the height of the table (when true).
10688			 * Note that this parameter will be set by the initialisation routine. To
10689			 * set a default use {@link DataTable.defaults}.
10690			 *  @type boolean
10691			 */
10692			"bCollapse": null,
10693			
10694			/**
10695			 * Infinite scrolling enablement flag. Now deprecated in favour of
10696			 * using the Scroller plug-in.
10697			 * Note that this parameter will be set by the initialisation routine. To
10698			 * set a default use {@link DataTable.defaults}.
10699			 *  @type boolean
10700			 */
10701			"bInfinite": null,
10702			
10703			/**
10704			 * Width of the scrollbar for the web-browser's platform. Calculated
10705			 * during table initialisation.
10706			 *  @type int
10707			 *  @default 0
10708			 */
10709			"iBarWidth": 0,
10710			
10711			/**
10712			 * Space (in pixels) between the bottom of the scrolling container and 
10713			 * the bottom of the scrolling viewport before the next page is loaded
10714			 * when using infinite scrolling.
10715			 * Note that this parameter will be set by the initialisation routine. To
10716			 * set a default use {@link DataTable.defaults}.
10717			 *  @type int
10718			 */
10719			"iLoadGap": null,
10720			
10721			/**
10722			 * Viewport width for horizontal scrolling. Horizontal scrolling is 
10723			 * disabled if an empty string.
10724			 * Note that this parameter will be set by the initialisation routine. To
10725			 * set a default use {@link DataTable.defaults}.
10726			 *  @type string
10727			 */
10728			"sX": null,
10729			
10730			/**
10731			 * Width to expand the table to when using x-scrolling. Typically you
10732			 * should not need to use this.
10733			 * Note that this parameter will be set by the initialisation routine. To
10734			 * set a default use {@link DataTable.defaults}.
10735			 *  @type string
10736			 *  @deprecated
10737			 */
10738			"sXInner": null,
10739			
10740			/**
10741			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
10742			 * if an empty string.
10743			 * Note that this parameter will be set by the initialisation routine. To
10744			 * set a default use {@link DataTable.defaults}.
10745			 *  @type string
10746			 */
10747			"sY": null
10748		},
10749		
10750		/**
10751		 * Language information for the table.
10752		 *  @namespace
10753		 *  @extends DataTable.defaults.oLanguage
10754		 */
10755		"oLanguage": {
10756			/**
10757			 * Information callback function. See 
10758			 * {@link DataTable.defaults.fnInfoCallback}
10759			 *  @type function
10760			 *  @default null
10761			 */
10762			"fnInfoCallback": null
10763		},
10764		
10765		/**
10766		 * Browser support parameters
10767		 *  @namespace
10768		 */
10769		"oBrowser": {
10770			/**
10771			 * Indicate if the browser incorrectly calculates width:100% inside a
10772			 * scrolling element (IE6/7)
10773			 *  @type boolean
10774			 *  @default false
10775			 */
10776			"bScrollOversize": false
10777		},
10778		
10779		/**
10780		 * Array referencing the nodes which are used for the features. The 
10781		 * parameters of this object match what is allowed by sDom - i.e.
10782		 *   <ul>
10783		 *     <li>'l' - Length changing</li>
10784		 *     <li>'f' - Filtering input</li>
10785		 *     <li>'t' - The table!</li>
10786		 *     <li>'i' - Information</li>
10787		 *     <li>'p' - Pagination</li>
10788		 *     <li>'r' - pRocessing</li>
10789		 *   </ul>
10790		 *  @type array
10791		 *  @default []
10792		 */
10793		"aanFeatures": [],
10794		
10795		/**
10796		 * Store data information - see {@link DataTable.models.oRow} for detailed
10797		 * information.
10798		 *  @type array
10799		 *  @default []
10800		 */
10801		"aoData": [],
10802		
10803		/**
10804		 * Array of indexes which are in the current display (after filtering etc)
10805		 *  @type array
10806		 *  @default []
10807		 */
10808		"aiDisplay": [],
10809		
10810		/**
10811		 * Array of indexes for display - no filtering
10812		 *  @type array
10813		 *  @default []
10814		 */
10815		"aiDisplayMaster": [],
10816		
10817		/**
10818		 * Store information about each column that is in use
10819		 *  @type array
10820		 *  @default []
10821		 */
10822		"aoColumns": [],
10823		
10824		/**
10825		 * Store information about the table's header
10826		 *  @type array
10827		 *  @default []
10828		 */
10829		"aoHeader": [],
10830		
10831		/**
10832		 * Store information about the table's footer
10833		 *  @type array
10834		 *  @default []
10835		 */
10836		"aoFooter": [],
10837		
10838		/**
10839		 * Search data array for regular expression searching
10840		 *  @type array
10841		 *  @default []
10842		 */
10843		"asDataSearch": [],
10844		
10845		/**
10846		 * Store the applied global search information in case we want to force a 
10847		 * research or compare the old search to a new one.
10848		 * Note that this parameter will be set by the initialisation routine. To
10849		 * set a default use {@link DataTable.defaults}.
10850		 *  @namespace
10851		 *  @extends DataTable.models.oSearch
10852		 */
10853		"oPreviousSearch": {},
10854		
10855		/**
10856		 * Store the applied search for each column - see 
10857		 * {@link DataTable.models.oSearch} for the format that is used for the
10858		 * filtering information for each column.
10859		 *  @type array
10860		 *  @default []
10861		 */
10862		"aoPreSearchCols": [],
10863		
10864		/**
10865		 * Sorting that is applied to the table. Note that the inner arrays are
10866		 * used in the following manner:
10867		 * <ul>
10868		 *   <li>Index 0 - column number</li>
10869		 *   <li>Index 1 - current sorting direction</li>
10870		 *   <li>Index 2 - index of asSorting for this column</li>
10871		 * </ul>
10872		 * Note that this parameter will be set by the initialisation routine. To
10873		 * set a default use {@link DataTable.defaults}.
10874		 *  @type array
10875		 *  @todo These inner arrays should really be objects
10876		 */
10877		"aaSorting": null,
10878		
10879		/**
10880		 * Sorting that is always applied to the table (i.e. prefixed in front of
10881		 * aaSorting).
10882		 * Note that this parameter will be set by the initialisation routine. To
10883		 * set a default use {@link DataTable.defaults}.
10884		 *  @type array|null
10885		 *  @default null
10886		 */
10887		"aaSortingFixed": null,
10888		
10889		/**
10890		 * Classes to use for the striping of a table.
10891		 * Note that this parameter will be set by the initialisation routine. To
10892		 * set a default use {@link DataTable.defaults}.
10893		 *  @type array
10894		 *  @default []
10895		 */
10896		"asStripeClasses": null,
10897		
10898		/**
10899		 * If restoring a table - we should restore its striping classes as well
10900		 *  @type array
10901		 *  @default []
10902		 */
10903		"asDestroyStripes": [],
10904		
10905		/**
10906		 * If restoring a table - we should restore its width 
10907		 *  @type int
10908		 *  @default 0
10909		 */
10910		"sDestroyWidth": 0,
10911		
10912		/**
10913		 * Callback functions array for every time a row is inserted (i.e. on a draw).
10914		 *  @type array
10915		 *  @default []
10916		 */
10917		"aoRowCallback": [],
10918		
10919		/**
10920		 * Callback functions for the header on each draw.
10921		 *  @type array
10922		 *  @default []
10923		 */
10924		"aoHeaderCallback": [],
10925		
10926		/**
10927		 * Callback function for the footer on each draw.
10928		 *  @type array
10929		 *  @default []
10930		 */
10931		"aoFooterCallback": [],
10932		
10933		/**
10934		 * Array of callback functions for draw callback functions
10935		 *  @type array
10936		 *  @default []
10937		 */
10938		"aoDrawCallback": [],
10939		
10940		/**
10941		 * Array of callback functions for row created function
10942		 *  @type array
10943		 *  @default []
10944		 */
10945		"aoRowCreatedCallback": [],
10946		
10947		/**
10948		 * Callback functions for just before the table is redrawn. A return of 
10949		 * false will be used to cancel the draw.
10950		 *  @type array
10951		 *  @default []
10952		 */
10953		"aoPreDrawCallback": [],
10954		
10955		/**
10956		 * Callback functions for when the table has been initialised.
10957		 *  @type array
10958		 *  @default []
10959		 */
10960		"aoInitComplete": [],
10961	
10962		
10963		/**
10964		 * Callbacks for modifying the settings to be stored for state saving, prior to
10965		 * saving state.
10966		 *  @type array
10967		 *  @default []
10968		 */
10969		"aoStateSaveParams": [],
10970		
10971		/**
10972		 * Callbacks for modifying the settings that have been stored for state saving
10973		 * prior to using the stored values to restore the state.
10974		 *  @type array
10975		 *  @default []
10976		 */
10977		"aoStateLoadParams": [],
10978		
10979		/**
10980		 * Callbacks for operating on the settings object once the saved state has been
10981		 * loaded
10982		 *  @type array
10983		 *  @default []
10984		 */
10985		"aoStateLoaded": [],
10986		
10987		/**
10988		 * Cache the table ID for quick access
10989		 *  @type string
10990		 *  @default <i>Empty string</i>
10991		 */
10992		"sTableId": "",
10993		
10994		/**
10995		 * The TABLE node for the main table
10996		 *  @type node
10997		 *  @default null
10998		 */
10999		"nTable": null,
11000		
11001		/**
11002		 * Permanent ref to the thead element
11003		 *  @type node
11004		 *  @default null
11005		 */
11006		"nTHead": null,
11007		
11008		/**
11009		 * Permanent ref to the tfoot element - if it exists
11010		 *  @type node
11011		 *  @default null
11012		 */
11013		"nTFoot": null,
11014		
11015		/**
11016		 * Permanent ref to the tbody element
11017		 *  @type node
11018		 *  @default null
11019		 */
11020		"nTBody": null,
11021		
11022		/**
11023		 * Cache the wrapper node (contains all DataTables controlled elements)
11024		 *  @type node
11025		 *  @default null
11026		 */
11027		"nTableWrapper": null,
11028		
11029		/**
11030		 * Indicate if when using server-side processing the loading of data 
11031		 * should be deferred until the second draw.
11032		 * Note that this parameter will be set by the initialisation routine. To
11033		 * set a default use {@link DataTable.defaults}.
11034		 *  @type boolean
11035		 *  @default false
11036		 */
11037		"bDeferLoading": false,
11038		
11039		/**
11040		 * Indicate if all required information has been read in
11041		 *  @type boolean
11042		 *  @default false
11043		 */
11044		"bInitialised": false,
11045		
11046		/**
11047		 * Information about open rows. Each object in the array has the parameters
11048		 * 'nTr' and 'nParent'
11049		 *  @type array
11050		 *  @default []
11051		 */
11052		"aoOpenRows": [],
11053		
11054		/**
11055		 * Dictate the positioning of DataTables' control elements - see
11056		 * {@link DataTable.model.oInit.sDom}.
11057		 * Note that this parameter will be set by the initialisation routine. To
11058		 * set a default use {@link DataTable.defaults}.
11059		 *  @type string
11060		 *  @default null
11061		 */
11062		"sDom": null,
11063		
11064		/**
11065		 * Which type of pagination should be used.
11066		 * Note that this parameter will be set by the initialisation routine. To
11067		 * set a default use {@link DataTable.defaults}.
11068		 *  @type string 
11069		 *  @default two_button
11070		 */
11071		"sPaginationType": "two_button",
11072		
11073		/**
11074		 * The cookie duration (for bStateSave) in seconds.
11075		 * Note that this parameter will be set by the initialisation routine. To
11076		 * set a default use {@link DataTable.defaults}.
11077		 *  @type int
11078		 *  @default 0
11079		 */
11080		"iCookieDuration": 0,
11081		
11082		/**
11083		 * The cookie name prefix.
11084		 * Note that this parameter will be set by the initialisation routine. To
11085		 * set a default use {@link DataTable.defaults}.
11086		 *  @type string
11087		 *  @default <i>Empty string</i>
11088		 */
11089		"sCookiePrefix": "",
11090		
11091		/**
11092		 * Callback function for cookie creation.
11093		 * Note that this parameter will be set by the initialisation routine. To
11094		 * set a default use {@link DataTable.defaults}.
11095		 *  @type function
11096		 *  @default null
11097		 */
11098		"fnCookieCallback": null,
11099		
11100		/**
11101		 * Array of callback functions for state saving. Each array element is an 
11102		 * object with the following parameters:
11103		 *   <ul>
11104		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11105		 *       and the JSON string to save that has been thus far created. Returns
11106		 *       a JSON string to be inserted into a json object 
11107		 *       (i.e. '"param": [ 0, 1, 2]')</li>
11108		 *     <li>string:sName - name of callback</li>
11109		 *   </ul>
11110		 *  @type array
11111		 *  @default []
11112		 */
11113		"aoStateSave": [],
11114		
11115		/**
11116		 * Array of callback functions for state loading. Each array element is an 
11117		 * object with the following parameters:
11118		 *   <ul>
11119		 *     <li>function:fn - function to call. Takes two parameters, oSettings 
11120		 *       and the object stored. May return false to cancel state loading</li>
11121		 *     <li>string:sName - name of callback</li>
11122		 *   </ul>
11123		 *  @type array
11124		 *  @default []
11125		 */
11126		"aoStateLoad": [],
11127		
11128		/**
11129		 * State that was loaded from the cookie. Useful for back reference
11130		 *  @type object
11131		 *  @default null
11132		 */
11133		"oLoadedState": null,
11134		
11135		/**
11136		 * Source url for AJAX data for the table.
11137		 * Note that this parameter will be set by the initialisation routine. To
11138		 * set a default use {@link DataTable.defaults}.
11139		 *  @type string
11140		 *  @default null
11141		 */
11142		"sAjaxSource": null,
11143		
11144		/**
11145		 * Property from a given object from which to read the table data from. This
11146		 * can be an empty string (when not server-side processing), in which case 
11147		 * it is  assumed an an array is given directly.
11148		 * Note that this parameter will be set by the initialisation routine. To
11149		 * set a default use {@link DataTable.defaults}.
11150		 *  @type string
11151		 */
11152		"sAjaxDataProp": null,
11153		
11154		/**
11155		 * Note if draw should be blocked while getting data
11156		 *  @type boolean
11157		 *  @default true
11158		 */
11159		"bAjaxDataGet": true,
11160		
11161		/**
11162		 * The last jQuery XHR object that was used for server-side data gathering. 
11163		 * This can be used for working with the XHR information in one of the 
11164		 * callbacks
11165		 *  @type object
11166		 *  @default null
11167		 */
11168		"jqXHR": null,
11169		
11170		/**
11171		 * Function to get the server-side data.
11172		 * Note that this parameter will be set by the initialisation routine. To
11173		 * set a default use {@link DataTable.defaults}.
11174		 *  @type function
11175		 */
11176		"fnServerData": null,
11177		
11178		/**
11179		 * Functions which are called prior to sending an Ajax request so extra 
11180		 * parameters can easily be sent to the server
11181		 *  @type array
11182		 *  @default []
11183		 */
11184		"aoServerParams": [],
11185		
11186		/**
11187		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 
11188		 * required).
11189		 * Note that this parameter will be set by the initialisation routine. To
11190		 * set a default use {@link DataTable.defaults}.
11191		 *  @type string
11192		 */
11193		"sServerMethod": null,
11194		
11195		/**
11196		 * Format numbers for display.
11197		 * Note that this parameter will be set by the initialisation routine. To
11198		 * set a default use {@link DataTable.defaults}.
11199		 *  @type function
11200		 */
11201		"fnFormatNumber": null,
11202		
11203		/**
11204		 * List of options that can be used for the user selectable length menu.
11205		 * Note that this parameter will be set by the initialisation routine. To
11206		 * set a default use {@link DataTable.defaults}.
11207		 *  @type array
11208		 *  @default []
11209		 */
11210		"aLengthMenu": null,
11211		
11212		/**
11213		 * Counter for the draws that the table does. Also used as a tracker for
11214		 * server-side processing
11215		 *  @type int
11216		 *  @default 0
11217		 */
11218		"iDraw": 0,
11219		
11220		/**
11221		 * Indicate if a redraw is being done - useful for Ajax
11222		 *  @type boolean
11223		 *  @default false
11224		 */
11225		"bDrawing": false,
11226		
11227		/**
11228		 * Draw index (iDraw) of the last error when parsing the returned data
11229		 *  @type int
11230		 *  @default -1
11231		 */
11232		"iDrawError": -1,
11233		
11234		/**
11235		 * Paging display length
11236		 *  @type int
11237		 *  @default 10
11238		 */
11239		"_iDisplayLength": 10,
11240	
11241		/**
11242		 * Paging start point - aiDisplay index
11243		 *  @type int
11244		 *  @default 0
11245		 */
11246		"_iDisplayStart": 0,
11247	
11248		/**
11249		 * Paging end point - aiDisplay index. Use fnDisplayEnd rather than
11250		 * this property to get the end point
11251		 *  @type int
11252		 *  @default 10
11253		 *  @private
11254		 */
11255		"_iDisplayEnd": 10,
11256		
11257		/**
11258		 * Server-side processing - number of records in the result set
11259		 * (i.e. before filtering), Use fnRecordsTotal rather than
11260		 * this property to get the value of the number of records, regardless of
11261		 * the server-side processing setting.
11262		 *  @type int
11263		 *  @default 0
11264		 *  @private
11265		 */
11266		"_iRecordsTotal": 0,
11267	
11268		/**
11269		 * Server-side processing - number of records in the current display set
11270		 * (i.e. after filtering). Use fnRecordsDisplay rather than
11271		 * this property to get the value of the number of records, regardless of
11272		 * the server-side processing setting.
11273		 *  @type boolean
11274		 *  @default 0
11275		 *  @private
11276		 */
11277		"_iRecordsDisplay": 0,
11278		
11279		/**
11280		 * Flag to indicate if jQuery UI marking and classes should be used.
11281		 * Note that this parameter will be set by the initialisation routine. To
11282		 * set a default use {@link DataTable.defaults}.
11283		 *  @type boolean
11284		 */
11285		"bJUI": null,
11286		
11287		/**
11288		 * The classes to use for the table
11289		 *  @type object
11290		 *  @default {}
11291		 */
11292		"oClasses": {},
11293		
11294		/**
11295		 * Flag attached to the settings object so you can check in the draw 
11296		 * callback if filtering has been done in the draw. Deprecated in favour of
11297		 * events.
11298		 *  @type boolean
11299		 *  @default false
11300		 *  @deprecated
11301		 */
11302		"bFiltered": false,
11303		
11304		/**
11305		 * Flag attached to the settings object so you can check in the draw 
11306		 * callback if sorting has been done in the draw. Deprecated in favour of
11307		 * events.
11308		 *  @type boolean
11309		 *  @default false
11310		 *  @deprecated
11311		 */
11312		"bSorted": false,
11313		
11314		/**
11315		 * Indicate that if multiple rows are in the header and there is more than 
11316		 * one unique cell per column, if the top one (true) or bottom one (false) 
11317		 * should be used for sorting / title by DataTables.
11318		 * Note that this parameter will be set by the initialisation routine. To
11319		 * set a default use {@link DataTable.defaults}.
11320		 *  @type boolean
11321		 */
11322		"bSortCellsTop": null,
11323		
11324		/**
11325		 * Initialisation object that is used for the table
11326		 *  @type object
11327		 *  @default null
11328		 */
11329		"oInit": null,
11330		
11331		/**
11332		 * Destroy callback functions - for plug-ins to attach themselves to the
11333		 * destroy so they can clean up markup and events.
11334		 *  @type array
11335		 *  @default []
11336		 */
11337		"aoDestroyCallback": [],
11338	
11339		
11340		/**
11341		 * Get the number of records in the current record set, before filtering
11342		 *  @type function
11343		 */
11344		"fnRecordsTotal": function ()
11345		{
11346			if ( this.oFeatures.bServerSide ) {
11347				return parseInt(this._iRecordsTotal, 10);
11348			} else {
11349				return this.aiDisplayMaster.length;
11350			}
11351		},
11352		
11353		/**
11354		 * Get the number of records in the current record set, after filtering
11355		 *  @type function
11356		 */
11357		"fnRecordsDisplay": function ()
11358		{
11359			if ( this.oFeatures.bServerSide ) {
11360				return parseInt(this._iRecordsDisplay, 10);
11361			} else {
11362				return this.aiDisplay.length;
11363			}
11364		},
11365		
11366		/**
11367		 * Set the display end point - aiDisplay index
11368		 *  @type function
11369		 *  @todo Should do away with _iDisplayEnd and calculate it on-the-fly here
11370		 */
11371		"fnDisplayEnd": function ()
11372		{
11373			if ( this.oFeatures.bServerSide ) {
11374				if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
11375					return this._iDisplayStart+this.aiDisplay.length;
11376				} else {
11377					return Math.min( this._iDisplayStart+this._iDisplayLength, 
11378						this._iRecordsDisplay );
11379				}
11380			} else {
11381				return this._iDisplayEnd;
11382			}
11383		},
11384		
11385		/**
11386		 * The DataTables object for this table
11387		 *  @type object
11388		 *  @default null
11389		 */
11390		"oInstance": null,
11391		
11392		/**
11393		 * Unique identifier for each instance of the DataTables object. If there
11394		 * is an ID on the table node, then it takes that value, otherwise an
11395		 * incrementing internal counter is used.
11396		 *  @type string
11397		 *  @default null
11398		 */
11399		"sInstance": null,
11400	
11401		/**
11402		 * tabindex attribute value that is added to DataTables control elements, allowing
11403		 * keyboard navigation of the table and its controls.
11404		 */
11405		"iTabIndex": 0,
11406	
11407		/**
11408		 * DIV container for the footer scrolling table if scrolling
11409		 */
11410		"nScrollHead": null,
11411	
11412		/**
11413		 * DIV container for the footer scrolling table if scrolling
11414		 */
11415		"nScrollFoot": null
11416	};
11417
11418	/**
11419	 * Extension object for DataTables that is used to provide all extension options.
11420	 * 
11421	 * Note that the <i>DataTable.ext</i> object is available through
11422	 * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is
11423	 * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons.
11424	 *  @namespace
11425	 *  @extends DataTable.models.ext
11426	 */
11427	DataTable.ext = $.extend( true, {}, DataTable.models.ext );
11428	
11429	$.extend( DataTable.ext.oStdClasses, {
11430		"sTable": "dataTable",
11431	
11432		/* Two buttons buttons */
11433		"sPagePrevEnabled": "paginate_enabled_previous",
11434		"sPagePrevDisabled": "paginate_disabled_previous",
11435		"sPageNextEnabled": "paginate_enabled_next",
11436		"sPageNextDisabled": "paginate_disabled_next",
11437		"sPageJUINext": "",
11438		"sPageJUIPrev": "",
11439		
11440		/* Full numbers paging buttons */
11441		"sPageButton": "paginate_button",
11442		"sPageButtonActive": "paginate_active",
11443		"sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
11444		"sPageFirst": "first",
11445		"sPagePrevious": "previous",
11446		"sPageNext": "next",
11447		"sPageLast": "last",
11448		
11449		/* Striping classes */
11450		"sStripeOdd": "odd",
11451		"sStripeEven": "even",
11452		
11453		/* Empty row */
11454		"sRowEmpty": "dataTables_empty",
11455		
11456		/* Features */
11457		"sWrapper": "dataTables_wrapper",
11458		"sFilter": "dataTables_filter",
11459		"sInfo": "dataTables_info",
11460		"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
11461		"sLength": "dataTables_length",
11462		"sProcessing": "dataTables_processing",
11463		
11464		/* Sorting */
11465		"sSortAsc": "sorting_asc",
11466		"sSortDesc": "sorting_desc",
11467		"sSortable": "sorting", /* Sortable in both directions */
11468		"sSortableAsc": "sorting_asc_disabled",
11469		"sSortableDesc": "sorting_desc_disabled",
11470		"sSortableNone": "sorting_disabled",
11471		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
11472		"sSortJUIAsc": "",
11473		"sSortJUIDesc": "",
11474		"sSortJUI": "",
11475		"sSortJUIAscAllowed": "",
11476		"sSortJUIDescAllowed": "",
11477		"sSortJUIWrapper": "",
11478		"sSortIcon": "",
11479		
11480		/* Scrolling */
11481		"sScrollWrapper": "dataTables_scroll",
11482		"sScrollHead": "dataTables_scrollHead",
11483		"sScrollHeadInner": "dataTables_scrollHeadInner",
11484		"sScrollBody": "dataTables_scrollBody",
11485		"sScrollFoot": "dataTables_scrollFoot",
11486		"sScrollFootInner": "dataTables_scrollFootInner",
11487		
11488		/* Misc */
11489		"sFooterTH": "",
11490		"sJUIHeader": "",
11491		"sJUIFooter": ""
11492	} );
11493	
11494	
11495	$.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, {
11496		/* Two buttons buttons */
11497		"sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
11498		"sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
11499		"sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
11500		"sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
11501		"sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
11502		"sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
11503		
11504		/* Full numbers paging buttons */
11505		"sPageButton": "fg-button ui-button ui-state-default",
11506		"sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
11507		"sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
11508		"sPageFirst": "first ui-corner-tl ui-corner-bl",
11509		"sPageLast": "last ui-corner-tr ui-corner-br",
11510		
11511		/* Features */
11512		"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
11513			"ui-buttonset-multi paging_", /* Note that the type is postfixed */
11514		
11515		/* Sorting */
11516		"sSortAsc": "ui-state-default",
11517		"sSortDesc": "ui-state-default",
11518		"sSortable": "ui-state-default",
11519		"sSortableAsc": "ui-state-default",
11520		"sSortableDesc": "ui-state-default",
11521		"sSortableNone": "ui-state-default",
11522		"sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
11523		"sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
11524		"sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
11525		"sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
11526		"sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
11527		"sSortJUIWrapper": "DataTables_sort_wrapper",
11528		"sSortIcon": "DataTables_sort_icon",
11529		
11530		/* Scrolling */
11531		"sScrollHead": "dataTables_scrollHead ui-state-default",
11532		"sScrollFoot": "dataTables_scrollFoot ui-state-default",
11533		
11534		/* Misc */
11535		"sFooterTH": "ui-state-default",
11536		"sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",
11537		"sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"
11538	} );
11539	
11540	/*
11541	 * Variable: oPagination
11542	 * Purpose:  
11543	 * Scope:    jQuery.fn.dataTableExt
11544	 */
11545	$.extend( DataTable.ext.oPagination, {
11546		/*
11547		 * Variable: two_button
11548		 * Purpose:  Standard two button (forward/back) pagination
11549		 * Scope:    jQuery.fn.dataTableExt.oPagination
11550		 */
11551		"two_button": {
11552			/*
11553			 * Function: oPagination.two_button.fnInit
11554			 * Purpose:  Initialise dom elements required for pagination with forward/back buttons only
11555			 * Returns:  -
11556			 * Inputs:   object:oSettings - dataTables settings object
11557			 *           node:nPaging - the DIV which contains this pagination control
11558			 *           function:fnCallbackDraw - draw function which must be called on update
11559			 */
11560			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
11561			{
11562				var oLang = oSettings.oLanguage.oPaginate;
11563				var oClasses = oSettings.oClasses;
11564				var fnClickHandler = function ( e ) {
11565					if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
11566					{
11567						fnCallbackDraw( oSettings );
11568					}
11569				};
11570	
11571				var sAppend = (!oSettings.bJUI) ?
11572					'<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+
11573					'<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>'
11574					:
11575					'<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+
11576					'<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>';
11577				$(nPaging).append( sAppend );
11578				
11579				var els = $('a', nPaging);
11580				var nPrevious = els[0],
11581					nNext = els[1];
11582				
11583				oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );
11584				oSettings.oApi._fnBindAction( nNext,     {action: "next"},     fnClickHandler );
11585				
11586				/* ID the first elements only */
11587				if ( !oSettings.aanFeatures.p )
11588				{
11589					nPaging.id = oSettings.sTableId+'_paginate';
11590					nPrevious.id = oSettings.sTableId+'_previous';
11591					nNext.id = oSettings.sTableId+'_next';
11592	
11593					nPrevious.setAttribute('aria-controls', oSettings.sTableId);
11594					nNext.setAttribute('aria-controls', oSettings.sTableId);
11595				}
11596			},
11597			
11598			/*
11599			 * Function: oPagination.two_button.fnUpdate
11600			 * Purpose:  Update the two button pagination at the end of the draw
11601			 * Returns:  -
11602			 * Inputs:   object:oSettings - dataTables settings object
11603			 *           function:fnCallbackDraw - draw function to call on page change
11604			 */
11605			"fnUpdate": function ( oSettings, fnCallbackDraw )
11606			{
11607				if ( !oSettings.aanFeatures.p )
11608				{
11609					return;
11610				}
11611				
11612				var oClasses = oSettings.oClasses;
11613				var an = oSettings.aanFeatures.p;
11614				var nNode;
11615	
11616				/* Loop over each instance of the pager */
11617				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
11618				{
11619					nNode = an[i].firstChild;
11620					if ( nNode )
11621					{
11622						/* Previous page */
11623						nNode.className = ( oSettings._iDisplayStart === 0 ) ?
11624						    oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;
11625						    
11626						/* Next page */
11627						nNode = nNode.nextSibling;
11628						nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
11629						    oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;
11630					}
11631				}
11632			}
11633		},
11634		
11635		
11636		/*
11637		 * Variable: iFullNumbersShowPages
11638		 * Purpose:  Change the number of pages which can be seen
11639		 * Scope:    jQuery.fn.dataTableExt.oPagination
11640		 */
11641		"iFullNumbersShowPages": 5,
11642		
11643		/*
11644		 * Variable: full_numbers
11645		 * Purpose:  Full numbers pagination
11646		 * Scope:    jQuery.fn.dataTableExt.oPagination
11647		 */
11648		"full_numbers": {
11649			/*
11650			 * Function: oPagination.full_numbers.fnInit
11651			 * Purpose:  Initialise dom elements required for pagination with a list of the pages
11652			 * Returns:  -
11653			 * Inputs:   object:oSettings - dataTables settings object
11654			 *           node:nPaging - the DIV which contains this pagination control
11655			 *           function:fnCallbackDraw - draw function which must be called on update
11656			 */
11657			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
11658			{
11659				var oLang = oSettings.oLanguage.oPaginate;
11660				var oClasses = oSettings.oClasses;
11661				var fnClickHandler = function ( e ) {
11662					if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
11663					{
11664						fnCallbackDraw( oSettings );
11665					}
11666				};
11667	
11668				$(nPaging).append(
11669					'<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+
11670					'<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+
11671					'<span></span>'+
11672					'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+
11673					'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>'
11674				);
11675				var els = $('a', nPaging);
11676				var nFirst = els[0],
11677					nPrev = els[1],
11678					nNext = els[2],
11679					nLast = els[3];
11680				
11681				oSettings.oApi._fnBindAction( nFirst, {action: "first"},    fnClickHandler );
11682				oSettings.oApi._fnBindAction( nPrev,  {action: "previous"}, fnClickHandler );
11683				oSettings.oApi._fnBindAction( nNext,  {action: "next"},     fnClickHandler );
11684				oSettings.oApi._fnBindAction( nLast,  {action: "last"},     fnClickHandler );
11685				
11686				/* ID the first elements only */
11687				if ( !oSettings.aanFeatures.p )
11688				{
11689					nPaging.id = oSettings.sTableId+'_paginate';
11690					nFirst.id =oSettings.sTableId+'_first';
11691					nPrev.id =oSettings.sTableId+'_previous';
11692					nNext.id =oSettings.sTableId+'_next';
11693					nLast.id =oSettings.sTableId+'_last';
11694				}
11695			},
11696			
11697			/*
11698			 * Function: oPagination.full_numbers.fnUpdate
11699			 * Purpose:  Update the list of page buttons shows
11700			 * Returns:  -
11701			 * Inputs:   object:oSettings - dataTables settings object
11702			 *           function:fnCallbackDraw - draw function to call on page change
11703			 */
11704			"fnUpdate": function ( oSettings, fnCallbackDraw )
11705			{
11706				if ( !oSettings.aanFeatures.p )
11707				{
11708					return;
11709				}
11710				
11711				var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages;
11712				var iPageCountHalf = Math.floor(iPageCount / 2);
11713				var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
11714				var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
11715				var sList = "";
11716				var iStartButton, iEndButton, i, iLen;
11717				var oClasses = oSettings.oClasses;
11718				var anButtons, anStatic, nPaginateList, nNode;
11719				var an = oSettings.aanFeatures.p;
11720				var fnBind = function (j) {
11721					oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) {
11722						/* Use the information in the element to jump to the required page */
11723						oSettings.oApi._fnPageChange( oSettings, e.data.page );
11724						fnCallbackDraw( oSettings );
11725						e.preventDefault();
11726					} );
11727				};
11728				
11729				/* Pages calculation */
11730				if ( oSettings._iDisplayLength === -1 )
11731				{
11732					iStartButton = 1;
11733					iEndButton = 1;
11734					iCurrentPage = 1;
11735				}
11736				else if (iPages < iPageCount)
11737				{
11738					iStartButton = 1;
11739					iEndButton = iPages;
11740				}
11741				else if (iCurrentPage <= iPageCountHalf)
11742				{
11743					iStartButton = 1;
11744					iEndButton = iPageCount;
11745				}
11746				else if (iCurrentPage >= (iPages - iPageCountHalf))
11747				{
11748					iStartButton = iPages - iPageCount + 1;
11749					iEndButton = iPages;
11750				}
11751				else
11752				{
11753					iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
11754					iEndButton = iStartButton + iPageCount - 1;
11755				}
11756	
11757				
11758				/* Build the dynamic list */
11759				for ( i=iStartButton ; i<=iEndButton ; i++ )
11760				{
11761					sList += (iCurrentPage !== i) ?
11762						'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' :
11763						'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>';
11764				}
11765				
11766				/* Loop over each instance of the pager */
11767				for ( i=0, iLen=an.length ; i<iLen ; i++ )
11768				{
11769					nNode = an[i];
11770					if ( !nNode.hasChildNodes() )
11771					{
11772						continue;
11773					}
11774					
11775					/* Build up the dynamic list first - html and listeners */
11776					$('span:eq(0)', nNode)
11777						.html( sList )
11778						.children('a').each( fnBind );
11779					
11780					/* Update the permanent button's classes */
11781					anButtons = nNode.getElementsByTagName('a');
11782					anStatic = [
11783						anButtons[0], anButtons[1], 
11784						anButtons[anButtons.length-2], anButtons[anButtons.length-1]
11785					];
11786	
11787					$(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
11788					$([anStatic[0], anStatic[1]]).addClass( 
11789						(iCurrentPage==1) ?
11790							oClasses.sPageButtonStaticDisabled :
11791							oClasses.sPageButton
11792					);
11793					$([anStatic[2], anStatic[3]]).addClass(
11794						(iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ?
11795							oClasses.sPageButtonStaticDisabled :
11796							oClasses.sPageButton
11797					);
11798				}
11799			}
11800		}
11801	} );
11802	
11803	$.extend( DataTable.ext.oSort, {
11804		/*
11805		 * text sorting
11806		 */
11807		"string-pre": function ( a )
11808		{
11809			if ( typeof a != 'string' ) {
11810				a = (a !== null && a.toString) ? a.toString() : '';
11811			}
11812			return a.toLowerCase();
11813		},
11814	
11815		"string-asc": function ( x, y )
11816		{
11817			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
11818		},
11819		
11820		"string-desc": function ( x, y )
11821		{
11822			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
11823		},
11824		
11825		
11826		/*
11827		 * html sorting (ignore html tags)
11828		 */
11829		"html-pre": function ( a )
11830		{
11831			return a.replace( /<.*?>/g, "" ).toLowerCase();
11832		},
11833		
11834		"html-asc": function ( x, y )
11835		{
11836			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
11837		},
11838		
11839		"html-desc": function ( x, y )
11840		{
11841			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
11842		},
11843		
11844		
11845		/*
11846		 * date sorting
11847		 */
11848		"date-pre": function ( a )
11849		{
11850			var x = Date.parse( a );
11851			
11852			if ( isNaN(x) || x==="" )
11853			{
11854				x = Date.parse( "01/01/1970 00:00:00" );
11855			}
11856			return x;
11857		},
11858	
11859		"date-asc": function ( x, y )
11860		{
11861			return x - y;
11862		},
11863		
11864		"date-desc": function ( x, y )
11865		{
11866			return y - x;
11867		},
11868		
11869		
11870		/*
11871		 * numerical sorting
11872		 */
11873		"numeric-pre": function ( a )
11874		{
11875			return (a=="-" || a==="") ? 0 : a*1;
11876		},
11877	
11878		"numeric-asc": function ( x, y )
11879		{
11880			return x - y;
11881		},
11882		
11883		"numeric-desc": function ( x, y )
11884		{
11885			return y - x;
11886		}
11887	} );
11888	
11889	
11890	$.extend( DataTable.ext.aTypes, [
11891		/*
11892		 * Function: -
11893		 * Purpose:  Check to see if a string is numeric
11894		 * Returns:  string:'numeric' or null
11895		 * Inputs:   mixed:sText - string to check
11896		 */
11897		function ( sData )
11898		{
11899			/* Allow zero length strings as a number */
11900			if ( typeof sData === 'number' )
11901			{
11902				return 'numeric';
11903			}
11904			else if ( typeof sData !== 'string' )
11905			{
11906				return null;
11907			}
11908			
11909			var sValidFirstChars = "0123456789-";
11910			var sValidChars = "0123456789.";
11911			var Char;
11912			var bDecimal = false;
11913			
11914			/* Check for a valid first char (no period and allow negatives) */
11915			Char = sData.charAt(0); 
11916			if (sValidFirstChars.indexOf(Char) == -1) 
11917			{
11918				return null;
11919			}
11920			
11921			/* Check all the other characters are valid */
11922			for ( var i=1 ; i<sData.length ; i++ ) 
11923			{
11924				Char = sData.charAt(i); 
11925				if (sValidChars.indexOf(Char) == -1) 
11926				{
11927					return null;
11928				}
11929				
11930				/* Only allowed one decimal place... */
11931				if ( Char == "." )
11932				{
11933					if ( bDecimal )
11934					{
11935						return null;
11936					}
11937					bDecimal = true;
11938				}
11939			}
11940			
11941			return 'numeric';
11942		},
11943		
11944		/*
11945		 * Function: -
11946		 * Purpose:  Check to see if a string is actually a formatted date
11947		 * Returns:  string:'date' or null
11948		 * Inputs:   string:sText - string to check
11949		 */
11950		function ( sData )
11951		{
11952			var iParse = Date.parse(sData);
11953			if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )
11954			{
11955				return 'date';
11956			}
11957			return null;
11958		},
11959		
11960		/*
11961		 * Function: -
11962		 * Purpose:  Check to see if a string should be treated as an HTML string
11963		 * Returns:  string:'html' or null
11964		 * Inputs:   string:sText - string to check
11965		 */
11966		function ( sData )
11967		{
11968			if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
11969			{
11970				return 'html';
11971			}
11972			return null;
11973		}
11974	] );
11975	
11976
11977	// jQuery aliases
11978	$.fn.DataTable = DataTable;
11979	$.fn.dataTable = DataTable;
11980	$.fn.dataTableSettings = DataTable.settings;
11981	$.fn.dataTableExt = DataTable.ext;
11982
11983
11984	// Information about events fired by DataTables - for documentation.
11985	/**
11986	 * Draw event, fired whenever the table is redrawn on the page, at the same point as
11987	 * fnDrawCallback. This may be useful for binding events or performing calculations when
11988	 * the table is altered at all.
11989	 *  @name DataTable#draw
11990	 *  @event
11991	 *  @param {event} e jQuery event object
11992	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11993	 */
11994
11995	/**
11996	 * Filter event, fired when the filtering applied to the table (using the build in global
11997	 * global filter, or column filters) is altered.
11998	 *  @name DataTable#filter
11999	 *  @event
12000	 *  @param {event} e jQuery event object
12001	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
12002	 */
12003
12004	/**
12005	 * Page change event, fired when the paging of the table is altered.
12006	 *  @name DataTable#page
12007	 *  @event
12008	 *  @param {event} e jQuery event object
12009	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
12010	 */
12011
12012	/**
12013	 * Sort event, fired when the sorting applied to the table is altered.
12014	 *  @name DataTable#sort
12015	 *  @event
12016	 *  @param {event} e jQuery event object
12017	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
12018	 */
12019
12020	/**
12021	 * DataTables initialisation complete event, fired when the table is fully drawn,
12022	 * including Ajax data loaded, if Ajax data is required.
12023	 *  @name DataTable#init
12024	 *  @event
12025	 *  @param {event} e jQuery event object
12026	 *  @param {object} oSettings DataTables settings object
12027	 *  @param {object} json The JSON object request from the server - only
12028	 *    present if client-side Ajax sourced data is used</li></ol>
12029	 */
12030
12031	/**
12032	 * State save event, fired when the table has changed state a new state save is required.
12033	 * This method allows modification of the state saving object prior to actually doing the
12034	 * save, including addition or other state properties (for plug-ins) or modification
12035	 * of a DataTables core property.
12036	 *  @name DataTable#stateSaveParams
12037	 *  @event
12038	 *  @param {event} e jQuery event object
12039	 *  @param {object} oSettings DataTables settings object
12040	 *  @param {object} json The state information to be saved
12041	 */
12042
12043	/**
12044	 * State load event, fired when the table is loading state from the stored data, but
12045	 * prior to the settings object being modified by the saved state - allowing modification
12046	 * of the saved state is required or loading of state for a plug-in.
12047	 *  @name DataTable#stateLoadParams
12048	 *  @event
12049	 *  @param {event} e jQuery event object
12050	 *  @param {object} oSettings DataTables settings object
12051	 *  @param {object} json The saved state information
12052	 */
12053
12054	/**
12055	 * State loaded event, fired when state has been loaded from stored data and the settings
12056	 * object has been modified by the loaded data.
12057	 *  @name DataTable#stateLoaded
12058	 *  @event
12059	 *  @param {event} e jQuery event object
12060	 *  @param {object} oSettings DataTables settings object
12061	 *  @param {object} json The saved state information
12062	 */
12063
12064	/**
12065	 * Processing event, fired when DataTables is doing some kind of processing (be it,
12066	 * sort, filter or anything else). Can be used to indicate to the end user that
12067	 * there is something happening, or that something has finished.
12068	 *  @name DataTable#processing
12069	 *  @event
12070	 *  @param {event} e jQuery event object
12071	 *  @param {object} oSettings DataTables settings object
12072	 *  @param {boolean} bShow Flag for if DataTables is doing processing or not
12073	 */
12074
12075	/**
12076	 * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to 
12077	 * made to the server for new data (note that this trigger is called 
12077in fnServerData,
12078	 * if you override fnServerData and which to use this event, you need to trigger it in
12079	 * you success function).
12080	 *  @name DataTable#xhr
12081	 *  @event
12082	 *  @param {event} e jQuery event object
12083	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
12084	 *  @param {object} json JSON returned from the server
12085	 */
12086
12087	/**
12088	 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing
12089	 * the bDestroy:true parameter in the initialisation object. This can be used to remove
12090	 * bound events, added DOM nodes, etc.
12091	 *  @name DataTable#destroy
12092	 *  @event
12093	 *  @param {event} e jQuery event object
12094	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
12095	 */
12096}));
12097
12098}(window, document));
12099

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.