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