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