PageSourceSearch

https://dewservice.com/js/jquery.dataTables.js?v=6

js dewservice.com collected 2026-10-08 17:36:47 UTC 376,072 bytes, 12,051 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,oSettings] );
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,oSettings] );
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" />') :
2079			  sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />';
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" '+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 sNameFile = sName;
4494			var sFullCookie, oData;
4495			
4496			try{
4497				if(window.localStorage && typeof window.localStorage.setItem === 'function') window.localStorage.setItem(sNameFile, encodeURIComponent(sValue));
4498			}catch(e){
4499				if($.isQuotaExceeded && $.isQuotaExceeded(e)){
4500					if($.cleanLocalStorage){
4501						$.cleanLocalStorage();
4502
4503						try{
4504							if(window.localStorage && typeof window.localStorage.setItem === 'function') 
4505							window.localStorage.setItem(sNameFile, encodeURIComponent(sValue));
4506						}catch(e){
4507							
4508						}
4509					}
4510				}
4511			}
4512			
4513		}
4514		
4515		
4516		/**
4517		 * Read an old cookie to get a cookie with an old table state
4518		 *  @param {string} sName name of the cookie to read
4519		 *  @returns {string} contents of the cookie - or null if no cookie with that name found
4520		 *  @memberof DataTable#oApi
4521		 */
4522		function _fnReadCookie ( sName )
4523		{
4524			var	sNameEQ = sName;
4525			
4526			try{
4527				if(window.localStorage && typeof window.localStorage.getItem === 'function') 
4528				return decodeURIComponent(window.localStorage.getItem(sNameEQ));
4529			}catch(e){
4530				if($.cleanLocalStorage){
4531					$.cleanLocalStorage();
4532
4533					try{
4534						if(window.localStorage && typeof window.localStorage.getItem === 'function') 
4535						return decodeURIComponent(window.localStorage.getItem(sNameEQ));
4536					}catch(e){
4537
4538					}
4539				}
4540			}
4541			return null;
4542
4543		}
4544		
4545		
4546		/**
4547		 * Return the settings object for a particular table
4548		 *  @param {node} nTable table we are using as a dataTable
4549		 *  @returns {object} Settings object - or null if not found
4550		 *  @memberof DataTable#oApi
4551		 */
4552		function _fnSettingsFromNode ( nTable )
4553		{
4554			for ( var i=0 ; i<DataTable.settings.length ; i++ )
4555			{
4556				if ( DataTable.settings[i].nTable === nTable )
4557				{
4558					return DataTable.settings[i];
4559				}
4560			}
4561			
4562			return null;
4563		}
4564		
4565		
4566		/**
4567		 * Return an array with the TR nodes for the table
4568		 *  @param {object} oSettings dataTables settings object
4569		 *  @returns {array} TR array
4570		 *  @memberof DataTable#oApi
4571		 */
4572		function _fnGetTrNodes ( oSettings )
4573		{
4574			var aNodes = [];
4575			var aoData = oSettings.aoData;
4576			for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
4577			{
4578				if ( aoData[i].nTr !== null )
4579				{
4580					aNodes.push( aoData[i].nTr );
4581				}
4582			}
4583			return aNodes;
4584		}
4585		
4586		
4587		/**
4588		 * Return an flat array with all TD nodes for the table, or row
4589		 *  @param {object} oSettings dataTables settings object
4590		 *  @param {int} [iIndividualRow] aoData index to get the nodes for - optional 
4591		 *    if not given then the return array will contain all nodes for the table
4592		 *  @returns {array} TD array
4593		 *  @memberof DataTable#oApi
4594		 */
4595		function _fnGetTdNodes ( oSettings, iIndividualRow )
4596		{
4597			var anReturn = [];
4598			var iCorrector;
4599			var anTds, nTd;
4600			var iRow, iRows=oSettings.aoData.length,
4601				iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
4602			
4603			/* Allow the collection to be limited to just one row */
4604			if ( iIndividualRow !== undefined )
4605			{
4606				iStart = iIndividualRow;
4607				iEnd = iIndividualRow+1;
4608			}
4609		
4610			for ( iRow=iStart ; iRow<iEnd ; iRow++ )
4611			{
4612				oData = oSettings.aoData[iRow];
4613				if ( oData.nTr !== null )
4614				{
4615					/* get the TD child nodes - taking into account text etc nodes */
4616					anTds = [];
4617					nTd = oData.nTr.firstChild;
4618					while ( nTd )
4619					{
4620						sNodeName = nTd.nodeName.toLowerCase();
4621						if ( sNodeName == 'td' || sNodeName == 'th' )
4622						{
4623							anTds.push( nTd );
4624						}
4625						nTd = nTd.nextSibling;
4626					}
4627		
4628					iCorrector = 0;
4629					for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
4630					{
4631						if ( oSettings.aoColumns[iColumn].bVisible )
4632						{
4633							anReturn.push( anTds[iColumn-iCorrector] );
4634						}
4635						else
4636						{
4637							anReturn.push( oData._anHidden[iColumn] );
4638							iCorrector++;
4639						}
4640					}
4641				}
4642			}
4643		
4644			return anReturn;
4645		}
4646		
4647		
4648		/**
4649		 * Log an error message
4650		 *  @param {object} oSettings dataTables settings object
4651		 *  @param {int} iLevel log error messages, or display them to the user
4652		 *  @param {string} sMesg error message
4653		 *  @memberof DataTable#oApi
4654		 */
4655		function _fnLog( oSettings, iLevel, sMesg )
4656		{
4657			var sAlert = (oSettings===null) ?
4658				"DataTables warning: "+sMesg :
4659				"DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
4660			
4661			if ( iLevel === 0 )
4662			{
4663				if ( DataTable.ext.sErrMode == 'alert' )
4664				{
4665					alert( sAlert );
4666				}
4667				else
4668				{
4669					throw new Error(sAlert);
4670				}
4671				return;
4672			}
4673			else if ( window.console && console.log )
4674			{
4675				console.log( sAlert );
4676			}
4677		}
4678		
4679		
4680		/**
4681		 * See if a property is defined on one object, if so assign it to the other object
4682		 *  @param {object} oRet target object
4683		 *  @param {object} oSrc source object
4684		 *  @param {string} sName property
4685		 *  @param {string} [sMappedName] name to map too - optional, sName used if not given
4686		 *  @memberof DataTable#oApi
4687		 */
4688		function _fnMap( oRet, oSrc, sName, sMappedName )
4689		{
4690			if ( sMappedName === undefined )
4691			{
4692				sMappedName = sName;
4693			}
4694			if ( oSrc[sName] !== undefined )
4695			{
4696				oRet[sMappedName] = oSrc[sName];
4697			}
4698		}
4699		
4700		
4701		/**
4702		 * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
4703		 * copy arrays. The reason we need to do this, is that we don't want to deep copy array
4704		 * init values (such as aaSorting) since the dev wouldn't be able to override them, but
4705		 * we do want to deep copy arrays.
4706		 *  @param {object} oOut Object to extend
4707		 *  @param {object} oExtender Object from which the properties will be applied to oOut
4708		 *  @returns {object} oOut Reference, just for convenience - oOut === the return.
4709		 *  @memberof DataTable#oApi
4710		 *  @todo This doesn't take account of arrays inside the deep copied objects.
4711		 */
4712		function _fnExtend( oOut, oExtender )
4713		{
4714			var val;
4715			
4716			for ( var prop in oExtender )
4717			{
4718				if ( oExtender.hasOwnProperty(prop) )
4719				{
4720					val = oExtender[prop];
4721		
4722					if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
4723					{
4724						$.extend( true, oOut[prop], val );
4725					}
4726					else
4727					{
4728						oOut[prop] = val;
4729					}
4730				}
4731			}
4732		
4733			return oOut;
4734		}
4735		
4736		
4737		/**
4738		 * Bind an event handers to allow a click or return key to activate the callback.
4739		 * This is good for accessibility since a return on the keyboard will have the
4740		 * same effect as a click, if the element has focus.
4741		 *  @param {element} n Element to bind the action to
4742		 *  @param {object} oData Data object to pass to the triggered function
4743		 *  @param {function} fn Callback function for when the event is triggered
4744		 *  @memberof DataTable#oApi
4745		 */
4746		function _fnBindAction( n, oData, fn )
4747		{
4748			$(n)
4749				.bind( 'click.DT', oData, function (e) {
4750						n.blur(); // Remove focus outline for mouse users
4751						fn(e);
4752					} )
4753				.bind( 'keypress.DT', oData, function (e){
4754					if ( e.which === 13 ) {
4755						fn(e);
4756					} } )
4757				.bind( 'selectstart.DT', function () {
4758					/* Take the brutal approach to cancelling text selection */
4759					return false;
4760					} );
4761		}
4762		
4763		
4764		/**
4765		 * Register a callback function. Easily allows a callback function to be added to
4766		 * an array store of callback functions that can then all be called together.
4767		 *  @param {object} oSettings dataTables settings object
4768		 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
4769		 *  @param {function} fn Function to be called back
4770		 *  @param {string} sName Identifying name for the callback (i.e. a label)
4771		 *  @memberof DataTable#oApi
4772		 */
4773		function _fnCallbackReg( oSettings, sStore, fn, sName )
4774		{
4775			if ( fn )
4776			{
4777				oSettings[sStore].push( {
4778					"fn": fn,
4779					"sName": sName
4780				} );
4781			}
4782		}
4783		
4784		
4785		/**
4786		 * Fire callback functions and trigger events. Note that the loop over the callback
4787		 * array store is done backwards! Further note that you do not want to fire off triggers
4788		 * in time sensitive applications (for example cell creation) as its slow.
4789		 *  @param {object} oSettings dataTables settings object
4790		 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
4791		 *  @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
4792		 *    is fired
4793		 *  @param {array} aArgs Array of arguments to pass to the callback function / trigger
4794		 *  @memberof DataTable#oApi
4795		 */
4796		function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
4797		{
4798			var aoStore = oSettings[sStore];
4799			var aRet =[];
4800		
4801			for ( var i=aoStore.length-1 ; i>=0 ; i-- )
4802			{
4803				aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
4804			}
4805		
4806			if ( sTrigger !== null )
4807			{
4808				$(oSettings.oInstance).trigger(sTrigger, aArgs);
4809			}
4810		
4811			return aRet;
4812		}
4813		
4814		
4815		/**
4816		 * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
4817		 * library, then we use that as it is fast, safe and accurate. If the function isn't 
4818		 * available then we need to built it ourselves - the inspiration for this function comes
4819		 * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
4820		 * not perfect and absolutely should not be used as a replacement to json2.js - but it does
4821		 * do what we need, without requiring a dependency for DataTables.
4822		 *  @param {object} o JSON object to be converted
4823		 *  @returns {string} JSON string
4824		 *  @memberof DataTable#oApi
4825		 */
4826		var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
4827		{
4828			/* Not an object or array */
4829			var sType = typeof o;
4830			if (sType !== "object" || o === null)
4831			{
4832				// simple data type
4833				if (sType === "string")
4834				{
4835					o = '"'+o+'"';
4836				}
4837				return o+"";
4838			}
4839		
4840			/* If object or array, need to recurse over it */
4841			var
4842				sProp, mValue,
4843				json = [],
4844				bArr = $.isArray(o);
4845			
4846			for (sProp in o)
4847			{
4848				mValue = o[sProp];
4849				sType = typeof mValue;
4850		
4851				if (sType === "string")
4852				{
4853					mValue = '"'+mValue+'"';
4854				}
4855				else if (sType === "object" && mValue !== null)
4856				{
4857					mValue = _fnJsonString(mValue);
4858				}
4859		
4860				json.push((bArr ? "" : '"'+sProp+'":') + mValue);
4861			}
4862		
4863			return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
4864		};
4865		
4866		
4867		/**
4868		 * From some browsers (specifically IE6/7) we need special handling to work around browser
4869		 * bugs - this function is used to detect when these workarounds are needed.
4870		 *  @param {object} oSettings dataTables settings object
4871		 *  @memberof DataTable#oApi
4872		 */
4873		function _fnBrowserDetect( oSettings )
4874		{
4875			/* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
4876			 * width of the scrollbar, while other browsers ensure the inner element is contained
4877			 * without forcing scrolling
4878			 */
4879			var n = $(
4880				'<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+
4881					'<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+
4882						'<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+
4883					'</div>'+
4884				'</div>')[0];
4885		
4886			document.body.appendChild( n );
4887			oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
4888			document.body.removeChild( n );
4889		}
4890		
4891
4892		/**
4893		 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
4894		 * return the resulting jQuery object.
4895		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
4896		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
4897		 *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
4898		 *    criterion ("applied") or all TR elements (i.e. no filter).
4899		 *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
4900		 *    Can be either 'current', whereby the current sorting of the table is used, or
4901		 *    'original' whereby the original order the data was read into the table is used.
4902		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
4903		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
4904		 *    'current' and filter is 'applied', regardless of what they might be given as.
4905		 *  @returns {object} jQuery object, filtered by the given selector.
4906		 *  @dtopt API
4907		 *
4908		 *  @example
4909		 *    $(document).ready(function() {
4910		 *      var oTable = $('#example').dataTable();
4911		 *
4912		 *      // Highlight every second row
4913		 *      oTable.$('tr:odd').css('backgroundColor', 'blue');
4914		 *    } );
4915		 *
4916		 *  @example
4917		 *    $(document).ready(function() {
4918		 *      var oTable = $('#example').dataTable();
4919		 *
4920		 *      // Filter to rows with 'Webkit' in them, add a background colour and then
4921		 *      // remove the filter, thus highlighting the 'Webkit' rows only.
4922		 *      oTable.fnFilter('Webkit');
4923		 *      oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
4924		 *      oTable.fnFilter('');
4925		 *    } );
4926		 */
4927		this.$ = function ( sSelector, oOpts )
4928		{
4929			var i, iLen, a = [], tr;
4930			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
4931			var aoData = oSettings.aoData;
4932			var aiDisplay = oSettings.aiDisplay;
4933			var aiDisplayMaster = oSettings.aiDisplayMaster;
4934		
4935			if ( !oOpts )
4936			{
4937				oOpts = {};
4938			}
4939		
4940			oOpts = $.extend( {}, {
4941				"filter": "none", // applied
4942				"order": "current", // "original"
4943				"page": "all" // current
4944			}, oOpts );
4945		
4946			// Current page implies that order=current and fitler=applied, since it is fairly
4947			// senseless otherwise
4948			if ( oOpts.page == 'current' )
4949			{
4950				for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
4951				{
4952					tr = aoData[ aiDisplay[i] ].nTr;
4953					if ( tr )
4954					{
4955						a.push( tr );
4956					}
4957				}
4958			}
4959			else if ( oOpts.order == "current" && oOpts.filter == "none" )
4960			{
4961				for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )
4962				{
4963					tr = aoData[ aiDisplayMaster[i] ].nTr;
4964					if ( tr )
4965					{
4966						a.push( tr );
4967					}
4968				}
4969			}
4970			else if ( oOpts.order == "current" && oOpts.filter == "applied" )
4971			{
4972				for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )
4973				{
4974					tr = aoData[ aiDisplay[i] ].nTr;
4975					if ( tr )
4976					{
4977						a.push( tr );
4978					}
4979				}
4980			}
4981			else if ( oOpts.order == "original" && oOpts.filter == "none" )
4982			{
4983				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
4984				{
4985					tr = aoData[ i ].nTr ;
4986					if ( tr )
4987					{
4988						a.push( tr );
4989					}
4990				}
4991			}
4992			else if ( oOpts.order == "original" && oOpts.filter == "applied" )
4993			{
4994				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
4995				{
4996					tr = aoData[ i ].nTr;
4997					if ( $.inArray( i, aiDisplay ) !== -1 && tr )
4998					{
4999						a.push( tr );
5000					}
5001				}
5002			}
5003			else
5004			{
5005				_fnLog( oSettings, 1, "Unknown selection options" );
5006			}
5007		
5008			/* We need to filter on the TR elements and also 'find' in their descendants
5009			 * to make the selector act like it would in a full table - so we need
5010			 * to build both results and then combine them together
5011			 */
5012			var jqA = $(a);
5013			var jqTRs = jqA.filter( sSelector );
5014			var jqDescendants = jqA.find( sSelector );
5015		
5016			return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
5017		};
5018		
5019		
5020		/**
5021		 * Almost identical to $ in operation, but in this case returns the data for the matched
5022		 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5023		 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5024		 * rows are found, the data returned is the original data array/object that was used to  
5025		 * create the row (or a generated array if from a DOM source).
5026		 *
5027		 * This method is often useful in-combination with $ where both functions are given the
5028		 * same parameters and the array indexes will match identically.
5029		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5030		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
5031		 *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
5032		 *    criterion ("applied") or all elements (i.e. no filter).
5033		 *  @param {string} [oOpts.order=current] Order of the data in the processed array.
5034		 *    Can be either 'current', whereby the current sorting of the table is used, or
5035		 *    'original' whereby the original order the data was read into the table is used.
5036		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5037		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
5038		 *    'current' and filter is 'applied', regardless of what they might be given as.
5039		 *  @returns {array} Data for the matched elements. If any elements, as a result of the
5040		 *    selector, were not TR, TD or TH elements in the DataTable, they will have a null 
5041		 *    entry in the array.
5042		 *  @dtopt API
5043		 *
5044		 *  @example
5045		 *    $(document).ready(function() {
5046		 *      var oTable = $('#example').dataTable();
5047		 *
5048		 *      // Get the data from the first row in the table
5049		 *      var data = oTable._('tr:first');
5050		 *
5051		 *      // Do something useful with the data
5052		 *      alert( "First cell is: "+data[0] );
5053		 *    } );
5054		 *
5055		 *  @example
5056		 *    $(document).ready(function() {
5057		 *      var oTable = $('#example').dataTable();
5058		 *
5059		 *      // Filter to 'Webkit' and get all data for 
5060		 *      oTable.fnFilter('Webkit');
5061		 *      var data = oTable._('tr', {"filter": "applied"});
5062		 *      
5063		 *      // Do something with the data
5064		 *      alert( data.length+" rows matched the filter" );
5065		 *    } );
5066		 */
5067		this._ = function ( sSelector, oOpts )
5068		{
5069			var aOut = [];
5070			var i, iLen, iIndex;
5071			var aTrs = this.$( sSelector, oOpts );
5072		
5073			for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
5074			{
5075				aOut.push( this.fnGetData(aTrs[i]) );
5076			}
5077		
5078			return aOut;
5079		};
5080		
5081		
5082		/**
5083		 * Add a single new row or multiple rows of data to the table. Please note
5084		 * that this is suitable for client-side processing only - if you are using 
5085		 * server-side processing (i.e. "bServerSide": true), then to add data, you
5086		 * must add it to the data source, i.e. the server-side, through an Ajax call.
5087		 *  @param {array|object} mData The data to be added to the table. This can be:
5088		 *    <ul>
5089		 *      <li>1D array of data - add a single row with the data provided</li>
5090		 *      <li>2D array of arrays - add multiple rows in a single call</li>
5091		 *      <li>object - data object when using <i>mData</i></li>
5092		 *      <li>array of objects - multiple data objects when using <i>mData</i></li>
5093		 *    </ul>
5094		 *  @param {bool} [bRedraw=true] redraw the table or not
5095		 *  @returns {array} An array of integers, representing the list of indexes in 
5096		 *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 
5097		 *    the table.
5098		 *  @dtopt API
5099		 *
5100		 *  @example
5101		 *    // Global var for counter
5102		 *    var giCount = 2;
5103		 *    
5104		 *    $(document).ready(function() {
5105		 *      $('#example').dataTable();
5106		 *    } );
5107		 *    
5108		 *    function fnClickAddRow() {
5109		 *      $('#example').dataTable().fnAddData( [
5110		 *        giCount+".1",
5111		 *        giCount+".2",
5112		 *        giCount+".3",
5113		 *        giCount+".4" ]
5114		 *      );
5115		 *        
5116		 *      giCount++;
5117		 *    }
5118		 */
5119		this.fnAddData = function( mData, bRedraw )
5120		{
5121			if ( mData.length === 0 )
5122			{
5123				return [];
5124			}
5125			
5126			var aiReturn = [];
5127			var iTest;
5128			
5129			/* Find settings from table node */
5130			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5131			
5132			/* Check if we want to add multiple rows or not */
5133			if ( typeof mData[0] === "object" && mData[0] !== null )
5134			{
5135				for ( var i=0 ; i<mData.length ; i++ )
5136				{
5137					iTest = _fnAddData( oSettings, mData[i] );
5138					if ( iTest == -1 )
5139					{
5140						return aiReturn;
5141					}
5142					aiReturn.push( iTest );
5143				}
5144			}
5145			else
5146			{
5147				iTest = _fnAddData( oSettings, mData );
5148				if ( iTest == -1 )
5149				{
5150					return aiReturn;
5151				}
5152				aiReturn.push( iTest );
5153			}
5154			
5155			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
5156			
5157			if ( bRedraw === undefined || bRedraw )
5158			{
5159				_fnReDraw( oSettings );
5160			}
5161			return aiReturn;
5162		};
5163		
5164		
5165		/**
5166		 * This function will make DataTables recalculate the column sizes, based on the data 
5167		 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 
5168		 * through the sWidth parameter). This can be useful when the width of the table's 
5169		 * parent element changes (for example a window resize).
5170		 *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5171		 *  @dtopt API
5172		 *
5173		 *  @example
5174		 *    $(document).ready(function() {
5175		 *      var oTable = $('#example').dataTable( {
5176		 *        "sScrollY": "200px",
5177		 *        "bPaginate": false
5178		 *      } );
5179		 *      
5180		 *      $(window).bind('resize', function () {
5181		 *        oTable.fnAdjustColumnSizing();
5182		 *      } );
5183		 *    } );
5184		 */
5185		this.fnAdjustColumnSizing = function ( bRedraw )
5186		{
5187			var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
5188			_fnAdjustColumnSizing( oSettings );
5189			
5190			if ( bRedraw === undefined || bRedraw )
5191			{
5192				this.fnDraw( false );
5193			}
5194			else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
5195			{
5196				/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5197				this.oApi._fnScrollDraw(oSettings);
5198			}
5199		};
5200		
5201		
5202		/**
5203		 * Quickly and simply clear a table
5204		 *  @param {bool} [bRedraw=true] redraw the table or not
5205		 *  @dtopt API
5206		 *
5207		 *  @example
5208		 *    $(document).ready(function() {
5209		 *      var oTable = $('#example').dataTable();
5210		 *      
5211		 *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5212		 *      oTable.fnClearTable();
5213		 *    } );
5214		 */
5215		this.fnClearTable = function( bRedraw )
5216		{
5217			/* Find settings from table node */
5218			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5219			_fnClearTable( oSettings );
5220			
5221			if ( bRedraw === undefined || bRedraw )
5222			{
5223				_fnDraw( oSettings );
5224			}
5225		};
5226		
5227		
5228		/**
5229		 * The exact opposite of 'opening' a row, this function will close any rows which 
5230		 * are currently 'open'.
5231		 *  @param {node} nTr the table row to 'close'
5232		 *  @returns {int} 0 on success, or 1 if failed (can't find the row)
5233		 *  @dtopt API
5234		 *
5235		 *  @example
5236		 *    $(document).ready(function() {
5237		 *      var oTable;
5238		 *      
5239		 *      // 'open' an information row when a row is clicked on
5240		 *      $('#example tbody tr').click( function () {
5241		 *        if ( oTable.fnIsOpen(this) ) {
5242		 *          oTable.fnClose( this );
5243		 *        } else {
5244		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5245		 *        }
5246		 *      } );
5247		 *      
5248		 *      oTable = $('#example').dataTable();
5249		 *    } );
5250		 */
5251		this.fnClose = function( nTr )
5252		{
5253			/* Find settings from table node */
5254			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5255			
5256			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
5257			{
5258				if ( oSettings.aoOpenRows[i].nParent == nTr )
5259				{
5260					var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
5261					if ( nTrParent )
5262					{
5263						/* Remove it if it is currently on display */
5264						nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
5265					}
5266					oSettings.aoOpenRows.splice( i, 1 );
5267					return 0;
5268				}
5269			}
5270			return 1;
5271		};
5272		
5273		
5274		/**
5275		 * Remove a row for the table
5276		 *  @param {mixed} mTarget The index of the row from aoData to be deleted, or
5277		 *    the TR element you want to delete
5278		 *  @param {function|null} [fnCallBack] Callback function
5279		 *  @param {bool} [bRedraw=true] Redraw the table or not
5280		 *  @returns {array} The row that was deleted
5281		 *  @dtopt API
5282		 *
5283		 *  @example
5284		 *    $(document).ready(function() {
5285		 *      var oTable = $('#example').dataTable();
5286		 *      
5287		 *      // Immediately remove the first row
5288		 *      oTable.fnDeleteRow( 0 );
5289		 *    } );
5290		 */
5291		this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
5292		{
5293			/* Find settings from table node */
5294			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5295			var i, iLen, iAODataIndex;
5296			
5297			iAODataIndex = (typeof mTarget === 'object') ? 
5298				_fnNodeToDataIndex(oSettings, mTarget) : mTarget;
5299			
5300			/* Return the data array from this row */
5301			var oData = oSettings.aoData.splice( iAODataIndex, 1 );
5302		
5303			/* Update the _DT_RowIndex parameter */
5304			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
5305			{
5306				if ( oSettings.aoData[i].nTr !== null )
5307				{
5308					oSettings.aoData[i].nTr._DT_RowIndex = i;
5309				}
5310			}
5311			
5312			/* Remove the target row from the search array */
5313			var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
5314			oSettings.asDataSearch.splice( iDisplayIndex, 1 );
5315			
5316			/* Delete from the display arrays */
5317			_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
5318			_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
5319			
5320			/* If there is a user callback function - call it */
5321			if ( typeof fnCallBack === "function" )
5322			{
5323				fnCallBack.call( this, oSettings, oData );
5324			}
5325			
5326			/* Check for an 'overflow' they case for displaying the table */
5327			if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
5328			{
5329				oSettings._iDisplayStart -= oSettings._iDisplayLength;
5330				if ( oSettings._iDisplayStart < 0 )
5331				{
5332					oSettings._iDisplayStart = 0;
5333				}
5334			}
5335			
5336			if ( bRedraw === undefined || bRedraw )
5337			{
5338				_fnCalculateEnd( oSettings );
5339				_fnDraw( oSettings );
5340			}
5341			
5342			return oData;
5343		};
5344		
5345		
5346		/**
5347		 * Restore the table to it's original state in the DOM by removing all of DataTables 
5348		 * enhancements, alterations to the DOM structure of the table and event listeners.
5349		 *  @param {boolean} [bRemove=false] Completely remove the table from the DOM
5350		 *  @dtopt API
5351		 *
5352		 *  @example
5353		 *    $(document).ready(function() {
5354		 *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
5355		 *      var oTable = $('#example').dataTable();
5356		 *      oTable.fnDestroy();
5357		 *    } );
5358		 */
5359		this.fnDestroy = function ( bRemove )
5360		{
5361			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5362			var nOrig = oSettings.nTableWrapper.parentNode;
5363			var nBody = oSettings.nTBody;
5364			var i, iLen;
5365		
5366			bRemove = (bRemove===undefined) ? false : bRemove;
5367			
5368			/* Flag to note that the table is currently being destroyed - no action should be taken */
5369			oSettings.bDestroying = true;
5370			
5371			/* Fire off the destroy callbacks for plug-ins etc */
5372			_fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );
5373		
5374			/* If the table is not being removed, restore the hidden columns */
5375			if ( !bRemove )
5376			{
5377				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
5378				{
5379					if ( oSettings.aoColumns[i].bVisible === false )
5380					{
5381						this.fnSetColumnVis( i, true );
5382					}
5383				}
5384			}
5385			
5386			/* Blitz all DT events */
5387			$(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
5388			
5389			/* If there is an 'empty' indicator row, remove it */
5390			$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
5391			
5392			/* When scrolling we had to break the table up - restore it */
5393			if ( oSettings.nTable != oSettings.nTHead.parentNode )
5394			{
5395				$(oSettings.nTable).children('thead').remove();
5396				oSettings.nTable.appendChild( oSettings.nTHead );
5397			}
5398			
5399			if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
5400			{
5401				$(oSettings.nTable).children('tfoot').remove();
5402				oSettings.nTable.appendChild( oSettings.nTFoot );
5403			}
5404			
5405			/* Remove the DataTables generated nodes, events and classes */
5406			oSettings.nTable.parentNode.removeChild( oSettings.nTable );
5407			$(oSettings.nTableWrapper).remove();
5408			
5409			oSettings.aaSorting = [];
5410			oSettings.aaSortingFixed = [];
5411			_fnSortingClasses( oSettings );
5412			
5413			$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
5414			
5415			$('th, td', oSettings.nTHead).removeClass( [
5416				oSettings.oClasses.sSortable,
5417				oSettings.oClasses.sSortableAsc,
5418				oSettings.oClasses.sSortableDesc,
5419				oSettings.oClasses.sSortableNone ].join(' ')
5420			);
5421			if ( oSettings.bJUI )
5422			{
5423				$('th span.'+oSettings.oClasses.sSortIcon
5424					+ ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
5425		
5426				$('th, td', oSettings.nTHead).each( function () {
5427					var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
5428					var kids = jqWrapper.contents();
5429					$(this).append( kids );
5430					jqWrapper.remove();
5431				} );
5432			}
5433			
5434			/* Add the TR elements back into the table in their original order */
5435			if ( !bRemove && oSettings.nTableReinsertBefore )
5436			{
5437				nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
5438			}
5439			else if ( !bRemove )
5440			{
5441				nOrig.appendChild( oSettings.nTable );
5442			}
5443		
5444			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
5445			{
5446				if ( oSettings.aoData[i].nTr !== null )
5447				{
5448					nBody.appendChild( oSettings.aoData[i].nTr );
5449				}
5450			}
5451			
5452			/* Restore the width of the original table */
5453			if ( oSettings.oFeatures.bAutoWidth === true )
5454			{
5455			  oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
5456			}
5457			
5458			/* If the were originally stripe classes - then we add them back here. Note
5459			 * this is not fool proof (for example if not all rows had stripe classes - but
5460			 * it's a good effort without getting carried away
5461			 */
5462			iLen = oSettings.asDestroyStripes.length;
5463			if (iLen)
5464			{
5465				var anRows = $(nBody).children('tr');
5466				for ( i=0 ; i<iLen ; i++ )
5467				{
5468					anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );
5469				}
5470			}
5471			
5472			/* Remove the settings object from the settings array */
5473			for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
5474			{
5475				if ( DataTable.settings[i] == oSettings )
5476				{
5477					DataTable.settings.splice( i, 1 );
5478				}
5479			}
5480			
5481			/* End it all */
5482			oSettings = null;
5483			oInit = null;
5484		};
5485		
5486		
5487		/**
5488		 * Redraw the table
5489		 *  @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
5490		 *  @dtopt API
5491		 *
5492		 *  @example
5493		 *    $(document).ready(function() {
5494		 *      var oTable = $('#example').dataTable();
5495		 *      
5496		 *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5497		 *      oTable.fnDraw();
5498		 *    } );
5499		 */
5500		this.fnDraw = function( bComplete )
5501		{
5502			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5503			if ( bComplete === false )
5504			{
5505				_fnCalculateEnd( oSettings );
5506				_fnDraw( oSettings );
5507			}
5508			else
5509			{
5510				_fnReDraw( oSettings );
5511			}
5512		};
5513		
5514		
5515		/**
5516		 * Filter the input based on data
5517		 *  @param {string} sInput String to filter the table on
5518		 *  @param {int|null} [iColumn] Column to limit filtering to
5519		 *  @param {bool} [bRegex=false] Treat as regular expression or not
5520		 *  @param {bool} [bSmart=true] Perform smart filtering or not
5521		 *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5522		 *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5523		 *  @dtopt API
5524		 *
5525		 *  @example
5526		 *    $(document).ready(function() {
5527		 *      var oTable = $('#example').dataTable();
5528		 *      
5529		 *      // Sometime later - filter...
5530		 *      oTable.fnFilter( 'test string' );
5531		 *    } );
5532		 */
5533		this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5534		{
5535			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5536			
5537			if ( !oSettings.oFeatures.bFilter )
5538			{
5539				return;
5540			}
5541			
5542			if ( bRegex === undefined || bRegex === null )
5543			{
5544				bRegex = false;
5545			}
5546			
5547			if ( bSmart === undefined || bSmart === null )
5548			{
5549				bSmart = true;
5550			}
5551			
5552			if ( bShowGlobal === undefined || bShowGlobal === null )
5553			{
5554				bShowGlobal = true;
5555			}
5556			
5557			if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
5558			{
5559				bCaseInsensitive = true;
5560			}
5561			
5562			if ( iColumn === undefined || iColumn === null )
5563			{
5564				/* Global filter */
5565				_fnFilterComplete( oSettings, {
5566					"sSearch":sInput+"",
5567					"bRegex": bRegex,
5568					"bSmart": bSmart,
5569					"bCaseInsensitive": bCaseInsensitive
5570				}, 1 );
5571				
5572				if ( bShowGlobal && oSettings.aanFeatures.f )
5573				{
5574					var n = oSettings.aanFeatures.f;
5575					for ( var i=0, iLen=n.length ; i<iLen ; i++ )
5576					{
5577						// IE9 throws an 'unknown error' if document.activeElement is used
5578						// inside an iframe or frame...
5579						try {
5580							if ( n[i]._DT_Input != document.activeElement )
5581							{
5582								$(n[i]._DT_Input).val( sInput );
5583							}
5584						}
5585						catch ( e ) {
5586							$(n[i]._DT_Input).val( sInput );
5587						}
5588					}
5589				}
5590			}
5591			else
5592			{
5593				/* Single column filter */
5594				$.extend( oSettings.aoPreSearchCols[ iColumn ], {
5595					"sSearch": sInput+"",
5596					"bRegex": bRegex,
5597					"bSmart": bSmart,
5598					"bCaseInsensitive": bCaseInsensitive
5599				} );
5600				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
5601			}
5602		};
5603		
5604		
5605		/**
5606		 * Get the data for the whole table, an individual row or an individual cell based on the 
5607		 * provided parameters.
5608		 *  @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
5609		 *    a TR node then the data source for the whole row will be returned. If given as a
5610		 *    TD/TH cell node then iCol will be automatically calculated and the data for the
5611		 *    cell returned. If given as an integer, then this is treated as the aoData internal
5612		 *    data index for the row (see fnGetPosition) and the data for that row used.
5613		 *  @param {int} [iCol] Optional column index that you want the data of.
5614		 *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
5615		 *    returned. If mRow is defined, just data for that row, and is iCol is
5616		 *    defined, only data for the designated cell is returned.
5617		 *  @dtopt API
5618		 *
5619		 *  @example
5620		 *    // Row data
5621		 *    $(document).ready(function() {
5622		 *      oTable = $('#example').dataTable();
5623		 *
5624		 *      oTable.$('tr').click( function () {
5625		 *        var data = oTable.fnGetData( this );
5626		 *        // ... do something with the array / object of data for the row
5627		 *      } );
5628		 *    } );
5629		 *
5630		 *  @example
5631		 *    // Individual cell data
5632		 *    $(document).ready(function() {
5633		 *      oTable = $('#example').dataTable();
5634		 *
5635		 *      oTable.$('td').click( function () {
5636		 *        var sData = oTable.fnGetData( this );
5637		 *        alert( 'The cell clicked on had the value of '+sData );
5638		 *      } );
5639		 *    } );
5640		 */
5641		this.fnGetData = function( mRow, iCol )
5642		{
5643			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5644			
5645			if ( mRow !== undefined )
5646			{
5647				var iRow = mRow;
5648				if ( typeof mRow === 'object' )
5649				{
5650					var sNode = mRow.nodeName.toLowerCase();
5651					if (sNode === "tr" )
5652					{
5653						iRow = _fnNodeToDataIndex(oSettings, mRow);
5654					}
5655					else if ( sNode === "td" )
5656					{
5657						iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
5658						iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
5659					}
5660				}
5661		
5662				if ( iCol !== undefined )
5663				{
5664					return _fnGetCellData( oSettings, iRow, iCol, '' );
5665				}
5666				return (oSettings.aoData[iRow]!==undefined) ?
5667					oSettings.aoData[iRow]._aData : null;
5668			}
5669			return _fnGetDataMaster( oSettings );
5670		};
5671		
5672		
5673		/**
5674		 * Get an array of the TR nodes that are used in the table's body. Note that you will 
5675		 * typically want to use the '$' API method in preference to this as it is more 
5676		 * flexible.
5677		 *  @param {int} [iRow] Optional row index for the TR element you want
5678		 *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
5679		 *    in the table's body, or iRow is defined, just the TR element requested.
5680		 *  @dtopt API
5681		 *
5682		 *  @example
5683		 *    $(document).ready(function() {
5684		 *      var oTable = $('#example').dataTable();
5685		 *      
5686		 *      // Get the nodes from the table
5687		 *      var nNodes = oTable.fnGetNodes( );
5688		 *    } );
5689		 */
5690		this.fnGetNodes = function( iRow )
5691		{
5692			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5693			
5694			if ( iRow !== undefined ) {
5695				return (oSettings.aoData[iRow]!==undefined) ?
5696					oSettings.aoData[iRow].nTr : null;
5697			}
5698			return _fnGetTrNodes( oSettings );
5699		};
5700		
5701		
5702		/**
5703		 * Get the array indexes of a particular cell from it's DOM element
5704		 * and column index including hidden columns
5705		 *  @param {node} nNode this can either be a TR, TD or TH in the table's body
5706		 *  @returns {int} If nNode is given as a TR, then a single index is returned, or
5707		 *    if given as a cell, an array of [row index, column index (visible), 
5708		 *    column index (all)] is given.
5709		 *  @dtopt API
5710		 *
5711		 *  @example
5712		 *    $(document).ready(function() {
5713		 *      $('#example tbody td').click( function () {
5714		 *        // Get the position of the current data from the node
5715		 *        var aPos = oTable.fnGetPosition( this );
5716		 *        
5717		 *        // Get the data array for this row
5718		 *        var aData = oTable.fnGetData( aPos[0] );
5719		 *        
5720		 *        // Update the data array and return the value
5721		 *        aData[ aPos[1] ] = 'clicked';
5722		 *        this.innerHTML = 'clicked';
5723		 *      } );
5724		 *      
5725		 *      // Init DataTables
5726		 *      oTable = $('#example').dataTable();
5727		 *    } );
5728		 */
5729		this.fnGetPosition = function( nNode )
5730		{
5731			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5732			var sNodeName = nNode.nodeName.toUpperCase();
5733			
5734			if ( sNodeName == "TR" )
5735			{
5736				return _fnNodeToDataIndex(oSettings, nNode);
5737			}
5738			else if ( sNodeName == "TD" || sNodeName == "TH" )
5739			{
5740				var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
5741				var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
5742				return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
5743			}
5744			return null;
5745		};
5746		
5747		
5748		/**
5749		 * Check to see if a row is 'open' or not.
5750		 *  @param {node} nTr the table row to check
5751		 *  @returns {boolean} true if the row is currently open, false otherwise
5752		 *  @dtopt API
5753		 *
5754		 *  @example
5755		 *    $(document).ready(function() {
5756		 *      var oTable;
5757		 *      
5758		 *      // 'open' an information row when a row is clicked on
5759		 *      $('#example tbody tr').click( function () {
5760		 *        if ( oTable.fnIsOpen(this) ) {
5761		 *          oTable.fnClose( this );
5762		 *        } else {
5763		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5764		 *        }
5765		 *      } );
5766		 *      
5767		 *      oTable = $('#example').dataTable();
5768		 *    } );
5769		 */
5770		this.fnIsOpen = function( nTr )
5771		{
5772			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5773			var aoOpenRows = oSettings.aoOpenRows;
5774			
5775			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
5776			{
5777				if ( oSettings.aoOpenRows[i].nParent == nTr )
5778				{
5779					return true;
5780				}
5781			}
5782			return false;
5783		};
5784		
5785		
5786		/**
5787		 * This function will place a new row directly after a row which is currently 
5788		 * on display on the page, with the HTML contents that is passed into the 
5789		 * function. This can be used, for example, to ask for confirmation that a 
5790		 * particular record should be deleted.
5791		 *  @param {node} nTr The table row to 'open'
5792		 *  @param {string|node|jQuery} mHtml The HTML to put into the row
5793		 *  @param {string} sClass Class to give the new TD cell
5794		 *  @returns {node} The row opened. Note that if the table row passed in as the
5795		 *    first parameter, is not found in the table, this method will silently
5796		 *    return.
5797		 *  @dtopt API
5798		 *
5799		 *  @example
5800		 *    $(document).ready(function() {
5801		 *      var oTable;
5802		 *      
5803		 *      // 'open' an information row when a row is clicked on
5804		 *      $('#example tbody tr').click( function () {
5805		 *        if ( oTable.fnIsOpen(this) ) {
5806		 *          oTable.fnClose( this );
5807		 *        } else {
5808		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5809		 *        }
5810		 *      } );
5811		 *      
5812		 *      oTable = $('#example').dataTable();
5813		 *    } );
5814		 */
5815		this.fnOpen = function( nTr, mHtml, sClass )
5816		{
5817			/* Find settings from table node */
5818			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5819		
5820			/* Check that the row given is in the table */
5821			var nTableRows = _fnGetTrNodes( oSettings );
5822			if ( $.inArray(nTr, nTableRows) === -1 )
5823			{
5824				return;
5825			}
5826			
5827			/* the old open one if there is one */
5828			this.fnClose( nTr );
5829			
5830			var nNewRow = document.createElement("tr");
5831			var nNewCell = document.createElement("td");
5832			nNewRow.appendChild( nNewCell );
5833			nNewCell.className = sClass;
5834			nNewCell.colSpan = _fnVisbleColumns( oSettings );
5835		
5836			if (typeof mHtml === "string")
5837			{
5838				nNewCell.innerHTML = mHtml;
5839			}
5840			else
5841			{
5842				$(nNewCell).html( mHtml );
5843			}
5844		
5845			/* If the nTr isn't on the page at the moment - then we don't insert at the moment */
5846			var nTrs = $('tr', oSettings.nTBody);
5847			if ( $.inArray(nTr, nTrs) != -1  )
5848			{
5849				$(nNewRow).insertAfter(nTr);
5850			}
5851			
5852			oSettings.aoOpenRows.push( {
5853				"nTr": nNewRow,
5854				"nParent": nTr
5855			} );
5856			
5857			return nNewRow;
5858		};
5859		
5860		
5861		/**
5862		 * Change the pagination - provides the internal logic for pagination in a simple API 
5863		 * function. With this function you can have a DataTables table go to the next, 
5864		 * previous, first or last pages.
5865		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5866		 *    or page number to jump to (integer), note that page 0 is the first page.
5867		 *  @param {bool} [bRedraw=true] Redraw the table or not
5868		 *  @dtopt API
5869		 *
5870		 *  @example
5871		 *    $(document).ready(function() {
5872		 *      var oTable = $('#example').dataTable();
5873		 *      oTable.fnPageChange( 'next' );
5874		 *    } );
5875		 */
5876		this.fnPageChange = function ( mAction, bRedraw )
5877		{
5878			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5879			_fnPageChange( oSettings, mAction );
5880			_fnCalculateEnd( oSettings );
5881			
5882			if ( bRedraw === undefined || bRedraw )
5883			{
5884				_fnDraw( oSettings );
5885			}
5886		};
5887		
5888		
5889		/**
5890		 * Show a particular column
5891		 *  @param {int} iCol The column whose display should be changed
5892		 *  @param {bool} bShow Show (true) or hide (false) the column
5893		 *  @param {bool} [bRedraw=true] Redraw the table or not
5894		 *  @dtopt API
5895		 *
5896		 *  @example
5897		 *    $(document).ready(function() {
5898		 *      var oTable = $('#example').dataTable();
5899		 *      
5900		 *      // Hide the second column after initialisation
5901		 *      oTable.fnSetColumnVis( 1, false );
5902		 *    } );
5903		 */
5904		this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5905		{
5906			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5907			var i, iLen;
5908			var aoColumns = oSettings.aoColumns;
5909			var aoData = oSettings.aoData;
5910			var nTd, bAppend, iBefore;
5911			
5912			/* No point in doing anything if we are requesting what is already true */
5913			if ( aoColumns[iCol].bVisible == bShow )
5914			{
5915				return;
5916			}
5917			
5918			/* Show the column */
5919			if ( bShow )
5920			{
5921				var iInsert = 0;
5922				for ( i=0 ; i<iCol ; i++ )
5923				{
5924					if ( aoColumns[i].bVisible )
5925					{
5926						iInsert++;
5927					}
5928				}
5929				
5930				/* Need to decide if we should use appendChild or insertBefore */
5931				bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
5932		
5933				/* Which coloumn should we be inserting before? */
5934				if ( !bAppend )
5935				{
5936					for ( i=iCol ; i<aoColumns.length ; i++ )
5937					{
5938						if ( aoColumns[i].bVisible )
5939						{
5940							iBefore = i;
5941							break;
5942						}
5943					}
5944				}
5945		
5946				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
5947				{
5948					if ( aoData[i].nTr !== null )
5949					{
5950						if ( bAppend )
5951						{
5952							aoData[i].nTr.appendChild( 
5953								aoData[i]._anHidden[iCol]
5954							);
5955						}
5956						else
5957						{
5958							aoData[i].nTr.insertBefore(
5959								aoData[i]._anHidden[iCol], 
5960								_fnGetTdNodes( oSettings, i )[iBefore] );
5961						}
5962					}
5963				}
5964			}
5965			else
5966			{
5967				/* Remove a column from display */
5968				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
5969				{
5970					if ( aoData[i].nTr !== null )
5971					{
5972						nTd = _fnGetTdNodes( oSettings, i )[iCol];
5973						aoData[i]._anHidden[iCol] = nTd;
5974						nTd.parentNode.removeChild( nTd );
5975					}
5976				}
5977			}
5978		
5979			/* Clear to set the visible flag */
5980			aoColumns[iCol].bVisible = bShow;
5981		
5982			/* Redraw the header and footer based on the new column visibility */
5983			_fnDrawHead( oSettings, oSettings.aoHeader );
5984			if ( oSettings.nTFoot )
5985			{
5986				_fnDrawHead( oSettings, oSettings.aoFooter );
5987			}
5988			
5989			/* If there are any 'open' rows, then we need to alter the colspan for this col change */
5990			for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
5991			{
5992				oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
5993			}
5994			
5995			/* Do a redraw incase anything depending on the table columns needs it 
5996			 * (built-in: scrolling) 
5997			 */
5998			if ( bRedraw === undefined || bRedraw )
5999			{
6000				_fnAdjustColumnSizing( oSettings );
6001				_fnDraw( oSettings );
6002			}
6003			
6004			_fnSaveState( oSettings );
6005		};
6006		
6007		
6008		/**
6009		 * Get the settings for a particular table for external manipulation
6010		 *  @returns {object} DataTables settings object. See 
6011		 *    {@link DataTable.models.oSettings}
6012		 *  @dtopt API
6013		 *
6014		 *  @example
6015		 *    $(document).ready(function() {
6016		 *      var oTable = $('#example').dataTable();
6017		 *      var oSettings = oTable.fnSettings();
6018		 *      
6019		 *      // Show an example parameter from the settings
6020		 *      alert( oSettings._iDisplayStart );
6021		 *    } );
6022		 */
6023		this.fnSettings = function()
6024		{
6025			return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
6026		};
6027		
6028		
6029		/**
6030		 * Sort the table by a particular column
6031		 *  @param {int} iCol the data index to sort on. Note that this will not match the 
6032		 *    'display index' if you have hidden data entries
6033		 *  @dtopt API
6034		 *
6035		 *  @example
6036		 *    $(document).ready(function() {
6037		 *      var oTable = $('#example').dataTable();
6038		 *      
6039		 *      // Sort immediately with columns 0 and 1
6040		 *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
6041		 *    } );
6042		 */
6043		this.fnSort = function( aaSort )
6044		{
6045			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
6046			oSettings.aaSorting = aaSort;
6047			_fnSort( oSettings );
6048		};
6049		
6050		
6051		/**
6052		 * Attach a sort listener to an element for a given column
6053		 *  @param {node} nNode the element to attach the sort listener to
6054		 *  @param {int} iColumn the column that a click on this node will sort on
6055		 *  @param {function} [fnCallback] callback function when sort is run
6056		 *  @dtopt API
6057		 *
6058		 *  @example
6059		 *    $(document).ready(function() {
6060		 *      var oTable = $('#example').dataTable();
6061		 *      
6062		 *      // Sort on column 1, when 'sorter' is clicked on
6063		 *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
6064		 *    } );
6065		 */
6066		this.fnSortListener = function( nNode, iColumn, fnCallback )
6067		{
6068			_fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
6069			 	fnCallback );
6070		};
6071		
6072		
6073		/**
6074		 * Update a table cell or row - this method will accept either a single value to
6075		 * update the cell with, an array of values with one element for each column or
6076		 * an object in the same format as the original data source. The function is
6077		 * self-referencing in order to make the multi column updates easier.
6078		 *  @param {object|array|string} mData Data to update the cell/row with
6079		 *  @param {node|int} mRow TR element you want to update or the aoData index
6080		 *  @param {int} [iColumn] The column to update (not used of mData is an array or object)
6081		 *  @param {bool} [bRedraw=true] Redraw the table or not
6082		 *  @param {bool} [bAction=true] Perform pre-draw actions or not
6083		 *  @returns {int} 0 on success, 1 on error
6084		 *  @dtopt API
6085		 *
6086		 *  @example
6087		 *    $(document).ready(function() {
6088		 *      var oTable = $('#example').dataTable();
6089		 *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
6090		 *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
6091		 *    } );
6092		 */
6093		this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
6094		{
6095			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
6096			var i, iLen, sDisplay;
6097			var iRow = (typeof mRow === 'object') ? 
6098				_fnNodeToDataIndex(oSettings, mRow) : mRow;
6099			
6100			if ( $.isArray(mData) && iColumn === undefined )
6101			{
6102				/* Array update - update the whole row */
6103				oSettings.aoData[iRow]._aData = mData.slice();
6104				
6105				/* Flag to the function that we are recursing */
6106				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
6107				{
6108					this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
6109				}
6110			}
6111			else if ( $.isPlainObject(mData) && iColumn === undefined )
6112			{
6113				/* Object update - update the whole row - assume the developer gets the object right */
6114				oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
6115		
6116				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
6117				{
6118					this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
6119				}
6120			}
6121			else
6122			{
6123				/* Individual cell update */
6124				_fnSetCellData( oSettings, iRow, iColumn, mData );
6125				sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
6126				
6127				var oCol = oSettings.aoColumns[iColumn];
6128				if ( oCol.fnRender !== null )
6129				{
6130					sDisplay = _fnRender( oSettings, iRow, iColumn );
6131					if ( oCol.bUseRendered )
6132					{
6133						_fnSetCellData( oSettings, iRow, iColumn, sDisplay );
6134					}
6135				}
6136				
6137				if ( oSettings.aoData[iRow].nTr !== null )
6138				{
6139					/* Do the actual HTML update */
6140					_fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
6141				}
6142			}
6143			
6144			/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
6145			 * will rebuild the search array - however, the redraw might be disabled by the user)
6146			 */
6147			var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
6148			oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(
6149				oSettings, 
6150				_fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )
6151			);
6152			
6153			/* Perform pre-draw actions */
6154			if ( bAction === undefined || bAction )
6155			{
6156				_fnAdjustColumnSizing( oSettings );
6157			}
6158			
6159			/* Redraw the table */
6160			if ( bRedraw === undefined || bRedraw )
6161			{
6162				_fnReDraw( oSettings );
6163			}
6164			return 0;
6165		};
6166		
6167		
6168		/**
6169		 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6170		 * to ensure compatibility.
6171		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6172		 *    formats "X" and "X.Y" are also acceptable.
6173		 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
6174		 *    version, or false if this version of DataTales is not suitable
6175		 *  @method
6176		 *  @dtopt API
6177		 *
6178		 *  @example
6179		 *    $(document).ready(function() {
6180		 *      var oTable = $('#example').dataTable();
6181		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
6182		 *    } );
6183		 */
6184		this.fnVersionCheck = DataTable.ext.fnVersionCheck;
6185		
6186		
6187		/*
6188		 * This is really a good bit rubbish this method of exposing the internal methods
6189		 * publicly... - To be fixed in 2.0 using methods on the prototype
6190		 */
6191		
6192		
6193		/**
6194		 * Create a wrapper function for exporting an internal functions to an external API.
6195		 *  @param {string} sFunc API function name
6196		 *  @returns {function} wrapped function
6197		 *  @memberof DataTable#oApi
6198		 */
6199		function _fnExternApiFunc (sFunc)
6200		{
6201			return function() {
6202				var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat( 
6203					Array.prototype.slice.call(arguments) );
6204				return DataTable.ext.oApi[sFunc].apply( this, aArgs );
6205			};
6206		}
6207		
6208		
6209		/**
6210		 * Reference to internal functions for use by plug-in developers. Note that these
6211		 * methods are references to internal functions and are considered to be private.
6212		 * If you use these methods, be aware that they are liable to change between versions
6213		 * (check the upgrade notes).
6214		 *  @namespace
6215		 */
6216		this.oApi = {
6217			"_fnExternApiFunc": _fnExternApiFunc,
6218			"_fnInitialise": _fnInitialise,
6219			"_fnInitComplete": _fnInitComplete,
6220			"_fnLanguageCompat": _fnLanguageCompat,
6221			"_fnAddColumn": _fnAddColumn,
6222			"_fnColumnOptions": _fnColumnOptions,
6223			"_fnAddData": _fnAddData,
6224			"_fnCreateTr": _fnCreateTr,
6225			"_fnGatherData": _fnGatherData,
6226			"_fnBuildHead": _fnBuildHead,
6227			"_fnDrawHead": _fnDrawHead,
6228			"_fnDraw": _fnDraw,
6229			"_fnReDraw": _fnReDraw,
6230			"_fnAjaxUpdate": _fnAjaxUpdate,
6231			"_fnAjaxParameters": _fnAjaxParameters,
6232			"_fnAjaxUpdateDraw": _fnAjaxUpdateDraw,
6233			"_fnServerParams": _fnServerParams,
6234			"_fnAddOptionsHtml": _fnAddOptionsHtml,
6235			"_fnFeatureHtmlTable": _fnFeatureHtmlTable,
6236			"_fnScrollDraw": _fnScrollDraw,
6237			"_fnAdjustColumnSizing": _fnAdjustColumnSizing,
6238			"_fnFeatureHtmlFilter": _fnFeatureHtmlFilter,
6239			"_fnFilterComplete": _fnFilterComplete,
6240			"_fnFilterCustom": _fnFilterCustom,
6241			"_fnFilterColumn": _fnFilterColumn,
6242			"_fnFilter": _fnFilter,
6243			"_fnBuildSearchArray": _fnBuildSearchArray,
6244			"_fnBuildSearchRow": _fnBuildSearchRow,
6245			"_fnFilterCreateSearch": _fnFilterCreateSearch,
6246			"_fnDataToSearch": _fnDataToSearch,
6247			"_fnSort": _fnSort,
6248			"_fnSortAttachListener": _fnSortAttachListener,
6249			"_fnSortingClasses": _fnSortingClasses,
6250			"_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate,
6251			"_fnPageChange": _fnPageChange,
6252			"_fnFeatureHtmlInfo": _fnFeatureHtmlInfo,
6253			"_fnUpdateInfo": _fnUpdateInfo,
6254			"_fnFeatureHtmlLength": _fnFeatureHtmlLength,
6255			"_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing,
6256			"_fnProcessingDisplay": _fnProcessingDisplay,
6257			"_fnVisibleToColumnIndex": _fnVisibleToColumnIndex,
6258			"_fnColumnIndexToVisible": _fnColumnIndexToVisible,
6259			"_fnNodeToDataIndex": _fnNodeToDataIndex,
6260			"_fnVisbleColumns": _fnVisbleColumns,
6261			"_fnCalculateEnd": _fnCalculateEnd,
6262			"_fnConvertToWidth": _fnConvertToWidth,
6263			"_fnCalculateColumnWidths": _fnCalculateColumnWidths,
6264			"_fnScrollingWidthAdjust": _fnScrollingWidthAdjust,
6265			"_fnGetWidestNode": _fnGetWidestNode,
6266			"_fnGetMaxLenString": _fnGetMaxLenString,
6267			"_fnStringToCss": _fnStringToCss,
6268			"_fnDetectType": _fnDetectType,
6269			"_fnSettingsFromNode": _fnSettingsFromNode,
6270			"_fnGetDataMaster": _fnGetDataMaster,
6271			"_fnGetTrNodes": _fnGetTrNodes,
6272			"_fnGetTdNodes": _fnGetTdNodes,
6273			"_fnEscapeRegex": _fnEscapeRegex,
6274			"_fnDeleteIndex": _fnDeleteIndex,
6275			"_fnReOrderIndex": _fnReOrderIndex,
6276			"_fnColumnOrdering": _fnColumnOrdering,
6277			"_fnLog": _fnLog,
6278			"_fnClearTable": _fnClearTable,
6279			"_fnSaveState": _fnSaveState,
6280			"_fnLoadState": _fnLoadState,
6281			"_fnCreateCookie": _fnCreateCookie,
6282			"_fnReadCookie": _fnReadCookie,
6283			"_fnDetectHeader": _fnDetectHeader,
6284			"_fnGetUniqueThs": _fnGetUniqueThs,
6285			"_fnScrollBarWidth": _fnScrollBarWidth,
6286			"_fnApplyToChildren": _fnApplyToChildren,
6287			"_fnMap": _fnMap,
6288			"_fnGetRowData": _fnGetRowData,
6289			"_fnGetCellData": _fnGetCellData,
6290			"_fnSetCellData": _fnSetCellData,
6291			"_fnGetObjectDataFn": _fnGetObjectDataFn,
6292			"_fnSetObjectDataFn": _fnSetObjectDataFn,
6293			"_fnApplyColumnDefs": _fnApplyColumnDefs,
6294			"_fnBindAction": _fnBindAction,
6295			"_fnExtend": _fnExtend,
6296			"_fnCallbackReg": _fnCallbackReg,
6297			"_fnCallbackFire": _fnCallbackFire,
6298			"_fnJsonString": _fnJsonString,
6299			"_fnRender": _fnRender,
6300			"_fnNodeToColumnIndex": _fnNodeToColumnIndex,
6301			"_fnInfoMacros": _fnInfoMacros,
6302			"_fnBrowserDetect": _fnBrowserDetect,
6303			"_fnGetColumns": _fnGetColumns
6304		};
6305		
6306		$.extend( DataTable.ext.oApi, this.oApi );
6307		
6308		for ( var sFunc in DataTable.ext.oApi )
6309		{
6310			if ( sFunc )
6311			{
6312				this[sFunc] = _fnExternApiFunc(sFunc);
6313			}
6314		}
6315		
6316		
6317		var _that = this;
6318		this.each(function() {
6319			var i=0, iLen, j, jLen, k, kLen;
6320			var sId = this.getAttribute( 'data-id' )?this.getAttribute( 'data-id' ):this.getAttribute( 'id' );
6321			var bInitHandedOff = false;
6322			var bUsePassedData = false;
6323			
6324			
6325			/* Sanity check */
6326			if ( this.nodeName.toLowerCase() != 'table' )
6327			{
6328				_fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+
6329					"table: "+this.nodeName );
6330				return;
6331			}
6332			
6333			/* Check to see if we are re-initialising a table */
6334			for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
6335			{
6336				/* Base check on table node */
6337				if ( DataTable.settings[i].nTable == this )
6338				{
6339					if ( oInit === undefined || oInit.bRetrieve )
6340					{
6341						return DataTable.settings[i].oInstance;
6342					}
6343					else if ( oInit.bDestroy )
6344					{
6345						DataTable.settings[i].oInstance.fnDestroy();
6346						break;
6347					}
6348					else
6349					{
6350						_fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+
6351							"To retrieve the DataTables object for this table, pass no arguments or see "+
6352							"the docs for bRetrieve and bDestroy" );
6353						return;
6354					}
6355				}
6356				
6357				/* If the element we are initialising has the same ID as a table which was previously
6358				 * initialised, but the table nodes don't match (from before) then we destroy the old
6359				 * instance by simply deleting it. This is under the assumption that the table has been
6360				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6361				 */
6362				if ( DataTable.settings[i].sTableId == this.id )
6363				{
6364					DataTable.settings.splice( i, 1 );
6365					break;
6366				}
6367			}
6368			
6369			/* Ensure the table has an ID - required for accessibility */
6370			if ( sId === null || sId === "" )
6371			{
6372				sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);
6373				this.id = sId;
6374			}
6375			
6376			/* Create the settings object for this table and set some of the default parameters */
6377			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6378				"nTable":        this,
6379				"oApi":          _that.oApi,
6380				"oInit":         oInit,
6381				"sDestroyWidth": $(this).width(),
6382				"sInstance":     sId,
6383				"sTableId":      sId
6384			} );
6385			DataTable.settings.push( oSettings );
6386			
6387			// Need to add the instance after the instance after the settings object has been added
6388			// to the settings array, so we can self reference the table instance if more than one
6389			oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6390			
6391			/* Setting up the initialisation object */
6392			if ( !oInit )
6393			{
6394				oInit = {};
6395			}
6396			
6397			// Backwards compatibility, before we apply all the defaults
6398			if ( oInit.oLanguage )
6399			{
6400				_fnLanguageCompat( oInit.oLanguage );
6401			}
6402			
6403			oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );
6404			
6405			// Map the initialisation options onto the settings object
6406			_fnMap( oSettings.oFeatures, oInit, "bPaginate" );
6407			_fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
6408			_fnMap( oSettings.oFeatures, oInit, "bFilter" );
6409			_fnMap( oSettings.oFeatures, oInit, "bSort" );
6410			_fnMap( oSettings.oFeatures, oInit, "bInfo" );
6411			_fnMap( oSettings.oFeatures, oInit, "bProcessing" );
6412			_fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
6413			_fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
6414			_fnMap( oSettings.oFeatures, oInit, "bServerSide" );
6415			_fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
6416			_fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
6417			_fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
6418			_fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
6419			_fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
6420			_fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
6421			_fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
6422			_fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
6423			_fnMap( oSettings, oInit, "asStripeClasses" );
6424			_fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
6425			_fnMap( oSettings, oInit, "fnServerData" );
6426			_fnMap( oSettings, oInit, "fnFormatNumber" );
6427			_fnMap( oSettings, oInit, "sServerMethod" );
6428			_fnMap( oSettings, oInit, "aaSorting" );
6429			_fnMap( oSettings, oInit, "aaSortingFixed" );
6430			_fnMap( oSettings, oInit, "aLengthMenu" );
6431			_fnMap( oSettings, oInit, "sPaginationType" );
6432			_fnMap( oSettings, oInit, "sAjaxSource" );
6433			_fnMap( oSettings, oInit, "sAjaxDataProp" );
6434			_fnMap( oSettings, oInit, "iCookieDuration" );
6435			_fnMap( oSettings, oInit, "sCookiePrefix" );
6436			_fnMap( oSettings, oInit, "sDom" );
6437			_fnMap( oSettings, oInit, "bSortCellsTop" );
6438			_fnMap( oSettings, oInit, "iTabIndex" );
6439			_fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
6440			_fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
6441			_fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
6442			_fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
6443			_fnMap( oSettings, oInit, "fnCookieCallback" );
6444			_fnMap( oSettings, oInit, "fnStateLoad" );
6445			_fnMap( oSettings, oInit, "fnStateSave" );
6446			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6447			
6448			/* Callback functions which are array driven */
6449			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
6450			_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
6451			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
6452			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
6453			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
6454			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
6455			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
6456			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
6457			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
6458			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
6459			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
6460			
6461			if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
6462				   oSettings.oFeatures.bSortClasses )
6463			{
6464				/* Enable sort classes for server-side processing. Safe to do it here, since server-side
6465				 * processing must be enabled by the developer
6466				 */
6467				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );
6468			}
6469			else if ( oSettings.oFeatures.bDeferRender )
6470			{
6471				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );
6472			}
6473			
6474			if ( oInit.bJQueryUI )
6475			{
6476				/* Use the JUI classes object for display. You could clone the oStdClasses object if 
6477				 * you want to have multiple tables with multiple independent classes 
6478				 */
6479				$.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );
6480				
6481				if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )
6482				{
6483					/* Set the DOM to use a layout suitable for jQuery UI's theming */
6484					oSettings.sDom = '<"H"lfr>t<"F"ip>';
6485				}
6486			}
6487			else
6488			{
6489				$.extend( oSettings.oClasses, DataTable.ext.oStdClasses );
6490			}
6491			$(this).addClass( oSettings.oClasses.sTable );
6492			
6493			/* Calculate the scroll bar width and cache it for use later on */
6494			if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6495			{
6496				oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6497			}
6498			
6499			if ( oSettings.iInitDisplayStart === undefined )
6500			{
6501				/* Display start point, taking into account the save saving */
6502				oSettings.iInitDisplayStart = oInit.iDisplayStart;
6503				oSettings._iDisplayStart = oInit.iDisplayStart;
6504			}
6505			
6506			/* Must be done after everything which can be overridden by a cookie! */
6507			if ( oInit.bStateSave )
6508			{
6509				oSettings.oFeatures.bStateSave = true;
6510				_fnLoadState( oSettings, oInit );
6511				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6512			}
6513			
6514			if ( oInit.iDeferLoading !== null )
6515			{
6516				oSettings.bDeferLoading = true;
6517				var tmp = $.isArray( oInit.iDeferLoading );
6518				oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6519				oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6520			}
6521			
6522			if ( oInit.aaData !== null )
6523			{
6524				bUsePassedData = true;
6525			}
6526			
6527			/* Language definitions */
6528			if ( oInit.oLanguage.sUrl !== "" )
6529			{
6530				/* Get the language definitions from a file - because this Ajax call makes the language
6531				 * get async to the remainder of this function we use bInitHandedOff to indicate that 
6532				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6533				 */
6534				oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
6535				$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
6536					_fnLanguageCompat( json );
6537					$.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
6538					_fnInitialise( oSettings );
6539				} );
6540				bInitHandedOff = true;
6541			}
6542			else
6543			{
6544				$.extend( true, oSettings.oLanguage, oInit.oLanguage );
6545			}
6546			
6547			
6548			/*
6549			 * Stripes
6550			 */
6551			if ( oInit.asStripeClasses === null )
6552			{
6553				oSettings.asStripeClasses =[
6554					oSettings.oClasses.sStripeOdd,
6555					oSettings.oClasses.sStripeEven
6556				];
6557			}
6558			
6559			/* Remove row stripe classes if they are already on the table row */
6560			iLen=oSettings.asStripeClasses.length;
6561			oSettings.asDestroyStripes = [];
6562			if (iLen)
6563			{
6564				var bStripeRemove = false;
6565				var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')');
6566				for ( i=0 ; i<iLen ; i++ )
6567				{
6568					if ( anRows.hasClass( oSettings.asStripeClasses[i] ) )
6569					{
6570						bStripeRemove = true;
6571						
6572						/* Store the classes which we are about to remove so they can be re-added on destroy */
6573						oSettings.asDestroyStripes.push( oSettings.asStripeClasses[i] );
6574					}
6575				}
6576				
6577				if ( bStripeRemove )
6578				{
6579					anRows.removeClass( oSettings.asStripeClasses.join(' ') );
6580				}
6581			}
6582			
6583			/*
6584			 * Columns
6585			 * See if we should load columns automatically or use defined ones
6586			 */
6587			var anThs = [];
6588			var aoColumnsInit;
6589			var nThead = this.getElementsByTagName('thead');
6590			if ( nThead.length !== 0 )
6591			{
6592				_fnDetectHeader( oSettings.aoHeader, nThead[0] );
6593				anThs = _fnGetUniqueThs( oSettings );
6594			}
6595			
6596			/* If not given a column array, generate one with nulls */
6597			if ( oInit.aoColumns === null )
6598			{
6599				aoColumnsInit = [];
6600				for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6601				{
6602					aoColumnsInit.push( null );
6603				}
6604			}
6605			else
6606			{
6607				aoColumnsInit = oInit.aoColumns;
6608			}
6609			
6610			/* Add the columns */
6611			for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6612			{
6613				/* Short cut - use the loop to check if we have column visibility state to restore */
6614				if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen )
6615				{
6616					if ( aoColumnsInit[i] === null )
6617					{
6618						aoColumnsInit[i] = {};
6619					}
6620					aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
6621				}
6622				
6623				_fnAddColumn( oSettings, anThs ? anThs[i] : null );
6624			}
6625			
6626			/* Apply the column definitions */
6627			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6628				_fnColumnOptions( oSettings, iCol, oDef );
6629			} );
6630			
6631			
6632			/*
6633			 * Sorting
6634			 * Check the aaSorting array
6635			 */
6636			for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
6637			{
6638				if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
6639				{
6640					oSettings.aaSorting[i][0] = 0;
6641				}
6642				var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
6643				
6644				/* Add a default sorting index */
6645				if ( oSettings.aaSorting[i][2] === undefined )
6646				{
6647					oSettings.aaSorting[i][2] = 0;
6648				}
6649				
6650				/* If aaSorting is not defined, then we use the first indicator in asSorting */
6651				if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined )
6652				{
6653					oSettings.aaSorting[i][1] = oColumn.asSorting[0];
6654				}
6655				
6656				/* Set the current sorting index based on aoColumns.asSorting */
6657				for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
6658				{
6659					if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
6660					{
6661						oSettings.aaSorting[i][2] = j;
6662						break;
6663					}
6664				}
6665			}
6666				
6667			/* Do a first pass on the sorting classes (allows any size changes to be taken into
6668			 * account, and also will apply sorting disabled classes if disabled
6669			 */
6670			_fnSortingClasses( oSettings );
6671			
6672			
6673			/*
6674			 * Final init
6675			 * Cache the header, body and footer as required, creating them if needed
6676			 */
6677			
6678			/* Browser support detection */
6679			_fnBrowserDetect( oSettings );
6680			
6681			// Work around for Webkit bug 83867 - store the caption-side before removing from doc
6682			var captions = $(this).children('caption').each( function () {
6683				this._captionSide = $(this).css('caption-side');
6684			} );
6685			
6686			var thead = $(this).children('thead');
6687			if ( thead.length === 0 )
6688			{
6689				thead = [ document.createElement( 'thead' ) ];
6690				this.appendChild( thead[0] );
6691			}
6692			oSettings.nTHead = thead[0];
6693			
6694			var tbody = $(this).children('tbody');
6695			if ( tbody.length === 0 )
6696			{
6697				tbody = [ document.createElement( 'tbody' ) ];
6698				this.appendChild( tbody[0] );
6699			}
6700			oSettings.nTBody = tbody[0];
6701			oSettings.nTBody.setAttribute( "role", "alert" );
6702			oSettings.nTBody.setAttribute( "aria-live", "polite" );
6703			oSettings.nTBody.setAttribute( "aria-relevant", "all" );
6704			
6705			var tfoot = $(this).children('tfoot');
6706			if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6707			{
6708				// If we are a scrolling table, and no footer has been given, then we need to create
6709				// a tfoot element for the caption element to be appended to
6710				tfoot = [ document.createElement( 'tfoot' ) ];
6711				this.appendChild( tfoot[0] );
6712			}
6713			
6714			if ( tfoot.length > 0 )
6715			{
6716				oSettings.nTFoot = tfoot[0];
6717				_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6718			}
6719			
6720			/* Check if there is data passing into the constructor */
6721			if ( bUsePassedData )
6722			{
6723				for ( i=0 ; i<oInit.aaData.length ; i++ )
6724				{
6725					_fnAddData( oSettings, oInit.aaData[ i ] );
6726				}
6727			}
6728			else
6729			{
6730				/* Grab the data from the page */
6731				_fnGatherData( oSettings );
6732			}
6733			
6734			/* Copy the data index array */
6735			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6736			
6737			/* Initialisation complete - table can be drawn */
6738			oSettings.bInitialised = true;
6739			
6740			/* Check if we need to initialise the table (it might not have been handed off to the
6741			 * language processor)
6742			 */
6743			if ( bInitHandedOff === false )
6744			{
6745				_fnInitialise( oSettings );
6746			}
6747		} );
6748		_that = null;
6749		return this;
6750	};
6751
6752	
6753	
6754	/**
6755	 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6756	 * to ensure compatibility.
6757	 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6758	 *    formats "X" and "X.Y" are also acceptable.
6759	 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
6760	 *    version, or false if this version of DataTales is not suitable
6761	 *  @static
6762	 *  @dtopt API-Static
6763	 *
6764	 *  @example
6765	 *    alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );
6766	 */
6767	DataTable.fnVersionCheck = function( sVersion )
6768	{
6769		/* This is cheap, but effective */
6770		var fnZPad = function (Zpad, count)
6771		{
6772			while(Zpad.length < count) {
6773				Zpad += '0';
6774			}
6775			return Zpad;
6776		};
6777		var aThis = DataTable.ext.sVersion.split('.');
6778		var aThat = sVersion.split('.');
6779		var sThis = '', sThat = '';
6780		
6781		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
6782		{
6783			sThis += fnZPad( aThis[i], 3 );
6784			sThat += fnZPad( aThat[i], 3 );
6785		}
6786		
6787		return parseInt(sThis, 10) >= parseInt(sThat, 10);
6788	};
6789	
6790	
6791	/**
6792	 * Check if a TABLE node is a DataTable table already or not.
6793	 *  @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other
6794	 *    node types can be passed in, but will always return false).
6795	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
6796	 *  @static
6797	 *  @dtopt API-Static
6798	 *
6799	 *  @example
6800	 *    var ex = document.getElementById('example');
6801	 *    if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {
6802	 *      $(ex).dataTable();
6803	 *    }
6804	 */
6805	DataTable.fnIsDataTable = function ( nTable )
6806	{
6807		var o = DataTable.settings;
6808	
6809		for ( var i=0 ; i<o.length ; i++ )
6810		{
6811			if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable )
6812			{
6813				return true;
6814			}
6815		}
6816	
6817		return false;
6818	};
6819	
6820	
6821	/**
6822	 * Get all DataTable tables that have been initialised - optionally you can select to
6823	 * get only currently visible tables.
6824	 *  @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or 
6825	 *    visible tables only.
6826	 *  @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables
6827	 *  @static
6828	 *  @dtopt API-Static
6829	 *
6830	 *  @example
6831	 *    var table = $.fn.dataTable.fnTables(true);
6832	 *    if ( table.length > 0 ) {
6833	 *      $(table).dataTable().fnAdjustColumnSizing();
6834	 *    }
6835	 */
6836	DataTable.fnTables = function ( bVisible )
6837	{
6838		var out = [];
6839	
6840		jQuery.each( DataTable.settings, function (i, o) {
6841			if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )
6842			{
6843				out.push( o.nTable );
6844			}
6845		} );
6846	
6847		return out;
6848	};
6849	
6850
6851	/**
6852	 * Version string for plug-ins to check compatibility. Allowed format is
6853	 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
6854	 * e are optional
6855	 *  @member
6856	 *  @type string
6857	 *  @default Version number
6858	 */
6859	DataTable.version = "1.9.4";
6860
6861	/**
6862	 * Private data store, containing all of the settings objects that are created for the
6863	 * tables on a given page.
6864	 * 
6865	 * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i> 
6866	 * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>.
6867	 *  @member
6868	 *  @type array
6869	 *  @default []
6870	 *  @private
6871	 */
6872	DataTable.settings = [];
6873
6874	/**
6875	 * Object models container, for the various models that DataTables has available
6876	 * to it. These models define the objects that are used to hold the active state 
6877	 * and configuration of the table.
6878	 *  @namespace
6879	 */
6880	DataTable.models = {};
6881	
6882	
6883	/**
6884	 * DataTables extension options and plug-ins. This namespace acts as a collection "area"
6885	 * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
6886	 * of the build in methods use this method to provide their own capabilities (sorting methods
6887	 * for example).
6888	 * 
6889	 * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed
6890	 * and modified by plug-ins.
6891	 *  @namespace
6892	 */
6893	DataTable.models.ext = {
6894		/**
6895		 * Plug-in filtering functions - this method of filtering is complimentary to the default
6896		 * type based filtering, and a lot more comprehensive as it allows you complete control
6897		 * over the filtering logic. Each element in this array is a function (parameters
6898		 * described below) that is called for every row in the table, and your logic decides if
6899		 * it should be included in the filtered data set or not.
6900		 *   <ul>
6901		 *     <li>
6902		 *       Function input parameters:
6903		 *       <ul>
6904		 *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
6905		 *         <li>{array|object} Data for the row to be processed (same as the original format
6906		 *           that was passed in as the data source, or an array from a DOM data source</li>
6907		 *         <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can
6908		 *           be useful to retrieve the TR element if you need DOM interaction.</li>
6909		 *       </ul>
6910		 *     </li>
6911		 *     <li>
6912		 *       Function return:
6913		 *       <ul>
6914		 *         <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>
6915		 *       </ul>
6916		 *     </il>
6917		 *   </ul>
6918		 *  @type array
6919		 *  @default []
6920		 *
6921		 *  @example
6922		 *    // The following example shows custom filtering being applied to the fourth column (i.e.
6923		 *    // the aData[3] index) based on two input values from the end-user, matching the data in 
6924		 *    // a certain range.
6925		 *    $.fn.dataTableExt.afnFiltering.push(
6926		 *      function( oSettings, aData, iDataIndex ) {
6927		 *        var iMin = document.getElementById('min').value * 1;
6928		 *        var iMax = document.getElementById('max').value * 1;
6929		 *        var iVersion = aData[3] == "-" ? 0 : aData[3]*1;
6930		 *        if ( iMin == "" && iMax == "" ) {
6931		 *          return true;
6932		 *        }
6933		 *        else if ( iMin == "" && iVersion < iMax ) {
6934		 *          return true;
6935		 *        }
6936		 *        else if ( iMin < iVersion && "" == iMax ) {
6937		 *          return true;
6938		 *        }
6939		 *        else if ( iMin < iVersion && iVersion < iMax ) {
6940		 *          return true;
6941		 *        }
6942		 *        return false;
6943		 *      }
6944		 *    );
6945		 */
6946		"afnFiltering": [],
6947	
6948	
6949		/**
6950		 * Plug-in sorting functions - this method of sorting is complimentary to the default type
6951		 * based sorting that DataTables does automatically, allowing much greater control over the
6952		 * the data that is being used to sort a column. This is useful if you want to do sorting
6953		 * based on live data (for example the contents of an 'input' element) rather than just the
6954		 * static string that DataTables knows of. The way these plug-ins work is that you create
6955		 * an array of the values you wish to be sorted for the column in question and then return
6956		 * that array. Which pre-sorting function is run here depends on the sSortDataType parameter
6957		 * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort 
6958		 * data.
6959		 *   <ul>
6960	     *     <li>
6961	     *       Function input parameters:
6962	     *       <ul>
6963		 *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
6964	     *         <li>{int} Target column index</li>
6965	     *       </ul>
6966	     *     </li>
6967		 *     <li>
6968		 *       Function return:
6969		 *       <ul>
6970		 *         <li>{array} Data for the column to be sorted upon</li>
6971		 *       </ul>
6972		 *     </il>
6973		 *   </ul>
6974		 *  
6975		 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
6976		 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
6977		 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
6978		 * prepare the data as required for the different types. As such, this method is deprecated.
6979		 *  @type array
6980		 *  @default []
6981		 *  @deprecated
6982		 *
6983		 *  @example
6984		 *    // Updating the cached sorting information with user entered values in HTML input elements
6985		 *    jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
6986		 *    {
6987		 *      var aData = [];
6988		 *      $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
6989		 *        aData.push( this.value );
6990		 *      } );
6991		 *      return aData;
6992		 *    }
6993		 */
6994		"afnSortData": [],
6995	
6996	
6997		/**
6998		 * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are
6999		 * available to DataTables. These feature plug-ins are accessible through the sDom initialisation
7000		 * option. As such, each feature plug-in must describe a function that is used to initialise
7001		 * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name
7002		 * of the feature (sFeature). Thus the objects attached to this method must provide:
7003		 *   <ul>
7004		 *     <li>{function} fnInit Initialisation of the plug-in
7005		 *       <ul>
7006	     *         <li>
7007	     *           Function input parameters:
7008	     *           <ul>
7009		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
7010	     *           </ul>
7011	     *         </li>
7012		 *         <li>
7013		 *           Function return:
7014		 *           <ul>
7015		 *             <li>{node|null} The element which contains your feature. Note that the return
7016		 *                may also be void if your plug-in does not require to inject any DOM elements 
7017		 *                into DataTables control (sDom) - for example this might be useful when 
7018		 *                developing a plug-in which allows table control via keyboard entry.</li>
7019		 *           </ul>
7020		 *         </il>
7021		 *       </ul>
7022		 *     </li>
7023		 *     <li>{character} cFeature Character that will be matched in sDom - case sensitive</li>
7024		 *     <li>{string} sFeature Feature name</li>
7025		 *   </ul>
7026		 *  @type array
7027		 *  @default []
7028		 * 
7029		 *  @example
7030		 *    // How TableTools initialises itself.
7031		 *    $.fn.dataTableExt.aoFeatures.push( {
7032		 *      "fnInit": function( oSettings ) {
7033		 *        return new TableTools( { "oDTSettings": oSettings } );
7034		 *      },
7035		 *      "cFeature": "T",
7036		 *      "sFeature": "TableTools"
7037		 *    } );
7038		 */
7039		"aoFeatures": [],
7040	
7041	
7042		/**
7043		 * Type detection plug-in functions - DataTables utilises types to define how sorting and
7044		 * filtering behave, and types can be either  be defined by the developer (sType for the
7045		 * column) or they can be automatically detected by the methods in this array. The functions
7046		 * defined in the array are quite simple, taking a single parameter (the data to analyse) 
7047		 * and returning the type if it is a known type, or null otherwise.
7048		 *   <ul>
7049	     *     <li>
7050	     *       Function input parameters:
7051	     *       <ul>
7052		 *         <li>{*} Data from the column cell to be analysed</li>
7053	     *       </ul>
7054	     *     </li>
7055		 *     <li>
7056		 *       Function return:
7057		 *       <ul>
7058		 *         <li>{string|null} Data type detected, or null if unknown (and thus pass it
7059		 *           on to the other type detection functions.</li>
7060		 *       </ul>
7061		 *     </il>
7062		 *   </ul>
7063		 *  @type array
7064		 *  @default []
7065		 *  
7066		 *  @example
7067		 *    // Currency type detection plug-in:
7068		 *    jQuery.fn.dataTableExt.aTypes.push(
7069		 *      function ( sData ) {
7070		 *        var sValidChars = "0123456789.-";
7071		 *        var Char;
7072		 *        
7073		 *        // Check the numeric part
7074		 *        for ( i=1 ; i<sData.length ; i++ ) {
7075		 *          Char = sData.charAt(i); 
7076		 *          if (sValidChars.indexOf(Char) == -1) {
7077		 *            return null;
7078		 *          }
7079		 *        }
7080		 *        
7081		 *        // Check prefixed by currency
7082		 *        if ( sData.charAt(0) == '$' || sData.charAt(0) == '&pound;' ) {
7083		 *          return 'currency';
7084		 *        }
7085		 *        return null;
7086		 *      }
7087		 *    );
7088		 */
7089		"aTypes": [],
7090	
7091	
7092		/**
7093		 * Provide a common method for plug-ins to check the version of DataTables being used, 
7094		 * in order to ensure compatibility.
7095		 *  @type function
7096		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note 
7097		 *    that the formats "X" and "X.Y" are also acceptable.
7098		 *  @returns {boolean} true if this version of DataTables is greater or equal to the 
7099		 *    required version, or false if this version of DataTales is not suitable
7100		 *
7101		 *  @example
7102		 *    $(document).ready(function() {
7103		 *      var oTable = $('#example').dataTable();
7104		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
7105		 *    } );
7106		 */
7107		"fnVersionCheck": DataTable.fnVersionCheck,
7108	
7109	
7110		/**
7111		 * Index for what 'this' index API functions should use
7112		 *  @type int
7113		 *  @default 0
7114		 */
7115		"iApiIndex": 0,
7116	
7117	
7118		/**
7119		 * Pre-processing of filtering data plug-ins - When you assign the sType for a column
7120		 * (or have it automatically detected for you by DataTables or a type detection plug-in), 
7121		 * you will typically be using this for custom sorting, but it can also be used to provide 
7122		 * custom filtering by allowing you to pre-processing the data and returning the data in
7123		 * the format that should be filtered upon. This is done by adding functions this object 
7124		 * with a parameter name which matches the sType for that target column. This is the
7125		 * corollary of <i>afnSortData</i> for filtering data.
7126		 *   <ul>
7127	     *     <li>
7128	     *       Function input parameters:
7129	     *       <ul>
7130		 *         <li>{*} Data from the column cell to be prepared for filtering</li>
7131	     *       </ul>
7132	     *     </li>
7133		 *     <li>
7134		 *       Function return:
7135		 *       <ul>
7136		 *         <li>{string|null} Formatted string that will be used for the filtering.</li>
7137		 *       </ul>
7138		 *     </il>
7139		 *   </ul>
7140		 * 
7141		 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
7142		 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
7143		 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
7144		 * prepare the data as required for the different types. As such, this method is deprecated.
7145		 *  @type object
7146		 *  @default {}
7147		 *  @deprecated
7148		 *
7149		 *  @example
7150		 *    $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {
7151		 *      return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
7152		 *    }
7153		 */
7154		"ofnSearch": {},
7155	
7156	
7157		/**
7158		 * Container for all private functions in DataTables so they can be exposed externally
7159		 *  @type object
7160		 *  @default {}
7161		 */
7162		"oApi": {},
7163	
7164	
7165		/**
7166		 * Storage for the various classes that DataTables uses
7167		 *  @type object
7168		 *  @default {}
7169		 */
7170		"oStdClasses": {},
7171		
7172	
7173		/**
7174		 * Storage for the various classes that DataTables uses - jQuery UI suitable
7175		 *  @type object
7176		 *  @default {}
7177		 */
7178		"oJUIClasses": {},
7179	
7180	
7181		/**
7182		 * Pagination plug-in methods - The style and controls of the pagination can significantly 
7183		 * impact on how the end user interacts with the data in your table, and DataTables allows 
7184		 * the addition of pagination controls by extending this object, which can then be enabled
7185		 * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that
7186		 * is added is an object (the property name of which is what <i>sPaginationType</i> refers
7187		 * to) that has two properties, both methods that are used by DataTables to update the
7188		 * control's state.
7189		 *   <ul>
7190		 *     <li>
7191		 *       fnInit -  Initialisation of the paging controls. Called only during initialisation 
7192		 *         of the table. It is expected that this function will add the required DOM elements 
7193		 *         to the page for the paging controls to work. The element pointer 
7194		 *         'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging 
7195		 *         controls (note that this is a 2D array to allow for multiple instances of each 
7196		 *         DataTables DOM element). It is suggested that you add the controls to this element 
7197		 *         as children
7198		 *       <ul>
7199	     *         <li>
7200	     *           Function input parameters:
7201	     *           <ul>
7202		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
7203		 *             <li>{node} Container into which the pagination controls must be inserted</li>
7204		 *             <li>{function} Draw callback function - whenever the controls cause a page
7205		 *               change, this method must be called to redraw the table.</li>
7206	     *           </ul>
7207	     *         </li>
7208		 *         <li>
7209		 *           Function return:
7210		 *           <ul>
7211		 *             <li>No return required</li>
7212		 *           </ul>
7213		 *         </il>
7214		 *       </ul>
7215		 *     </il>
7216		 *     <li>
7217		 *       fnInit -  This function is called whenever the paging status of the table changes and is
7218		 *         typically used to update classes and/or text of the paging controls to reflex the new 
7219		 *         status.
7220		 *       <ul>
7221	     *         <li>
7222	     *           Function input parameters:
7223	     *           <ul>
7224		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
7225		 *             <li>{function} Draw callback function - in case you need to redraw the table again
7226		 *               or attach new event listeners</li>
7227	     *           </ul>
7228	     *         </li>
7229		 *         <li>
7230		 *           Function return:
7231		 *           <ul>
7232		 *             <li>No return required</li>
7233		 *           </ul>
7234		 *         </il>
7235		 *       </ul>
7236		 *     </il>
7237		 *   </ul>
7238		 *  @type object
7239		 *  @default {}
7240		 *
7241		 *  @example
7242		 *    $.fn.dataTableExt.oPagination.four_button = {
7243		 *      "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) {
7244		 *        nFirst = document.createElement( 'span' );
7245		 *        nPrevious = document.createElement( 'span' );
7246		 *        nNext = document.createElement( 'span' );
7247		 *        nLast = document.createElement( 'span' );
7248		 *        
7249		 *        nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
7250		 *        nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
7251		 *        nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
7252		 *        nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );
7253		 *        
7254		 *        nFirst.className = "paginate_button first";
7255		 *        nPrevious.className = "paginate_button previous";
7256		 *        nNext.className="paginate_button next";
7257		 *        nLast.className = "paginate_button last";
7258		 *        
7259		 *        nPaging.appendChild( nFirst );
7260		 *        nPaging.appendChild( nPrevious );
7261		 *        nPaging.appendChild( nNext );
7262		 *        nPaging.appendChild( nLast );
7263		 *        
7264		 *        $(nFirst).click( function () {
7265		 *          oSettings.oApi._fnPageChange( oSettings, "first" );
7266		 *          fnCallbackDraw( oSettings );
7267		 *        } );
7268		 *        
7269		 *        $(nPrevious).click( function() {
7270		 *          oSettings.oApi._fnPageChange( oSettings, "previous" );
7271		 *          fnCallbackDraw( oSettings );
7272		 *        } );
7273		 *        
7274		 *        $(nNext).click( function() {
7275		 *          oSettings.oApi._fnPageChange( oSettings, "next" );
7276		 *          fnCallbackDraw( oSettings );
7277		 *        } );
7278		 *        
7279		 *        $(nLast).click( function() {
7280		 *          oSettings.oApi._fnPageChange( oSettings, "last" );
7281		 *          fnCallbackDraw( oSettings );
7282		 *        } );
7283		 *        
7284		 *        $(nFirst).bind( 'selectstart', function () { return false; } );
7285		 *        $(nPrevious).bind( 'selectstart', function () { return false; } );
7286		 *        $(nNext).bind( 'selectstart', function () { return false; } );
7287		 *        $(nLast).bind( 'selectstart', function () { return false; } );
7288		 *      },
7289		 *      
7290		 *      "fnUpdate": function ( oSettings, fnCallbackDraw ) {
7291		 *        if ( !oSettings.aanFeatures.p ) {
7292		 *          return;
7293		 *        }
7294		 *        
7295		 *        // Loop over each instance of the pager
7296		 *        var an = oSettings.aanFeatures.p;
7297		 *        for ( var i=0, iLen=an.length ; i<iLen ; i++ ) {
7298		 *          var buttons = an[i].getElementsByTagName('span');
7299		 *          if ( oSettings._iDisplayStart === 0 ) {
7300		 *            buttons[0].className = "paginate_disabled_previous";
7301		 *            buttons[1].className = "paginate_disabled_previous";
7302		 *          }
7303		 *          else {
7304		 *            buttons[0].className = "paginate_enabled_previous";
7305		 *            buttons[1].className = "paginate_enabled_previous";
7306		 *          }
7307		 *          
7308		 *          if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {
7309		 *            buttons[2].className = "paginate_disabled_next";
7310		 *            buttons[3].className = "paginate_disabled_next";
7311		 *          }
7312		 *          else {
7313		 *            buttons[2].className = "paginate_enabled_next";
7314		 *            buttons[3].className = "paginate_enabled_next";
7315		 *          }
7316		 *        }
7317		 *      }
7318		 *    };
7319		 */
7320		"oPagination": {},
7321	
7322	
7323		/**
7324		 * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the
7325		 * data column (you can add your own type detection functions, or override automatic 
7326		 * detection using sType). With this specific type given to the column, DataTables will 
7327		 * apply the required sort from the functions in the object. Each sort type must provide
7328		 * two mandatory methods, one each for ascending and descending sorting, and can optionally
7329		 * provide a pre-formatting method that will help speed up sorting by allowing DataTables
7330		 * to pre-format the sort data only once (rather than every time the actual sort functions
7331		 * are run). The two sorting functions are typical Javascript sort methods:
7332		 *   <ul>
7333	     *     <li>
7334	     *       Function input parameters:
7335	     *       <ul>
7336		 *         <li>{*} Data to compare to the second parameter</li>
7337		 *         <li>{*} Data to compare to the first parameter</li>
7338	     *       </ul>
7339	     *     </li>
7340		 *     <li>
7341		 *       Function return:
7342		 *       <ul>
7343		 *         <li>{int} Sorting match: <0 if first parameter should be sorted lower than
7344		 *           the second parameter, ===0 if the two parameters are equal and >0 if
7345		 *           the first parameter should be sorted height than the second parameter.</li>
7346		 *       </ul>
7347		 *     </il>
7348		 *   </ul>
7349		 *  @type object
7350		 *  @default {}
7351		 *
7352		 *  @example
7353		 *    // Case-sensitive string sorting, with no pre-formatting method
7354		 *    $.extend( $.fn.dataTableExt.oSort, {
7355		 *      "string-case-asc": function(x,y) {
7356		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
7357		 *      },
7358		 *      "string-case-desc": function(x,y) {
7359		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
7360		 *      }
7361		 *    } );
7362		 *
7363		 *  @example
7364		 *    // Case-insensitive string sorting, with pre-formatting
7365		 *    $.extend( $.fn.dataTableExt.oSort, {
7366		 *      "string-pre": function(x) {
7367		 *        return x.toLowerCase();
7368		 *      },
7369		 *      "string-asc": function(x,y) {
7370		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
7371		 *      },
7372		 *      "string-desc": function(x,y) {
7373		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
7374		 *      }
7375		 *    } );
7376		 */
7377		"oSort": {},
7378	
7379	
7380		/**
7381		 * Version string for plug-ins to check compatibility. Allowed format is
7382		 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
7383		 * e are optional
7384		 *  @type string
7385		 *  @default Version number
7386		 */
7387		"sVersion": DataTable.version,
7388	
7389	
7390		/**
7391		 * How should DataTables report an error. Can take the value 'alert' or 'throw'
7392		 *  @type string
7393		 *  @default alert
7394		 */
7395		"sErrMode": "alert",
7396	
7397	
7398		/**
7399		 * Store information for DataTables to access globally about other instances
7400		 *  @namespace
7401		 *  @private
7402		 */
7403		"_oExternConfig": {
7404			/* int:iNextUnique - next unique number for an instance */
7405			"iNextUnique": 0
7406		}
7407	};
7408	
7409	
7410	
7411	
7412	/**
7413	 * Template object for the way in which DataTables holds information about
7414	 * search information for the global filter and individual column filters.
7415	 *  @namespace
7416	 */
7417	DataTable.models.oSearch = {
7418		/**
7419		 * Flag to indicate if the filtering should be case insensitive or not
7420		 *  @type boolean
7421		 *  @default true
7422		 */
7423		"bCaseInsensitive": true,
7424	
7425		/**
7426		 * Applied search term
7427		 *  @type string
7428		 *  @default <i>Empty string</i>
7429		 */
7430		"sSearch": "",
7431	
7432		/**
7433		 * Flag to indicate if the search term should be interpreted as a
7434		 * regular expression (true) or not (false) and therefore and special
7435		 * regex characters escaped.
7436		 *  @type boolean
7437		 *  @default false
7438		 */
7439		"bRegex": false,
7440	
7441		/**
7442		 * Flag to indicate if DataTables is to use its smart filtering or not.
7443		 *  @type boolean
7444		 *  @default true
7445		 */
7446		"bSmart": true
7447	};
7448	
7449	
7450	
7451	
7452	/**
7453	 * Template object for the way in which DataTables holds information about
7454	 * each individual row. This is the object format used for the settings 
7455	 * aoData array.
7456	 *  @namespace
7457	 */
7458	DataTable.models.oRow = {
7459		/**
7460		 * TR element for the row
7461		 *  @type node
7462		 *  @default null
7463		 */
7464		"nTr": null,
7465	
7466		/**
7467		 * Data object from the original data source for the row. This is either
7468		 * an array if using the traditional form of DataTables, or an object if
7469		 * using mData options. The exact type will depend on the passed in
7470		 * data from the data source, or will be an array if using DOM a data 
7471		 * source.
7472		 *  @type array|object
7473		 *  @default []
7474		 */
7475		"_aData": [],
7476	
7477		/**
7478		 * Sorting data cache - this array is ostensibly the same length as the
7479		 * number of columns (although each index is generated only as it is 
7480		 * needed), and holds the data that is used for sorting each column in the
7481		 * row. We do this cache generation at the start of the sort in order that
7482		 * the formatting of the sort data need be done only once for each cell
7483		 * per sort. This array should not be read from or written to by anything
7484		 * other than the master sorting methods.
7485		 *  @type array
7486		 *  @default []
7487		 *  @private
7488		 */
7489		"_aSortData": [],
7490	
7491		/**
7492		 * Array of TD elements that are cached for hidden rows, so they can be
7493		 * reinserted into the table if a column is made visible again (or to act
7494		 * as a store if a column is made hidden). Only hidden columns have a 
7495		 * reference in the array. For non-hidden columns the value is either
7496		 * undefined or null.
7497		 *  @type array nodes
7498		 *  @default []
7499		 *  @private
7500		 */
7501		"_anHidden": [],
7502	
7503		/**
7504		 * Cache of the class name that DataTables has applied to the row, so we
7505		 * can quickly look at this variable rather than needing to do a DOM check
7506		 * on className for the nTr property.
7507		 *  @type string
7508		 *  @default <i>Empty string</i>
7509		 *  @private
7510		 */
7511		"_sRowStripe": ""
7512	};
7513	
7514	
7515	
7516	/**
7517	 * Template object for the column information object in DataTables. This object
7518	 * is held in the settings aoColumns array and contains all the information that
7519	 * DataTables needs about each individual column.
7520	 * 
7521	 * Note that this object is related to {@link DataTable.defaults.columns} 
7522	 * but this one is the internal data store for DataTables's cache of columns.
7523	 * It should NOT be manipulated outside of DataTables. Any configuration should
7524	 * be done through the initialisation options.
7525	 *  @namespace
7526	 */
7527	DataTable.models.oColumn = {
7528		/**
7529		 * A list of the columns that sorting should occur on when this column
7530		 * is sorted. That this property is an array allows multi-column sorting
7531		 * to be defined for a column (for example first name / last name columns
7532		 * would benefit from this). The values are integers pointing to the
7533		 * columns to be sorted on (typically it will be a single integer pointing
7534		 * at itself, but that doesn't need to be the case).
7535		 *  @type array
7536		 */
7537		"aDataSort": null,
7538	
7539		/**
7540		 * Define the sorting directions that are applied to the column, in sequence
7541		 * as the column is repeatedly sorted upon - i.e. the first value is used
7542		 * as the sorting direction when the column if first sorted (clicked on).
7543		 * Sort it again (click again) and it will move on to the next index.
7544		 * Repeat until loop.
7545		 *  @type array
7546		 */
7547		"asSorting": null,
7548		
7549		/**
7550		 * Flag to indicate if the column is searchable, and thus should be included
7551		 * in the filtering or not.
7552		 *  @type boolean
7553		 */
7554		"bSearchable": null,
7555		
7556		/**
7557		 * Flag to indicate if the column is sortable or not.
7558		 *  @type boolean
7559		 */
7560		"bSortable": null,
7561		
7562		/**
7563		 * <code>Deprecated</code> When using fnRender, you have two options for what 
7564		 * to do with the data, and this property serves as the switch. Firstly, you 
7565		 * can have the sorting and filtering use the rendered value (true - default), 
7566		 * or you can have the sorting and filtering us the original value (false).
7567		 *
7568		 * Please note that this option has now been deprecated and will be removed
7569		 * in the next version of DataTables. Please use mRender / mData rather than
7570		 * fnRender.
7571		 *  @type boolean
7572		 *  @deprecated
7573		 */
7574		"bUseRendered": null,
7575		
7576		/**
7577		 * Flag to indicate if the column is currently visible in the table or not
7578		 *  @type boolean
7579		 */
7580		"bVisible": null,
7581		
7582		/**
7583		 * Flag to indicate to the type detection method if the automatic type
7584		 * detection should be used, or if a column type (sType) has been specified
7585		 *  @type boolean
7586		 *  @default true
7587		 *  @private
7588		 */
7589		"_bAutoType": true,
7590		
7591		/**
7592		 * Developer definable function that is called whenever a cell is created (Ajax source,
7593		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
7594		 * allowing you to modify the DOM element (add background colour for example) when the
7595		 * element is available.
7596		 *  @type function
7597		 *  @param {element} nTd The TD node that has been created
7598		 *  @param {*} sData The Data for the cell
7599		 *  @param {array|object} oData The data for the whole row
7600		 *  @param {int} iRow The row index for the aoData data store
7601		 *  @default null
7602		 */
7603		"fnCreatedCell": null,
7604		
7605		/**
7606		 * Function to get data from a cell in a column. You should <b>never</b>
7607		 * access data directly through _aData internally in DataTables - always use
7608		 * the method attached to this property. It allows mData to function as
7609		 * required. This function is automatically assigned by the column 
7610		 * initialisation method
7611		 *  @type function
7612		 *  @param {array|object} oData The data array/object for the array 
7613		 *    (i.e. aoData[]._aData)
7614		 *  @param {string} sSpecific The specific data type you want to get - 
7615		 *    'display', 'type' 'filter' 'sort'
7616		 *  @returns {*} The data for the cell from the given row's data
7617		 *  @default null
7618		 */
7619		"fnGetData": null,
7620		
7621		/**
7622		 * <code>Deprecated</code> Custom display function that will be called for the 
7623		 * display of each cell in this column.
7624		 *
7625		 * Please note that this option has now been deprecated and will be removed
7626		 * in the next version of DataTables. Please use mRender / mData rather than
7627		 * fnRender.
7628		 *  @type function
7629		 *  @param {object} o Object with the following parameters:
7630		 *  @param {int}    o.iDataRow The row in aoData
7631		 *  @param {int}    o.iDataColumn The column in question
7632		 *  @param {array}  o.aData The data for the row in question
7633		 *  @param {object} o.oSettings The settings object for this DataTables instance
7634		 *  @returns {string} The string you which to use in the display
7635		 *  @default null
7636		 *  @deprecated
7637		 */
7638		"fnRender": null,
7639		
7640		/**
7641		 * Function to set data for a cell in the column. You should <b>never</b> 
7642		 * set the data directly to _aData internally in DataTables - always use
7643		 * this method. It allows mData to function as required. This function
7644		 * is automatically assigned by the column initialisation method
7645		 *  @type function
7646		 *  @param {array|object} oData The data array/object for the array 
7647		 *    (i.e. aoData[]._aData)
7648		 *  @param {*} sValue Value to set
7649		 *  @default null
7650		 */
7651		"fnSetData": null,
7652		
7653		/**
7654		 * Property to read the value for the cells in the column from the data 
7655		 * source array / object. If null, then the default content is used, if a
7656		 * function is given then the return from the function is used.
7657		 *  @type function|int|string|null
7658		 *  @default null
7659		 */
7660		"mData": null,
7661		
7662		/**
7663		 * Partner property to mData which is used (only when defined) to get
7664		 * the data - i.e. it is basically the same as mData, but without the
7665		 * 'set' option, and also the data fed to it is the result from mData.
7666		 * This is the rendering method to match the data method of mData.
7667		 *  @type function|int|string|null
7668		 *  @default null
7669		 */
7670		"mRender": null,
7671		
7672		/**
7673		 * Unique header TH/TD element for this column - this is what the sorting
7674		 * listener is attached to (if sorting is enabled.)
7675		 *  @type node
7676		 *  @default null
7677		 */
7678		"nTh": null,
7679		
7680		/**
7681		 * Unique footer TH/TD element for this column (if there is one). Not used 
7682		 * in DataTables as such, but can be used for plug-ins to reference the 
7683		 * footer for each column.
7684		 *  @type node
7685		 *  @default null
7686		 */
7687		"nTf": null,
7688		
7689		/**
7690		 * The class to apply to all TD elements in the table's TBODY for the column
7691		 *  @type string
7692		 *  @default null
7693		 */
7694		"sClass": null,
7695		
7696		/**
7697		 * When DataTables calculates the column widths to assign to each column,
7698		 * it finds the longest string in each column and then constructs a
7699		 * temporary table and reads the widths from that. The problem with this
7700		 * is that "mmm" is much wider then "iiii", but the latter is a longer 
7701		 * string - thus the calculation can go wrong (doing it properly and putting
7702		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
7703		 * a "work around" we provide this option. It will append its value to the
7704		 * text that is found to be the longest string for the column - i.e. padding.
7705		 *  @type string
7706		 */
7707		"sContentPadding": null,
7708		
7709		/**
7710		 * Allows a default value to be given for a column's data, and will be used
7711		 * whenever a null data source is encountered (this can be because mData
7712		 * is set to null, or because the data source itself is null).
7713		 *  @type string
7714		 *  @default null
7715		 */
7716		"sDefaultContent": null,
7717		
7718		/**
7719		 * Name for the column, allowing reference to the column by name as well as
7720		 * by index (needs a lookup to work by name).
7721		 *  @type string
7722		 */
7723		"sName": null,
7724		
7725		/**
7726		 * Custom sorting data type - defines which of the available plug-ins in
7727		 * afnSortData the custom sorting will use - if any is defined.
7728		 *  @type string
7729		 *  @default std
7730		 */
7731		"sSortDataType": 'std',
7732		
7733		/**
7734		 * Class to be applied to the header element when sorting on this column
7735		 *  @type string
7736		 *  @default null
7737		 */
7738		"sSortingClass": null,
7739		
7740		/**
7741		 * Class to be applied to the header element when sorting on this column -
7742		 * when jQuery UI theming is used.
7743		 *  @type string
7744		 *  @default null
7745		 */
7746		"sSortingClassJUI": null,
7747		
7748		/**
7749		 * Title of the column - what is seen in the TH element (nTh).
7750		 *  @type string
7751		 */
7752		"sTitle": null,
7753		
7754		/**
7755		 * Column sorting and filtering type
7756		 *  @type string
7757		 *  @default null
7758		 */
7759		"sType": null,
7760		
7761		/**
7762		 * Width of the column
7763		 *  @type string
7764		 *  @default null
7765		 */
7766		"sWidth": null,
7767		
7768		/**
7769		 * Width of the column when it was first "encountered"
7770		 *  @type string
7771		 *  @default null
7772		 */
7773		"sWidthOrig": null
7774	};
7775	
7776	
7777	
7778	/**
7779	 * Initialisation options that can be given to DataTables at initialisation 
7780	 * time.
7781	 *  @namespace
7782	 */
7783	DataTable.defaults = {
7784		/**
7785		 * An array of data to use for the table, passed in at initialisation which 
7786		 * will be used in preference to any data which is already in the DOM. This is
7787		 * particularly useful for constructing tables purely in Javascript, for
7788		 * example with a custom Ajax call.
7789		 *  @type array
7790		 *  @default null
7791		 *  @dtopt Option
7792		 * 
7793		 *  @example
7794		 *    // Using a 2D array data source
7795		 *    $(document).ready( function () {
7796		 *      $('#example').dataTable( {
7797		 *        "aaData": [
7798		 *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
7799		 *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
7800		 *        ],
7801		 *        "aoColumns": [
7802		 *          { "sTitle": "Engine" },
7803		 *          { "sTitle": "Browser" },
7804		 *          { "sTitle": "Platform" },
7805		 *          { "sTitle": "Version" },
7806		 *          { "sTitle": "Grade" }
7807		 *        ]
7808		 *      } );
7809		 *    } );
7810		 *    
7811		 *  @example
7812		 *    // Using an array of objects as a data source (mData)
7813		 *    $(document).ready( function () {
7814		 *      $('#example').dataTable( {
7815		 *        "aaData": [
7816		 *          {
7817		 *            "engine":   "Trident",
7818		 *            "browser":  "Internet Explorer 4.0",
7819		 *            "platform": "Win 95+",
7820		 *            "version":  4,
7821		 *            "grade":    "X"
7822		 *          },
7823		 *          {
7824		 *            "engine":   "Trident",
7825		 *            "browser":  "Internet Explorer 5.0",
7826		 *            "platform": "Win 95+",
7827		 *            "version":  5,
7828		 *            "grade":    "C"
7829		 *          }
7830		 *        ],
7831		 *        "aoColumns": [
7832		 *          { "sTitle": "Engine",   "mData": "engine" },
7833		 *          { "sTitle": "Browser",  "mData": "browser" },
7834		 *          { "sTitle": "Platform", "mData": "platform" },
7835		 *          { "sTitle": "Version",  "mData": "version" },
7836		 *          { "sTitle": "Grade",    "mData": "grade" }
7837		 *        ]
7838		 *      } );
7839		 *    } );
7840		 */
7841		"aaData": null,
7842	
7843	
7844		/**
7845		 * If sorting is enabled, then DataTables will perform a first pass sort on 
7846		 * initialisation. You can define which column(s) the sort is performed upon, 
7847		 * and the sorting direction, with this variable. The aaSorting array should 
7848		 * contain an array for each column to be sorted initially containing the 
7849		 * column's index and a direction string ('asc' or 'desc').
7850		 *  @type array
7851		 *  @default [[0,'asc']]
7852		 *  @dtopt Option
7853		 * 
7854		 *  @example
7855		 *    // Sort by 3rd column first, and then 4th column
7856		 *    $(document).ready( function() {
7857		 *      $('#example').dataTable( {
7858		 *        "aaSorting": [[2,'asc'], [3,'desc']]
7859		 *      } );
7860		 *    } );
7861		 *    
7862		 *    // No initial sorting
7863		 *    $(document).ready( function() {
7864		 *      $('#example').dataTable( {
7865		 *        "aaSorting": []
7866		 *      } );
7867		 *    } );
7868		 */
7869		"aaSorting": [[0,'asc']],
7870	
7871	
7872		/**
7873		 * This parameter is basically identical to the aaSorting parameter, but 
7874		 * cannot be overridden by user interaction with the table. What this means 
7875		 * is that you could have a column (visible or hidden) which the sorting will 
7876		 * always be forced on first - any sorting after that (from the user) will 
7877		 * then be performed as required. This can be useful for grouping rows 
7878		 * together.
7879		 *  @type array
7880		 *  @default null
7881		 *  @dtopt Option
7882		 * 
7883		 *  @example
7884		 *    $(document).ready( function() {
7885		 *      $('#example').dataTable( {
7886		 *        "aaSortingFixed": [[0,'asc']]
7887		 *      } );
7888		 *    } )
7889		 */
7890		"aaSortingFixed": null,
7891	
7892	
7893		/**
7894		 * This parameter allows you to readily specify the entries in the length drop
7895		 * down menu that DataTables shows when pagination is enabled. It can be 
7896		 * either a 1D array of options which will be used for both the displayed 
7897		 * option and the value, or a 2D array which will use the array in the first 
7898		 * position as the value, and the array in the second position as the 
7899		 * displayed options (useful for language strings such as 'All').
7900		 *  @type array
7901		 *  @default [ 10, 25, 50, 100 ]
7902		 *  @dtopt Option
7903		 * 
7904		 *  @example
7905		 *    $(document).ready( function() {
7906		 *      $('#example').dataTable( {
7907		 *        "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
7908		 *      } );
7909		 *    } );
7910		 *  
7911		 *  @example
7912		 *    // Setting the default display length as well as length menu
7913		 *    // This is likely to be wanted if you remove the '10' option which
7914		 *    // is the iDisplayLength default.
7915		 *    $(document).ready( function() {
7916		 *      $('#example').dataTable( {
7917		 *        "iDisplayLength": 25,
7918		 *        "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
7919		 *      } );
7920		 *    } );
7921		 */
7922		"aLengthMenu": [ 10, 25, 50, 100 ],
7923	
7924	
7925		/**
7926		 * The aoColumns option in the initialisation parameter allows you to define
7927		 * details about the way individual columns behave. For a full list of
7928		 * column options that can be set, please see 
7929		 * {@link DataTable.defaults.columns}. Note that if you use aoColumns to
7930		 * define your columns, you must have an entry in the array for every single
7931		 * column that you have in your table (these can be null if you don't which
7932		 * to specify any options).
7933		 *  @member
7934		 */
7935		"aoColumns": null,
7936	
7937		/**
7938		 * Very similar to aoColumns, aoColumnDefs allows you to target a specific 
7939		 * column, multiple columns, or all columns, using the aTargets property of 
7940		 * each object in the array. This allows great flexibility when creating 
7941		 * tables, as the aoColumnDefs arrays can be of any length, targeting the 
7942		 * columns you specifically want. aoColumnDefs may use any of the column 
7943		 * options available: {@link DataTable.defaults.columns}, but it _must_
7944		 * have aTargets defined in each object in the array. Values in the aTargets
7945		 * array may be:
7946		 *   <ul>
7947		 *     <li>
7947a string - class name will be matched on the TH for the column</li>
7948		 *     <li>0 or a positive integer - column index counting from the left</li>
7949		 *     <li>a negative integer - column index counting from the right</li>
7950		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
7951		 *   </ul>
7952		 *  @member
7953		 */
7954		"aoColumnDefs": null,
7955	
7956	
7957		/**
7958		 * Basically the same as oSearch, this parameter defines the individual column
7959		 * filtering state at initialisation time. The array must be of the same size 
7960		 * as the number of columns, and each element be an object with the parameters
7961		 * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also
7962		 * accepted and the default will be used.
7963		 *  @type array
7964		 *  @default []
7965		 *  @dtopt Option
7966		 * 
7967		 *  @example
7968		 *    $(document).ready( function() {
7969		 *      $('#example').dataTable( {
7970		 *        "aoSearchCols": [
7971		 *          null,
7972		 *          { "sSearch": "My filter" },
7973		 *          null,
7974		 *          { "sSearch": "^[0-9]", "bEscapeRegex": false }
7975		 *        ]
7976		 *      } );
7977		 *    } )
7978		 */
7979		"aoSearchCols": [],
7980	
7981	
7982		/**
7983		 * An array of CSS classes that should be applied to displayed rows. This 
7984		 * array may be of any length, and DataTables will apply each class 
7985		 * sequentially, looping when required.
7986		 *  @type array
7987		 *  @default null <i>Will take the values determined by the oClasses.sStripe*
7988		 *    options</i>
7989		 *  @dtopt Option
7990		 * 
7991		 *  @example
7992		 *    $(document).ready( function() {
7993		 *      $('#example').dataTable( {
7994		 *        "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]
7995		 *      } );
7996		 *    } )
7997		 */
7998		"asStripeClasses": null,
7999	
8000	
8001		/**
8002		 * Enable or disable automatic column width calculation. This can be disabled
8003		 * as an optimisation (it takes some time to calculate the widths) if the
8004		 * tables widths are passed in using aoColumns.
8005		 *  @type boolean
8006		 *  @default true
8007		 *  @dtopt Features
8008		 * 
8009		 *  @example
8010		 *    $(document).ready( function () {
8011		 *      $('#example').dataTable( {
8012		 *        "bAutoWidth": false
8013		 *      } );
8014		 *    } );
8015		 */
8016		"bAutoWidth": true,
8017	
8018	
8019		/**
8020		 * Deferred rendering can provide DataTables with a huge speed boost when you
8021		 * are using an Ajax or JS data source for the table. This option, when set to
8022		 * true, will cause DataTables to defer the creation of the table elements for
8023		 * each row until they are needed for a draw - saving a significant amount of
8024		 * time.
8025		 *  @type boolean
8026		 *  @default false
8027		 *  @dtopt Features
8028		 * 
8029		 *  @example
8030		 *    $(document).ready( function() {
8031		 *      var oTable = $('#example').dataTable( {
8032		 *        "sAjaxSource": "sources/arrays.txt",
8033		 *        "bDeferRender": true
8034		 *      } );
8035		 *    } );
8036		 */
8037		"bDeferRender": false,
8038	
8039	
8040		/**
8041		 * Replace a DataTable which matches the given selector and replace it with 
8042		 * one which has the properties of the new initialisation object passed. If no
8043		 * table matches the selector, then the new DataTable will be constructed as
8044		 * per normal.
8045		 *  @type boolean
8046		 *  @default false
8047		 *  @dtopt Options
8048		 * 
8049		 *  @example
8050		 *    $(document).ready( function() {
8051		 *      $('#example').dataTable( {
8052		 *        "sScrollY": "200px",
8053		 *        "bPaginate": false
8054		 *      } );
8055		 *      
8056		 *      // Some time later....
8057		 *      $('#example').dataTable( {
8058		 *        "bFilter": false,
8059		 *        "bDestroy": true
8060		 *      } );
8061		 *    } );
8062		 */
8063		"bDestroy": false,
8064	
8065	
8066		/**
8067		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
8068		 * that it allows the end user to input multiple words (space separated) and
8069		 * will match a row containing those words, even if not in the order that was
8070		 * specified (this allow matching across multiple columns). Note that if you
8071		 * wish to use filtering in DataTables this must remain 'true' - to remove the
8072		 * default filtering input box and retain filtering abilities, please use
8073		 * {@link DataTable.defaults.sDom}.
8074		 *  @type boolean
8075		 *  @default true
8076		 *  @dtopt Features
8077		 * 
8078		 *  @example
8079		 *    $(document).ready( function () {
8080		 *      $('#example').dataTable( {
8081		 *        "bFilter": false
8082		 *      } );
8083		 *    } );
8084		 */
8085		"bFilter": true,
8086	
8087	
8088		/**
8089		 * Enable or disable the table information display. This shows information 
8090		 * about the data that is currently visible on the page, including information
8091		 * about filtered data if that action is being performed.
8092		 *  @type boolean
8093		 *  @default true
8094		 *  @dtopt Features
8095		 * 
8096		 *  @example
8097		 *    $(document).ready( function () {
8098		 *      $('#example').dataTable( {
8099		 *        "bInfo": false
8100		 *      } );
8101		 *    } );
8102		 */
8103		"bInfo": true,
8104	
8105	
8106		/**
8107		 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
8108		 * slightly different and additional mark-up from what DataTables has
8109		 * traditionally used).
8110		 *  @type boolean
8111		 *  @default false
8112		 *  @dtopt Features
8113		 * 
8114		 *  @example
8115		 *    $(document).ready( function() {
8116		 *      $('#example').dataTable( {
8117		 *        "bJQueryUI": true
8118		 *      } );
8119		 *    } );
8120		 */
8121		"bJQueryUI": false,
8122	
8123	
8124		/**
8125		 * Allows the end user to select the size of a formatted page from a select
8126		 * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate).
8127		 *  @type boolean
8128		 *  @default true
8129		 *  @dtopt Features
8130		 * 
8131		 *  @example
8132		 *    $(document).ready( function () {
8133		 *      $('#example').dataTable( {
8134		 *        "bLengthChange": false
8135		 *      } );
8136		 *    } );
8137		 */
8138		"bLengthChange": true,
8139	
8140	
8141		/**
8142		 * Enable or disable pagination.
8143		 *  @type boolean
8144		 *  @default true
8145		 *  @dtopt Features
8146		 * 
8147		 *  @example
8148		 *    $(document).ready( function () {
8149		 *      $('#example').dataTable( {
8150		 *        "bPaginate": false
8151		 *      } );
8152		 *    } );
8153		 */
8154		"bPaginate": true,
8155	
8156	
8157		/**
8158		 * Enable or disable the display of a 'processing' indicator when the table is
8159		 * being processed (e.g. a sort). This is particularly useful for tables with
8160		 * large amounts of data where it can take a noticeable amount of time to sort
8161		 * the entries.
8162		 *  @type boolean
8163		 *  @default false
8164		 *  @dtopt Features
8165		 * 
8166		 *  @example
8167		 *    $(document).ready( function () {
8168		 *      $('#example').dataTable( {
8169		 *        "bProcessing": true
8170		 *      } );
8171		 *    } );
8172		 */
8173		"bProcessing": false,
8174	
8175	
8176		/**
8177		 * Retrieve the DataTables object for the given selector. Note that if the
8178		 * table has already been initialised, this parameter will cause DataTables
8179		 * to simply return the object that has already been set up - it will not take
8180		 * account of any changes you might have made to the initialisation object
8181		 * passed to DataTables (setting this parameter to true is an acknowledgement
8182		 * that you understand this). bDestroy can be used to reinitialise a table if
8183		 * you need.
8184		 *  @type boolean
8185		 *  @default false
8186		 *  @dtopt Options
8187		 * 
8188		 *  @example
8189		 *    $(document).ready( function() {
8190		 *      initTable();
8191		 *      tableActions();
8192		 *    } );
8193		 *    
8194		 *    function initTable ()
8195		 *    {
8196		 *      return $('#example').dataTable( {
8197		 *        "sScrollY": "200px",
8198		 *        "bPaginate": false,
8199		 *        "bRetrieve": true
8200		 *      } );
8201		 *    }
8202		 *    
8203		 *    function tableActions ()
8204		 *    {
8205		 *      var oTable = initTable();
8206		 *      // perform API operations with oTable 
8207		 *    }
8208		 */
8209		"bRetrieve": false,
8210	
8211	
8212		/**
8213		 * Indicate if DataTables should be allowed to set the padding / margin
8214		 * etc for the scrolling header elements or not. Typically you will want
8215		 * this.
8216		 *  @type boolean
8217		 *  @default true
8218		 *  @dtopt Options
8219		 * 
8220		 *  @example
8221		 *    $(document).ready( function() {
8222		 *      $('#example').dataTable( {
8223		 *        "bScrollAutoCss": false,
8224		 *        "sScrollY": "200px"
8225		 *      } );
8226		 *    } );
8227		 */
8228		"bScrollAutoCss": true,
8229	
8230	
8231		/**
8232		 * When vertical (y) scrolling is enabled, DataTables will force the height of
8233		 * the table's viewport to the given height at all times (useful for layout).
8234		 * However, this can look odd when filtering data down to a small data set,
8235		 * and the footer is left "floating" further down. This parameter (when
8236		 * enabled) will cause DataTables to collapse the table's viewport down when
8237		 * the result set will fit within the given Y height.
8238		 *  @type boolean
8239		 *  @default false
8240		 *  @dtopt Options
8241		 * 
8242		 *  @example
8243		 *    $(document).ready( function() {
8244		 *      $('#example').dataTable( {
8245		 *        "sScrollY": "200",
8246		 *        "bScrollCollapse": true
8247		 *      } );
8248		 *    } );
8249		 */
8250		"bScrollCollapse": false,
8251	
8252	
8253		/**
8254		 * Enable infinite scrolling for DataTables (to be used in combination with
8255		 * sScrollY). Infinite scrolling means that DataTables will continually load
8256		 * data as a user scrolls through a table, which is very useful for large
8257		 * dataset. This cannot be used with pagination, which is automatically
8258		 * disabled. Note - the Scroller extra for DataTables is recommended in
8259		 * in preference to this option.
8260		 *  @type boolean
8261		 *  @default false
8262		 *  @dtopt Features
8263		 * 
8264		 *  @example
8265		 *    $(document).ready( function() {
8266		 *      $('#example').dataTable( {
8267		 *        "bScrollInfinite": true,
8268		 *        "bScrollCollapse": true,
8269		 *        "sScrollY": "200px"
8270		 *      } );
8271		 *    } );
8272		 */
8273		"bScrollInfinite": false,
8274	
8275	
8276		/**
8277		 * Configure DataTables to use server-side processing. Note that the
8278		 * sAjaxSource parameter must also be given in order to give DataTables a
8279		 * source to obtain the required data for each draw.
8280		 *  @type boolean
8281		 *  @default false
8282		 *  @dtopt Features
8283		 *  @dtopt Server-side
8284		 * 
8285		 *  @example
8286		 *    $(document).ready( function () {
8287		 *      $('#example').dataTable( {
8288		 *        "bServerSide": true,
8289		 *        "sAjaxSource": "xhr.php"
8290		 *      } );
8291		 *    } );
8292		 */
8293		"bServerSide": false,
8294	
8295	
8296		/**
8297		 * Enable or disable sorting of columns. Sorting of individual columns can be
8298		 * disabled by the "bSortable" option for each column.
8299		 *  @type boolean
8300		 *  @default true
8301		 *  @dtopt Features
8302		 * 
8303		 *  @example
8304		 *    $(document).ready( function () {
8305		 *      $('#example').dataTable( {
8306		 *        "bSort": false
8307		 *      } );
8308		 *    } );
8309		 */
8310		"bSort": true,
8311	
8312	
8313		/**
8314		 * Allows control over whether DataTables should use the top (true) unique
8315		 * cell that is found for a single column, or the bottom (false - default).
8316		 * This is useful when using complex headers.
8317		 *  @type boolean
8318		 *  @default false
8319		 *  @dtopt Options
8320		 * 
8321		 *  @example
8322		 *    $(document).ready( function() {
8323		 *      $('#example').dataTable( {
8324		 *        "bSortCellsTop": true
8325		 *      } );
8326		 *    } );
8327		 */
8328		"bSortCellsTop": false,
8329	
8330	
8331		/**
8332		 * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and
8333		 * 'sorting_3' to the columns which are currently being sorted on. This is
8334		 * presented as a feature switch as it can increase processing time (while
8335		 * classes are removed and added) so for large data sets you might want to
8336		 * turn this off.
8337		 *  @type boolean
8338		 *  @default true
8339		 *  @dtopt Features
8340		 * 
8341		 *  @example
8342		 *    $(document).ready( function () {
8343		 *      $('#example').dataTable( {
8344		 *        "bSortClasses": false
8345		 *      } );
8346		 *    } );
8347		 */
8348		"bSortClasses": true,
8349	
8350	
8351		/**
8352		 * Enable or disable state saving. When enabled a cookie will be used to save
8353		 * table display information such as pagination information, display length,
8354		 * filtering and sorting. As such when the end user reloads the page the
8355		 * display display will match what thy had previously set up.
8356		 *  @type boolean
8357		 *  @default false
8358		 *  @dtopt Features
8359		 * 
8360		 *  @example
8361		 *    $(document).ready( function () {
8362		 *      $('#example').dataTable( {
8363		 *        "bStateSave": true
8364		 *      } );
8365		 *    } );
8366		 */
8367		"bStateSave": false,
8368	
8369	
8370		/**
8371		 * Customise the cookie and / or the parameters being stored when using
8372		 * DataTables with state saving enabled. This function is called whenever
8373		 * the cookie is modified, and it expects a fully formed cookie string to be
8374		 * returned. Note that the data object passed in is a Javascript object which
8375		 * must be converted to a string (JSON.stringify for example).
8376		 *  @type function
8377		 *  @param {string} sName Name of the cookie defined by DataTables
8378		 *  @param {object} oData Data to be stored in the cookie
8379		 *  @param {string} sExpires Cookie expires string
8380		 *  @param {string} sPath Path of the cookie to set
8381		 *  @returns {string} Cookie formatted string (which should be encoded by
8382		 *    using encodeURIComponent())
8383		 *  @dtopt Callbacks
8384		 * 
8385		 *  @example
8386		 *    $(document).ready( function () {
8387		 *      $('#example').dataTable( {
8388		 *        "fnCookieCallback": function (sName, oData, sExpires, sPath) {
8389		 *          // Customise oData or sName or whatever else here
8390		 *          return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath;
8391		 *        }
8392		 *      } );
8393		 *    } );
8394		 */
8395		"fnCookieCallback": null,
8396	
8397	
8398		/**
8399		 * This function is called when a TR element is created (and all TD child
8400		 * elements have been inserted), or registered if using a DOM source, allowing
8401		 * manipulation of the TR element (adding classes etc).
8402		 *  @type function
8403		 *  @param {node} nRow "TR" element for the current row
8404		 *  @param {array} aData Raw data array for this row
8405		 *  @param {int} iDataIndex The index of this row in aoData
8406		 *  @dtopt Callbacks
8407		 * 
8408		 *  @example
8409		 *    $(document).ready( function() {
8410		 *      $('#example').dataTable( {
8411		 *        "fnCreatedRow": function( nRow, aData, iDataIndex ) {
8412		 *          // Bold the grade for all 'A' grade browsers
8413		 *          if ( aData[4] == "A" )
8414		 *          {
8415		 *            $('td:eq(4)', nRow).html( '<b>A</b>' );
8416		 *          }
8417		 *        }
8418		 *      } );
8419		 *    } );
8420		 */
8421		"fnCreatedRow": null,
8422	
8423	
8424		/**
8425		 * This function is called on every 'draw' event, and allows you to
8426		 * dynamically modify any aspect you want about the created DOM.
8427		 *  @type function
8428		 *  @param {object} oSettings DataTables settings object
8429		 *  @dtopt Callbacks
8430		 * 
8431		 *  @example
8432		 *    $(document).ready( function() {
8433		 *      $('#example').dataTable( {
8434		 *        "fnDrawCallback": function( oSettings ) {
8435		 *          alert( 'DataTables has redrawn the table' );
8436		 *        }
8437		 *      } );
8438		 *    } );
8439		 */
8440		"fnDrawCallback": null,
8441	
8442	
8443		/**
8444		 * Identical to fnHeaderCallback() but for the table footer this function
8445		 * allows you to modify the table footer on every 'draw' even.
8446		 *  @type function
8447		 *  @param {node} nFoot "TR" element for the footer
8448		 *  @param {array} aData Full table data (as derived from the original HTML)
8449		 *  @param {int} iStart Index for the current display starting point in the 
8450		 *    display array
8451		 *  @param {int} iEnd Index for the current display ending point in the 
8452		 *    display array
8453		 *  @param {array int} aiDisplay Index array to translate the visual position
8454		 *    to the full data array
8455		 *  @dtopt Callbacks
8456		 * 
8457		 *  @example
8458		 *    $(document).ready( function() {
8459		 *      $('#example').dataTable( {
8460		 *        "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) {
8461		 *          nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart;
8462		 *        }
8463		 *      } );
8464		 *    } )
8465		 */
8466		"fnFooterCallback": null,
8467	
8468	
8469		/**
8470		 * When rendering large numbers in the information element for the table
8471		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
8472		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
8473		 * rendered as "1,000,000") to help readability for the end user. This
8474		 * function will override the default method DataTables uses.
8475		 *  @type function
8476		 *  @member
8477		 *  @param {int} iIn number to be formatted
8478		 *  @returns {string} formatted string for DataTables to show the number
8479		 *  @dtopt Callbacks
8480		 * 
8481		 *  @example
8482		 *    $(document).ready( function() {
8483		 *      $('#example').dataTable( {
8484		 *        "fnFormatNumber": function ( iIn ) {
8485		 *          if ( iIn &lt; 1000 ) {
8486		 *            return iIn;
8487		 *          } else {
8488		 *            var 
8489		 *              s=(iIn+""), 
8490		 *              a=s.split(""), out="", 
8491		 *              iLen=s.length;
8492		 *            
8493		 *            for ( var i=0 ; i&lt;iLen ; i++ ) {
8494		 *              if ( i%3 === 0 &amp;&amp; i !== 0 ) {
8495		 *                out = "'"+out;
8496		 *              }
8497		 *              out = a[iLen-i-1]+out;
8498		 *            }
8499		 *          }
8500		 *          return out;
8501		 *        };
8502		 *      } );
8503		 *    } );
8504		 */
8505		"fnFormatNumber": function ( iIn ) {
8506			if ( iIn < 1000 )
8507			{
8508				// A small optimisation for what is likely to be the majority of use cases
8509				return iIn;
8510			}
8511	
8512			var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
8513			
8514			for ( var i=0 ; i<iLen ; i++ )
8515			{
8516				if ( i%3 === 0 && i !== 0 )
8517				{
8518					out = this.oLanguage.sInfoThousands+out;
8519				}
8520				out = a[iLen-i-1]+out;
8521			}
8522			return out;
8523		},
8524	
8525	
8526		/**
8527		 * This function is called on every 'draw' event, and allows you to
8528		 * dynamically modify the header row. This can be used to calculate and
8529		 * display useful information about the table.
8530		 *  @type function
8531		 *  @param {node} nHead "TR" element for the header
8532		 *  @param {array} aData Full table data (as derived from the original HTML)
8533		 *  @param {int} iStart Index for the current display starting point in the
8534		 *    display array
8535		 *  @param {int} iEnd Index for the current display ending point in the
8536		 *    display array
8537		 *  @param {array int} aiDisplay Index array to translate the visual position
8538		 *    to the full data array
8539		 *  @dtopt Callbacks
8540		 * 
8541		 *  @example
8542		 *    $(document).ready( function() {
8543		 *      $('#example').dataTable( {
8544		 *        "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) {
8545		 *          nHead.getElementsByTagName('th')[0].innerHTML = "Dis
8545playing "+(iEnd-iStart)+" records";
8546		 *        }
8547		 *      } );
8548		 *    } )
8549		 */
8550		"fnHeaderCallback": null,
8551	
8552	
8553		/**
8554		 * The information element can be used to convey information about the current
8555		 * state of the table. Although the internationalisation options presented by
8556		 * DataTables are quite capable of dealing with most customisations, there may
8557		 * be times where you wish to customise the string further. This callback
8558		 * allows you to do exactly that.
8559		 *  @type function
8560		 *  @param {object} oSettings DataTables settings object
8561		 *  @param {int} iStart Starting position in data for the draw
8562		 *  @param {int} iEnd End position in data for the draw
8563		 *  @param {int} iMax Total number of rows in the table (regardless of
8564		 *    filtering)
8565		 *  @param {int} iTotal Total number of rows in the data set, after filtering
8566		 *  @param {string} sPre The string that DataTables has formatted using it's
8567		 *    own rules
8568		 *  @returns {string} The string to be displayed in the information element.
8569		 *  @dtopt Callbacks
8570		 * 
8571		 *  @example
8572		 *    $('#example').dataTable( {
8573		 *      "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
8574		 *        return iStart +" to "+ iEnd;
8575		 *      }
8576		 *    } );
8577		 */
8578		"fnInfoCallback": null,
8579	
8580	
8581		/**
8582		 * Called when the table has been initialised. Normally DataTables will
8583		 * initialise sequentially and there will be no need for this function,
8584		 * however, this does not hold true when using external language information
8585		 * since that is obtained using an async XHR call.
8586		 *  @type function
8587		 *  @param {object} oSettings DataTables settings object
8588		 *  @param {object} json The JSON object request from the server - only
8589		 *    present if client-side Ajax sourced data is used
8590		 *  @dtopt Callbacks
8591		 * 
8592		 *  @example
8593		 *    $(document).ready( function() {
8594		 *      $('#example').dataTable( {
8595		 *        "fnInitComplete": function(oSettings, json) {
8596		 *          alert( 'DataTables has finished its initialisation.' );
8597		 *        }
8598		 *      } );
8599		 *    } )
8600		 */
8601		"fnInitComplete": null,
8602	
8603	
8604		/**
8605		 * Called at the very start of each table draw and can be used to cancel the
8606		 * draw by returning false, any other return (including undefined) results in
8607		 * the full draw occurring).
8608		 *  @type function
8609		 *  @param {object} oSettings DataTables settings object
8610		 *  @returns {boolean} False will cancel the draw, anything else (including no
8611		 *    return) will allow it to complete.
8612		 *  @dtopt Callbacks
8613		 * 
8614		 *  @example
8615		 *    $(document).ready( function() {
8616		 *      $('#example').dataTable( {
8617		 *        "fnPreDrawCallback": function( oSettings ) {
8618		 *          if ( $('#test').val() == 1 ) {
8619		 *            return false;
8620		 *          }
8621		 *        }
8622		 *      } );
8623		 *    } );
8624		 */
8625		"fnPreDrawCallback": null,
8626	
8627	
8628		/**
8629		 * This function allows you to 'post process' each row after it have been
8630		 * generated for each table draw, but before it is rendered on screen. This
8631		 * function might be used for setting the row class name etc.
8632		 *  @type function
8633		 *  @param {node} nRow "TR" element for the current row
8634		 *  @param {array} aData Raw data array for this row
8635		 *  @param {int} iDisplayIndex The display index for the current table draw
8636		 *  @param {int} iDisplayIndexFull The index of the data in the full list of
8637		 *    rows (after filtering)
8638		 *  @dtopt Callbacks
8639		 * 
8640		 *  @example
8641		 *    $(document).ready( function() {
8642		 *      $('#example').dataTable( {
8643		 *        "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
8644		 *          // Bold the grade for all 'A' grade browsers
8645		 *          if ( aData[4] == "A" )
8646		 *          {
8647		 *            $('td:eq(4)', nRow).html( '<b>A</b>' );
8648		 *          }
8649		 *        }
8650		 *      } );
8651		 *    } );
8652		 */
8653		"fnRowCallback": null,
8654	
8655	
8656		/**
8657		 * This parameter allows you to override the default function which obtains
8658		 * the data from the server ($.getJSON) so something more suitable for your
8659		 * application. For example you could use POST data, or pull information from
8660		 * a Gears or AIR database.
8661		 *  @type function
8662		 *  @member
8663		 *  @param {string} sSource HTTP source to obtain the data from (sAjaxSource)
8664		 *  @param {array}
8664 aoData A key/value pair object containing the data to send
8665		 *    to the server
8666		 *  @param {function} fnCallback to be called on completion of the data get
8667		 *    process that will draw the data on the page.
8668		 *  @param {object} oSettings DataTables settings object
8669		 *  @dtopt Callbacks
8670		 *  @dtopt Server-side
8671		 * 
8672		 *  @example
8673		 *    // POST data to server
8674		 *    $(document).ready( function() {
8675		 *      $('#example').dataTable( {
8676		 *        "bProcessing": true,
8677		 *        "bServerSide": true,
8678		 *        "sAjaxSource": "xhr.php",
8679		 *        "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
8680		 *          oSettings.jqXHR = $.ajax( {
8681		 *            "dataType": 'json', 
8682		 *            "type": "POST", 
8683		 *            "url": sSource, 
8684		 *            "data": aoData, 
8685		 *            "success": fnCallback
8686		 *          } );
8687		 *        }
8688		 *      } );
8689		 *    } );
8690		 */
8691		"fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {
8692			oSettings.jqXHR = $.ajax( {
8693				"url":  sUrl,
8694				"data": aoData,
8695				"success": function (json) {
8696					if ( json.sError ) {
8697						oSettings.oApi._fnLog( oSettings, 0, json.sError );
8698					}
8699					
8700					$(oSettings.oInstance).trigger('xhr', [oSettings, json]);
8701					fnCallback( json );
8702				},
8703				"dataType": "json",
8704				"cache": false,
8705				"type": oSettings.sServerMethod,
8706				"error": function (xhr, error, thrown) {
8707					if ( error == "parsererror" ) {
8708						oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+
8709							"server could not be parsed. This is caused by a JSON formatting error." );
8710					}
8711				}
8712			} );
8713		},
8714	
8715	
8716		/**
8717		 * It is often useful to send extra data to the server when making an Ajax
8718		 * request - for example custom filtering information, and this callback
8719		 * function makes it trivial to send extra information to the server. The
8720		 * passed in parameter is the data set that has been constructed by
8721		 * DataTables, and you can add to this or modify it as you require.
8722		 *  @type function
8723		 *  @param {array} aoData Data array (array of objects which are name/value
8724		 *    pairs) that has been constructed by DataTables and will be sent to the
8725		 *    server. In the case of Ajax sourced data with server-side processing
8726		 *    this will be an empty array, for server-side processing there will be a
8727		 *    significant number of parameters!
8728		 *  @returns {undefined} Ensure that you modify the aoData array passed in,
8729		 *    as this is passed by reference.
8730		 *  @dtopt Callbacks
8731		 *  @dtopt Server-side
8732		 * 
8733		 *  @example
8734		 *    $(document).ready( function() {
8735		 *      $('#example').dataTable( {
8736		 *        "bProcessing": true,
8737		 *        "bServerSide": true,
8738		 *        "sAjaxSource": "scripts/server_processing.php",
8739		 *        "fnServerParams": function ( aoData ) {
8740		 *          aoData.push( { "name": "more_data", "value": "my_value" } );
8741		 *        }
8742		 *      } );
8743		 *    } );
8744		 */
8745		"fnServerParams": null,
8746	
8747	
8748		/**
8749		 * Load the table state. With this function you can define from where, and how, the
8750		 * state of a table is loaded. By default DataTables will load from its state saving
8751		 * cookie, but you might wish to use local storage (HTML5) or a server-side database.
8752		 *  @type function
8753		 *  @member
8754		 *  @param {object} oSettings DataTables settings object
8755		 *  @return {object} The DataTables state object to be loaded
8756		 *  @dtopt Callbacks
8757		 * 
8758		 *  @example
8759		 *    $(document).ready( function() {
8760		 *      $('#example').dataTable( {
8761		 *        "bStateSave": true,
8762		 *        "fnStateLoad": function (oSettings) {
8763		 *          var o;
8764		 *          
8765		 *          // Send an Ajax request to the server to get the data. Note that
8766		 *          // this is a synchronous request.
8767		 *          $.ajax( {
8768		 *            "url": "/state_load",
8769		 *            "async": false,
8770		 *            "dataType": "json",
8771		 *            "success": function (json) {
8772		 *              o = json;
8773		 *            }
8774		 *          } );
8775		 *          
8776		 *          return o;
8777		 *        }
8778		 *      } );
8779		 *    } );
8780		 */
8781		"fnStateLoad": function ( oSettings ) {
8782			var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
8783			var oData;
8784	
8785			try {
8786				oData = (typeof $.parseJSON === 'function') ? 
8787					$.parseJSON(sData) : eval( '('+sData+')' );
8788			} catch (e) {
8789				oData = null;
8790			}
8791	
8792			return oData;
8793		},
8794	
8795	
8796		/**
8797		 * Callback which allows modification of the saved state prior to loading that state.
8798		 * This callback is called when the table is loading state from the stored data, but
8799		 * prior to the settings object being modified by the saved state. Note that for 
8800		 * plug-in authors, you should use the 'stateLoadParams' event to load parameters for 
8801		 * a plug-in.
8802		 *  @type function
8803		 *  @param {object} oSettings DataTables settings object
8804		 *  @param {object} oData The state object that is to be loaded
8805		 *  @dtopt Callbacks
8806		 * 
8807		 *  @example
8808		 *    // Remove a saved filter, so filtering is never loaded
8809		 *    $(document).ready( function() {
8810		 *      $('#example').dataTable( {
8811		 *        "bStateSave": true,
8812		 *        "fnStateLoadParams": function (oSettings, oData) {
8813		 *          oData.oSearch.sSearch = "";
8814		 *        }
8815		 *      } );
8816		 *    } );
8817		 * 
8818		 *  @example
8819		 *    // Disallow state loading by returning false
8820		 *    $(document).ready( function() {
8821		 *      $('#example').dataTable( {
8822		 *        "bStateSave": true,
8823		 *        "fnStateLoadParams": function (oSettings, oData) {
8824		 *          return false;
8825		 *        }
8826		 *      } );
8827		 *    } );
8828		 */
8829		"fnStateLoadParams": null,
8830	
8831	
8832		/**
8833		 * Callback that is called when the state has been loaded from the state saving method
8834		 * and the DataTables settings object has been modified as a result of the loaded state.
8835		 *  @type function
8836		 *  @param {object} oSettings DataTables settings object
8837		 *  @param {object} oData The state object that was loaded
8838		 *  @dtopt Callbacks
8839		 * 
8840		 *  @example
8841		 *    // Show an alert with the filtering value that was saved
8842		 *    $(document).ready( function() {
8843		 *      $('#example').dataTable( {
8844		 *        "bStateSave": true,
8845		 *        "fnStateLoaded": function (oSettings, oData) {
8846		 *          alert( 'Saved filter was: '+oData.oSearch.sSearch );
8847		 *        }
8848		 *      } );
8849		 *    } );
8850		 */
8851		"fnStateLoaded": null,
8852	
8853	
8854		/**
8855		 * Save the table state. This function allows you to define where and how the state
8856		 * information for the table is stored - by default it will use a cookie, but you
8857		 * might want to use local storage (HTML5) or a server-side database.
8858		 *  @type function
8859		 *  @member
8860		 *  @param {object} oSettings DataTables settings object
8861		 *  @param {object} oData The state object to be saved
8862		 *  @dtopt Callbacks
8863		 * 
8864		 *  @example
8865		 *    $(document).ready( function() {
8866		 *      $('#example').dataTable( {
8867		 *        "bStateSave": true,
8868		 *        "fnStateSave": function (oSettings, oData) {
8869		 *          // Send an Ajax request to the server with the state object
8870		 *          $.ajax( {
8871		 *            "url": "/state_save",
8872		 *            "data": oData,
8873		 *            "dataType": "json",
8874		 *            "method": "POST"
8875		 *            "success": function () {}
8876		 *          } );
8877		 *        }
8878		 *      } );
8879		 *    } );
8880		 */
8881		"fnStateSave": function ( oSettings, oData ) {
8882			this.oApi._fnCreateCookie( 
8883				oSettings.sCookiePrefix+oSettings.sInstance, 
8884				this.oApi._fnJsonString(oData), 
8885				oSettings.iCookieDuration, 
8886				oSettings.sCookiePrefix, 
8887				oSettings.fnCookieCallback
8888			);
8889		},
8890	
8891	
8892		/**
8893		 * Callback which allows modification of the state to be saved. Called when the table 
8894		 * has changed state a new state save is required. This method allows modification of
8895		 * the state saving object prior to actually doing the save, including addition or 
8896		 * other state properties or modification. Note that for plug-in authors, you should 
8897		 * use the 'stateSaveParams' event to save parameters for a plug-in.
8898		 *  @type function
8899		 *  @param {object} oSettings DataTables settings object
8900		 *  @param {object} oData The state object to be saved
8901		 *  @dtopt Callbacks
8902		 * 
8903		 *  @example
8904		 *    // Remove a saved filter, so filtering is never saved
8905		 *    $(document).ready( function() {
8906		 *      $('#example').dataTable( {
8907		 *        "bStateSave": true,
8908		 *        "fnStateSaveParams": function (oSettings, oData) {
8909		 *          oData.oSearch.sSearch = "";
8910		 *        }
8911		 *      } );
8912		 *    } );
8913		 */
8914		"fnStateSaveParams": null,
8915	
8916	
8917		/**
8918		 * Duration of the cookie which is used for storing session information. This
8919		 * value is given in seconds.
8920		 *  @type int
8921		 *  @default 7200 <i>(2 hours)</i>
8922		 *  @dtopt Options
8923		 * 
8924		 *  @example
8925		 *    $(document).ready( function() {
8926		 *      $('#example').dataTable( {
8927		 *        "iCookieDuration": 60*60*24; // 1 day
8928		 *      } );
8929		 *    } )
8930		 */
8931		"iCookieDuration": 7200,
8932	
8933	
8934		/**
8935		 * When enabled DataTables will not make a request to the server for the first
8936		 * page draw - rather it will use the data already on the page (no sorting etc
8937		 * will be applied to it), thus saving on an XHR at load time. iDeferLoading
8938		 * is used to indicate that deferred loading is required, but it is also used
8939		 * to tell DataTables how many records there are in the full table (allowing
8940		 * the information element and pagination to be displayed correctly). In the case
8941		 * where a filtering is applied to the table on initial load, this can be
8942		 * indicated by giving the parameter as an array, where the first element is
8943		 * the number of records available after filtering and the second element is the
8944		 * number of records without filtering (allowing the table information element
8945		 * to be shown correctly).
8946		 *  @type int | array
8947		 *  @default null
8948		 *  @dtopt Options
8949		 * 
8950		 *  @example
8951		 *    // 57 records available in the table, no filtering applied
8952		 *    $(document).ready( function() {
8953		 *      $('#example').dataTable( {
8954		 *        "bServerSide": true,
8955		 *        "sAjaxSource": "scripts/server_processing.php",
8956		 *        "iDeferLoading": 57
8957		 *      } );
8958		 *    } );
8959		 * 
8960		 *  @example
8961		 *    // 57 records after filtering, 100 without filtering (an initial filter applied)
8962		 *    $(document).ready( function() {
8963		 *      $('#example').dataTable( {
8964		 *        "bServerSide": true,
8965		 *        "sAjaxSource": "scripts/server_processing.php",
8966		 *        "iDeferLoading": [ 57, 100 ],
8967		 *        "oSearch": {
8968		 *          "sSearch": "my_filter"
8969		 *        }
8970		 *      } );
8971		 *    } );
8972		 */
8973		"iDeferLoading": null,
8974	
8975	
8976		/**
8977		 * Number of rows to display on a single page when using pagination. If
8978		 * feature enabled (bLengthChange) then the end user will be able to override
8979		 * this to a custom setting using a pop-up menu.
8980		 *  @type int
8981		 *  @default 10
8982		 *  @dtopt Options
8983		 * 
8984		 *  @example
8985		 *    $(document).ready( function() {
8986		 *      $('#example').dataTable( {
8987		 *        "iDisplayLength": 50
8988		 *      } );
8989		 *    } )
8990		 */
8991		"iDisplayLength": 10,
8992	
8993	
8994		/**
8995		 * Define the starting point for data display when using DataTables with
8996		 * pagination. Note that this parameter is the number of records, rather than
8997		 * the page number, so if you have 10 records per page and want to start on
8998		 * the third page, it should be "20".
8999		 *  @type int
9000		 *  @default 0
9001		 *  @dtopt Options
9002		 * 
9003		 *  @example
9004		 *    $(document).ready( function() {
9005		 *      $('#example').dataTable( {
9006		 *        "iDisplayStart": 20
9007		 *      } );
9008		 *    } )
9009		 */
9010		"iDisplayStart": 0,
9011	
9012	
9013		/**
9014		 * The scroll gap is the amount of scrolling that is left to go before
9015		 * DataTables will load the next 'page' of data automatically. You typically
9016		 * want a gap which is big enough that the scrolling will be smooth for the
9017		 * user, while not so large that it will load more data than need.
9018		 *  @type int
9019		 *  @default 100
9020		 *  @dtopt Options
9021		 * 
9022		 *  @example
9023		 *    $(document).ready( function() {
9024		 *      $('#example').dataTable( {
9025		 *        "bScrollInfinite": true,
9026		 *        "bScrollCollapse": true,
9027		 *        "sScrollY": "200px",
9028		 *        "iScrollLoadGap": 50
9029		 *      } );
9030		 *    } );
9031		 */
9032		"iScrollLoadGap": 100,
9033	
9034	
9035		/**
9036		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
9037		 * and filtering) by adding a tabindex attribute to the required elements. This
9038		 * allows you to tab through the controls and press the enter key to activate them.
9039		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
9040		 * You can overrule this using this parameter if you wish. Use a value of -1 to
9041		 * disable built-in keyboard navigation.
9042		 *  @type int
9043		 *  @default 0
9044		 *  @dtopt Options
9045		 * 
9046		 *  @example
9047		 *    $(document).ready( function() {
9048		 *      $('#example').dataTable( {
9049		 *        "iTabIndex": 1
9050		 *      } );
9051		 *    } );
9052		 */
9053		"iTabIndex": 0,
9054	
9055	
9056		/**
9057		 * All strings that DataTables uses in the user interface that it creates
9058		 * are defined in this object, allowing you to modified them individually or
9059		 * completely replace them all as required.
9060		 *  @namespace
9061		 */
9062		"oLanguage": {
9063			/**
9064			 * Strings that are used for WAI-ARIA labels and controls only (these are not
9065			 * actually visible on the page, but will be read by screenreaders, and thus
9066			 * must be internationalised as well).
9067			 *  @namespace
9068			 */
9069			"oAria": {
9070				/**
9071				 * ARIA label that is added to the table headers when the column may be
9072				 * sorted ascending by activing the column (click or return when focused).
9073				 * Note that the column header is prefixed to this string.
9074				 *  @type string
9075				 *  @default : activate to sort column ascending
9076				 *  @dtopt Language
9077				 * 
9078				 *  @example
9079				 *    $(document).ready( function() {
9080				 *      $('#example').dataTable( {
9081				 *        "oLanguage": {
9082				 *          "oAria": {
9083				 *            "sSortAscending": " - click/return to sort ascending"
9084				 *          }
9085				 *        }
9086				 *      } );
9087				 *    } );
9088				 */
9089				"sSortAscending": ": activate to sort column ascending",
9090	
9091				/**
9092				 * ARIA label that is added to the table headers when the column may be
9093				 * sorted descending by activing the column (click or return when focused).
9094				 * Note that the column header is prefixed to this string.
9095				 *  @type string
9096				 *  @default : activate to sort column ascending
9097				 *  @dtopt Language
9098				 * 
9099				 *  @example
9100				 *    $(document).ready( function() {
9101				 *      $('#example').dataTable( {
9102				 *        "oLanguage": {
9103				 *          "oAria": {
9104				 *            "sSortDescending": " - click/return to sort descending"
9105				 *          }
9106				 *        }
9107				 *      } );
9108				 *    } );
9109				 */
9110				"sSortDescending": ": activate to sort column descending"
9111			},
9112	
9113			/**
9114			 * Pagination string used by DataTables for the two built-in pagination
9115			 * control types ("two_button" and "full_numbers")
9116			 *  @namespace
9117			 */
9118			"oPaginate": {
9119				/**
9120				 * Text to use when using the 'full_numbers' type of pagination for the
9121				 * button to take the user to the first page.
9122				 *  @type string
9123				 *  @default First
9124				 *  @dtopt Language
9125				 * 
9126				 *  @example
9127				 *    $(document).ready( function() {
9128				 *      $('#example').dataTable( {
9129				 *        "oLanguage": {
9130				 *          "oPaginate": {
9131				 *            "sFirst": "First page"
9132				 *          }
9133				 *        }
9134				 *      } );
9135				 *    } );
9136				 */
9137				"sFirst": "First",
9138			
9139			
9140				/**
9141				 * Text to use when using the 'full_numbers' type of pagination for the
9142				 * button to take the user to the last page.
9143				 *  @type string
9144				 *  @default Last
9145				 *  @dtopt Language
9146				 * 
9147				 *  @example
9148				 *    $(document).ready( function() {
9149				 *      $('#example').dataTable( {
9150				 *        "oLanguage": {
9151				 *          "oPaginate": {
9152				 *            "sLast": "Last page"
9153				 *          }
9154				 *        }
9155				 *      } );
9156				 *    } );
9157				 */
9158				"sLast": "Last",
9159			
9160			
9161				/**
9162				 * Text to use for the 'next' pagination button (to take the user to the 
9163				 * next page).
9164				 *  @type string
9165				 *  @default Next
9166				 *  @dtopt Language
9167				 * 
9168				 *  @example
9169				 *    $(document).ready( function() {
9170				 *      $('#example').dataTable( {
9171				 *        "oLanguage": {
9172				 *          "oPaginate": {
9173				 *            "sNext": "Next page"
9174				 *          }
9175				 *        }
9176				 *      } );
9177				 *    } );
9178				 */
9179				"sNext": "Next",
9180			
9181			
9182				/**
9183				 * Text to use for the 'previous' pagination button (to take the user to  
9184				 * the previous page).
9185				 *  @type string
9186				 *  @default Previous
9187				 *  @dtopt Language
9188				 * 
9189				 *  @example
9190				 *    $(document).ready( function() {
9191				 *      $('#example').dataTable( {
9192				 *        "oLanguage": {
9193				 *          "oPaginate": {
9194				 *            "sPrevious": "Previous page"
9195				 *          }
9196				 *        }
9197				 *      } );
9198				 *    } );
9199				 */
9200				"sPrevious": "Previous"
9201			},
9202		
9203			/**
9204			 * This string is shown in preference to sZeroRecords when the table is
9205			 * empty of data (regardless of filtering). Note that this is an optional
9206			 * parameter - if it is not given, the value of sZeroRecords will be used
9207			 * instead (either the default or given value).
9208			 *  @type string
9209			 *  @default No data available in table
9210			 *  @dtopt Language
9211			 * 
9212			 *  @example
9213			 *    $(document).ready( function() {
9214			 *      $('#example').dataTable( {
9215			 *        "oLanguage": {
9216			 *          "sEmptyTable": "No data available in table"
9217			 *        }
9218			 *      } );
9219			 *    } );
9220			 */
9221			"sEmptyTable": "No data available in table",
9222		
9223		
9224			/**
9225			 * This string gives information to the end user about the information that 
9226			 * is current on display on the page. The _START_, _END_ and _TOTAL_ 
9227			 * variables are all dynamically replaced as the table display updates, and 
9228			 * can be freely moved or removed as the language requirements change.
9229			 *  @type string
9230			 *  @default Showing _START_ to _END_ of _TOTAL_ entries
9231			 *  @dtopt Language
9232			 * 
9233			 *  @example
9234			 *    $(document).ready( function() {
9235			 *      $('#example').dataTable( {
9236			 *        "oLanguage": {
9237			 *          "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"
9238			 *        }
9239			 *      } );
9240			 *    } );
9241			 */
9242			"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
9243		
9244		
9245			/**
9246			 * Display information string for when the table is empty. Typically the 
9247			 * format of this string should match sInfo.
9248			 *  @type string
9249			 *  @default Showing 0 to 0 of 0 entries
9250			 *  @dtopt Language
9251			 * 
9252			 *  @example
9253			 *    $(document).ready( function() {
9254			 *      $('#example').dataTable( {
9255			 *        "oLanguage": {
9256			 *          "sInfoEmpty": "No entries to show"
9257			 *        }
9258			 *      } );
9259			 *    } );
9260			 */
9261			"sInfoEmpty": "Showing 0 to 0 of 0 entries",
9262		
9263		
9264			/**
9265			 * When a user filters the information in a table, this string is appended 
9266			 * to the information (sInfo) to give an idea of how strong the filtering 
9267			 * is. The variable _MAX_ is dynamically updated.
9268			 *  @type string
9269			 *  @default (filtered from _MAX_ total entries)
9270			 *  @dtopt Language
9271			 * 
9272			 *  @example
9273			 *    $(document).ready( function() {
9274			 *      $('#example').dataTable( {
9275			 *        "oLanguage": {
9276			 *          "sInfoFiltered": " - filtering from _MAX_ records"
9277			 *        }
9278			 *      } );
9279			 *    } );
9280			 */
9281			"sInfoFiltered": "(filtered from _MAX_ total entries)",
9282		
9283		
9284			/**
9285			 * If can be useful to append extra information to the info string at times,
9286			 * and this variable does exactly that. This information will be appended to
9287			 * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are
9288			 * being used) at all times.
9289			 *  @type string
9290			 *  @default <i>Empty string</i>
9291			 *  @dtopt Language
9292			 * 
9293			 *  @example
9294			 *    $(document).ready( function() {
9295			 *      $('#example').dataTable( {
9296			 *        "oLanguage": {
9297			 *          "sInfoPostFix": "All records shown are derived from real information."
9298			 *        }
9299			 *      } );
9300			 *    } );
9301			 */
9302			"sInfoPostFix": "",
9303		
9304		
9305			/**
9306			 * DataTables has a build in number formatter (fnFormatNumber) which is used
9307			 * to format large numbers that are used in the table information. By
9308			 * default a comma is used, but this can be trivially changed to any
9309			 * character you wish with this parameter.
9310			 *  @type string
9311			 *  @default ,
9312			 *  @dtopt Language
9313			 * 
9314			 *  @example
9315			 *    $(document).ready( function() {
9316			 *      $('#example').dataTable( {
9317			 *        "oLanguage": {
9318			 *          "sInfoThousands": "'"
9319			 *        }
9320			 *      } );
9321			 *    } );
9322			 */
9323			"sInfoThousands": ",",
9324		
9325		
9326			/**
9327			 * Detail the action that will be taken when the drop down menu for the
9328			 * pagination length option is changed. The '_MENU_' variable is replaced
9329			 * with a default select list of 10, 25, 50 and 100, and can be replaced
9330			 * with a custom select box if required.
9331			 *  @type string
9332			 *  @default Show _MENU_ entries
9333			 *  @dtopt Language
9334			 * 
9335			 *  @example
9336			 *    // Language change only
9337			 *    $(document).ready( function() {
9338			 *      $('#example').dataTable( {
9339			 *        "oLanguage": {
9340			 *          "sLengthMenu": "Display _MENU_ records"
9341			 *        }
9342			 *      } );
9343			 *    } );
9344			 *    
9345			 *  @example
9346			 *    // Language and options change
9347			 *    $(document).ready( function() {
9348			 *      $('#example').dataTable( {
9349			 *        "oLanguage": {
9350			 *          "sLengthMenu": 'Display <select>'+
9351			 *            '<option value="10">10</option>'+
9352			 *            '<option value="20">20</option>'+
9353			 *            '<option value="30">30</option>'+
9354			 *            '<option value="40">40</option>'+
9355			 *            '<option value="50">50</option>'+
9356			 *            '<option value="-1">All</option>'+
9357			 *            '</select> records'
9358			 *        }
9359			 *      } );
9360			 *    } );
9361			 */
9362			"sLengthMenu": "Show _MENU_ entries",
9363		
9364		
9365			/**
9366			 * When using Ajax sourced data and during the first draw when DataTables is
9367			 * gathering the data, this message is shown in an empty row in the table to
9368			 * indicate to the end user the the data is being loaded. Note that this
9369			 * parameter is not used when loading data by server-side processing, just
9370			 * Ajax sourced data with client-side processing.
9371			 *  @type string
9372			 *  @default Loading...
9373			 *  @dtopt Language
9374			 * 
9375			 *  @example
9376			 *    $(document).ready( function() {
9377			 *      $('#example').dataTable( {
9378			 *        "oLanguage": {
9379			 *          "sLoadingRecords": "Please wait - loading..."
9380			 *        }
9381			 *      } );
9382			 *    } );
9383			 */
9384			"sLoadingRecords": "Loading...",
9385		
9386		
9387			/**
9388			 * Text which is displayed when the table is processing a user action
9389			 * (usually a sort command or similar).
9390			 *  @type string
9391			 *  @default Processing...
9392			 *  @dtopt Language
9393			 * 
9394			 *  @example
9395			 *    $(document).ready( function() {
9396			 *      $('#example').dataTable( {
9397			 *        "oLanguage": {
9398			 *          "sProcessing": "DataTables is currently busy"
9399			 *        }
9400			 *      } );
9401			 *    } );
9402			 */
9403			"sProcessing": "Processing...",
9404		
9405		
9406			/**
9407			 * Details the actions that will be taken when the user types into the
9408			 * filtering input text box. The variable "_INPUT_", if used in the string,
9409			 * is replaced with the HTML text box for the filtering input allowing
9410			 * control over where it appears in the string. If "_INPUT_" is not given
9411			 * then the input box is appended to the string automatically.
9412			 *  @type string
9413			 *  @default Search:
9414			 *  @dtopt Language
9415			 * 
9416			 *  @example
9417			 *    // Input text box will be appended at the end automatically
9418			 *    $(document).ready( function() {
9419			 *      $('#example').dataTable( {
9420			 *        "oLanguage": {
9421			 *          "sSearch": "Filter records:"
9422			 *        }
9423			 *      } );
9424			 *    } );
9425			 *    
9426			 *  @example
9427			 *    // Specify where the filter should appear
9428			 *    $(document).ready( function() {
9429			 *      $('#example').dataTable( {
9430			 *        "oLanguage": {
9431			 *          "sSearch": "Apply filter _INPUT_ to table"
9432			 *        }
9433			 *      } );
9434			 *    } );
9435			 */
9436			"sSearch": "Search:",
9437		
9438		
9439			/**
9440			 * All of the language information can be stored in a file on the
9441			 * server-side, which DataTables will look up if this parameter is passed.
9442			 * It must store the URL of the language file, which is in a JSON format,
9443			 * and the object has the same properties as the oLanguage object in the
9444			 * initialiser object (i.e. the above parameters). Please refer to one of
9445			 * the example language files to see how this works in action.
9446			 *  @type string
9447			 *  @default <i>Empty string - i.e. disabled</i>
9448			 *  @dtopt Language
9449			 * 
9450			 *  @example
9451			 *    $(document).ready( function() {
9452			 *      $('#example').dataTable( {
9453			 *        "oLanguage": {
9454			 *          "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"
9455			 *        }
9456			 *      } );
9457			 *    } );
9458			 */
9459			"sUrl": "",
9460		
9461		
9462			/**
9463			 * Text shown inside the table records when the is no information to be
9464			 * displayed after filtering. sEmptyTable is shown when there is simply no
9465			 * information in the table at all (regardless of filtering).
9466			 *  @type string
9467			 *  @default No matching records found
9468			 *  @dtopt Language
9469			 * 
9470			 *  @example
9471			 *    $(document).ready( function() {
9472			 *      $('#example').dataTable( {
9473			 *        "oLanguage": {
9474			 *          "sZeroRecords": "No records to display"
9475			 *        }
9476			 *      } );
9477			 *    } );
9478			 */
9479			"sZeroRecords": "No matching records found"
9480		},
9481	
9482	
9483		/**
9484		 * This parameter allows you to have define the global filtering state at
9485		 * initialisation time. As an object the "sSearch" parameter must be
9486		 * defined, but all other parameters are optional. When "bRegex" is true,
9487		 * the search string will be treated as a regular expression, when false
9488		 * (default) it will be treated as a straight string. When "bSmart"
9489		 * DataTables will use it's smart filtering methods (to word match at
9490		 * any point in the data), when false this will not be done.
9491		 *  @namespace
9492		 *  @extends DataTable.models.oSearch
9493		 *  @dtopt Options
9494		 * 
9495		 *  @example
9496		 *    $(document).ready( function() {
9497		 *      $('#example').dataTable( {
9498		 *        "oSearch": {"sSearch": "Initial search"}
9499		 *      } );
9500		 *    } )
9501		 */
9502		"oSearch": $.extend( {}, DataTable.models.oSearch ),
9503	
9504	
9505		/**
9506		 * By default DataTables will look for the property 'aaData' when obtaining
9507		 * data from an Ajax source or for server-side processing - this parameter
9508		 * allows that property to be changed. You can use Javascript dotted object
9509		 * notation to get a data source for multiple levels of nesting.
9510		 *  @type string
9511		 *  @default aaData
9512		 *  @dtopt Options
9513		 *  @dtopt Server-side
9514		 * 
9515		 *  @example
9516		 *    // Get data from { "data": [...] }
9517		 *    $(document).ready( function() {
9518		 *      var oTable = $('#example').dataTable( {
9519		 *        "sAjaxSource": "sources/data.txt",
9520		 *        "sAjaxDataProp": "data"
9521		 *      } );
9522		 *    } );
9523		 *    
9524		 *  @example
9525		 *    // Get data from { "data": { "inner": [...] } }
9526		 *    $(document).ready( function() {
9527		 *      var oTable = $('#example').dataTable( {
9528		 *        "sAjaxSource": "sources/data.txt",
9529		 *        "sAjaxDataProp": "data.inner"
9530		 *      } );
9531		 *    } );
9532		 */
9533		"sAjaxDataProp": "aaData",
9534	
9535	
9536		/**
9537		 * You can instruct DataTables to load data from an external source using this
9538		 * parameter (use aData if you want to pass data in you already have). Simply
9539		 * provide a url a JSON object can be obtained from. This object must include
9540		 * the parameter 'aaData' which is the data source for the table.
9541		 *  @type string
9542		 *  @default null
9543		 *  @dtopt Options
9544		 *  @dtopt Server-side
9545		 * 
9546		 *  @example
9547		 *    $(document).ready( function() {
9548		 *      $('#example').dataTable( {
9549		 *        "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"
9550		 *      } );
9551		 *    } )
9552		 */
9553		"sAjaxSource": null,
9554	
9555	
9556		/**
9557		 * This parameter can be used to override the default prefix that DataTables
9558		 * assigns to a cookie when state saving is enabled.
9559		 *  @type string
9560		 *  @default SpryMedia_DataTables_
9561		 *  @dtopt Options
9562		 * 
9563		 *  @example
9564		 *    $(document).ready( function() {
9565		 *      $('#example').dataTable( {
9566		 *        "sCookiePrefix": "my_datatable_",
9567		 *      } );
9568		 *    } );
9569		 */
9570		"sCookiePrefix": "SpryMedia_DataTables_",
9571	
9572	
9573		/**
9574		 * This initialisation variable allows you to specify exactly where in the
9575		 * DOM you want DataTables to inject the various controls it adds to the page
9576		 * (for example you might want the pagination controls at the top of the
9577		 * table). DIV elements (with or without a custom class) can also be added to
9578		 * aid styling. The follow syntax is used:
9579		 *   <ul>
9580		 *     <li>The following options are allowed:	
9581		 *       <ul>
9582		 *         <li>'l' - Length changing</li
9583		 *         <li>'f' - Filtering input</li>
9584		 *         <li>'t' - The table!</li>
9585		 *         <li>'i' - Information</li>
9586		 *         <li>'p' - Pagination</li>
9587		 *         <li>'r' - pRocessing</li>
9588		 *       </ul>
9589		 *     </li>
9590		 *     <li>The following constants are allowed:
9591		 *       <ul>
9592		 *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
9593		 *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
9594		 *       </ul>
9595		 *     </li>
9596		 *     <li>The following syntax is expected:
9597		 *       <ul>
9598		 *         <li>'&lt;' and '&gt;' - div elements</li>
9599		 *         <li>'&lt;"class" and '&gt;' - div with a class</li>
9600		 *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
9601		 *       </ul>
9602		 *     </li>
9603		 *     <li>Examples:
9604		 *       <ul>
9605		 *         <li>'&lt;"wrapper"flipt&gt;'</li>
9606		 *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
9607		 *       </ul>
9608		 *     </li>
9609		 *   </ul>
9610		 *  @type string
9611		 *  @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b> 
9612		 *    <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i>
9613		 *  @dtopt Options
9614		 * 
9615		 *  @example
9616		 *    $(document).ready( function() {
9617		 *      $('#example').dataTable( {
9618		 *        "sDom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
9619		 *      } );
9620		 *    } );
9621		 */
9622		"sDom": "lfrtip",
9623	
9624	
9625		/**
9626		 * DataTables features two different built-in pagination interaction methods
9627		 * ('two_button' or 'full_numbers') which present different page controls to
9628		 * the end user. Further methods can be added using the API (see below).
9629		 *  @type string
9630		 *  @default two_button
9631		 *  @dtopt Options
9632		 * 
9633		 *  @example
9634		 *    $(document).ready( function() {
9635		 *      $('#example').dataTable( {
9636		 *        "sPaginationType": "full_numbers"
9637		 *      } );
9638		 *    } )
9639		 */
9640		"sPaginationType": "two_button",
9641	
9642	
9643		/**
9644		 * Enable horizontal scrolling. When a table is too wide to fit into a certain
9645		 * layout, or you have a large number of columns in the table, you can enable
9646		 * x-scrolling to show the table in a viewport, which can be scrolled. This
9647		 * property can be any CSS unit, or a number (in which case it will be treated
9648		 * as a pixel measurement).
9649		 *  @type string
9650		 *  @default <i>blank string - i.e. disabled</i>
9651		 *  @dtopt Features
9652		 * 
9653		 *  @example
9654		 *    $(document).ready( function() {
9655		 *      $('#example').dataTable( {
9656		 *        "sScrollX": "100%",
9657		 *        "bScrollCollapse": true
9658		 *      } );
9659		 *    } );
9660		 */
9661		"sScrollX": "",
9662	
9663	
9664		/**
9665		 * This property can be used to force a DataTable to use more width than it
9666		 * might otherwise do when x-scrolling is enabled. For example if you have a
9667		 * table which requires to be well spaced, this parameter is useful for
9668		 * "over-sizing" the table, and thus forcing scrolling. This property can by
9669		 * any CSS unit, or a number (in which case it will be treated as a pixel
9670		 * measurement).
9671		 *  @type string
9672		 *  @default <i>blank string - i.e. disabled</i>
9673		 *  @dtopt Options
9674		 * 
9675		 *  @example
9676		 *    $(document).ready( function() {
9677		 *      $('#example').dataTable( {
9678		 *        "sScrollX": "100%",
9679		 *        "sScrollXInner": "110%"
9680		 *      } );
9681		 *    } );
9682		 */
9683		"sScrollXInner": "",
9684	
9685	
9686		/**
9687		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
9688		 * to the given height, and enable scrolling for any data which overflows the
9689		 * current viewport. This can be used as an alternative to paging to display
9690		 * a lot of data in a small area (although paging and scrolling can both be
9691		 * enabled at the same time). This property can be any CSS unit, or a number
9692		 * (in which case it will be treated as a pixel measurement).
9693		 *  @type string
9694		 *  @default <i>blank string - i.e. disabled</i>
9695		 *  @dtopt Features
9696		 * 
9697		 *  @example
9698		 *    $(document).ready( function() {
9699		 *      $('#example').dataTable( {
9700		 *        "sScrollY": "200px",
9701		 *        "bPaginate": false
9702		 *      } );
9703		 *    } );
9704		 */
9705		"sScrollY": "",
9706	
9707	
9708		/**
9709		 * Set the HTTP method that is used to make the Ajax call for server-side
9710		 * processing or Ajax sourced data.
9711		 *  @type string
9712		 *  @default GET
9713		 *  @dtopt Options
9714		 *  @dtopt Server-side
9715		 * 
9716		 *  @example
9717		 *    $(document).ready( function() {
9718		 *      $('#example').dataTable( {
9719		 *        "bServerSide": true,
9720		 *        "sAjaxSource": "scripts/post.php",
9721		 *        "sServerMethod": "POST"
9722		 *      } );
9723		 *    } );
9724		 */
9725		"sServerMethod": "GET"
9726	};
9727	
9728	
9729	
9730	/**
9731	 * Column options that can be given to DataTables at initialisation time.
9732	 *  @namespace
9733	 */
9734	DataTable.defaults.columns = {
9735		/**
9736		 * Allows a column's sorting to take multiple columns into account when 
9737		 * doing a sort. For example first name / last name columns make sense to 
9738		 * do a multi-column sort over the two columns.
9739		 *  @type array
9740		 *  @default null <i>Takes the value of the column index automatically</i>
9741		 *  @dtopt Columns
9742		 * 
9743		 *  @example
9744		 *    // Using aoColumnDefs
9745		 *    $(document).ready( function() {
9746		 *      $('#example').dataTable( {
9747		 *        "aoColumnDefs": [
9748		 *          { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] },
9749		 *          { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] },
9750		 *          { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] }
9751		 *        ]
9752		 *      } );
9753		 *    } );
9754		 *    
9755		 *  @example
9756		 *    // Using aoColumns
9757		 *    $(document).ready( function() {
9758		 *      $('#example').dataTable( {
9759		 *        "aoColumns": [
9760		 *          { "aDataSort": [ 0, 1 ] },
9761		 *          { "aDataSort": [ 1, 0 ] },
9762		 *          { "aDataSort": [ 2, 3, 4 ] },
9763		 *          null,
9764		 *          null
9765		 *        ]
9766		 *      } );
9767		 *    } );
9768		 */
9769		"aDataSort": null,
9770	
9771	
9772		/**
9773		 * You can control the default sorting direction, and even alter the behaviour
9774		 * of the sort handler (i.e. only allow ascending sorting etc) using this
9775		 * parameter.
9776		 *  @type array
9777		 *  @default [ 'asc', 'desc' ]
9778		 *  @dtopt Columns
9779		 * 
9780		 *  @example
9781		 *    // Using aoColumnDefs
9782		 *    $(document).ready( function() {
9783		 *      $('#example').dataTable( {
9784		 *        "aoColumnDefs": [
9785		 *          { "asSorting": [ "asc" ], "aTargets": [ 1 ] },
9786		 *          { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] },
9787		 *          { "asSorting": [ "desc" ], "aTargets": [ 3 ] }
9788		 *        ]
9789		 *      } );
9790		 *    } );
9791		 *    
9792		 *  @example
9793		 *    // Using aoColumns
9794		 *    $(document).ready( function() {
9795		 *      $('#example').dataTable( {
9796		 *        "aoColumns": [
9797		 *          null,
9798		 *          { "asSorting": [ "asc" ] },
9799		 *          { "asSorting": [ "desc", "asc", "asc" ] },
9800		 *          { "asSorting": [ "desc" ] },
9801		 *          null
9802		 *        ]
9803		 *      } );
9804		 *    } );
9805		 */
9806		"asSorting": [ 'asc', 'desc' ],
9807	
9808	
9809		/**
9810		 * Enable or disable filtering on the data in this column.
9811		 *  @type boolean
9812		 *  @default true
9813		 *  @dtopt Columns
9814		 * 
9815		 *  @example
9816		 *    // Using aoColumnDefs
9817		 *    $(document).ready( function() {
9818		 *      $('#example').dataTable( {
9819		 *        "aoColumnDefs": [ 
9820		 *          { "bSearchable": false, "aTargets": [ 0 ] }
9821		 *        ] } );
9822		 *    } );
9823		 *    
9824		 *  @example
9825		 *    // Using aoColumns
9826		 *    $(document).ready( function() {
9827		 *      $('#example').dataTable( {
9828		 *        "aoColumns": [ 
9829		 *          { "bSearchable": false },
9830		 *          null,
9831		 *          null,
9832		 *          null,
9833		 *          null
9834		 *        ] } );
9835		 *    } );
9836		 */
9837		"bSearchable": true,
9838	
9839	
9840		/**
9841		 * Enable or disable sorting on this column.
9842		 *  @type boolean
9843		 *  @default true
9844		 *  @dtopt Columns
9845		 * 
9846		 *  @example
9847		 *    // Using aoColumnDefs
9848		 *    $(document).ready( function() {
9849		 *      $('#example').dataTable( {
9850		 *        "aoColumnDefs": [ 
9851		 *          { "bSortable": false, "aTargets": [ 0 ] }
9852		 *        ] } );
9853		 *    } );
9854		 *    
9855		 *  @example
9856		 *    // Using aoColumns
9857		 *    $(document).ready( function() {
9858		 *      $('#example').dataTable( {
9859		 *        "aoColumns": [ 
9860		 *          { "bSortable": false },
9861		 *          null,
9862		 *          null,
9863		 *          null,
9864		 *          null
9865		 *        ] } );
9866		 *    } );
9867		 */
9868		"bSortable": true,
9869	
9870	
9871		/**
9872		 * <code>Deprecated</code> When using fnRender() for a column, you may wish 
9873		 * to use the original data (before rendering) for sorting and filtering 
9874		 * (the default is to used the rendered data that the user can see). This 
9875		 * may be useful for dates etc.
9876		 * 
9877		 * Please note that this option has now been deprecated and will be removed
9878		 * in the next version of DataTables. Please use mRender / mData rather than
9879		 * fnRender.
9880		 *  @type boolean
9881		 *  @default true
9882		 *  @dtopt Columns
9883		 *  @deprecated
9884		 */
9885		"bUseRendered": true,
9886	
9887	
9888		/**
9889		 * Enable or disable the display of 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		 *          { "bVisible": false, "aTargets": [ 0 ] }
9900		 *        ] } );
9901		 *    } );
9902		 *    
9903		 *  @example
9904		 *    // Using aoColumns
9905		 *    $(document).ready( function() {
9906		 *      $('#example').dataTable( {
9907		 *        "aoColumns": [ 
9908		 *          { "bVisible": false },
9909		 *          null,
9910		 *          null,
9911		 *          null,
9912		 *          null
9913		 *        ] } );
9914		 *    } );
9915		 */
9916		"bVisible": true,
9917		
9918		
9919		/**
9920		 * Developer definable function that is called whenever a cell is created (Ajax source,
9921		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9922		 * allowing you to modify the DOM element (add background colour for example) when the
9923		 * element is available.
9924		 *  @type function
9925		 *  @param {element} nTd The TD node that has been created
9926		 *  @param {*} sData The Data for the cell
9927		 *  @param {array|object} oData The data for the whole row
9928		 *  @param {int} iRow The row index for the aoData data store
9929		 *  @param {int} iCol The column index for aoColumns
9930		 *  @dtopt Columns
9931		 * 
9932		 *  @example
9933		 *    $(document).ready( function() {
9934		 *      $('#example').dataTable( {
9935		 *        "aoColumnDefs": [ {
9936		 *          "aTargets": [3],
9937		 *          "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
9938		 *            if ( sData == "1.7" ) {
9939		 *              $(nTd).css('color', 'blue')
9940		 *            }
9941		 *          }
9942		 *        } ]
9943		 *      });
9944		 *    } );
9945		 */
9946		"fnCreatedCell": null,
9947	
9948	
9949		/**
9950		 * <code>Deprecated</code> Custom display function that will be called for the 
9951		 * display of each cell in this column.
9952		 *
9953		 * Please note that this option has now been deprecated and will be removed
9954		 * in the next version of DataTables. Please use mRender / mData rather than
9955		 * fnRender.
9956		 *  @type function
9957		 *  @param {object} o Object with the following parameters:
9958		 *  @param {int}    o.iDataRow The row in aoData
9959		 *  @param {int}    o.iDataColumn The column in question
9960		 *  @param {array}  o.aData The data for the row in question
9961		 *  @param {object} o.oSettings The settings object for this DataTables instance
9962		 *  @param {object} o.mDataProp The data property used for this column
9963		 *  @param {*}      val The current cell value
9964		 *  @returns {string} The string you which to use in the display
9965		 *  @dtopt Columns
9966		 *  @deprecated
9967		 */
9968		"fnRender": null,
9969	
9970	
9971		/**
9972		 * The column index (starting from 0!) that you wish a sort to be performed
9973		 * upon when this column is selected for sorting. This can be used for sorting
9974		 * on hidden columns for example.
9975		 *  @type int
9976		 *  @default -1 <i>Use automatically calculated column index</i>
9977		 *  @dtopt Columns
9978		 * 
9979		 *  @example
9980		 *    // Using aoColumnDefs
9981		 *    $(document).ready( function() {
9982		 *      $('#example').dataTable( {
9983		 *        "aoColumnDefs": [ 
9984		 *          { "iDataSort": 1, "aTargets": [ 0 ] }
9985		 *        ]
9986		 *      } );
9987		 *    } );
9988		 *    
9989		 *  @example
9990		 *    // Using aoColumns
9991		 *    $(document).ready( function() {
9992		 *      $('#example').dataTable( {
9993		 *        "aoColumns": [ 
9994		 *          { "iDataSort": 1 },
9995		 *          null,
9996		 *          null,
9997		 *          null,
9998		 *          null
9999		 *        ]
10000		 *      } );
10001		 *    } );
10002		 */
10003		"iDataSort": -1,
10004	
10005	
10006		/**
10007		 * This parameter has been replaced by mData in DataTables to ensure naming
10008		 * consistency. mDataProp can still be used, as there is backwards compatibility
10009		 * in DataTables for this option, but it is strongly recommended that you use
10010		 * mData in preference to mDataProp.
10011		 *  @name DataTable.defaults.columns.mDataProp
10012		 */
10013	
10014	
10015		/**
10016		 * This property can be used to read data from any JSON data source property,
10017		 * including deeply nested objects / properties. mData can be given in a
10018		 * number of different ways which effect its behaviour:
10019		 *   <ul>
10020		 *     <li>integer - treated as an array index for the data source. This is the
10021		 *       default that DataTables uses (incrementally increased for each column).</li>
10022		 *     <li>string - read an object property from the data source. Note that you can
10023		 *       use Javascript dotted notation to read deep properties / arrays from the
10024		 *       data source.</li>
10025		 *     <li>null - the sDefaultContent option will be used for the cell (null
10026		 *       by default, so you will need to specify the default content you want -
10027		 *       typically an empty string). This can be useful on generated columns such 
10028		 *       as edit / delete action columns.</li>
10029		 *     <li>function - the function given will be executed whenever DataTables 
10030		 *       needs to set or get the data for a cell in the column. The function 
10031		 *       takes three parameters:
10032		 *       <ul>
10033		 *         <li>{array|object} The data source for the row</li>
10034		 *         <li>{string} The type call data requested - this will be 'set' when
10035		 *           setting data or 'filter', 'display', 'type', 'sort' or undefined when 
10036		 *           gathering data. Note that when <i>undefined</i> is given for the type
10037		 *           DataTables expects to get the raw data for the object back</li>
10038		 *         <li>{*} Data to set when the second parameter is 'set'.</li>
10039		 *       </ul>
10040		 *       The return value from the function is not required when 'set' is the type
10041		 *       of call, but otherwise the return is what will be used for the data
10042		 *       requested.</li>
10043		 *    </ul>
10044		 *
10045		 * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change
10046		 * reflects the flexibility of this property and is consistent with the naming of
10047		 * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as
10048		 * it automatically maps the old name to the new if required.
10049		 *  @type string|int|function|null
10050		 *  @default null <i>Use automatically calculated column index</i>
10051		 *  @dtopt Columns
10052		 * 
10053		 *  @example
10054		 *    // Read table data from objects
10055		 *    $(document).ready( function() {
10056		 *      var oTable = $('#example').dataTable( {
10057		 *        "sAjaxSource": "sources/deep.txt",
10058		 *        "aoColumns": [
10059		 *          { "mData": "engine" },
10060		 *          { "mData": "browser" },
10061		 *          { "mData": "platform.inner" },
10062		 *          { "mData": "platform.details.0" },
10063		 *          { "mData": "platform.details.1" }
10064		 *        ]
10065		 *      } );
10066		 *    } );
10067		 * 
10068		 *  @example
10069		 *    // Using mData as a function to provide different information for
10070		 *    // sorting, filtering and display. In this case, currency (price)
10071		 *    $(document).ready( function() {
10072		 *      var oTable = $('#example').dataTable( {
10073		 *        "aoColumnDefs": [ {
10074		 *          "aTargets": [ 0 ],
10075		 *          "mData": function ( source, type, val ) {
10076		 *            if (type === 'set') {
10077		 *              source.price = val;
10078		 *              // Store the computed dislay and filter values for efficiency
10079		 *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
10080		 *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
10081		 *              return;
10082		 *            }
10083		 *            else if (type === 'display') {
10084		 *              return source.price_display;
10085		 *            }
10086		 *            else if (type === 'filter') {
10087		 *              return source.price_filter;
10088		 *            }
10089		 *            // 'sort', 'type' and undefined all just use the integer
10090		 *            return source.price;
10091		 *          }
10092		 *        } ]
10093		 *      } );
10094		 *    } );
10095		 */
10096		"mData": null,
10097	
10098	
10099		/**
10100		 * This property is the rendering partner to mData and it is suggested that
10101		 * when you want to manipulate data for display (including filtering, sorting etc)
10102		 * but not altering the underlying data for the table, use this property. mData
10103		 * can actually do everything this property can and more, but this parameter is
10104		 * easier to use since there is no 'set' option. Like mData is can be given
10105		 * in a number of different ways to effect its behaviour, with the addition of 
10106		 * supporting array syntax for easy outputting of arrays (including arrays of
10107		 * objects):
10108		 *   <ul>
10109		 *     <li>integer - treated as an array index for the data source. This is the
10110		 *       default that DataTables uses (incrementally increased for each column).</li>
10111		 *     <li>string - read an object property from the data source. Note that you can
10112		 *       use Javascript dotted notation to read deep properties / arrays from the
10113		 *       data source and also array brackets to indicate that the data reader should
10114		 *       loop over the data source array. When characters are given between the array
10115		 *       brackets, these characters are used to join the data source array together.
10116		 *       For example: "accounts[, ].name" would result in a comma separated list with
10117		 *       the 'name' value from the 'accounts' array of objects.</li>
10118		 *     <li>function - the function given will be executed whenever DataTables 
10119		 *       needs to set or get the data for a cell in the column. The function 
10120		 *       takes three parameters:
10121		 *       <ul>
10122		 *         <li>{array|object} The data source for the row (based on mData)</li>
10123		 *         <li>{string} The type call data requested - this will be 'filter', 'display', 
10124		 *           'type' or 'sort'.</li>
10125		 *         <li>{array|object} The full data source for the row (not based on mData)</li>
10126		 *       </ul>
10127		 *       The return value from the function is what will be used for the data
10128		 *       requested.</li>
10129		 *    </ul>
10130		 *  @type string|int|function|null
10131		 *  @default null <i>Use mData</i>
10132		 *  @dtopt Columns
10133		 * 
10134		 *  @example
10135		 *    // Create a comma separated list from an array of objects
10136		 *    $(document).ready( function() {
10137		 *      var oTable = $('#example').dataTable( {
10138		 *        "sAjaxSource": "sources/deep.txt",
10139		 *        "aoColumns": [
10140		 *          { "mData": "engine" },
10141		 *          { "mData": "browser" },
10142		 *          {
10143		 *            "mData": "platform",
10144		 *            "mRender": "[, ].name"
10145		 *          }
10146		 *        ]
10147		 *      } );
10148		 *    } );
10149		 * 
10150		 *  @example
10151		 *    // Use as a function to create a link from the data source
10152		 *    $(document).ready( function() {
10153		 *      var oTable = $('#example').dataTable( {
10154		 *        "aoColumnDefs": [
10155		 *        {
10156		 *          "aTargets": [ 0 ],
10157		 *          "mData": "download_link",
10158		 *          "mRender": function ( data, type, full ) {
10159		 *            return '<a href="'+data+'">Download</a>';
10160		 *          }
10161		 *        ]
10162		 *      } );
10163		 *    } );
10164		 */
10165		"mRender": null,
10166	
10167	
10168		/**
10169		 * Change the cell type created for the column - either TD cells or TH cells. This
10170		 * can be useful as TH cells have semantic meaning in the table body, allowing them
10171		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
10172		 *  @type string
10173		 *  @default td
10174		 *  @dtopt Columns
10175		 * 
10176		 *  @example
10177		 *    // Make the first column use TH cells
10178		 *    $(document).ready( function() {
10179		 *      var oTable = $('#example').dataTable( {
10180		 *        "aoColumnDefs": [ {
10181		 *          "aTargets": [ 0 ],
10182		 *          "sCellType": "th"
10183		 *        } ]
10184		 *      } );
10185		 *    } );
10186		 */
10187		"sCellType": "td",
10188	
10189	
10190		/**
10191		 * Class to give to each cell in this column.
10192		 *  @type string
10193		 *  @default <i>Empty string</i>
10194		 *  @dtopt Columns
10195		 * 
10196		 *  @example
10197		 *    // Using aoColumnDefs
10198		 *    $(document).ready( function() {
10199		 *      $('#example').dataTable( {
10200		 *        "aoColumnDefs": [ 
10201		 *          { "sClass": "my_class", "aTargets": [ 0 ] }
10202		 *        ]
10203		 *      } );
10204		 *    } );
10205		 *    
10206		 *  @example
10207		 *    // Using aoColumns
10208		 *    $(document).ready( function() {
10209		 *      $('#example').dataTable( {
10210		 *        "aoColumns": [ 
10211		 *          { "sClass": "my_class" },
10212		 *          null,
10213		 *          null,
10214		 *          null,
10215		 *          null
10216		 *        ]
10217		 *      } );
10218		 *    } );
10219		 */
10220		"sClass": "",
10221		
10222		/**
10223		 * When DataTables calculates the column widths to assign to each column,
10224		 * it finds the longest string in each column and then constructs a
10225		 * temporary table and reads the widths from that. The problem with this
10226		 * is that "mmm" is much wider then "iiii", but the latter is a longer 
10227		 * string - thus the calculation can go wrong (doing it properly and putting
10228		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
10229		 * a "work around" we provide this option. It will append its value to the
10230		 * text that is found to be the longest string for the column - i.e. padding.
10231		 * Generally you shouldn't need this, and it is not documented on the 
10232		 * general DataTables.net documentation
10233		 *  @type string
10234		 *  @default <i>Empty string<i>
10235		 *  @dtopt Columns
10236		 *    
10237		 *  @example
10238		 *    // Using aoColumns
10239		 *    $(document).ready( function() {
10240		 *      $('#example').dataTable( {
10241		 *        "aoColumns": [ 
10242		 *          null,
10243		 *          null,
10244		 *          null,
10245		 *          {
10246		 *            "sContentPadding": "mmm"
10247		 *          }
10248		 *        ]
10249		 *      } );
10250		 *    } );
10251		 */
10252		"sContentPadding": "",
10253	
10254	
10255		/**
10256		 * Allows a default value to be given for a column's data, and will be used
10257		 * whenever a null data source is encountered (this can be because mData
10258		 * is set to null, or because the data source itself is null).
10259		 *  @type string
10260		 *  @default null
10261		 *  @dtopt Columns
10262		 * 
10263		 *  @example
10264		 *    // Using aoColumnDefs
10265		 *    $(document).ready( function() {
10266		 *      $('#example').dataTable( {
10267		 *        "aoColumnDefs": [ 
10268		 *          {
10269		 *            "mData": null,
10270		 *            "sDefaultContent": "Edit",
10271		 *            "aTargets": [ -1 ]
10272		 *          }
10273		 *        ]
10274		 *      } );
10275		 *    } );
10276		 *    
10277		 *  @example
10278		 *    // Using aoColumns
10279		 *    $(document).ready( function() {
10280		 *      $('#example').dataTable( {
10281		 *        "aoColumns": [ 
10282		 *          null,
10283		 *          null,
10284		 *          null,
10285		 *          {
10286		 *            "mData": null,
10287		 *            "sDefaultContent": "Edit"
10288		 *          }
10289		 *        ]
10290		 *      } );
10291		 *    } );
10292		 */
10293		"sDefaultContent": null,
10294	
10295	
10296		/**
10297		 * This parameter is only used in DataTables' server-side processing. It can
10298		 * be exceptionally useful to know what columns are being displayed on the
10299		 * client side, and to map these to database fields. When defined, the names
10300		 * also allow DataTables to reorder information from the server if it comes
10301		 * back in an unexpected order (i.e. if you switch your columns around on the
10302		 * client-side, your server-side code does not also need updating).
10303		 *  @type string
10304		 *  @default <i>Empty string</i>
10305		 *  @dtopt Columns
10306		 * 
10307		 *  @example
10308		 *    // Using aoColumnDefs
10309		 *    $(document).ready( function() {
10310		 *      $('#example').dataTable( {
10311		 *        "aoColumnDefs": [ 
10312		 *          { "sName": "engine", "aTargets": [ 0 ] },
10313		 *          { "sName": "browser", "aTargets": [ 1 ] },
10314		 *          { "sName": "platform", "aTargets": [ 2 ] },
10315		 *          { "sName": "version", "aTargets": [ 3 ] },
10316		 *          { "sName": "grade", "aTargets": [ 4 ] }
10317		 *        ]
10318		 *      } );
10319		 *    } );
10320		 *    
10321		 *  @example
10322		 *    // Using aoColumns
10323		 *    $(document).ready( function() {
10324		 *      $('#example').dataTable( {
10325		 *        "aoColumns": [ 
10326		 *          { "sName": "engine" },
10327		 *          { "sName": "browser" },
10328		 *          { "sName": "platform" },
10329		 *          { "sName": "version" },
10330		 *          { "sName": "grade" }
10331		 *        ]
10332		 *      } );
10333		 *    } );
10334		 */
10335		"sName": "",
10336	
10337	
10338		/**
10339		 * Defines a data source type for the sorting which can be used to read
10340		 * real-time information from the table (updating the internally cached
10341		 * version) prior to sorting. This allows sorting to occur on user editable
10342		 * elements such as form inputs.
10343		 *  @type string
10344		 *  @default std
10345		 *  @dtopt Columns
10346		 * 
10347		 *  @example
10348		 *    // Using aoColumnDefs
10349		 *    $(document).ready( function() {
10350		 *      $('#example').dataTable( {
10351		 *        "aoColumnDefs": [
10352		 *          { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] },
10353		 *          { "sType": "numeric", "aTargets": [ 3 ] },
10354		 *          { "sSortDataType": "dom-select", "aTargets": [ 4 ] },
10355		 *          { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] }
10356		 *        ]
10357		 *      } );
10358		 *    } );
10359		 *    
10360		 *  @example
10361		 *    // Using aoColumns
10362		 *    $(document).ready( function() {
10363		 *      $('#example').dataTable( {
10364		 *        "aoColumns": [
10365		 *          null,
10366		 *          null,
10367		 *          { "sSortDataType": "dom-text" },
10368		 *          { "sSortDataType": "dom-text", "sType": "numeric" },
10369		 *          { "sSortDataType": "dom-select" },
10370		 *          { "sSortDataType": "dom-checkbox" }
10371		 *        ]
10372		 *      } );
10373		 *    } );
10374		 */
10375		"sSortDataType": "std",
10376	
10377	
10378		/**
10379		 * The title of this column.
10380		 *  @type string
10381		 *  @default null <i>Derived from the 'TH' value for this column in the 
10382		 *    original HTML table.</i>
10383		 *  @dtopt Columns
10384		 * 
10385		 *  @example
10386		 *    // Using aoColumnDefs
10387		 *    $(document).ready( function() {
10388		 *      $('#example').dataTable( {
10389		 *        "aoColumnDefs": [ 
10390		 *          { "sTitle": "My column title", "aTargets": [ 0 ] }
10391		 *        ]
10392		 *      } );
10393		 *    } );
10394		 *    
10395		 *  @example
10396		 *    // Using aoColumns
10397		 *    $(document).ready( function() {
10398		 *      $('#example').dataTable( {
10399		 *        "aoColumns": [ 
10400		 *          { "sTitle": "My column title" },
10401		 *          null,
10402		 *          null,
10403		 *          null,
10404		 *          null
10405		 *        ]
10406		 *      } );
10407		 *    } );
10408		 */
10409		"sTitle": null,
10410	
10411	
10412		/**
10413		 * The type allows you to specify how the data for this column will be sorted.
10414		 * Four types (string, numeric, date and html (which will strip HTML tags
10415		 * before sorting)) are currently available. Note that only date formats
10416		 * understood by Javascript's Date() object will be accepted as type date. For
10417		 * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric',
10418		 * 'date' or 'html' (by default). Further types can be adding through
10419		 * plug-ins.
10420		 *  @type string
10421		 *  @default null <i>Auto-detected from raw data</i>
10422		 *  @dtopt Columns
10423		 * 
10424		 *  @example
10425		 *    // Using aoColumnDefs
10426		 *    $(document).ready( function() {
10427		 *      $('#example').dataTable( {
10428		 *        "aoColumnDefs": [ 
10429		 *          { "sType": "html", "aTargets": [ 0 ] }
10430		 *        ]
10431		 *      } );
10432		 *    } );
10433		 *    
10434		 *  @example
10435		 *    // Using aoColumns
10436		 *    $(document).ready( function() {
10437		 *      $('#example').dataTable( {
10438		 *        "aoColumns": [ 
10439		 *          { "sType": "html" },
10440		 *          null,
10441		 *          null,
10442		 *          null,
10443		 *          null
10444		 *        ]
10445		 *      } );
10446		 *    } );
10447		 */
10448		"sType": null,
10449	
10450	
10451		/**
10452		 * Defining the width of the column, this parameter may take any CSS value
10453		 * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not
10454		 * been given a specific width through this interface ensuring that the table
10455		 * remains readable.
10456		 *  @type string
10457		 *  @default null <i>Automatic</i>
10458		 *  @dtopt Columns
10459		 * 
10460		 *  @example
10461		 *    // Using aoColumnDefs
10462		 *    $(document).ready( function() {
10463		 *      $('#example').dataTable( {
10464		 *        "aoColumnDefs": [ 
10465		 *          { "sWidth": "20%", "aTargets": [ 0 ] }
10466		 *        ]
10467		 *      } );
10468		 *    } );
10469		 *    
10470		 *  @example
10471		 *    // Using aoColumns
10472		 *    $(document).ready( function() {
10473		 *      $('#example').dataTable( {
10474		 *        "aoColumns": [ 
10475		 *          { "sWidth": "20%" },
10476		 *          null,
10477		 *          null,
10478		 *          null,
10479		 *          null
10480		 *        ]
10481		 *      } );
10482		 *    } );
10483		 */
10484		"sWidth": null
10485	};
10486	
10487	
10488	
10489	/**
10490	 * DataTables settings object - this holds all the information needed for a
10491	 * given table, including configuration, data and current application of the
10492	 * table options. DataTables does not have a single instance for each DataTable
10493	 * with the settings attached to that instance, but rather instances of the
10494	 * DataTable "class" are created on-the-fly as needed (typically by a 
10495	 * $().dataTable() call) and the settings object is then applied to that
10496	 * instance.
10497	 * 
10498	 * Note that this object is related to {@link DataTable.defaults} but this 
10499	 * one is the internal data store for DataTables's cache of columns. It should
10500	 * NOT be manipulated outside of DataTables. Any configuration should be done
10501	 * through the initialisation options.
10502	 *  @namespace
10503	 *  @todo Really should attach the settings object to individual instances so we
10504	 *    don't need to create new instances on each $().dataTable() call (if the
10505	 *    table already exists). It would also save passing oSettings around and
10506	 *    into every single function. However, this is a very significant 
10507	 *    architecture change for DataTables and will almost certainly break
10508	 *    backwards compatibility with older installations. This is something that
10509	 *    will be done in 2.0.
10510	 */
10511	DataTable.models.oSettings = {
10512		/**
10513		 * Primary features of DataTables and their enablement state.
10514		 *  @namespace
10515		 */
10516		"oFeatures": {
10517			
10518			/**
10519			 * Flag to say if DataTables should automatically try to calculate the
10520			 * optimum table and columns widths (true) or not (false).
10521			 * Note that this parameter will be set by the initialisation routine. To
10522			 * set a default use {@link DataTable.defaults}.
10523			 *  @type boolean
10524			 */
10525			"bAutoWidth": null,
10526	
10527			/**
10528			 * Delay the creation of TR and TD elements until they are actually
10529			 * needed by a driven page draw. This can give a significant speed
10530			 * increase for Ajax source and Javascript source data, but makes no
10531			 * difference at all fro DOM and server-side processing tables.
10532			 * Note that this parameter will be set by the initialisation routine. To
10533			 * set a default use {@link DataTable.defaults}.
10534			 *  @type boolean
10535			 */
10536			"bDeferRender": null,
10537			
10538			/**
10539			 * Enable filtering on the table or not. Note that if this is disabled
10540			 * then there is no filtering at all on the table, including fnFilter.
10541			 * To just remove the filtering input use sDom and remove the 'f' option.
10542			 * Note that this parameter will be set by the initialisation routine. To
10543			 * set a default use {@link DataTable.defaults}.
10544			 *  @type boolean
10545			 */
10546			"bFilter": null,
10547			
10548			/**
10549			 * Table information element (the 'Showing x of y records' div) enable
10550			 * flag.
10551			 * Note that this parameter will be set by the initialisation routine. To
10552			 * set a default use {@link DataTable.defaults}.
10553			 *  @type boolean
10554			 */
10555			"bInfo": null,
10556			
10557			/**
10558			 * Present a user control allowing the end user to change the page size
10559			 * when pagination is enabled.
10560			 * Note that this parameter will be set by the initialisation routine. To
10561			 * set a default use {@link DataTable.defaults}.
10562			 *  @type boolean
10563			 */
10564			"bLengthChange": null,
10565	
10566			/**
10567			 * Pagination enabled or not. Note that if this is disabled then length
10568			 * changing must also be disabled.
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			"bPaginate": null,
10574			
10575			/**
10576			 * Processing indicator enable flag whenever DataTables is enacting a
10577			 * user request - typically an Ajax request for server-side processing.
10578			 * Note that this parameter will be set by the initialisation routine. To
10579			 * set a default use {@link DataTable.defaults}.
10580			 *  @type boolean
10581			 */
10582			"bProcessing": null,
10583			
10584			/**
10585			 * Server-side processing enabled flag - when enabled DataTables will
10586			 * get all data from the server for every draw - there is no filtering,
10587			 * sorting or paging done on the client-side.
10588			 * Note that this parameter will be set by the initialisation routine. To
10589			 * set a default use {@link DataTable.defaults}.
10590			 *  @type boolean
10591			 */
10592			"bServerSide": null,
10593			
10594			/**
10595			 * Sorting enablement flag.
10596			 * Note that this parameter will be set by the initialisation routine. To
10597			 * set a default use {@link DataTable.defaults}.
10598			 *  @type boolean
10599			 */
10600			"bSort": null,
10601			
10602			/**
10603			 * Apply a class to the columns which are being sorted to provide a
10604			 * visual highlight or not. This can slow things down when enabled since
10605			 * there is a lot of DOM interaction.
10606			 * Note that this parameter will be set by the initialisation routine. To
10607			 * set a default use {@link DataTable.defaults}.
10608			 *  @type boolean
10609			 */
10610			"bSortClasses": null,
10611			
10612			/**
10613			 * State saving enablement flag.
10614			 * Note that this parameter will be set by the initialisation routine. To
10615			 * set a default use {@link DataTable.defaults}.
10616			 *  @type boolean
10617			 */
10618			"bStateSave": null
10619		},
10620		
10621	
10622		/**
10623		 * Scrolling settings for a table.
10624		 *  @namespace
10625		 */
10626		"oScroll": {
10627			/**
10628			 * Indicate if DataTables should be allowed to set the padding / margin
10629			 * etc for the scrolling header elements or not. Typically you will want
10630			 * this.
10631			 * Note that this parameter will be set by the initialisation routine. To
10632			 * set a default use {@link DataTable.defaults}.
10633			 *  @type boolean
10634			 */
10635			"bAutoCss": null,
10636			
10637			/**
10638			 * When the table is shorter in height than sScrollY, collapse the
10639			 * table container down to the height of the table (when true).
10640			 * Note that this parameter will be set by the initialisation routine. To
10641			 * set a default use {@link DataTable.defaults}.
10642			 *  @type boolean
10643			 */
10644			"bCollapse": null,
10645			
10646			/**
10647			 * Infinite scrolling enablement flag. Now deprecated in favour of
10648			 * using the Scroller plug-in.
10649			 * Note that this parameter will be set by the initialisation routine. To
10650			 * set a default use {@link DataTable.defaults}.
10651			 *  @type boolean
10652			 */
10653			"bInfinite": null,
10654			
10655			/**
10656			 * Width of the scrollbar for the web-browser's platform. Calculated
10657			 * during table initialisation.
10658			 *  @type int
10659			 *  @default 0
10660			 */
10661			"iBarWidth": 0,
10662			
10663			/**
10664			 * Space (in pixels) between the bottom of the scrolling container and 
10665			 * the bottom of the scrolling viewport before the next page is loaded
10666			 * when using infinite scrolling.
10667			 * Note that this parameter will be set by the initialisation routine. To
10668			 * set a default use {@link DataTable.defaults}.
10669			 *  @type int
10670			 */
10671			"iLoadGap": null,
10672			
10673			/**
10674			 * Viewport width for horizontal scrolling. Horizontal scrolling is 
10675			 * disabled if an empty string.
10676			 * Note that this parameter will be set by the initialisation routine. To
10677			 * set a default use {@link DataTable.defaults}.
10678			 *  @type string
10679			 */
10680			"sX": null,
10681			
10682			/**
10683			 * Width to expand the table to when using x-scrolling. Typically you
10684			 * should not need to use this.
10685			 * Note that this parameter will be set by the initialisation routine. To
10686			 * set a default use {@link DataTable.defaults}.
10687			 *  @type string
10688			 *  @deprecated
10689			 */
10690			"sXInner": null,
10691			
10692			/**
10693			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
10694			 * if an empty string.
10695			 * Note that this parameter will be set by the initialisation routine. To
10696			 * set a default use {@link DataTable.defaults}.
10697			 *  @type string
10698			 */
10699			"sY": null
10700		},
10701		
10702		/**
10703		 * Language information for the table.
10704		 *  @namespace
10705		 *  @extends DataTable.defaults.oLanguage
10706		 */
10707		"oLanguage": {
10708			/**
10709			 * Information callback function. See 
10710			 * {@link DataTable.defaults.fnInfoCallback}
10711			 *  @type function
10712			 *  @default null
10713			 */
10714			"fnInfoCallback": null
10715		},
10716		
10717		/**
10718		 * Browser support parameters
10719		 *  @namespace
10720		 */
10721		"oBrowser": {
10722			/**
10723			 * Indicate if the browser incorrectly calculates width:100% inside a
10724			 * scrolling element (IE6/7)
10725			 *  @type boolean
10726			 *  @default false
10727			 */
10728			"bScrollOversize": false
10729		},
10730		
10731		/**
10732		 * Array referencing the nodes which are used for the features. The 
10733		 * parameters of this object match what is allowed by sDom - i.e.
10734		 *   <ul>
10735		 *     <li>'l' - Length changing</li>
10736		 *     <li>'f' - Filtering input</li>
10737		 *     <li>'t' - The table!</li>
10738		 *     <li>'i' - Information</li>
10739		 *     <li>'p' - Pagination</li>
10740		 *     <li>'r' - pRocessing</li>
10741		 *   </ul>
10742		 *  @type array
10743		 *  @default []
10744		 */
10745		"aanFeatures": [],
10746		
10747		/**
10748		 * Store data information - see {@link DataTable.models.oRow} for detailed
10749		 * information.
10750		 *  @type array
10751		 *  @default []
10752		 */
10753		"aoData": [],
10754		
10755		/**
10756		 * Array of indexes which are in the current display (after filtering etc)
10757		 *  @type array
10758		 *  @default []
10759		 */
10760		"aiDisplay": [],
10761		
10762		/**
10763		 * Array of indexes for display - no filtering
10764		 *  @type array
10765		 *  @default []
10766		 */
10767		"aiDisplayMaster": [],
10768		
10769		/**
10770		 * Store information about each column that is in use
10771		 *  @type array
10772		 *  @default []
10773		 */
10774		"aoColumns": [],
10775		
10776		/**
10777		 * Store information about the table's header
10778		 *  @type array
10779		 *  @default []
10780		 */
10781		"aoHeader": [],
10782		
10783		/**
10784		 * Store information about the table's footer
10785		 *  @type array
10786		 *  @default []
10787		 */
10788		"aoFooter": [],
10789		
10790		/**
10791		 * Search data array for regular expression searching
10792		 *  @type array
10793		 *  @default []
10794		 */
10795		"asDataSearch": [],
10796		
10797		/**
10798		 * Store the applied global search information in case we want to force a 
10799		 * research or compare the old search to a new one.
10800		 * Note that this parameter will be set by the initialisation routine. To
10801		 * set a default use {@link DataTable.defaults}.
10802		 *  @namespace
10803		 *  @extends DataTable.models.oSearch
10804		 */
10805		"oPreviousSearch": {},
10806		
10807		/**
10808		 * Store the applied search for each column - see 
10809		 * {@link DataTable.models.oSearch} for the format that is used for the
10810		 * filtering information for each column.
10811		 *  @type array
10812		 *  @default []
10813		 */
10814		"aoPreSearchCols": [],
10815		
10816		/**
10817		 * Sorting that is applied to the table. Note that the inner arrays are
10818		 * used in the following manner:
10819		 * <ul>
10820		 *   <li>Index 0 - column number</li>
10821		 *   <li>Index 1 - current sorting direction</li>
10822		 *   <li>Index 2 - index of asSorting for this column</li>
10823		 * </ul>
10824		 * Note that this parameter will be set by the initialisation routine. To
10825		 * set a default use {@link DataTable.defaults}.
10826		 *  @type array
10827		 *  @todo These inner arrays should really be objects
10828		 */
10829		"aaSorting": null,
10830		
10831		/**
10832		 * Sorting that is always applied to the table (i.e. prefixed in front of
10833		 * aaSorting).
10834		 * Note that this parameter will be set by the initialisation routine. To
10835		 * set a default use {@link DataTable.defaults}.
10836		 *  @type array|null
10837		 *  @default null
10838		 */
10839		"aaSortingFixed": null,
10840		
10841		/**
10842		 * Classes to use for the striping of a table.
10843		 * Note that this parameter will be set by the initialisation routine. To
10844		 * set a default use {@link DataTable.defaults}.
10845		 *  @type array
10846		 *  @default []
10847		 */
10848		"asStripeClasses": null,
10849		
10850		/**
10851		 * If restoring a table - we should restore its striping classes as well
10852		 *  @type array
10853		 *  @default []
10854		 */
10855		"asDestroyStripes": [],
10856		
10857		/**
10858		 * If restoring a table - we should restore its width 
10859		 *  @type int
10860		 *  @default 0
10861		 */
10862		"sDestroyWidth": 0,
10863		
10864		/**
10865		 * Callback functions array for every time a row is inserted (i.e. on a draw).
10866		 *  @type array
10867		 *  @default []
10868		 */
10869		"aoRowCallback": [],
10870		
10871		/**
10872		 * Callback functions for the header on each draw.
10873		 *  @type array
10874		 *  @default []
10875		 */
10876		"aoHeaderCallback": [],
10877		
10878		/**
10879		 * Callback function for the footer on each draw.
10880		 *  @type array
10881		 *  @default []
10882		 */
10883		"aoFooterCallback": [],
10884		
10885		/**
10886		 * Array of callback functions for draw callback functions
10887		 *  @type array
10888		 *  @default []
10889		 */
10890		"aoDrawCallback": [],
10891		
10892		/**
10893		 * Array of callback functions for row created function
10894		 *  @type array
10895		 *  @default []
10896		 */
10897		"aoRowCreatedCallback": [],
10898		
10899		/**
10900		 * Callback functions for just before the table is redrawn. A return of 
10901		 * false will be used to cancel the draw.
10902		 *  @type array
10903		 *  @default []
10904		 */
10905		"aoPreDrawCallback": [],
10906		
10907		/**
10908		 * Callback functions for when the table has been initialised.
10909		 *  @type array
10910		 *  @default []
10911		 */
10912		"aoInitComplete": [],
10913	
10914		
10915		/**
10916		 * Callbacks for modifying the settings to be stored for state saving, prior to
10917		 * saving state.
10918		 *  @type array
10919		 *  @default []
10920		 */
10921		"aoStateSaveParams": [],
10922		
10923		/**
10924		 * Callbacks for modifying the settings that have been stored for state saving
10925		 * prior to using the stored values to restore the state.
10926		 *  @type array
10927		 *  @default []
10928		 */
10929		"aoStateLoadParams": [],
10930		
10931		/**
10932		 * Callbacks for operating on the settings object once the saved state has been
10933		 * loaded
10934		 *  @type array
10935		 *  @default []
10936		 */
10937		"aoStateLoaded": [],
10938		
10939		/**
10940		 * Cache the table ID for quick access
10941		 *  @type string
10942		 *  @default <i>Empty string</i>
10943		 */
10944		"sTableId": "",
10945		
10946		/**
10947		 * The TABLE node for the main table
10948		 *  @type node
10949		 *  @default null
10950		 */
10951		"nTable": null,
10952		
10953		/**
10954		 * Permanent ref to the thead element
10955		 *  @type node
10956		 *  @default null
10957		 */
10958		"nTHead": null,
10959		
10960		/**
10961		 * Permanent ref to the tfoot element - if it exists
10962		 *  @type node
10963		 *  @default null
10964		 */
10965		"nTFoot": null,
10966		
10967		/**
10968		 * Permanent ref to the tbody element
10969		 *  @type node
10970		 *  @default null
10971		 */
10972		"nTBody": null,
10973		
10974		/**
10975		 * Cache the wrapper node (contains all DataTables controlled elements)
10976		 *  @type node
10977		 *  @default null
10978		 */
10979		"nTableWrapper": null,
10980		
10981		/**
10982		 * Indicate if when using server-side processing the loading of data 
10983		 * should be deferred until the second draw.
10984		 * Note that this parameter will be set by the initialisation routine. To
10985		 * set a default use {@link DataTable.defaults}.
10986		 *  @type boolean
10987		 *  @default false
10988		 */
10989		"bDeferLoading": false,
10990		
10991		/**
10992		 * Indicate if all required information has been read in
10993		 *  @type boolean
10994		 *  @default false
10995		 */
10996		"bInitialised": false,
10997		
10998		/**
10999		 * Information about open rows. Each object in the array has the parameters
11000		 * 'nTr' and 'nParent'
11001		 *  @type array
11002		 *  @default []
11003		 */
11004		"aoOpenRows": [],
11005		
11006		/**
11007		 * Dictate the positioning of DataTables' control elements - see
11008		 * {@link DataTable.model.oInit.sDom}.
11009		 * Note that this parameter will be set by the initialisation routine. To
11010		 * set a default use {@link DataTable.defaults}.
11011		 *  @type string
11012		 *  @default null
11013		 */
11014		"sDom": null,
11015		
11016		/**
11017		 * Which type of pagination should be used.
11018		 * Note that this parameter will be set by the initialisation routine. To
11019		 * set a default use {@link DataTable.defaults}.
11020		 *  @type string 
11021		 *  @default two_button
11022		 */
11023		"sPaginationType": "two_button",
11024		
11025		/**
11026		 * The cookie duration (for bStateSave) in seconds.
11027		 * Note that this parameter will be set by the initialisation routine. To
11028		 * set a default use {@link DataTable.defaults}.
11029		 *  @type int
11030		 *  @default 0
11031		 */
11032		"iCookieDuration": 0,
11033		
11034		/**
11035		 * The cookie name prefix.
11036		 * Note that this parameter will be set by the initialisation routine. To
11037		 * set a default use {@link DataTable.defaults}.
11038		 *  @type string
11039		 *  @default <i>Empty string</i>
11040		 */
11041		"sCookiePrefix": "",
11042		
11043		/**
11044		 * Callback function for cookie creation.
11045		 * Note that this parameter will be set by the initialisation routine. To
11046		 * set a default use {@link DataTable.defaults}.
11047		 *  @type function
11048		 *  @default null
11049		 */
11050		"fnCookieCallback": null,
11051		
11052		/**
11053		 * Array of callback functions for state saving. Each array element is an 
11054		 * object with the following parameters:
11055		 *   <ul>
11056		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11057		 *       and the JSON string to save that has been thus far created. Returns
11058		 *       a JSON string to be inserted into a json object 
11059		 *       (i.e. '"param": [ 0, 1, 2]')</li>
11060		 *     <li>string:sName - name of callback</li>
11061		 *   </ul>
11062		 *  @type array
11063		 *  @default []
11064		 */
11065		"aoStateSave": [],
11066		
11067		/**
11068		 * Array of callback functions for state loading. Each array element is an 
11069		 * object with the following parameters:
11070		 *   <ul>
11071		 *     <li>function:fn - function to call. Takes two parameters, oSettings 
11072		 *       and the object stored. May return false to cancel state loading</li>
11073		 *     <li>string:sName - name of callback</li>
11074		 *   </ul>
11075		 *  @type array
11076		 *  @default []
11077		 */
11078		"aoStateLoad": [],
11079		
11080		/**
11081		 * State that was loaded from the cookie. Useful for back reference
11082		 *  @type object
11083		 *  @default null
11084		 */
11085		"oLoadedState": null,
11086		
11087		/**
11088		 * Source url for AJAX data for the table.
11089		 * Note that this parameter will be set by the initialisation routine. To
11090		 * set a default use {@link DataTable.defaults}.
11091		 *  @type string
11092		 *  @default null
11093		 */
11094		"sAjaxSource": null,
11095		
11096		/**
11097		 * Property from a given object from which to read the table data from. This
11098		 * can be an empty string (when not server-side processing), in which case 
11099		 * it is  assumed an an array is given directly.
11100		 * Note that this parameter will be set by the initialisation routine. To
11101		 * set a default use {@link DataTable.defaults}.
11102		 *  @type string
11103		 */
11104		"sAjaxDataProp": null,
11105		
11106		/**
11107		 * Note if draw should be blocked while getting data
11108		 *  @type boolean
11109		 *  @default true
11110		 */
11111		"bAjaxDataGet": true,
11112		
11113		/**
11114		 * The last jQuery XHR object that was used for server-side data gathering. 
11115		 * This can be used for working with the XHR information in one of the 
11116		 * callbacks
11117		 *  @type object
11118		 *  @default null
11119		 */
11120		"jqXHR": null,
11121		
11122		/**
11123		 * Function to get the server-side data.
11124		 * Note that this parameter will be set by the initialisation routine. To
11125		 * set a default use {@link DataTable.defaults}.
11126		 *  @type function
11127		 */
11128		"fnServerData": null,
11129		
11130		/**
11131		 * Functions which are called prior to sending an Ajax request so extra 
11132		 * parameters can easily be sent to the server
11133		 *  @type array
11134		 *  @default []
11135		 */
11136		"aoServerParams": [],
11137		
11138		/**
11139		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 
11140		 * required).
11141		 * Note that this parameter will be set by the initialisation routine. To
11142		 * set a default use {@link DataTable.defaults}.
11143		 *  @type string
11144		 */
11145		"sServerMethod": null,
11146		
11147		/**
11148		 * Format numbers for display.
11149		 * Note that this parameter will be set by the initialisation routine. To
11150		 * set a default use {@link DataTable.defaults}.
11151		 *  @type function
11152		 */
11153		"fnFormatNumber": null,
11154		
11155		/**
11156		 * List of options that can be used for the user selectable length menu.
11157		 * Note that this parameter will be set by the initialisation routine. To
11158		 * set a default use {@link DataTable.defaults}.
11159		 *  @type array
11160		 *  @default []
11161		 */
11162		"aLengthMenu": null,
11163		
11164		/**
11165		 * Counter for the draws that the table does. Also used as a tracker for
11166		 * server-side processing
11167		 *  @type int
11168		 *  @default 0
11169		 */
11170		"iDraw": 0,
11171		
11172		/**
11173		 * Indicate if a redraw is being done - useful for Ajax
11174		 *  @type boolean
11175		 *  @default false
11176		 */
11177		"bDrawing": false,
11178		
11179		/**
11180		 * Draw index (iDraw) of the last error when parsing the returned data
11181		 *  @type int
11182		 *  @default -1
11183		 */
11184		"iDrawError": -1,
11185		
11186		/**
11187		 * Paging display length
11188		 *  @type int
11189		 *  @default 10
11190		 */
11191		"_iDisplayLength": 10,
11192	
11193		/**
11194		 * Paging start point - aiDisplay index
11195		 *  @type int
11196		 *  @default 0
11197		 */
11198		"_iDisplayStart": 0,
11199	
11200		/**
11201		 * Paging end point - aiDisplay index. Use fnDisplayEnd rather than
11202		 * this property to get the end point
11203		 *  @type int
11204		 *  @default 10
11205		 *  @private
11206		 */
11207		"_iDisplayEnd": 10,
11208		
11209		/**
11210		 * Server-side processing - number of records in the result set
11211		 * (i.e. before filtering), Use fnRecordsTotal rather than
11212		 * this property to get the value of the number of records, regardless of
11213		 * the server-side processing setting.
11214		 *  @type int
11215		 *  @default 0
11216		 *  @private
11217		 */
11218		"_iRecordsTotal": 0,
11219	
11220		/**
11221		 * Server-side processing - number of records in the current display set
11222		 * (i.e. after filtering). Use fnRecordsDisplay rather than
11223		 * this property to get the value of the number of records, regardless of
11224		 * the server-side processing setting.
11225		 *  @type boolean
11226		 *  @default 0
11227		 *  @private
11228		 */
11229		"_iRecordsDisplay": 0,
11230		
11231		/**
11232		 * Flag to indicate if jQuery UI marking and classes should be used.
11233		 * Note that this parameter will be set by the initialisation routine. To
11234		 * set a default use {@link DataTable.defaults}.
11235		 *  @type boolean
11236		 */
11237		"bJUI": null,
11238		
11239		/**
11240		 * The classes to use for the table
11241		 *  @type object
11242		 *  @default {}
11243		 */
11244		"oClasses": {},
11245		
11246		/**
11247		 * Flag attached to the settings object so you can check in the draw 
11248		 * callback if filtering has been done in the draw. Deprecated in favour of
11249		 * events.
11250		 *  @type boolean
11251		 *  @default false
11252		 *  @deprecated
11253		 */
11254		"bFiltered": false,
11255		
11256		/**
11257		 * Flag attached to the settings object so you can check in the draw 
11258		 * callback if sorting has been done in the draw. Deprecated in favour of
11259		 * events.
11260		 *  @type boolean
11261		 *  @default false
11262		 *  @deprecated
11263		 */
11264		"bSorted": false,
11265		
11266		/**
11267		 * Indicate that if multiple rows are in the header and there is more than 
11268		 * one unique cell per column, if the top one (true) or bottom one (false) 
11269		 * should be used for sorting / title by DataTables.
11270		 * Note that this parameter will be set by the initialisation routine. To
11271		 * set a default use {@link DataTable.defaults}.
11272		 *  @type boolean
11273		 */
11274		"bSortCellsTop": null,
11275		
11276		/**
11277		 * Initialisation object that is used for the table
11278		 *  @type object
11279		 *  @default null
11280		 */
11281		"oInit": null,
11282		
11283		/**
11284		 * Destroy callback functions - for plug-ins to attach themselves to the
11285		 * destroy so they can clean up markup and events.
11286		 *  @type array
11287		 *  @default []
11288		 */
11289		"aoDestroyCallback": [],
11290	
11291		
11292		/**
11293		 * Get the number of records in the current record set, before filtering
11294		 *  @type function
11295		 */
11296		"fnRecordsTotal": function ()
11297		{
11298			if ( this.oFeatures.bServerSide ) {
11299				return parseInt(this._iRecordsTotal, 10);
11300			} else {
11301				return this.aiDisplayMaster.length;
11302			}
11303		},
11304		
11305		/**
11306		 * Get the number of records in the current record set, after filtering
11307		 *  @type function
11308		 */
11309		"fnRecordsDisplay": function ()
11310		{
11311			if ( this.oFeatures.bServerSide ) {
11312				return parseInt(this._iRecordsDisplay, 10);
11313			} else {
11314				return this.aiDisplay.length;
11315			}
11316		},
11317		
11318		/**
11319		 * Set the display end point - aiDisplay index
11320		 *  @type function
11321		 *  @todo Should do away with _iDisplayEnd and calculate it on-the-fly here
11322		 */
11323		"fnDisplayEnd": function ()
11324		{
11325			if ( this.oFeatures.bServerSide ) {
11326				if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
11327					return this._iDisplayStart+this.aiDisplay.length;
11328				} else {
11329					return Math.min( this._iDisplayStart+this._iDisplayLength, 
11330						this._iRecordsDisplay );
11331				}
11332			} else {
11333				return this._iDisplayEnd;
11334			}
11335		},
11336		
11337		/**
11338		 * The DataTables object for this table
11339		 *  @type object
11340		 *  @default null
11341		 */
11342		"oInstance": null,
11343		
11344		/**
11345		 * Unique identifier for each instance of the DataTables object. If there
11346		 * is an ID on the table node, then it takes that value, otherwise an
11347		 * incrementing internal counter is used.
11348		 *  @type string
11349		 *  @default null
11350		 */
11351		"sInstance": null,
11352	
11353		/**
11354		 * tabindex attribute value that is added to DataTables control elements, allowing
11355		 * keyboard navigation of the table and its controls.
11356		 */
11357		"iTabIndex": 0,
11358	
11359		/**
11360		 * DIV container for the footer scrolling table if scrolling
11361		 */
11362		"nScrollHead": null,
11363	
11364		/**
11365		 * DIV container for the footer scrolling table if scrolling
11366		 */
11367		"nScrollFoot": null
11368	};
11369
11370	/**
11371	 * Extension object for DataTables that is used to provide all extension options.
11372	 * 
11373	 * Note that the <i>DataTable.ext</i> object is available through
11374	 * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is
11375	 * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons.
11376	 *  @namespace
11377	 *  @extends DataTable.models.ext
11378	 */
11379	DataTable.ext = $.extend( true, {}, DataTable.models.ext );
11380	
11381	$.extend( DataTable.ext.oStdClasses, {
11382		"sTable": "dataTable",
11383	
11384		/* Two buttons buttons */
11385		"sPagePrevEnabled": "paginate_enabled_previous",
11386		"sPagePrevDisabled": "paginate_disabled_previous",
11387		"sPageNextEnabled": "paginate_enabled_next",
11388		"sPageNextDisabled": "paginate_disabled_next",
11389		"sPageJUINext": "",
11390		"sPageJUIPrev": "",
11391		
11392		/* Full numbers paging buttons */
11393		"sPageButton": "paginate_button",
11394		"sPageButtonActive": "paginate_active",
11395		"sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
11396		"sPageFirst": "first",
11397		"sPagePrevious": "previous",
11398		"sPageNext": "next",
11399		"sPageLast": "last",
11400		
11401		/* Striping classes */
11402		"sStripeOdd": "odd",
11403		"sStripeEven": "even",
11404		
11405		/* Empty row */
11406		"sRowEmpty": "dataTables_empty",
11407		
11408		/* Features */
11409		"sWrapper": "dataTables_wrapper",
11410		"sFilter": "dataTables_filter",
11411		"sInfo": "dataTables_info",
11412		"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
11413		"sLength": "dataTables_length",
11414		"sProcessing": "dataTables_processing",
11415		
11416		/* Sorting */
11417		"sSortAsc": "sorting_asc",
11418		"sSortDesc": "sorting_desc",
11419		"sSortable": "sorting", /* Sortable in both directions */
11420		"sSortableAsc": "sorting_asc_disabled",
11421		"sSortableDesc": "sorting_desc_disabled",
11422		"sSortableNone": "sorting_disabled",
11423		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
11424		"sSortJUIAsc": "",
11425		"sSortJUIDesc": "",
11426		"sSortJUI": "",
11427		"sSortJUIAscAllowed": "",
11428		"sSortJUIDescAllowed": "",
11429		"sSortJUIWrapper": "",
11430		"sSortIcon": "",
11431		
11432		/* Scrolling */
11433		"sScrollWrapper": "dataTables_scroll",
11434		"sScrollHead": "dataTables_scrollHead",
11435		"sScrollHeadInner": "dataTables_scrollHeadInner",
11436		"sScrollBody": "dataTables_scrollBody",
11437		"sScrollFoot": "dataTables_scrollFoot",
11438		"sScrollFootInner": "dataTables_scrollFootInner",
11439		
11440		/* Misc */
11441		"sFooterTH": "",
11442		"sJUIHeader": "",
11443		"sJUIFooter": ""
11444	} );
11445	
11446	
11447	$.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, {
11448		/* Two buttons buttons */
11449		"sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
11450		"sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
11451		"sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
11452		"sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
11453		"sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
11454		"sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
11455		
11456		/* Full numbers paging buttons */
11457		"sPageButton": "fg-button ui-button ui-state-default",
11458		"sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
11459		"sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
11460		"sPageFirst": "first ui-corner-tl ui-corner-bl",
11461		"sPageLast": "last ui-corner-tr ui-corner-br",
11462		
11463		/* Features */
11464		"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
11465			"ui-buttonset-multi paging_", /* Note that the type is postfixed */
11466		
11467		/* Sorting */
11468		"sSortAsc": "ui-state-default",
11469		"sSortDesc": "ui-state-default",
11470		"sSortable": "ui-state-default",
11471		"sSortableAsc": "ui-state-default",
11472		"sSortableDesc": "ui-state-default",
11473		"sSortableNone": "ui-state-default",
11474		"sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
11475		"sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
11476		"sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
11477		"sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
11478		"sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
11479		"sSortJUIWrapper": "DataTables_sort_wrapper",
11480		"sSortIcon": "DataTables_sort_icon",
11481		
11482		/* Scrolling */
11483		"sScrollHead": "dataTables_scrollHead ui-state-default",
11484		"sScrollFoot": "dataTables_scrollFoot ui-state-default",
11485		
11486		/* Misc */
11487		"sFooterTH": "ui-state-default",
11488		"sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",
11489		"sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"
11490	} );
11491	
11492	/*
11493	 * Variable: oPagination
11494	 * Purpose:  
11495	 * Scope:    jQuery.fn.dataTableExt
11496	 */
11497	$.extend( DataTable.ext.oPagination, {
11498		/*
11499		 * Variable: two_button
11500		 * Purpose:  Standard two button (forward/back) pagination
11501		 * Scope:    jQuery.fn.dataTableExt.oPagination
11502		 */
11503		"two_button": {
11504			/*
11505			 * Function: oPagination.two_button.fnInit
11506			 * Purpose:  Initialise dom elements required for pagination with forward/back buttons only
11507			 * Returns:  -
11508			 * Inputs:   object:oSettings - dataTables settings object
11509			 *           node:nPaging - the DIV which contains this pagination control
11510			 *           function:fnCallbackDraw - draw function which must be called on update
11511			 */
11512			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
11513			{
11514				var oLang = oSettings.oLanguage.oPaginate;
11515				var oClasses = oSettings.oClasses;
11516				var fnClickHandler = function ( e ) {
11517					if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
11518					{
11519						fnCallbackDraw( oSettings );
11520					}
11521				};
11522	
11523				var sAppend = (!oSettings.bJUI) ?
11524					'<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+
11525					'<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>'
11526					:
11527					'<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+
11528					'<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>';
11529				$(nPaging).append( sAppend );
11530				
11531				var els = $('a', nPaging);
11532				var nPrevious = els[0],
11533					nNext = els[1];
11534				
11535				oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );
11536				oSettings.oApi._fnBindAction( nNext,     {action: "next"},     fnClickHandler );
11537				
11538				/* ID the first elements only */
11539				if ( !oSettings.aanFeatures.p )
11540				{
11541					nPaging.id = oSettings.sTableId+'_paginate';
11542					nPrevious.id = oSettings.sTableId+'_previous';
11543					nNext.id = oSettings.sTableId+'_next';
11544	
11545					nPrevious.setAttribute('aria-controls', oSettings.sTableId);
11546					nNext.setAttribute('aria-controls', oSettings.sTableId);
11547				}
11548			},
11549			
11550			/*
11551			 * Function: oPagination.two_button.fnUpdate
11552			 * Purpose:  Update the two button pagination at the end of the draw
11553			 * Returns:  -
11554			 * Inputs:   object:oSettings - dataTables settings object
11555			 *           function:fnCallbackDraw - draw function to call on page change
11556			 */
11557			"fnUpdate": function ( oSettings, fnCallbackDraw )
11558			{
11559				if ( !oSettings.aanFeatures.p )
11560				{
11561					return;
11562				}
11563				
11564				var oClasses = oSettings.oClasses;
11565				var an = oSettings.aanFeatures.p;
11566				var nNode;
11567	
11568				/* Loop over each instance of the pager */
11569				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
11570				{
11571					nNode = an[i].firstChild;
11572					if ( nNode )
11573					{
11574						/* Previous page */
11575						nNode.className = ( oSettings._iDisplayStart === 0 ) ?
11576						    oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;
11577						    
11578						/* Next page */
11579						nNode = nNode.nextSibling;
11580						nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
11581						    oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;
11582					}
11583				}
11584			}
11585		},
11586		
11587		
11588		/*
11589		 * Variable: iFullNumbersShowPages
11590		 * Purpose:  Change the number of pages which can be seen
11591		 * Scope:    jQuery.fn.dataTableExt.oPagination
11592		 */
11593		"iFullNumbersShowPages": 5,
11594		
11595		/*
11596		 * Variable: full_numbers
11597		 * Purpose:  Full numbers pagination
11598		 * Scope:    jQuery.fn.dataTableExt.oPagination
11599		 */
11600		"full_numbers": {
11601			/*
11602			 * Function: oPagination.full_numbers.fnInit
11603			 * Purpose:  Initialise dom elements required for pagination with a list of the pages
11604			 * Returns:  -
11605			 * Inputs:   object:oSettings - dataTables settings object
11606			 *           node:nPaging - the DIV which contains this pagination control
11607			 *           function:fnCallbackDraw - draw function which must be called on update
11608			 */
11609			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
11610			{
11611				var oLang = oSettings.oLanguage.oPaginate;
11612				var oClasses = oSettings.oClasses;
11613				var fnClickHandler = function ( e ) {
11614					if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
11615					{
11616						fnCallbackDraw( oSettings );
11617					}
11618				};
11619	
11620				$(nPaging).append(
11621					'<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+
11622					'<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+
11623					'<span></span>'+
11624					'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+
11625					'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>'
11626				);
11627				var els = $('a', nPaging);
11628				var nFirst = els[0],
11629					nPrev = els[1],
11630					nNext = els[2],
11631					nLast = els[3];
11632				
11633				oSettings.oApi._fnBindAction( nFirst, {action: "first"},    fnClickHandler );
11634				oSettings.oApi._fnBindAction( nPrev,  {action: "previous"}, fnClickHandler );
11635				oSettings.oApi._fnBindAction( nNext,  {action: "next"},     fnClickHandler );
11636				oSettings.oApi._fnBindAction( nLast,  {action: "last"},     fnClickHandler );
11637				
11638				/* ID the first elements only */
11639				if ( !oSettings.aanFeatures.p )
11640				{
11641					nPaging.id = oSettings.sTableId+'_paginate';
11642					nFirst.id =oSettings.sTableId+'_first';
11643					nPrev.id =oSettings.sTableId+'_previous';
11644					nNext.id =oSettings.sTableId+'_next';
11645					nLast.id =oSettings.sTableId+'_last';
11646				}
11647			},
11648			
11649			/*
11650			 * Function: oPagination.full_numbers.fnUpdate
11651			 * Purpose:  Update the list of page buttons shows
11652			 * Returns:  -
11653			 * Inputs:   object:oSettings - dataTables settings object
11654			 *           function:fnCallbackDraw - draw function to call on page change
11655			 */
11656			"fnUpdate": function ( oSettings, fnCallbackDraw )
11657			{
11658				if ( !oSettings.aanFeatures.p )
11659				{
11660					return;
11661				}
11662				
11663				var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages;
11664				var iPageCountHalf = Math.floor(iPageCount / 2);
11665				var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
11666				var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
11667				var sList = "";
11668				var iStartButton, iEndButton, i, iLen;
11669				var oClasses = oSettings.oClasses;
11670				var anButtons, anStatic, nPaginateList, nNode;
11671				var an = oSettings.aanFeatures.p;
11672				var fnBind = function (j) {
11673					oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) {
11674						/* Use the information in the element to jump to the required page */
11675						oSettings.oApi._fnPageChange( oSettings, e.data.page );
11676						fnCallbackDraw( oSettings );
11677						e.preventDefault();
11678					} );
11679				};
11680				
11681				/* Pages calculation */
11682				if ( oSettings._iDisplayLength === -1 )
11683				{
11684					iStartButton = 1;
11685					iEndButton = 1;
11686					iCurrentPage = 1;
11687				}
11688				else if (iPages < iPageCount)
11689				{
11690					iStartButton = 1;
11691					iEndButton = iPages;
11692				}
11693				else if (iCurrentPage <= iPageCountHalf)
11694				{
11695					iStartButton = 1;
11696					iEndButton = iPageCount;
11697				}
11698				else if (iCurrentPage >= (iPages - iPageCountHalf))
11699				{
11700					iStartButton = iPages - iPageCount + 1;
11701					iEndButton = iPages;
11702				}
11703				else
11704				{
11705					iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
11706					iEndButton = iStartButton + iPageCount - 1;
11707				}
11708	
11709				
11710				/* Build the dynamic list */
11711				for ( i=iStartButton ; i<=iEndButton ; i++ )
11712				{
11713					sList += (iCurrentPage !== i) ?
11714						'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' :
11715						'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>';
11716				}
11717				
11718				/* Loop over each instance of the pager */
11719				for ( i=0, iLen=an.length ; i<iLen ; i++ )
11720				{
11721					nNode = an[i];
11722					if ( !nNode.hasChildNodes() )
11723					{
11724						continue;
11725					}
11726					
11727					/* Build up the dynamic list first - html and listeners */
11728					$('span:eq(0)', nNode)
11729						.html( sList )
11730						.children('a').each( fnBind );
11731					
11732					/* Update the permanent button's classes */
11733					anButtons = nNode.getElementsByTagName('a');
11734					anStatic = [
11735						anButtons[0], anButtons[1], 
11736						anButtons[anButtons.length-2], anButtons[anButtons.length-1]
11737					];
11738	
11739					$(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
11740					$([anStatic[0], anStatic[1]]).addClass( 
11741						(iCurrentPage==1) ?
11742							oClasses.sPageButtonStaticDisabled :
11743							oClasses.sPageButton
11744					);
11745					$([anStatic[2], anStatic[3]]).addClass(
11746						(iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ?
11747							oClasses.sPageButtonStaticDisabled :
11748							oClasses.sPageButton
11749					);
11750				}
11751			}
11752		}
11753	} );
11754	
11755	$.extend( DataTable.ext.oSort, {
11756		/*
11757		 * text sorting
11758		 */
11759		"string-pre": function ( a )
11760		{
11761			if ( typeof a != 'string' ) {
11762				a = (a !== null && a.toString) ? a.toString() : '';
11763			}
11764			return a.toLowerCase();
11765		},
11766	
11767		"string-asc": function ( x, y )
11768		{
11769			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
11770		},
11771		
11772		"string-desc": function ( x, y )
11773		{
11774			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
11775		},
11776		
11777		
11778		/*
11779		 * html sorting (ignore html tags)
11780		 */
11781		"html-pre": function ( a )
11782		{
11783			return a.replace( /<.*?>/g, "" ).toLowerCase();
11784		},
11785		
11786		"html-asc": function ( x, y )
11787		{
11788			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
11789		},
11790		
11791		"html-desc": function ( x, y )
11792		{
11793			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
11794		},
11795		
11796		
11797		/*
11798		 * date sorting
11799		 */
11800		"date-pre": function ( a )
11801		{
11802			var x = Date.parse( a );
11803			
11804			if ( isNaN(x) || x==="" )
11805			{
11806				x = Date.parse( "01/01/1970 00:00:00" );
11807			}
11808			return x;
11809		},
11810	
11811		"date-asc": function ( x, y )
11812		{
11813			return x - y;
11814		},
11815		
11816		"date-desc": function ( x, y )
11817		{
11818			return y - x;
11819		},
11820		
11821		
11822		/*
11823		 * numerical sorting
11824		 */
11825		"numeric-pre": function ( a )
11826		{
11827			return (a=="-" || a==="") ? 0 : a*1;
11828		},
11829	
11830		"numeric-asc": function ( x, y )
11831		{
11832			return x - y;
11833		},
11834		
11835		"numeric-desc": function ( x, y )
11836		{
11837			return y - x;
11838		}
11839	} );
11840	
11841	
11842	$.extend( DataTable.ext.aTypes, [
11843		/*
11844		 * Function: -
11845		 * Purpose:  Check to see if a string is numeric
11846		 * Returns:  string:'numeric' or null
11847		 * Inputs:   mixed:sText - string to check
11848		 */
11849		function ( sData )
11850		{
11851			/* Allow zero length strings as a number */
11852			if ( typeof sData === 'number' )
11853			{
11854				return 'numeric';
11855			}
11856			else if ( typeof sData !== 'string' )
11857			{
11858				return null;
11859			}
11860			
11861			var sValidFirstChars = "0123456789-";
11862			var sValidChars = "0123456789.";
11863			var Char;
11864			var bDecimal = false;
11865			
11866			/* Check for a valid first char (no period and allow negatives) */
11867			Char = sData.charAt(0); 
11868			if (sValidFirstChars.indexOf(Char) == -1) 
11869			{
11870				return null;
11871			}
11872			
11873			/* Check all the other characters are valid */
11874			for ( var i=1 ; i<sData.length ; i++ ) 
11875			{
11876				Char = sData.charAt(i); 
11877				if (sValidChars.indexOf(Char) == -1) 
11878				{
11879					return null;
11880				}
11881				
11882				/* Only allowed one decimal place... */
11883				if ( Char == "." )
11884				{
11885					if ( bDecimal )
11886					{
11887						return null;
11888					}
11889					bDecimal = true;
11890				}
11891			}
11892			
11893			return 'numeric';
11894		},
11895		
11896		/*
11897		 * Function: -
11898		 * Purpose:  Check to see if a string is actually a formatted date
11899		 * Returns:  string:'date' or null
11900		 * Inputs:   string:sText - string to check
11901		 */
11902		function ( sData )
11903		{
11904			var iParse = Date.parse(sData);
11905			if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )
11906			{
11907				return 'date';
11908			}
11909			return null;
11910		},
11911		
11912		/*
11913		 * Function: -
11914		 * Purpose:  Check to see if a string should be treated as an HTML string
11915		 * Returns:  string:'html' or null
11916		 * Inputs:   string:sText - string to check
11917		 */
11918		function ( sData )
11919		{
11920			if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
11921			{
11922				return 'html';
11923			}
11924			return null;
11925		}
11926	] );
11927	
11928
11929	// jQuery aliases
11930	$.fn.DataTable = DataTable;
11931	$.fn.dataTable = DataTable;
11932	$.fn.dataTableSettings = DataTable.settings;
11933	$.fn.dataTableExt = DataTable.ext;
11934
11935
11936	// Information about events fired by DataTables - for documentation.
11937	/**
11938	 * Draw event, fired whenever the table is redrawn on the page, at the same point as
11939	 * fnDrawCallback. This may be useful for binding events or performing calculations when
11940	 * the table is altered at all.
11941	 *  @name DataTable#draw
11942	 *  @event
11943	 *  @param {event} e jQuery event object
11944	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11945	 */
11946
11947	/**
11948	 * Filter event, fired when the filtering applied to the table (using the build in global
11949	 * global filter, or column filters) is altered.
11950	 *  @name DataTable#filter
11951	 *  @event
11952	 *  @param {event} e jQuery event object
11953	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11954	 */
11955
11956	/**
11957	 * Page change event, fired when the paging of the table is altered.
11958	 *  @name DataTable#page
11959	 *  @event
11960	 *  @param {event} e jQuery event object
11961	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11962	 */
11963
11964	/**
11965	 * Sort event, fired when the sorting applied to the table is altered.
11966	 *  @name DataTable#sort
11967	 *  @event
11968	 *  @param {event} e jQuery event object
11969	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11970	 */
11971
11972	/**
11973	 * DataTables initialisation complete event, fired when the table is fully drawn,
11974	 * including Ajax data loaded, if Ajax data is required.
11975	 *  @name DataTable#init
11976	 *  @event
11977	 *  @param {event} e jQuery event object
11978	 *  @param {object} oSettings DataTables settings object
11979	 *  @param {object} json The JSON object request from the server - only
11980	 *    present if client-side Ajax sourced data is used</li></ol>
11981	 */
11982
11983	/**
11984	 * State save event, fired when the table has changed state a new state save is required.
11985	 * This method allows modification of the state saving object prior to actually doing the
11986	 * save, including addition or other state properties (for plug-ins) or modification
11987	 * of a DataTables core property.
11988	 *  @name DataTable#stateSaveParams
11989	 *  @event
11990	 *  @param {event} e jQuery event object
11991	 *  @param {object} oSettings DataTables settings object
11992	 *  @param {object} json The state information to be saved
11993	 */
11994
11995	/**
11996	 * State load event, fired when the table is loading state from the stored data, but
11997	 * prior to the settings object being modified by the saved state - allowing modification
11998	 * of the saved state is required or loading of state for a plug-in.
11999	 *  @name DataTable#stateLoadParams
12000	 *  @event
12001	 *  @param {event} e jQuery event object
12002	 *  @param {object} oSettings DataTables settings object
12003	 *  @param {object} json The saved state information
12004	 */
12005
12006	/**
12007	 * State loaded event, fired when state has been loaded from stored data and the settings
12008	 * object has been modified by the loaded data.
12009	 *  @name DataTable#stateLoaded
12010	 *  @event
12011	 *  @param {event} e jQuery event object
12012	 *  @param {object} oSettings DataTables settings object
12013	 *  @param {object} json The saved state information
12014	 */
12015
12016	/**
12017	 * Processing event, fired when DataTables is doing some kind of processing (be it,
12018	 * sort, filter or anything else). Can be used to indicate to the end user that
12019	 * there is something happening, or that something has finished.
12020	 *  @name DataTable#processing
12021	 *  @event
12022	 *  @param {event} e jQuery event object
12023	 *  @param {object} oSettings DataTables settings object
12024	 *  @param {boolean} bShow Flag for if DataTables is doing processing or not
12025	 */
12026
12027	/**
12028	 * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to 
12029	 * made to the server for new data (note that this trigger is called 
12029in fnServerData,
12030	 * if you override fnServerData and which to use this event, you need to trigger it in
12031	 * you success function).
12032	 *  @name DataTable#xhr
12033	 *  @event
12034	 *  @param {event} e jQuery event object
12035	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
12036	 *  @param {object} json JSON returned from the server
12037	 */
12038
12039	/**
12040	 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing
12041	 * the bDestroy:true parameter in the initialisation object. This can be used to remove
12042	 * bound events, added DOM nodes, etc.
12043	 *  @name DataTable#destroy
12044	 *  @event
12045	 *  @param {event} e jQuery event object
12046	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
12047	 */
12048}));
12049
12050}(window, document));
12051

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.