vw_small

Hardened fork of Vaultwarden (https://github.com/dani-garcia/vaultwarden) with fewer features.
git clone https://git.philomathiclife.com/repos/vw_small
Log | Files | Refs | README

datatables.js (370923B)


      1 /*
      2  * This combined file was created by the DataTables downloader builder:
      3  *   https://datatables.net/download
      4  *
      5  * To rebuild or modify this file with the latest versions of the included
      6  * software please visit:
      7  *   https://datatables.net/download/#bs5/dt-2.0.8
      8  *
      9  * Included libraries:
     10  *   DataTables 2.0.8
     11  */
     12 
     13 /*! DataTables 2.0.8
     14  * © SpryMedia Ltd - datatables.net/license
     15  */
     16 
     17 /**
     18  * @summary     DataTables
     19  * @description Paginate, search and order HTML tables
     20  * @version     2.0.8
     21  * @author      SpryMedia Ltd
     22  * @contact     www.datatables.net
     23  * @copyright   SpryMedia Ltd.
     24  *
     25  * This source file is free software, available under the following license:
     26  *   MIT license - https://datatables.net/license
     27  *
     28  * This source file is distributed in the hope that it will be useful, but
     29  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     30  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
     31  *
     32  * For details please refer to: https://www.datatables.net
     33  */
     34 
     35 (function( factory ) {
     36 	"use strict";
     37 
     38 	if ( typeof define === 'function' && define.amd ) {
     39 		// AMD
     40 		define( ['jquery'], function ( $ ) {
     41 			return factory( $, window, document );
     42 		} );
     43 	}
     44 	else if ( typeof exports === 'object' ) {
     45 		// CommonJS
     46 		// jQuery's factory checks for a global window - if it isn't present then it
     47 		// returns a factory function that expects the window object
     48 		var jq = require('jquery');
     49 
     50 		if (typeof window === 'undefined') {
     51 			module.exports = function (root, $) {
     52 				if ( ! root ) {
     53 					// CommonJS environments without a window global must pass a
     54 					// root. This will give an error otherwise
     55 					root = window;
     56 				}
     57 
     58 				if ( ! $ ) {
     59 					$ = jq( root );
     60 				}
     61 
     62 				return factory( $, root, root.document );
     63 			};
     64 		}
     65 		else {
     66 			module.exports = factory( jq, window, window.document );
     67 		}
     68 	}
     69 	else {
     70 		// Browser
     71 		window.DataTable = factory( jQuery, window, document );
     72 	}
     73 }(function( $, window, document ) {
     74 	"use strict";
     75 
     76 	
     77 	var DataTable = function ( selector, options )
     78 	{
     79 		// Check if called with a window or jQuery object for DOM less applications
     80 		// This is for backwards compatibility
     81 		if (DataTable.factory(selector, options)) {
     82 			return DataTable;
     83 		}
     84 	
     85 		// When creating with `new`, create a new DataTable, returning the API instance
     86 		if (this instanceof DataTable) {
     87 			return $(selector).DataTable(options);
     88 		}
     89 		else {
     90 			// Argument switching
     91 			options = selector;
     92 		}
     93 	
     94 		var _that = this;
     95 		var emptyInit = options === undefined;
     96 		var len = this.length;
     97 	
     98 		if ( emptyInit ) {
     99 			options = {};
    100 		}
    101 	
    102 		// Method to get DT API instance from jQuery object
    103 		this.api = function ()
    104 		{
    105 			return new _Api( this );
    106 		};
    107 	
    108 		this.each(function() {
    109 			// For each initialisation we want to give it a clean initialisation
    110 			// object that can be bashed around
    111 			var o = {};
    112 			var oInit = len > 1 ? // optimisation for single table case
    113 				_fnExtend( o, options, true ) :
    114 				options;
    115 	
    116 			
    117 			var i=0, iLen;
    118 			var sId = this.getAttribute( 'id' );
    119 			var bInitHandedOff = false;
    120 			var defaults = DataTable.defaults;
    121 			var $this = $(this);
    122 			
    123 			
    124 			/* Sanity check */
    125 			if ( this.nodeName.toLowerCase() != 'table' )
    126 			{
    127 				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
    128 				return;
    129 			}
    130 			
    131 			$(this).trigger( 'options.dt', oInit );
    132 			
    133 			/* Backwards compatibility for the defaults */
    134 			_fnCompatOpts( defaults );
    135 			_fnCompatCols( defaults.column );
    136 			
    137 			/* Convert the camel-case defaults to Hungarian */
    138 			_fnCamelToHungarian( defaults, defaults, true );
    139 			_fnCamelToHungarian( defaults.column, defaults.column, true );
    140 			
    141 			/* Setting up the initialisation object */
    142 			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
    143 			
    144 			
    145 			
    146 			/* Check to see if we are re-initialising a table */
    147 			var allSettings = DataTable.settings;
    148 			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
    149 			{
    150 				var s = allSettings[i];
    151 			
    152 				/* Base check on table node */
    153 				if (
    154 					s.nTable == this ||
    155 					(s.nTHead && s.nTHead.parentNode == this) ||
    156 					(s.nTFoot && s.nTFoot.parentNode == this)
    157 				) {
    158 					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
    159 					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
    160 			
    161 					if ( emptyInit || bRetrieve )
    162 					{
    163 						return s.oInstance;
    164 					}
    165 					else if ( bDestroy )
    166 					{
    167 						new DataTable.Api(s).destroy();
    168 						break;
    169 					}
    170 					else
    171 					{
    172 						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
    173 						return;
    174 					}
    175 				}
    176 			
    177 				/* If the element we are initialising has the same ID as a table which was previously
    178 				 * initialised, but the table nodes don't match (from before) then we destroy the old
    179 				 * instance by simply deleting it. This is under the assumption that the table has been
    180 				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
    181 				 */
    182 				if ( s.sTableId == this.id )
    183 				{
    184 					allSettings.splice( i, 1 );
    185 					break;
    186 				}
    187 			}
    188 			
    189 			/* Ensure the table has an ID - required for accessibility */
    190 			if ( sId === null || sId === "" )
    191 			{
    192 				sId = "DataTables_Table_"+(DataTable.ext._unique++);
    193 				this.id = sId;
    194 			}
    195 			
    196 			/* Create the settings object for this table and set some of the default parameters */
    197 			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
    198 				"sDestroyWidth": $this[0].style.width,
    199 				"sInstance":     sId,
    200 				"sTableId":      sId,
    201 				colgroup: $('<colgroup>').prependTo(this),
    202 				fastData: function (row, column, type) {
    203 					return _fnGetCellData(oSettings, row, column, type);
    204 				}
    205 			} );
    206 			oSettings.nTable = this;
    207 			oSettings.oInit  = oInit;
    208 			
    209 			allSettings.push( oSettings );
    210 			
    211 			// Make a single API instance available for internal handling
    212 			oSettings.api = new _Api( oSettings );
    213 			
    214 			// Need to add the instance after the instance after the settings object has been added
    215 			// to the settings array, so we can self reference the table instance if more than one
    216 			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
    217 			
    218 			// Backwards compatibility, before we apply all the defaults
    219 			_fnCompatOpts( oInit );
    220 			
    221 			// If the length menu is given, but the init display length is not, use the length menu
    222 			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
    223 			{
    224 				oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
    225 					? oInit.aLengthMenu[0][0]
    226 					: $.isPlainObject( oInit.aLengthMenu[0] )
    227 						? oInit.aLengthMenu[0].value
    228 						: oInit.aLengthMenu[0];
    229 			}
    230 			
    231 			// Apply the defaults and init options to make a single init object will all
    232 			// options defined from defaults and instance options.
    233 			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
    234 			
    235 			
    236 			// Map the initialisation options onto the settings object
    237 			_fnMap( oSettings.oFeatures, oInit, [
    238 				"bPaginate",
    239 				"bLengthChange",
    240 				"bFilter",
    241 				"bSort",
    242 				"bSortMulti",
    243 				"bInfo",
    244 				"bProcessing",
    245 				"bAutoWidth",
    246 				"bSortClasses",
    247 				"bServerSide",
    248 				"bDeferRender"
    249 			] );
    250 			_fnMap( oSettings, oInit, [
    251 				"ajax",
    252 				"fnFormatNumber",
    253 				"sServerMethod",
    254 				"aaSorting",
    255 				"aaSortingFixed",
    256 				"aLengthMenu",
    257 				"sPaginationType",
    258 				"iStateDuration",
    259 				"bSortCellsTop",
    260 				"iTabIndex",
    261 				"sDom",
    262 				"fnStateLoadCallback",
    263 				"fnStateSaveCallback",
    264 				"renderer",
    265 				"searchDelay",
    266 				"rowId",
    267 				"caption",
    268 				"layout",
    269 				[ "iCookieDuration", "iStateDuration" ], // backwards compat
    270 				[ "oSearch", "oPreviousSearch" ],
    271 				[ "aoSearchCols", "aoPreSearchCols" ],
    272 				[ "iDisplayLength", "_iDisplayLength" ]
    273 			] );
    274 			_fnMap( oSettings.oScroll, oInit, [
    275 				[ "sScrollX", "sX" ],
    276 				[ "sScrollXInner", "sXInner" ],
    277 				[ "sScrollY", "sY" ],
    278 				[ "bScrollCollapse", "bCollapse" ]
    279 			] );
    280 			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
    281 			
    282 			/* Callback functions which are array driven */
    283 			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback );
    284 			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams );
    285 			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams );
    286 			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded );
    287 			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback );
    288 			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
    289 			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback );
    290 			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback );
    291 			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete );
    292 			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback );
    293 			
    294 			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
    295 			
    296 			/* Browser support detection */
    297 			_fnBrowserDetect( oSettings );
    298 			
    299 			var oClasses = oSettings.oClasses;
    300 			
    301 			$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
    302 			$this.addClass( oClasses.table );
    303 			
    304 			if (! oSettings.oFeatures.bPaginate) {
    305 				oInit.iDisplayStart = 0;
    306 			}
    307 			
    308 			if ( oSettings.iInitDisplayStart === undefined )
    309 			{
    310 				/* Display start point, taking into account the save saving */
    311 				oSettings.iInitDisplayStart = oInit.iDisplayStart;
    312 				oSettings._iDisplayStart = oInit.iDisplayStart;
    313 			}
    314 			
    315 			/* Language definitions */
    316 			var oLanguage = oSettings.oLanguage;
    317 			$.extend( true, oLanguage, oInit.oLanguage );
    318 			
    319 			if ( oLanguage.sUrl )
    320 			{
    321 				/* Get the language definitions from a file - because this Ajax call makes the language
    322 				 * get async to the remainder of this function we use bInitHandedOff to indicate that
    323 				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
    324 				 */
    325 				$.ajax( {
    326 					dataType: 'json',
    327 					url: oLanguage.sUrl,
    328 					success: function ( json ) {
    329 						_fnCamelToHungarian( defaults.oLanguage, json );
    330 						$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
    331 			
    332 						_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
    333 						_fnInitialise( oSettings );
    334 					},
    335 					error: function () {
    336 						// Error occurred loading language file
    337 						_fnLog( oSettings, 0, 'i18n file loading error', 21 );
    338 			
    339 						// continue on as best we can
    340 						_fnInitialise( oSettings );
    341 					}
    342 				} );
    343 				bInitHandedOff = true;
    344 			}
    345 			else {
    346 				_fnCallbackFire( oSettings, null, 'i18n', [oSettings]);
    347 			}
    348 			
    349 			/*
    350 			 * Columns
    351 			 * See if we should load columns automatically or use defined ones
    352 			 */
    353 			var columnsInit = [];
    354 			var thead = this.getElementsByTagName('thead');
    355 			var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
    356 			
    357 			// If we don't have a columns array, then generate one with nulls
    358 			if ( oInit.aoColumns ) {
    359 				columnsInit = oInit.aoColumns;
    360 			}
    361 			else if ( initHeaderLayout.length ) {
    362 				for ( i=0, iLen=initHeaderLayout[0].length ; i<iLen ; i++ ) {
    363 					columnsInit.push( null );
    364 				}
    365 			}
    366 			
    367 			// Add the columns
    368 			for ( i=0, iLen=columnsInit.length ; i<iLen ; i++ ) {
    369 				_fnAddColumn( oSettings );
    370 			}
    371 			
    372 			// Apply the column definitions
    373 			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
    374 				_fnColumnOptions( oSettings, iCol, oDef );
    375 			} );
    376 			
    377 			/* HTML5 attribute detection - build an mData object automatically if the
    378 			 * attributes are found
    379 			 */
    380 			var rowOne = $this.children('tbody').find('tr').eq(0);
    381 			
    382 			if ( rowOne.length ) {
    383 				var a = function ( cell, name ) {
    384 					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
    385 				};
    386 			
    387 				$( rowOne[0] ).children('th, td').each( function (i, cell) {
    388 					var col = oSettings.aoColumns[i];
    389 			
    390 					if (! col) {
    391 						_fnLog( oSettings, 0, 'Incorrect column count', 18 );
    392 					}
    393 			
    394 					if ( col.mData === i ) {
    395 						var sort = a( cell, 'sort' ) || a( cell, 'order' );
    396 						var filter = a( cell, 'filter' ) || a( cell, 'search' );
    397 			
    398 						if ( sort !== null || filter !== null ) {
    399 							col.mData = {
    400 								_:      i+'.display',
    401 								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
    402 								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
    403 								filter: filter !== null ? i+'.@data-'+filter : undefined
    404 							};
    405 							col._isArrayHost = true;
    406 			
    407 							_fnColumnOptions( oSettings, i );
    408 						}
    409 					}
    410 				} );
    411 			}
    412 			
    413 			var features = oSettings.oFeatures;
    414 			var loadedInit = function () {
    415 				/*
    416 				 * Sorting
    417 				 * @todo For modularisation (1.11) this needs to do into a sort start up handler
    418 				 */
    419 			
    420 				// If aaSorting is not defined, then we use the first indicator in asSorting
    421 				// in case that has been altered, so the default sort reflects that option
    422 				if ( oInit.aaSorting === undefined ) {
    423 					var sorting = oSettings.aaSorting;
    424 					for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
    425 						sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
    426 					}
    427 				}
    428 			
    429 				/* Do a first pass on the sorting classes (allows any size changes to be taken into
    430 				 * account, and also will apply sorting disabled classes if disabled
    431 				 */
    432 				_fnSortingClasses( oSettings );
    433 			
    434 				_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
    435 					if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
    436 						_fnSortingClasses( oSettings );
    437 					}
    438 				} );
    439 			
    440 			
    441 				/*
    442 				 * Final init
    443 				 * Cache the header, body and footer as required, creating them if needed
    444 				 */
    445 				var caption = $this.children('caption');
    446 			
    447 				if ( oSettings.caption ) {
    448 					if ( caption.length === 0 ) {
    449 						caption = $('<caption/>').appendTo( $this );
    450 					}
    451 			
    452 					caption.html( oSettings.caption );
    453 				}
    454 			
    455 				// Store the caption side, so we can remove the element from the document
    456 				// when creating the element
    457 				if (caption.length) {
    458 					caption[0]._captionSide = caption.css('caption-side');
    459 					oSettings.captionNode = caption[0];
    460 				}
    461 			
    462 				if ( thead.length === 0 ) {
    463 					thead = $('<thead/>').appendTo($this);
    464 				}
    465 				oSettings.nTHead = thead[0];
    466 				$('tr', thead).addClass(oClasses.thead.row);
    467 			
    468 				var tbody = $this.children('tbody');
    469 				if ( tbody.length === 0 ) {
    470 					tbody = $('<tbody/>').insertAfter(thead);
    471 				}
    472 				oSettings.nTBody = tbody[0];
    473 			
    474 				var tfoot = $this.children('tfoot');
    475 				if ( tfoot.length === 0 ) {
    476 					// If we are a scrolling table, and no footer has been given, then we need to create
    477 					// a tfoot element for the caption element to be appended to
    478 					tfoot = $('<tfoot/>').appendTo($this);
    479 				}
    480 				oSettings.nTFoot = tfoot[0];
    481 				$('tr', tfoot).addClass(oClasses.tfoot.row);
    482 			
    483 				// Check if there is data passing into the constructor
    484 				if ( oInit.aaData ) {
    485 					for ( i=0 ; i<oInit.aaData.length ; i++ ) {
    486 						_fnAddData( oSettings, oInit.aaData[ i ] );
    487 					}
    488 				}
    489 				else if ( _fnDataSource( oSettings ) == 'dom' ) {
    490 					// Grab the data from the page
    491 					_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
    492 				}
    493 			
    494 				/* Copy the data index array */
    495 				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
    496 			
    497 				/* Initialisation complete - table can be drawn */
    498 				oSettings.bInitialised = true;
    499 			
    500 				/* Check if we need to initialise the table (it might not have been handed off to the
    501 				 * language processor)
    502 				 */
    503 				if ( bInitHandedOff === false ) {
    504 					_fnInitialise( oSettings );
    505 				}
    506 			};
    507 			
    508 			/* Must be done after everything which can be overridden by the state saving! */
    509 			_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState );
    510 			
    511 			if ( oInit.bStateSave )
    512 			{
    513 				features.bStateSave = true;
    514 				_fnLoadState( oSettings, oInit, loadedInit );
    515 			}
    516 			else {
    517 				loadedInit();
    518 			}
    519 			
    520 		} );
    521 		_that = null;
    522 		return this;
    523 	};
    524 	
    525 	
    526 	
    527 	/**
    528 	 * DataTables extensions
    529 	 * 
    530 	 * This namespace acts as a collection area for plug-ins that can be used to
    531 	 * extend DataTables capabilities. Indeed many of the build in methods
    532 	 * use this method to provide their own capabilities (sorting methods for
    533 	 * example).
    534 	 *
    535 	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
    536 	 * reasons
    537 	 *
    538 	 *  @namespace
    539 	 */
    540 	DataTable.ext = _ext = {
    541 		/**
    542 		 * Buttons. For use with the Buttons extension for DataTables. This is
    543 		 * defined here so other extensions can define buttons regardless of load
    544 		 * order. It is _not_ used by DataTables core.
    545 		 *
    546 		 *  @type object
    547 		 *  @default {}
    548 		 */
    549 		buttons: {},
    550 	
    551 	
    552 		/**
    553 		 * Element class names
    554 		 *
    555 		 *  @type object
    556 		 *  @default {}
    557 		 */
    558 		classes: {},
    559 	
    560 	
    561 		/**
    562 		 * DataTables build type (expanded by the download builder)
    563 		 *
    564 		 *  @type string
    565 		 */
    566 		builder: "bs5/dt-2.0.8",
    567 	
    568 	
    569 		/**
    570 		 * Error reporting.
    571 		 * 
    572 		 * How should DataTables report an error. Can take the value 'alert',
    573 		 * 'throw', 'none' or a function.
    574 		 *
    575 		 *  @type string|function
    576 		 *  @default alert
    577 		 */
    578 		errMode: "alert",
    579 	
    580 	
    581 		/**
    582 		 * Legacy so v1 plug-ins don't throw js errors on load
    583 		 */
    584 		feature: [],
    585 	
    586 		/**
    587 		 * Feature plug-ins.
    588 		 * 
    589 		 * This is an object of callbacks which provide the features for DataTables
    590 		 * to be initialised via the `layout` option.
    591 		 */
    592 		features: {},
    593 	
    594 	
    595 		/**
    596 		 * Row searching.
    597 		 * 
    598 		 * This method of searching is complimentary to the default type based
    599 		 * searching, and a lot more comprehensive as it allows you complete control
    600 		 * over the searching logic. Each element in this array is a function
    601 		 * (parameters described below) that is called for every row in the table,
    602 		 * and your logic decides if it should be included in the searching data set
    603 		 * or not.
    604 		 *
    605 		 * Searching functions have the following input parameters:
    606 		 *
    607 		 * 1. `{object}` DataTables settings object: see
    608 		 *    {@link DataTable.models.oSettings}
    609 		 * 2. `{array|object}` Data for the row to be processed (same as the
    610 		 *    original format that was passed in as the data source, or an array
    611 		 *    from a DOM data source
    612 		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
    613 		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
    614 		 *
    615 		 * And the following return is expected:
    616 		 *
    617 		 * * {boolean} Include the row in the searched result set (true) or not
    618 		 *   (false)
    619 		 *
    620 		 * Note that as with the main search ability in DataTables, technically this
    621 		 * is "filtering", since it is subtractive. However, for consistency in
    622 		 * naming we call it searching here.
    623 		 *
    624 		 *  @type array
    625 		 *  @default []
    626 		 *
    627 		 *  @example
    628 		 *    // The following example shows custom search being applied to the
    629 		 *    // fourth column (i.e. the data[3] index) based on two input values
    630 		 *    // from the end-user, matching the data in a certain range.
    631 		 *    $.fn.dataTable.ext.search.push(
    632 		 *      function( settings, data, dataIndex ) {
    633 		 *        var min = document.getElementById('min').value * 1;
    634 		 *        var max = document.getElementById('max').value * 1;
    635 		 *        var version = data[3] == "-" ? 0 : data[3]*1;
    636 		 *
    637 		 *        if ( min == "" && max == "" ) {
    638 		 *          return true;
    639 		 *        }
    640 		 *        else if ( min == "" && version < max ) {
    641 		 *          return true;
    642 		 *        }
    643 		 *        else if ( min < version && "" == max ) {
    644 		 *          return true;
    645 		 *        }
    646 		 *        else if ( min < version && version < max ) {
    647 		 *          return true;
    648 		 *        }
    649 		 *        return false;
    650 		 *      }
    651 		 *    );
    652 		 */
    653 		search: [],
    654 	
    655 	
    656 		/**
    657 		 * Selector extensions
    658 		 *
    659 		 * The `selector` option can be used to extend the options available for the
    660 		 * selector modifier options (`selector-modifier` object data type) that
    661 		 * each of the three built in selector types offer (row, column and cell +
    662 		 * their plural counterparts). For example the Select extension uses this
    663 		 * mechanism to provide an option to select only rows, columns and cells
    664 		 * that have been marked as selected by the end user (`{selected: true}`),
    665 		 * which can be used in conjunction with the existing built in selector
    666 		 * options.
    667 		 *
    668 		 * Each property is an array to which functions can be pushed. The functions
    669 		 * take three attributes:
    670 		 *
    671 		 * * Settings object for the host table
    672 		 * * Options object (`selector-modifier` object type)
    673 		 * * Array of selected item indexes
    674 		 *
    675 		 * The return is an array of the resulting item indexes after the custom
    676 		 * selector has been applied.
    677 		 *
    678 		 *  @type object
    679 		 */
    680 		selector: {
    681 			cell: [],
    682 			column: [],
    683 			row: []
    684 		},
    685 	
    686 	
    687 		/**
    688 		 * Legacy configuration options. Enable and disable legacy options that
    689 		 * are available in DataTables.
    690 		 *
    691 		 *  @type object
    692 		 */
    693 		legacy: {
    694 			/**
    695 			 * Enable / disable DataTables 1.9 compatible server-side processing
    696 			 * requests
    697 			 *
    698 			 *  @type boolean
    699 			 *  @default null
    700 			 */
    701 			ajax: null
    702 		},
    703 	
    704 	
    705 		/**
    706 		 * Pagination plug-in methods.
    707 		 * 
    708 		 * Each entry in this object is a function and defines which buttons should
    709 		 * be shown by the pagination rendering method that is used for the table:
    710 		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
    711 		 * buttons are displayed in the document, while the functions here tell it
    712 		 * what buttons to display. This is done by returning an array of button
    713 		 * descriptions (what each button will do).
    714 		 *
    715 		 * Pagination types (the four built in options and any additional plug-in
    716 		 * options defined here) can be used through the `paginationType`
    717 		 * initialisation parameter.
    718 		 *
    719 		 * The functions defined take two parameters:
    720 		 *
    721 		 * 1. `{int} page` The current page index
    722 		 * 2. `{int} pages` The number of pages in the table
    723 		 *
    724 		 * Each function is expected to return an array where each element of the
    725 		 * array can be one of:
    726 		 *
    727 		 * * `first` - Jump to first page when activated
    728 		 * * `last` - Jump to last page when activated
    729 		 * * `previous` - Show previous page when activated
    730 		 * * `next` - Show next page when activated
    731 		 * * `{int}` - Show page of the index given
    732 		 * * `{array}` - A nested array containing the above elements to add a
    733 		 *   containing 'DIV' element (might be useful for styling).
    734 		 *
    735 		 * Note that DataTables v1.9- used this object slightly differently whereby
    736 		 * an object with two functions would be defined for each plug-in. That
    737 		 * ability is still supported by DataTables 1.10+ to provide backwards
    738 		 * compatibility, but this option of use is now decremented and no longer
    739 		 * documented in DataTables 1.10+.
    740 		 *
    741 		 *  @type object
    742 		 *  @default {}
    743 		 *
    744 		 *  @example
    745 		 *    // Show previous, next and current page buttons only
    746 		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
    747 		 *      return [ 'previous', page, 'next' ];
    748 		 *    };
    749 		 */
    750 		pager: {},
    751 	
    752 	
    753 		renderer: {
    754 			pageButton: {},
    755 			header: {}
    756 		},
    757 	
    758 	
    759 		/**
    760 		 * Ordering plug-ins - custom data source
    761 		 * 
    762 		 * The extension options for ordering of data available here is complimentary
    763 		 * to the default type based ordering that DataTables typically uses. It
    764 		 * allows much greater control over the the data that is being used to
    765 		 * order a column, but is necessarily therefore more complex.
    766 		 * 
    767 		 * This type of ordering is useful if you want to do ordering based on data
    768 		 * live from the DOM (for example the contents of an 'input' element) rather
    769 		 * than just the static string that DataTables knows of.
    770 		 * 
    771 		 * The way these plug-ins work is that you create an array of the values you
    772 		 * wish to be ordering for the column in question and then return that
    773 		 * array. The data in the array much be in the index order of the rows in
    774 		 * the table (not the currently ordering order!). Which order data gathering
    775 		 * function is run here depends on the `dt-init columns.orderDataType`
    776 		 * parameter that is used for the column (if any).
    777 		 *
    778 		 * The functions defined take two parameters:
    779 		 *
    780 		 * 1. `{object}` DataTables settings object: see
    781 		 *    {@link DataTable.models.oSettings}
    782 		 * 2. `{int}` Target column index
    783 		 *
    784 		 * Each function is expected to return an array:
    785 		 *
    786 		 * * `{array}` Data for the column to be ordering upon
    787 		 *
    788 		 *  @type array
    789 		 *
    790 		 *  @example
    791 		 *    // Ordering using `input` node values
    792 		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
    793 		 *    {
    794 		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
    795 		 *        return $('input', td).val();
    796 		 *      } );
    797 		 *    }
    798 		 */
    799 		order: {},
    800 	
    801 	
    802 		/**
    803 		 * Type based plug-ins.
    804 		 *
    805 		 * Each column in DataTables has a type assigned to it, either by automatic
    806 		 * detection or by direct assignment using the `type` option for the column.
    807 		 * The type of a column will effect how it is ordering and search (plug-ins
    808 		 * can also make use of the column type if required).
    809 		 *
    810 		 * @namespace
    811 		 */
    812 		type: {
    813 			/**
    814 			 * Automatic column class assignment
    815 			 */
    816 			className: {},
    817 	
    818 			/**
    819 			 * Type detection functions.
    820 			 *
    821 			 * The functions defined in this object are used to automatically detect
    822 			 * a column's type, making initialisation of DataTables super easy, even
    823 			 * when complex data is in the table.
    824 			 *
    825 			 * The functions defined take two parameters:
    826 			 *
    827 		     *  1. `{*}` Data from the column cell to be analysed
    828 		     *  2. `{settings}` DataTables settings object. This can be used to
    829 		     *     perform context specific type detection - for example detection
    830 		     *     based on language settings such as using a comma for a decimal
    831 		     *     place. Generally speaking the options from the settings will not
    832 		     *     be required
    833 			 *
    834 			 * Each function is expected to return:
    835 			 *
    836 			 * * `{string|null}` Data type detected, or null if unknown (and thus
    837 			 *   pass it on to the other type detection functions.
    838 			 *
    839 			 *  @type array
    840 			 *
    841 			 *  @example
    842 			 *    // Currency type detection plug-in:
    843 			 *    $.fn.dataTable.ext.type.detect.push(
    844 			 *      function ( data, settings ) {
    845 			 *        // Check the numeric part
    846 			 *        if ( ! data.substring(1).match(/[0-9]/) ) {
    847 			 *          return null;
    848 			 *        }
    849 			 *
    850 			 *        // Check prefixed by currency
    851 			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
    852 			 *          return 'currency';
    853 			 *        }
    854 			 *        return null;
    855 			 *      }
    856 			 *    );
    857 			 */
    858 			detect: [],
    859 	
    860 			/**
    861 			 * Automatic renderer assignment
    862 			 */
    863 			render: {},
    864 	
    865 	
    866 			/**
    867 			 * Type based search formatting.
    868 			 *
    869 			 * The type based searching functions can be used to pre-format the
    870 			 * data to be search on. For example, it can be used to strip HTML
    871 			 * tags or to de-format telephone numbers for numeric only searching.
    872 			 *
    873 			 * Note that is a search is not defined for a column of a given type,
    874 			 * no search formatting will be performed.
    875 			 * 
    876 			 * Pre-processing of searching data plug-ins - When you assign the sType
    877 			 * for a column (or have it automatically detected for you by DataTables
    878 			 * or a type detection plug-in), you will typically be using this for
    879 			 * custom sorting, but it can also be used to provide custom searching
    880 			 * by allowing you to pre-processing the data and returning the data in
    881 			 * the format that should be searched upon. This is done by adding
    882 			 * functions this object with a parameter name which matches the sType
    883 			 * for that target column. This is the corollary of <i>afnSortData</i>
    884 			 * for searching data.
    885 			 *
    886 			 * The functions defined take a single parameter:
    887 			 *
    888 		     *  1. `{*}` Data from the column cell to be prepared for searching
    889 			 *
    890 			 * Each function is expected to return:
    891 			 *
    892 			 * * `{string|null}` Formatted string that will be used for the searching.
    893 			 *
    894 			 *  @type object
    895 			 *  @default {}
    896 			 *
    897 			 *  @example
    898 			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
    899 			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
    900 			 *    }
    901 			 */
    902 			search: {},
    903 	
    904 	
    905 			/**
    906 			 * Type based ordering.
    907 			 *
    908 			 * The column type tells DataTables what ordering to apply to the table
    909 			 * when a column is sorted upon. The order for each type that is defined,
    910 			 * is defined by the functions available in this object.
    911 			 *
    912 			 * Each ordering option can be described by three properties added to
    913 			 * this object:
    914 			 *
    915 			 * * `{type}-pre` - Pre-formatting function
    916 			 * * `{type}-asc` - Ascending order function
    917 			 * * `{type}-desc` - Descending order function
    918 			 *
    919 			 * All three can be used together, only `{type}-pre` or only
    920 			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
    921 			 * that only `{type}-pre` is used, as this provides the optimal
    922 			 * implementation in terms of speed, although the others are provided
    923 			 * for compatibility with existing Javascript sort functions.
    924 			 *
    925 			 * `{type}-pre`: Functions defined take a single parameter:
    926 			 *
    927 		     *  1. `{*}` Data from the column cell to be prepared for ordering
    928 			 *
    929 			 * And return:
    930 			 *
    931 			 * * `{*}` Data to be sorted upon
    932 			 *
    933 			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
    934 			 * functions, taking two parameters:
    935 			 *
    936 		     *  1. `{*}` Data to compare to the second parameter
    937 		     *  2. `{*}` Data to compare to the first parameter
    938 			 *
    939 			 * And returning:
    940 			 *
    941 			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
    942 			 *   than the second parameter, ===0 if the two parameters are equal and
    943 			 *   >0 if the first parameter should be sorted height than the second
    944 			 *   parameter.
    945 			 * 
    946 			 *  @type object
    947 			 *  @default {}
    948 			 *
    949 			 *  @example
    950 			 *    // Numeric ordering of formatted numbers with a pre-formatter
    951 			 *    $.extend( $.fn.dataTable.ext.type.order, {
    952 			 *      "string-pre": function(x) {
    953 			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
    954 			 *        return parseFloat( a );
    955 			 *      }
    956 			 *    } );
    957 			 *
    958 			 *  @example
    959 			 *    // Case-sensitive string ordering, with no pre-formatting method
    960 			 *    $.extend( $.fn.dataTable.ext.order, {
    961 			 *      "string-case-asc": function(x,y) {
    962 			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    963 			 *      },
    964 			 *      "string-case-desc": function(x,y) {
    965 			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
    966 			 *      }
    967 			 *    } );
    968 			 */
    969 			order: {}
    970 		},
    971 	
    972 		/**
    973 		 * Unique DataTables instance counter
    974 		 *
    975 		 * @type int
    976 		 * @private
    977 		 */
    978 		_unique: 0,
    979 	
    980 	
    981 		//
    982 		// Depreciated
    983 		// The following properties are retained for backwards compatibility only.
    984 		// The should not be used in new projects and will be removed in a future
    985 		// version
    986 		//
    987 	
    988 		/**
    989 		 * Version check function.
    990 		 *  @type function
    991 		 *  @depreciated Since 1.10
    992 		 */
    993 		fnVersionCheck: DataTable.fnVersionCheck,
    994 	
    995 	
    996 		/**
    997 		 * Index for what 'this' index API functions should use
    998 		 *  @type int
    999 		 *  @deprecated Since v1.10
   1000 		 */
   1001 		iApiIndex: 0,
   1002 	
   1003 	
   1004 		/**
   1005 		 * Software version
   1006 		 *  @type string
   1007 		 *  @deprecated Since v1.10
   1008 		 */
   1009 		sVersion: DataTable.version
   1010 	};
   1011 	
   1012 	
   1013 	//
   1014 	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
   1015 	//
   1016 	$.extend( _ext, {
   1017 		afnFiltering: _ext.search,
   1018 		aTypes:       _ext.type.detect,
   1019 		ofnSearch:    _ext.type.search,
   1020 		oSort:        _ext.type.order,
   1021 		afnSortData:  _ext.order,
   1022 		aoFeatures:   _ext.feature,
   1023 		oStdClasses:  _ext.classes,
   1024 		oPagination:  _ext.pager
   1025 	} );
   1026 	
   1027 	
   1028 	$.extend( DataTable.ext.classes, {
   1029 		container: 'dt-container',
   1030 		empty: {
   1031 			row: 'dt-empty'
   1032 		},
   1033 		info: {
   1034 			container: 'dt-info'
   1035 		},
   1036 		length: {
   1037 			container: 'dt-length',
   1038 			select: 'dt-input'
   1039 		},
   1040 		order: {
   1041 			canAsc: 'dt-orderable-asc',
   1042 			canDesc: 'dt-orderable-desc',
   1043 			isAsc: 'dt-ordering-asc',
   1044 			isDesc: 'dt-ordering-desc',
   1045 			none: 'dt-orderable-none',
   1046 			position: 'sorting_'
   1047 		},
   1048 		processing: {
   1049 			container: 'dt-processing'
   1050 		},
   1051 		scrolling: {
   1052 			body: 'dt-scroll-body',
   1053 			container: 'dt-scroll',
   1054 			footer: {
   1055 				self: 'dt-scroll-foot',
   1056 				inner: 'dt-scroll-footInner'
   1057 			},
   1058 			header: {
   1059 				self: 'dt-scroll-head',
   1060 				inner: 'dt-scroll-headInner'
   1061 			}
   1062 		},
   1063 		search: {
   1064 			container: 'dt-search',
   1065 			input: 'dt-input'
   1066 		},
   1067 		table: 'dataTable',	
   1068 		tbody: {
   1069 			cell: '',
   1070 			row: ''
   1071 		},
   1072 		thead: {
   1073 			cell: '',
   1074 			row: ''
   1075 		},
   1076 		tfoot: {
   1077 			cell: '',
   1078 			row: ''
   1079 		},
   1080 		paging: {
   1081 			active: 'current',
   1082 			button: 'dt-paging-button',
   1083 			container: 'dt-paging',
   1084 			disabled: 'disabled'
   1085 		}
   1086 	} );
   1087 	
   1088 	
   1089 	/*
   1090 	 * It is useful to have variables which are scoped locally so only the
   1091 	 * DataTables functions can access them and they don't leak into global space.
   1092 	 * At the same time these functions are often useful over multiple files in the
   1093 	 * core and API, so we list, or at least document, all variables which are used
   1094 	 * by DataTables as private variables here. This also ensures that there is no
   1095 	 * clashing of variable names and that they can easily referenced for reuse.
   1096 	 */
   1097 	
   1098 	
   1099 	// Defined else where
   1100 	//  _selector_run
   1101 	//  _selector_opts
   1102 	//  _selector_row_indexes
   1103 	
   1104 	var _ext; // DataTable.ext
   1105 	var _Api; // DataTable.Api
   1106 	var _api_register; // DataTable.Api.register
   1107 	var _api_registerPlural; // DataTable.Api.registerPlural
   1108 	
   1109 	var _re_dic = {};
   1110 	var _re_new_lines = /[\r\n\u2028]/g;
   1111 	var _re_html = /<([^>]*>)/g;
   1112 	var _max_str_len = Math.pow(2, 28);
   1113 	
   1114 	// This is not strict ISO8601 - Date.parse() is quite lax, although
   1115 	// implementations differ between browsers.
   1116 	var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
   1117 	
   1118 	// Escape regular expression special characters
   1119 	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
   1120 	
   1121 	// https://en.wikipedia.org/wiki/Foreign_exchange_market
   1122 	// - \u20BD - Russian ruble.
   1123 	// - \u20a9 - South Korean Won
   1124 	// - \u20BA - Turkish Lira
   1125 	// - \u20B9 - Indian Rupee
   1126 	// - R - Brazil (R$) and South Africa
   1127 	// - fr - Swiss Franc
   1128 	// - kr - Swedish krona, Norwegian krone and Danish krone
   1129 	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
   1130 	// - Ƀ - Bitcoin
   1131 	// - Ξ - Ethereum
   1132 	//   standards as thousands separators.
   1133 	var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
   1134 	
   1135 	
   1136 	var _empty = function ( d ) {
   1137 		return !d || d === true || d === '-' ? true : false;
   1138 	};
   1139 	
   1140 	
   1141 	var _intVal = function ( s ) {
   1142 		var integer = parseInt( s, 10 );
   1143 		return !isNaN(integer) && isFinite(s) ? integer : null;
   1144 	};
   1145 	
   1146 	// Convert from a formatted number with characters other than `.` as the
   1147 	// decimal place, to a Javascript number
   1148 	var _numToDecimal = function ( num, decimalPoint ) {
   1149 		// Cache created regular expressions for speed as this function is called often
   1150 		if ( ! _re_dic[ decimalPoint ] ) {
   1151 			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
   1152 		}
   1153 		return typeof num === 'string' && decimalPoint !== '.' ?
   1154 			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
   1155 			num;
   1156 	};
   1157 	
   1158 	
   1159 	var _isNumber = function ( d, decimalPoint, formatted ) {
   1160 		var type = typeof d;
   1161 		var strType = type === 'string';
   1162 	
   1163 		if ( type === 'number' || type === 'bigint') {
   1164 			return true;
   1165 		}
   1166 	
   1167 		// If empty return immediately so there must be a number if it is a
   1168 		// formatted string (this stops the string "k", or "kr", etc being detected
   1169 		// as a formatted number for currency
   1170 		if ( _empty( d ) ) {
   1171 			return true;
   1172 		}
   1173 	
   1174 		if ( decimalPoint && strType ) {
   1175 			d = _numToDecimal( d, decimalPoint );
   1176 		}
   1177 	
   1178 		if ( formatted && strType ) {
   1179 			d = d.replace( _re_formatted_numeric, '' );
   1180 		}
   1181 	
   1182 		return !isNaN( parseFloat(d) ) && isFinite( d );
   1183 	};
   1184 	
   1185 	
   1186 	// A string without HTML in it can be considered to be HTML still
   1187 	var _isHtml = function ( d ) {
   1188 		return _empty( d ) || typeof d === 'string';
   1189 	};
   1190 	
   1191 	// Is a string a number surrounded by HTML?
   1192 	var _htmlNumeric = function ( d, decimalPoint, formatted ) {
   1193 		if ( _empty( d ) ) {
   1194 			return true;
   1195 		}
   1196 	
   1197 		// input and select strings mean that this isn't just a number
   1198 		if (typeof d === 'string' && d.match(/<(input|select)/i)) {
   1199 			return null;
   1200 		}
   1201 	
   1202 		var html = _isHtml( d );
   1203 		return ! html ?
   1204 			null :
   1205 			_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
   1206 				true :
   1207 				null;
   1208 	};
   1209 	
   1210 	
   1211 	var _pluck = function ( a, prop, prop2 ) {
   1212 		var out = [];
   1213 		var i=0, ien=a.length;
   1214 	
   1215 		// Could have the test in the loop for slightly smaller code, but speed
   1216 		// is essential here
   1217 		if ( prop2 !== undefined ) {
   1218 			for ( ; i<ien ; i++ ) {
   1219 				if ( a[i] && a[i][ prop ] ) {
   1220 					out.push( a[i][ prop ][ prop2 ] );
   1221 				}
   1222 			}
   1223 		}
   1224 		else {
   1225 			for ( ; i<ien ; i++ ) {
   1226 				if ( a[i] ) {
   1227 					out.push( a[i][ prop ] );
   1228 				}
   1229 			}
   1230 		}
   1231 	
   1232 		return out;
   1233 	};
   1234 	
   1235 	
   1236 	// Basically the same as _pluck, but rather than looping over `a` we use `order`
   1237 	// as the indexes to pick from `a`
   1238 	var _pluck_order = function ( a, order, prop, prop2 )
   1239 	{
   1240 		var out = [];
   1241 		var i=0, ien=order.length;
   1242 	
   1243 		// Could have the test in the loop for slightly smaller code, but speed
   1244 		// is essential here
   1245 		if ( prop2 !== undefined ) {
   1246 			for ( ; i<ien ; i++ ) {
   1247 				if ( a[ order[i] ][ prop ] ) {
   1248 					out.push( a[ order[i] ][ prop ][ prop2 ] );
   1249 				}
   1250 			}
   1251 		}
   1252 		else {
   1253 			for ( ; i<ien ; i++ ) {
   1254 				if ( a[ order[i] ] ) {
   1255 					out.push( a[ order[i] ][ prop ] );
   1256 				}
   1257 			}
   1258 		}
   1259 	
   1260 		return out;
   1261 	};
   1262 	
   1263 	
   1264 	var _range = function ( len, start )
   1265 	{
   1266 		var out = [];
   1267 		var end;
   1268 	
   1269 		if ( start === undefined ) {
   1270 			start = 0;
   1271 			end = len;
   1272 		}
   1273 		else {
   1274 			end = start;
   1275 			start = len;
   1276 		}
   1277 	
   1278 		for ( var i=start ; i<end ; i++ ) {
   1279 			out.push( i );
   1280 		}
   1281 	
   1282 		return out;
   1283 	};
   1284 	
   1285 	
   1286 	var _removeEmpty = function ( a )
   1287 	{
   1288 		var out = [];
   1289 	
   1290 		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
   1291 			if ( a[i] ) { // careful - will remove all falsy values!
   1292 				out.push( a[i] );
   1293 			}
   1294 		}
   1295 	
   1296 		return out;
   1297 	};
   1298 	
   1299 	// Replaceable function in api.util
   1300 	var _stripHtml = function (input) {
   1301 		// Irrelevant check to workaround CodeQL's false positive on the regex
   1302 		if (input.length > _max_str_len) {
   1303 			throw new Error('Exceeded max str len');
   1304 		}
   1305 	
   1306 		var previous;
   1307 	
   1308 		input = input.replace(_re_html, ''); // Complete tags
   1309 	
   1310 		// Safety for incomplete script tag - use do / while to ensure that
   1311 		// we get all instances
   1312 		do {
   1313 			previous = input;
   1314 			input = input.replace(/<script/i, '');
   1315 		} while (input !== previous);
   1316 	
   1317 		return previous;
   1318 	};
   1319 	
   1320 	// Replaceable function in api.util
   1321 	var _escapeHtml = function ( d ) {
   1322 		if (Array.isArray(d)) {
   1323 			d = d.join(',');
   1324 		}
   1325 	
   1326 		return typeof d === 'string' ?
   1327 			d
   1328 				.replace(/&/g, '&amp;')
   1329 				.replace(/</g, '&lt;')
   1330 				.replace(/>/g, '&gt;')
   1331 				.replace(/"/g, '&quot;') :
   1332 			d;
   1333 	};
   1334 	
   1335 	// Remove diacritics from a string by decomposing it and then removing
   1336 	// non-ascii characters
   1337 	var _normalize = function (str, both) {
   1338 		if (typeof str !== 'string') {
   1339 			return str;
   1340 		}
   1341 	
   1342 		// It is faster to just run `normalize` than it is to check if
   1343 		// we need to with a regex!
   1344 		var res = str.normalize("NFD");
   1345 	
   1346 		// Equally, here we check if a regex is needed or not
   1347 		return res.length !== str.length
   1348 			? (both === true ? str + ' ' : '' ) + res.replace(/[\u0300-\u036f]/g, "")
   1349 			: res;
   1350 	}
   1351 	
   1352 	/**
   1353 	 * Determine if all values in the array are unique. This means we can short
   1354 	 * cut the _unique method at the cost of a single loop. A sorted array is used
   1355 	 * to easily check the values.
   1356 	 *
   1357 	 * @param  {array} src Source array
   1358 	 * @return {boolean} true if all unique, false otherwise
   1359 	 * @ignore
   1360 	 */
   1361 	var _areAllUnique = function ( src ) {
   1362 		if ( src.length < 2 ) {
   1363 			return true;
   1364 		}
   1365 	
   1366 		var sorted = src.slice().sort();
   1367 		var last = sorted[0];
   1368 	
   1369 		for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
   1370 			if ( sorted[i] === last ) {
   1371 				return false;
   1372 			}
   1373 	
   1374 			last = sorted[i];
   1375 		}
   1376 	
   1377 		return true;
   1378 	};
   1379 	
   1380 	
   1381 	/**
   1382 	 * Find the unique elements in a source array.
   1383 	 *
   1384 	 * @param  {array} src Source array
   1385 	 * @return {array} Array of unique items
   1386 	 * @ignore
   1387 	 */
   1388 	var _unique = function ( src )
   1389 	{
   1390 		if (Array.from && Set) {
   1391 			return Array.from(new Set(src));
   1392 		}
   1393 	
   1394 		if ( _areAllUnique( src ) ) {
   1395 			return src.slice();
   1396 		}
   1397 	
   1398 		// A faster unique method is to use object keys to identify used values,
   1399 		// but this doesn't work with arrays or objects, which we must also
   1400 		// consider. See jsperf.app/compare-array-unique-versions/4 for more
   1401 		// information.
   1402 		var
   1403 			out = [],
   1404 			val,
   1405 			i, ien=src.length,
   1406 			j, k=0;
   1407 	
   1408 		again: for ( i=0 ; i<ien ; i++ ) {
   1409 			val = src[i];
   1410 	
   1411 			for ( j=0 ; j<k ; j++ ) {
   1412 				if ( out[j] === val ) {
   1413 					continue again;
   1414 				}
   1415 			}
   1416 	
   1417 			out.push( val );
   1418 			k++;
   1419 		}
   1420 	
   1421 		return out;
   1422 	};
   1423 	
   1424 	// Surprisingly this is faster than [].concat.apply
   1425 	// https://jsperf.com/flatten-an-array-loop-vs-reduce/2
   1426 	var _flatten = function (out, val) {
   1427 		if (Array.isArray(val)) {
   1428 			for (var i=0 ; i<val.length ; i++) {
   1429 				_flatten(out, val[i]);
   1430 			}
   1431 		}
   1432 		else {
   1433 			out.push(val);
   1434 		}
   1435 	
   1436 		return out;
   1437 	}
   1438 	
   1439 	// Similar to jQuery's addClass, but use classList.add
   1440 	function _addClass(el, name) {
   1441 		if (name) {
   1442 			name.split(' ').forEach(function (n) {
   1443 				if (n) {
   1444 					// `add` does deduplication, so no need to check `contains`
   1445 					el.classList.add(n);
   1446 				}
   1447 			});
   1448 		}
   1449 	}
   1450 	
   1451 	/**
   1452 	 * DataTables utility methods
   1453 	 * 
   1454 	 * This namespace provides helper methods that DataTables uses internally to
   1455 	 * create a DataTable, but which are not exclusively used only for DataTables.
   1456 	 * These methods can be used by extension authors to save the duplication of
   1457 	 * code.
   1458 	 *
   1459 	 *  @namespace
   1460 	 */
   1461 	DataTable.util = {
   1462 		/**
   1463 		 * Return a string with diacritic characters decomposed
   1464 		 * @param {*} mixed Function or string to normalize
   1465 		 * @param {*} both Return original string and the normalized string
   1466 		 * @returns String or undefined
   1467 		 */
   1468 		diacritics: function (mixed, both) {
   1469 			var type = typeof mixed;
   1470 	
   1471 			if (type !== 'function') {
   1472 				return _normalize(mixed, both);
   1473 			}
   1474 			_normalize = mixed;
   1475 		},
   1476 	
   1477 		/**
   1478 		 * Debounce a function
   1479 		 *
   1480 		 * @param {function} fn Function to be called
   1481 		 * @param {integer} freq Call frequency in mS
   1482 		 * @return {function} Wrapped function
   1483 		 */
   1484 		debounce: function ( fn, timeout ) {
   1485 			var timer;
   1486 	
   1487 			return function () {
   1488 				var that = this;
   1489 				var args = arguments;
   1490 	
   1491 				clearTimeout(timer);
   1492 	
   1493 				timer = setTimeout( function () {
   1494 					fn.apply(that, args);
   1495 				}, timeout || 250 );
   1496 			};
   1497 		},
   1498 	
   1499 		/**
   1500 		 * Throttle the calls to a function. Arguments and context are maintained
   1501 		 * for the throttled function.
   1502 		 *
   1503 		 * @param {function} fn Function to be called
   1504 		 * @param {integer} freq Call frequency in mS
   1505 		 * @return {function} Wrapped function
   1506 		 */
   1507 		throttle: function ( fn, freq ) {
   1508 			var
   1509 				frequency = freq !== undefined ? freq : 200,
   1510 				last,
   1511 				timer;
   1512 	
   1513 			return function () {
   1514 				var
   1515 					that = this,
   1516 					now  = +new Date(),
   1517 					args = arguments;
   1518 	
   1519 				if ( last && now < last + frequency ) {
   1520 					clearTimeout( timer );
   1521 	
   1522 					timer = setTimeout( function () {
   1523 						last = undefined;
   1524 						fn.apply( that, args );
   1525 					}, frequency );
   1526 				}
   1527 				else {
   1528 					last = now;
   1529 					fn.apply( that, args );
   1530 				}
   1531 			};
   1532 		},
   1533 	
   1534 		/**
   1535 		 * Escape a string such that it can be used in a regular expression
   1536 		 *
   1537 		 *  @param {string} val string to escape
   1538 		 *  @returns {string} escaped string
   1539 		 */
   1540 		escapeRegex: function ( val ) {
   1541 			return val.replace( _re_escape_regex, '\\$1' );
   1542 		},
   1543 	
   1544 		/**
   1545 		 * Create a function that will write to a nested object or array
   1546 		 * @param {*} source JSON notation string
   1547 		 * @returns Write function
   1548 		 */
   1549 		set: function ( source ) {
   1550 			if ( $.isPlainObject( source ) ) {
   1551 				/* Unlike get, only the underscore (global) option is used for for
   1552 				 * setting data since we don't know the type here. This is why an object
   1553 				 * option is not documented for `mData` (which is read/write), but it is
   1554 				 * for `mRender` which is read only.
   1555 				 */
   1556 				return DataTable.util.set( source._ );
   1557 			}
   1558 			else if ( source === null ) {
   1559 				// Nothing to do when the data source is null
   1560 				return function () {};
   1561 			}
   1562 			else if ( typeof source === 'function' ) {
   1563 				return function (data, val, meta) {
   1564 					source( data, 'set', val, meta );
   1565 				};
   1566 			}
   1567 			else if (
   1568 				typeof source === 'string' && (source.indexOf('.') !== -1 ||
   1569 				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
   1570 			) {
   1571 				// Like the get, we need to get data from a nested object
   1572 				var setData = function (data, val, src) {
   1573 					var a = _fnSplitObjNotation( src ), b;
   1574 					var aLast = a[a.length-1];
   1575 					var arrayNotation, funcNotation, o, innerSrc;
   1576 		
   1577 					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {
   1578 						// Protect against prototype pollution
   1579 						if (a[i] === '__proto__' || a[i] === 'constructor') {
   1580 							throw new Error('Cannot set prototype values');
   1581 						}
   1582 		
   1583 						// Check if we are dealing with an array notation request
   1584 						arrayNotation = a[i].match(__reArray);
   1585 						funcNotation = a[i].match(__reFn);
   1586 		
   1587 						if ( arrayNotation ) {
   1588 							a[i] = a[i].replace(__reArray, '');
   1589 							data[ a[i] ] = [];
   1590 		
   1591 							// Get the remainder of the nested object to set so we can recurse
   1592 							b = a.slice();
   1593 							b.splice( 0, i+1 );
   1594 							innerSrc = b.join('.');
   1595 		
   1596 							// Traverse each entry in the array setting the properties requested
   1597 							if ( Array.isArray( val ) ) {
   1598 								for ( var j=0, jLen=val.length ; j<jLen ; j++ ) {
   1599 									o = {};
   1600 									setData( o, val[j], innerSrc );
   1601 									data[ a[i] ].push( o );
   1602 								}
   1603 							}
   1604 							else {
   1605 								// We've been asked to save data to an array, but it
   1606 								// isn't array data to be saved. Best that can be done
   1607 								// is to just save the value.
   1608 								data[ a[i] ] = val;
   1609 							}
   1610 		
   1611 							// The inner call to setData has already traversed through the remainder
   1612 							// of the source and has set the data, thus we can exit here
   1613 							return;
   1614 						}
   1615 						else if ( funcNotation ) {
   1616 							// Function call
   1617 							a[i] = a[i].replace(__reFn, '');
   1618 							data = data[ a[i] ]( val );
   1619 						}
   1620 		
   1621 						// If the nested object doesn't currently exist - since we are
   1622 						// trying to set the value - create it
   1623 						if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {
   1624 							data[ a[i] ] = {};
   1625 						}
   1626 						data = data[ a[i] ];
   1627 					}
   1628 		
   1629 					// Last item in the input - i.e, the actual set
   1630 					if ( aLast.match(__reFn ) ) {
   1631 						// Function call
   1632 						data = data[ aLast.replace(__reFn, '') ]( val );
   1633 					}
   1634 					else {
   1635 						// If array notation is used, we just want to strip it and use the property name
   1636 						// and assign the value. If it isn't used, then we get the result we want anyway
   1637 						data[ aLast.replace(__reArray, '') ] = val;
   1638 					}
   1639 				};
   1640 		
   1641 				return function (data, val) { // meta is also passed in, but not used
   1642 					return setData( data, val, source );
   1643 				};
   1644 			}
   1645 			else {
   1646 				// Array or flat object mapping
   1647 				return function (data, val) { // meta is also passed in, but not used
   1648 					data[source] = val;
   1649 				};
   1650 			}
   1651 		},
   1652 	
   1653 		/**
   1654 		 * Create a function that will read nested objects from arrays, based on JSON notation
   1655 		 * @param {*} source JSON notation string
   1656 		 * @returns Value read
   1657 		 */
   1658 		get: function ( source ) {
   1659 			if ( $.isPlainObject( source ) ) {
   1660 				// Build an object of get functions, and wrap them in a single call
   1661 				var o = {};
   1662 				$.each( source, function (key, val) {
   1663 					if ( val ) {
   1664 						o[key] = DataTable.util.get( val );
   1665 					}
   1666 				} );
   1667 		
   1668 				return function (data, type, row, meta) {
   1669 					var t = o[type] || o._;
   1670 					return t !== undefined ?
   1671 						t(data, type, row, meta) :
   1672 						data;
   1673 				};
   1674 			}
   1675 			else if ( source === null ) {
   1676 				// Give an empty string for rendering / sorting etc
   1677 				return function (data) { // type, row and meta also passed, but not used
   1678 					return data;
   1679 				};
   1680 			}
   1681 			else if ( typeof source === 'function' ) {
   1682 				return function (data, type, row, meta) {
   1683 					return source( data, type, row, meta );
   1684 				};
   1685 			}
   1686 			else if (
   1687 				typeof source === 'string' && (source.indexOf('.') !== -1 ||
   1688 				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
   1689 			) {
   1690 				/* If there is a . in the source string then the data source is in a
   1691 				 * nested object so we loop over the data for each level to get the next
   1692 				 * level down. On each loop we test for undefined, and if found immediately
   1693 				 * return. This allows entire objects to be missing and sDefaultContent to
   1694 				 * be used if defined, rather than throwing an error
   1695 				 */
   1696 				var fetchData = function (data, type, src) {
   1697 					var arrayNotation, funcNotation, out, innerSrc;
   1698 		
   1699 					if ( src !== "" ) {
   1700 						var a = _fnSplitObjNotation( src );
   1701 		
   1702 						for ( var i=0, iLen=a.length ; i<iLen ; i++ ) {
   1703 							// Check if we are dealing with special notation
   1704 							arrayNotation = a[i].match(__reArray);
   1705 							funcNotation = a[i].match(__reFn);
   1706 		
   1707 							if ( arrayNotation ) {
   1708 								// Array notation
   1709 								a[i] = a[i].replace(__reArray, '');
   1710 		
   1711 								// Condition allows simply [] to be passed in
   1712 								if ( a[i] !== "" ) {
   1713 									data = data[ a[i] ];
   1714 								}
   1715 								out = [];
   1716 		
   1717 								// Get the remainder of the nested object to get
   1718 								a.splice( 0, i+1 );
   1719 								innerSrc = a.join('.');
   1720 		
   1721 								// Traverse each entry in the array getting the properties requested
   1722 								if ( Array.isArray( data ) ) {
   1723 									for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
   1724 										out.push( fetchData( data[j], type, innerSrc ) );
   1725 									}
   1726 								}
   1727 		
   1728 								// If a string is given in between the array notation indicators, that
   1729 								// is used to join the strings together, otherwise an array is returned
   1730 								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
   1731 								data = (join==="") ? out : out.join(join);
   1732 		
   1733 								// The inner call to fetchData has already traversed through the remainder
   1734 								// of the source requested, so we exit from the loop
   1735 								break;
   1736 							}
   1737 							else if ( funcNotation ) {
   1738 								// Function call
   1739 								a[i] = a[i].replace(__reFn, '');
   1740 								data = data[ a[i] ]();
   1741 								continue;
   1742 							}
   1743 		
   1744 							if (data === null || data[ a[i] ] === null) {
   1745 								return null;
   1746 							}
   1747 							else if ( data === undefined || data[ a[i] ] === undefined ) {
   1748 								return undefined;
   1749 							}
   1750 	
   1751 							data = data[ a[i] ];
   1752 						}
   1753 					}
   1754 		
   1755 					return data;
   1756 				};
   1757 		
   1758 				return function (data, type) { // row and meta also passed, but not used
   1759 					return fetchData( data, type, source );
   1760 				};
   1761 			}
   1762 			else {
   1763 				// Array or flat object mapping
   1764 				return function (data) { // row and meta also passed, but not used
   1765 					return data[source];
   1766 				};
   1767 			}
   1768 		},
   1769 	
   1770 		stripHtml: function (mixed) {
   1771 			var type = typeof mixed;
   1772 	
   1773 			if (type === 'function') {
   1774 				_stripHtml = mixed;
   1775 				return;
   1776 			}
   1777 			else if (type === 'string') {
   1778 				return _stripHtml(mixed);
   1779 			}
   1780 			return mixed;
   1781 		},
   1782 	
   1783 		escapeHtml: function (mixed) {
   1784 			var type = typeof mixed;
   1785 	
   1786 			if (type === 'function') {
   1787 				_escapeHtml = mixed;
   1788 				return;
   1789 			}
   1790 			else if (type === 'string' || Array.isArray(mixed)) {
   1791 				return _escapeHtml(mixed);
   1792 			}
   1793 			return mixed;
   1794 		},
   1795 	
   1796 		unique: _unique
   1797 	};
   1798 	
   1799 	
   1800 	
   1801 	/**
   1802 	 * Create a mapping object that allows camel case parameters to be looked up
   1803 	 * for their Hungarian counterparts. The mapping is stored in a private
   1804 	 * parameter called `_hungarianMap` which can be accessed on the source object.
   1805 	 *  @param {object} o
   1806 	 *  @memberof DataTable#oApi
   1807 	 */
   1808 	function _fnHungarianMap ( o )
   1809 	{
   1810 		var
   1811 			hungarian = 'a aa ai ao as b fn i m o s ',
   1812 			match,
   1813 			newKey,
   1814 			map = {};
   1815 	
   1816 		$.each( o, function (key) {
   1817 			match = key.match(/^([^A-Z]+?)([A-Z])/);
   1818 	
   1819 			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
   1820 			{
   1821 				newKey = key.replace( match[0], match[2].toLowerCase() );
   1822 				map[ newKey ] = key;
   1823 	
   1824 				if ( match[1] === 'o' )
   1825 				{
   1826 					_fnHungarianMap( o[key] );
   1827 				}
   1828 			}
   1829 		} );
   1830 	
   1831 		o._hungarianMap = map;
   1832 	}
   1833 	
   1834 	
   1835 	/**
   1836 	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
   1837 	 * created by _fnHungarianMap.
   1838 	 *  @param {object} src The model object which holds all parameters that can be
   1839 	 *    mapped.
   1840 	 *  @param {object} user The object to convert from camel case to Hungarian.
   1841 	 *  @param {boolean} force When set to `true`, properties which already have a
   1842 	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
   1843 	 *    won't be.
   1844 	 *  @memberof DataTable#oApi
   1845 	 */
   1846 	function _fnCamelToHungarian ( src, user, force )
   1847 	{
   1848 		if ( ! src._hungarianMap ) {
   1849 			_fnHungarianMap( src );
   1850 		}
   1851 	
   1852 		var hungarianKey;
   1853 	
   1854 		$.each( user, function (key) {
   1855 			hungarianKey = src._hungarianMap[ key ];
   1856 	
   1857 			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
   1858 			{
   1859 				// For objects, we need to buzz down into the object to copy parameters
   1860 				if ( hungarianKey.charAt(0) === 'o' )
   1861 				{
   1862 					// Copy the camelCase options over to the hungarian
   1863 					if ( ! user[ hungarianKey ] ) {
   1864 						user[ hungarianKey ] = {};
   1865 					}
   1866 					$.extend( true, user[hungarianKey], user[key] );
   1867 	
   1868 					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
   1869 				}
   1870 				else {
   1871 					user[hungarianKey] = user[ key ];
   1872 				}
   1873 			}
   1874 		} );
   1875 	}
   1876 	
   1877 	/**
   1878 	 * Map one parameter onto another
   1879 	 *  @param {object} o Object to map
   1880 	 *  @param {*} knew The new parameter name
   1881 	 *  @param {*} old The old parameter name
   1882 	 */
   1883 	var _fnCompatMap = function ( o, knew, old ) {
   1884 		if ( o[ knew ] !== undefined ) {
   1885 			o[ old ] = o[ knew ];
   1886 		}
   1887 	};
   1888 	
   1889 	
   1890 	/**
   1891 	 * Provide backwards compatibility for the main DT options. Note that the new
   1892 	 * options are mapped onto the old parameters, so this is an external interface
   1893 	 * change only.
   1894 	 *  @param {object} init Object to map
   1895 	 */
   1896 	function _fnCompatOpts ( init )
   1897 	{
   1898 		_fnCompatMap( init, 'ordering',      'bSort' );
   1899 		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
   1900 		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
   1901 		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
   1902 		_fnCompatMap( init, 'order',         'aaSorting' );
   1903 		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
   1904 		_fnCompatMap( init, 'paging',        'bPaginate' );
   1905 		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
   1906 		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
   1907 		_fnCompatMap( init, 'searching',     'bFilter' );
   1908 	
   1909 		// Boolean initialisation of x-scrolling
   1910 		if ( typeof init.sScrollX === 'boolean' ) {
   1911 			init.sScrollX = init.sScrollX ? '100%' : '';
   1912 		}
   1913 		if ( typeof init.scrollX === 'boolean' ) {
   1914 			init.scrollX = init.scrollX ? '100%' : '';
   1915 		}
   1916 	
   1917 		// Column search objects are in an array, so it needs to be converted
   1918 		// element by element
   1919 		var searchCols = init.aoSearchCols;
   1920 	
   1921 		if ( searchCols ) {
   1922 			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
   1923 				if ( searchCols[i] ) {
   1924 					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
   1925 				}
   1926 			}
   1927 		}
   1928 	
   1929 		// Enable search delay if server-side processing is enabled
   1930 		if (init.serverSide && ! init.searchDelay) {
   1931 			init.searchDelay = 400;
   1932 		}
   1933 	}
   1934 	
   1935 	
   1936 	/**
   1937 	 * Provide backwards compatibility for column options. Note that the new options
   1938 	 * are mapped onto the old parameters, so this is an external interface change
   1939 	 * only.
   1940 	 *  @param {object} init Object to map
   1941 	 */
   1942 	function _fnCompatCols ( init )
   1943 	{
   1944 		_fnCompatMap( init, 'orderable',     'bSortable' );
   1945 		_fnCompatMap( init, 'orderData',     'aDataSort' );
   1946 		_fnCompatMap( init, 'orderSequence', 'asSorting' );
   1947 		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
   1948 	
   1949 		// orderData can be given as an integer
   1950 		var dataSort = init.aDataSort;
   1951 		if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {
   1952 			init.aDataSort = [ dataSort ];
   1953 		}
   1954 	}
   1955 	
   1956 	
   1957 	/**
   1958 	 * Browser feature detection for capabilities, quirks
   1959 	 *  @param {object} settings dataTables settings object
   1960 	 *  @memberof DataTable#oApi
   1961 	 */
   1962 	function _fnBrowserDetect( settings )
   1963 	{
   1964 		// We don't need to do this every time DataTables is constructed, the values
   1965 		// calculated are specific to the browser and OS configuration which we
   1966 		// don't expect to change between initialisations
   1967 		if ( ! DataTable.__browser ) {
   1968 			var browser = {};
   1969 			DataTable.__browser = browser;
   1970 	
   1971 			// Scrolling feature / quirks detection
   1972 			var n = $('<div/>')
   1973 				.css( {
   1974 					position: 'fixed',
   1975 					top: 0,
   1976 					left: -1 * window.pageXOffset, // allow for scrolling
   1977 					height: 1,
   1978 					width: 1,
   1979 					overflow: 'hidden'
   1980 				} )
   1981 				.append(
   1982 					$('<div/>')
   1983 						.css( {
   1984 							position: 'absolute',
   1985 							top: 1,
   1986 							left: 1,
   1987 							width: 100,
   1988 							overflow: 'scroll'
   1989 						} )
   1990 						.append(
   1991 							$('<div/>')
   1992 								.css( {
   1993 									width: '100%',
   1994 									height: 10
   1995 								} )
   1996 						)
   1997 				)
   1998 				.appendTo( 'body' );
   1999 	
   2000 			var outer = n.children();
   2001 			var inner = outer.children();
   2002 	
   2003 			// Get scrollbar width
   2004 			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
   2005 	
   2006 			// In rtl text layout, some browsers (most, but not all) will place the
   2007 			// scrollbar on the left, rather than the right.
   2008 			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
   2009 	
   2010 			n.remove();
   2011 		}
   2012 	
   2013 		$.extend( settings.oBrowser, DataTable.__browser );
   2014 		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
   2015 	}
   2016 	
   2017 	/**
   2018 	 * Add a column to the list used for the table with default values
   2019 	 *  @param {object} oSettings dataTables settings object
   2020 	 *  @memberof DataTable#oApi
   2021 	 */
   2022 	function _fnAddColumn( oSettings )
   2023 	{
   2024 		// Add column to aoColumns array
   2025 		var oDefaults = DataTable.defaults.column;
   2026 		var iCol = oSettings.aoColumns.length;
   2027 		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
   2028 			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
   2029 			"mData": oDefaults.mData ? oDefaults.mData : iCol,
   2030 			idx: iCol,
   2031 			searchFixed: {},
   2032 			colEl: $('<col>').attr('data-dt-column', iCol)
   2033 		} );
   2034 		oSettings.aoColumns.push( oCol );
   2035 	
   2036 		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
   2037 		// passed into extend can be undefined. This allows the user to give a default
   2038 		// with only some of the parameters defined, and also not give a default
   2039 		var searchCols = oSettings.aoPreSearchCols;
   2040 		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
   2041 	}
   2042 	
   2043 	
   2044 	/**
   2045 	 * Apply options for a column
   2046 	 *  @param {object} oSettings dataTables settings object
   2047 	 *  @param {int} iCol column index to consider
   2048 	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
   2049 	 *  @memberof DataTable#oApi
   2050 	 */
   2051 	function _fnColumnOptions( oSettings, iCol, oOptions )
   2052 	{
   2053 		var oCol = oSettings.aoColumns[ iCol ];
   2054 	
   2055 		/* User specified column options */
   2056 		if ( oOptions !== undefined && oOptions !== null )
   2057 		{
   2058 			// Backwards compatibility
   2059 			_fnCompatCols( oOptions );
   2060 	
   2061 			// Map camel case parameters to their Hungarian counterparts
   2062 			_fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
   2063 	
   2064 			/* Backwards compatibility for mDataProp */
   2065 			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
   2066 			{
   2067 				oOptions.mData = oOptions.mDataProp;
   2068 			}
   2069 	
   2070 			if ( oOptions.sType )
   2071 			{
   2072 				oCol._sManualType = oOptions.sType;
   2073 			}
   2074 		
   2075 			// `class` is a reserved word in Javascript, so we need to provide
   2076 			// the ability to use a valid name for the camel case input
   2077 			if ( oOptions.className && ! oOptions.sClass )
   2078 			{
   2079 				oOptions.sClass = oOptions.className;
   2080 			}
   2081 	
   2082 			var origClass = oCol.sClass;
   2083 	
   2084 			$.extend( oCol, oOptions );
   2085 			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
   2086 	
   2087 			// Merge class from previously defined classes with this one, rather than just
   2088 			// overwriting it in the extend above
   2089 			if (origClass !== oCol.sClass) {
   2090 				oCol.sClass = origClass + ' ' + oCol.sClass;
   2091 			}
   2092 	
   2093 			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
   2094 			 * priority if defined
   2095 			 */
   2096 			if ( oOptions.iDataSort !== undefined )
   2097 			{
   2098 				oCol.aDataSort = [ oOptions.iDataSort ];
   2099 			}
   2100 			_fnMap( oCol, oOptions, "aDataSort" );
   2101 		}
   2102 	
   2103 		/* Cache the data get and set functions for speed */
   2104 		var mDataSrc = oCol.mData;
   2105 		var mData = _fnGetObjectDataFn( mDataSrc );
   2106 	
   2107 		// The `render` option can be given as an array to access the helper rendering methods.
   2108 		// The first element is the rendering method to use, the rest are the parameters to pass
   2109 		if ( oCol.mRender && Array.isArray( oCol.mRender ) ) {
   2110 			var copy = oCol.mRender.slice();
   2111 			var name = copy.shift();
   2112 	
   2113 			oCol.mRender = DataTable.render[name].apply(window, copy);
   2114 		}
   2115 	
   2116 		oCol._render = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
   2117 	
   2118 		var attrTest = function( src ) {
   2119 			return typeof src === 'string' && src.indexOf('@') !== -1;
   2120 		};
   2121 		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
   2122 			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
   2123 		);
   2124 		oCol._setter = null;
   2125 	
   2126 		oCol.fnGetData = function (rowData, type, meta) {
   2127 			var innerData = mData( rowData, type, undefined, meta );
   2128 	
   2129 			return oCol._render && type ?
   2130 				oCol._render( innerData, type, rowData, meta ) :
   2131 				innerData;
   2132 		};
   2133 		oCol.fnSetData = function ( rowData, val, meta ) {
   2134 			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
   2135 		};
   2136 	
   2137 		// Indicate if DataTables should read DOM data as an object or array
   2138 		// Used in _fnGetRowElements
   2139 		if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) {
   2140 			oSettings._rowReadObject = true;
   2141 		}
   2142 	
   2143 		/* Feature sorting overrides column specific when off */
   2144 		if ( !oSettings.oFeatures.bSort )
   2145 		{
   2146 			oCol.bSortable = false;
   2147 		}
   2148 	}
   2149 	
   2150 	
   2151 	/**
   2152 	 * Adjust the table column widths for new data. Note: you would probably want to
   2153 	 * do a redraw after calling this function!
   2154 	 *  @param {object} settings dataTables settings object
   2155 	 *  @memberof DataTable#oApi
   2156 	 */
   2157 	function _fnAdjustColumnSizing ( settings )
   2158 	{
   2159 		_fnCalculateColumnWidths( settings );
   2160 		_fnColumnSizes( settings );
   2161 	
   2162 		var scroll = settings.oScroll;
   2163 		if ( scroll.sY !== '' || scroll.sX !== '') {
   2164 			_fnScrollDraw( settings );
   2165 		}
   2166 	
   2167 		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
   2168 	}
   2169 	
   2170 	/**
   2171 	 * Apply column sizes
   2172 	 *
   2173 	 * @param {*} settings DataTables settings object
   2174 	 */
   2175 	function _fnColumnSizes ( settings )
   2176 	{
   2177 		var cols = settings.aoColumns;
   2178 	
   2179 		for (var i=0 ; i<cols.length ; i++) {
   2180 			var width = _fnColumnsSumWidth(settings, [i], false, false);
   2181 	
   2182 			cols[i].colEl.css('width', width);
   2183 		}
   2184 	}
   2185 	
   2186 	
   2187 	/**
   2188 	 * Convert the index of a visible column to the index in the data array (take account
   2189 	 * of hidden columns)
   2190 	 *  @param {object} oSettings dataTables settings object
   2191 	 *  @param {int} iMatch Visible column index to lookup
   2192 	 *  @returns {int} i the data index
   2193 	 *  @memberof DataTable#oApi
   2194 	 */
   2195 	function _fnVisibleToColumnIndex( oSettings, iMatch )
   2196 	{
   2197 		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
   2198 	
   2199 		return typeof aiVis[iMatch] === 'number' ?
   2200 			aiVis[iMatch] :
   2201 			null;
   2202 	}
   2203 	
   2204 	
   2205 	/**
   2206 	 * Convert the index of an index in the data array and convert it to the visible
   2207 	 *   column index (take account of hidden columns)
   2208 	 *  @param {int} iMatch Column index to lookup
   2209 	 *  @param {object} oSettings dataTables settings object
   2210 	 *  @returns {int} i the data index
   2211 	 *  @memberof DataTable#oApi
   2212 	 */
   2213 	function _fnColumnIndexToVisible( oSettings, iMatch )
   2214 	{
   2215 		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
   2216 		var iPos = aiVis.indexOf(iMatch);
   2217 	
   2218 		return iPos !== -1 ? iPos : null;
   2219 	}
   2220 	
   2221 	
   2222 	/**
   2223 	 * Get the number of visible columns
   2224 	 *  @param {object} oSettings dataTables settings object
   2225 	 *  @returns {int} i the number of visible columns
   2226 	 *  @memberof DataTable#oApi
   2227 	 */
   2228 	function _fnVisbleColumns( settings )
   2229 	{
   2230 		var layout = settings.aoHeader;
   2231 		var columns = settings.aoColumns;
   2232 		var vis = 0;
   2233 	
   2234 		if ( layout.length ) {
   2235 			for ( var i=0, ien=layout[0].length ; i<ien ; i++ ) {
   2236 				if ( columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none' ) {
   2237 					vis++;
   2238 				}
   2239 			}
   2240 		}
   2241 	
   2242 		return vis;
   2243 	}
   2244 	
   2245 	
   2246 	/**
   2247 	 * Get an array of column indexes that match a given property
   2248 	 *  @param {object} oSettings dataTables settings object
   2249 	 *  @param {string} sParam Parameter in aoColumns to look for - typically
   2250 	 *    bVisible or bSearchable
   2251 	 *  @returns {array} Array of indexes with matched properties
   2252 	 *  @memberof DataTable#oApi
   2253 	 */
   2254 	function _fnGetColumns( oSettings, sParam )
   2255 	{
   2256 		var a = [];
   2257 	
   2258 		oSettings.aoColumns.map( function(val, i) {
   2259 			if ( val[sParam] ) {
   2260 				a.push( i );
   2261 			}
   2262 		} );
   2263 	
   2264 		return a;
   2265 	}
   2266 	
   2267 	
   2268 	/**
   2269 	 * Calculate the 'type' of a column
   2270 	 *  @param {object} settings dataTables settings object
   2271 	 *  @memberof DataTable#oApi
   2272 	 */
   2273 	function _fnColumnTypes ( settings )
   2274 	{
   2275 		var columns = settings.aoColumns;
   2276 		var data = settings.aoData;
   2277 		var types = DataTable.ext.type.detect;
   2278 		var i, ien, j, jen, k, ken;
   2279 		var col, detectedType, cache;
   2280 	
   2281 		// For each column, spin over the 
   2282 		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
   2283 			col = columns[i];
   2284 			cache = [];
   2285 	
   2286 			if ( ! col.sType && col._sManualType ) {
   2287 				col.sType = col._sManualType;
   2288 			}
   2289 			else if ( ! col.sType ) {
   2290 				for ( j=0, jen=types.length ; j<jen ; j++ ) {
   2291 					for ( k=0, ken=data.length ; k<ken ; k++ ) {
   2292 	
   2293 						if (! data[k]) {
   2294 							continue;
   2295 						}
   2296 	
   2297 						// Use a cache array so we only need to get the type data
   2298 						// from the formatter once (when using multiple detectors)
   2299 						if ( cache[k] === undefined ) {
   2300 							cache[k] = _fnGetCellData( settings, k, i, 'type' );
   2301 						}
   2302 	
   2303 						detectedType = types[j]( cache[k], settings );
   2304 	
   2305 						// If null, then this type can't apply to this column, so
   2306 						// rather than testing all cells, break out. There is an
   2307 						// exception for the last type which is `html`. We need to
   2308 						// scan all rows since it is possible to mix string and HTML
   2309 						// types
   2310 						if ( ! detectedType && j !== types.length-2 ) {
   2311 							break;
   2312 						}
   2313 	
   2314 						// Only a single match is needed for html type since it is
   2315 						// bottom of the pile and very similar to string - but it
   2316 						// must not be empty
   2317 						if ( detectedType === 'html' && ! _empty(cache[k]) ) {
   2318 							break;
   2319 						}
   2320 					}
   2321 	
   2322 					// Type is valid for all data points in the column - use this
   2323 					// type
   2324 					if ( detectedType ) {
   2325 						col.sType = detectedType;
   2326 						break;
   2327 					}
   2328 				}
   2329 	
   2330 				// Fall back - if no type was detected, always use string
   2331 				if ( ! col.sType ) {
   2332 					col.sType = 'string';
   2333 				}
   2334 			}
   2335 	
   2336 			// Set class names for header / footer for auto type classes
   2337 			var autoClass = _ext.type.className[col.sType];
   2338 	
   2339 			if (autoClass) {
   2340 				_columnAutoClass(settings.aoHeader, i, autoClass);
   2341 				_columnAutoClass(settings.aoFooter, i, autoClass);
   2342 			}
   2343 	
   2344 			var renderer = _ext.type.render[col.sType];
   2345 	
   2346 			// This can only happen once! There is no way to remover
   2347 			// a renderer. After the first time the renderer has
   2348 			// already been set so createTr will run the renderer itself.
   2349 			if (renderer && ! col._render) {
   2350 				col._render = DataTable.util.get(renderer);
   2351 	
   2352 				_columnAutoRender(settings, i);
   2353 			}
   2354 		}
   2355 	}
   2356 	
   2357 	/**
   2358 	 * Apply an auto detected renderer to data which doesn't yet have
   2359 	 * a renderer
   2360 	 */
   2361 	function _columnAutoRender(settings, colIdx) {
   2362 		var data = settings.aoData;
   2363 	
   2364 		for (var i=0 ; i<data.length ; i++) {
   2365 			if (data[i].nTr) {
   2366 				// We have to update the display here since there is no
   2367 				// invalidation check for the data
   2368 				var display = _fnGetCellData( settings, i, colIdx, 'display' );
   2369 	
   2370 				data[i].displayData[colIdx] = display;
   2371 				_fnWriteCell(data[i].anCells[colIdx], display);
   2372 	
   2373 				// No need to update sort / filter data since it has
   2374 				// been invalidated and will be re-read with the
   2375 				// renderer now applied
   2376 			}
   2377 		}
   2378 	}
   2379 	
   2380 	/**
   2381 	 * Apply a class name to a column's header cells
   2382 	 */
   2383 	function _columnAutoClass(container, colIdx, className) {
   2384 		container.forEach(function (row) {
   2385 			if (row[colIdx] && row[colIdx].unique) {
   2386 				_addClass(row[colIdx].cell, className);
   2387 			}
   2388 		});
   2389 	}
   2390 	
   2391 	/**
   2392 	 * Take the column definitions and static columns arrays and calculate how
   2393 	 * they relate to column indexes. The callback function will then apply the
   2394 	 * definition found for a column to a suitable configuration object.
   2395 	 *  @param {object} oSettings dataTables settings object
   2396 	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
   2397 	 *  @param {array} aoCols The aoColumns array that defines columns individually
   2398 	 *  @param {array} headerLayout Layout for header as it was loaded
   2399 	 *  @param {function} fn Callback function - takes two parameters, the calculated
   2400 	 *    column index and the definition for that column.
   2401 	 *  @memberof DataTable#oApi
   2402 	 */
   2403 	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, headerLayout, fn )
   2404 	{
   2405 		var i, iLen, j, jLen, k, kLen, def;
   2406 		var columns = oSettings.aoColumns;
   2407 	
   2408 		if ( aoCols ) {
   2409 			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
   2410 				if (aoCols[i] && aoCols[i].name) {
   2411 					columns[i].sName = aoCols[i].name;
   2412 				}
   2413 			}
   2414 		}
   2415 	
   2416 		// Column definitions with aTargets
   2417 		if ( aoColDefs )
   2418 		{
   2419 			/* Loop over the definitions array - loop in reverse so first instance has priority */
   2420 			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
   2421 			{
   2422 				def = aoColDefs[i];
   2423 	
   2424 				/* Each definition can target multiple columns, as it is an array */
   2425 				var aTargets = def.target !== undefined
   2426 					? def.target
   2427 					: def.targets !== undefined
   2428 						? def.targets
   2429 						: def.aTargets;
   2430 	
   2431 				if ( ! Array.isArray( aTargets ) )
   2432 				{
   2433 					aTargets = [ aTargets ];
   2434 				}
   2435 	
   2436 				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
   2437 				{
   2438 					var target = aTargets[j];
   2439 	
   2440 					if ( typeof target === 'number' && target >= 0 )
   2441 					{
   2442 						/* Add columns that we don't yet know about */
   2443 						while( columns.length <= target )
   2444 						{
   2445 							_fnAddColumn( oSettings );
   2446 						}
   2447 	
   2448 						/* Integer, basic index */
   2449 						fn( target, def );
   2450 					}
   2451 					else if ( typeof target === 'number' && target < 0 )
   2452 					{
   2453 						/* Negative integer, right to left column counting */
   2454 						fn( columns.length+target, def );
   2455 					}
   2456 					else if ( typeof target === 'string' )
   2457 					{
   2458 						for ( k=0, kLen=columns.length ; k<kLen ; k++ ) {
   2459 							if (target === '_all') {
   2460 								// Apply to all columns
   2461 								fn( k, def );
   2462 							}
   2463 							else if (target.indexOf(':name') !== -1) {
   2464 								// Column selector
   2465 								if (columns[k].sName === target.replace(':name', '')) {
   2466 									fn( k, def );
   2467 								}
   2468 							}
   2469 							else {
   2470 								// Cell selector
   2471 								headerLayout.forEach(function (row) {
   2472 									if (row[k]) {
   2473 										var cell = $(row[k].cell);
   2474 	
   2475 										// Legacy support. Note that it means that we don't support
   2476 										// an element name selector only, since they are treated as
   2477 										// class names for 1.x compat.
   2478 										if (target.match(/^[a-z][\w-]*$/i)) {
   2479 											target = '.' + target;
   2480 										}
   2481 	
   2482 										if (cell.is( target )) {
   2483 											fn( k, def );
   2484 										}
   2485 									}
   2486 								});
   2487 							}
   2488 						}
   2489 					}
   2490 				}
   2491 			}
   2492 		}
   2493 	
   2494 		// Statically defined columns array
   2495 		if ( aoCols ) {
   2496 			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
   2497 				fn( i, aoCols[i] );
   2498 			}
   2499 		}
   2500 	}
   2501 	
   2502 	
   2503 	/**
   2504 	 * Get the width for a given set of columns
   2505 	 *
   2506 	 * @param {*} settings DataTables settings object
   2507 	 * @param {*} targets Columns - comma separated string or array of numbers
   2508 	 * @param {*} original Use the original width (true) or calculated (false)
   2509 	 * @param {*} incVisible Include visible columns (true) or not (false)
   2510 	 * @returns Combined CSS value
   2511 	 */
   2512 	function _fnColumnsSumWidth( settings, targets, original, incVisible ) {
   2513 		if ( ! Array.isArray( targets ) ) {
   2514 			targets = _fnColumnsFromHeader( targets );
   2515 		}
   2516 	
   2517 		var sum = 0;
   2518 		var unit;
   2519 		var columns = settings.aoColumns;
   2520 		
   2521 		for ( var i=0, ien=targets.length ; i<ien ; i++ ) {
   2522 			var column = columns[ targets[i] ];
   2523 			var definedWidth = original ?
   2524 				column.sWidthOrig :
   2525 				column.sWidth;
   2526 	
   2527 			if ( ! incVisible && column.bVisible === false ) {
   2528 				continue;
   2529 			}
   2530 	
   2531 			if ( definedWidth === null || definedWidth === undefined ) {
   2532 				return null; // can't determine a defined width - browser defined
   2533 			}
   2534 			else if ( typeof definedWidth === 'number' ) {
   2535 				unit = 'px';
   2536 				sum += definedWidth;
   2537 			}
   2538 			else {
   2539 				var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
   2540 	
   2541 				if ( matched ) {
   2542 					sum += matched[1] * 1;
   2543 					unit = matched.length === 3 ?
   2544 						matched[2] :
   2545 						'px';
   2546 				}
   2547 			}
   2548 		}
   2549 	
   2550 		return sum + unit;
   2551 	}
   2552 	
   2553 	function _fnColumnsFromHeader( cell )
   2554 	{
   2555 		var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
   2556 	
   2557 		if ( ! attr ) {
   2558 			return [];
   2559 		}
   2560 	
   2561 		return attr.split(',').map( function (val) {
   2562 			return val * 1;
   2563 		} );
   2564 	}
   2565 	/**
   2566 	 * Add a data array to the table, creating DOM node etc. This is the parallel to
   2567 	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
   2568 	 * DOM source.
   2569 	 *  @param {object} settings dataTables settings object
   2570 	 *  @param {array} data data array to be added
   2571 	 *  @param {node} [tr] TR element to add to the table - optional. If not given,
   2572 	 *    DataTables will create a row automatically
   2573 	 *  @param {array} [tds] Array of TD|TH elements for the row - must be given
   2574 	 *    if nTr is.
   2575 	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
   2576 	 *  @memberof DataTable#oApi
   2577 	 */
   2578 	function _fnAddData ( settings, dataIn, tr, tds )
   2579 	{
   2580 		/* Create the object for storing information about this new row */
   2581 		var rowIdx = settings.aoData.length;
   2582 		var rowModel = $.extend( true, {}, DataTable.models.oRow, {
   2583 			src: tr ? 'dom' : 'data',
   2584 			idx: rowIdx
   2585 		} );
   2586 	
   2587 		rowModel._aData = dataIn;
   2588 		settings.aoData.push( rowModel );
   2589 	
   2590 		var columns = settings.aoColumns;
   2591 	
   2592 		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
   2593 		{
   2594 			// Invalidate the column types as the new data needs to be revalidated
   2595 			columns[i].sType = null;
   2596 		}
   2597 	
   2598 		/* Add to the display array */
   2599 		settings.aiDisplayMaster.push( rowIdx );
   2600 	
   2601 		var id = settings.rowIdFn( dataIn );
   2602 		if ( id !== undefined ) {
   2603 			settings.aIds[ id ] = rowModel;
   2604 		}
   2605 	
   2606 		/* Create the DOM information, or register it if already present */
   2607 		if ( tr || ! settings.oFeatures.bDeferRender )
   2608 		{
   2609 			_fnCreateTr( settings, rowIdx, tr, tds );
   2610 		}
   2611 	
   2612 		return rowIdx;
   2613 	}
   2614 	
   2615 	
   2616 	/**
   2617 	 * Add one or more TR elements to the table. Generally we'd expect to
   2618 	 * use this for reading data from a DOM sourced table, but it could be
   2619 	 * used for an TR element. Note that if a TR is given, it is used (i.e.
   2620 	 * it is not cloned).
   2621 	 *  @param {object} settings dataTables settings object
   2622 	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
   2623 	 *  @returns {array} Array of indexes for the added rows
   2624 	 *  @memberof DataTable#oApi
   2625 	 */
   2626 	function _fnAddTr( settings, trs )
   2627 	{
   2628 		var row;
   2629 	
   2630 		// Allow an individual node to be passed in
   2631 		if ( ! (trs instanceof $) ) {
   2632 			trs = $(trs);
   2633 		}
   2634 	
   2635 		return trs.map( function (i, el) {
   2636 			row = _fnGetRowElements( settings, el );
   2637 			return _fnAddData( settings, row.data, el, row.cells );
   2638 		} );
   2639 	}
   2640 	
   2641 	
   2642 	/**
   2643 	 * Get the data for a given cell from the internal cache, taking into account data mapping
   2644 	 *  @param {object} settings dataTables settings object
   2645 	 *  @param {int} rowIdx aoData row id
   2646 	 *  @param {int} colIdx Column index
   2647 	 *  @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
   2648 	 *  @returns {*} Cell data
   2649 	 *  @memberof DataTable#oApi
   2650 	 */
   2651 	function _fnGetCellData( settings, rowIdx, colIdx, type )
   2652 	{
   2653 		if (type === 'search') {
   2654 			type = 'filter';
   2655 		}
   2656 		else if (type === 'order') {
   2657 			type = 'sort';
   2658 		}
   2659 	
   2660 		var row = settings.aoData[rowIdx];
   2661 	
   2662 		if (! row) {
   2663 			return undefined;
   2664 		}
   2665 	
   2666 		var draw           = settings.iDraw;
   2667 		var col            = settings.aoColumns[colIdx];
   2668 		var rowData        = row._aData;
   2669 		var defaultContent = col.sDefaultContent;
   2670 		var cellData       = col.fnGetData( rowData, type, {
   2671 			settings: settings,
   2672 			row:      rowIdx,
   2673 			col:      colIdx
   2674 		} );
   2675 	
   2676 		// Allow for a node being returned for non-display types
   2677 		if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
   2678 			cellData = cellData.innerHTML;
   2679 		}
   2680 	
   2681 		if ( cellData === undefined ) {
   2682 			if ( settings.iDrawError != draw && defaultContent === null ) {
   2683 				_fnLog( settings, 0, "Requested unknown parameter "+
   2684 					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
   2685 					" for row "+rowIdx+", column "+colIdx, 4 );
   2686 				settings.iDrawError = draw;
   2687 			}
   2688 			return defaultContent;
   2689 		}
   2690 	
   2691 		// When the data source is null and a specific data type is requested (i.e.
   2692 		// not the original data), we can use default column data
   2693 		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
   2694 			cellData = defaultContent;
   2695 		}
   2696 		else if ( typeof cellData === 'function' ) {
   2697 			// If the data source is a function, then we run it and use the return,
   2698 			// executing in the scope of the data object (for instances)
   2699 			return cellData.call( rowData );
   2700 		}
   2701 	
   2702 		if ( cellData === null && type === 'display' ) {
   2703 			return '';
   2704 		}
   2705 	
   2706 		if ( type === 'filter' ) {
   2707 			var fomatters = DataTable.ext.type.search;
   2708 	
   2709 			if ( fomatters[ col.sType ] ) {
   2710 				cellData = fomatters[ col.sType ]( cellData );
   2711 			}
   2712 		}
   2713 	
   2714 		return cellData;
   2715 	}
   2716 	
   2717 	
   2718 	/**
   2719 	 * Set the value for a specific cell, into the internal data cache
   2720 	 *  @param {object} settings dataTables settings object
   2721 	 *  @param {int} rowIdx aoData row id
   2722 	 *  @param {int} colIdx Column index
   2723 	 *  @param {*} val Value to set
   2724 	 *  @memberof DataTable#oApi
   2725 	 */
   2726 	function _fnSetCellData( settings, rowIdx, colIdx, val )
   2727 	{
   2728 		var col     = settings.aoColumns[colIdx];
   2729 		var rowData = settings.aoData[rowIdx]._aData;
   2730 	
   2731 		col.fnSetData( rowData, val, {
   2732 			settings: settings,
   2733 			row:      rowIdx,
   2734 			col:      colIdx
   2735 		}  );
   2736 	}
   2737 	
   2738 	/**
   2739 	 * Write a value to a cell
   2740 	 * @param {*} td Cell
   2741 	 * @param {*} val Value
   2742 	 */
   2743 	function _fnWriteCell(td, val)
   2744 	{
   2745 		if (val && typeof val === 'object' && val.nodeName) {
   2746 			$(td)
   2747 				.empty()
   2748 				.append(val);
   2749 		}
   2750 		else {
   2751 			td.innerHTML = val;
   2752 		}
   2753 	}
   2754 	
   2755 	
   2756 	// Private variable that is used to match action syntax in the data property object
   2757 	var __reArray = /\[.*?\]$/;
   2758 	var __reFn = /\(\)$/;
   2759 	
   2760 	/**
   2761 	 * Split string on periods, taking into account escaped periods
   2762 	 * @param  {string} str String to split
   2763 	 * @return {array} Split string
   2764 	 */
   2765 	function _fnSplitObjNotation( str )
   2766 	{
   2767 		var parts = str.match(/(\\.|[^.])+/g) || [''];
   2768 	
   2769 		return parts.map( function ( s ) {
   2770 			return s.replace(/\\\./g, '.');
   2771 		} );
   2772 	}
   2773 	
   2774 	
   2775 	/**
   2776 	 * Return a function that can be used to get data from a source object, taking
   2777 	 * into account the ability to use nested objects as a source
   2778 	 *  @param {string|int|function} mSource The data source for the object
   2779 	 *  @returns {function} Data get function
   2780 	 *  @memberof DataTable#oApi
   2781 	 */
   2782 	var _fnGetObjectDataFn = DataTable.util.get;
   2783 	
   2784 	
   2785 	/**
   2786 	 * Return a function that can be used to set data from a source object, taking
   2787 	 * into account the ability to use nested objects as a source
   2788 	 *  @param {string|int|function} mSource The data source for the object
   2789 	 *  @returns {function} Data set function
   2790 	 *  @memberof DataTable#oApi
   2791 	 */
   2792 	var _fnSetObjectDataFn = DataTable.util.set;
   2793 	
   2794 	
   2795 	/**
   2796 	 * Return an array with the full table data
   2797 	 *  @param {object} oSettings dataTables settings object
   2798 	 *  @returns array {array} aData Master data array
   2799 	 *  @memberof DataTable#oApi
   2800 	 */
   2801 	function _fnGetDataMaster ( settings )
   2802 	{
   2803 		return _pluck( settings.aoData, '_aData' );
   2804 	}
   2805 	
   2806 	
   2807 	/**
   2808 	 * Nuke the table
   2809 	 *  @param {object} oSettings dataTables settings object
   2810 	 *  @memberof DataTable#oApi
   2811 	 */
   2812 	function _fnClearTable( settings )
   2813 	{
   2814 		settings.aoData.length = 0;
   2815 		settings.aiDisplayMaster.length = 0;
   2816 		settings.aiDisplay.length = 0;
   2817 		settings.aIds = {};
   2818 	}
   2819 	
   2820 	
   2821 	/**
   2822 	 * Mark cached data as invalid such that a re-read of the data will occur when
   2823 	 * the cached data is next requested. Also update from the data source object.
   2824 	 *
   2825 	 * @param {object} settings DataTables settings object
   2826 	 * @param {int}    rowIdx   Row index to invalidate
   2827 	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
   2828 	 *     or 'data'
   2829 	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
   2830 	 *     row will be invalidated
   2831 	 * @memberof DataTable#oApi
   2832 	 *
   2833 	 * @todo For the modularisation of v1.11 this will need to become a callback, so
   2834 	 *   the sort and filter methods can subscribe to it. That will required
   2835 	 *   initialisation options for sorting, which is why it is not already baked in
   2836 	 */
   2837 	function _fnInvalidate( settings, rowIdx, src, colIdx )
   2838 	{
   2839 		var row = settings.aoData[ rowIdx ];
   2840 		var i, ien;
   2841 	
   2842 		// Remove the cached data for the row
   2843 		row._aSortData = null;
   2844 		row._aFilterData = null;
   2845 		row.displayData = null;
   2846 	
   2847 		// Are we reading last data from DOM or the data object?
   2848 		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
   2849 			// Read the data from the DOM
   2850 			row._aData = _fnGetRowElements(
   2851 					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
   2852 				)
   2853 				.data;
   2854 		}
   2855 		else {
   2856 			// Reading from data object, update the DOM
   2857 			var cells = row.anCells;
   2858 			var display = _fnGetRowDisplay(settings, rowIdx);
   2859 	
   2860 			if ( cells ) {
   2861 				if ( colIdx !== undefined ) {
   2862 					_fnWriteCell(cells[colIdx], display[colIdx]);
   2863 				}
   2864 				else {
   2865 					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
   2866 						_fnWriteCell(cells[i], display[i]);
   2867 					}
   2868 				}
   2869 			}
   2870 		}
   2871 	
   2872 		// Column specific invalidation
   2873 		var cols = settings.aoColumns;
   2874 		if ( colIdx !== undefined ) {
   2875 			// Type - the data might have changed
   2876 			cols[ colIdx ].sType = null;
   2877 	
   2878 			// Max length string. Its a fairly cheep recalculation, so not worth
   2879 			// something more complicated
   2880 			cols[ colIdx ].maxLenString = null;
   2881 		}
   2882 		else {
   2883 			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
   2884 				cols[i].sType = null;
   2885 				cols[i].maxLenString = null;
   2886 			}
   2887 	
   2888 			// Update DataTables special `DT_*` attributes for the row
   2889 			_fnRowAttributes( settings, row );
   2890 		}
   2891 	}
   2892 	
   2893 	
   2894 	/**
   2895 	 * Build a data source object from an HTML row, reading the contents of the
   2896 	 * cells that are in the row.
   2897 	 *
   2898 	 * @param {object} settings DataTables settings object
   2899 	 * @param {node|object} TR element from which to read data or existing row
   2900 	 *   object from which to re-read the data from the cells
   2901 	 * @param {int} [colIdx] Optional column index
   2902 	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
   2903 	 *   parameter should also be given and will be used to write the data into.
   2904 	 *   Only the column in question will be written
   2905 	 * @returns {object} Object with two parameters: `data` the data read, in
   2906 	 *   document order, and `cells` and array of nodes (they can be useful to the
   2907 	 *   caller, so rather than needing a second traversal to get them, just return
   2908 	 *   them from here).
   2909 	 * @memberof DataTable#oApi
   2910 	 */
   2911 	function _fnGetRowElements( settings, row, colIdx, d )
   2912 	{
   2913 		var
   2914 			tds = [],
   2915 			td = row.firstChild,
   2916 			name, col, i=0, contents,
   2917 			columns = settings.aoColumns,
   2918 			objectRead = settings._rowReadObject;
   2919 	
   2920 		// Allow the data object to be passed in, or construct
   2921 		d = d !== undefined ?
   2922 			d :
   2923 			objectRead ?
   2924 				{} :
   2925 				[];
   2926 	
   2927 		var attr = function ( str, td  ) {
   2928 			if ( typeof str === 'string' ) {
   2929 				var idx = str.indexOf('@');
   2930 	
   2931 				if ( idx !== -1 ) {
   2932 					var attr = str.substring( idx+1 );
   2933 					var setter = _fnSetObjectDataFn( str );
   2934 					setter( d, td.getAttribute( attr ) );
   2935 				}
   2936 			}
   2937 		};
   2938 	
   2939 		// Read data from a cell and store into the data object
   2940 		var cellProcess = function ( cell ) {
   2941 			if ( colIdx === undefined || colIdx === i ) {
   2942 				col = columns[i];
   2943 				contents = (cell.innerHTML).trim();
   2944 	
   2945 				if ( col && col._bAttrSrc ) {
   2946 					var setter = _fnSetObjectDataFn( col.mData._ );
   2947 					setter( d, contents );
   2948 	
   2949 					attr( col.mData.sort, cell );
   2950 					attr( col.mData.type, cell );
   2951 					attr( col.mData.filter, cell );
   2952 				}
   2953 				else {
   2954 					// Depending on the `data` option for the columns the data can
   2955 					// be read to either an object or an array.
   2956 					if ( objectRead ) {
   2957 						if ( ! col._setter ) {
   2958 							// Cache the setter function
   2959 							col._setter = _fnSetObjectDataFn( col.mData );
   2960 						}
   2961 						col._setter( d, contents );
   2962 					}
   2963 					else {
   2964 						d[i] = contents;
   2965 					}
   2966 				}
   2967 			}
   2968 	
   2969 			i++;
   2970 		};
   2971 	
   2972 		if ( td ) {
   2973 			// `tr` element was passed in
   2974 			while ( td ) {
   2975 				name = td.nodeName.toUpperCase();
   2976 	
   2977 				if ( name == "TD" || name == "TH" ) {
   2978 					cellProcess( td );
   2979 					tds.push( td );
   2980 				}
   2981 	
   2982 				td = td.nextSibling;
   2983 			}
   2984 		}
   2985 		else {
   2986 			// Existing row object passed in
   2987 			tds = row.anCells;
   2988 	
   2989 			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
   2990 				cellProcess( tds[j] );
   2991 			}
   2992 		}
   2993 	
   2994 		// Read the ID from the DOM if present
   2995 		var rowNode = row.firstChild ? row : row.nTr;
   2996 	
   2997 		if ( rowNode ) {
   2998 			var id = rowNode.getAttribute( 'id' );
   2999 	
   3000 			if ( id ) {
   3001 				_fnSetObjectDataFn( settings.rowId )( d, id );
   3002 			}
   3003 		}
   3004 	
   3005 		return {
   3006 			data: d,
   3007 			cells: tds
   3008 		};
   3009 	}
   3010 	
   3011 	/**
   3012 	 * Render and cache a row's display data for the columns, if required
   3013 	 * @returns 
   3014 	 */
   3015 	function _fnGetRowDisplay (settings, rowIdx) {
   3016 		let rowModal = settings.aoData[rowIdx];
   3017 		let columns = settings.aoColumns;
   3018 	
   3019 		if (! rowModal.displayData) {
   3020 			// Need to render and cache
   3021 			rowModal.displayData = [];
   3022 		
   3023 			for ( var colIdx=0, len=columns.length ; colIdx<len ; colIdx++ ) {
   3024 				rowModal.displayData.push(
   3025 					_fnGetCellData( settings, rowIdx, colIdx, 'display' )
   3026 				);
   3027 			}
   3028 		}
   3029 	
   3030 		return rowModal.displayData;
   3031 	}
   3032 	
   3033 	/**
   3034 	 * Create a new TR element (and it's TD children) for a row
   3035 	 *  @param {object} oSettings dataTables settings object
   3036 	 *  @param {int} iRow Row to consider
   3037 	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
   3038 	 *    DataTables will create a row automatically
   3039 	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
   3040 	 *    if nTr is.
   3041 	 *  @memberof DataTable#oApi
   3042 	 */
   3043 	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
   3044 	{
   3045 		var
   3046 			row = oSettings.aoData[iRow],
   3047 			rowData = row._aData,
   3048 			cells = [],
   3049 			nTr, nTd, oCol,
   3050 			i, iLen, create,
   3051 			trClass = oSettings.oClasses.tbody.row;
   3052 	
   3053 		if ( row.nTr === null )
   3054 		{
   3055 			nTr = nTrIn || document.createElement('tr');
   3056 	
   3057 			row.nTr = nTr;
   3058 			row.anCells = cells;
   3059 	
   3060 			_addClass(nTr, trClass);
   3061 	
   3062 			/* Use a private property on the node to allow reserve mapping from the node
   3063 			 * to the aoData array for fast look up
   3064 			 */
   3065 			nTr._DT_RowIndex = iRow;
   3066 	
   3067 			/* Special parameters can be given by the data source to be used on the row */
   3068 			_fnRowAttributes( oSettings, row );
   3069 	
   3070 			/* Process each column */
   3071 			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
   3072 			{
   3073 				oCol = oSettings.aoColumns[i];
   3074 				create = nTrIn && anTds[i] ? false : true;
   3075 	
   3076 				nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
   3077 	
   3078 				if (! nTd) {
   3079 					_fnLog( oSettings, 0, 'Incorrect column count', 18 );
   3080 				}
   3081 	
   3082 				nTd._DT_CellIndex = {
   3083 					row: iRow,
   3084 					column: i
   3085 				};
   3086 				
   3087 				cells.push( nTd );
   3088 				
   3089 				var display = _fnGetRowDisplay(oSettings, iRow);
   3090 	
   3091 				// Need to create the HTML if new, or if a rendering function is defined
   3092 				if (
   3093 					create ||
   3094 					(
   3095 						(oCol.mRender || oCol.mData !== i) &&
   3096 						(!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
   3097 					)
   3098 				) {
   3099 					_fnWriteCell(nTd, display[i]);
   3100 				}
   3101 	
   3102 				// Visibility - add or remove as required
   3103 				if ( oCol.bVisible && create )
   3104 				{
   3105 					nTr.appendChild( nTd );
   3106 				}
   3107 				else if ( ! oCol.bVisible && ! create )
   3108 				{
   3109 					nTd.parentNode.removeChild( nTd );
   3110 				}
   3111 	
   3112 				if ( oCol.fnCreatedCell )
   3113 				{
   3114 					oCol.fnCreatedCell.call( oSettings.oInstance,
   3115 						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
   3116 					);
   3117 				}
   3118 			}
   3119 	
   3120 			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells] );
   3121 		}
   3122 		else {
   3123 			_addClass(row.nTr, trClass);
   3124 		}
   3125 	}
   3126 	
   3127 	
   3128 	/**
   3129 	 * Add attributes to a row based on the special `DT_*` parameters in a data
   3130 	 * source object.
   3131 	 *  @param {object} settings DataTables settings object
   3132 	 *  @param {object} DataTables row object for the row to be modified
   3133 	 *  @memberof DataTable#oApi
   3134 	 */
   3135 	function _fnRowAttributes( settings, row )
   3136 	{
   3137 		var tr = row.nTr;
   3138 		var data = row._aData;
   3139 	
   3140 		if ( tr ) {
   3141 			var id = settings.rowIdFn( data );
   3142 	
   3143 			if ( id ) {
   3144 				tr.id = id;
   3145 			}
   3146 	
   3147 			if ( data.DT_RowClass ) {
   3148 				// Remove any classes added by DT_RowClass before
   3149 				var a = data.DT_RowClass.split(' ');
   3150 				row.__rowc = row.__rowc ?
   3151 					_unique( row.__rowc.concat( a ) ) :
   3152 					a;
   3153 	
   3154 				$(tr)
   3155 					.removeClass( row.__rowc.join(' ') )
   3156 					.addClass( data.DT_RowClass );
   3157 			}
   3158 	
   3159 			if ( data.DT_RowAttr ) {
   3160 				$(tr).attr( data.DT_RowAttr );
   3161 			}
   3162 	
   3163 			if ( data.DT_RowData ) {
   3164 				$(tr).data( data.DT_RowData );
   3165 			}
   3166 		}
   3167 	}
   3168 	
   3169 	
   3170 	/**
   3171 	 * Create the HTML header for the table
   3172 	 *  @param {object} oSettings dataTables settings object
   3173 	 *  @memberof DataTable#oApi
   3174 	 */
   3175 	function _fnBuildHead( settings, side )
   3176 	{
   3177 		var classes = settings.oClasses;
   3178 		var columns = settings.aoColumns;
   3179 		var i, ien, row;
   3180 		var target = side === 'header'
   3181 			? settings.nTHead
   3182 			: settings.nTFoot;
   3183 		var titleProp = side === 'header' ? 'sTitle' : side;
   3184 	
   3185 		// Footer might be defined
   3186 		if (! target) {
   3187 			return;
   3188 		}
   3189 	
   3190 		// If no cells yet and we have content for them, then create
   3191 		if (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) {
   3192 			row = $('tr', target);
   3193 	
   3194 			// Add a row if needed
   3195 			if (! row.length) {
   3196 				row = $('<tr/>').appendTo(target)
   3197 			}
   3198 	
   3199 			// Add the number of cells needed to make up to the number of columns
   3200 			if (row.length === 1) {
   3201 				var cells = $('td, th', row);
   3202 	
   3203 				for ( i=cells.length, ien=columns.length ; i<ien ; i++ ) {
   3204 					$('<th/>')
   3205 						.html( columns[i][titleProp] || '' )
   3206 						.appendTo( row );
   3207 				}
   3208 			}
   3209 		}
   3210 	
   3211 		var detected = _fnDetectHeader( settings, target, true );
   3212 	
   3213 		if (side === 'header') {
   3214 			settings.aoHeader = detected;
   3215 		}
   3216 		else {
   3217 			settings.aoFooter = detected;
   3218 		}
   3219 	
   3220 		// ARIA role for the rows
   3221 		$(target).children('tr').attr('role', 'row');
   3222 	
   3223 		// Every cell needs to be passed through the renderer
   3224 		$(target).children('tr').children('th, td')
   3225 			.each( function () {
   3226 				_fnRenderer( settings, side )(
   3227 					settings, $(this), classes
   3228 				);
   3229 			} );
   3230 	}
   3231 	
   3232 	/**
   3233 	 * Build a layout structure for a header or footer
   3234 	 *
   3235 	 * @param {*} settings DataTables settings
   3236 	 * @param {*} source Source layout array
   3237 	 * @param {*} incColumns What columns should be included
   3238 	 * @returns Layout array
   3239 	 */
   3240 	function _fnHeaderLayout( settings, source, incColumns )
   3241 	{
   3242 		var row, column, cell;
   3243 		var local = [];
   3244 		var structure = [];
   3245 		var columns = settings.aoColumns;
   3246 		var columnCount = columns.length;
   3247 		var rowspan, colspan;
   3248 	
   3249 		if ( ! source ) {
   3250 			return;
   3251 		}
   3252 	
   3253 		// Default is to work on only visible columns
   3254 		if ( ! incColumns ) {
   3255 			incColumns = _range(columnCount)
   3256 				.filter(function (idx) {
   3257 					return columns[idx].bVisible;
   3258 				});
   3259 		}
   3260 	
   3261 		// Make a copy of the master layout array, but with only the columns we want
   3262 		for ( row=0 ; row<source.length ; row++ ) {
   3263 			// Remove any columns we haven't selected
   3264 			local[row] = source[row].slice().filter(function (cell, i) {
   3265 				return incColumns.includes(i);
   3266 			});
   3267 	
   3268 			// Prep the structure array - it needs an element for each row
   3269 			structure.push( [] );
   3270 		}
   3271 	
   3272 		for ( row=0 ; row<local.length ; row++ ) {
   3273 			for ( column=0 ; column<local[row].length ; column++ ) {
   3274 				rowspan = 1;
   3275 				colspan = 1;
   3276 	
   3277 				// Check to see if there is already a cell (row/colspan) covering our target
   3278 				// insert point. If there is, then there is nothing to do.
   3279 				if ( structure[row][column] === undefined ) {
   3280 					cell = local[row][column].cell;
   3281 	
   3282 					// Expand for rowspan
   3283 					while (
   3284 						local[row+rowspan] !== undefined &&
   3285 						local[row][column].cell == local[row+rowspan][column].cell
   3286 					) {
   3287 						structure[row+rowspan][column] = null;
   3288 						rowspan++;
   3289 					}
   3290 	
   3291 					// And for colspan
   3292 					while (
   3293 						local[row][column+colspan] !== undefined &&
   3294 						local[row][column].cell == local[row][column+colspan].cell
   3295 					) {
   3296 						// Which also needs to go over rows
   3297 						for ( var k=0 ; k<rowspan ; k++ ) {
   3298 							structure[row+k][column+colspan] = null;
   3299 						}
   3300 	
   3301 						colspan++;
   3302 					}
   3303 	
   3304 					var titleSpan = $('span.dt-column-title', cell);
   3305 	
   3306 					structure[row][column] = {
   3307 						cell: cell,
   3308 						colspan: colspan,
   3309 						rowspan: rowspan,
   3310 						title: titleSpan.length
   3311 							? titleSpan.html()
   3312 							: $(cell).html()
   3313 					};
   3314 				}
   3315 			}
   3316 		}
   3317 	
   3318 		return structure;
   3319 	}
   3320 	
   3321 	
   3322 	/**
   3323 	 * Draw the header (or footer) element based on the column visibility states.
   3324 	 *
   3325 	 *  @param object oSettings dataTables settings object
   3326 	 *  @param array aoSource Layout array from _fnDetectHeader
   3327 	 *  @memberof DataTable#oApi
   3328 	 */
   3329 	function _fnDrawHead( settings, source )
   3330 	{
   3331 		var layout = _fnHeaderLayout(settings, source);
   3332 		var tr, n;
   3333 	
   3334 		for ( var row=0 ; row<source.length ; row++ ) {
   3335 			tr = source[row].row;
   3336 	
   3337 			// All cells are going to be replaced, so empty out the row
   3338 			// Can't use $().empty() as that kills event handlers
   3339 			if (tr) {
   3340 				while( (n = tr.firstChild) ) {
   3341 					tr.removeChild( n );
   3342 				}
   3343 			}
   3344 	
   3345 			for ( var column=0 ; column<layout[row].length ; column++ ) {
   3346 				var point = layout[row][column];
   3347 	
   3348 				if (point) {
   3349 					$(point.cell)
   3350 						.appendTo(tr)
   3351 						.attr('rowspan', point.rowspan)
   3352 						.attr('colspan', point.colspan);
   3353 				}
   3354 			}
   3355 		}
   3356 	}
   3357 	
   3358 	
   3359 	/**
   3360 	 * Insert the required TR nodes into the table for display
   3361 	 *  @param {object} oSettings dataTables settings object
   3362 	 *  @param ajaxComplete true after ajax call to complete rendering
   3363 	 *  @memberof DataTable#oApi
   3364 	 */
   3365 	function _fnDraw( oSettings, ajaxComplete )
   3366 	{
   3367 		// Allow for state saving and a custom start position
   3368 		_fnStart( oSettings );
   3369 	
   3370 		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
   3371 		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
   3372 		if ( aPreDraw.indexOf(false) !== -1 )
   3373 		{
   3374 			_fnProcessingDisplay( oSettings, false );
   3375 			return;
   3376 		}
   3377 	
   3378 		var anRows = [];
   3379 		var iRowCount = 0;
   3380 		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
   3381 		var aiDisplay = oSettings.aiDisplay;
   3382 		var iDisplayStart = oSettings._iDisplayStart;
   3383 		var iDisplayEnd = oSettings.fnDisplayEnd();
   3384 		var columns = oSettings.aoColumns;
   3385 		var body = $(oSettings.nTBody);
   3386 	
   3387 		oSettings.bDrawing = true;
   3388 	
   3389 		/* Server-side processing draw intercept */
   3390 		if ( !bServerSide )
   3391 		{
   3392 			oSettings.iDraw++;
   3393 		}
   3394 		else if ( !oSettings.bDestroying && !ajaxComplete)
   3395 		{
   3396 			// Show loading message for server-side processing
   3397 			if (oSettings.iDraw === 0) {
   3398 				body.empty().append(_emptyRow(oSettings));
   3399 			}
   3400 	
   3401 			_fnAjaxUpdate( oSettings );
   3402 			return;
   3403 		}
   3404 	
   3405 		if ( aiDisplay.length !== 0 )
   3406 		{
   3407 			var iStart = bServerSide ? 0 : iDisplayStart;
   3408 			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
   3409 	
   3410 			for ( var j=iStart ; j<iEnd ; j++ )
   3411 			{
   3412 				var iDataIndex = aiDisplay[j];
   3413 				var aoData = oSettings.aoData[ iDataIndex ];
   3414 				if ( aoData.nTr === null )
   3415 				{
   3416 					_fnCreateTr( oSettings, iDataIndex );
   3417 				}
   3418 	
   3419 				var nRow = aoData.nTr;
   3420 	
   3421 				// Add various classes as needed
   3422 				for (var i=0 ; i<columns.length ; i++) {
   3423 					var col = columns[i];
   3424 					var td = aoData.anCells[i];
   3425 	
   3426 					_addClass(td, _ext.type.className[col.sType]); // auto class
   3427 					_addClass(td, col.sClass); // column class
   3428 					_addClass(td, oSettings.oClasses.tbody.cell); // all cells
   3429 				}
   3430 	
   3431 				// Row callback functions - might want to manipulate the row
   3432 				// iRowCount and j are not currently documented. Are they at all
   3433 				// useful?
   3434 				_fnCallbackFire( oSettings, 'aoRowCallback', null,
   3435 					[nRow, aoData._aData, iRowCount, j, iDataIndex] );
   3436 	
   3437 				anRows.push( nRow );
   3438 				iRowCount++;
   3439 			}
   3440 		}
   3441 		else
   3442 		{
   3443 			anRows[ 0 ] = _emptyRow(oSettings);
   3444 		}
   3445 	
   3446 		/* Header and footer callbacks */
   3447 		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
   3448 			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
   3449 	
   3450 		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
   3451 			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
   3452 	
   3453 		// replaceChildren is faster, but only became widespread in 2020,
   3454 		// so a fall back in jQuery is provided for older browsers.
   3455 		if (body[0].replaceChildren) {
   3456 			body[0].replaceChildren.apply(body[0], anRows);
   3457 		}
   3458 		else {
   3459 			body.children().detach();
   3460 			body.append( $(anRows) );
   3461 		}
   3462 	
   3463 		// Empty table needs a specific class
   3464 		$(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
   3465 	
   3466 		/* Call all required callback functions for the end of a draw */
   3467 		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings], true );
   3468 	
   3469 		/* Draw is complete, sorting and filtering must be as well */
   3470 		oSettings.bSorted = false;
   3471 		oSettings.bFiltered = false;
   3472 		oSettings.bDrawing = false;
   3473 	}
   3474 	
   3475 	
   3476 	/**
   3477 	 * Redraw the table - taking account of the various features which are enabled
   3478 	 *  @param {object} oSettings dataTables settings object
   3479 	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
   3480 	 *    the paging is reset to the first page
   3481 	 *  @memberof DataTable#oApi
   3482 	 */
   3483 	function _fnReDraw( settings, holdPosition, recompute )
   3484 	{
   3485 		var
   3486 			features = settings.oFeatures,
   3487 			sort     = features.bSort,
   3488 			filter   = features.bFilter;
   3489 	
   3490 		if (recompute === undefined || recompute === true) {
   3491 			if ( sort ) {
   3492 				_fnSort( settings );
   3493 			}
   3494 	
   3495 			if ( filter ) {
   3496 				_fnFilterComplete( settings, settings.oPreviousSearch );
   3497 			}
   3498 			else {
   3499 				// No filtering, so we want to just use the display master
   3500 				settings.aiDisplay = settings.aiDisplayMaster.slice();
   3501 			}
   3502 		}
   3503 	
   3504 		if ( holdPosition !== true ) {
   3505 			settings._iDisplayStart = 0;
   3506 		}
   3507 	
   3508 		// Let any modules know about the draw hold position state (used by
   3509 		// scrolling internally)
   3510 		settings._drawHold = holdPosition;
   3511 	
   3512 		_fnDraw( settings );
   3513 	
   3514 		settings._drawHold = false;
   3515 	}
   3516 	
   3517 	
   3518 	/*
   3519 	 * Table is empty - create a row with an empty message in it
   3520 	 */
   3521 	function _emptyRow ( settings ) {
   3522 		var oLang = settings.oLanguage;
   3523 		var zero = oLang.sZeroRecords;
   3524 		var dataSrc = _fnDataSource( settings );
   3525 	
   3526 		if (
   3527 			(settings.iDraw < 1 && dataSrc === 'ssp') ||
   3528 			(settings.iDraw <= 1 && dataSrc === 'ajax')
   3529 		) {
   3530 			zero = oLang.sLoadingRecords;
   3531 		}
   3532 		else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
   3533 		{
   3534 			zero = oLang.sEmptyTable;
   3535 		}
   3536 	
   3537 		return $( '<tr/>' )
   3538 			.append( $('<td />', {
   3539 				'colSpan': _fnVisbleColumns( settings ),
   3540 				'class':   settings.oClasses.empty.row
   3541 			} ).html( zero ) )[0];
   3542 	}
   3543 	
   3544 	
   3545 	/**
   3546 	 * Convert a `layout` object given by a user to the object structure needed
   3547 	 * for the renderer. This is done twice, once for above and once for below
   3548 	 * the table. Ordering must also be considered.
   3549 	 *
   3550 	 * @param {*} settings DataTables settings object
   3551 	 * @param {*} layout Layout object to convert
   3552 	 * @param {string} side `top` or `bottom`
   3553 	 * @returns Converted array structure - one item for each row.
   3554 	 */
   3555 	function _layoutArray ( settings, layout, side )
   3556 	{
   3557 		var groups = {};
   3558 	
   3559 		// Combine into like groups (e.g. `top`, `top2`, etc)
   3560 		$.each( layout, function ( pos, val ) {
   3561 			if (val === null) {
   3562 				return;
   3563 			}
   3564 	
   3565 			var splitPos = pos.replace(/([A-Z])/g, ' $1').split(' ');
   3566 	
   3567 			if ( ! groups[ splitPos[0] ] ) {
   3568 				groups[ splitPos[0] ] = {};
   3569 			}
   3570 	
   3571 			var align = splitPos.length === 1 ?
   3572 				'full' :
   3573 				splitPos[1].toLowerCase();
   3574 			var group = groups[ splitPos[0] ];
   3575 			var groupRun = function (contents, innerVal) {
   3576 				// If it is an object, then there can be multiple features contained in it
   3577 				if ( $.isPlainObject( innerVal ) ) {
   3578 					Object.keys(innerVal).map(function (key) {
   3579 						contents.push( {
   3580 							feature: key,
   3581 							opts: innerVal[key]
   3582 						});
   3583 					});
   3584 				}
   3585 				else {
   3586 					contents.push(innerVal);
   3587 				}
   3588 			}
   3589 	
   3590 			// Transform to an object with a contents property
   3591 			if (! group[align] || ! group[align].contents) {
   3592 				group[align] = { contents: [] };
   3593 			}
   3594 	
   3595 			// Allow for an array or just a single object
   3596 			if ( Array.isArray(val)) {
   3597 				for (var i=0 ; i<val.length ; i++) {
   3598 					groupRun(group[align].contents, val[i]);
   3599 				}
   3600 			}
   3601 			else {
   3602 				groupRun(group[ align ].contents, val);
   3603 			}
   3604 	
   3605 			// And make contents an array
   3606 			if ( ! Array.isArray( group[ align ].contents ) ) {
   3607 				group[ align ].contents = [ group[ align ].contents ];
   3608 			}
   3609 		} );
   3610 	
   3611 		var filtered = Object.keys(groups)
   3612 			.map( function ( pos ) {
   3613 				// Filter to only the side we need
   3614 				if ( pos.indexOf(side) !== 0 ) {
   3615 					return null;
   3616 				}
   3617 	
   3618 				return {
   3619 					name: pos,
   3620 					val: groups[pos]
   3621 				};
   3622 			} )
   3623 			.filter( function (item) {
   3624 				return item !== null;
   3625 			});
   3626 	
   3627 		// Order by item identifier
   3628 		filtered.sort( function ( a, b ) {
   3629 			var order1 = a.name.replace(/[^0-9]/g, '') * 1;
   3630 			var order2 = b.name.replace(/[^0-9]/g, '') * 1;
   3631 	
   3632 			return order2 - order1;
   3633 		} );
   3634 		
   3635 		if ( side === 'bottom' ) {
   3636 			filtered.reverse();
   3637 		}
   3638 	
   3639 		// Split into rows
   3640 		var rows = [];
   3641 		for ( var i=0, ien=filtered.length ; i<ien ; i++ ) {
   3642 			if (  filtered[i].val.full ) {
   3643 				rows.push( { full: filtered[i].val.full } );
   3644 				_layoutResolve( settings, rows[ rows.length - 1 ] );
   3645 	
   3646 				delete filtered[i].val.full;
   3647 			}
   3648 	
   3649 			if ( Object.keys(filtered[i].val).length ) {
   3650 				rows.push( filtered[i].val );
   3651 				_layoutResolve( settings, rows[ rows.length - 1 ] );
   3652 			}
   3653 		}
   3654 	
   3655 		return rows;
   3656 	}
   3657 	
   3658 	
   3659 	/**
   3660 	 * Convert the contents of a row's layout object to nodes that can be inserted
   3661 	 * into the document by a renderer. Execute functions, look up plug-ins, etc.
   3662 	 *
   3663 	 * @param {*} settings DataTables settings object
   3664 	 * @param {*} row Layout object for this row
   3665 	 */
   3666 	function _layoutResolve( settings, row ) {
   3667 		var getFeature = function (feature, opts) {
   3668 			if ( ! _ext.features[ feature ] ) {
   3669 				_fnLog( settings, 0, 'Unknown feature: '+ feature );
   3670 			}
   3671 	
   3672 			return _ext.features[ feature ].apply( this, [settings, opts] );
   3673 		};
   3674 	
   3675 		var resolve = function ( item ) {
   3676 			var line = row[ item ].contents;
   3677 	
   3678 			for ( var i=0, ien=line.length ; i<ien ; i++ ) {
   3679 				if ( ! line[i] ) {
   3680 					continue;
   3681 				}
   3682 				else if ( typeof line[i] === 'string' ) {
   3683 					line[i] = getFeature( line[i], null );
   3684 				}
   3685 				else if ( $.isPlainObject(line[i]) ) {
   3686 					// If it's an object, it just has feature and opts properties from
   3687 					// the transform in _layoutArray
   3688 					line[i] = getFeature(line[i].feature, line[i].opts);
   3689 				}
   3690 				else if ( typeof line[i].node === 'function' ) {
   3691 					line[i] = line[i].node( settings );
   3692 				}
   3693 				else if ( typeof line[i] === 'function' ) {
   3694 					var inst = line[i]( settings );
   3695 	
   3696 					line[i] = typeof inst.node === 'function' ?
   3697 						inst.node() :
   3698 						inst;
   3699 				}
   3700 			}
   3701 		};
   3702 	
   3703 		$.each( row, function ( key ) {
   3704 			resolve( key );
   3705 		} );
   3706 	}
   3707 	
   3708 	
   3709 	/**
   3710 	 * Add the options to the page HTML for the table
   3711 	 *  @param {object} settings DataTables settings object
   3712 	 *  @memberof DataTable#oApi
   3713 	 */
   3714 	function _fnAddOptionsHtml ( settings )
   3715 	{
   3716 		var classes = settings.oClasses;
   3717 		var table = $(settings.nTable);
   3718 	
   3719 		// Wrapper div around everything DataTables controls
   3720 		var insert = $('<div/>')
   3721 			.attr({
   3722 				id:      settings.sTableId+'_wrapper',
   3723 				'class': classes.container
   3724 			})
   3725 			.insertBefore(table);
   3726 	
   3727 		settings.nTableWrapper = insert[0];
   3728 	
   3729 		if (settings.sDom) {
   3730 			// Legacy
   3731 			_fnLayoutDom(settings, settings.sDom, insert);
   3732 		}
   3733 		else {
   3734 			var top = _layoutArray( settings, settings.layout, 'top' );
   3735 			var bottom = _layoutArray( settings, settings.layout, 'bottom' );
   3736 			var renderer = _fnRenderer( settings, 'layout' );
   3737 		
   3738 			// Everything above - the renderer will actually insert the contents into the document
   3739 			top.forEach(function (item) {
   3740 				renderer( settings, insert, item );
   3741 			});
   3742 	
   3743 			// The table - always the center of attention
   3744 			renderer( settings, insert, {
   3745 				full: {
   3746 					table: true,
   3747 					contents: [ _fnFeatureHtmlTable(settings) ]
   3748 				}
   3749 			} );
   3750 	
   3751 			// Everything below
   3752 			bottom.forEach(function (item) {
   3753 				renderer( settings, insert, item );
   3754 			});
   3755 		}
   3756 	
   3757 		// Processing floats on top, so it isn't an inserted feature
   3758 		_processingHtml( settings );
   3759 	}
   3760 	
   3761 	/**
   3762 	 * Draw the table with the legacy DOM property
   3763 	 * @param {*} settings DT settings object
   3764 	 * @param {*} dom DOM string
   3765 	 * @param {*} insert Insert point
   3766 	 */
   3767 	function _fnLayoutDom( settings, dom, insert )
   3768 	{
   3769 		var parts = dom.match(/(".*?")|('.*?')|./g);
   3770 		var featureNode, option, newNode, next, attr;
   3771 	
   3772 		for ( var i=0 ; i<parts.length ; i++ ) {
   3773 			featureNode = null;
   3774 			option = parts[i];
   3775 	
   3776 			if ( option == '<' ) {
   3777 				// New container div
   3778 				newNode = $('<div/>');
   3779 	
   3780 				// Check to see if we should append an id and/or a class name to the container
   3781 				next = parts[i+1];
   3782 	
   3783 				if ( next[0] == "'" || next[0] == '"' ) {
   3784 					attr = next.replace(/['"]/g, '');
   3785 	
   3786 					var id = '', className;
   3787 	
   3788 					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
   3789 					 * breaks the string into parts and applies them as needed
   3790 					 */
   3791 					if ( attr.indexOf('.') != -1 ) {
   3792 						var split = attr.split('.');
   3793 	
   3794 						id = split[0];
   3795 						className = split[1];
   3796 					}
   3797 					else if ( attr[0] == "#" ) {
   3798 						id = attr;
   3799 					}
   3800 					else {
   3801 						className = attr;
   3802 					}
   3803 	
   3804 					newNode
   3805 						.attr('id', id.substring(1))
   3806 						.addClass(className);
   3807 	
   3808 					i++; // Move along the position array
   3809 				}
   3810 	
   3811 				insert.append( newNode );
   3812 				insert = newNode;
   3813 			}
   3814 			else if ( option == '>' ) {
   3815 				// End container div
   3816 				insert = insert.parent();
   3817 			}
   3818 			else if ( option == 't' ) {
   3819 				// Table
   3820 				featureNode = _fnFeatureHtmlTable( settings );
   3821 			}
   3822 			else
   3823 			{
   3824 				DataTable.ext.feature.forEach(function(feature) {
   3825 					if ( option == feature.cFeature ) {
   3826 						featureNode = feature.fnInit( settings );
   3827 					}
   3828 				});
   3829 			}
   3830 	
   3831 			// Add to the display
   3832 			if ( featureNode ) {
   3833 				insert.append( featureNode );
   3834 			}
   3835 		}
   3836 	}
   3837 	
   3838 	
   3839 	/**
   3840 	 * Use the DOM source to create up an array of header cells. The idea here is to
   3841 	 * create a layout grid (array) of rows x columns, which contains a reference
   3842 	 * to the cell that that point in the grid (regardless of col/rowspan), such that
   3843 	 * any column / row could be removed and the new grid constructed
   3844 	 *  @param {node} thead The header/footer element for the table
   3845 	 *  @returns {array} Calculated layout array
   3846 	 *  @memberof DataTable#oApi
   3847 	 */
   3848 	function _fnDetectHeader ( settings, thead, write )
   3849 	{
   3850 		var columns = settings.aoColumns;
   3851 		var rows = $(thead).children('tr');
   3852 		var row, cell;
   3853 		var i, k, l, iLen, shifted, column, colspan, rowspan;
   3854 		var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
   3855 		var layout = [];
   3856 		var unique;
   3857 		var shift = function ( a, i, j ) {
   3858 			var k = a[i];
   3859 			while ( k[j] ) {
   3860 				j++;
   3861 			}
   3862 			return j;
   3863 		};
   3864 	
   3865 		// We know how many rows there are in the layout - so prep it
   3866 		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
   3867 			layout.push( [] );
   3868 		}
   3869 	
   3870 		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
   3871 			row = rows[i];
   3872 			column = 0;
   3873 	
   3874 			// For every cell in the row..
   3875 			cell = row.firstChild;
   3876 			while ( cell ) {
   3877 				if (
   3878 					cell.nodeName.toUpperCase() == 'TD' ||
   3879 					cell.nodeName.toUpperCase() == 'TH'
   3880 				) {
   3881 					var cols = [];
   3882 	
   3883 					// Get the col and rowspan attributes from the DOM and sanitise them
   3884 					colspan = cell.getAttribute('colspan') * 1;
   3885 					rowspan = cell.getAttribute('rowspan') * 1;
   3886 					colspan = (!colspan || colspan===0 || colspan===1) ? 1 : colspan;
   3887 					rowspan = (!rowspan || rowspan===0 || rowspan===1) ? 1 : rowspan;
   3888 	
   3889 					// There might be colspan cells already in this row, so shift our target
   3890 					// accordingly
   3891 					shifted = shift( layout, i, column );
   3892 	
   3893 					// Cache calculation for unique columns
   3894 					unique = colspan === 1 ?
   3895 						true :
   3896 						false;
   3897 					
   3898 					// Perform header setup
   3899 					if ( write ) {
   3900 						if (unique) {
   3901 							// Allow column options to be set from HTML attributes
   3902 							_fnColumnOptions( settings, shifted, $(cell).data() );
   3903 							
   3904 							// Get the width for the column. This can be defined from the
   3905 							// width attribute, style attribute or `columns.width` option
   3906 							var columnDef = columns[shifted];
   3907 							var width = cell.getAttribute('width') || null;
   3908 							var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
   3909 							if ( t ) {
   3910 								width = t[1];
   3911 							}
   3912 	
   3913 							columnDef.sWidthOrig = columnDef.sWidth || width;
   3914 	
   3915 							if (isHeader) {
   3916 								// Column title handling - can be user set, or read from the DOM
   3917 								// This happens before the render, so the original is still in place
   3918 								if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
   3919 									cell.innerHTML = columnDef.sTitle;
   3920 								}
   3921 	
   3922 								if (! columnDef.sTitle && unique) {
   3923 									columnDef.sTitle = _stripHtml(cell.innerHTML);
   3924 									columnDef.autoTitle = true;
   3925 								}
   3926 							}
   3927 							else {
   3928 								// Footer specific operations
   3929 								if (columnDef.footer) {
   3930 									cell.innerHTML = columnDef.footer;
   3931 								}
   3932 							}
   3933 	
   3934 							// Fall back to the aria-label attribute on the table header if no ariaTitle is
   3935 							// provided.
   3936 							if (! columnDef.ariaTitle) {
   3937 								columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
   3938 							}
   3939 	
   3940 							// Column specific class names
   3941 							if ( columnDef.className ) {
   3942 								$(cell).addClass( columnDef.className );
   3943 							}
   3944 						}
   3945 	
   3946 						// Wrap the column title so we can write to it in future
   3947 						if ( $('span.dt-column-title', cell).length === 0) {
   3948 							$('<span>')
   3949 								.addClass('dt-column-title')
   3950 								.append(cell.childNodes)
   3951 								.appendTo(cell);
   3952 						}
   3953 	
   3954 						if ( isHeader && $('span.dt-column-order', cell).length === 0) {
   3955 							$('<span>')
   3956 								.addClass('dt-column-order')
   3957 								.appendTo(cell);
   3958 						}
   3959 					}
   3960 	
   3961 					// If there is col / rowspan, copy the information into the layout grid
   3962 					for ( l=0 ; l<colspan ; l++ ) {
   3963 						for ( k=0 ; k<rowspan ; k++ ) {
   3964 							layout[i+k][shifted+l] = {
   3965 								cell: cell,
   3966 								unique: unique
   3967 							};
   3968 	
   3969 							layout[i+k].row = row;
   3970 						}
   3971 	
   3972 						cols.push( shifted+l );
   3973 					}
   3974 	
   3975 					// Assign an attribute so spanning cells can still be identified
   3976 					// as belonging to a column
   3977 					cell.setAttribute('data-dt-column', _unique(cols).join(','));
   3978 				}
   3979 	
   3980 				cell = cell.nextSibling;
   3981 			}
   3982 		}
   3983 	
   3984 		return layout;
   3985 	}
   3986 	
   3987 	/**
   3988 	 * Set the start position for draw
   3989 	 *  @param {object} oSettings dataTables settings object
   3990 	 */
   3991 	function _fnStart( oSettings )
   3992 	{
   3993 		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
   3994 		var iInitDisplayStart = oSettings.iInitDisplayStart;
   3995 	
   3996 		// Check and see if we have an initial draw position from state saving
   3997 		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
   3998 		{
   3999 			oSettings._iDisplayStart = bServerSide ?
   4000 				iInitDisplayStart :
   4001 				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
   4002 					0 :
   4003 					iInitDisplayStart;
   4004 	
   4005 			oSettings.iInitDisplayStart = -1;
   4006 		}
   4007 	}
   4008 	
   4009 	/**
   4010 	 * Create an Ajax call based on the table's settings, taking into account that
   4011 	 * parameters can have multiple forms, and backwards compatibility.
   4012 	 *
   4013 	 * @param {object} oSettings dataTables settings object
   4014 	 * @param {array} data Data to send to the server, required by
   4015 	 *     DataTables - may be augmented by developer callbacks
   4016 	 * @param {function} fn Callback function to run when data is obtained
   4017 	 */
   4018 	function _fnBuildAjax( oSettings, data, fn )
   4019 	{
   4020 		var ajaxData;
   4021 		var ajax = oSettings.ajax;
   4022 		var instance = oSettings.oInstance;
   4023 		var callback = function ( json ) {
   4024 			var status = oSettings.jqXHR
   4025 				? oSettings.jqXHR.status
   4026 				: null;
   4027 	
   4028 			if ( json === null || (typeof status === 'number' && status == 204 ) ) {
   4029 				json = {};
   4030 				_fnAjaxDataSrc( oSettings, json, [] );
   4031 			}
   4032 	
   4033 			var error = json.error || json.sError;
   4034 			if ( error ) {
   4035 				_fnLog( oSettings, 0, error );
   4036 			}
   4037 	
   4038 			oSettings.json = json;
   4039 	
   4040 			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
   4041 			fn( json );
   4042 		};
   4043 	
   4044 		if ( $.isPlainObject( ajax ) && ajax.data )
   4045 		{
   4046 			ajaxData = ajax.data;
   4047 	
   4048 			var newData = typeof ajaxData === 'function' ?
   4049 				ajaxData( data, oSettings ) :  // fn can manipulate data or return
   4050 				ajaxData;                      // an object object or array to merge
   4051 	
   4052 			// If the function returned something, use that alone
   4053 			data = typeof ajaxData === 'function' && newData ?
   4054 				newData :
   4055 				$.extend( true, data, newData );
   4056 	
   4057 			// Remove the data property as we've resolved it already and don't want
   4058 			// jQuery to do it again (it is restored at the end of the function)
   4059 			delete ajax.data;
   4060 		}
   4061 	
   4062 		var baseAjax = {
   4063 			"url": typeof ajax === 'string' ?
   4064 				ajax :
   4065 				'',
   4066 			"data": data,
   4067 			"success": callback,
   4068 			"dataType": "json",
   4069 			"cache": false,
   4070 			"type": oSettings.sServerMethod,
   4071 			"error": function (xhr, error) {
   4072 				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
   4073 	
   4074 				if ( ret.indexOf(true) === -1 ) {
   4075 					if ( error == "parsererror" ) {
   4076 						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
   4077 					}
   4078 					else if ( xhr.readyState === 4 ) {
   4079 						_fnLog( oSettings, 0, 'Ajax error', 7 );
   4080 					}
   4081 				}
   4082 	
   4083 				_fnProcessingDisplay( oSettings, false );
   4084 			}
   4085 		};
   4086 	
   4087 		// If `ajax` option is an object, extend and override our default base
   4088 		if ( $.isPlainObject( ajax ) ) {
   4089 			$.extend( baseAjax, ajax )
   4090 		}
   4091 	
   4092 		// Store the data submitted for the API
   4093 		oSettings.oAjaxData = data;
   4094 	
   4095 		// Allow plug-ins and external processes to modify the data
   4096 		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
   4097 	
   4098 		if ( typeof ajax === 'function' )
   4099 		{
   4100 			// Is a function - let the caller define what needs to be done
   4101 			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
   4102 		}
   4103 		else if (ajax.url === '') {
   4104 			// No url, so don't load any data. Just apply an empty data array
   4105 			// to the object for the callback.
   4106 			var empty = {};
   4107 	
   4108 			DataTable.util.set(ajax.dataSrc)(empty, []);
   4109 			callback(empty);
   4110 		}
   4111 		else {
   4112 			// Object to extend the base settings
   4113 			oSettings.jqXHR = $.ajax( baseAjax );
   4114 	
   4115 			// Restore for next time around
   4116 			if ( ajaxData ) {
   4117 				ajax.data = ajaxData;
   4118 			}
   4119 		}
   4120 	}
   4121 	
   4122 	
   4123 	/**
   4124 	 * Update the table using an Ajax call
   4125 	 *  @param {object} settings dataTables settings object
   4126 	 *  @returns {boolean} Block the table drawing or not
   4127 	 *  @memberof DataTable#oApi
   4128 	 */
   4129 	function _fnAjaxUpdate( settings )
   4130 	{
   4131 		settings.iDraw++;
   4132 		_fnProcessingDisplay( settings, true );
   4133 	
   4134 		_fnBuildAjax(
   4135 			settings,
   4136 			_fnAjaxParameters( settings ),
   4137 			function(json) {
   4138 				_fnAjaxUpdateDraw( settings, json );
   4139 			}
   4140 		);
   4141 	}
   4142 	
   4143 	
   4144 	/**
   4145 	 * Build up the parameters in an object needed for a server-side processing
   4146 	 * request.
   4147 	 *  @param {object} oSettings dataTables settings object
   4148 	 *  @returns {bool} block the table drawing or not
   4149 	 *  @memberof DataTable#oApi
   4150 	 */
   4151 	function _fnAjaxParameters( settings )
   4152 	{
   4153 		var
   4154 			columns = settings.aoColumns,
   4155 			features = settings.oFeatures,
   4156 			preSearch = settings.oPreviousSearch,
   4157 			preColSearch = settings.aoPreSearchCols,
   4158 			colData = function ( idx, prop ) {
   4159 				return typeof columns[idx][prop] === 'function' ?
   4160 					'function' :
   4161 					columns[idx][prop];
   4162 			};
   4163 	
   4164 		return {
   4165 			draw: settings.iDraw,
   4166 			columns: columns.map( function ( column, i ) {
   4167 				return {
   4168 					data: colData(i, 'mData'),
   4169 					name: column.sName,
   4170 					searchable: column.bSearchable,
   4171 					orderable: column.bSortable,
   4172 					search: {
   4173 						value: preColSearch[i].search,
   4174 						regex: preColSearch[i].regex,
   4175 						fixed: Object.keys(column.searchFixed).map( function(name) {
   4176 							return {
   4177 								name: name,
   4178 								term: column.searchFixed[name].toString()
   4179 							}
   4180 						})
   4181 					}
   4182 				};
   4183 			} ),
   4184 			order: _fnSortFlatten( settings ).map( function ( val ) {
   4185 				return {
   4186 					column: val.col,
   4187 					dir: val.dir,
   4188 					name: colData(val.col, 'sName')
   4189 				};
   4190 			} ),
   4191 			start: settings._iDisplayStart,
   4192 			length: features.bPaginate ?
   4193 				settings._iDisplayLength :
   4194 				-1,
   4195 			search: {
   4196 				value: preSearch.search,
   4197 				regex: preSearch.regex,
   4198 				fixed: Object.keys(settings.searchFixed).map( function(name) {
   4199 					return {
   4200 						name: name,
   4201 						term: settings.searchFixed[name].toString()
   4202 					}
   4203 				})
   4204 			}
   4205 		};
   4206 	}
   4207 	
   4208 	
   4209 	/**
   4210 	 * Data the data from the server (nuking the old) and redraw the table
   4211 	 *  @param {object} oSettings dataTables settings object
   4212 	 *  @param {object} json json data return from the server.
   4213 	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
   4214 	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
   4215 	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
   4216 	 *  @param {array} json.aaData The data to display on this page
   4217 	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
   4218 	 *  @memberof DataTable#oApi
   4219 	 */
   4220 	function _fnAjaxUpdateDraw ( settings, json )
   4221 	{
   4222 		var data = _fnAjaxDataSrc(settings, json);
   4223 		var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
   4224 		var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
   4225 		var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
   4226 	
   4227 		if ( draw !== undefined ) {
   4228 			// Protect against out of sequence returns
   4229 			if ( draw*1 < settings.iDraw ) {
   4230 				return;
   4231 			}
   4232 			settings.iDraw = draw * 1;
   4233 		}
   4234 	
   4235 		// No data in returned object, so rather than an array, we show an empty table
   4236 		if ( ! data ) {
   4237 			data = [];
   4238 		}
   4239 	
   4240 		_fnClearTable( settings );
   4241 		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
   4242 		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
   4243 	
   4244 		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
   4245 			_fnAddData( settings, data[i] );
   4246 		}
   4247 		settings.aiDisplay = settings.aiDisplayMaster.slice();
   4248 	
   4249 		_fnDraw( settings, true );
   4250 		_fnInitComplete( settings );
   4251 		_fnProcessingDisplay( settings, false );
   4252 	}
   4253 	
   4254 	
   4255 	/**
   4256 	 * Get the data from the JSON data source to use for drawing a table. Using
   4257 	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
   4258 	 * source object, or from a processing function.
   4259 	 *  @param {object} settings dataTables settings object
   4260 	 *  @param  {object} json Data source object / array from the server
   4261 	 *  @return {array} Array of data to use
   4262 	 */
   4263 	function _fnAjaxDataSrc ( settings, json, write )
   4264 	{
   4265 		var dataProp = 'data';
   4266 	
   4267 		if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
   4268 			// Could in inside a `dataSrc` object, or not!
   4269 			var dataSrc = settings.ajax.dataSrc;
   4270 	
   4271 			// string, function and object are valid types
   4272 			if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
   4273 				dataProp = dataSrc;
   4274 			}
   4275 			else if (dataSrc.data !== undefined) {
   4276 				dataProp = dataSrc.data;
   4277 			}
   4278 		}
   4279 	
   4280 		if ( ! write ) {
   4281 			if ( dataProp === 'data' ) {
   4282 				// If the default, then we still want to support the old style, and safely ignore
   4283 				// it if possible
   4284 				return json.aaData || json[dataProp];
   4285 			}
   4286 	
   4287 			return dataProp !== "" ?
   4288 				_fnGetObjectDataFn( dataProp )( json ) :
   4289 				json;
   4290 		}
   4291 		
   4292 		// set
   4293 		_fnSetObjectDataFn( dataProp )( json, write );
   4294 	}
   4295 	
   4296 	/**
   4297 	 * Very similar to _fnAjaxDataSrc, but for the other SSP properties
   4298 	 * @param {*} settings DataTables settings object
   4299 	 * @param {*} param Target parameter
   4300 	 * @param {*} json JSON data
   4301 	 * @returns Resolved value
   4302 	 */
   4303 	function _fnAjaxDataSrcParam (settings, param, json) {
   4304 		var dataSrc = $.isPlainObject( settings.ajax )
   4305 			? settings.ajax.dataSrc
   4306 			: null;
   4307 	
   4308 		if (dataSrc && dataSrc[param]) {
   4309 			// Get from custom location
   4310 			return _fnGetObjectDataFn( dataSrc[param] )( json );
   4311 		}
   4312 	
   4313 		// else - Default behaviour
   4314 		var old = '';
   4315 	
   4316 		// Legacy support
   4317 		if (param === 'draw') {
   4318 			old = 'sEcho';
   4319 		}
   4320 		else if (param === 'recordsTotal') {
   4321 			old = 'iTotalRecords';
   4322 		}
   4323 		else if (param === 'recordsFiltered') {
   4324 			old = 'iTotalDisplayRecords';
   4325 		}
   4326 	
   4327 		return json[old] !== undefined
   4328 			? json[old]
   4329 			: json[param];
   4330 	}
   4331 	
   4332 	
   4333 	/**
   4334 	 * Filter the table using both the global filter and column based filtering
   4335 	 *  @param {object} settings dataTables settings object
   4336 	 *  @param {object} input search information
   4337 	 *  @memberof DataTable#oApi
   4338 	 */
   4339 	function _fnFilterComplete ( settings, input )
   4340 	{
   4341 		var columnsSearch = settings.aoPreSearchCols;
   4342 	
   4343 		// Resolve any column types that are unknown due to addition or invalidation
   4344 		// @todo As per sort - can this be moved into an event handler?
   4345 		_fnColumnTypes( settings );
   4346 	
   4347 		// In server-side processing all filtering is done by the server, so no point hanging around here
   4348 		if ( _fnDataSource( settings ) != 'ssp' )
   4349 		{
   4350 			// Check if any of the rows were invalidated
   4351 			_fnFilterData( settings );
   4352 	
   4353 			// Start from the full data set
   4354 			settings.aiDisplay = settings.aiDisplayMaster.slice();
   4355 	
   4356 			// Global filter first
   4357 			_fnFilter( settings.aiDisplay, settings, input.search, input );
   4358 	
   4359 			$.each(settings.searchFixed, function (name, term) {
   4360 				_fnFilter(settings.aiDisplay, settings, term, {});
   4361 			});
   4362 	
   4363 			// Then individual column filters
   4364 			for ( var i=0 ; i<columnsSearch.length ; i++ )
   4365 			{
   4366 				var col = columnsSearch[i];
   4367 	
   4368 				_fnFilter(
   4369 					settings.aiDisplay,
   4370 					settings,
   4371 					col.search,
   4372 					col,
   4373 					i
   4374 				);
   4375 	
   4376 				$.each(settings.aoColumns[i].searchFixed, function (name, term) {
   4377 					_fnFilter(settings.aiDisplay, settings, term, {}, i);
   4378 				});
   4379 			}
   4380 	
   4381 			// And finally global filtering
   4382 			_fnFilterCustom( settings );
   4383 		}
   4384 	
   4385 		// Tell the draw function we have been filtering
   4386 		settings.bFiltered = true;
   4387 	
   4388 		_fnCallbackFire( settings, null, 'search', [settings] );
   4389 	}
   4390 	
   4391 	
   4392 	/**
   4393 	 * Apply custom filtering functions
   4394 	 * 
   4395 	 * This is legacy now that we have named functions, but it is widely used
   4396 	 * from 1.x, so it is not yet deprecated.
   4397 	 *  @param {object} oSettings dataTables settings object
   4398 	 *  @memberof DataTable#oApi
   4399 	 */
   4400 	function _fnFilterCustom( settings )
   4401 	{
   4402 		var filters = DataTable.ext.search;
   4403 		var displayRows = settings.aiDisplay;
   4404 		var row, rowIdx;
   4405 	
   4406 		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
   4407 			var rows = [];
   4408 	
   4409 			// Loop over each row and see if it should be included
   4410 			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
   4411 				rowIdx = displayRows[ j ];
   4412 				row = settings.aoData[ rowIdx ];
   4413 	
   4414 				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
   4415 					rows.push( rowIdx );
   4416 				}
   4417 			}
   4418 	
   4419 			// So the array reference doesn't break set the results into the
   4420 			// existing array
   4421 			displayRows.length = 0;
   4422 			displayRows.push.apply(displayRows, rows);
   4423 		}
   4424 	}
   4425 	
   4426 	
   4427 	/**
   4428 	 * Filter the data table based on user input and draw the table
   4429 	 */
   4430 	function _fnFilter( searchRows, settings, input, options, column )
   4431 	{
   4432 		if ( input === '' ) {
   4433 			return;
   4434 		}
   4435 	
   4436 		var i = 0;
   4437 		var matched = [];
   4438 	
   4439 		// Search term can be a function, regex or string - if a string we apply our
   4440 		// smart filtering regex (assuming the options require that)
   4441 		var searchFunc = typeof input === 'function' ? input : null;
   4442 		var rpSearch = input instanceof RegExp
   4443 			? input
   4444 			: searchFunc
   4445 				? null
   4446 				: _fnFilterCreateSearch( input, options );
   4447 	
   4448 		// Then for each row, does the test pass. If not, lop the row from the array
   4449 		for (i=0 ; i<searchRows.length ; i++) {
   4450 			var row = settings.aoData[ searchRows[i] ];
   4451 			var data = column === undefined
   4452 				? row._sFilterRow
   4453 				: row._aFilterData[ column ];
   4454 	
   4455 			if ( (searchFunc && searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && rpSearch.test(data)) ) {
   4456 				matched.push(searchRows[i]);
   4457 			}
   4458 		}
   4459 	
   4460 		// Mutate the searchRows array
   4461 		searchRows.length = matched.length;
   4462 	
   4463 		for (i=0 ; i<matched.length ; i++) {
   4464 			searchRows[i] = matched[i];
   4465 		}
   4466 	}
   4467 	
   4468 	
   4469 	/**
   4470 	 * Build a regular expression object suitable for searching a table
   4471 	 *  @param {string} sSearch string to search for
   4472 	 *  @param {bool} bRegex treat as a regular expression or not
   4473 	 *  @param {bool} bSmart perform smart filtering or not
   4474 	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
   4475 	 *  @returns {RegExp} constructed object
   4476 	 *  @memberof DataTable#oApi
   4477 	 */
   4478 	function _fnFilterCreateSearch( search, inOpts )
   4479 	{
   4480 		var not = [];
   4481 		var options = $.extend({}, {
   4482 			boundary: false,
   4483 			caseInsensitive: true,
   4484 			exact: false,
   4485 			regex: false,
   4486 			smart: true
   4487 		}, inOpts);
   4488 	
   4489 		if (typeof search !== 'string') {
   4490 			search = search.toString();
   4491 		}
   4492 	
   4493 		// Remove diacritics if normalize is set up to do so
   4494 		search = _normalize(search);
   4495 	
   4496 		if (options.exact) {
   4497 			return new RegExp(
   4498 				'^'+_fnEscapeRegex(search)+'$',
   4499 				options.caseInsensitive ? 'i' : ''
   4500 			);
   4501 		}
   4502 	
   4503 		search = options.regex ?
   4504 			search :
   4505 			_fnEscapeRegex( search );
   4506 		
   4507 		if ( options.smart ) {
   4508 			/* For smart filtering we want to allow the search to work regardless of
   4509 			 * word order. We also want double quoted text to be preserved, so word
   4510 			 * order is important - a la google. And a negative look around for
   4511 			 * finding rows which don't contain a given string.
   4512 			 * 
   4513 			 * So this is the sort of thing we want to generate:
   4514 			 * 
   4515 			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
   4516 			 */
   4517 			var parts = search.match( /!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''];
   4518 			var a = parts.map( function ( word ) {
   4519 				var negative = false;
   4520 				var m;
   4521 	
   4522 				// Determine if it is a "does not include"
   4523 				if ( word.charAt(0) === '!' ) {
   4524 					negative = true;
   4525 					word = word.substring(1);
   4526 				}
   4527 	
   4528 				// Strip the quotes from around matched phrases
   4529 				if ( word.charAt(0) === '"' ) {
   4530 					m = word.match( /^"(.*)"$/ );
   4531 					word = m ? m[1] : word;
   4532 				}
   4533 				else if ( word.charAt(0) === '\u201C' ) {
   4534 					// Smart quote match (iPhone users)
   4535 					m = word.match( /^\u201C(.*)\u201D$/ );
   4536 					word = m ? m[1] : word;
   4537 				}
   4538 	
   4539 				// For our "not" case, we need to modify the string that is
   4540 				// allowed to match at the end of the expression.
   4541 				if (negative) {
   4542 					if (word.length > 1) {
   4543 						not.push('(?!'+word+')');
   4544 					}
   4545 	
   4546 					word = '';
   4547 				}
   4548 	
   4549 				return word.replace(/"/g, '');
   4550 			} );
   4551 	
   4552 			var match = not.length
   4553 				? not.join('')
   4554 				: '';
   4555 	
   4556 			var boundary = options.boundary
   4557 				? '\\b'
   4558 				: '';
   4559 	
   4560 			search = '^(?=.*?'+boundary+a.join( ')(?=.*?'+boundary )+')('+match+'.)*$';
   4561 		}
   4562 	
   4563 		return new RegExp( search, options.caseInsensitive ? 'i' : '' );
   4564 	}
   4565 	
   4566 	
   4567 	/**
   4568 	 * Escape a string such that it can be used in a regular expression
   4569 	 *  @param {string} sVal string to escape
   4570 	 *  @returns {string} escaped string
   4571 	 *  @memberof DataTable#oApi
   4572 	 */
   4573 	var _fnEscapeRegex = DataTable.util.escapeRegex;
   4574 	
   4575 	var __filter_div = $('<div>')[0];
   4576 	var __filter_div_textContent = __filter_div.textContent !== undefined;
   4577 	
   4578 	// Update the filtering data for each row if needed (by invalidation or first run)
   4579 	function _fnFilterData ( settings )
   4580 	{
   4581 		var columns = settings.aoColumns;
   4582 		var data = settings.aoData;
   4583 		var column;
   4584 		var j, jen, filterData, cellData, row;
   4585 		var wasInvalidated = false;
   4586 	
   4587 		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
   4588 			if (! data[rowIdx]) {
   4589 				continue;
   4590 			}
   4591 	
   4592 			row = data[rowIdx];
   4593 	
   4594 			if ( ! row._aFilterData ) {
   4595 				filterData = [];
   4596 	
   4597 				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
   4598 					column = columns[j];
   4599 	
   4600 					if ( column.bSearchable ) {
   4601 						cellData = _fnGetCellData( settings, rowIdx, j, 'filter' );
   4602 	
   4603 						// Search in DataTables is string based
   4604 						if ( cellData === null ) {
   4605 							cellData = '';
   4606 						}
   4607 	
   4608 						if ( typeof cellData !== 'string' && cellData.toString ) {
   4609 							cellData = cellData.toString();
   4610 						}
   4611 					}
   4612 					else {
   4613 						cellData = '';
   4614 					}
   4615 	
   4616 					// If it looks like there is an HTML entity in the string,
   4617 					// attempt to decode it so sorting works as expected. Note that
   4618 					// we could use a single line of jQuery to do this, but the DOM
   4619 					// method used here is much faster https://jsperf.com/html-decode
   4620 					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
   4621 						__filter_div.innerHTML = cellData;
   4622 						cellData = __filter_div_textContent ?
   4623 							__filter_div.textContent :
   4624 							__filter_div.innerText;
   4625 					}
   4626 	
   4627 					if ( cellData.replace ) {
   4628 						cellData = cellData.replace(/[\r\n\u2028]/g, '');
   4629 					}
   4630 	
   4631 					filterData.push( cellData );
   4632 				}
   4633 	
   4634 				row._aFilterData = filterData;
   4635 				row._sFilterRow = filterData.join('  ');
   4636 				wasInvalidated = true;
   4637 			}
   4638 		}
   4639 	
   4640 		return wasInvalidated;
   4641 	}
   4642 	
   4643 	
   4644 	/**
   4645 	 * Draw the table for the first time, adding all required features
   4646 	 *  @param {object} settings dataTables settings object
   4647 	 *  @memberof DataTable#oApi
   4648 	 */
   4649 	function _fnInitialise ( settings )
   4650 	{
   4651 		var i, iAjaxStart=settings.iInitDisplayStart;
   4652 	
   4653 		/* Ensure that the table data is fully initialised */
   4654 		if ( ! settings.bInitialised ) {
   4655 			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
   4656 			return;
   4657 		}
   4658 	
   4659 		/* Build and draw the header / footer for the table */
   4660 		_fnBuildHead( settings, 'header' );
   4661 		_fnBuildHead( settings, 'footer' );
   4662 		_fnDrawHead( settings, settings.aoHeader );
   4663 		_fnDrawHead( settings, settings.aoFooter );
   4664 	
   4665 		// Enable features
   4666 		_fnAddOptionsHtml( settings );
   4667 		_fnSortInit( settings );
   4668 	
   4669 		_colGroup( settings );
   4670 	
   4671 		/* Okay to show that something is going on now */
   4672 		_fnProcessingDisplay( settings, true );
   4673 	
   4674 		_fnCallbackFire( settings, null, 'preInit', [settings], true );
   4675 	
   4676 		// If there is default sorting required - let's do it. The sort function
   4677 		// will do the drawing for us. Otherwise we draw the table regardless of the
   4678 		// Ajax source - this allows the table to look initialised for Ajax sourcing
   4679 		// data (show 'loading' message possibly)
   4680 		_fnReDraw( settings );
   4681 	
   4682 		var dataSrc = _fnDataSource( settings );
   4683 	
   4684 		// Server-side processing init complete is done by _fnAjaxUpdateDraw
   4685 		if ( dataSrc != 'ssp' ) {
   4686 			// if there is an ajax source load the data
   4687 			if ( dataSrc == 'ajax' ) {
   4688 				_fnBuildAjax( settings, {}, function(json) {
   4689 					var aData = _fnAjaxDataSrc( settings, json );
   4690 	
   4691 					// Got the data - add it to the table
   4692 					for ( i=0 ; i<aData.length ; i++ ) {
   4693 						_fnAddData( settings, aData[i] );
   4694 					}
   4695 	
   4696 					// Reset the init display for cookie saving. We've already done
   4697 					// a filter, and therefore cleared it before. So we need to make
   4698 					// it appear 'fresh'
   4699 					settings.iInitDisplayStart = iAjaxStart;
   4700 	
   4701 					_fnReDraw( settings );
   4702 					_fnProcessingDisplay( settings, false );
   4703 					_fnInitComplete( settings );
   4704 				}, settings );
   4705 			}
   4706 			else {
   4707 				_fnInitComplete( settings );
   4708 				_fnProcessingDisplay( settings, false );
   4709 			}
   4710 		}
   4711 	}
   4712 	
   4713 	
   4714 	/**
   4715 	 * Draw the table for the first time, adding all required features
   4716 	 *  @param {object} settings dataTables settings object
   4717 	 *  @memberof DataTable#oApi
   4718 	 */
   4719 	function _fnInitComplete ( settings )
   4720 	{
   4721 		if (settings._bInitComplete) {
   4722 			return;
   4723 		}
   4724 	
   4725 		var args = [settings, settings.json];
   4726 	
   4727 		settings._bInitComplete = true;
   4728 	
   4729 		// Table is fully set up and we have data, so calculate the
   4730 		// column widths
   4731 		_fnAdjustColumnSizing( settings );
   4732 	
   4733 		_fnCallbackFire( settings, null, 'plugin-init', args, true );
   4734 		_fnCallbackFire( settings, 'aoInitComplete', 'init', args, true );
   4735 	}
   4736 	
   4737 	function _fnLengthChange ( settings, val )
   4738 	{
   4739 		var len = parseInt( val, 10 );
   4740 		settings._iDisplayLength = len;
   4741 	
   4742 		_fnLengthOverflow( settings );
   4743 	
   4744 		// Fire length change event
   4745 		_fnCallbackFire( settings, null, 'length', [settings, len] );
   4746 	}
   4747 	
   4748 	/**
   4749 	 * Alter the display settings to change the page
   4750 	 *  @param {object} settings DataTables settings object
   4751 	 *  @param {string|int} action Paging action to take: "first", "previous",
   4752 	 *    "next" or "last" or page number to jump to (integer)
   4753 	 *  @param [bool] redraw Automatically draw the update or not
   4754 	 *  @returns {bool} true page has changed, false - no change
   4755 	 *  @memberof DataTable#oApi
   4756 	 */
   4757 	function _fnPageChange ( settings, action, redraw )
   4758 	{
   4759 		var
   4760 			start     = settings._iDisplayStart,
   4761 			len       = settings._iDisplayLength,
   4762 			records   = settings.fnRecordsDisplay();
   4763 	
   4764 		if ( records === 0 || len === -1 )
   4765 		{
   4766 			start = 0;
   4767 		}
   4768 		else if ( typeof action === "number" )
   4769 		{
   4770 			start = action * len;
   4771 	
   4772 			if ( start > records )
   4773 			{
   4774 				start = 0;
   4775 			}
   4776 		}
   4777 		else if ( action == "first" )
   4778 		{
   4779 			start = 0;
   4780 		}
   4781 		else if ( action == "previous" )
   4782 		{
   4783 			start = len >= 0 ?
   4784 				start - len :
   4785 				0;
   4786 	
   4787 			if ( start < 0 )
   4788 			{
   4789 				start = 0;
   4790 			}
   4791 		}
   4792 		else if ( action == "next" )
   4793 		{
   4794 			if ( start + len < records )
   4795 			{
   4796 				start += len;
   4797 			}
   4798 		}
   4799 		else if ( action == "last" )
   4800 		{
   4801 			start = Math.floor( (records-1) / len) * len;
   4802 		}
   4803 		else if ( action === 'ellipsis' )
   4804 		{
   4805 			return;
   4806 		}
   4807 		else
   4808 		{
   4809 			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
   4810 		}
   4811 	
   4812 		var changed = settings._iDisplayStart !== start;
   4813 		settings._iDisplayStart = start;
   4814 	
   4815 		_fnCallbackFire( settings, null, changed ? 'page' : 'page-nc', [settings] );
   4816 	
   4817 		if ( changed && redraw ) {
   4818 			_fnDraw( settings );
   4819 		}
   4820 	
   4821 		return changed;
   4822 	}
   4823 	
   4824 	
   4825 	/**
   4826 	 * Generate the node required for the processing node
   4827 	 *  @param {object} settings DataTables settings object
   4828 	 */
   4829 	function _processingHtml ( settings )
   4830 	{
   4831 		var table = settings.nTable;
   4832 		var scrolling = settings.oScroll.sX !== '' || settings.oScroll.sY !== '';
   4833 	
   4834 		if ( settings.oFeatures.bProcessing ) {
   4835 			var n = $('<div/>', {
   4836 					'id': settings.sTableId + '_processing',
   4837 					'class': settings.oClasses.processing.container,
   4838 					'role': 'status'
   4839 				} )
   4840 				.html( settings.oLanguage.sProcessing )
   4841 				.append('<div><div></div><div></div><div></div><div></div></div>');
   4842 	
   4843 			// Different positioning depending on if scrolling is enabled or not
   4844 			if (scrolling) {
   4845 				n.prependTo( $('div.dt-scroll', settings.nTableWrapper) );
   4846 			}
   4847 			else {
   4848 				n.insertBefore( table );
   4849 			}
   4850 	
   4851 			$(table).on( 'processing.dt.DT', function (e, s, show) {
   4852 				n.css( 'display', show ? 'block' : 'none' );
   4853 			} );
   4854 		}
   4855 	}
   4856 	
   4857 	
   4858 	/**
   4859 	 * Display or hide the processing indicator
   4860 	 *  @param {object} settings DataTables settings object
   4861 	 *  @param {bool} show Show the processing indicator (true) or not (false)
   4862 	 */
   4863 	function _fnProcessingDisplay ( settings, show )
   4864 	{
   4865 		_fnCallbackFire( settings, null, 'processing', [settings, show] );
   4866 	}
   4867 	/**
   4868 	 * Add any control elements for the table - specifically scrolling
   4869 	 *  @param {object} settings dataTables settings object
   4870 	 *  @returns {node} Node to add to the DOM
   4871 	 *  @memberof DataTable#oApi
   4872 	 */
   4873 	function _fnFeatureHtmlTable ( settings )
   4874 	{
   4875 		var table = $(settings.nTable);
   4876 	
   4877 		// Scrolling from here on in
   4878 		var scroll = settings.oScroll;
   4879 	
   4880 		if ( scroll.sX === '' && scroll.sY === '' ) {
   4881 			return settings.nTable;
   4882 		}
   4883 	
   4884 		var scrollX = scroll.sX;
   4885 		var scrollY = scroll.sY;
   4886 		var classes = settings.oClasses.scrolling;
   4887 		var caption = settings.captionNode;
   4888 		var captionSide = caption ? caption._captionSide : null;
   4889 		var headerClone = $( table[0].cloneNode(false) );
   4890 		var footerClone = $( table[0].cloneNode(false) );
   4891 		var footer = table.children('tfoot');
   4892 		var _div = '<div/>';
   4893 		var size = function ( s ) {
   4894 			return !s ? null : _fnStringToCss( s );
   4895 		};
   4896 	
   4897 		if ( ! footer.length ) {
   4898 			footer = null;
   4899 		}
   4900 	
   4901 		/*
   4902 		 * The HTML structure that we want to generate in this function is:
   4903 		 *  div - scroller
   4904 		 *    div - scroll head
   4905 		 *      div - scroll head inner
   4906 		 *        table - scroll head table
   4907 		 *          thead - thead
   4908 		 *    div - scroll body
   4909 		 *      table - table (master table)
   4910 		 *        thead - thead clone for sizing
   4911 		 *        tbody - tbody
   4912 		 *    div - scroll foot
   4913 		 *      div - scroll foot inner
   4914 		 *        table - scroll foot table
   4915 		 *          tfoot - tfoot
   4916 		 */
   4917 		var scroller = $( _div, { 'class': classes.container } )
   4918 			.append(
   4919 				$(_div, { 'class': classes.header.self } )
   4920 					.css( {
   4921 						overflow: 'hidden',
   4922 						position: 'relative',
   4923 						border: 0,
   4924 						width: scrollX ? size(scrollX) : '100%'
   4925 					} )
   4926 					.append(
   4927 						$(_div, { 'class': classes.header.inner } )
   4928 							.css( {
   4929 								'box-sizing': 'content-box',
   4930 								width: scroll.sXInner || '100%'
   4931 							} )
   4932 							.append(
   4933 								headerClone
   4934 									.removeAttr('id')
   4935 									.css( 'margin-left', 0 )
   4936 									.append( captionSide === 'top' ? caption : null )
   4937 									.append(
   4938 										table.children('thead')
   4939 									)
   4940 							)
   4941 					)
   4942 			)
   4943 			.append(
   4944 				$(_div, { 'class': classes.body } )
   4945 					.css( {
   4946 						position: 'relative',
   4947 						overflow: 'auto',
   4948 						width: size( scrollX )
   4949 					} )
   4950 					.append( table )
   4951 			);
   4952 	
   4953 		if ( footer ) {
   4954 			scroller.append(
   4955 				$(_div, { 'class': classes.footer.self } )
   4956 					.css( {
   4957 						overflow: 'hidden',
   4958 						border: 0,
   4959 						width: scrollX ? size(scrollX) : '100%'
   4960 					} )
   4961 					.append(
   4962 						$(_div, { 'class': classes.footer.inner } )
   4963 							.append(
   4964 								footerClone
   4965 									.removeAttr('id')
   4966 									.css( 'margin-left', 0 )
   4967 									.append( captionSide === 'bottom' ? caption : null )
   4968 									.append(
   4969 										table.children('tfoot')
   4970 									)
   4971 							)
   4972 					)
   4973 			);
   4974 		}
   4975 	
   4976 		var children = scroller.children();
   4977 		var scrollHead = children[0];
   4978 		var scrollBody = children[1];
   4979 		var scrollFoot = footer ? children[2] : null;
   4980 	
   4981 		// When the body is scrolled, then we also want to scroll the headers
   4982 		$(scrollBody).on( 'scroll.DT', function () {
   4983 			var scrollLeft = this.scrollLeft;
   4984 	
   4985 			scrollHead.scrollLeft = scrollLeft;
   4986 	
   4987 			if ( footer ) {
   4988 				scrollFoot.scrollLeft = scrollLeft;
   4989 			}
   4990 		} );
   4991 	
   4992 		// When focus is put on the header cells, we might need to scroll the body
   4993 		$('th, td', scrollHead).on('focus', function () {
   4994 			var scrollLeft = scrollHead.scrollLeft;
   4995 	
   4996 			scrollBody.scrollLeft = scrollLeft;
   4997 	
   4998 			if ( footer ) {
   4999 				scrollBody.scrollLeft = scrollLeft;
   5000 			}
   5001 		});
   5002 	
   5003 		$(scrollBody).css('max-height', scrollY);
   5004 		if (! scroll.bCollapse) {
   5005 			$(scrollBody).css('height', scrollY);
   5006 		}
   5007 	
   5008 		settings.nScrollHead = scrollHead;
   5009 		settings.nScrollBody = scrollBody;
   5010 		settings.nScrollFoot = scrollFoot;
   5011 	
   5012 		// On redraw - align columns
   5013 		settings.aoDrawCallback.push(_fnScrollDraw);
   5014 	
   5015 		return scroller[0];
   5016 	}
   5017 	
   5018 	
   5019 	
   5020 	/**
   5021 	 * Update the header, footer and body tables for resizing - i.e. column
   5022 	 * alignment.
   5023 	 *
   5024 	 * Welcome to the most horrible function DataTables. The process that this
   5025 	 * function follows is basically:
   5026 	 *   1. Re-create the table inside the scrolling div
   5027 	 *   2. Correct colgroup > col values if needed
   5028 	 *   3. Copy colgroup > col over to header and footer
   5029 	 *   4. Clean up
   5030 	 *
   5031 	 *  @param {object} settings dataTables settings object
   5032 	 *  @memberof DataTable#oApi
   5033 	 */
   5034 	function _fnScrollDraw ( settings )
   5035 	{
   5036 		// Given that this is such a monster function, a lot of variables are use
   5037 		// to try and keep the minimised size as small as possible
   5038 		var
   5039 			scroll         = settings.oScroll,
   5040 			barWidth       = scroll.iBarWidth,
   5041 			divHeader      = $(settings.nScrollHead),
   5042 			divHeaderInner = divHeader.children('div'),
   5043 			divHeaderTable = divHeaderInner.children('table'),
   5044 			divBodyEl      = settings.nScrollBody,
   5045 			divBody        = $(divBodyEl),
   5046 			divFooter      = $(settings.nScrollFoot),
   5047 			divFooterInner = divFooter.children('div'),
   5048 			divFooterTable = divFooterInner.children('table'),
   5049 			header         = $(settings.nTHead),
   5050 			table          = $(settings.nTable),
   5051 			footer         = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
   5052 			browser        = settings.oBrowser,
   5053 			headerCopy, footerCopy;
   5054 	
   5055 		// If the scrollbar visibility has changed from the last draw, we need to
   5056 		// adjust the column sizes as the table width will have changed to account
   5057 		// for the scrollbar
   5058 		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
   5059 		
   5060 		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
   5061 			settings.scrollBarVis = scrollBarVis;
   5062 			_fnAdjustColumnSizing( settings );
   5063 			return; // adjust column sizing will call this function again
   5064 		}
   5065 		else {
   5066 			settings.scrollBarVis = scrollBarVis;
   5067 		}
   5068 	
   5069 		// 1. Re-create the table inside the scrolling div
   5070 		// Remove the old minimised thead and tfoot elements in the inner table
   5071 		table.children('thead, tfoot').remove();
   5072 	
   5073 		// Clone the current header and footer elements and then place it into the inner table
   5074 		headerCopy = header.clone().prependTo( table );
   5075 		headerCopy.find('th, td').removeAttr('tabindex');
   5076 		headerCopy.find('[id]').removeAttr('id');
   5077 	
   5078 		if ( footer ) {
   5079 			footerCopy = footer.clone().prependTo( table );
   5080 			footerCopy.find('[id]').removeAttr('id');
   5081 		}
   5082 	
   5083 		// 2. Correct colgroup > col values if needed
   5084 		// It is possible that the cell sizes are smaller than the content, so we need to
   5085 		// correct colgroup>col for such cases. This can happen if the auto width detection
   5086 		// uses a cell which has a longer string, but isn't the widest! For example 
   5087 		// "Chief Executive Officer (CEO)" is the longest string in the demo, but
   5088 		// "Systems Administrator" is actually the widest string since it doesn't collapse.
   5089 		// Note the use of translating into a column index to get the `col` element. This
   5090 		// is because of Responsive which might remove `col` elements, knocking the alignment
   5091 		// of the indexes out.
   5092 		if (settings.aiDisplay.length) {
   5093 			// Get the column sizes from the first row in the table
   5094 			var colSizes = table.children('tbody').eq(0).children('tr').eq(0).children('th, td').map(function (vis) {
   5095 				return {
   5096 					idx: _fnVisibleToColumnIndex(settings, vis),
   5097 					width: $(this).outerWidth()
   5098 				}
   5099 			});
   5100 	
   5101 			// Check against what the colgroup > col is set to and correct if needed
   5102 			for (var i=0 ; i<colSizes.length ; i++) {
   5103 				var colEl = settings.aoColumns[ colSizes[i].idx ].colEl[0];
   5104 				var colWidth = colEl.style.width.replace('px', '');
   5105 	
   5106 				if (colWidth !== colSizes[i].width) {
   5107 					colEl.style.width = colSizes[i].width + 'px';
   5108 				}
   5109 			}
   5110 		}
   5111 	
   5112 		// 3. Copy the colgroup over to the header and footer
   5113 		divHeaderTable
   5114 			.find('colgroup')
   5115 			.remove();
   5116 	
   5117 		divHeaderTable.append(settings.colgroup.clone());
   5118 	
   5119 		if ( footer ) {
   5120 			divFooterTable
   5121 				.find('colgroup')
   5122 				.remove();
   5123 	
   5124 			divFooterTable.append(settings.colgroup.clone());
   5125 		}
   5126 	
   5127 		// "Hide" the header and footer that we used for the sizing. We need to keep
   5128 		// the content of the cell so that the width applied to the header and body
   5129 		// both match, but we want to hide it completely.
   5130 		$('th, td', headerCopy).each(function () {
   5131 			$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
   5132 		});
   5133 	
   5134 		if ( footer ) {
   5135 			$('th, td', footerCopy).each(function () {
   5136 				$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
   5137 			});
   5138 		}
   5139 	
   5140 		// 4. Clean up
   5141 		// Figure out if there are scrollbar present - if so then we need a the header and footer to
   5142 		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
   5143 		var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
   5144 		var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
   5145 	
   5146 		// Set the width's of the header and footer tables
   5147 		var outerWidth = table.outerWidth();
   5148 	
   5149 		divHeaderTable.css('width', _fnStringToCss( outerWidth ));
   5150 		divHeaderInner
   5151 			.css('width', _fnStringToCss( outerWidth ))
   5152 			.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
   5153 	
   5154 		if ( footer ) {
   5155 			divFooterTable.css('width', _fnStringToCss( outerWidth ));
   5156 			divFooterInner
   5157 				.css('width', _fnStringToCss( outerWidth ))
   5158 				.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
   5159 		}
   5160 	
   5161 		// Correct DOM ordering for colgroup - comes before the thead
   5162 		table.children('colgroup').prependTo(table);
   5163 	
   5164 		// Adjust the position of the header in case we loose the y-scrollbar
   5165 		divBody.trigger('scroll');
   5166 	
   5167 		// If sorting or filtering has occurred, jump the scrolling back to the top
   5168 		// only if we aren't holding the position
   5169 		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
   5170 			divBodyEl.scrollTop = 0;
   5171 		}
   5172 	}
   5173 	
   5174 	/**
   5175 	 * Calculate the width of columns for the table
   5176 	 *  @param {object} settings dataTables settings object
   5177 	 *  @memberof DataTable#oApi
   5178 	 */
   5179 	function _fnCalculateColumnWidths ( settings )
   5180 	{
   5181 		// Not interested in doing column width calculation if auto-width is disabled
   5182 		if (! settings.oFeatures.bAutoWidth) {
   5183 			return;
   5184 		}
   5185 	
   5186 		var
   5187 			table = settings.nTable,
   5188 			columns = settings.aoColumns,
   5189 			scroll = settings.oScroll,
   5190 			scrollY = scroll.sY,
   5191 			scrollX = scroll.sX,
   5192 			scrollXInner = scroll.sXInner,
   5193 			visibleColumns = _fnGetColumns( settings, 'bVisible' ),
   5194 			tableWidthAttr = table.getAttribute('width'), // from DOM element
   5195 			tableContainer = table.parentNode,
   5196 			i, column, columnIdx;
   5197 	
   5198 		var styleWidth = table.style.width;
   5199 		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
   5200 			tableWidthAttr = styleWidth;
   5201 		}
   5202 	
   5203 		// Let plug-ins know that we are doing a recalc, in case they have changed any of the
   5204 		// visible columns their own way (e.g. Responsive uses display:none).
   5205 		_fnCallbackFire(
   5206 			settings,
   5207 			null,
   5208 			'column-calc',
   5209 			{visible: visibleColumns},
   5210 			false
   5211 		);
   5212 	
   5213 		// Construct a single row, worst case, table with the widest
   5214 		// node in the data, assign any user defined widths, then insert it into
   5215 		// the DOM and allow the browser to do all the hard work of calculating
   5216 		// table widths
   5217 		var tmpTable = $(table.cloneNode())
   5218 			.css( 'visibility', 'hidden' )
   5219 			.removeAttr( 'id' );
   5220 	
   5221 		// Clean up the table body
   5222 		tmpTable.append('<tbody>')
   5223 		var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
   5224 	
   5225 		// Clone the table header and footer - we can't use the header / footer
   5226 		// from the cloned table, since if scrolling is active, the table's
   5227 		// real header and footer are contained in different table tags
   5228 		tmpTable
   5229 			.append( $(settings.nTHead).clone() )
   5230 			.append( $(settings.nTFoot).clone() );
   5231 	
   5232 		// Remove any assigned widths from the footer (from scrolling)
   5233 		tmpTable.find('tfoot th, tfoot td').css('width', '');
   5234 	
   5235 		// Apply custom sizing to the cloned header
   5236 		tmpTable.find('thead th, thead td').each( function () {
   5237 			// Get the `width` from the header layout
   5238 			var width = _fnColumnsSumWidth( settings, this, true, false );
   5239 	
   5240 			if ( width ) {
   5241 				this.style.width = width;
   5242 	
   5243 				// For scrollX we need to force the column width otherwise the
   5244 				// browser will collapse it. If this width is smaller than the
   5245 				// width the column requires, then it will have no effect
   5246 				if ( scrollX ) {
   5247 					$( this ).append( $('<div/>').css( {
   5248 						width: width,
   5249 						margin: 0,
   5250 						padding: 0,
   5251 						border: 0,
   5252 						height: 1
   5253 					} ) );
   5254 				}
   5255 			}
   5256 			else {
   5257 				this.style.width = '';
   5258 			}
   5259 		} );
   5260 	
   5261 		// Find the widest piece of data for each column and put it into the table
   5262 		for ( i=0 ; i<visibleColumns.length ; i++ ) {
   5263 			columnIdx = visibleColumns[i];
   5264 			column = columns[ columnIdx ];
   5265 	
   5266 			var longest = _fnGetMaxLenString(settings, columnIdx);
   5267 			var autoClass = _ext.type.className[column.sType];
   5268 			var text = longest + column.sContentPadding;
   5269 			var insert = longest.indexOf('<') === -1
   5270 				? document.createTextNode(text)
   5271 				: text
   5272 			
   5273 			$('<td/>')
   5274 				.addClass(autoClass)
   5275 				.addClass(column.sClass)
   5276 				.append(insert)
   5277 				.appendTo(tr);
   5278 		}
   5279 	
   5280 		// Tidy the temporary table - remove name attributes so there aren't
   5281 		// duplicated in the dom (radio elements for example)
   5282 		$('[name]', tmpTable).removeAttr('name');
   5283 	
   5284 		// Table has been built, attach to the document so we can work with it.
   5285 		// A holding element is used, positioned at the top of the container
   5286 		// with minimal height, so it has no effect on if the container scrolls
   5287 		// or not. Otherwise it might trigger scrolling when it actually isn't
   5288 		// needed
   5289 		var holder = $('<div/>').css( scrollX || scrollY ?
   5290 				{
   5291 					position: 'absolute',
   5292 					top: 0,
   5293 					left: 0,
   5294 					height: 1,
   5295 					right: 0,
   5296 					overflow: 'hidden'
   5297 				} :
   5298 				{}
   5299 			)
   5300 			.append( tmpTable )
   5301 			.appendTo( tableContainer );
   5302 	
   5303 		// When scrolling (X or Y) we want to set the width of the table as 
   5304 		// appropriate. However, when not scrolling leave the table width as it
   5305 		// is. This results in slightly different, but I think correct behaviour
   5306 		if ( scrollX && scrollXInner ) {
   5307 			tmpTable.width( scrollXInner );
   5308 		}
   5309 		else if ( scrollX ) {
   5310 			tmpTable.css( 'width', 'auto' );
   5311 			tmpTable.removeAttr('width');
   5312 	
   5313 			// If there is no width attribute or style, then allow the table to
   5314 			// collapse
   5315 			if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
   5316 				tmpTable.width( tableContainer.clientWidth );
   5317 			}
   5318 		}
   5319 		else if ( scrollY ) {
   5320 			tmpTable.width( tableContainer.clientWidth );
   5321 		}
   5322 		else if ( tableWidthAttr ) {
   5323 			tmpTable.width( tableWidthAttr );
   5324 		}
   5325 	
   5326 		// Get the width of each column in the constructed table
   5327 		var total = 0;
   5328 		var bodyCells = tmpTable.find('tbody tr').eq(0).children();
   5329 	
   5330 		for ( i=0 ; i<visibleColumns.length ; i++ ) {
   5331 			// Use getBounding for sub-pixel accuracy, which we then want to round up!
   5332 			var bounding = bodyCells[i].getBoundingClientRect().width;
   5333 	
   5334 			// Total is tracked to remove any sub-pixel errors as the outerWidth
   5335 			// of the table might not equal the total given here
   5336 			total += bounding;
   5337 	
   5338 			// Width for each column to use
   5339 			columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding );
   5340 		}
   5341 	
   5342 		table.style.width = _fnStringToCss( total );
   5343 	
   5344 		// Finished with the table - ditch it
   5345 		holder.remove();
   5346 	
   5347 		// If there is a width attr, we want to attach an event listener which
   5348 		// allows the table sizing to automatically adjust when the window is
   5349 		// resized. Use the width attr rather than CSS, since we can't know if the
   5350 		// CSS is a relative value or absolute - DOM read is always px.
   5351 		if ( tableWidthAttr ) {
   5352 			table.style.width = _fnStringToCss( tableWidthAttr );
   5353 		}
   5354 	
   5355 		if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
   5356 			var bindResize = function () {
   5357 				$(window).on('resize.DT-'+settings.sInstance, DataTable.util.throttle( function () {
   5358 					if (! settings.bDestroying) {
   5359 						_fnAdjustColumnSizing( settings );
   5360 					}
   5361 				} ) );
   5362 			};
   5363 	
   5364 			bindResize();
   5365 	
   5366 			settings._reszEvt = true;
   5367 		}
   5368 	}
   5369 	
   5370 	
   5371 	/**
   5372 	 * Get the maximum strlen for each data column
   5373 	 *  @param {object} settings dataTables settings object
   5374 	 *  @param {int} colIdx column of interest
   5375 	 *  @returns {string} string of the max length
   5376 	 *  @memberof DataTable#oApi
   5377 	 */
   5378 	function _fnGetMaxLenString( settings, colIdx )
   5379 	{
   5380 		var column = settings.aoColumns[colIdx];
   5381 	
   5382 		if (! column.maxLenString) {
   5383 			var s, max='', maxLen = -1;
   5384 		
   5385 			for ( var i=0, ien=settings.aiDisplayMaster.length ; i<ien ; i++ ) {
   5386 				var rowIdx = settings.aiDisplayMaster[i];
   5387 				var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
   5388 	
   5389 				var cellString = data && typeof data === 'object' && data.nodeType
   5390 					? data.innerHTML
   5391 					: data+'';
   5392 	
   5393 				// Remove id / name attributes from elements so they
   5394 				// don't interfere with existing elements
   5395 				cellString = cellString
   5396 					.replace(/id=".*?"/g, '')
   5397 					.replace(/name=".*?"/g, '');
   5398 	
   5399 				s = _stripHtml(cellString)
   5400 					.replace( /&nbsp;/g, ' ' );
   5401 		
   5402 				if ( s.length > maxLen ) {
   5403 					// We want the HTML in the string, but the length that
   5404 					// is important is the stripped string
   5405 					max = cellString;
   5406 					maxLen = s.length;
   5407 				}
   5408 			}
   5409 	
   5410 			column.maxLenString = max;
   5411 		}
   5412 	
   5413 		return column.maxLenString;
   5414 	}
   5415 	
   5416 	
   5417 	/**
   5418 	 * Append a CSS unit (only if required) to a string
   5419 	 *  @param {string} value to css-ify
   5420 	 *  @returns {string} value with css unit
   5421 	 *  @memberof DataTable#oApi
   5422 	 */
   5423 	function _fnStringToCss( s )
   5424 	{
   5425 		if ( s === null ) {
   5426 			return '0px';
   5427 		}
   5428 	
   5429 		if ( typeof s == 'number' ) {
   5430 			return s < 0 ?
   5431 				'0px' :
   5432 				s+'px';
   5433 		}
   5434 	
   5435 		// Check it has a unit character already
   5436 		return s.match(/\d$/) ?
   5437 			s+'px' :
   5438 			s;
   5439 	}
   5440 	
   5441 	/**
   5442 	 * Re-insert the `col` elements for current visibility
   5443 	 *
   5444 	 * @param {*} settings DT settings
   5445 	 */
   5446 	function _colGroup( settings ) {
   5447 		var cols = settings.aoColumns;
   5448 	
   5449 		settings.colgroup.empty();
   5450 	
   5451 		for (i=0 ; i<cols.length ; i++) {
   5452 			if (cols[i].bVisible) {
   5453 				settings.colgroup.append(cols[i].colEl);
   5454 			}
   5455 		}
   5456 	}
   5457 	
   5458 	
   5459 	function _fnSortInit( settings ) {
   5460 		var target = settings.nTHead;
   5461 		var headerRows = target.querySelectorAll('tr');
   5462 		var legacyTop = settings.bSortCellsTop;
   5463 		var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
   5464 		
   5465 		// Legacy support for `orderCellsTop`
   5466 		if (legacyTop === true) {
   5467 			target = headerRows[0];
   5468 		}
   5469 		else if (legacyTop === false) {
   5470 			target = headerRows[ headerRows.length - 1 ];
   5471 		}
   5472 	
   5473 		_fnSortAttachListener(
   5474 			settings,
   5475 			target,
   5476 			target === settings.nTHead
   5477 				? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
   5478 				: 'th'+notSelector+', td'+notSelector
   5479 		);
   5480 	
   5481 		// Need to resolve the user input array into our internal structure
   5482 		var order = [];
   5483 		_fnSortResolve( settings, order, settings.aaSorting );
   5484 	
   5485 		settings.aaSorting = order;
   5486 	}
   5487 	
   5488 	
   5489 	function _fnSortAttachListener(settings, node, selector, column, callback) {
   5490 		_fnBindAction( node, selector, function (e) {
   5491 			var run = false;
   5492 			var columns = column === undefined
   5493 				? _fnColumnsFromHeader( e.target )
   5494 				: [column];
   5495 	
   5496 			if ( columns.length ) {
   5497 				for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
   5498 					var ret = _fnSortAdd( settings, columns[i], i, e.shiftKey );
   5499 	
   5500 					if (ret !== false) {
   5501 						run = true;
   5502 					}					
   5503 	
   5504 					// If the first entry is no sort, then subsequent
   5505 					// sort columns are ignored
   5506 					if (settings.aaSorting.length === 1 && settings.aaSorting[0][1] === '') {
   5507 						break;
   5508 					}
   5509 				}
   5510 	
   5511 				if (run) {
   5512 					_fnProcessingDisplay( settings, true );
   5513 	
   5514 					// Allow the processing display to show
   5515 					setTimeout( function () {
   5516 						_fnSort( settings );
   5517 						_fnSortDisplay( settings, settings.aiDisplay );
   5518 	
   5519 						// Sort processing done - redraw has its own processing display
   5520 						_fnProcessingDisplay( settings, false );
   5521 	
   5522 						_fnReDraw( settings, false, false );
   5523 	
   5524 						if (callback) {
   5525 							callback();
   5526 						}
   5527 					}, 0);
   5528 				}
   5529 			}
   5530 		} );
   5531 	}
   5532 	
   5533 	/**
   5534 	 * Sort the display array to match the master's order
   5535 	 * @param {*} settings
   5536 	 */
   5537 	function _fnSortDisplay(settings, display) {
   5538 		if (display.length < 2) {
   5539 			return;
   5540 		}
   5541 	
   5542 		var master = settings.aiDisplayMaster;
   5543 		var masterMap = {};
   5544 		var map = {};
   5545 		var i;
   5546 	
   5547 		// Rather than needing an `indexOf` on master array, we can create a map
   5548 		for (i=0 ; i<master.length ; i++) {
   5549 			masterMap[master[i]] = i;
   5550 		}
   5551 	
   5552 		// And then cache what would be the indexOf fom the display
   5553 		for (i=0 ; i<display.length ; i++) {
   5554 			map[display[i]] = masterMap[display[i]];
   5555 		}
   5556 	
   5557 		display.sort(function(a, b){
   5558 			// Short version of this function is simply `master.indexOf(a) - master.indexOf(b);`
   5559 			return map[a] - map[b];
   5560 		});
   5561 	}
   5562 	
   5563 	
   5564 	function _fnSortResolve (settings, nestedSort, sort) {
   5565 		var push = function ( a ) {
   5566 			if ($.isPlainObject(a)) {
   5567 				if (a.idx !== undefined) {
   5568 					// Index based ordering
   5569 					nestedSort.push([a.idx, a.dir]);
   5570 				}
   5571 				else if (a.name) {
   5572 					// Name based ordering
   5573 					var cols = _pluck( settings.aoColumns, 'sName');
   5574 					var idx = cols.indexOf(a.name);
   5575 	
   5576 					if (idx !== -1) {
   5577 						nestedSort.push([idx, a.dir]);
   5578 					}
   5579 				}
   5580 			}
   5581 			else {
   5582 				// Plain column index and direction pair
   5583 				nestedSort.push(a);
   5584 			}
   5585 		};
   5586 	
   5587 		if ( $.isPlainObject(sort) ) {
   5588 			// Object
   5589 			push(sort);
   5590 		}
   5591 		else if ( sort.length && typeof sort[0] === 'number' ) {
   5592 			// 1D array
   5593 			push(sort);
   5594 		}
   5595 		else if ( sort.length ) {
   5596 			// 2D array
   5597 			for (var z=0; z<sort.length; z++) {
   5598 				push(sort[z]); // Object or array
   5599 			}
   5600 		}
   5601 	}
   5602 	
   5603 	
   5604 	function _fnSortFlatten ( settings )
   5605 	{
   5606 		var
   5607 			i, k, kLen,
   5608 			aSort = [],
   5609 			extSort = DataTable.ext.type.order,
   5610 			aoColumns = settings.aoColumns,
   5611 			aDataSort, iCol, sType, srcCol,
   5612 			fixed = settings.aaSortingFixed,
   5613 			fixedObj = $.isPlainObject( fixed ),
   5614 			nestedSort = [];
   5615 		
   5616 		if ( ! settings.oFeatures.bSort ) {
   5617 			return aSort;
   5618 		}
   5619 	
   5620 		// Build the sort array, with pre-fix and post-fix options if they have been
   5621 		// specified
   5622 		if ( Array.isArray( fixed ) ) {
   5623 			_fnSortResolve( settings, nestedSort, fixed );
   5624 		}
   5625 	
   5626 		if ( fixedObj && fixed.pre ) {
   5627 			_fnSortResolve( settings, nestedSort, fixed.pre );
   5628 		}
   5629 	
   5630 		_fnSortResolve( settings, nestedSort, settings.aaSorting );
   5631 	
   5632 		if (fixedObj && fixed.post ) {
   5633 			_fnSortResolve( settings, nestedSort, fixed.post );
   5634 		}
   5635 	
   5636 		for ( i=0 ; i<nestedSort.length ; i++ )
   5637 		{
   5638 			srcCol = nestedSort[i][0];
   5639 	
   5640 			if ( aoColumns[ srcCol ] ) {
   5641 				aDataSort = aoColumns[ srcCol ].aDataSort;
   5642 	
   5643 				for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
   5644 				{
   5645 					iCol = aDataSort[k];
   5646 					sType = aoColumns[ iCol ].sType || 'string';
   5647 	
   5648 					if ( nestedSort[i]._idx === undefined ) {
   5649 						nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
   5650 					}
   5651 	
   5652 					if ( nestedSort[i][1] ) {
   5653 						aSort.push( {
   5654 							src:       srcCol,
   5655 							col:       iCol,
   5656 							dir:       nestedSort[i][1],
   5657 							index:     nestedSort[i]._idx,
   5658 							type:      sType,
   5659 							formatter: extSort[ sType+"-pre" ],
   5660 							sorter:    extSort[ sType+"-"+nestedSort[i][1] ]
   5661 						} );
   5662 					}
   5663 				}
   5664 			}
   5665 		}
   5666 	
   5667 		return aSort;
   5668 	}
   5669 	
   5670 	/**
   5671 	 * Change the order of the table
   5672 	 *  @param {object} oSettings dataTables settings object
   5673 	 *  @memberof DataTable#oApi
   5674 	 */
   5675 	function _fnSort ( oSettings, col, dir )
   5676 	{
   5677 		var
   5678 			i, ien, iLen,
   5679 			aiOrig = [],
   5680 			extSort = DataTable.ext.type.order,
   5681 			aoData = oSettings.aoData,
   5682 			sortCol,
   5683 			displayMaster = oSettings.aiDisplayMaster,
   5684 			aSort;
   5685 	
   5686 		// Resolve any column types that are unknown due to addition or invalidation
   5687 		// @todo Can this be moved into a 'data-ready' handler which is called when
   5688 		//   data is going to be used in the table?
   5689 		_fnColumnTypes( oSettings );
   5690 	
   5691 		// Allow a specific column to be sorted, which will _not_ alter the display
   5692 		// master
   5693 		if (col !== undefined) {
   5694 			var srcCol = oSettings.aoColumns[col];
   5695 			aSort = [{
   5696 				src:       col,
   5697 				col:       col,
   5698 				dir:       dir,
   5699 				index:     0,
   5700 				type:      srcCol.sType,
   5701 				formatter: extSort[ srcCol.sType+"-pre" ],
   5702 				sorter:    extSort[ srcCol.sType+"-"+dir ]
   5703 			}];
   5704 			displayMaster = displayMaster.slice();
   5705 		}
   5706 		else {
   5707 			aSort = _fnSortFlatten( oSettings );
   5708 		}
   5709 	
   5710 		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
   5711 			sortCol = aSort[i];
   5712 	
   5713 			// Load the data needed for the sort, for each cell
   5714 			_fnSortData( oSettings, sortCol.col );
   5715 		}
   5716 	
   5717 		/* No sorting required if server-side or no sorting array */
   5718 		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
   5719 		{
   5720 			// Reset the initial positions on each pass so we get a stable sort
   5721 			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
   5722 				aiOrig[ i ] = i;
   5723 			}
   5724 	
   5725 			// If the first sort is desc, then reverse the array to preserve original
   5726 			// order, just in reverse
   5727 			if (aSort.length && aSort[0].dir === 'desc') {
   5728 				aiOrig.reverse();
   5729 			}
   5730 	
   5731 			/* Do the sort - here we want multi-column sorting based on a given data source (column)
   5732 			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
   5733 			 * follow on it's own, but this is what we want (example two column sorting):
   5734 			 *  fnLocalSorting = function(a,b){
   5735 			 *    var test;
   5736 			 *    test = oSort['string-asc']('data11', 'data12');
   5737 			 *      if (test !== 0)
   5738 			 *        return test;
   5739 			 *    test = oSort['numeric-desc']('data21', 'data22');
   5740 			 *    if (test !== 0)
   5741 			 *      return test;
   5742 			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
   5743 			 *  }
   5744 			 * Basically we have a test for each sorting column, if the data in that column is equal,
   5745 			 * test the next column. If all columns match, then we use a numeric sort on the row
   5746 			 * positions in the original data array to provide a stable sort.
   5747 			 */
   5748 			displayMaster.sort( function ( a, b ) {
   5749 				var
   5750 					x, y, k, test, sort,
   5751 					len=aSort.length,
   5752 					dataA = aoData[a]._aSortData,
   5753 					dataB = aoData[b]._aSortData;
   5754 	
   5755 				for ( k=0 ; k<len ; k++ ) {
   5756 					sort = aSort[k];
   5757 	
   5758 					// Data, which may have already been through a `-pre` function
   5759 					x = dataA[ sort.col ];
   5760 					y = dataB[ sort.col ];
   5761 	
   5762 					if (sort.sorter) {
   5763 						// If there is a custom sorter (`-asc` or `-desc`) for this
   5764 						// data type, use it
   5765 						test = sort.sorter(x, y);
   5766 	
   5767 						if ( test !== 0 ) {
   5768 							return test;
   5769 						}
   5770 					}
   5771 					else {
   5772 						// Otherwise, use generic sorting
   5773 						test = x<y ? -1 : x>y ? 1 : 0;
   5774 	
   5775 						if ( test !== 0 ) {
   5776 							return sort.dir === 'asc' ? test : -test;
   5777 						}
   5778 					}
   5779 				}
   5780 	
   5781 				x = aiOrig[a];
   5782 				y = aiOrig[b];
   5783 	
   5784 				return x<y ? -1 : x>y ? 1 : 0;
   5785 			} );
   5786 		}
   5787 		else if ( aSort.length === 0 ) {
   5788 			// Apply index order
   5789 			displayMaster.sort(function (x, y) {
   5790 				return x<y ? -1 : x>y ? 1 : 0;
   5791 			});
   5792 		}
   5793 	
   5794 		if (col === undefined) {
   5795 			// Tell the draw function that we have sorted the data
   5796 			oSettings.bSorted = true;
   5797 	
   5798 			_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort] );
   5799 		}
   5800 	
   5801 		return displayMaster;
   5802 	}
   5803 	
   5804 	
   5805 	/**
   5806 	 * Function to run on user sort request
   5807 	 *  @param {object} settings dataTables settings object
   5808 	 *  @param {node} attachTo node to attach the handler to
   5809 	 *  @param {int} colIdx column sorting index
   5810 	 *  @param {int} addIndex Counter
   5811 	 *  @param {boolean} [shift=false] Shift click add
   5812 	 *  @param {function} [callback] callback function
   5813 	 *  @memberof DataTable#oApi
   5814 	 */
   5815 	function _fnSortAdd ( settings, colIdx, addIndex, shift )
   5816 	{
   5817 		var col = settings.aoColumns[ colIdx ];
   5818 		var sorting = settings.aaSorting;
   5819 		var asSorting = col.asSorting;
   5820 		var nextSortIdx;
   5821 		var next = function ( a, overflow ) {
   5822 			var idx = a._idx;
   5823 			if ( idx === undefined ) {
   5824 				idx = asSorting.indexOf(a[1]);
   5825 			}
   5826 	
   5827 			return idx+1 < asSorting.length ?
   5828 				idx+1 :
   5829 				overflow ?
   5830 					null :
   5831 					0;
   5832 		};
   5833 	
   5834 		if ( ! col.bSortable ) {
   5835 			return false;
   5836 		}
   5837 	
   5838 		// Convert to 2D array if needed
   5839 		if ( typeof sorting[0] === 'number' ) {
   5840 			sorting = settings.aaSorting = [ sorting ];
   5841 		}
   5842 	
   5843 		// If appending the sort then we are multi-column sorting
   5844 		if ( (shift || addIndex) && settings.oFeatures.bSortMulti ) {
   5845 			// Are we already doing some kind of sort on this column?
   5846 			var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
   5847 	
   5848 			if ( sortIdx !== -1 ) {
   5849 				// Yes, modify the sort
   5850 				nextSortIdx = next( sorting[sortIdx], true );
   5851 	
   5852 				if ( nextSortIdx === null && sorting.length === 1 ) {
   5853 					nextSortIdx = 0; // can't remove sorting completely
   5854 				}
   5855 	
   5856 				if ( nextSortIdx === null ) {
   5857 					sorting.splice( sortIdx, 1 );
   5858 				}
   5859 				else {
   5860 					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
   5861 					sorting[sortIdx]._idx = nextSortIdx;
   5862 				}
   5863 			}
   5864 			else if (shift) {
   5865 				// No sort on this column yet, being added by shift click
   5866 				// add it as itself
   5867 				sorting.push( [ colIdx, asSorting[0], 0 ] );
   5868 				sorting[sorting.length-1]._idx = 0;
   5869 			}
   5870 			else {
   5871 				// No sort on this column yet, being added from a colspan
   5872 				// so add with same direction as first column
   5873 				sorting.push( [ colIdx, sorting[0][1], 0 ] );
   5874 				sorting[sorting.length-1]._idx = 0;
   5875 			}
   5876 		}
   5877 		else if ( sorting.length && sorting[0][0] == colIdx ) {
   5878 			// Single column - already sorting on this column, modify the sort
   5879 			nextSortIdx = next( sorting[0] );
   5880 	
   5881 			sorting.length = 1;
   5882 			sorting[0][1] = asSorting[ nextSortIdx ];
   5883 			sorting[0]._idx = nextSortIdx;
   5884 		}
   5885 		else {
   5886 			// Single column - sort only on this column
   5887 			sorting.length = 0;
   5888 			sorting.push( [ colIdx, asSorting[0] ] );
   5889 			sorting[0]._idx = 0;
   5890 		}
   5891 	}
   5892 	
   5893 	
   5894 	/**
   5895 	 * Set the sorting classes on table's body, Note: it is safe to call this function
   5896 	 * when bSort and bSortClasses are false
   5897 	 *  @param {object} oSettings dataTables settings object
   5898 	 *  @memberof DataTable#oApi
   5899 	 */
   5900 	function _fnSortingClasses( settings )
   5901 	{
   5902 		var oldSort = settings.aLastSort;
   5903 		var sortClass = settings.oClasses.order.position;
   5904 		var sort = _fnSortFlatten( settings );
   5905 		var features = settings.oFeatures;
   5906 		var i, ien, colIdx;
   5907 	
   5908 		if ( features.bSort && features.bSortClasses ) {
   5909 			// Remove old sorting classes
   5910 			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
   5911 				colIdx = oldSort[i].src;
   5912 	
   5913 				// Remove column sorting
   5914 				$( _pluck( settings.aoData, 'anCells', colIdx ) )
   5915 					.removeClass( sortClass + (i<2 ? i+1 : 3) );
   5916 			}
   5917 	
   5918 			// Add new column sorting
   5919 			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
   5920 				colIdx = sort[i].src;
   5921 	
   5922 				$( _pluck( settings.aoData, 'anCells', colIdx ) )
   5923 					.addClass( sortClass + (i<2 ? i+1 : 3) );
   5924 			}
   5925 		}
   5926 	
   5927 		settings.aLastSort = sort;
   5928 	}
   5929 	
   5930 	
   5931 	// Get the data to sort a column, be it from cache, fresh (populating the
   5932 	// cache), or from a sort formatter
   5933 	function _fnSortData( settings, colIdx )
   5934 	{
   5935 		// Custom sorting function - provided by the sort data type
   5936 		var column = settings.aoColumns[ colIdx ];
   5937 		var customSort = DataTable.ext.order[ column.sSortDataType ];
   5938 		var customData;
   5939 	
   5940 		if ( customSort ) {
   5941 			customData = customSort.call( settings.oInstance, settings, colIdx,
   5942 				_fnColumnIndexToVisible( settings, colIdx )
   5943 			);
   5944 		}
   5945 	
   5946 		// Use / populate cache
   5947 		var row, cellData;
   5948 		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
   5949 		var data = settings.aoData;
   5950 	
   5951 		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
   5952 			// Sparse array
   5953 			if (! data[rowIdx]) {
   5954 				continue;
   5955 			}
   5956 	
   5957 			row = data[rowIdx];
   5958 	
   5959 			if ( ! row._aSortData ) {
   5960 				row._aSortData = [];
   5961 			}
   5962 	
   5963 			if ( ! row._aSortData[colIdx] || customSort ) {
   5964 				cellData = customSort ?
   5965 					customData[rowIdx] : // If there was a custom sort function, use data from there
   5966 					_fnGetCellData( settings, rowIdx, colIdx, 'sort' );
   5967 	
   5968 				row._aSortData[ colIdx ] = formatter ?
   5969 					formatter( cellData, settings ) :
   5970 					cellData;
   5971 			}
   5972 		}
   5973 	}
   5974 	
   5975 	
   5976 	/**
   5977 	 * State information for a table
   5978 	 *
   5979 	 * @param {*} settings
   5980 	 * @returns State object
   5981 	 */
   5982 	function _fnSaveState ( settings )
   5983 	{
   5984 		if (settings._bLoadingState) {
   5985 			return;
   5986 		}
   5987 	
   5988 		/* Store the interesting variables */
   5989 		var state = {
   5990 			time:    +new Date(),
   5991 			start:   settings._iDisplayStart,
   5992 			length:  settings._iDisplayLength,
   5993 			order:   $.extend( true, [], settings.aaSorting ),
   5994 			search:  $.extend({}, settings.oPreviousSearch),
   5995 			columns: settings.aoColumns.map( function ( col, i ) {
   5996 				return {
   5997 					visible: col.bVisible,
   5998 					search: $.extend({}, settings.aoPreSearchCols[i])
   5999 				};
   6000 			} )
   6001 		};
   6002 	
   6003 		settings.oSavedState = state;
   6004 		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
   6005 		
   6006 		if ( settings.oFeatures.bStateSave && !settings.bDestroying )
   6007 		{
   6008 			settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
   6009 		}	
   6010 	}
   6011 	
   6012 	
   6013 	/**
   6014 	 * Attempt to load a saved table state
   6015 	 *  @param {object} oSettings dataTables settings object
   6016 	 *  @param {object} oInit DataTables init object so we can override settings
   6017 	 *  @param {function} callback Callback to execute when the state has been loaded
   6018 	 *  @memberof DataTable#oApi
   6019 	 */
   6020 	function _fnLoadState ( settings, init, callback )
   6021 	{
   6022 		if ( ! settings.oFeatures.bStateSave ) {
   6023 			callback();
   6024 			return;
   6025 		}
   6026 	
   6027 		var loaded = function(state) {
   6028 			_fnImplementState(settings, state, callback);
   6029 		}
   6030 	
   6031 		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
   6032 	
   6033 		if ( state !== undefined ) {
   6034 			_fnImplementState( settings, state, callback );
   6035 		}
   6036 		// otherwise, wait for the loaded callback to be executed
   6037 	
   6038 		return true;
   6039 	}
   6040 	
   6041 	function _fnImplementState ( settings, s, callback) {
   6042 		var i, ien;
   6043 		var columns = settings.aoColumns;
   6044 		settings._bLoadingState = true;
   6045 	
   6046 		// When StateRestore was introduced the state could now be implemented at any time
   6047 		// Not just initialisation. To do this an api instance is required in some places
   6048 		var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
   6049 	
   6050 		if ( ! s || ! s.time ) {
   6051 			settings._bLoadingState = false;
   6052 			callback();
   6053 			return;
   6054 		}
   6055 	
   6056 		// Reject old data
   6057 		var duration = settings.iStateDuration;
   6058 		if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
   6059 			settings._bLoadingState = false;
   6060 			callback();
   6061 			return;
   6062 		}
   6063 	
   6064 		// Allow custom and plug-in manipulation functions to alter the saved data set and
   6065 		// cancelling of loading by returning false
   6066 		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
   6067 		if ( abStateLoad.indexOf(false) !== -1 ) {
   6068 			settings._bLoadingState = false;
   6069 			callback();
   6070 			return;
   6071 		}
   6072 	
   6073 		// Number of columns have changed - all bets are off, no restore of settings
   6074 		if ( s.columns && columns.length !== s.columns.length ) {
   6075 			settings._bLoadingState = false;
   6076 			callback();
   6077 			return;
   6078 		}
   6079 	
   6080 		// Store the saved state so it might be accessed at any time
   6081 		settings.oLoadedState = $.extend( true, {}, s );
   6082 	
   6083 		// This is needed for ColReorder, which has to happen first to allow all
   6084 		// the stored indexes to be usable. It is not publicly documented.
   6085 		_fnCallbackFire( settings, null, 'stateLoadInit', [settings, s], true );
   6086 	
   6087 		// Page Length
   6088 		if ( s.length !== undefined ) {
   6089 			// If already initialised just set the value directly so that the select element is also updated
   6090 			if (api) {
   6091 				api.page.len(s.length)
   6092 			}
   6093 			else {
   6094 				settings._iDisplayLength   = s.length;
   6095 			}
   6096 		}
   6097 	
   6098 		// Restore key features - todo - for 1.11 this needs to be done by
   6099 		// subscribed events
   6100 		if ( s.start !== undefined ) {
   6101 			if(api === null) {
   6102 				settings._iDisplayStart    = s.start;
   6103 				settings.iInitDisplayStart = s.start;
   6104 			}
   6105 			else {
   6106 				_fnPageChange(settings, s.start/settings._iDisplayLength);
   6107 			}
   6108 		}
   6109 	
   6110 		// Order
   6111 		if ( s.order !== undefined ) {
   6112 			settings.aaSorting = [];
   6113 			$.each( s.order, function ( i, col ) {
   6114 				settings.aaSorting.push( col[0] >= columns.length ?
   6115 					[ 0, col[1] ] :
   6116 					col
   6117 				);
   6118 			} );
   6119 		}
   6120 	
   6121 		// Search
   6122 		if ( s.search !== undefined ) {
   6123 			$.extend( settings.oPreviousSearch, s.search );
   6124 		}
   6125 	
   6126 		// Columns
   6127 		if ( s.columns ) {
   6128 			for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
   6129 				var col = s.columns[i];
   6130 	
   6131 				// Visibility
   6132 				if ( col.visible !== undefined ) {
   6133 					// If the api is defined, the table has been initialised so we need to use it rather than internal settings
   6134 					if (api) {
   6135 						// Don't redraw the columns on every iteration of this loop, we will do this at the end instead
   6136 						api.column(i).visible(col.visible, false);
   6137 					}
   6138 					else {
   6139 						columns[i].bVisible = col.visible;
   6140 					}
   6141 				}
   6142 	
   6143 				// Search
   6144 				if ( col.search !== undefined ) {
   6145 					$.extend( settings.aoPreSearchCols[i], col.search );
   6146 				}
   6147 			}
   6148 			
   6149 			// If the api is defined then we need to adjust the columns once the visibility has been changed
   6150 			if (api) {
   6151 				api.columns.adjust();
   6152 			}
   6153 		}
   6154 	
   6155 		settings._bLoadingState = false;
   6156 		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
   6157 		callback();
   6158 	}
   6159 	
   6160 	/**
   6161 	 * Log an error message
   6162 	 *  @param {object} settings dataTables settings object
   6163 	 *  @param {int} level log error messages, or display them to the user
   6164 	 *  @param {string} msg error message
   6165 	 *  @param {int} tn Technical note id to get more information about the error.
   6166 	 *  @memberof DataTable#oApi
   6167 	 */
   6168 	function _fnLog( settings, level, msg, tn )
   6169 	{
   6170 		msg = 'DataTables warning: '+
   6171 			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
   6172 	
   6173 		if ( tn ) {
   6174 			msg += '. For more information about this error, please see '+
   6175 			'https://datatables.net/tn/'+tn;
   6176 		}
   6177 	
   6178 		if ( ! level  ) {
   6179 			// Backwards compatibility pre 1.10
   6180 			var ext = DataTable.ext;
   6181 			var type = ext.sErrMode || ext.errMode;
   6182 	
   6183 			if ( settings ) {
   6184 				_fnCallbackFire( settings, null, 'dt-error', [ settings, tn, msg ], true );
   6185 			}
   6186 	
   6187 			if ( type == 'alert' ) {
   6188 				alert( msg );
   6189 			}
   6190 			else if ( type == 'throw' ) {
   6191 				throw new Error(msg);
   6192 			}
   6193 			else if ( typeof type == 'function' ) {
   6194 				type( settings, tn, msg );
   6195 			}
   6196 		}
   6197 		else if ( window.console && console.log ) {
   6198 			console.log( msg );
   6199 		}
   6200 	}
   6201 	
   6202 	
   6203 	/**
   6204 	 * See if a property is defined on one object, if so assign it to the other object
   6205 	 *  @param {object} ret target object
   6206 	 *  @param {object} src source object
   6207 	 *  @param {string} name property
   6208 	 *  @param {string} [mappedName] name to map too - optional, name used if not given
   6209 	 *  @memberof DataTable#oApi
   6210 	 */
   6211 	function _fnMap( ret, src, name, mappedName )
   6212 	{
   6213 		if ( Array.isArray( name ) ) {
   6214 			$.each( name, function (i, val) {
   6215 				if ( Array.isArray( val ) ) {
   6216 					_fnMap( ret, src, val[0], val[1] );
   6217 				}
   6218 				else {
   6219 					_fnMap( ret, src, val );
   6220 				}
   6221 			} );
   6222 	
   6223 			return;
   6224 		}
   6225 	
   6226 		if ( mappedName === undefined ) {
   6227 			mappedName = name;
   6228 		}
   6229 	
   6230 		if ( src[name] !== undefined ) {
   6231 			ret[mappedName] = src[name];
   6232 		}
   6233 	}
   6234 	
   6235 	
   6236 	/**
   6237 	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
   6238 	 * shallow copy arrays. The reason we need to do this, is that we don't want to
   6239 	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
   6240 	 * able to override them, but we do want to deep copy arrays.
   6241 	 *  @param {object} out Object to extend
   6242 	 *  @param {object} extender Object from which the properties will be applied to
   6243 	 *      out
   6244 	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
   6245 	 *      independent copy with the exception of the `data` or `aaData` parameters
   6246 	 *      if they are present. This is so you can pass in a collection to
   6247 	 *      DataTables and have that used as your data source without breaking the
   6248 	 *      references
   6249 	 *  @returns {object} out Reference, just for convenience - out === the return.
   6250 	 *  @memberof DataTable#oApi
   6251 	 *  @todo This doesn't take account of arrays inside the deep copied objects.
   6252 	 */
   6253 	function _fnExtend( out, extender, breakRefs )
   6254 	{
   6255 		var val;
   6256 	
   6257 		for ( var prop in extender ) {
   6258 			if ( Object.prototype.hasOwnProperty.call(extender, prop) ) {
   6259 				val = extender[prop];
   6260 	
   6261 				if ( $.isPlainObject( val ) ) {
   6262 					if ( ! $.isPlainObject( out[prop] ) ) {
   6263 						out[prop] = {};
   6264 					}
   6265 					$.extend( true, out[prop], val );
   6266 				}
   6267 				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {
   6268 					out[prop] = val.slice();
   6269 				}
   6270 				else {
   6271 					out[prop] = val;
   6272 				}
   6273 			}
   6274 		}
   6275 	
   6276 		return out;
   6277 	}
   6278 	
   6279 	
   6280 	/**
   6281 	 * Bind an event handers to allow a click or return key to activate the callback.
   6282 	 * This is good for accessibility since a return on the keyboard will have the
   6283 	 * same effect as a click, if the element has focus.
   6284 	 *  @param {element} n Element to bind the action to
   6285 	 *  @param {object|string} selector Selector (for delegated events) or data object
   6286 	 *   to pass to the triggered function
   6287 	 *  @param {function} fn Callback function for when the event is triggered
   6288 	 *  @memberof DataTable#oApi
   6289 	 */
   6290 	function _fnBindAction( n, selector, fn )
   6291 	{
   6292 		$(n)
   6293 			.on( 'click.DT', selector, function (e) {
   6294 				fn(e);
   6295 			} )
   6296 			.on( 'keypress.DT', selector, function (e){
   6297 				if ( e.which === 13 ) {
   6298 					e.preventDefault();
   6299 					fn(e);
   6300 				}
   6301 			} )
   6302 			.on( 'selectstart.DT', selector, function () {
   6303 				// Don't want a double click resulting in text selection
   6304 				return false;
   6305 			} );
   6306 	}
   6307 	
   6308 	
   6309 	/**
   6310 	 * Register a callback function. Easily allows a callback function to be added to
   6311 	 * an array store of callback functions that can then all be called together.
   6312 	 *  @param {object} settings dataTables settings object
   6313 	 *  @param {string} store Name of the array storage for the callbacks in oSettings
   6314 	 *  @param {function} fn Function to be called back
   6315 	 *  @memberof DataTable#oApi
   6316 	 */
   6317 	function _fnCallbackReg( settings, store, fn )
   6318 	{
   6319 		if ( fn ) {
   6320 			settings[store].push(fn);
   6321 		}
   6322 	}
   6323 	
   6324 	
   6325 	/**
   6326 	 * Fire callback functions and trigger events. Note that the loop over the
   6327 	 * callback array store is done backwards! Further note that you do not want to
   6328 	 * fire off triggers in time sensitive applications (for example cell creation)
   6329 	 * as its slow.
   6330 	 *  @param {object} settings dataTables settings object
   6331 	 *  @param {string} callbackArr Name of the array storage for the callbacks in
   6332 	 *      oSettings
   6333 	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
   6334 	 *      null no trigger is fired
   6335 	 *  @param {array} args Array of arguments to pass to the callback function /
   6336 	 *      trigger
   6337 	 *  @param {boolean} [bubbles] True if the event should bubble
   6338 	 *  @memberof DataTable#oApi
   6339 	 */
   6340 	function _fnCallbackFire( settings, callbackArr, eventName, args, bubbles )
   6341 	{
   6342 		var ret = [];
   6343 	
   6344 		if ( callbackArr ) {
   6345 			ret = settings[callbackArr].slice().reverse().map( function (val) {
   6346 				return val.apply( settings.oInstance, args );
   6347 			} );
   6348 		}
   6349 	
   6350 		if ( eventName !== null) {
   6351 			var e = $.Event( eventName+'.dt' );
   6352 			var table = $(settings.nTable);
   6353 			
   6354 			// Expose the DataTables API on the event object for easy access
   6355 			e.dt = settings.api;
   6356 	
   6357 			table[bubbles ?  'trigger' : 'triggerHandler']( e, args );
   6358 	
   6359 			// If not yet attached to the document, trigger the event
   6360 			// on the body directly to sort of simulate the bubble
   6361 			if (bubbles && table.parents('body').length === 0) {
   6362 				$('body').trigger( e, args );
   6363 			}
   6364 	
   6365 			ret.push( e.result );
   6366 		}
   6367 	
   6368 		return ret;
   6369 	}
   6370 	
   6371 	
   6372 	function _fnLengthOverflow ( settings )
   6373 	{
   6374 		var
   6375 			start = settings._iDisplayStart,
   6376 			end = settings.fnDisplayEnd(),
   6377 			len = settings._iDisplayLength;
   6378 	
   6379 		/* If we have space to show extra rows (backing up from the end point - then do so */
   6380 		if ( start >= end )
   6381 		{
   6382 			start = end - len;
   6383 		}
   6384 	
   6385 		// Keep the start record on the current page
   6386 		start -= (start % len);
   6387 	
   6388 		if ( len === -1 || start < 0 )
   6389 		{
   6390 			start = 0;
   6391 		}
   6392 	
   6393 		settings._iDisplayStart = start;
   6394 	}
   6395 	
   6396 	
   6397 	function _fnRenderer( settings, type )
   6398 	{
   6399 		var renderer = settings.renderer;
   6400 		var host = DataTable.ext.renderer[type];
   6401 	
   6402 		if ( $.isPlainObject( renderer ) && renderer[type] ) {
   6403 			// Specific renderer for this type. If available use it, otherwise use
   6404 			// the default.
   6405 			return host[renderer[type]] || host._;
   6406 		}
   6407 		else if ( typeof renderer === 'string' ) {
   6408 			// Common renderer - if there is one available for this type use it,
   6409 			// otherwise use the default
   6410 			return host[renderer] || host._;
   6411 		}
   6412 	
   6413 		// Use the default
   6414 		return host._;
   6415 	}
   6416 	
   6417 	
   6418 	/**
   6419 	 * Detect the data source being used for the table. Used to simplify the code
   6420 	 * a little (ajax) and to make it compress a little smaller.
   6421 	 *
   6422 	 *  @param {object} settings dataTables settings object
   6423 	 *  @returns {string} Data source
   6424 	 *  @memberof DataTable#oApi
   6425 	 */
   6426 	function _fnDataSource ( settings )
   6427 	{
   6428 		if ( settings.oFeatures.bServerSide ) {
   6429 			return 'ssp';
   6430 		}
   6431 		else if ( settings.ajax ) {
   6432 			return 'ajax';
   6433 		}
   6434 		return 'dom';
   6435 	}
   6436 	
   6437 	/**
   6438 	 * Common replacement for language strings
   6439 	 *
   6440 	 * @param {*} settings DT settings object
   6441 	 * @param {*} str String with values to replace
   6442 	 * @param {*} entries Plural number for _ENTRIES_ - can be undefined
   6443 	 * @returns String
   6444 	 */
   6445 	function _fnMacros ( settings, str, entries )
   6446 	{
   6447 		// When infinite scrolling, we are always starting at 1. _iDisplayStart is
   6448 		// used only internally
   6449 		var
   6450 			formatter  = settings.fnFormatNumber,
   6451 			start      = settings._iDisplayStart+1,
   6452 			len        = settings._iDisplayLength,
   6453 			vis        = settings.fnRecordsDisplay(),
   6454 			max        = settings.fnRecordsTotal(),
   6455 			all        = len === -1;
   6456 	
   6457 		return str.
   6458 			replace(/_START_/g, formatter.call( settings, start ) ).
   6459 			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
   6460 			replace(/_MAX_/g,   formatter.call( settings, max ) ).
   6461 			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
   6462 			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
   6463 			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ).
   6464 			replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries) ).
   6465 			replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max) ).
   6466 			replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
   6467 	}
   6468 	
   6469 	
   6470 	
   6471 	/**
   6472 	 * Computed structure of the DataTables API, defined by the options passed to
   6473 	 * `DataTable.Api.register()` when building the API.
   6474 	 *
   6475 	 * The structure is built in order to speed creation and extension of the Api
   6476 	 * objects since the extensions are effectively pre-parsed.
   6477 	 *
   6478 	 * The array is an array of objects with the following structure, where this
   6479 	 * base array represents the Api prototype base:
   6480 	 *
   6481 	 *     [
   6482 	 *       {
   6483 	 *         name:      'data'                -- string   - Property name
   6484 	 *         val:       function () {},       -- function - Api method (or undefined if just an object
   6485 	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
   6486 	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
   6487 	 *       },
   6488 	 *       {
   6489 	 *         name:     'row'
   6490 	 *         val:       {},
   6491 	 *         methodExt: [ ... ],
   6492 	 *         propExt:   [
   6493 	 *           {
   6494 	 *             name:      'data'
   6495 	 *             val:       function () {},
   6496 	 *             methodExt: [ ... ],
   6497 	 *             propExt:   [ ... ]
   6498 	 *           },
   6499 	 *           ...
   6500 	 *         ]
   6501 	 *       }
   6502 	 *     ]
   6503 	 *
   6504 	 * @type {Array}
   6505 	 * @ignore
   6506 	 */
   6507 	var __apiStruct = [];
   6508 	
   6509 	
   6510 	/**
   6511 	 * `Array.prototype` reference.
   6512 	 *
   6513 	 * @type object
   6514 	 * @ignore
   6515 	 */
   6516 	var __arrayProto = Array.prototype;
   6517 	
   6518 	
   6519 	/**
   6520 	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
   6521 	 * take several different forms for ease of use.
   6522 	 *
   6523 	 * Each of the input parameter types will be converted to a DataTables settings
   6524 	 * object where possible.
   6525 	 *
   6526 	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
   6527 	 *   of:
   6528 	 *
   6529 	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
   6530 	 *     with be found and used.
   6531 	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
   6532 	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
   6533 	 *   * `object` - DataTables settings object
   6534 	 *   * `DataTables.Api` - API instance
   6535 	 * @return {array|null} Matching DataTables settings objects. `null` or
   6536 	 *   `undefined` is returned if no matching DataTable is found.
   6537 	 * @ignore
   6538 	 */
   6539 	var _toSettings = function ( mixed )
   6540 	{
   6541 		var idx, jq;
   6542 		var settings = DataTable.settings;
   6543 		var tables = _pluck(settings, 'nTable');
   6544 	
   6545 		if ( ! mixed ) {
   6546 			return [];
   6547 		}
   6548 		else if ( mixed.nTable && mixed.oFeatures ) {
   6549 			// DataTables settings object
   6550 			return [ mixed ];
   6551 		}
   6552 		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
   6553 			// Table node
   6554 			idx = tables.indexOf(mixed);
   6555 			return idx !== -1 ? [ settings[idx] ] : null;
   6556 		}
   6557 		else if ( mixed && typeof mixed.settings === 'function' ) {
   6558 			return mixed.settings().toArray();
   6559 		}
   6560 		else if ( typeof mixed === 'string' ) {
   6561 			// jQuery selector
   6562 			jq = $(mixed).get();
   6563 		}
   6564 		else if ( mixed instanceof $ ) {
   6565 			// jQuery object (also DataTables instance)
   6566 			jq = mixed.get();
   6567 		}
   6568 	
   6569 		if ( jq ) {
   6570 			return settings.filter(function (v, idx) {
   6571 				return jq.includes(tables[idx]);
   6572 			});
   6573 		}
   6574 	};
   6575 	
   6576 	
   6577 	/**
   6578 	 * DataTables API class - used to control and interface with  one or more
   6579 	 * DataTables enhanced tables.
   6580 	 *
   6581 	 * The API class is heavily based on jQuery, presenting a chainable interface
   6582 	 * that you can use to interact with tables. Each instance of the API class has
   6583 	 * a "context" - i.e. the tables that it will operate on. This could be a single
   6584 	 * table, all tables on a page or a sub-set thereof.
   6585 	 *
   6586 	 * Additionally the API is designed to allow you to easily work with the data in
   6587 	 * the tables, retrieving and manipulating it as required. This is done by
   6588 	 * presenting the API class as an array like interface. The contents of the
   6589 	 * array depend upon the actions requested by each method (for example
   6590 	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
   6591 	 * return an array of objects or arrays depending upon your table's
   6592 	 * configuration). The API object has a number of array like methods (`push`,
   6593 	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
   6594 	 * `unique` etc) to assist your working with the data held in a table.
   6595 	 *
   6596 	 * Most methods (those which return an Api instance) are chainable, which means
   6597 	 * the return from a method call also has all of the methods available that the
   6598 	 * top level object had. For example, these two calls are equivalent:
   6599 	 *
   6600 	 *     // Not chained
   6601 	 *     api.row.add( {...} );
   6602 	 *     api.draw();
   6603 	 *
   6604 	 *     // Chained
   6605 	 *     api.row.add( {...} ).draw();
   6606 	 *
   6607 	 * @class DataTable.Api
   6608 	 * @param {array|object|string|jQuery} context DataTable identifier. This is
   6609 	 *   used to define which DataTables enhanced tables this API will operate on.
   6610 	 *   Can be one of:
   6611 	 *
   6612 	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
   6613 	 *     with be found and used.
   6614 	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
   6615 	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
   6616 	 *   * `object` - DataTables settings object
   6617 	 * @param {array} [data] Data to initialise the Api instance with.
   6618 	 *
   6619 	 * @example
   6620 	 *   // Direct initialisation during DataTables construction
   6621 	 *   var api = $('#example').DataTable();
   6622 	 *
   6623 	 * @example
   6624 	 *   // Initialisation using a DataTables jQuery object
   6625 	 *   var api = $('#example').dataTable().api();
   6626 	 *
   6627 	 * @example
   6628 	 *   // Initialisation as a constructor
   6629 	 *   var api = new DataTable.Api( 'table.dataTable' );
   6630 	 */
   6631 	_Api = function ( context, data )
   6632 	{
   6633 		if ( ! (this instanceof _Api) ) {
   6634 			return new _Api( context, data );
   6635 		}
   6636 	
   6637 		var settings = [];
   6638 		var ctxSettings = function ( o ) {
   6639 			var a = _toSettings( o );
   6640 			if ( a ) {
   6641 				settings.push.apply( settings, a );
   6642 			}
   6643 		};
   6644 	
   6645 		if ( Array.isArray( context ) ) {
   6646 			for ( var i=0, ien=context.length ; i<ien ; i++ ) {
   6647 				ctxSettings( context[i] );
   6648 			}
   6649 		}
   6650 		else {
   6651 			ctxSettings( context );
   6652 		}
   6653 	
   6654 		// Remove duplicates
   6655 		this.context = settings.length > 1
   6656 			? _unique( settings )
   6657 			: settings;
   6658 	
   6659 		// Initial data
   6660 		if ( data ) {
   6661 			this.push.apply(this, data);
   6662 		}
   6663 	
   6664 		// selector
   6665 		this.selector = {
   6666 			rows: null,
   6667 			cols: null,
   6668 			opts: null
   6669 		};
   6670 	
   6671 		_Api.extend( this, this, __apiStruct );
   6672 	};
   6673 	
   6674 	DataTable.Api = _Api;
   6675 	
   6676 	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
   6677 	// isPlainObject.
   6678 	$.extend( _Api.prototype, {
   6679 		any: function ()
   6680 		{
   6681 			return this.count() !== 0;
   6682 		},
   6683 	
   6684 		context: [], // array of table settings objects
   6685 	
   6686 		count: function ()
   6687 		{
   6688 			return this.flatten().length;
   6689 		},
   6690 	
   6691 		each: function ( fn )
   6692 		{
   6693 			for ( var i=0, ien=this.length ; i<ien; i++ ) {
   6694 				fn.call( this, this[i], i, this );
   6695 			}
   6696 	
   6697 			return this;
   6698 		},
   6699 	
   6700 		eq: function ( idx )
   6701 		{
   6702 			var ctx = this.context;
   6703 	
   6704 			return ctx.length > idx ?
   6705 				new _Api( ctx[idx], this[idx] ) :
   6706 				null;
   6707 		},
   6708 	
   6709 		filter: function ( fn )
   6710 		{
   6711 			var a = __arrayProto.filter.call( this, fn, this );
   6712 	
   6713 			return new _Api( this.context, a );
   6714 		},
   6715 	
   6716 		flatten: function ()
   6717 		{
   6718 			var a = [];
   6719 	
   6720 			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
   6721 		},
   6722 	
   6723 		get: function ( idx )
   6724 		{
   6725 			return this[ idx ];
   6726 		},
   6727 	
   6728 		join:    __arrayProto.join,
   6729 	
   6730 		includes: function ( find ) {
   6731 			return this.indexOf( find ) === -1 ? false : true;
   6732 		},
   6733 	
   6734 		indexOf: __arrayProto.indexOf,
   6735 	
   6736 		iterator: function ( flatten, type, fn, alwaysNew ) {
   6737 			var
   6738 				a = [], ret,
   6739 				i, ien, j, jen,
   6740 				context = this.context,
   6741 				rows, items, item,
   6742 				selector = this.selector;
   6743 	
   6744 			// Argument shifting
   6745 			if ( typeof flatten === 'string' ) {
   6746 				alwaysNew = fn;
   6747 				fn = type;
   6748 				type = flatten;
   6749 				flatten = false;
   6750 			}
   6751 	
   6752 			for ( i=0, ien=context.length ; i<ien ; i++ ) {
   6753 				var apiInst = new _Api( context[i] );
   6754 	
   6755 				if ( type === 'table' ) {
   6756 					ret = fn.call( apiInst, context[i], i );
   6757 	
   6758 					if ( ret !== undefined ) {
   6759 						a.push( ret );
   6760 					}
   6761 				}
   6762 				else if ( type === 'columns' || type === 'rows' ) {
   6763 					// this has same length as context - one entry for each table
   6764 					ret = fn.call( apiInst, context[i], this[i], i );
   6765 	
   6766 					if ( ret !== undefined ) {
   6767 						a.push( ret );
   6768 					}
   6769 				}
   6770 				else if ( type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
   6771 					// columns and rows share the same structure.
   6772 					// 'this' is an array of column indexes for each context
   6773 					items = this[i];
   6774 	
   6775 					if ( type === 'column-rows' ) {
   6776 						rows = _selector_row_indexes( context[i], selector.opts );
   6777 					}
   6778 	
   6779 					for ( j=0, jen=items.length ; j<jen ; j++ ) {
   6780 						item = items[j];
   6781 	
   6782 						if ( type === 'cell' ) {
   6783 							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
   6784 						}
   6785 						else {
   6786 							ret = fn.call( apiInst, context[i], item, i, j, rows );
   6787 						}
   6788 	
   6789 						if ( ret !== undefined ) {
   6790 							a.push( ret );
   6791 						}
   6792 					}
   6793 				}
   6794 			}
   6795 	
   6796 			if ( a.length || alwaysNew ) {
   6797 				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
   6798 				var apiSelector = api.selector;
   6799 				apiSelector.rows = selector.rows;
   6800 				apiSelector.cols = selector.cols;
   6801 				apiSelector.opts = selector.opts;
   6802 				return api;
   6803 			}
   6804 			return this;
   6805 		},
   6806 	
   6807 		lastIndexOf: __arrayProto.lastIndexOf,
   6808 	
   6809 		length:  0,
   6810 	
   6811 		map: function ( fn )
   6812 		{
   6813 			var a = __arrayProto.map.call( this, fn, this );
   6814 	
   6815 			return new _Api( this.context, a );
   6816 		},
   6817 	
   6818 		pluck: function ( prop )
   6819 		{
   6820 			var fn = DataTable.util.get(prop);
   6821 	
   6822 			return this.map( function ( el ) {
   6823 				return fn(el);
   6824 			} );
   6825 		},
   6826 	
   6827 		pop:     __arrayProto.pop,
   6828 	
   6829 		push:    __arrayProto.push,
   6830 	
   6831 		reduce: __arrayProto.reduce,
   6832 	
   6833 		reduceRight: __arrayProto.reduceRight,
   6834 	
   6835 		reverse: __arrayProto.reverse,
   6836 	
   6837 		// Object with rows, columns and opts
   6838 		selector: null,
   6839 	
   6840 		shift:   __arrayProto.shift,
   6841 	
   6842 		slice: function () {
   6843 			return new _Api( this.context, this );
   6844 		},
   6845 	
   6846 		sort:    __arrayProto.sort,
   6847 	
   6848 		splice:  __arrayProto.splice,
   6849 	
   6850 		toArray: function ()
   6851 		{
   6852 			return __arrayProto.slice.call( this );
   6853 		},
   6854 	
   6855 		to$: function ()
   6856 		{
   6857 			return $( this );
   6858 		},
   6859 	
   6860 		toJQuery: function ()
   6861 		{
   6862 			return $( this );
   6863 		},
   6864 	
   6865 		unique: function ()
   6866 		{
   6867 			return new _Api( this.context, _unique(this.toArray()) );
   6868 		},
   6869 	
   6870 		unshift: __arrayProto.unshift
   6871 	} );
   6872 	
   6873 	
   6874 	function _api_scope( scope, fn, struc ) {
   6875 		return function () {
   6876 			var ret = fn.apply( scope || this, arguments );
   6877 	
   6878 			// Method extension
   6879 			_Api.extend( ret, ret, struc.methodExt );
   6880 			return ret;
   6881 		};
   6882 	}
   6883 	
   6884 	function _api_find( src, name ) {
   6885 		for ( var i=0, ien=src.length ; i<ien ; i++ ) {
   6886 			if ( src[i].name === name ) {
   6887 				return src[i];
   6888 			}
   6889 		}
   6890 		return null;
   6891 	}
   6892 	
   6893 	window.__apiStruct = __apiStruct;
   6894 	
   6895 	_Api.extend = function ( scope, obj, ext )
   6896 	{
   6897 		// Only extend API instances and static properties of the API
   6898 		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
   6899 			return;
   6900 		}
   6901 	
   6902 		var
   6903 			i, ien,
   6904 			struct;
   6905 	
   6906 		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
   6907 			struct = ext[i];
   6908 	
   6909 			if (struct.name === '__proto__') {
   6910 				continue;
   6911 			}
   6912 	
   6913 			// Value
   6914 			obj[ struct.name ] = struct.type === 'function' ?
   6915 				_api_scope( scope, struct.val, struct ) :
   6916 				struct.type === 'object' ?
   6917 					{} :
   6918 					struct.val;
   6919 	
   6920 			obj[ struct.name ].__dt_wrapper = true;
   6921 	
   6922 			// Property extension
   6923 			_Api.extend( scope, obj[ struct.name ], struct.propExt );
   6924 		}
   6925 	};
   6926 	
   6927 	//     [
   6928 	//       {
   6929 	//         name:      'data'                -- string   - Property name
   6930 	//         val:       function () {},       -- function - Api method (or undefined if just an object
   6931 	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
   6932 	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
   6933 	//       },
   6934 	//       {
   6935 	//         name:     'row'
   6936 	//         val:       {},
   6937 	//         methodExt: [ ... ],
   6938 	//         propExt:   [
   6939 	//           {
   6940 	//             name:      'data'
   6941 	//             val:       function () {},
   6942 	//             methodExt: [ ... ],
   6943 	//             propExt:   [ ... ]
   6944 	//           },
   6945 	//           ...
   6946 	//         ]
   6947 	//       }
   6948 	//     ]
   6949 	
   6950 	
   6951 	_Api.register = _api_register = function ( name, val )
   6952 	{
   6953 		if ( Array.isArray( name ) ) {
   6954 			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
   6955 				_Api.register( name[j], val );
   6956 			}
   6957 			return;
   6958 		}
   6959 	
   6960 		var
   6961 			i, ien,
   6962 			heir = name.split('.'),
   6963 			struct = __apiStruct,
   6964 			key, method;
   6965 	
   6966 		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
   6967 			method = heir[i].indexOf('()') !== -1;
   6968 			key = method ?
   6969 				heir[i].replace('()', '') :
   6970 				heir[i];
   6971 	
   6972 			var src = _api_find( struct, key );
   6973 			if ( ! src ) {
   6974 				src = {
   6975 					name:      key,
   6976 					val:       {},
   6977 					methodExt: [],
   6978 					propExt:   [],
   6979 					type:      'object'
   6980 				};
   6981 				struct.push( src );
   6982 			}
   6983 	
   6984 			if ( i === ien-1 ) {
   6985 				src.val = val;
   6986 				src.type = typeof val === 'function' ?
   6987 					'function' :
   6988 					$.isPlainObject( val ) ?
   6989 						'object' :
   6990 						'other';
   6991 			}
   6992 			else {
   6993 				struct = method ?
   6994 					src.methodExt :
   6995 					src.propExt;
   6996 			}
   6997 		}
   6998 	};
   6999 	
   7000 	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
   7001 		_Api.register( pluralName, val );
   7002 	
   7003 		_Api.register( singularName, function () {
   7004 			var ret = val.apply( this, arguments );
   7005 	
   7006 			if ( ret === this ) {
   7007 				// Returned item is the API instance that was passed in, return it
   7008 				return this;
   7009 			}
   7010 			else if ( ret instanceof _Api ) {
   7011 				// New API instance returned, want the value from the first item
   7012 				// in the returned array for the singular result.
   7013 				return ret.length ?
   7014 					Array.isArray( ret[0] ) ?
   7015 						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
   7016 						ret[0] :
   7017 					undefined;
   7018 			}
   7019 	
   7020 			// Non-API return - just fire it back
   7021 			return ret;
   7022 		} );
   7023 	};
   7024 	
   7025 	
   7026 	/**
   7027 	 * Selector for HTML tables. Apply the given selector to the give array of
   7028 	 * DataTables settings objects.
   7029 	 *
   7030 	 * @param {string|integer} [selector] jQuery selector string or integer
   7031 	 * @param  {array} Array of DataTables settings objects to be filtered
   7032 	 * @return {array}
   7033 	 * @ignore
   7034 	 */
   7035 	var __table_selector = function ( selector, a )
   7036 	{
   7037 		if ( Array.isArray(selector) ) {
   7038 			var result = [];
   7039 	
   7040 			selector.forEach(function (sel) {
   7041 				var inner = __table_selector(sel, a);
   7042 	
   7043 				result.push.apply(result, inner);
   7044 			});
   7045 	
   7046 			return result.filter( function (item) {
   7047 				return item;
   7048 			});
   7049 		}
   7050 	
   7051 		// Integer is used to pick out a table by index
   7052 		if ( typeof selector === 'number' ) {
   7053 			return [ a[ selector ] ];
   7054 		}
   7055 	
   7056 		// Perform a jQuery selector on the table nodes
   7057 		var nodes = a.map( function (el) {
   7058 			return el.nTable;
   7059 		} );
   7060 	
   7061 		return $(nodes)
   7062 			.filter( selector )
   7063 			.map( function () {
   7064 				// Need to translate back from the table node to the settings
   7065 				var idx = nodes.indexOf(this);
   7066 				return a[ idx ];
   7067 			} )
   7068 			.toArray();
   7069 	};
   7070 	
   7071 	
   7072 	
   7073 	/**
   7074 	 * Context selector for the API's context (i.e. the tables the API instance
   7075 	 * refers to.
   7076 	 *
   7077 	 * @name    DataTable.Api#tables
   7078 	 * @param {string|integer} [selector] Selector to pick which tables the iterator
   7079 	 *   should operate on. If not given, all tables in the current context are
   7080 	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
   7081 	 *   select multiple tables or as an integer to select a single table.
   7082 	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
   7083 	 */
   7084 	_api_register( 'tables()', function ( selector ) {
   7085 		// A new instance is created if there was a selector specified
   7086 		return selector !== undefined && selector !== null ?
   7087 			new _Api( __table_selector( selector, this.context ) ) :
   7088 			this;
   7089 	} );
   7090 	
   7091 	
   7092 	_api_register( 'table()', function ( selector ) {
   7093 		var tables = this.tables( selector );
   7094 		var ctx = tables.context;
   7095 	
   7096 		// Truncate to the first matched table
   7097 		return ctx.length ?
   7098 			new _Api( ctx[0] ) :
   7099 			tables;
   7100 	} );
   7101 	
   7102 	// Common methods, combined to reduce size
   7103 	[
   7104 		['nodes', 'node', 'nTable'],
   7105 		['body', 'body', 'nTBody'],
   7106 		['header', 'header', 'nTHead'],
   7107 		['footer', 'footer', 'nTFoot'],
   7108 	].forEach(function (item) {
   7109 		_api_registerPlural(
   7110 			'tables().' + item[0] + '()',
   7111 			'table().' + item[1] + '()' ,
   7112 			function () {
   7113 				return this.iterator( 'table', function ( ctx ) {
   7114 					return ctx[item[2]];
   7115 				}, 1 );
   7116 			}
   7117 		);
   7118 	});
   7119 	
   7120 	// Structure methods
   7121 	[
   7122 		['header', 'aoHeader'],
   7123 		['footer', 'aoFooter'],
   7124 	].forEach(function (item) {
   7125 		_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
   7126 			var indexes = this.columns(selector).indexes().flatten();
   7127 			var ctx = this.context[0];
   7128 			
   7129 			return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
   7130 		} );
   7131 	})
   7132 	
   7133 	
   7134 	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
   7135 		return this.iterator( 'table', function ( ctx ) {
   7136 			return ctx.nTableWrapper;
   7137 		}, 1 );
   7138 	} );
   7139 	
   7140 	_api_register( 'tables().every()', function ( fn ) {
   7141 		var that = this;
   7142 	
   7143 		return this.iterator('table', function (s, i) {
   7144 			fn.call(that.table(i), i);
   7145 		});
   7146 	});
   7147 	
   7148 	_api_register( 'caption()', function ( value, side ) {
   7149 		var context = this.context;
   7150 	
   7151 		// Getter - return existing node's content
   7152 		if ( value === undefined ) {
   7153 			var caption = context[0].captionNode;
   7154 	
   7155 			return caption && context.length ?
   7156 				caption.innerHTML : 
   7157 				null;
   7158 		}
   7159 	
   7160 		return this.iterator( 'table', function ( ctx ) {
   7161 			var table = $(ctx.nTable);
   7162 			var caption = $(ctx.captionNode);
   7163 			var container = $(ctx.nTableWrapper);
   7164 	
   7165 			// Create the node if it doesn't exist yet
   7166 			if ( ! caption.length ) {
   7167 				caption = $('<caption/>').html( value );
   7168 				ctx.captionNode = caption[0];
   7169 	
   7170 				// If side isn't set, we need to insert into the document to let the
   7171 				// CSS decide so we can read it back, otherwise there is no way to
   7172 				// know if the CSS would put it top or bottom for scrolling
   7173 				if (! side) {
   7174 					table.prepend(caption);
   7175 	
   7176 					side = caption.css('caption-side');
   7177 				}
   7178 			}
   7179 	
   7180 			caption.html( value );
   7181 	
   7182 			if ( side ) {
   7183 				caption.css( 'caption-side', side );
   7184 				caption[0]._captionSide = side;
   7185 			}
   7186 	
   7187 			if (container.find('div.dataTables_scroll').length) {
   7188 				var selector = (side === 'top' ? 'Head' : 'Foot');
   7189 	
   7190 				container.find('div.dataTables_scroll'+ selector +' table').prepend(caption);
   7191 			}
   7192 			else {
   7193 				table.prepend(caption);
   7194 			}
   7195 		}, 1 );
   7196 	} );
   7197 	
   7198 	_api_register( 'caption.node()', function () {
   7199 		var ctx = this.context;
   7200 	
   7201 		return ctx.length ? ctx[0].captionNode : null;
   7202 	} );
   7203 	
   7204 	
   7205 	/**
   7206 	 * Redraw the tables in the current context.
   7207 	 */
   7208 	_api_register( 'draw()', function ( paging ) {
   7209 		return this.iterator( 'table', function ( settings ) {
   7210 			if ( paging === 'page' ) {
   7211 				_fnDraw( settings );
   7212 			}
   7213 			else {
   7214 				if ( typeof paging === 'string' ) {
   7215 					paging = paging === 'full-hold' ?
   7216 						false :
   7217 						true;
   7218 				}
   7219 	
   7220 				_fnReDraw( settings, paging===false );
   7221 			}
   7222 		} );
   7223 	} );
   7224 	
   7225 	
   7226 	
   7227 	/**
   7228 	 * Get the current page index.
   7229 	 *
   7230 	 * @return {integer} Current page index (zero based)
   7231 	 *//**
   7232 	 * Set the current page.
   7233 	 *
   7234 	 * Note that if you attempt to show a page which does not exist, DataTables will
   7235 	 * not throw an error, but rather reset the paging.
   7236 	 *
   7237 	 * @param {integer|string} action The paging action to take. This can be one of:
   7238 	 *  * `integer` - The page index to jump to
   7239 	 *  * `string` - An action to take:
   7240 	 *    * `first` - Jump to first page.
   7241 	 *    * `next` - Jump to the next page
   7242 	 *    * `previous` - Jump to previous page
   7243 	 *    * `last` - Jump to the last page.
   7244 	 * @returns {DataTables.Api} this
   7245 	 */
   7246 	_api_register( 'page()', function ( action ) {
   7247 		if ( action === undefined ) {
   7248 			return this.page.info().page; // not an expensive call
   7249 		}
   7250 	
   7251 		// else, have an action to take on all tables
   7252 		return this.iterator( 'table', function ( settings ) {
   7253 			_fnPageChange( settings, action );
   7254 		} );
   7255 	} );
   7256 	
   7257 	
   7258 	/**
   7259 	 * Paging information for the first table in the current context.
   7260 	 *
   7261 	 * If you require paging information for another table, use the `table()` method
   7262 	 * with a suitable selector.
   7263 	 *
   7264 	 * @return {object} Object with the following properties set:
   7265 	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
   7266 	 *  * `pages` - Total number of pages
   7267 	 *  * `start` - Display index for the first record shown on the current page
   7268 	 *  * `end` - Display index for the last record shown on the current page
   7269 	 *  * `length` - Display length (number of records). Note that generally `start
   7270 	 *    + length = end`, but this is not always true, for example if there are
   7271 	 *    only 2 records to show on the final page, with a length of 10.
   7272 	 *  * `recordsTotal` - Full data set length
   7273 	 *  * `recordsDisplay` - Data set length once the current filtering criterion
   7274 	 *    are applied.
   7275 	 */
   7276 	_api_register( 'page.info()', function () {
   7277 		if ( this.context.length === 0 ) {
   7278 			return undefined;
   7279 		}
   7280 	
   7281 		var
   7282 			settings   = this.context[0],
   7283 			start      = settings._iDisplayStart,
   7284 			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
   7285 			visRecords = settings.fnRecordsDisplay(),
   7286 			all        = len === -1;
   7287 	
   7288 		return {
   7289 			"page":           all ? 0 : Math.floor( start / len ),
   7290 			"pages":          all ? 1 : Math.ceil( visRecords / len ),
   7291 			"start":          start,
   7292 			"end":            settings.fnDisplayEnd(),
   7293 			"length":         len,
   7294 			"recordsTotal":   settings.fnRecordsTotal(),
   7295 			"recordsDisplay": visRecords,
   7296 			"serverSide":     _fnDataSource( settings ) === 'ssp'
   7297 		};
   7298 	} );
   7299 	
   7300 	
   7301 	/**
   7302 	 * Get the current page length.
   7303 	 *
   7304 	 * @return {integer} Current page length. Note `-1` indicates that all records
   7305 	 *   are to be shown.
   7306 	 *//**
   7307 	 * Set the current page length.
   7308 	 *
   7309 	 * @param {integer} Page length to set. Use `-1` to show all records.
   7310 	 * @returns {DataTables.Api} this
   7311 	 */
   7312 	_api_register( 'page.len()', function ( len ) {
   7313 		// Note that we can't call this function 'length()' because `length`
   7314 		// is a Javascript property of functions which defines how many arguments
   7315 		// the function expects.
   7316 		if ( len === undefined ) {
   7317 			return this.context.length !== 0 ?
   7318 				this.context[0]._iDisplayLength :
   7319 				undefined;
   7320 		}
   7321 	
   7322 		// else, set the page length
   7323 		return this.iterator( 'table', function ( settings ) {
   7324 			_fnLengthChange( settings, len );
   7325 		} );
   7326 	} );
   7327 	
   7328 	
   7329 	
   7330 	var __reload = function ( settings, holdPosition, callback ) {
   7331 		// Use the draw event to trigger a callback
   7332 		if ( callback ) {
   7333 			var api = new _Api( settings );
   7334 	
   7335 			api.one( 'draw', function () {
   7336 				callback( api.ajax.json() );
   7337 			} );
   7338 		}
   7339 	
   7340 		if ( _fnDataSource( settings ) == 'ssp' ) {
   7341 			_fnReDraw( settings, holdPosition );
   7342 		}
   7343 		else {
   7344 			_fnProcessingDisplay( settings, true );
   7345 	
   7346 			// Cancel an existing request
   7347 			var xhr = settings.jqXHR;
   7348 			if ( xhr && xhr.readyState !== 4 ) {
   7349 				xhr.abort();
   7350 			}
   7351 	
   7352 			// Trigger xhr
   7353 			_fnBuildAjax( settings, {}, function( json ) {
   7354 				_fnClearTable( settings );
   7355 	
   7356 				var data = _fnAjaxDataSrc( settings, json );
   7357 				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
   7358 					_fnAddData( settings, data[i] );
   7359 				}
   7360 	
   7361 				_fnReDraw( settings, holdPosition );
   7362 				_fnInitComplete( settings );
   7363 				_fnProcessingDisplay( settings, false );
   7364 			} );
   7365 		}
   7366 	};
   7367 	
   7368 	
   7369 	/**
   7370 	 * Get the JSON response from the last Ajax request that DataTables made to the
   7371 	 * server. Note that this returns the JSON from the first table in the current
   7372 	 * context.
   7373 	 *
   7374 	 * @return {object} JSON received from the server.
   7375 	 */
   7376 	_api_register( 'ajax.json()', function () {
   7377 		var ctx = this.context;
   7378 	
   7379 		if ( ctx.length > 0 ) {
   7380 			return ctx[0].json;
   7381 		}
   7382 	
   7383 		// else return undefined;
   7384 	} );
   7385 	
   7386 	
   7387 	/**
   7388 	 * Get the data submitted in the last Ajax request
   7389 	 */
   7390 	_api_register( 'ajax.params()', function () {
   7391 		var ctx = this.context;
   7392 	
   7393 		if ( ctx.length > 0 ) {
   7394 			return ctx[0].oAjaxData;
   7395 		}
   7396 	
   7397 		// else return undefined;
   7398 	} );
   7399 	
   7400 	
   7401 	/**
   7402 	 * Reload tables from the Ajax data source. Note that this function will
   7403 	 * automatically re-draw the table when the remote data has been loaded.
   7404 	 *
   7405 	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
   7406 	 *   position. A full re-sort and re-filter is performed when this method is
   7407 	 *   called, which is why the pagination reset is the default action.
   7408 	 * @returns {DataTables.Api} this
   7409 	 */
   7410 	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
   7411 		return this.iterator( 'table', function (settings) {
   7412 			__reload( settings, resetPaging===false, callback );
   7413 		} );
   7414 	} );
   7415 	
   7416 	
   7417 	/**
   7418 	 * Get the current Ajax URL. Note that this returns the URL from the first
   7419 	 * table in the current context.
   7420 	 *
   7421 	 * @return {string} Current Ajax source URL
   7422 	 *//**
   7423 	 * Set the Ajax URL. Note that this will set the URL for all tables in the
   7424 	 * current context.
   7425 	 *
   7426 	 * @param {string} url URL to set.
   7427 	 * @returns {DataTables.Api} this
   7428 	 */
   7429 	_api_register( 'ajax.url()', function ( url ) {
   7430 		var ctx = this.context;
   7431 	
   7432 		if ( url === undefined ) {
   7433 			// get
   7434 			if ( ctx.length === 0 ) {
   7435 				return undefined;
   7436 			}
   7437 			ctx = ctx[0];
   7438 	
   7439 			return $.isPlainObject( ctx.ajax ) ?
   7440 				ctx.ajax.url :
   7441 				ctx.ajax;
   7442 		}
   7443 	
   7444 		// set
   7445 		return this.iterator( 'table', function ( settings ) {
   7446 			if ( $.isPlainObject( settings.ajax ) ) {
   7447 				settings.ajax.url = url;
   7448 			}
   7449 			else {
   7450 				settings.ajax = url;
   7451 			}
   7452 		} );
   7453 	} );
   7454 	
   7455 	
   7456 	/**
   7457 	 * Load data from the newly set Ajax URL. Note that this method is only
   7458 	 * available when `ajax.url()` is used to set a URL. Additionally, this method
   7459 	 * has the same effect as calling `ajax.reload()` but is provided for
   7460 	 * convenience when setting a new URL. Like `ajax.reload()` it will
   7461 	 * automatically redraw the table once the remote data has been loaded.
   7462 	 *
   7463 	 * @returns {DataTables.Api} this
   7464 	 */
   7465 	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
   7466 		// Same as a reload, but makes sense to present it for easy access after a
   7467 		// url change
   7468 		return this.iterator( 'table', function ( ctx ) {
   7469 			__reload( ctx, resetPaging===false, callback );
   7470 		} );
   7471 	} );
   7472 	
   7473 	
   7474 	
   7475 	
   7476 	var _selector_run = function ( type, selector, selectFn, settings, opts )
   7477 	{
   7478 		var
   7479 			out = [], res,
   7480 			a, i, ien, j, jen,
   7481 			selectorType = typeof selector;
   7482 	
   7483 		// Can't just check for isArray here, as an API or jQuery instance might be
   7484 		// given with their array like look
   7485 		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
   7486 			selector = [ selector ];
   7487 		}
   7488 	
   7489 		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
   7490 			// Only split on simple strings - complex expressions will be jQuery selectors
   7491 			a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
   7492 				selector[i].split(',') :
   7493 				[ selector[i] ];
   7494 	
   7495 			for ( j=0, jen=a.length ; j<jen ; j++ ) {
   7496 				res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
   7497 	
   7498 				// Remove empty items
   7499 				res = res.filter( function (item) {
   7500 					return item !== null && item !== undefined;
   7501 				});
   7502 	
   7503 				if ( res && res.length ) {
   7504 					out = out.concat( res );
   7505 				}
   7506 			}
   7507 		}
   7508 	
   7509 		// selector extensions
   7510 		var ext = _ext.selector[ type ];
   7511 		if ( ext.length ) {
   7512 			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
   7513 				out = ext[i]( settings, opts, out );
   7514 			}
   7515 		}
   7516 	
   7517 		return _unique( out );
   7518 	};
   7519 	
   7520 	
   7521 	var _selector_opts = function ( opts )
   7522 	{
   7523 		if ( ! opts ) {
   7524 			opts = {};
   7525 		}
   7526 	
   7527 		// Backwards compatibility for 1.9- which used the terminology filter rather
   7528 		// than search
   7529 		if ( opts.filter && opts.search === undefined ) {
   7530 			opts.search = opts.filter;
   7531 		}
   7532 	
   7533 		return $.extend( {
   7534 			search: 'none',
   7535 			order: 'current',
   7536 			page: 'all'
   7537 		}, opts );
   7538 	};
   7539 	
   7540 	
   7541 	// Reduce the API instance to the first item found
   7542 	var _selector_first = function ( old )
   7543 	{
   7544 		let inst = new _Api(old.context[0]);
   7545 	
   7546 		// Use a push rather than passing to the constructor, since it will
   7547 		// merge arrays down automatically, which isn't what is wanted here
   7548 		if (old.length) {
   7549 			inst.push( old[0] );
   7550 		}
   7551 	
   7552 		inst.selector = old.selector;
   7553 	
   7554 		// Limit to a single row / column / cell
   7555 		if (inst.length && inst[0].length > 1) {
   7556 			inst[0].splice(1);
   7557 		}
   7558 	
   7559 		return inst;
   7560 	};
   7561 	
   7562 	
   7563 	var _selector_row_indexes = function ( settings, opts )
   7564 	{
   7565 		var
   7566 			i, ien, tmp, a=[],
   7567 			displayFiltered = settings.aiDisplay,
   7568 			displayMaster = settings.aiDisplayMaster;
   7569 	
   7570 		var
   7571 			search = opts.search,  // none, applied, removed
   7572 			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
   7573 			page   = opts.page;    // all, current
   7574 	
   7575 		if ( _fnDataSource( settings ) == 'ssp' ) {
   7576 			// In server-side processing mode, most options are irrelevant since
   7577 			// rows not shown don't exist and the index order is the applied order
   7578 			// Removed is a special case - for consistency just return an empty
   7579 			// array
   7580 			return search === 'removed' ?
   7581 				[] :
   7582 				_range( 0, displayMaster.length );
   7583 		}
   7584 	
   7585 		if ( page == 'current' ) {
   7586 			// Current page implies that order=current and filter=applied, since it is
   7587 			// fairly senseless otherwise, regardless of what order and search actually
   7588 			// are
   7589 			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
   7590 				a.push( displayFiltered[i] );
   7591 			}
   7592 		}
   7593 		else if ( order == 'current' || order == 'applied' ) {
   7594 			if ( search == 'none') {
   7595 				a = displayMaster.slice();
   7596 			}
   7597 			else if ( search == 'applied' ) {
   7598 				a = displayFiltered.slice();
   7599 			}
   7600 			else if ( search == 'removed' ) {
   7601 				// O(n+m) solution by creating a hash map
   7602 				var displayFilteredMap = {};
   7603 	
   7604 				for ( i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
   7605 					displayFilteredMap[displayFiltered[i]] = null;
   7606 				}
   7607 	
   7608 				displayMaster.forEach(function (item) {
   7609 					if (! Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
   7610 						a.push(item);
   7611 					}
   7612 				});
   7613 			}
   7614 		}
   7615 		else if ( order == 'index' || order == 'original' ) {
   7616 			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
   7617 				if (! settings.aoData[i]) {
   7618 					continue;
   7619 				}
   7620 	
   7621 				if ( search == 'none' ) {
   7622 					a.push( i );
   7623 				}
   7624 				else { // applied | removed
   7625 					tmp = displayFiltered.indexOf(i);
   7626 	
   7627 					if ((tmp === -1 && search == 'removed') ||
   7628 						(tmp >= 0   && search == 'applied') )
   7629 					{
   7630 						a.push( i );
   7631 					}
   7632 				}
   7633 			}
   7634 		}
   7635 		else if ( typeof order === 'number' ) {
   7636 			// Order the rows by the given column
   7637 			var ordered = _fnSort(settings, order, 'asc');
   7638 	
   7639 			if (search === 'none') {
   7640 				a = ordered;
   7641 			}
   7642 			else { // applied | removed
   7643 				for (i=0; i<ordered.length; i++) {
   7644 					tmp = displayFiltered.indexOf(ordered[i]);
   7645 	
   7646 					if ((tmp === -1 && search == 'removed') ||
   7647 						(tmp >= 0   && search == 'applied') )
   7648 					{
   7649 						a.push( ordered[i] );
   7650 					}
   7651 				}
   7652 			}
   7653 		}
   7654 	
   7655 		return a;
   7656 	};
   7657 	
   7658 	
   7659 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   7660 	 * Rows
   7661 	 *
   7662 	 * {}          - no selector - use all available rows
   7663 	 * {integer}   - row aoData index
   7664 	 * {node}      - TR node
   7665 	 * {string}    - jQuery selector to apply to the TR elements
   7666 	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
   7667 	 *
   7668 	 */
   7669 	var __row_selector = function ( settings, selector, opts )
   7670 	{
   7671 		var rows;
   7672 		var run = function ( sel ) {
   7673 			var selInt = _intVal( sel );
   7674 			var aoData = settings.aoData;
   7675 	
   7676 			// Short cut - selector is a number and no options provided (default is
   7677 			// all records, so no need to check if the index is in there, since it
   7678 			// must be - dev error if the index doesn't exist).
   7679 			if ( selInt !== null && ! opts ) {
   7680 				return [ selInt ];
   7681 			}
   7682 	
   7683 			if ( ! rows ) {
   7684 				rows = _selector_row_indexes( settings, opts );
   7685 			}
   7686 	
   7687 			if ( selInt !== null && rows.indexOf(selInt) !== -1 ) {
   7688 				// Selector - integer
   7689 				return [ selInt ];
   7690 			}
   7691 			else if ( sel === null || sel === undefined || sel === '' ) {
   7692 				// Selector - none
   7693 				return rows;
   7694 			}
   7695 	
   7696 			// Selector - function
   7697 			if ( typeof sel === 'function' ) {
   7698 				return rows.map( function (idx) {
   7699 					var row = aoData[ idx ];
   7700 					return sel( idx, row._aData, row.nTr ) ? idx : null;
   7701 				} );
   7702 			}
   7703 	
   7704 			// Selector - node
   7705 			if ( sel.nodeName ) {
   7706 				var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
   7707 				var cellIdx = sel._DT_CellIndex;
   7708 	
   7709 				if ( rowIdx !== undefined ) {
   7710 					// Make sure that the row is actually still present in the table
   7711 					return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
   7712 						[ rowIdx ] :
   7713 						[];
   7714 				}
   7715 				else if ( cellIdx ) {
   7716 					return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
   7717 						[ cellIdx.row ] :
   7718 						[];
   7719 				}
   7720 				else {
   7721 					var host = $(sel).closest('*[data-dt-row]');
   7722 					return host.length ?
   7723 						[ host.data('dt-row') ] :
   7724 						[];
   7725 				}
   7726 			}
   7727 	
   7728 			// ID selector. Want to always be able to select rows by id, regardless
   7729 			// of if the tr element has been created or not, so can't rely upon
   7730 			// jQuery here - hence a custom implementation. This does not match
   7731 			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
   7732 			// but to select it using a CSS selector engine (like Sizzle or
   7733 			// querySelect) it would need to need to be escaped for some characters.
   7734 			// DataTables simplifies this for row selectors since you can select
   7735 			// only a row. A # indicates an id any anything that follows is the id -
   7736 			// unescaped.
   7737 			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
   7738 				// get row index from id
   7739 				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
   7740 				if ( rowObj !== undefined ) {
   7741 					return [ rowObj.idx ];
   7742 				}
   7743 	
   7744 				// need to fall through to jQuery in case there is DOM id that
   7745 				// matches
   7746 			}
   7747 			
   7748 			// Get nodes in the order from the `rows` array with null values removed
   7749 			var nodes = _removeEmpty(
   7750 				_pluck_order( settings.aoData, rows, 'nTr' )
   7751 			);
   7752 	
   7753 			// Selector - jQuery selector string, array of nodes or jQuery object/
   7754 			// As jQuery's .filter() allows jQuery objects to be passed in filter,
   7755 			// it also allows arrays, so this will cope with all three options
   7756 			return $(nodes)
   7757 				.filter( sel )
   7758 				.map( function () {
   7759 					return this._DT_RowIndex;
   7760 				} )
   7761 				.toArray();
   7762 		};
   7763 	
   7764 		var matched = _selector_run( 'row', selector, run, settings, opts );
   7765 	
   7766 		if (opts.order === 'current' || opts.order === 'applied') {
   7767 			_fnSortDisplay(settings, matched);
   7768 		}
   7769 	
   7770 		return matched;
   7771 	};
   7772 	
   7773 	
   7774 	_api_register( 'rows()', function ( selector, opts ) {
   7775 		// argument shifting
   7776 		if ( selector === undefined ) {
   7777 			selector = '';
   7778 		}
   7779 		else if ( $.isPlainObject( selector ) ) {
   7780 			opts = selector;
   7781 			selector = '';
   7782 		}
   7783 	
   7784 		opts = _selector_opts( opts );
   7785 	
   7786 		var inst = this.iterator( 'table', function ( settings ) {
   7787 			return __row_selector( settings, selector, opts );
   7788 		}, 1 );
   7789 	
   7790 		// Want argument shifting here and in __row_selector?
   7791 		inst.selector.rows = selector;
   7792 		inst.selector.opts = opts;
   7793 	
   7794 		return inst;
   7795 	} );
   7796 	
   7797 	_api_register( 'rows().nodes()', function () {
   7798 		return this.iterator( 'row', function ( settings, row ) {
   7799 			return settings.aoData[ row ].nTr || undefined;
   7800 		}, 1 );
   7801 	} );
   7802 	
   7803 	_api_register( 'rows().data()', function () {
   7804 		return this.iterator( true, 'rows', function ( settings, rows ) {
   7805 			return _pluck_order( settings.aoData, rows, '_aData' );
   7806 		}, 1 );
   7807 	} );
   7808 	
   7809 	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
   7810 		return this.iterator( 'row', function ( settings, row ) {
   7811 			var r = settings.aoData[ row ];
   7812 			return type === 'search' ? r._aFilterData : r._aSortData;
   7813 		}, 1 );
   7814 	} );
   7815 	
   7816 	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
   7817 		return this.iterator( 'row', function ( settings, row ) {
   7818 			_fnInvalidate( settings, row, src );
   7819 		} );
   7820 	} );
   7821 	
   7822 	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
   7823 		return this.iterator( 'row', function ( settings, row ) {
   7824 			return row;
   7825 		}, 1 );
   7826 	} );
   7827 	
   7828 	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
   7829 		var a = [];
   7830 		var context = this.context;
   7831 	
   7832 		// `iterator` will drop undefined values, but in this case we want them
   7833 		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
   7834 			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
   7835 				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
   7836 				a.push( (hash === true ? '#' : '' )+ id );
   7837 			}
   7838 		}
   7839 	
   7840 		return new _Api( context, a );
   7841 	} );
   7842 	
   7843 	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
   7844 		this.iterator( 'row', function ( settings, row ) {
   7845 			var data = settings.aoData;
   7846 			var rowData = data[ row ];
   7847 	
   7848 			// Delete from the display arrays
   7849 			var idx = settings.aiDisplayMaster.indexOf(row);
   7850 			if (idx !== -1) {
   7851 				settings.aiDisplayMaster.splice(idx, 1);
   7852 			}
   7853 	
   7854 			// For server-side processing tables - subtract the deleted row from the count
   7855 			if ( settings._iRecordsDisplay > 0 ) {
   7856 				settings._iRecordsDisplay--;
   7857 			}
   7858 	
   7859 			// Check for an 'overflow' they case for displaying the table
   7860 			_fnLengthOverflow( settings );
   7861 	
   7862 			// Remove the row's ID reference if there is one
   7863 			var id = settings.rowIdFn( rowData._aData );
   7864 			if ( id !== undefined ) {
   7865 				delete settings.aIds[ id ];
   7866 			}
   7867 	
   7868 			data[row] = null;
   7869 		} );
   7870 	
   7871 		return this;
   7872 	} );
   7873 	
   7874 	
   7875 	_api_register( 'rows.add()', function ( rows ) {
   7876 		var newRows = this.iterator( 'table', function ( settings ) {
   7877 				var row, i, ien;
   7878 				var out = [];
   7879 	
   7880 				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
   7881 					row = rows[i];
   7882 	
   7883 					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
   7884 						out.push( _fnAddTr( settings, row )[0] );
   7885 					}
   7886 					else {
   7887 						out.push( _fnAddData( settings, row ) );
   7888 					}
   7889 				}
   7890 	
   7891 				return out;
   7892 			}, 1 );
   7893 	
   7894 		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
   7895 		var modRows = this.rows( -1 );
   7896 		modRows.pop();
   7897 		modRows.push.apply(modRows, newRows);
   7898 	
   7899 		return modRows;
   7900 	} );
   7901 	
   7902 	
   7903 	
   7904 	
   7905 	
   7906 	/**
   7907 	 *
   7908 	 */
   7909 	_api_register( 'row()', function ( selector, opts ) {
   7910 		return _selector_first( this.rows( selector, opts ) );
   7911 	} );
   7912 	
   7913 	
   7914 	_api_register( 'row().data()', function ( data ) {
   7915 		var ctx = this.context;
   7916 	
   7917 		if ( data === undefined ) {
   7918 			// Get
   7919 			return ctx.length && this.length && this[0].length ?
   7920 				ctx[0].aoData[ this[0] ]._aData :
   7921 				undefined;
   7922 		}
   7923 	
   7924 		// Set
   7925 		var row = ctx[0].aoData[ this[0] ];
   7926 		row._aData = data;
   7927 	
   7928 		// If the DOM has an id, and the data source is an array
   7929 		if ( Array.isArray( data ) && row.nTr && row.nTr.id ) {
   7930 			_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
   7931 		}
   7932 	
   7933 		// Automatically invalidate
   7934 		_fnInvalidate( ctx[0], this[0], 'data' );
   7935 	
   7936 		return this;
   7937 	} );
   7938 	
   7939 	
   7940 	_api_register( 'row().node()', function () {
   7941 		var ctx = this.context;
   7942 	
   7943 		if (ctx.length && this.length && this[0].length) {
   7944 			var row = ctx[0].aoData[ this[0] ];
   7945 	
   7946 			if (row && row.nTr) {
   7947 				return row.nTr;
   7948 			}
   7949 		}
   7950 	
   7951 		return null;
   7952 	} );
   7953 	
   7954 	
   7955 	_api_register( 'row.add()', function ( row ) {
   7956 		// Allow a jQuery object to be passed in - only a single row is added from
   7957 		// it though - the first element in the set
   7958 		if ( row instanceof $ && row.length ) {
   7959 			row = row[0];
   7960 		}
   7961 	
   7962 		var rows = this.iterator( 'table', function ( settings ) {
   7963 			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
   7964 				return _fnAddTr( settings, row )[0];
   7965 			}
   7966 			return _fnAddData( settings, row );
   7967 		} );
   7968 	
   7969 		// Return an Api.rows() extended instance, with the newly added row selected
   7970 		return this.row( rows[0] );
   7971 	} );
   7972 	
   7973 	
   7974 	$(document).on('plugin-init.dt', function (e, context) {
   7975 		var api = new _Api( context );
   7976 	
   7977 		api.on( 'stateSaveParams.DT', function ( e, settings, d ) {
   7978 			// This could be more compact with the API, but it is a lot faster as a simple
   7979 			// internal loop
   7980 			var idFn = settings.rowIdFn;
   7981 			var rows = settings.aiDisplayMaster;
   7982 			var ids = [];
   7983 	
   7984 			for (var i=0 ; i<rows.length ; i++) {
   7985 				var rowIdx = rows[i];
   7986 				var data = settings.aoData[rowIdx];
   7987 	
   7988 				if (data._detailsShow) {
   7989 					ids.push( '#' + idFn(data._aData) );
   7990 				}
   7991 			}
   7992 	
   7993 			d.childRows = ids;
   7994 		});
   7995 	
   7996 		// For future state loads (e.g. with StateRestore)
   7997 		api.on( 'stateLoaded.DT', function (e, settings, state) {
   7998 			__details_state_load( api, state );
   7999 		});
   8000 	
   8001 		// And the initial load state
   8002 		__details_state_load( api, api.state.loaded() );
   8003 	});
   8004 	
   8005 	var __details_state_load = function (api, state)
   8006 	{
   8007 		if ( state && state.childRows ) {
   8008 			api
   8009 				.rows( state.childRows.map(function (id) {
   8010 					// Escape any `:` characters from the row id. Accounts for
   8011 					// already escaped characters.
   8012 					return id.replace(/([^:\\]*(?:\\.[^:\\]*)*):/g, "$1\\:");
   8013 				}) )
   8014 				.every( function () {
   8015 					_fnCallbackFire( api.settings()[0], null, 'requestChild', [ this ] )
   8016 				});
   8017 		}
   8018 	}
   8019 	
   8020 	var __details_add = function ( ctx, row, data, klass )
   8021 	{
   8022 		// Convert to array of TR elements
   8023 		var rows = [];
   8024 		var addRow = function ( r, k ) {
   8025 			// Recursion to allow for arrays of jQuery objects
   8026 			if ( Array.isArray( r ) || r instanceof $ ) {
   8027 				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
   8028 					addRow( r[i], k );
   8029 				}
   8030 				return;
   8031 			}
   8032 	
   8033 			// If we get a TR element, then just add it directly - up to the dev
   8034 			// to add the correct number of columns etc
   8035 			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
   8036 				r.setAttribute( 'data-dt-row', row.idx );
   8037 				rows.push( r );
   8038 			}
   8039 			else {
   8040 				// Otherwise create a row with a wrapper
   8041 				var created = $('<tr><td></td></tr>')
   8042 					.attr( 'data-dt-row', row.idx )
   8043 					.addClass( k );
   8044 				
   8045 				$('td', created)
   8046 					.addClass( k )
   8047 					.html( r )[0].colSpan = _fnVisbleColumns( ctx );
   8048 	
   8049 				rows.push( created[0] );
   8050 			}
   8051 		};
   8052 	
   8053 		addRow( data, klass );
   8054 	
   8055 		if ( row._details ) {
   8056 			row._details.detach();
   8057 		}
   8058 	
   8059 		row._details = $(rows);
   8060 	
   8061 		// If the children were already shown, that state should be retained
   8062 		if ( row._detailsShow ) {
   8063 			row._details.insertAfter( row.nTr );
   8064 		}
   8065 	};
   8066 	
   8067 	
   8068 	// Make state saving of child row details async to allow them to be batch processed
   8069 	var __details_state = DataTable.util.throttle(
   8070 		function (ctx) {
   8071 			_fnSaveState( ctx[0] )
   8072 		},
   8073 		500
   8074 	);
   8075 	
   8076 	
   8077 	var __details_remove = function ( api, idx )
   8078 	{
   8079 		var ctx = api.context;
   8080 	
   8081 		if ( ctx.length ) {
   8082 			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
   8083 	
   8084 			if ( row && row._details ) {
   8085 				row._details.remove();
   8086 	
   8087 				row._detailsShow = undefined;
   8088 				row._details = undefined;
   8089 				$( row.nTr ).removeClass( 'dt-hasChild' );
   8090 				__details_state( ctx );
   8091 			}
   8092 		}
   8093 	};
   8094 	
   8095 	
   8096 	var __details_display = function ( api, show ) {
   8097 		var ctx = api.context;
   8098 	
   8099 		if ( ctx.length && api.length ) {
   8100 			var row = ctx[0].aoData[ api[0] ];
   8101 	
   8102 			if ( row._details ) {
   8103 				row._detailsShow = show;
   8104 	
   8105 				if ( show ) {
   8106 					row._details.insertAfter( row.nTr );
   8107 					$( row.nTr ).addClass( 'dt-hasChild' );
   8108 				}
   8109 				else {
   8110 					row._details.detach();
   8111 					$( row.nTr ).removeClass( 'dt-hasChild' );
   8112 				}
   8113 	
   8114 				_fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )
   8115 	
   8116 				__details_events( ctx[0] );
   8117 				__details_state( ctx );
   8118 			}
   8119 		}
   8120 	};
   8121 	
   8122 	
   8123 	var __details_events = function ( settings )
   8124 	{
   8125 		var api = new _Api( settings );
   8126 		var namespace = '.dt.DT_details';
   8127 		var drawEvent = 'draw'+namespace;
   8128 		var colvisEvent = 'column-sizing'+namespace;
   8129 		var destroyEvent = 'destroy'+namespace;
   8130 		var data = settings.aoData;
   8131 	
   8132 		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
   8133 	
   8134 		if ( _pluck( data, '_details' ).length > 0 ) {
   8135 			// On each draw, insert the required elements into the document
   8136 			api.on( drawEvent, function ( e, ctx ) {
   8137 				if ( settings !== ctx ) {
   8138 					return;
   8139 				}
   8140 	
   8141 				api.rows( {page:'current'} ).eq(0).each( function (idx) {
   8142 					// Internal data grab
   8143 					var row = data[ idx ];
   8144 	
   8145 					if ( row._detailsShow ) {
   8146 						row._details.insertAfter( row.nTr );
   8147 					}
   8148 				} );
   8149 			} );
   8150 	
   8151 			// Column visibility change - update the colspan
   8152 			api.on( colvisEvent, function ( e, ctx ) {
   8153 				if ( settings !== ctx ) {
   8154 					return;
   8155 				}
   8156 	
   8157 				// Update the colspan for the details rows (note, only if it already has
   8158 				// a colspan)
   8159 				var row, visible = _fnVisbleColumns( ctx );
   8160 	
   8161 				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
   8162 					row = data[i];
   8163 	
   8164 					if ( row && row._details ) {
   8165 						row._details.each(function () {
   8166 							var el = $(this).children('td');
   8167 	
   8168 							if (el.length == 1) {
   8169 								el.attr('colspan', visible);
   8170 							}
   8171 						});
   8172 					}
   8173 				}
   8174 			} );
   8175 	
   8176 			// Table destroyed - nuke any child rows
   8177 			api.on( destroyEvent, function ( e, ctx ) {
   8178 				if ( settings !== ctx ) {
   8179 					return;
   8180 				}
   8181 	
   8182 				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
   8183 					if ( data[i] && data[i]._details ) {
   8184 						__details_remove( api, i );
   8185 					}
   8186 				}
   8187 			} );
   8188 		}
   8189 	};
   8190 	
   8191 	// Strings for the method names to help minification
   8192 	var _emp = '';
   8193 	var _child_obj = _emp+'row().child';
   8194 	var _child_mth = _child_obj+'()';
   8195 	
   8196 	// data can be:
   8197 	//  tr
   8198 	//  string
   8199 	//  jQuery or array of any of the above
   8200 	_api_register( _child_mth, function ( data, klass ) {
   8201 		var ctx = this.context;
   8202 	
   8203 		if ( data === undefined ) {
   8204 			// get
   8205 			return ctx.length && this.length && ctx[0].aoData[ this[0] ]
   8206 				? ctx[0].aoData[ this[0] ]._details
   8207 				: undefined;
   8208 		}
   8209 		else if ( data === true ) {
   8210 			// show
   8211 			this.child.show();
   8212 		}
   8213 		else if ( data === false ) {
   8214 			// remove
   8215 			__details_remove( this );
   8216 		}
   8217 		else if ( ctx.length && this.length ) {
   8218 			// set
   8219 			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
   8220 		}
   8221 	
   8222 		return this;
   8223 	} );
   8224 	
   8225 	
   8226 	_api_register( [
   8227 		_child_obj+'.show()',
   8228 		_child_mth+'.show()' // only when `child()` was called with parameters (without
   8229 	], function () {         // it returns an object and this method is not executed)
   8230 		__details_display( this, true );
   8231 		return this;
   8232 	} );
   8233 	
   8234 	
   8235 	_api_register( [
   8236 		_child_obj+'.hide()',
   8237 		_child_mth+'.hide()' // only when `child()` was called with parameters (without
   8238 	], function () {         // it returns an object and this method is not executed)
   8239 		__details_display( this, false );
   8240 		return this;
   8241 	} );
   8242 	
   8243 	
   8244 	_api_register( [
   8245 		_child_obj+'.remove()',
   8246 		_child_mth+'.remove()' // only when `child()` was called with parameters (without
   8247 	], function () {           // it returns an object and this method is not executed)
   8248 		__details_remove( this );
   8249 		return this;
   8250 	} );
   8251 	
   8252 	
   8253 	_api_register( _child_obj+'.isShown()', function () {
   8254 		var ctx = this.context;
   8255 	
   8256 		if ( ctx.length && this.length && ctx[0].aoData[ this[0] ] ) {
   8257 			// _detailsShown as false or undefined will fall through to return false
   8258 			return ctx[0].aoData[ this[0] ]._detailsShow || false;
   8259 		}
   8260 		return false;
   8261 	} );
   8262 	
   8263 	
   8264 	
   8265 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   8266 	 * Columns
   8267 	 *
   8268 	 * {integer}           - column index (>=0 count from left, <0 count from right)
   8269 	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
   8270 	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
   8271 	 * "{string}:name"     - column name
   8272 	 * "{string}"          - jQuery selector on column header nodes
   8273 	 *
   8274 	 */
   8275 	
   8276 	// can be an array of these items, comma separated list, or an array of comma
   8277 	// separated lists
   8278 	
   8279 	var __re_column_selector = /^([^:]+)?:(name|title|visIdx|visible)$/;
   8280 	
   8281 	
   8282 	// r1 and r2 are redundant - but it means that the parameters match for the
   8283 	// iterator callback in columns().data()
   8284 	var __columnData = function ( settings, column, r1, r2, rows, type ) {
   8285 		var a = [];
   8286 		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
   8287 			a.push( _fnGetCellData( settings, rows[row], column, type ) );
   8288 		}
   8289 		return a;
   8290 	};
   8291 	
   8292 	
   8293 	var __column_header = function ( settings, column, row ) {
   8294 		var header = settings.aoHeader;
   8295 		var target = row !== undefined
   8296 			? row
   8297 			: settings.bSortCellsTop // legacy support
   8298 				? 0
   8299 				: header.length - 1;
   8300 	
   8301 		return header[target][column].cell;
   8302 	};
   8303 	
   8304 	var __column_selector = function ( settings, selector, opts )
   8305 	{
   8306 		var
   8307 			columns = settings.aoColumns,
   8308 			names = _pluck( columns, 'sName' ),
   8309 			titles = _pluck( columns, 'sTitle' ),
   8310 			cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
   8311 			nodes = _unique( _flatten([], cells) );
   8312 		
   8313 		var run = function ( s ) {
   8314 			var selInt = _intVal( s );
   8315 	
   8316 			// Selector - all
   8317 			if ( s === '' ) {
   8318 				return _range( columns.length );
   8319 			}
   8320 	
   8321 			// Selector - index
   8322 			if ( selInt !== null ) {
   8323 				return [ selInt >= 0 ?
   8324 					selInt : // Count from left
   8325 					columns.length + selInt // Count from right (+ because its a negative value)
   8326 				];
   8327 			}
   8328 	
   8329 			// Selector = function
   8330 			if ( typeof s === 'function' ) {
   8331 				var rows = _selector_row_indexes( settings, opts );
   8332 	
   8333 				return columns.map(function (col, idx) {
   8334 					return s(
   8335 							idx,
   8336 							__columnData( settings, idx, 0, 0, rows ),
   8337 							__column_header( settings, idx )
   8338 						) ? idx : null;
   8339 				});
   8340 			}
   8341 	
   8342 			// jQuery or string selector
   8343 			var match = typeof s === 'string' ?
   8344 				s.match( __re_column_selector ) :
   8345 				'';
   8346 	
   8347 			if ( match ) {
   8348 				switch( match[2] ) {
   8349 					case 'visIdx':
   8350 					case 'visible':
   8351 						if (match[1]) {
   8352 							var idx = parseInt( match[1], 10 );
   8353 							// Visible index given, convert to column index
   8354 							if ( idx < 0 ) {
   8355 								// Counting from the right
   8356 								var visColumns = columns.map( function (col,i) {
   8357 									return col.bVisible ? i : null;
   8358 								} );
   8359 								return [ visColumns[ visColumns.length + idx ] ];
   8360 							}
   8361 							// Counting from the left
   8362 							return [ _fnVisibleToColumnIndex( settings, idx ) ];
   8363 						}
   8364 						
   8365 						// `:visible` on its own
   8366 						return columns.map( function (col, i) {
   8367 							return col.bVisible ? i : null;
   8368 						} );
   8369 	
   8370 					case 'name':
   8371 						// match by name. `names` is column index complete and in order
   8372 						return names.map( function (name, i) {
   8373 							return name === match[1] ? i : null;
   8374 						} );
   8375 	
   8376 					case 'title':
   8377 						// match by column title
   8378 						return titles.map( function (title, i) {
   8379 							return title === match[1] ? i : null;
   8380 						} );
   8381 	
   8382 					default:
   8383 						return [];
   8384 				}
   8385 			}
   8386 	
   8387 			// Cell in the table body
   8388 			if ( s.nodeName && s._DT_CellIndex ) {
   8389 				return [ s._DT_CellIndex.column ];
   8390 			}
   8391 	
   8392 			// jQuery selector on the TH elements for the columns
   8393 			var jqResult = $( nodes )
   8394 				.filter( s )
   8395 				.map( function () {
   8396 					return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
   8397 				} )
   8398 				.toArray();
   8399 	
   8400 			if ( jqResult.length || ! s.nodeName ) {
   8401 				return jqResult;
   8402 			}
   8403 	
   8404 			// Otherwise a node which might have a `dt-column` data attribute, or be
   8405 			// a child or such an element
   8406 			var host = $(s).closest('*[data-dt-column]');
   8407 			return host.length ?
   8408 				[ host.data('dt-column') ] :
   8409 				[];
   8410 		};
   8411 	
   8412 		return _selector_run( 'column', selector, run, settings, opts );
   8413 	};
   8414 	
   8415 	
   8416 	var __setColumnVis = function ( settings, column, vis ) {
   8417 		var
   8418 			cols = settings.aoColumns,
   8419 			col  = cols[ column ],
   8420 			data = settings.aoData,
   8421 			cells, i, ien, tr;
   8422 	
   8423 		// Get
   8424 		if ( vis === undefined ) {
   8425 			return col.bVisible;
   8426 		}
   8427 	
   8428 		// Set
   8429 		// No change
   8430 		if ( col.bVisible === vis ) {
   8431 			return false;
   8432 		}
   8433 	
   8434 		if ( vis ) {
   8435 			// Insert column
   8436 			// Need to decide if we should use appendChild or insertBefore
   8437 			var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column+1);
   8438 	
   8439 			for ( i=0, ien=data.length ; i<ien ; i++ ) {
   8440 				if (data[i]) {
   8441 					tr = data[i].nTr;
   8442 					cells = data[i].anCells;
   8443 	
   8444 					if ( tr ) {
   8445 						// insertBefore can act like appendChild if 2nd arg is null
   8446 						tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
   8447 					}
   8448 				}
   8449 			}
   8450 		}
   8451 		else {
   8452 			// Remove column
   8453 			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
   8454 		}
   8455 	
   8456 		// Common actions
   8457 		col.bVisible = vis;
   8458 	
   8459 		_colGroup(settings);
   8460 		
   8461 		return true;
   8462 	};
   8463 	
   8464 	
   8465 	_api_register( 'columns()', function ( selector, opts ) {
   8466 		// argument shifting
   8467 		if ( selector === undefined ) {
   8468 			selector = '';
   8469 		}
   8470 		else if ( $.isPlainObject( selector ) ) {
   8471 			opts = selector;
   8472 			selector = '';
   8473 		}
   8474 	
   8475 		opts = _selector_opts( opts );
   8476 	
   8477 		var inst = this.iterator( 'table', function ( settings ) {
   8478 			return __column_selector( settings, selector, opts );
   8479 		}, 1 );
   8480 	
   8481 		// Want argument shifting here and in _row_selector?
   8482 		inst.selector.cols = selector;
   8483 		inst.selector.opts = opts;
   8484 	
   8485 		return inst;
   8486 	} );
   8487 	
   8488 	_api_registerPlural( 'columns().header()', 'column().header()', function ( row ) {
   8489 		return this.iterator( 'column', function (settings, column) {
   8490 			return __column_header(settings, column, row);
   8491 		}, 1 );
   8492 	} );
   8493 	
   8494 	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( row ) {
   8495 		return this.iterator( 'column', function ( settings, column ) {
   8496 			var footer = settings.aoFooter;
   8497 	
   8498 			if (! footer.length) {
   8499 				return null;
   8500 			}
   8501 	
   8502 			return settings.aoFooter[row !== undefined ? row : 0][column].cell;
   8503 		}, 1 );
   8504 	} );
   8505 	
   8506 	_api_registerPlural( 'columns().data()', 'column().data()', function () {
   8507 		return this.iterator( 'column-rows', __columnData, 1 );
   8508 	} );
   8509 	
   8510 	_api_registerPlural( 'columns().render()', 'column().render()', function ( type ) {
   8511 		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
   8512 			return __columnData( settings, column, i, j, rows, type );
   8513 		}, 1 );
   8514 	} );
   8515 	
   8516 	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
   8517 		return this.iterator( 'column', function ( settings, column ) {
   8518 			return settings.aoColumns[column].mData;
   8519 		}, 1 );
   8520 	} );
   8521 	
   8522 	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
   8523 		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
   8524 			return _pluck_order( settings.aoData, rows,
   8525 				type === 'search' ? '_aFilterData' : '_aSortData', column
   8526 			);
   8527 		}, 1 );
   8528 	} );
   8529 	
   8530 	_api_registerPlural( 'columns().init()', 'column().init()', function () {
   8531 		return this.iterator( 'column', function ( settings, column ) {
   8532 			return settings.aoColumns[column];
   8533 		}, 1 );
   8534 	} );
   8535 	
   8536 	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
   8537 		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
   8538 			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
   8539 		}, 1 );
   8540 	} );
   8541 	
   8542 	_api_registerPlural( 'columns().titles()', 'column().title()', function (title, row) {
   8543 		return this.iterator( 'column', function ( settings, column ) {
   8544 			// Argument shifting
   8545 			if (typeof title === 'number') {
   8546 				row = title;
   8547 				title = undefined;
   8548 			}
   8549 	
   8550 			var span = $('span.dt-column-title', this.column(column).header(row));
   8551 	
   8552 			if (title !== undefined) {
   8553 				span.html(title);
   8554 				return this;
   8555 			}
   8556 	
   8557 			return span.html();
   8558 		}, 1 );
   8559 	} );
   8560 	
   8561 	_api_registerPlural( 'columns().types()', 'column().type()', function () {
   8562 		return this.iterator( 'column', function ( settings, column ) {
   8563 			var type = settings.aoColumns[column].sType;
   8564 	
   8565 			// If the type was invalidated, then resolve it. This actually does
   8566 			// all columns at the moment. Would only happen once if getting all
   8567 			// column's data types.
   8568 			if (! type) {
   8569 				_fnColumnTypes(settings);
   8570 			}
   8571 	
   8572 			return type;
   8573 		}, 1 );
   8574 	} );
   8575 	
   8576 	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
   8577 		var that = this;
   8578 		var changed = [];
   8579 		var ret = this.iterator( 'column', function ( settings, column ) {
   8580 			if ( vis === undefined ) {
   8581 				return settings.aoColumns[ column ].bVisible;
   8582 			} // else
   8583 			
   8584 			if (__setColumnVis( settings, column, vis )) {
   8585 				changed.push(column);
   8586 			}
   8587 		} );
   8588 	
   8589 		// Group the column visibility changes
   8590 		if ( vis !== undefined ) {
   8591 			this.iterator( 'table', function ( settings ) {
   8592 				// Redraw the header after changes
   8593 				_fnDrawHead( settings, settings.aoHeader );
   8594 				_fnDrawHead( settings, settings.aoFooter );
   8595 		
   8596 				// Update colspan for no records display. Child rows and extensions will use their own
   8597 				// listeners to do this - only need to update the empty table item here
   8598 				if ( ! settings.aiDisplay.length ) {
   8599 					$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
   8600 				}
   8601 		
   8602 				_fnSaveState( settings );
   8603 	
   8604 				// Second loop once the first is done for events
   8605 				that.iterator( 'column', function ( settings, column ) {
   8606 					if (changed.includes(column)) {
   8607 						_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
   8608 					}
   8609 				} );
   8610 	
   8611 				if ( changed.length && (calc === undefined || calc) ) {
   8612 					that.columns.adjust();
   8613 				}
   8614 			});
   8615 		}
   8616 	
   8617 		return ret;
   8618 	} );
   8619 	
   8620 	_api_registerPlural( 'columns().widths()', 'column().width()', function () {
   8621 		// Injects a fake row into the table for just a moment so the widths can
   8622 		// be read, regardless of colspan in the header and rows being present in
   8623 		// the body
   8624 		var columns = this.columns(':visible').count();
   8625 		var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
   8626 	
   8627 		$(this.table().body()).append(row);
   8628 	
   8629 		var widths = row.children().map(function () {
   8630 			return $(this).outerWidth();
   8631 		});
   8632 	
   8633 		row.remove();
   8634 		
   8635 		return this.iterator( 'column', function ( settings, column ) {
   8636 			var visIdx = _fnColumnIndexToVisible( settings, column );
   8637 	
   8638 			return visIdx !== null ? widths[visIdx] : 0;
   8639 		}, 1);
   8640 	} );
   8641 	
   8642 	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
   8643 		return this.iterator( 'column', function ( settings, column ) {
   8644 			return type === 'visible' ?
   8645 				_fnColumnIndexToVisible( settings, column ) :
   8646 				column;
   8647 		}, 1 );
   8648 	} );
   8649 	
   8650 	_api_register( 'columns.adjust()', function () {
   8651 		return this.iterator( 'table', function ( settings ) {
   8652 			_fnAdjustColumnSizing( settings );
   8653 		}, 1 );
   8654 	} );
   8655 	
   8656 	_api_register( 'column.index()', function ( type, idx ) {
   8657 		if ( this.context.length !== 0 ) {
   8658 			var ctx = this.context[0];
   8659 	
   8660 			if ( type === 'fromVisible' || type === 'toData' ) {
   8661 				return _fnVisibleToColumnIndex( ctx, idx );
   8662 			}
   8663 			else if ( type === 'fromData' || type === 'toVisible' ) {
   8664 				return _fnColumnIndexToVisible( ctx, idx );
   8665 			}
   8666 		}
   8667 	} );
   8668 	
   8669 	_api_register( 'column()', function ( selector, opts ) {
   8670 		return _selector_first( this.columns( selector, opts ) );
   8671 	} );
   8672 	
   8673 	var __cell_selector = function ( settings, selector, opts )
   8674 	{
   8675 		var data = settings.aoData;
   8676 		var rows = _selector_row_indexes( settings, opts );
   8677 		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
   8678 		var allCells = $(_flatten( [], cells ));
   8679 		var row;
   8680 		var columns = settings.aoColumns.length;
   8681 		var a, i, ien, j, o, host;
   8682 	
   8683 		var run = function ( s ) {
   8684 			var fnSelector = typeof s === 'function';
   8685 	
   8686 			if ( s === null || s === undefined || fnSelector ) {
   8687 				// All cells and function selectors
   8688 				a = [];
   8689 	
   8690 				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
   8691 					row = rows[i];
   8692 	
   8693 					for ( j=0 ; j<columns ; j++ ) {
   8694 						o = {
   8695 							row: row,
   8696 							column: j
   8697 						};
   8698 	
   8699 						if ( fnSelector ) {
   8700 							// Selector - function
   8701 							host = data[ row ];
   8702 	
   8703 							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
   8704 								a.push( o );
   8705 							}
   8706 						}
   8707 						else {
   8708 							// Selector - all
   8709 							a.push( o );
   8710 						}
   8711 					}
   8712 				}
   8713 	
   8714 				return a;
   8715 			}
   8716 			
   8717 			// Selector - index
   8718 			if ( $.isPlainObject( s ) ) {
   8719 				// Valid cell index and its in the array of selectable rows
   8720 				return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
   8721 					[s] :
   8722 					[];
   8723 			}
   8724 	
   8725 			// Selector - jQuery filtered cells
   8726 			var jqResult = allCells
   8727 				.filter( s )
   8728 				.map( function (i, el) {
   8729 					return { // use a new object, in case someone changes the values
   8730 						row:    el._DT_CellIndex.row,
   8731 						column: el._DT_CellIndex.column
   8732 					};
   8733 				} )
   8734 				.toArray();
   8735 	
   8736 			if ( jqResult.length || ! s.nodeName ) {
   8737 				return jqResult;
   8738 			}
   8739 	
   8740 			// Otherwise the selector is a node, and there is one last option - the
   8741 			// element might be a child of an element which has dt-row and dt-column
   8742 			// data attributes
   8743 			host = $(s).closest('*[data-dt-row]');
   8744 			return host.length ?
   8745 				[ {
   8746 					row: host.data('dt-row'),
   8747 					column: host.data('dt-column')
   8748 				} ] :
   8749 				[];
   8750 		};
   8751 	
   8752 		return _selector_run( 'cell', selector, run, settings, opts );
   8753 	};
   8754 	
   8755 	
   8756 	
   8757 	
   8758 	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
   8759 		// Argument shifting
   8760 		if ( $.isPlainObject( rowSelector ) ) {
   8761 			// Indexes
   8762 			if ( rowSelector.row === undefined ) {
   8763 				// Selector options in first parameter
   8764 				opts = rowSelector;
   8765 				rowSelector = null;
   8766 			}
   8767 			else {
   8768 				// Cell index objects in first parameter
   8769 				opts = columnSelector;
   8770 				columnSelector = null;
   8771 			}
   8772 		}
   8773 		if ( $.isPlainObject( columnSelector ) ) {
   8774 			opts = columnSelector;
   8775 			columnSelector = null;
   8776 		}
   8777 	
   8778 		// Cell selector
   8779 		if ( columnSelector === null || columnSelector === undefined ) {
   8780 			return this.iterator( 'table', function ( settings ) {
   8781 				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
   8782 			} );
   8783 		}
   8784 	
   8785 		// The default built in options need to apply to row and columns
   8786 		var internalOpts = opts ? {
   8787 			page: opts.page,
   8788 			order: opts.order,
   8789 			search: opts.search
   8790 		} : {};
   8791 	
   8792 		// Row + column selector
   8793 		var columns = this.columns( columnSelector, internalOpts );
   8794 		var rows = this.rows( rowSelector, internalOpts );
   8795 		var i, ien, j, jen;
   8796 	
   8797 		var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
   8798 			var a = [];
   8799 	
   8800 			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
   8801 				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
   8802 					a.push( {
   8803 						row:    rows[idx][i],
   8804 						column: columns[idx][j]
   8805 					} );
   8806 				}
   8807 			}
   8808 	
   8809 			return a;
   8810 		}, 1 );
   8811 	
   8812 		// There is currently only one extension which uses a cell selector extension
   8813 		// It is a _major_ performance drag to run this if it isn't needed, so this is
   8814 		// an extension specific check at the moment
   8815 		var cells = opts && opts.selected ?
   8816 			this.cells( cellsNoOpts, opts ) :
   8817 			cellsNoOpts;
   8818 	
   8819 		$.extend( cells.selector, {
   8820 			cols: columnSelector,
   8821 			rows: rowSelector,
   8822 			opts: opts
   8823 		} );
   8824 	
   8825 		return cells;
   8826 	} );
   8827 	
   8828 	
   8829 	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
   8830 		return this.iterator( 'cell', function ( settings, row, column ) {
   8831 			var data = settings.aoData[ row ];
   8832 	
   8833 			return data && data.anCells ?
   8834 				data.anCells[ column ] :
   8835 				undefined;
   8836 		}, 1 );
   8837 	} );
   8838 	
   8839 	
   8840 	_api_register( 'cells().data()', function () {
   8841 		return this.iterator( 'cell', function ( settings, row, column ) {
   8842 			return _fnGetCellData( settings, row, column );
   8843 		}, 1 );
   8844 	} );
   8845 	
   8846 	
   8847 	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
   8848 		type = type === 'search' ? '_aFilterData' : '_aSortData';
   8849 	
   8850 		return this.iterator( 'cell', function ( settings, row, column ) {
   8851 			return settings.aoData[ row ][ type ][ column ];
   8852 		}, 1 );
   8853 	} );
   8854 	
   8855 	
   8856 	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
   8857 		return this.iterator( 'cell', function ( settings, row, column ) {
   8858 			return _fnGetCellData( settings, row, column, type );
   8859 		}, 1 );
   8860 	} );
   8861 	
   8862 	
   8863 	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
   8864 		return this.iterator( 'cell', function ( settings, row, column ) {
   8865 			return {
   8866 				row: row,
   8867 				column: column,
   8868 				columnVisible: _fnColumnIndexToVisible( settings, column )
   8869 			};
   8870 		}, 1 );
   8871 	} );
   8872 	
   8873 	
   8874 	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
   8875 		return this.iterator( 'cell', function ( settings, row, column ) {
   8876 			_fnInvalidate( settings, row, src, column );
   8877 		} );
   8878 	} );
   8879 	
   8880 	
   8881 	
   8882 	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
   8883 		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
   8884 	} );
   8885 	
   8886 	
   8887 	_api_register( 'cell().data()', function ( data ) {
   8888 		var ctx = this.context;
   8889 		var cell = this[0];
   8890 	
   8891 		if ( data === undefined ) {
   8892 			// Get
   8893 			return ctx.length && cell.length ?
   8894 				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
   8895 				undefined;
   8896 		}
   8897 	
   8898 		// Set
   8899 		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
   8900 		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
   8901 	
   8902 		return this;
   8903 	} );
   8904 	
   8905 	
   8906 	
   8907 	/**
   8908 	 * Get current ordering (sorting) that has been applied to the table.
   8909 	 *
   8910 	 * @returns {array} 2D array containing the sorting information for the first
   8911 	 *   table in the current context. Each element in the parent array represents
   8912 	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
   8913 	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
   8914 	 *   the column index that the sorting condition applies to, the second is the
   8915 	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
   8916 	 *   index of the sorting order from the `column.sorting` initialisation array.
   8917 	 *//**
   8918 	 * Set the ordering for the table.
   8919 	 *
   8920 	 * @param {integer} order Column index to sort upon.
   8921 	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
   8922 	 * @returns {DataTables.Api} this
   8923 	 *//**
   8924 	 * Set the ordering for the table.
   8925 	 *
   8926 	 * @param {array} order 1D array of sorting information to be applied.
   8927 	 * @param {array} [...] Optional additional sorting conditions
   8928 	 * @returns {DataTables.Api} this
   8929 	 *//**
   8930 	 * Set the ordering for the table.
   8931 	 *
   8932 	 * @param {array} order 2D array of sorting information to be applied.
   8933 	 * @returns {DataTables.Api} this
   8934 	 */
   8935 	_api_register( 'order()', function ( order, dir ) {
   8936 		var ctx = this.context;
   8937 		var args = Array.prototype.slice.call( arguments );
   8938 	
   8939 		if ( order === undefined ) {
   8940 			// get
   8941 			return ctx.length !== 0 ?
   8942 				ctx[0].aaSorting :
   8943 				undefined;
   8944 		}
   8945 	
   8946 		// set
   8947 		if ( typeof order === 'number' ) {
   8948 			// Simple column / direction passed in
   8949 			order = [ [ order, dir ] ];
   8950 		}
   8951 		else if ( args.length > 1 ) {
   8952 			// Arguments passed in (list of 1D arrays)
   8953 			order = args;
   8954 		}
   8955 		// otherwise a 2D array was passed in
   8956 	
   8957 		return this.iterator( 'table', function ( settings ) {
   8958 			settings.aaSorting = Array.isArray(order) ? order.slice() : order;
   8959 		} );
   8960 	} );
   8961 	
   8962 	
   8963 	/**
   8964 	 * Attach a sort listener to an element for a given column
   8965 	 *
   8966 	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
   8967 	 *   listener to. This can take the form of a single DOM node, a jQuery
   8968 	 *   collection of nodes or a jQuery selector which will identify the node(s).
   8969 	 * @param {integer} column the column that a click on this node will sort on
   8970 	 * @param {function} [callback] callback function when sort is run
   8971 	 * @returns {DataTables.Api} this
   8972 	 */
   8973 	_api_register( 'order.listener()', function ( node, column, callback ) {
   8974 		return this.iterator( 'table', function ( settings ) {
   8975 			_fnSortAttachListener(settings, node, {}, column, callback);
   8976 		} );
   8977 	} );
   8978 	
   8979 	
   8980 	_api_register( 'order.fixed()', function ( set ) {
   8981 		if ( ! set ) {
   8982 			var ctx = this.context;
   8983 			var fixed = ctx.length ?
   8984 				ctx[0].aaSortingFixed :
   8985 				undefined;
   8986 	
   8987 			return Array.isArray( fixed ) ?
   8988 				{ pre: fixed } :
   8989 				fixed;
   8990 		}
   8991 	
   8992 		return this.iterator( 'table', function ( settings ) {
   8993 			settings.aaSortingFixed = $.extend( true, {}, set );
   8994 		} );
   8995 	} );
   8996 	
   8997 	
   8998 	// Order by the selected column(s)
   8999 	_api_register( [
   9000 		'columns().order()',
   9001 		'column().order()'
   9002 	], function ( dir ) {
   9003 		var that = this;
   9004 	
   9005 		if ( ! dir ) {
   9006 			return this.iterator( 'column', function ( settings, idx ) {
   9007 				var sort = _fnSortFlatten( settings );
   9008 	
   9009 				for ( var i=0, ien=sort.length ; i<ien ; i++ ) {
   9010 					if ( sort[i].col === idx ) {
   9011 						return sort[i].dir;
   9012 					}
   9013 				}
   9014 	
   9015 				return null;
   9016 			}, 1 );
   9017 		}
   9018 		else {
   9019 			return this.iterator( 'table', function ( settings, i ) {
   9020 				settings.aaSorting = that[i].map( function (col) {
   9021 					return [ col, dir ];
   9022 				} );
   9023 			} );
   9024 		}
   9025 	} );
   9026 	
   9027 	_api_registerPlural('columns().orderable()', 'column().orderable()', function ( directions ) {
   9028 		return this.iterator( 'column', function ( settings, idx ) {
   9029 			var col = settings.aoColumns[idx];
   9030 	
   9031 			return directions ?
   9032 				col.asSorting :
   9033 				col.bSortable;
   9034 		}, 1 );
   9035 	} );
   9036 	
   9037 	
   9038 	_api_register( 'processing()', function ( show ) {
   9039 		return this.iterator( 'table', function ( ctx ) {
   9040 			_fnProcessingDisplay( ctx, show );
   9041 		} );
   9042 	} );
   9043 	
   9044 	
   9045 	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
   9046 		var ctx = this.context;
   9047 	
   9048 		if ( input === undefined ) {
   9049 			// get
   9050 			return ctx.length !== 0 ?
   9051 				ctx[0].oPreviousSearch.search :
   9052 				undefined;
   9053 		}
   9054 	
   9055 		// set
   9056 		return this.iterator( 'table', function ( settings ) {
   9057 			if ( ! settings.oFeatures.bFilter ) {
   9058 				return;
   9059 			}
   9060 	
   9061 			if (typeof regex === 'object') {
   9062 				// New style options to pass to the search builder
   9063 				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, regex, {
   9064 					search: input
   9065 				} ) );
   9066 			}
   9067 			else {
   9068 				// Compat for the old options
   9069 				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, {
   9070 					search: input,
   9071 					regex:  regex === null ? false : regex,
   9072 					smart:  smart === null ? true  : smart,
   9073 					caseInsensitive: caseInsen === null ? true : caseInsen
   9074 				} ) );
   9075 			}
   9076 		} );
   9077 	} );
   9078 	
   9079 	_api_register( 'search.fixed()', function ( name, search ) {
   9080 		var ret = this.iterator( true, 'table', function ( settings ) {
   9081 			var fixed = settings.searchFixed;
   9082 	
   9083 			if (! name) {
   9084 				return Object.keys(fixed)
   9085 			}
   9086 			else if (search === undefined) {
   9087 				return fixed[name];
   9088 			}
   9089 			else if (search === null) {
   9090 				delete fixed[name];
   9091 			}
   9092 			else {
   9093 				fixed[name] = search;
   9094 			}
   9095 	
   9096 			return this;
   9097 		} );
   9098 	
   9099 		return name !== undefined && search === undefined
   9100 			? ret[0]
   9101 			: ret;
   9102 	} );
   9103 	
   9104 	_api_registerPlural(
   9105 		'columns().search()',
   9106 		'column().search()',
   9107 		function ( input, regex, smart, caseInsen ) {
   9108 			return this.iterator( 'column', function ( settings, column ) {
   9109 				var preSearch = settings.aoPreSearchCols;
   9110 	
   9111 				if ( input === undefined ) {
   9112 					// get
   9113 					return preSearch[ column ].search;
   9114 				}
   9115 	
   9116 				// set
   9117 				if ( ! settings.oFeatures.bFilter ) {
   9118 					return;
   9119 				}
   9120 	
   9121 				if (typeof regex === 'object') {
   9122 					// New style options to pass to the search builder
   9123 					$.extend( preSearch[ column ], regex, {
   9124 						search: input
   9125 					} );
   9126 				}
   9127 				else {
   9128 					// Old style (with not all options available)
   9129 					$.extend( preSearch[ column ], {
   9130 						search: input,
   9131 						regex:  regex === null ? false : regex,
   9132 						smart:  smart === null ? true  : smart,
   9133 						caseInsensitive: caseInsen === null ? true : caseInsen
   9134 					} );
   9135 				}
   9136 	
   9137 				_fnFilterComplete( settings, settings.oPreviousSearch );
   9138 			} );
   9139 		}
   9140 	);
   9141 	
   9142 	_api_register([
   9143 			'columns().search.fixed()',
   9144 			'column().search.fixed()'
   9145 		],
   9146 		function ( name, search ) {
   9147 			var ret = this.iterator( true, 'column', function ( settings, colIdx ) {
   9148 				var fixed = settings.aoColumns[colIdx].searchFixed;
   9149 	
   9150 				if (! name) {
   9151 					return Object.keys(fixed)
   9152 				}
   9153 				else if (search === undefined) {
   9154 					return fixed[name];
   9155 				}
   9156 				else if (search === null) {
   9157 					delete fixed[name];
   9158 				}
   9159 				else {
   9160 					fixed[name] = search;
   9161 				}
   9162 	
   9163 				return this;
   9164 			} );
   9165 	
   9166 			return name !== undefined && search === undefined
   9167 				? ret[0]
   9168 				: ret;
   9169 		}
   9170 	);
   9171 	/*
   9172 	 * State API methods
   9173 	 */
   9174 	
   9175 	_api_register( 'state()', function ( set, ignoreTime ) {
   9176 		// getter
   9177 		if ( ! set ) {
   9178 			return this.context.length ?
   9179 				this.context[0].oSavedState :
   9180 				null;
   9181 		}
   9182 	
   9183 		var setMutate = $.extend( true, {}, set );
   9184 	
   9185 		// setter
   9186 		return this.iterator( 'table', function ( settings ) {
   9187 			if ( ignoreTime !== false ) {
   9188 				setMutate.time = +new Date() + 100;
   9189 			}
   9190 	
   9191 			_fnImplementState( settings, setMutate, function(){} );
   9192 		} );
   9193 	} );
   9194 	
   9195 	
   9196 	_api_register( 'state.clear()', function () {
   9197 		return this.iterator( 'table', function ( settings ) {
   9198 			// Save an empty object
   9199 			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
   9200 		} );
   9201 	} );
   9202 	
   9203 	
   9204 	_api_register( 'state.loaded()', function () {
   9205 		return this.context.length ?
   9206 			this.context[0].oLoadedState :
   9207 			null;
   9208 	} );
   9209 	
   9210 	
   9211 	_api_register( 'state.save()', function () {
   9212 		return this.iterator( 'table', function ( settings ) {
   9213 			_fnSaveState( settings );
   9214 		} );
   9215 	} );
   9216 	
   9217 	/**
   9218 	 * Set the jQuery or window object to be used by DataTables
   9219 	 *
   9220 	 * @param {*} module Library / container object
   9221 	 * @param {string} [type] Library or container type `lib`, `win` or `datetime`.
   9222 	 *   If not provided, automatic detection is attempted.
   9223 	 */
   9224 	DataTable.use = function (module, type) {
   9225 		if (type === 'lib' || module.fn) {
   9226 			$ = module;
   9227 		}
   9228 		else if (type == 'win' || module.document) {
   9229 			window = module;
   9230 			document = module.document;
   9231 		}
   9232 		else if (type === 'datetime' || module.type === 'DateTime') {
   9233 			DataTable.DateTime = module;
   9234 		}
   9235 	}
   9236 	
   9237 	/**
   9238 	 * CommonJS factory function pass through. This will check if the arguments
   9239 	 * given are a window object or a jQuery object. If so they are set
   9240 	 * accordingly.
   9241 	 * @param {*} root Window
   9242 	 * @param {*} jq jQUery
   9243 	 * @returns {boolean} Indicator
   9244 	 */
   9245 	DataTable.factory = function (root, jq) {
   9246 		var is = false;
   9247 	
   9248 		// Test if the first parameter is a window object
   9249 		if (root && root.document) {
   9250 			window = root;
   9251 			document = root.document;
   9252 		}
   9253 	
   9254 		// Test if the second parameter is a jQuery object
   9255 		if (jq && jq.fn && jq.fn.jquery) {
   9256 			$ = jq;
   9257 			is = true;
   9258 		}
   9259 	
   9260 		return is;
   9261 	}
   9262 	
   9263 	/**
   9264 	 * Provide a common method for plug-ins to check the version of DataTables being
   9265 	 * used, in order to ensure compatibility.
   9266 	 *
   9267 	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
   9268 	 *    Note that the formats "X" and "X.Y" are also acceptable.
   9269 	 *  @param {string} [version2=current DataTables version] As above, but optional.
   9270 	 *   If not given the current DataTables version will be used.
   9271 	 *  @returns {boolean} true if this version of DataTables is greater or equal to
   9272 	 *    the required version, or false if this version of DataTales is not
   9273 	 *    suitable
   9274 	 *  @static
   9275 	 *  @dtopt API-Static
   9276 	 *
   9277 	 *  @example
   9278 	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
   9279 	 */
   9280 	DataTable.versionCheck = function( version, version2 )
   9281 	{
   9282 		var aThis = version2 ?
   9283 			version2.split('.') :
   9284 			DataTable.version.split('.');
   9285 		var aThat = version.split('.');
   9286 		var iThis, iThat;
   9287 	
   9288 		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
   9289 			iThis = parseInt( aThis[i], 10 ) || 0;
   9290 			iThat = parseInt( aThat[i], 10 ) || 0;
   9291 	
   9292 			// Parts are the same, keep comparing
   9293 			if (iThis === iThat) {
   9294 				continue;
   9295 			}
   9296 	
   9297 			// Parts are different, return immediately
   9298 			return iThis > iThat;
   9299 		}
   9300 	
   9301 		return true;
   9302 	};
   9303 	
   9304 	
   9305 	/**
   9306 	 * Check if a `<table>` node is a DataTable table already or not.
   9307 	 *
   9308 	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
   9309 	 *      selector for the table to test. Note that if more than more than one
   9310 	 *      table is passed on, only the first will be checked
   9311 	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
   9312 	 *  @static
   9313 	 *  @dtopt API-Static
   9314 	 *
   9315 	 *  @example
   9316 	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
   9317 	 *      $('#example').dataTable();
   9318 	 *    }
   9319 	 */
   9320 	DataTable.isDataTable = function ( table )
   9321 	{
   9322 		var t = $(table).get(0);
   9323 		var is = false;
   9324 	
   9325 		if ( table instanceof DataTable.Api ) {
   9326 			return true;
   9327 		}
   9328 	
   9329 		$.each( DataTable.settings, function (i, o) {
   9330 			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
   9331 			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
   9332 	
   9333 			if ( o.nTable === t || head === t || foot === t ) {
   9334 				is = true;
   9335 			}
   9336 		} );
   9337 	
   9338 		return is;
   9339 	};
   9340 	
   9341 	
   9342 	/**
   9343 	 * Get all DataTable tables that have been initialised - optionally you can
   9344 	 * select to get only currently visible tables.
   9345 	 *
   9346 	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
   9347 	 *    or visible tables only.
   9348 	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
   9349 	 *    DataTables
   9350 	 *  @static
   9351 	 *  @dtopt API-Static
   9352 	 *
   9353 	 *  @example
   9354 	 *    $.each( $.fn.dataTable.tables(true), function () {
   9355 	 *      $(table).DataTable().columns.adjust();
   9356 	 *    } );
   9357 	 */
   9358 	DataTable.tables = function ( visible )
   9359 	{
   9360 		var api = false;
   9361 	
   9362 		if ( $.isPlainObject( visible ) ) {
   9363 			api = visible.api;
   9364 			visible = visible.visible;
   9365 		}
   9366 	
   9367 		var a = DataTable.settings
   9368 			.filter( function (o) {
   9369 				return !visible || (visible && $(o.nTable).is(':visible')) 
   9370 					? true
   9371 					: false;
   9372 			} )
   9373 			.map( function (o) {
   9374 				return o.nTable;
   9375 			});
   9376 	
   9377 		return api ?
   9378 			new _Api( a ) :
   9379 			a;
   9380 	};
   9381 	
   9382 	
   9383 	/**
   9384 	 * Convert from camel case parameters to Hungarian notation. This is made public
   9385 	 * for the extensions to provide the same ability as DataTables core to accept
   9386 	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
   9387 	 * parameters.
   9388 	 *
   9389 	 *  @param {object} src The model object which holds all parameters that can be
   9390 	 *    mapped.
   9391 	 *  @param {object} user The object to convert from camel case to Hungarian.
   9392 	 *  @param {boolean} force When set to `true`, properties which already have a
   9393 	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
   9394 	 *    won't be.
   9395 	 */
   9396 	DataTable.camelToHungarian = _fnCamelToHungarian;
   9397 	
   9398 	
   9399 	
   9400 	/**
   9401 	 *
   9402 	 */
   9403 	_api_register( '$()', function ( selector, opts ) {
   9404 		var
   9405 			rows   = this.rows( opts ).nodes(), // Get all rows
   9406 			jqRows = $(rows);
   9407 	
   9408 		return $( [].concat(
   9409 			jqRows.filter( selector ).toArray(),
   9410 			jqRows.find( selector ).toArray()
   9411 		) );
   9412 	} );
   9413 	
   9414 	
   9415 	// jQuery functions to operate on the tables
   9416 	$.each( [ 'on', 'one', 'off' ], function (i, key) {
   9417 		_api_register( key+'()', function ( /* event, handler */ ) {
   9418 			var args = Array.prototype.slice.call(arguments);
   9419 	
   9420 			// Add the `dt` namespace automatically if it isn't already present
   9421 			args[0] = args[0].split( /\s/ ).map( function ( e ) {
   9422 				return ! e.match(/\.dt\b/) ?
   9423 					e+'.dt' :
   9424 					e;
   9425 				} ).join( ' ' );
   9426 	
   9427 			var inst = $( this.tables().nodes() );
   9428 			inst[key].apply( inst, args );
   9429 			return this;
   9430 		} );
   9431 	} );
   9432 	
   9433 	
   9434 	_api_register( 'clear()', function () {
   9435 		return this.iterator( 'table', function ( settings ) {
   9436 			_fnClearTable( settings );
   9437 		} );
   9438 	} );
   9439 	
   9440 	
   9441 	_api_register( 'error()', function (msg) {
   9442 		return this.iterator( 'table', function ( settings ) {
   9443 			_fnLog( settings, 0, msg );
   9444 		} );
   9445 	} );
   9446 	
   9447 	
   9448 	_api_register( 'settings()', function () {
   9449 		return new _Api( this.context, this.context );
   9450 	} );
   9451 	
   9452 	
   9453 	_api_register( 'init()', function () {
   9454 		var ctx = this.context;
   9455 		return ctx.length ? ctx[0].oInit : null;
   9456 	} );
   9457 	
   9458 	
   9459 	_api_register( 'data()', function () {
   9460 		return this.iterator( 'table', function ( settings ) {
   9461 			return _pluck( settings.aoData, '_aData' );
   9462 		} ).flatten();
   9463 	} );
   9464 	
   9465 	
   9466 	_api_register( 'trigger()', function ( name, args, bubbles ) {
   9467 		return this.iterator( 'table', function ( settings ) {
   9468 			return _fnCallbackFire( settings, null, name, args, bubbles );
   9469 		} ).flatten();
   9470 	} );
   9471 	
   9472 	
   9473 	_api_register( 'ready()', function ( fn ) {
   9474 		var ctx = this.context;
   9475 	
   9476 		// Get status of first table
   9477 		if (! fn) {
   9478 			return ctx.length
   9479 				? (ctx[0]._bInitComplete || false)
   9480 				: null;
   9481 		}
   9482 	
   9483 		// Function to run either once the table becomes ready or
   9484 		// immediately if it is already ready.
   9485 		return this.tables().every(function () {
   9486 			if (this.context[0]._bInitComplete) {
   9487 				fn.call(this);
   9488 			}
   9489 			else {
   9490 				this.on('init', function () {
   9491 					fn.call(this);
   9492 				});
   9493 			}
   9494 		} );
   9495 	} );
   9496 	
   9497 	
   9498 	_api_register( 'destroy()', function ( remove ) {
   9499 		remove = remove || false;
   9500 	
   9501 		return this.iterator( 'table', function ( settings ) {
   9502 			var classes   = settings.oClasses;
   9503 			var table     = settings.nTable;
   9504 			var tbody     = settings.nTBody;
   9505 			var thead     = settings.nTHead;
   9506 			var tfoot     = settings.nTFoot;
   9507 			var jqTable   = $(table);
   9508 			var jqTbody   = $(tbody);
   9509 			var jqWrapper = $(settings.nTableWrapper);
   9510 			var rows      = settings.aoData.map( function (r) { return r ? r.nTr : null; } );
   9511 			var orderClasses = classes.order;
   9512 	
   9513 			// Flag to note that the table is currently being destroyed - no action
   9514 			// should be taken
   9515 			settings.bDestroying = true;
   9516 	
   9517 			// Fire off the destroy callbacks for plug-ins etc
   9518 			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings], true );
   9519 	
   9520 			// If not being removed from the document, make all columns visible
   9521 			if ( ! remove ) {
   9522 				new _Api( settings ).columns().visible( true );
   9523 			}
   9524 	
   9525 			// Blitz all `DT` namespaced events (these are internal events, the
   9526 			// lowercase, `dt` events are user subscribed and they are responsible
   9527 			// for removing them
   9528 			jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
   9529 			$(window).off('.DT-'+settings.sInstance);
   9530 	
   9531 			// When scrolling we had to break the table up - restore it
   9532 			if ( table != thead.parentNode ) {
   9533 				jqTable.children('thead').detach();
   9534 				jqTable.append( thead );
   9535 			}
   9536 	
   9537 			if ( tfoot && table != tfoot.parentNode ) {
   9538 				jqTable.children('tfoot').detach();
   9539 				jqTable.append( tfoot );
   9540 			}
   9541 	
   9542 			settings.colgroup.remove();
   9543 	
   9544 			settings.aaSorting = [];
   9545 			settings.aaSortingFixed = [];
   9546 			_fnSortingClasses( settings );
   9547 	
   9548 			$('th, td', thead)
   9549 				.removeClass(
   9550 					orderClasses.canAsc + ' ' +
   9551 					orderClasses.canDesc + ' ' +
   9552 					orderClasses.isAsc + ' ' +
   9553 					orderClasses.isDesc
   9554 				)
   9555 				.css('width', '');
   9556 	
   9557 			// Add the TR elements back into the table in their original order
   9558 			jqTbody.children().detach();
   9559 			jqTbody.append( rows );
   9560 	
   9561 			var orig = settings.nTableWrapper.parentNode;
   9562 			var insertBefore = settings.nTableWrapper.nextSibling;
   9563 	
   9564 			// Remove the DataTables generated nodes, events and classes
   9565 			var removedMethod = remove ? 'remove' : 'detach';
   9566 			jqTable[ removedMethod ]();
   9567 			jqWrapper[ removedMethod ]();
   9568 	
   9569 			// If we need to reattach the table to the document
   9570 			if ( ! remove && orig ) {
   9571 				// insertBefore acts like appendChild if !arg[1]
   9572 				orig.insertBefore( table, insertBefore );
   9573 	
   9574 				// Restore the width of the original table - was read from the style property,
   9575 				// so we can restore directly to that
   9576 				jqTable
   9577 					.css( 'width', settings.sDestroyWidth )
   9578 					.removeClass( classes.table );
   9579 			}
   9580 	
   9581 			/* Remove the settings object from the settings array */
   9582 			var idx = DataTable.settings.indexOf(settings);
   9583 			if ( idx !== -1 ) {
   9584 				DataTable.settings.splice( idx, 1 );
   9585 			}
   9586 		} );
   9587 	} );
   9588 	
   9589 	
   9590 	// Add the `every()` method for rows, columns and cells in a compact form
   9591 	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
   9592 		_api_register( type+'s().every()', function ( fn ) {
   9593 			var opts = this.selector.opts;
   9594 			var api = this;
   9595 			var inst;
   9596 			var counter = 0;
   9597 	
   9598 			return this.iterator( 'every', function ( settings, selectedIdx, tableIdx ) {
   9599 				inst = api[ type ](selectedIdx, opts);
   9600 	
   9601 				if (type === 'cell') {
   9602 					fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
   9603 				}
   9604 				else {
   9605 					fn.call(inst, selectedIdx, tableIdx, counter);
   9606 				}
   9607 	
   9608 				counter++;
   9609 			} );
   9610 		} );
   9611 	} );
   9612 	
   9613 	
   9614 	// i18n method for extensions to be able to use the language object from the
   9615 	// DataTable
   9616 	_api_register( 'i18n()', function ( token, def, plural ) {
   9617 		var ctx = this.context[0];
   9618 		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
   9619 	
   9620 		if ( resolved === undefined ) {
   9621 			resolved = def;
   9622 		}
   9623 	
   9624 		if ( $.isPlainObject( resolved ) ) {
   9625 			resolved = plural !== undefined && resolved[ plural ] !== undefined ?
   9626 				resolved[ plural ] :
   9627 				resolved._;
   9628 		}
   9629 	
   9630 		return typeof resolved === 'string'
   9631 			? resolved.replace( '%d', plural ) // nb: plural might be undefined,
   9632 			: resolved;
   9633 	} );
   9634 	
   9635 	/**
   9636 	 * Version string for plug-ins to check compatibility. Allowed format is
   9637 	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
   9638 	 * only for non-release builds. See https://semver.org/ for more information.
   9639 	 *  @member
   9640 	 *  @type string
   9641 	 *  @default Version number
   9642 	 */
   9643 	DataTable.version = "2.0.8";
   9644 	
   9645 	/**
   9646 	 * Private data store, containing all of the settings objects that are
   9647 	 * created for the tables on a given page.
   9648 	 *
   9649 	 * Note that the `DataTable.settings` object is aliased to
   9650 	 * `jQuery.fn.dataTableExt` through which it may be accessed and
   9651 	 * manipulated, or `jQuery.fn.dataTable.settings`.
   9652 	 *  @member
   9653 	 *  @type array
   9654 	 *  @default []
   9655 	 *  @private
   9656 	 */
   9657 	DataTable.settings = [];
   9658 	
   9659 	/**
   9660 	 * Object models container, for the various models that DataTables has
   9661 	 * available to it. These models define the objects that are used to hold
   9662 	 * the active state and configuration of the table.
   9663 	 *  @namespace
   9664 	 */
   9665 	DataTable.models = {};
   9666 	
   9667 	
   9668 	
   9669 	/**
   9670 	 * Template object for the way in which DataTables holds information about
   9671 	 * search information for the global filter and individual column filters.
   9672 	 *  @namespace
   9673 	 */
   9674 	DataTable.models.oSearch = {
   9675 		/**
   9676 		 * Flag to indicate if the filtering should be case insensitive or not
   9677 		 */
   9678 		"caseInsensitive": true,
   9679 	
   9680 		/**
   9681 		 * Applied search term
   9682 		 */
   9683 		"search": "",
   9684 	
   9685 		/**
   9686 		 * Flag to indicate if the search term should be interpreted as a
   9687 		 * regular expression (true) or not (false) and therefore and special
   9688 		 * regex characters escaped.
   9689 		 */
   9690 		"regex": false,
   9691 	
   9692 		/**
   9693 		 * Flag to indicate if DataTables is to use its smart filtering or not.
   9694 		 */
   9695 		"smart": true,
   9696 	
   9697 		/**
   9698 		 * Flag to indicate if DataTables should only trigger a search when
   9699 		 * the return key is pressed.
   9700 		 */
   9701 		"return": false
   9702 	};
   9703 	
   9704 	
   9705 	
   9706 	
   9707 	/**
   9708 	 * Template object for the way in which DataTables holds information about
   9709 	 * each individual row. This is the object format used for the settings
   9710 	 * aoData array.
   9711 	 *  @namespace
   9712 	 */
   9713 	DataTable.models.oRow = {
   9714 		/**
   9715 		 * TR element for the row
   9716 		 */
   9717 		"nTr": null,
   9718 	
   9719 		/**
   9720 		 * Array of TD elements for each row. This is null until the row has been
   9721 		 * created.
   9722 		 */
   9723 		"anCells": null,
   9724 	
   9725 		/**
   9726 		 * Data object from the original data source for the row. This is either
   9727 		 * an array if using the traditional form of DataTables, or an object if
   9728 		 * using mData options. The exact type will depend on the passed in
   9729 		 * data from the data source, or will be an array if using DOM a data
   9730 		 * source.
   9731 		 */
   9732 		"_aData": [],
   9733 	
   9734 		/**
   9735 		 * Sorting data cache - this array is ostensibly the same length as the
   9736 		 * number of columns (although each index is generated only as it is
   9737 		 * needed), and holds the data that is used for sorting each column in the
   9738 		 * row. We do this cache generation at the start of the sort in order that
   9739 		 * the formatting of the sort data need be done only once for each cell
   9740 		 * per sort. This array should not be read from or written to by anything
   9741 		 * other than the master sorting methods.
   9742 		 */
   9743 		"_aSortData": null,
   9744 	
   9745 		/**
   9746 		 * Per cell filtering data cache. As per the sort data cache, used to
   9747 		 * increase the performance of the filtering in DataTables
   9748 		 */
   9749 		"_aFilterData": null,
   9750 	
   9751 		/**
   9752 		 * Filtering data cache. This is the same as the cell filtering cache, but
   9753 		 * in this case a string rather than an array. This is easily computed with
   9754 		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
   9755 		 * needed on every search (memory traded for performance)
   9756 		 */
   9757 		"_sFilterRow": null,
   9758 	
   9759 		/**
   9760 		 * Denote if the original data source was from the DOM, or the data source
   9761 		 * object. This is used for invalidating data, so DataTables can
   9762 		 * automatically read data from the original source, unless uninstructed
   9763 		 * otherwise.
   9764 		 */
   9765 		"src": null,
   9766 	
   9767 		/**
   9768 		 * Index in the aoData array. This saves an indexOf lookup when we have the
   9769 		 * object, but want to know the index
   9770 		 */
   9771 		"idx": -1,
   9772 	
   9773 		/**
   9774 		 * Cached display value
   9775 		 */
   9776 		displayData: null
   9777 	};
   9778 	
   9779 	
   9780 	/**
   9781 	 * Template object for the column information object in DataTables. This object
   9782 	 * is held in the settings aoColumns array and contains all the information that
   9783 	 * DataTables needs about each individual column.
   9784 	 *
   9785 	 * Note that this object is related to {@link DataTable.defaults.column}
   9786 	 * but this one is the internal data store for DataTables's cache of columns.
   9787 	 * It should NOT be manipulated outside of DataTables. Any configuration should
   9788 	 * be done through the initialisation options.
   9789 	 *  @namespace
   9790 	 */
   9791 	DataTable.models.oColumn = {
   9792 		/**
   9793 		 * Column index.
   9794 		 */
   9795 		"idx": null,
   9796 	
   9797 		/**
   9798 		 * A list of the columns that sorting should occur on when this column
   9799 		 * is sorted. That this property is an array allows multi-column sorting
   9800 		 * to be defined for a column (for example first name / last name columns
   9801 		 * would benefit from this). The values are integers pointing to the
   9802 		 * columns to be sorted on (typically it will be a single integer pointing
   9803 		 * at itself, but that doesn't need to be the case).
   9804 		 */
   9805 		"aDataSort": null,
   9806 	
   9807 		/**
   9808 		 * Define the sorting directions that are applied to the column, in sequence
   9809 		 * as the column is repeatedly sorted upon - i.e. the first value is used
   9810 		 * as the sorting direction when the column if first sorted (clicked on).
   9811 		 * Sort it again (click again) and it will move on to the next index.
   9812 		 * Repeat until loop.
   9813 		 */
   9814 		"asSorting": null,
   9815 	
   9816 		/**
   9817 		 * Flag to indicate if the column is searchable, and thus should be included
   9818 		 * in the filtering or not.
   9819 		 */
   9820 		"bSearchable": null,
   9821 	
   9822 		/**
   9823 		 * Flag to indicate if the column is sortable or not.
   9824 		 */
   9825 		"bSortable": null,
   9826 	
   9827 		/**
   9828 		 * Flag to indicate if the column is currently visible in the table or not
   9829 		 */
   9830 		"bVisible": null,
   9831 	
   9832 		/**
   9833 		 * Store for manual type assignment using the `column.type` option. This
   9834 		 * is held in store so we can manipulate the column's `sType` property.
   9835 		 */
   9836 		"_sManualType": null,
   9837 	
   9838 		/**
   9839 		 * Flag to indicate if HTML5 data attributes should be used as the data
   9840 		 * source for filtering or sorting. True is either are.
   9841 		 */
   9842 		"_bAttrSrc": false,
   9843 	
   9844 		/**
   9845 		 * Developer definable function that is called whenever a cell is created (Ajax source,
   9846 		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
   9847 		 * allowing you to modify the DOM element (add background colour for example) when the
   9848 		 * element is available.
   9849 		 */
   9850 		"fnCreatedCell": null,
   9851 	
   9852 		/**
   9853 		 * Function to get data from a cell in a column. You should <b>never</b>
   9854 		 * access data directly through _aData internally in DataTables - always use
   9855 		 * the method attached to this property. It allows mData to function as
   9856 		 * required. This function is automatically assigned by the column
   9857 		 * initialisation method
   9858 		 */
   9859 		"fnGetData": null,
   9860 	
   9861 		/**
   9862 		 * Function to set data for a cell in the column. You should <b>never</b>
   9863 		 * set the data directly to _aData internally in DataTables - always use
   9864 		 * this method. It allows mData to function as required. This function
   9865 		 * is automatically assigned by the column initialisation method
   9866 		 */
   9867 		"fnSetData": null,
   9868 	
   9869 		/**
   9870 		 * Property to read the value for the cells in the column from the data
   9871 		 * source array / object. If null, then the default content is used, if a
   9872 		 * function is given then the return from the function is used.
   9873 		 */
   9874 		"mData": null,
   9875 	
   9876 		/**
   9877 		 * Partner property to mData which is used (only when defined) to get
   9878 		 * the data - i.e. it is basically the same as mData, but without the
   9879 		 * 'set' option, and also the data fed to it is the result from mData.
   9880 		 * This is the rendering method to match the data method of mData.
   9881 		 */
   9882 		"mRender": null,
   9883 	
   9884 		/**
   9885 		 * The class to apply to all TD elements in the table's TBODY for the column
   9886 		 */
   9887 		"sClass": null,
   9888 	
   9889 		/**
   9890 		 * When DataTables calculates the column widths to assign to each column,
   9891 		 * it finds the longest string in each column and then constructs a
   9892 		 * temporary table and reads the widths from that. The problem with this
   9893 		 * is that "mmm" is much wider then "iiii", but the latter is a longer
   9894 		 * string - thus the calculation can go wrong (doing it properly and putting
   9895 		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
   9896 		 * a "work around" we provide this option. It will append its value to the
   9897 		 * text that is found to be the longest string for the column - i.e. padding.
   9898 		 */
   9899 		"sContentPadding": null,
   9900 	
   9901 		/**
   9902 		 * Allows a default value to be given for a column's data, and will be used
   9903 		 * whenever a null data source is encountered (this can be because mData
   9904 		 * is set to null, or because the data source itself is null).
   9905 		 */
   9906 		"sDefaultContent": null,
   9907 	
   9908 		/**
   9909 		 * Name for the column, allowing reference to the column by name as well as
   9910 		 * by index (needs a lookup to work by name).
   9911 		 */
   9912 		"sName": null,
   9913 	
   9914 		/**
   9915 		 * Custom sorting data type - defines which of the available plug-ins in
   9916 		 * afnSortData the custom sorting will use - if any is defined.
   9917 		 */
   9918 		"sSortDataType": 'std',
   9919 	
   9920 		/**
   9921 		 * Class to be applied to the header element when sorting on this column
   9922 		 */
   9923 		"sSortingClass": null,
   9924 	
   9925 		/**
   9926 		 * Title of the column - what is seen in the TH element (nTh).
   9927 		 */
   9928 		"sTitle": null,
   9929 	
   9930 		/**
   9931 		 * Column sorting and filtering type
   9932 		 */
   9933 		"sType": null,
   9934 	
   9935 		/**
   9936 		 * Width of the column
   9937 		 */
   9938 		"sWidth": null,
   9939 	
   9940 		/**
   9941 		 * Width of the column when it was first "encountered"
   9942 		 */
   9943 		"sWidthOrig": null,
   9944 	
   9945 		/** Cached string which is the longest in the column */
   9946 		maxLenString: null,
   9947 	
   9948 		/**
   9949 		 * Store for named searches
   9950 		 */
   9951 		searchFixed: null
   9952 	};
   9953 	
   9954 	
   9955 	/*
   9956 	 * Developer note: The properties of the object below are given in Hungarian
   9957 	 * notation, that was used as the interface for DataTables prior to v1.10, however
   9958 	 * from v1.10 onwards the primary interface is camel case. In order to avoid
   9959 	 * breaking backwards compatibility utterly with this change, the Hungarian
   9960 	 * version is still, internally the primary interface, but is is not documented
   9961 	 * - hence the @name tags in each doc comment. This allows a Javascript function
   9962 	 * to create a map from Hungarian notation to camel case (going the other direction
   9963 	 * would require each property to be listed, which would add around 3K to the size
   9964 	 * of DataTables, while this method is about a 0.5K hit).
   9965 	 *
   9966 	 * Ultimately this does pave the way for Hungarian notation to be dropped
   9967 	 * completely, but that is a massive amount of work and will break current
   9968 	 * installs (therefore is on-hold until v2).
   9969 	 */
   9970 	
   9971 	/**
   9972 	 * Initialisation options that can be given to DataTables at initialisation
   9973 	 * time.
   9974 	 *  @namespace
   9975 	 */
   9976 	DataTable.defaults = {
   9977 		/**
   9978 		 * An array of data to use for the table, passed in at initialisation which
   9979 		 * will be used in preference to any data which is already in the DOM. This is
   9980 		 * particularly useful for constructing tables purely in Javascript, for
   9981 		 * example with a custom Ajax call.
   9982 		 */
   9983 		"aaData": null,
   9984 	
   9985 	
   9986 		/**
   9987 		 * If ordering is enabled, then DataTables will perform a first pass sort on
   9988 		 * initialisation. You can define which column(s) the sort is performed
   9989 		 * upon, and the sorting direction, with this variable. The `sorting` array
   9990 		 * should contain an array for each column to be sorted initially containing
   9991 		 * the column's index and a direction string ('asc' or 'desc').
   9992 		 */
   9993 		"aaSorting": [[0,'asc']],
   9994 	
   9995 	
   9996 		/**
   9997 		 * This parameter is basically identical to the `sorting` parameter, but
   9998 		 * cannot be overridden by user interaction with the table. What this means
   9999 		 * is that you could have a column (visible or hidden) which the sorting
  10000 		 * will always be forced on first - any sorting after that (from the user)
  10001 		 * will then be performed as required. This can be useful for grouping rows
  10002 		 * together.
  10003 		 */
  10004 		"aaSortingFixed": [],
  10005 	
  10006 	
  10007 		/**
  10008 		 * DataTables can be instructed to load data to display in the table from a
  10009 		 * Ajax source. This option defines how that Ajax call is made and where to.
  10010 		 *
  10011 		 * The `ajax` property has three different modes of operation, depending on
  10012 		 * how it is defined. These are:
  10013 		 *
  10014 		 * * `string` - Set the URL from where the data should be loaded from.
  10015 		 * * `object` - Define properties for `jQuery.ajax`.
  10016 		 * * `function` - Custom data get function
  10017 		 *
  10018 		 * `string`
  10019 		 * --------
  10020 		 *
  10021 		 * As a string, the `ajax` property simply defines the URL from which
  10022 		 * DataTables will load data.
  10023 		 *
  10024 		 * `object`
  10025 		 * --------
  10026 		 *
  10027 		 * As an object, the parameters in the object are passed to
  10028 		 * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
  10029 		 * of the Ajax request. DataTables has a number of default parameters which
  10030 		 * you can override using this option. Please refer to the jQuery
  10031 		 * documentation for a full description of the options available, although
  10032 		 * the following parameters provide additional options in DataTables or
  10033 		 * require special consideration:
  10034 		 *
  10035 		 * * `data` - As with jQuery, `data` can be provided as an object, but it
  10036 		 *   can also be used as a function to manipulate the data DataTables sends
  10037 		 *   to the server. The function takes a single parameter, an object of
  10038 		 *   parameters with the values that DataTables has readied for sending. An
  10039 		 *   object may be returned which will be merged into the DataTables
  10040 		 *   defaults, or you can add the items to the object that was passed in and
  10041 		 *   not return anything from the function. This supersedes `fnServerParams`
  10042 		 *   from DataTables 1.9-.
  10043 		 *
  10044 		 * * `dataSrc` - By default DataTables will look for the property `data` (or
  10045 		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
  10046 		 *   from an Ajax source or for server-side processing - this parameter
  10047 		 *   allows that property to be changed. You can use Javascript dotted
  10048 		 *   object notation to get a data source for multiple levels of nesting, or
  10049 		 *   it my be used as a function. As a function it takes a single parameter,
  10050 		 *   the JSON returned from the server, which can be manipulated as
  10051 		 *   required, with the returned value being that used by DataTables as the
  10052 		 *   data source for the table.
  10053 		 *
  10054 		 * * `success` - Should not be overridden it is used internally in
  10055 		 *   DataTables. To manipulate / transform the data returned by the server
  10056 		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
  10057 		 *
  10058 		 * `function`
  10059 		 * ----------
  10060 		 *
  10061 		 * As a function, making the Ajax call is left up to yourself allowing
  10062 		 * complete control of the Ajax request. Indeed, if desired, a method other
  10063 		 * than Ajax could be used to obtain the required data, such as Web storage
  10064 		 * or an AIR database.
  10065 		 *
  10066 		 * The function is given four parameters and no return is required. The
  10067 		 * parameters are:
  10068 		 *
  10069 		 * 1. _object_ - Data to send to the server
  10070 		 * 2. _function_ - Callback function that must be executed when the required
  10071 		 *    data has been obtained. That data should be passed into the callback
  10072 		 *    as the only parameter
  10073 		 * 3. _object_ - DataTables settings object for the table
  10074 		 */
  10075 		"ajax": null,
  10076 	
  10077 	
  10078 		/**
  10079 		 * This parameter allows you to readily specify the entries in the length drop
  10080 		 * down menu that DataTables shows when pagination is enabled. It can be
  10081 		 * either a 1D array of options which will be used for both the displayed
  10082 		 * option and the value, or a 2D array which will use the array in the first
  10083 		 * position as the value, and the array in the second position as the
  10084 		 * displayed options (useful for language strings such as 'All').
  10085 		 *
  10086 		 * Note that the `pageLength` property will be automatically set to the
  10087 		 * first value given in this array, unless `pageLength` is also provided.
  10088 		 */
  10089 		"aLengthMenu": [ 10, 25, 50, 100 ],
  10090 	
  10091 	
  10092 		/**
  10093 		 * The `columns` option in the initialisation parameter allows you to define
  10094 		 * details about the way individual columns behave. For a full list of
  10095 		 * column options that can be set, please see
  10096 		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
  10097 		 * define your columns, you must have an entry in the array for every single
  10098 		 * column that you have in your table (these can be null if you don't which
  10099 		 * to specify any options).
  10100 		 */
  10101 		"aoColumns": null,
  10102 	
  10103 		/**
  10104 		 * Very similar to `columns`, `columnDefs` allows you to target a specific
  10105 		 * column, multiple columns, or all columns, using the `targets` property of
  10106 		 * each object in the array. This allows great flexibility when creating
  10107 		 * tables, as the `columnDefs` arrays can be of any length, targeting the
  10108 		 * columns you specifically want. `columnDefs` may use any of the column
  10109 		 * options available: {@link DataTable.defaults.column}, but it _must_
  10110 		 * have `targets` defined in each object in the array. Values in the `targets`
  10111 		 * array may be:
  10112 		 *   <ul>
  10113 		 *     <li>a string - class name will be matched on the TH for the column</li>
  10114 		 *     <li>0 or a positive integer - column index counting from the left</li>
  10115 		 *     <li>a negative integer - column index counting from the right</li>
  10116 		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
  10117 		 *   </ul>
  10118 		 */
  10119 		"aoColumnDefs": null,
  10120 	
  10121 	
  10122 		/**
  10123 		 * Basically the same as `search`, this parameter defines the individual column
  10124 		 * filtering state at initialisation time. The array must be of the same size
  10125 		 * as the number of columns, and each element be an object with the parameters
  10126 		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
  10127 		 * accepted and the default will be used.
  10128 		 */
  10129 		"aoSearchCols": [],
  10130 	
  10131 	
  10132 		/**
  10133 		 * Enable or disable automatic column width calculation. This can be disabled
  10134 		 * as an optimisation (it takes some time to calculate the widths) if the
  10135 		 * tables widths are passed in using `columns`.
  10136 		 */
  10137 		"bAutoWidth": true,
  10138 	
  10139 	
  10140 		/**
  10141 		 * Deferred rendering can provide DataTables with a huge speed boost when you
  10142 		 * are using an Ajax or JS data source for the table. This option, when set to
  10143 		 * true, will cause DataTables to defer the creation of the table elements for
  10144 		 * each row until they are needed for a draw - saving a significant amount of
  10145 		 * time.
  10146 		 */
  10147 		"bDeferRender": true,
  10148 	
  10149 	
  10150 		/**
  10151 		 * Replace a DataTable which matches the given selector and replace it with
  10152 		 * one which has the properties of the new initialisation object passed. If no
  10153 		 * table matches the selector, then the new DataTable will be constructed as
  10154 		 * per normal.
  10155 		 */
  10156 		"bDestroy": false,
  10157 	
  10158 	
  10159 		/**
  10160 		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
  10161 		 * that it allows the end user to input multiple words (space separated) and
  10162 		 * will match a row containing those words, even if not in the order that was
  10163 		 * specified (this allow matching across multiple columns). Note that if you
  10164 		 * wish to use filtering in DataTables this must remain 'true' - to remove the
  10165 		 * default filtering input box and retain filtering abilities, please use
  10166 		 * {@link DataTable.defaults.dom}.
  10167 		 */
  10168 		"bFilter": true,
  10169 	
  10170 		/**
  10171 		 * Used only for compatiblity with DT1
  10172 		 * @deprecated
  10173 		 */
  10174 		"bInfo": true,
  10175 	
  10176 		/**
  10177 		 * Used only for compatiblity with DT1
  10178 		 * @deprecated
  10179 		 */
  10180 		"bLengthChange": true,
  10181 	
  10182 		/**
  10183 		 * Enable or disable pagination.
  10184 		 */
  10185 		"bPaginate": true,
  10186 	
  10187 	
  10188 		/**
  10189 		 * Enable or disable the display of a 'processing' indicator when the table is
  10190 		 * being processed (e.g. a sort). This is particularly useful for tables with
  10191 		 * large amounts of data where it can take a noticeable amount of time to sort
  10192 		 * the entries.
  10193 		 */
  10194 		"bProcessing": false,
  10195 	
  10196 	
  10197 		/**
  10198 		 * Retrieve the DataTables object for the given selector. Note that if the
  10199 		 * table has already been initialised, this parameter will cause DataTables
  10200 		 * to simply return the object that has already been set up - it will not take
  10201 		 * account of any changes you might have made to the initialisation object
  10202 		 * passed to DataTables (setting this parameter to true is an acknowledgement
  10203 		 * that you understand this). `destroy` can be used to reinitialise a table if
  10204 		 * you need.
  10205 		 */
  10206 		"bRetrieve": false,
  10207 	
  10208 	
  10209 		/**
  10210 		 * When vertical (y) scrolling is enabled, DataTables will force the height of
  10211 		 * the table's viewport to the given height at all times (useful for layout).
  10212 		 * However, this can look odd when filtering data down to a small data set,
  10213 		 * and the footer is left "floating" further down. This parameter (when
  10214 		 * enabled) will cause DataTables to collapse the table's viewport down when
  10215 		 * the result set will fit within the given Y height.
  10216 		 */
  10217 		"bScrollCollapse": false,
  10218 	
  10219 	
  10220 		/**
  10221 		 * Configure DataTables to use server-side processing. Note that the
  10222 		 * `ajax` parameter must also be given in order to give DataTables a
  10223 		 * source to obtain the required data for each draw.
  10224 		 */
  10225 		"bServerSide": false,
  10226 	
  10227 	
  10228 		/**
  10229 		 * Enable or disable sorting of columns. Sorting of individual columns can be
  10230 		 * disabled by the `sortable` option for each column.
  10231 		 */
  10232 		"bSort": true,
  10233 	
  10234 	
  10235 		/**
  10236 		 * Enable or display DataTables' ability to sort multiple columns at the
  10237 		 * same time (activated by shift-click by the user).
  10238 		 */
  10239 		"bSortMulti": true,
  10240 	
  10241 	
  10242 		/**
  10243 		 * Allows control over whether DataTables should use the top (true) unique
  10244 		 * cell that is found for a single column, or the bottom (false - default).
  10245 		 * This is useful when using complex headers.
  10246 		 */
  10247 		"bSortCellsTop": null,
  10248 	
  10249 	
  10250 		/**
  10251 		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
  10252 		 * `sorting\_3` to the columns which are currently being sorted on. This is
  10253 		 * presented as a feature switch as it can increase processing time (while
  10254 		 * classes are removed and added) so for large data sets you might want to
  10255 		 * turn this off.
  10256 		 */
  10257 		"bSortClasses": true,
  10258 	
  10259 	
  10260 		/**
  10261 		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
  10262 		 * used to save table display information such as pagination information,
  10263 		 * display length, filtering and sorting. As such when the end user reloads
  10264 		 * the page the display display will match what thy had previously set up.
  10265 		 */
  10266 		"bStateSave": false,
  10267 	
  10268 	
  10269 		/**
  10270 		 * This function is called when a TR element is created (and all TD child
  10271 		 * elements have been inserted), or registered if using a DOM source, allowing
  10272 		 * manipulation of the TR element (adding classes etc).
  10273 		 */
  10274 		"fnCreatedRow": null,
  10275 	
  10276 	
  10277 		/**
  10278 		 * This function is called on every 'draw' event, and allows you to
  10279 		 * dynamically modify any aspect you want about the created DOM.
  10280 		 */
  10281 		"fnDrawCallback": null,
  10282 	
  10283 	
  10284 		/**
  10285 		 * Identical to fnHeaderCallback() but for the table footer this function
  10286 		 * allows you to modify the table footer on every 'draw' event.
  10287 		 */
  10288 		"fnFooterCallback": null,
  10289 	
  10290 	
  10291 		/**
  10292 		 * When rendering large numbers in the information element for the table
  10293 		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
  10294 		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
  10295 		 * rendered as "1,000,000") to help readability for the end user. This
  10296 		 * function will override the default method DataTables uses.
  10297 		 */
  10298 		"fnFormatNumber": function ( toFormat ) {
  10299 			return toFormat.toString().replace(
  10300 				/\B(?=(\d{3})+(?!\d))/g,
  10301 				this.oLanguage.sThousands
  10302 			);
  10303 		},
  10304 	
  10305 	
  10306 		/**
  10307 		 * This function is called on every 'draw' event, and allows you to
  10308 		 * dynamically modify the header row. This can be used to calculate and
  10309 		 * display useful information about the table.
  10310 		 */
  10311 		"fnHeaderCallback": null,
  10312 	
  10313 	
  10314 		/**
  10315 		 * The information element can be used to convey information about the current
  10316 		 * state of the table. Although the internationalisation options presented by
  10317 		 * DataTables are quite capable of dealing with most customisations, there may
  10318 		 * be times where you wish to customise the string further. This callback
  10319 		 * allows you to do exactly that.
  10320 		 */
  10321 		"fnInfoCallback": null,
  10322 	
  10323 	
  10324 		/**
  10325 		 * Called when the table has been initialised. Normally DataTables will
  10326 		 * initialise sequentially and there will be no need for this function,
  10327 		 * however, this does not hold true when using external language information
  10328 		 * since that is obtained using an async XHR call.
  10329 		 */
  10330 		"fnInitComplete": null,
  10331 	
  10332 	
  10333 		/**
  10334 		 * Called at the very start of each table draw and can be used to cancel the
  10335 		 * draw by returning false, any other return (including undefined) results in
  10336 		 * the full draw occurring).
  10337 		 */
  10338 		"fnPreDrawCallback": null,
  10339 	
  10340 	
  10341 		/**
  10342 		 * This function allows you to 'post process' each row after it have been
  10343 		 * generated for each table draw, but before it is rendered on screen. This
  10344 		 * function might be used for setting the row class name etc.
  10345 		 */
  10346 		"fnRowCallback": null,
  10347 	
  10348 	
  10349 		/**
  10350 		 * Load the table state. With this function you can define from where, and how, the
  10351 		 * state of a table is loaded. By default DataTables will load from `localStorage`
  10352 		 * but you might wish to use a server-side database or cookies.
  10353 		 */
  10354 		"fnStateLoadCallback": function ( settings ) {
  10355 			try {
  10356 				return JSON.parse(
  10357 					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
  10358 						'DataTables_'+settings.sInstance+'_'+location.pathname
  10359 					)
  10360 				);
  10361 			} catch (e) {
  10362 				return {};
  10363 			}
  10364 		},
  10365 	
  10366 	
  10367 		/**
  10368 		 * Callback which allows modification of the saved state prior to loading that state.
  10369 		 * This callback is called when the table is loading state from the stored data, but
  10370 		 * prior to the settings object being modified by the saved state. Note that for
  10371 		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
  10372 		 * a plug-in.
  10373 		 */
  10374 		"fnStateLoadParams": null,
  10375 	
  10376 	
  10377 		/**
  10378 		 * Callback that is called when the state has been loaded from the state saving method
  10379 		 * and the DataTables settings object has been modified as a result of the loaded state.
  10380 		 */
  10381 		"fnStateLoaded": null,
  10382 	
  10383 	
  10384 		/**
  10385 		 * Save the table state. This function allows you to define where and how the state
  10386 		 * information for the table is stored By default DataTables will use `localStorage`
  10387 		 * but you might wish to use a server-side database or cookies.
  10388 		 */
  10389 		"fnStateSaveCallback": function ( settings, data ) {
  10390 			try {
  10391 				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
  10392 					'DataTables_'+settings.sInstance+'_'+location.pathname,
  10393 					JSON.stringify( data )
  10394 				);
  10395 			} catch (e) {
  10396 				// noop
  10397 			}
  10398 		},
  10399 	
  10400 	
  10401 		/**
  10402 		 * Callback which allows modification of the state to be saved. Called when the table
  10403 		 * has changed state a new state save is required. This method allows modification of
  10404 		 * the state saving object prior to actually doing the save, including addition or
  10405 		 * other state properties or modification. Note that for plug-in authors, you should
  10406 		 * use the `stateSaveParams` event to save parameters for a plug-in.
  10407 		 */
  10408 		"fnStateSaveParams": null,
  10409 	
  10410 	
  10411 		/**
  10412 		 * Duration for which the saved state information is considered valid. After this period
  10413 		 * has elapsed the state will be returned to the default.
  10414 		 * Value is given in seconds.
  10415 		 */
  10416 		"iStateDuration": 7200,
  10417 	
  10418 	
  10419 		/**
  10420 		 * Number of rows to display on a single page when using pagination. If
  10421 		 * feature enabled (`lengthChange`) then the end user will be able to override
  10422 		 * this to a custom setting using a pop-up menu.
  10423 		 */
  10424 		"iDisplayLength": 10,
  10425 	
  10426 	
  10427 		/**
  10428 		 * Define the starting point for data display when using DataTables with
  10429 		 * pagination. Note that this parameter is the number of records, rather than
  10430 		 * the page number, so if you have 10 records per page and want to start on
  10431 		 * the third page, it should be "20".
  10432 		 */
  10433 		"iDisplayStart": 0,
  10434 	
  10435 	
  10436 		/**
  10437 		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
  10438 		 * and filtering) by adding a `tabindex` attribute to the required elements. This
  10439 		 * allows you to tab through the controls and press the enter key to activate them.
  10440 		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
  10441 		 * You can overrule this using this parameter if you wish. Use a value of -1 to
  10442 		 * disable built-in keyboard navigation.
  10443 		 */
  10444 		"iTabIndex": 0,
  10445 	
  10446 	
  10447 		/**
  10448 		 * Classes that DataTables assigns to the various components and features
  10449 		 * that it adds to the HTML table. This allows classes to be configured
  10450 		 * during initialisation in addition to through the static
  10451 		 * {@link DataTable.ext.oStdClasses} object).
  10452 		 */
  10453 		"oClasses": {},
  10454 	
  10455 	
  10456 		/**
  10457 		 * All strings that DataTables uses in the user interface that it creates
  10458 		 * are defined in this object, allowing you to modified them individually or
  10459 		 * completely replace them all as required.
  10460 		 */
  10461 		"oLanguage": {
  10462 			/**
  10463 			 * Strings that are used for WAI-ARIA labels and controls only (these are not
  10464 			 * actually visible on the page, but will be read by screenreaders, and thus
  10465 			 * must be internationalised as well).
  10466 			 */
  10467 			"oAria": {
  10468 				/**
  10469 				 * ARIA label that is added to the table headers when the column may be sorted
  10470 				 */
  10471 				"orderable": ": Activate to sort",
  10472 	
  10473 				/**
  10474 				 * ARIA label that is added to the table headers when the column is currently being sorted
  10475 				 */
  10476 				"orderableReverse": ": Activate to invert sorting",
  10477 	
  10478 				/**
  10479 				 * ARIA label that is added to the table headers when the column is currently being 
  10480 				 * sorted and next step is to remove sorting
  10481 				 */
  10482 				"orderableRemove": ": Activate to remove sorting",
  10483 	
  10484 				paginate: {
  10485 					first: 'First',
  10486 					last: 'Last',
  10487 					next: 'Next',
  10488 					previous: 'Previous'
  10489 				}
  10490 			},
  10491 	
  10492 			/**
  10493 			 * Pagination string used by DataTables for the built-in pagination
  10494 			 * control types.
  10495 			 */
  10496 			"oPaginate": {
  10497 				/**
  10498 				 * Label and character for first page button («)
  10499 				 */
  10500 				"sFirst": "\u00AB",
  10501 	
  10502 				/**
  10503 				 * Last page button (»)
  10504 				 */
  10505 				"sLast": "\u00BB",
  10506 	
  10507 				/**
  10508 				 * Next page button (›)
  10509 				 */
  10510 				"sNext": "\u203A",
  10511 	
  10512 				/**
  10513 				 * Previous page button (‹)
  10514 				 */
  10515 				"sPrevious": "\u2039",
  10516 			},
  10517 	
  10518 			/**
  10519 			 * Plural object for the data type the table is showing
  10520 			 */
  10521 			entries: {
  10522 				_: "entries",
  10523 				1: "entry"
  10524 			},
  10525 	
  10526 			/**
  10527 			 * This string is shown in preference to `zeroRecords` when the table is
  10528 			 * empty of data (regardless of filtering). Note that this is an optional
  10529 			 * parameter - if it is not given, the value of `zeroRecords` will be used
  10530 			 * instead (either the default or given value).
  10531 			 */
  10532 			"sEmptyTable": "No data available in table",
  10533 	
  10534 	
  10535 			/**
  10536 			 * This string gives information to the end user about the information
  10537 			 * that is current on display on the page. The following tokens can be
  10538 			 * used in the string and will be dynamically replaced as the table
  10539 			 * display updates. This tokens can be placed anywhere in the string, or
  10540 			 * removed as needed by the language requires:
  10541 			 *
  10542 			 * * `\_START\_` - Display index of the first record on the current page
  10543 			 * * `\_END\_` - Display index of the last record on the current page
  10544 			 * * `\_TOTAL\_` - Number of records in the table after filtering
  10545 			 * * `\_MAX\_` - Number of records in the table without filtering
  10546 			 * * `\_PAGE\_` - Current page number
  10547 			 * * `\_PAGES\_` - Total number of pages of data in the table
  10548 			 */
  10549 			"sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
  10550 	
  10551 	
  10552 			/**
  10553 			 * Display information string for when the table is empty. Typically the
  10554 			 * format of this string should match `info`.
  10555 			 */
  10556 			"sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
  10557 	
  10558 	
  10559 			/**
  10560 			 * When a user filters the information in a table, this string is appended
  10561 			 * to the information (`info`) to give an idea of how strong the filtering
  10562 			 * is. The variable _MAX_ is dynamically updated.
  10563 			 */
  10564 			"sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
  10565 	
  10566 	
  10567 			/**
  10568 			 * If can be useful to append extra information to the info string at times,
  10569 			 * and this variable does exactly that. This information will be appended to
  10570 			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
  10571 			 * being used) at all times.
  10572 			 */
  10573 			"sInfoPostFix": "",
  10574 	
  10575 	
  10576 			/**
  10577 			 * This decimal place operator is a little different from the other
  10578 			 * language options since DataTables doesn't output floating point
  10579 			 * numbers, so it won't ever use this for display of a number. Rather,
  10580 			 * what this parameter does is modify the sort methods of the table so
  10581 			 * that numbers which are in a format which has a character other than
  10582 			 * a period (`.`) as a decimal place will be sorted numerically.
  10583 			 *
  10584 			 * Note that numbers with different decimal places cannot be shown in
  10585 			 * the same table and still be sortable, the table must be consistent.
  10586 			 * However, multiple different tables on the page can use different
  10587 			 * decimal place characters.
  10588 			 */
  10589 			"sDecimal": "",
  10590 	
  10591 	
  10592 			/**
  10593 			 * DataTables has a build in number formatter (`formatNumber`) which is
  10594 			 * used to format large numbers that are used in the table information.
  10595 			 * By default a comma is used, but this can be trivially changed to any
  10596 			 * character you wish with this parameter.
  10597 			 */
  10598 			"sThousands": ",",
  10599 	
  10600 	
  10601 			/**
  10602 			 * Detail the action that will be taken when the drop down menu for the
  10603 			 * pagination length option is changed. The '_MENU_' variable is replaced
  10604 			 * with a default select list of 10, 25, 50 and 100, and can be replaced
  10605 			 * with a custom select box if required.
  10606 			 */
  10607 			"sLengthMenu": "_MENU_ _ENTRIES_ per page",
  10608 	
  10609 	
  10610 			/**
  10611 			 * When using Ajax sourced data and during the first draw when DataTables is
  10612 			 * gathering the data, this message is shown in an empty row in the table to
  10613 			 * indicate to the end user the the data is being loaded. Note that this
  10614 			 * parameter is not used when loading data by server-side processing, just
  10615 			 * Ajax sourced data with client-side processing.
  10616 			 */
  10617 			"sLoadingRecords": "Loading...",
  10618 	
  10619 	
  10620 			/**
  10621 			 * Text which is displayed when the table is processing a user action
  10622 			 * (usually a sort command or similar).
  10623 			 */
  10624 			"sProcessing": "",
  10625 	
  10626 	
  10627 			/**
  10628 			 * Details the actions that will be taken when the user types into the
  10629 			 * filtering input text box. The variable "_INPUT_", if used in the string,
  10630 			 * is replaced with the HTML text box for the filtering input allowing
  10631 			 * control over where it appears in the string. If "_INPUT_" is not given
  10632 			 * then the input box is appended to the string automatically.
  10633 			 */
  10634 			"sSearch": "Search:",
  10635 	
  10636 	
  10637 			/**
  10638 			 * Assign a `placeholder` attribute to the search `input` element
  10639 			 *  @type string
  10640 			 *  @default 
  10641 			 *
  10642 			 *  @dtopt Language
  10643 			 *  @name DataTable.defaults.language.searchPlaceholder
  10644 			 */
  10645 			"sSearchPlaceholder": "",
  10646 	
  10647 	
  10648 			/**
  10649 			 * All of the language information can be stored in a file on the
  10650 			 * server-side, which DataTables will look up if this parameter is passed.
  10651 			 * It must store the URL of the language file, which is in a JSON format,
  10652 			 * and the object has the same properties as the oLanguage object in the
  10653 			 * initialiser object (i.e. the above parameters). Please refer to one of
  10654 			 * the example language files to see how this works in action.
  10655 			 */
  10656 			"sUrl": "",
  10657 	
  10658 	
  10659 			/**
  10660 			 * Text shown inside the table records when the is no information to be
  10661 			 * displayed after filtering. `emptyTable` is shown when there is simply no
  10662 			 * information in the table at all (regardless of filtering).
  10663 			 */
  10664 			"sZeroRecords": "No matching records found"
  10665 		},
  10666 	
  10667 	
  10668 		/**
  10669 		 * This parameter allows you to have define the global filtering state at
  10670 		 * initialisation time. As an object the `search` parameter must be
  10671 		 * defined, but all other parameters are optional. When `regex` is true,
  10672 		 * the search string will be treated as a regular expression, when false
  10673 		 * (default) it will be treated as a straight string. When `smart`
  10674 		 * DataTables will use it's smart filtering methods (to word match at
  10675 		 * any point in the data), when false this will not be done.
  10676 		 */
  10677 		"oSearch": $.extend( {}, DataTable.models.oSearch ),
  10678 	
  10679 	
  10680 		/**
  10681 		 * Table and control layout. This replaces the legacy `dom` option.
  10682 		 */
  10683 		layout: {
  10684 			topStart: 'pageLength',
  10685 			topEnd: 'search',
  10686 			bottomStart: 'info',
  10687 			bottomEnd: 'paging'
  10688 		},
  10689 	
  10690 	
  10691 		/**
  10692 		 * Legacy DOM layout option
  10693 		 */
  10694 		"sDom": null,
  10695 	
  10696 	
  10697 		/**
  10698 		 * Search delay option. This will throttle full table searches that use the
  10699 		 * DataTables provided search input element (it does not effect calls to
  10700 		 * `dt-api search()`, providing a delay before the search is made.
  10701 		 */
  10702 		"searchDelay": null,
  10703 	
  10704 	
  10705 		/**
  10706 		 * DataTables features six different built-in options for the buttons to
  10707 		 * display for pagination control:
  10708 		 *
  10709 		 * * `numbers` - Page number buttons only
  10710 		 * * `simple` - 'Previous' and 'Next' buttons only
  10711 		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
  10712 		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
  10713 		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
  10714 		 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
  10715 		 */
  10716 		"sPaginationType": "full_numbers",
  10717 	
  10718 	
  10719 		/**
  10720 		 * Enable horizontal scrolling. When a table is too wide to fit into a
  10721 		 * certain layout, or you have a large number of columns in the table, you
  10722 		 * can enable x-scrolling to show the table in a viewport, which can be
  10723 		 * scrolled. This property can be `true` which will allow the table to
  10724 		 * scroll horizontally when needed, or any CSS unit, or a number (in which
  10725 		 * case it will be treated as a pixel measurement). Setting as simply `true`
  10726 		 * is recommended.
  10727 		 */
  10728 		"sScrollX": "",
  10729 	
  10730 	
  10731 		/**
  10732 		 * This property can be used to force a DataTable to use more width than it
  10733 		 * might otherwise do when x-scrolling is enabled. For example if you have a
  10734 		 * table which requires to be well spaced, this parameter is useful for
  10735 		 * "over-sizing" the table, and thus forcing scrolling. This property can by
  10736 		 * any CSS unit, or a number (in which case it will be treated as a pixel
  10737 		 * measurement).
  10738 		 */
  10739 		"sScrollXInner": "",
  10740 	
  10741 	
  10742 		/**
  10743 		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
  10744 		 * to the given height, and enable scrolling for any data which overflows the
  10745 		 * current viewport. This can be used as an alternative to paging to display
  10746 		 * a lot of data in a small area (although paging and scrolling can both be
  10747 		 * enabled at the same time). This property can be any CSS unit, or a number
  10748 		 * (in which case it will be treated as a pixel measurement).
  10749 		 */
  10750 		"sScrollY": "",
  10751 	
  10752 	
  10753 		/**
  10754 		 * __Deprecated__ The functionality provided by this parameter has now been
  10755 		 * superseded by that provided through `ajax`, which should be used instead.
  10756 		 *
  10757 		 * Set the HTTP method that is used to make the Ajax call for server-side
  10758 		 * processing or Ajax sourced data.
  10759 		 */
  10760 		"sServerMethod": "GET",
  10761 	
  10762 	
  10763 		/**
  10764 		 * DataTables makes use of renderers when displaying HTML elements for
  10765 		 * a table. These renderers can be added or modified by plug-ins to
  10766 		 * generate suitable mark-up for a site. For example the Bootstrap
  10767 		 * integration plug-in for DataTables uses a paging button renderer to
  10768 		 * display pagination buttons in the mark-up required by Bootstrap.
  10769 		 *
  10770 		 * For further information about the renderers available see
  10771 		 * DataTable.ext.renderer
  10772 		 */
  10773 		"renderer": null,
  10774 	
  10775 	
  10776 		/**
  10777 		 * Set the data property name that DataTables should use to get a row's id
  10778 		 * to set as the `id` property in the node.
  10779 		 */
  10780 		"rowId": "DT_RowId",
  10781 	
  10782 	
  10783 		/**
  10784 		 * Caption value
  10785 		 */
  10786 		"caption": null
  10787 	};
  10788 	
  10789 	_fnHungarianMap( DataTable.defaults );
  10790 	
  10791 	
  10792 	
  10793 	/*
  10794 	 * Developer note - See note in model.defaults.js about the use of Hungarian
  10795 	 * notation and camel case.
  10796 	 */
  10797 	
  10798 	/**
  10799 	 * Column options that can be given to DataTables at initialisation time.
  10800 	 *  @namespace
  10801 	 */
  10802 	DataTable.defaults.column = {
  10803 		/**
  10804 		 * Define which column(s) an order will occur on for this column. This
  10805 		 * allows a column's ordering to take multiple columns into account when
  10806 		 * doing a sort or use the data from a different column. For example first
  10807 		 * name / last name columns make sense to do a multi-column sort over the
  10808 		 * two columns.
  10809 		 */
  10810 		"aDataSort": null,
  10811 		"iDataSort": -1,
  10812 	
  10813 		ariaTitle: '',
  10814 	
  10815 	
  10816 		/**
  10817 		 * You can control the default ordering direction, and even alter the
  10818 		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
  10819 		 * using this parameter.
  10820 		 */
  10821 		"asSorting": [ 'asc', 'desc', '' ],
  10822 	
  10823 	
  10824 		/**
  10825 		 * Enable or disable filtering on the data in this column.
  10826 		 */
  10827 		"bSearchable": true,
  10828 	
  10829 	
  10830 		/**
  10831 		 * Enable or disable ordering on this column.
  10832 		 */
  10833 		"bSortable": true,
  10834 	
  10835 	
  10836 		/**
  10837 		 * Enable or disable the display of this column.
  10838 		 */
  10839 		"bVisible": true,
  10840 	
  10841 	
  10842 		/**
  10843 		 * Developer definable function that is called whenever a cell is created (Ajax source,
  10844 		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
  10845 		 * allowing you to modify the DOM element (add background colour for example) when the
  10846 		 * element is available.
  10847 		 */
  10848 		"fnCreatedCell": null,
  10849 	
  10850 	
  10851 		/**
  10852 		 * This property can be used to read data from any data source property,
  10853 		 * including deeply nested objects / properties. `data` can be given in a
  10854 		 * number of different ways which effect its behaviour:
  10855 		 *
  10856 		 * * `integer` - treated as an array index for the data source. This is the
  10857 		 *   default that DataTables uses (incrementally increased for each column).
  10858 		 * * `string` - read an object property from the data source. There are
  10859 		 *   three 'special' options that can be used in the string to alter how
  10860 		 *   DataTables reads the data from the source object:
  10861 		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
  10862 		 *      Javascript to read from nested objects, so to can the options
  10863 		 *      specified in `data`. For example: `browser.version` or
  10864 		 *      `browser.name`. If your object parameter name contains a period, use
  10865 		 *      `\\` to escape it - i.e. `first\\.name`.
  10866 		 *    * `[]` - Array notation. DataTables can automatically combine data
  10867 		 *      from and array source, joining the data with the characters provided
  10868 		 *      between the two brackets. For example: `name[, ]` would provide a
  10869 		 *      comma-space separated list from the source array. If no characters
  10870 		 *      are provided between the brackets, the original array source is
  10871 		 *      returned.
  10872 		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
  10873 		 *      execute a function of the name given. For example: `browser()` for a
  10874 		 *      simple function on the data source, `browser.version()` for a
  10875 		 *      function in a nested property or even `browser().version` to get an
  10876 		 *      object property if the function called returns an object. Note that
  10877 		 *      function notation is recommended for use in `render` rather than
  10878 		 *      `data` as it is much simpler to use as a renderer.
  10879 		 * * `null` - use the original data source for the row rather than plucking
  10880 		 *   data directly from it. This action has effects on two other
  10881 		 *   initialisation options:
  10882 		 *    * `defaultContent` - When null is given as the `data` option and
  10883 		 *      `defaultContent` is specified for the column, the value defined by
  10884 		 *      `defaultContent` will be used for the cell.
  10885 		 *    * `render` - When null is used for the `data` option and the `render`
  10886 		 *      option is specified for the column, the whole data source for the
  10887 		 *      row is used for the renderer.
  10888 		 * * `function` - the function given will be executed whenever DataTables
  10889 		 *   needs to set or get the data for a cell in the column. The function
  10890 		 *   takes three parameters:
  10891 		 *    * Parameters:
  10892 		 *      * `{array|object}` The data source for the row
  10893 		 *      * `{string}` The type call data requested - this will be 'set' when
  10894 		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
  10895 		 *        when gathering data. Note that when `undefined` is given for the
  10896 		 *        type DataTables expects to get the raw data for the object back<
  10897 		 *      * `{*}` Data to set when the second parameter is 'set'.
  10898 		 *    * Return:
  10899 		 *      * The return value from the function is not required when 'set' is
  10900 		 *        the type of call, but otherwise the return is what will be used
  10901 		 *        for the data requested.
  10902 		 *
  10903 		 * Note that `data` is a getter and setter option. If you just require
  10904 		 * formatting of data for output, you will likely want to use `render` which
  10905 		 * is simply a getter and thus simpler to use.
  10906 		 *
  10907 		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
  10908 		 * name change reflects the flexibility of this property and is consistent
  10909 		 * with the naming of mRender. If 'mDataProp' is given, then it will still
  10910 		 * be used by DataTables, as it automatically maps the old name to the new
  10911 		 * if required.
  10912 		 */
  10913 		"mData": null,
  10914 	
  10915 	
  10916 		/**
  10917 		 * This property is the rendering partner to `data` and it is suggested that
  10918 		 * when you want to manipulate data for display (including filtering,
  10919 		 * sorting etc) without altering the underlying data for the table, use this
  10920 		 * property. `render` can be considered to be the the read only companion to
  10921 		 * `data` which is read / write (then as such more complex). Like `data`
  10922 		 * this option can be given in a number of different ways to effect its
  10923 		 * behaviour:
  10924 		 *
  10925 		 * * `integer` - treated as an array index for the data source. This is the
  10926 		 *   default that DataTables uses (incrementally increased for each column).
  10927 		 * * `string` - read an object property from the data source. There are
  10928 		 *   three 'special' options that can be used in the string to alter how
  10929 		 *   DataTables reads the data from the source object:
  10930 		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
  10931 		 *      Javascript to read from nested objects, so to can the options
  10932 		 *      specified in `data`. For example: `browser.version` or
  10933 		 *      `browser.name`. If your object parameter name contains a period, use
  10934 		 *      `\\` to escape it - i.e. `first\\.name`.
  10935 		 *    * `[]` - Array notation. DataTables can automatically combine data
  10936 		 *      from and array source, joining the data with the characters provided
  10937 		 *      between the two brackets. For example: `name[, ]` would provide a
  10938 		 *      comma-space separated list from the source array. If no characters
  10939 		 *      are provided between the brackets, the original array source is
  10940 		 *      returned.
  10941 		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
  10942 		 *      execute a function of the name given. For example: `browser()` for a
  10943 		 *      simple function on the data source, `browser.version()` for a
  10944 		 *      function in a nested property or even `browser().version` to get an
  10945 		 *      object property if the function called returns an object.
  10946 		 * * `object` - use different data for the different data types requested by
  10947 		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
  10948 		 *   of the object is the data type the property refers to and the value can
  10949 		 *   defined using an integer, string or function using the same rules as
  10950 		 *   `render` normally does. Note that an `_` option _must_ be specified.
  10951 		 *   This is the default value to use if you haven't specified a value for
  10952 		 *   the data type requested by DataTables.
  10953 		 * * `function` - the function given will be executed whenever DataTables
  10954 		 *   needs to set or get the data for a cell in the column. The function
  10955 		 *   takes three parameters:
  10956 		 *    * Parameters:
  10957 		 *      * {array|object} The data source for the row (based on `data`)
  10958 		 *      * {string} The type call data requested - this will be 'filter',
  10959 		 *        'display', 'type' or 'sort'.
  10960 		 *      * {array|object} The full data source for the row (not based on
  10961 		 *        `data`)
  10962 		 *    * Return:
  10963 		 *      * The return value from the function is what will be used for the
  10964 		 *        data requested.
  10965 		 */
  10966 		"mRender": null,
  10967 	
  10968 	
  10969 		/**
  10970 		 * Change the cell type created for the column - either TD cells or TH cells. This
  10971 		 * can be useful as TH cells have semantic meaning in the table body, allowing them
  10972 		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
  10973 		 */
  10974 		"sCellType": "td",
  10975 	
  10976 	
  10977 		/**
  10978 		 * Class to give to each cell in this column.
  10979 		 */
  10980 		"sClass": "",
  10981 	
  10982 		/**
  10983 		 * When DataTables calculates the column widths to assign to each column,
  10984 		 * it finds the longest string in each column and then constructs a
  10985 		 * temporary table and reads the widths from that. The problem with this
  10986 		 * is that "mmm" is much wider then "iiii", but the latter is a longer
  10987 		 * string - thus the calculation can go wrong (doing it properly and putting
  10988 		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
  10989 		 * a "work around" we provide this option. It will append its value to the
  10990 		 * text that is found to be the longest string for the column - i.e. padding.
  10991 		 * Generally you shouldn't need this!
  10992 		 */
  10993 		"sContentPadding": "",
  10994 	
  10995 	
  10996 		/**
  10997 		 * Allows a default value to be given for a column's data, and will be used
  10998 		 * whenever a null data source is encountered (this can be because `data`
  10999 		 * is set to null, or because the data source itself is null).
  11000 		 */
  11001 		"sDefaultContent": null,
  11002 	
  11003 	
  11004 		/**
  11005 		 * This parameter is only used in DataTables' server-side processing. It can
  11006 		 * be exceptionally useful to know what columns are being displayed on the
  11007 		 * client side, and to map these to database fields. When defined, the names
  11008 		 * also allow DataTables to reorder information from the server if it comes
  11009 		 * back in an unexpected order (i.e. if you switch your columns around on the
  11010 		 * client-side, your server-side code does not also need updating).
  11011 		 */
  11012 		"sName": "",
  11013 	
  11014 	
  11015 		/**
  11016 		 * Defines a data source type for the ordering which can be used to read
  11017 		 * real-time information from the table (updating the internally cached
  11018 		 * version) prior to ordering. This allows ordering to occur on user
  11019 		 * editable elements such as form inputs.
  11020 		 */
  11021 		"sSortDataType": "std",
  11022 	
  11023 	
  11024 		/**
  11025 		 * The title of this column.
  11026 		 */
  11027 		"sTitle": null,
  11028 	
  11029 	
  11030 		/**
  11031 		 * The type allows you to specify how the data for this column will be
  11032 		 * ordered. Four types (string, numeric, date and html (which will strip
  11033 		 * HTML tags before ordering)) are currently available. Note that only date
  11034 		 * formats understood by Javascript's Date() object will be accepted as type
  11035 		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
  11036 		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
  11037 		 * through plug-ins.
  11038 		 */
  11039 		"sType": null,
  11040 	
  11041 	
  11042 		/**
  11043 		 * Defining the width of the column, this parameter may take any CSS value
  11044 		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
  11045 		 * been given a specific width through this interface ensuring that the table
  11046 		 * remains readable.
  11047 		 */
  11048 		"sWidth": null
  11049 	};
  11050 	
  11051 	_fnHungarianMap( DataTable.defaults.column );
  11052 	
  11053 	
  11054 	
  11055 	/**
  11056 	 * DataTables settings object - this holds all the information needed for a
  11057 	 * given table, including configuration, data and current application of the
  11058 	 * table options. DataTables does not have a single instance for each DataTable
  11059 	 * with the settings attached to that instance, but rather instances of the
  11060 	 * DataTable "class" are created on-the-fly as needed (typically by a
  11061 	 * $().dataTable() call) and the settings object is then applied to that
  11062 	 * instance.
  11063 	 *
  11064 	 * Note that this object is related to {@link DataTable.defaults} but this
  11065 	 * one is the internal data store for DataTables's cache of columns. It should
  11066 	 * NOT be manipulated outside of DataTables. Any configuration should be done
  11067 	 * through the initialisation options.
  11068 	 */
  11069 	DataTable.models.oSettings = {
  11070 		/**
  11071 		 * Primary features of DataTables and their enablement state.
  11072 		 */
  11073 		"oFeatures": {
  11074 	
  11075 			/**
  11076 			 * Flag to say if DataTables should automatically try to calculate the
  11077 			 * optimum table and columns widths (true) or not (false).
  11078 			 * Note that this parameter will be set by the initialisation routine. To
  11079 			 * set a default use {@link DataTable.defaults}.
  11080 			 */
  11081 			"bAutoWidth": null,
  11082 	
  11083 			/**
  11084 			 * Delay the creation of TR and TD elements until they are actually
  11085 			 * needed by a driven page draw. This can give a significant speed
  11086 			 * increase for Ajax source and Javascript source data, but makes no
  11087 			 * difference at all for DOM and server-side processing tables.
  11088 			 * Note that this parameter will be set by the initialisation routine. To
  11089 			 * set a default use {@link DataTable.defaults}.
  11090 			 */
  11091 			"bDeferRender": null,
  11092 	
  11093 			/**
  11094 			 * Enable filtering on the table or not. Note that if this is disabled
  11095 			 * then there is no filtering at all on the table, including fnFilter.
  11096 			 * To just remove the filtering input use sDom and remove the 'f' option.
  11097 			 * Note that this parameter will be set by the initialisation routine. To
  11098 			 * set a default use {@link DataTable.defaults}.
  11099 			 */
  11100 			"bFilter": null,
  11101 	
  11102 			/**
  11103 			 * Used only for compatiblity with DT1
  11104 			 * @deprecated
  11105 			 */
  11106 			"bInfo": true,
  11107 	
  11108 			/**
  11109 			 * Used only for compatiblity with DT1
  11110 			 * @deprecated
  11111 			 */
  11112 			"bLengthChange": true,
  11113 	
  11114 			/**
  11115 			 * Pagination enabled or not. Note that if this is disabled then length
  11116 			 * changing must also be disabled.
  11117 			 * Note that this parameter will be set by the initialisation routine. To
  11118 			 * set a default use {@link DataTable.defaults}.
  11119 			 */
  11120 			"bPaginate": null,
  11121 	
  11122 			/**
  11123 			 * Processing indicator enable flag whenever DataTables is enacting a
  11124 			 * user request - typically an Ajax request for server-side processing.
  11125 			 * Note that this parameter will be set by the initialisation routine. To
  11126 			 * set a default use {@link DataTable.defaults}.
  11127 			 */
  11128 			"bProcessing": null,
  11129 	
  11130 			/**
  11131 			 * Server-side processing enabled flag - when enabled DataTables will
  11132 			 * get all data from the server for every draw - there is no filtering,
  11133 			 * sorting or paging done on the client-side.
  11134 			 * Note that this parameter will be set by the initialisation routine. To
  11135 			 * set a default use {@link DataTable.defaults}.
  11136 			 */
  11137 			"bServerSide": null,
  11138 	
  11139 			/**
  11140 			 * Sorting enablement flag.
  11141 			 * Note that this parameter will be set by the initialisation routine. To
  11142 			 * set a default use {@link DataTable.defaults}.
  11143 			 */
  11144 			"bSort": null,
  11145 	
  11146 			/**
  11147 			 * Multi-column sorting
  11148 			 * Note that this parameter will be set by the initialisation routine. To
  11149 			 * set a default use {@link DataTable.defaults}.
  11150 			 */
  11151 			"bSortMulti": null,
  11152 	
  11153 			/**
  11154 			 * Apply a class to the columns which are being sorted to provide a
  11155 			 * visual highlight or not. This can slow things down when enabled since
  11156 			 * there is a lot of DOM interaction.
  11157 			 * Note that this parameter will be set by the initialisation routine. To
  11158 			 * set a default use {@link DataTable.defaults}.
  11159 			 */
  11160 			"bSortClasses": null,
  11161 	
  11162 			/**
  11163 			 * State saving enablement flag.
  11164 			 * Note that this parameter will be set by the initialisation routine. To
  11165 			 * set a default use {@link DataTable.defaults}.
  11166 			 */
  11167 			"bStateSave": null
  11168 		},
  11169 	
  11170 	
  11171 		/**
  11172 		 * Scrolling settings for a table.
  11173 		 */
  11174 		"oScroll": {
  11175 			/**
  11176 			 * When the table is shorter in height than sScrollY, collapse the
  11177 			 * table container down to the height of the table (when true).
  11178 			 * Note that this parameter will be set by the initialisation routine. To
  11179 			 * set a default use {@link DataTable.defaults}.
  11180 			 */
  11181 			"bCollapse": null,
  11182 	
  11183 			/**
  11184 			 * Width of the scrollbar for the web-browser's platform. Calculated
  11185 			 * during table initialisation.
  11186 			 */
  11187 			"iBarWidth": 0,
  11188 	
  11189 			/**
  11190 			 * Viewport width for horizontal scrolling. Horizontal scrolling is
  11191 			 * disabled if an empty string.
  11192 			 * Note that this parameter will be set by the initialisation routine. To
  11193 			 * set a default use {@link DataTable.defaults}.
  11194 			 */
  11195 			"sX": null,
  11196 	
  11197 			/**
  11198 			 * Width to expand the table to when using x-scrolling. Typically you
  11199 			 * should not need to use this.
  11200 			 * Note that this parameter will be set by the initialisation routine. To
  11201 			 * set a default use {@link DataTable.defaults}.
  11202 			 *  @deprecated
  11203 			 */
  11204 			"sXInner": null,
  11205 	
  11206 			/**
  11207 			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
  11208 			 * if an empty string.
  11209 			 * Note that this parameter will be set by the initialisation routine. To
  11210 			 * set a default use {@link DataTable.defaults}.
  11211 			 */
  11212 			"sY": null
  11213 		},
  11214 	
  11215 		/**
  11216 		 * Language information for the table.
  11217 		 */
  11218 		"oLanguage": {
  11219 			/**
  11220 			 * Information callback function. See
  11221 			 * {@link DataTable.defaults.fnInfoCallback}
  11222 			 */
  11223 			"fnInfoCallback": null
  11224 		},
  11225 	
  11226 		/**
  11227 		 * Browser support parameters
  11228 		 */
  11229 		"oBrowser": {
  11230 			/**
  11231 			 * Determine if the vertical scrollbar is on the right or left of the
  11232 			 * scrolling container - needed for rtl language layout, although not
  11233 			 * all browsers move the scrollbar (Safari).
  11234 			 */
  11235 			"bScrollbarLeft": false,
  11236 	
  11237 			/**
  11238 			 * Browser scrollbar width
  11239 			 */
  11240 			"barWidth": 0
  11241 		},
  11242 	
  11243 	
  11244 		"ajax": null,
  11245 	
  11246 	
  11247 		/**
  11248 		 * Array referencing the nodes which are used for the features. The
  11249 		 * parameters of this object match what is allowed by sDom - i.e.
  11250 		 *   <ul>
  11251 		 *     <li>'l' - Length changing</li>
  11252 		 *     <li>'f' - Filtering input</li>
  11253 		 *     <li>'t' - The table!</li>
  11254 		 *     <li>'i' - Information</li>
  11255 		 *     <li>'p' - Pagination</li>
  11256 		 *     <li>'r' - pRocessing</li>
  11257 		 *   </ul>
  11258 		 */
  11259 		"aanFeatures": [],
  11260 	
  11261 		/**
  11262 		 * Store data information - see {@link DataTable.models.oRow} for detailed
  11263 		 * information.
  11264 		 */
  11265 		"aoData": [],
  11266 	
  11267 		/**
  11268 		 * Array of indexes which are in the current display (after filtering etc)
  11269 		 */
  11270 		"aiDisplay": [],
  11271 	
  11272 		/**
  11273 		 * Array of indexes for display - no filtering
  11274 		 */
  11275 		"aiDisplayMaster": [],
  11276 	
  11277 		/**
  11278 		 * Map of row ids to data indexes
  11279 		 */
  11280 		"aIds": {},
  11281 	
  11282 		/**
  11283 		 * Store information about each column that is in use
  11284 		 */
  11285 		"aoColumns": [],
  11286 	
  11287 		/**
  11288 		 * Store information about the table's header
  11289 		 */
  11290 		"aoHeader": [],
  11291 	
  11292 		/**
  11293 		 * Store information about the table's footer
  11294 		 */
  11295 		"aoFooter": [],
  11296 	
  11297 		/**
  11298 		 * Store the applied global search information in case we want to force a
  11299 		 * research or compare the old search to a new one.
  11300 		 * Note that this parameter will be set by the initialisation routine. To
  11301 		 * set a default use {@link DataTable.defaults}.
  11302 		 */
  11303 		"oPreviousSearch": {},
  11304 	
  11305 		/**
  11306 		 * Store for named searches
  11307 		 */
  11308 		searchFixed: {},
  11309 	
  11310 		/**
  11311 		 * Store the applied search for each column - see
  11312 		 * {@link DataTable.models.oSearch} for the format that is used for the
  11313 		 * filtering information for each column.
  11314 		 */
  11315 		"aoPreSearchCols": [],
  11316 	
  11317 		/**
  11318 		 * Sorting that is applied to the table. Note that the inner arrays are
  11319 		 * used in the following manner:
  11320 		 * <ul>
  11321 		 *   <li>Index 0 - column number</li>
  11322 		 *   <li>Index 1 - current sorting direction</li>
  11323 		 * </ul>
  11324 		 * Note that this parameter will be set by the initialisation routine. To
  11325 		 * set a default use {@link DataTable.defaults}.
  11326 		 */
  11327 		"aaSorting": null,
  11328 	
  11329 		/**
  11330 		 * Sorting that is always applied to the table (i.e. prefixed in front of
  11331 		 * aaSorting).
  11332 		 * Note that this parameter will be set by the initialisation routine. To
  11333 		 * set a default use {@link DataTable.defaults}.
  11334 		 */
  11335 		"aaSortingFixed": [],
  11336 	
  11337 		/**
  11338 		 * If restoring a table - we should restore its width
  11339 		 */
  11340 		"sDestroyWidth": 0,
  11341 	
  11342 		/**
  11343 		 * Callback functions array for every time a row is inserted (i.e. on a draw).
  11344 		 */
  11345 		"aoRowCallback": [],
  11346 	
  11347 		/**
  11348 		 * Callback functions for the header on each draw.
  11349 		 */
  11350 		"aoHeaderCallback": [],
  11351 	
  11352 		/**
  11353 		 * Callback function for the footer on each draw.
  11354 		 */
  11355 		"aoFooterCallback": [],
  11356 	
  11357 		/**
  11358 		 * Array of callback functions for draw callback functions
  11359 		 */
  11360 		"aoDrawCallback": [],
  11361 	
  11362 		/**
  11363 		 * Array of callback functions for row created function
  11364 		 */
  11365 		"aoRowCreatedCallback": [],
  11366 	
  11367 		/**
  11368 		 * Callback functions for just before the table is redrawn. A return of
  11369 		 * false will be used to cancel the draw.
  11370 		 */
  11371 		"aoPreDrawCallback": [],
  11372 	
  11373 		/**
  11374 		 * Callback functions for when the table has been initialised.
  11375 		 */
  11376 		"aoInitComplete": [],
  11377 	
  11378 	
  11379 		/**
  11380 		 * Callbacks for modifying the settings to be stored for state saving, prior to
  11381 		 * saving state.
  11382 		 */
  11383 		"aoStateSaveParams": [],
  11384 	
  11385 		/**
  11386 		 * Callbacks for modifying the settings that have been stored for state saving
  11387 		 * prior to using the stored values to restore the state.
  11388 		 */
  11389 		"aoStateLoadParams": [],
  11390 	
  11391 		/**
  11392 		 * Callbacks for operating on the settings object once the saved state has been
  11393 		 * loaded
  11394 		 */
  11395 		"aoStateLoaded": [],
  11396 	
  11397 		/**
  11398 		 * Cache the table ID for quick access
  11399 		 */
  11400 		"sTableId": "",
  11401 	
  11402 		/**
  11403 		 * The TABLE node for the main table
  11404 		 */
  11405 		"nTable": null,
  11406 	
  11407 		/**
  11408 		 * Permanent ref to the thead element
  11409 		 */
  11410 		"nTHead": null,
  11411 	
  11412 		/**
  11413 		 * Permanent ref to the tfoot element - if it exists
  11414 		 */
  11415 		"nTFoot": null,
  11416 	
  11417 		/**
  11418 		 * Permanent ref to the tbody element
  11419 		 */
  11420 		"nTBody": null,
  11421 	
  11422 		/**
  11423 		 * Cache the wrapper node (contains all DataTables controlled elements)
  11424 		 */
  11425 		"nTableWrapper": null,
  11426 	
  11427 		/**
  11428 		 * Indicate if all required information has been read in
  11429 		 */
  11430 		"bInitialised": false,
  11431 	
  11432 		/**
  11433 		 * Information about open rows. Each object in the array has the parameters
  11434 		 * 'nTr' and 'nParent'
  11435 		 */
  11436 		"aoOpenRows": [],
  11437 	
  11438 		/**
  11439 		 * Dictate the positioning of DataTables' control elements - see
  11440 		 * {@link DataTable.model.oInit.sDom}.
  11441 		 * Note that this parameter will be set by the initialisation routine. To
  11442 		 * set a default use {@link DataTable.defaults}.
  11443 		 */
  11444 		"sDom": null,
  11445 	
  11446 		/**
  11447 		 * Search delay (in mS)
  11448 		 */
  11449 		"searchDelay": null,
  11450 	
  11451 		/**
  11452 		 * Which type of pagination should be used.
  11453 		 * Note that this parameter will be set by the initialisation routine. To
  11454 		 * set a default use {@link DataTable.defaults}.
  11455 		 */
  11456 		"sPaginationType": "two_button",
  11457 	
  11458 		/**
  11459 		 * Number of paging controls on the page. Only used for backwards compatibility
  11460 		 */
  11461 		pagingControls: 0,
  11462 	
  11463 		/**
  11464 		 * The state duration (for `stateSave`) in seconds.
  11465 		 * Note that this parameter will be set by the initialisation routine. To
  11466 		 * set a default use {@link DataTable.defaults}.
  11467 		 */
  11468 		"iStateDuration": 0,
  11469 	
  11470 		/**
  11471 		 * Array of callback functions for state saving. Each array element is an
  11472 		 * object with the following parameters:
  11473 		 *   <ul>
  11474 		 *     <li>function:fn - function to call. Takes two parameters, oSettings
  11475 		 *       and the JSON string to save that has been thus far created. Returns
  11476 		 *       a JSON string to be inserted into a json object
  11477 		 *       (i.e. '"param": [ 0, 1, 2]')</li>
  11478 		 *     <li>string:sName - name of callback</li>
  11479 		 *   </ul>
  11480 		 */
  11481 		"aoStateSave": [],
  11482 	
  11483 		/**
  11484 		 * Array of callback functions for state loading. Each array element is an
  11485 		 * object with the following parameters:
  11486 		 *   <ul>
  11487 		 *     <li>function:fn - function to call. Takes two parameters, oSettings
  11488 		 *       and the object stored. May return false to cancel state loading</li>
  11489 		 *     <li>string:sName - name of callback</li>
  11490 		 *   </ul>
  11491 		 */
  11492 		"aoStateLoad": [],
  11493 	
  11494 		/**
  11495 		 * State that was saved. Useful for back reference
  11496 		 */
  11497 		"oSavedState": null,
  11498 	
  11499 		/**
  11500 		 * State that was loaded. Useful for back reference
  11501 		 */
  11502 		"oLoadedState": null,
  11503 	
  11504 		/**
  11505 		 * Note if draw should be blocked while getting data
  11506 		 */
  11507 		"bAjaxDataGet": true,
  11508 	
  11509 		/**
  11510 		 * The last jQuery XHR object that was used for server-side data gathering.
  11511 		 * This can be used for working with the XHR information in one of the
  11512 		 * callbacks
  11513 		 */
  11514 		"jqXHR": null,
  11515 	
  11516 		/**
  11517 		 * JSON returned from the server in the last Ajax request
  11518 		 */
  11519 		"json": undefined,
  11520 	
  11521 		/**
  11522 		 * Data submitted as part of the last Ajax request
  11523 		 */
  11524 		"oAjaxData": undefined,
  11525 	
  11526 		/**
  11527 		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
  11528 		 * required).
  11529 		 * Note that this parameter will be set by the initialisation routine. To
  11530 		 * set a default use {@link DataTable.defaults}.
  11531 		 */
  11532 		"sServerMethod": null,
  11533 	
  11534 		/**
  11535 		 * Format numbers for display.
  11536 		 * Note that this parameter will be set by the initialisation routine. To
  11537 		 * set a default use {@link DataTable.defaults}.
  11538 		 */
  11539 		"fnFormatNumber": null,
  11540 	
  11541 		/**
  11542 		 * List of options that can be used for the user selectable length menu.
  11543 		 * Note that this parameter will be set by the initialisation routine. To
  11544 		 * set a default use {@link DataTable.defaults}.
  11545 		 */
  11546 		"aLengthMenu": null,
  11547 	
  11548 		/**
  11549 		 * Counter for the draws that the table does. Also used as a tracker for
  11550 		 * server-side processing
  11551 		 */
  11552 		"iDraw": 0,
  11553 	
  11554 		/**
  11555 		 * Indicate if a redraw is being done - useful for Ajax
  11556 		 */
  11557 		"bDrawing": false,
  11558 	
  11559 		/**
  11560 		 * Draw index (iDraw) of the last error when parsing the returned data
  11561 		 */
  11562 		"iDrawError": -1,
  11563 	
  11564 		/**
  11565 		 * Paging display length
  11566 		 */
  11567 		"_iDisplayLength": 10,
  11568 	
  11569 		/**
  11570 		 * Paging start point - aiDisplay index
  11571 		 */
  11572 		"_iDisplayStart": 0,
  11573 	
  11574 		/**
  11575 		 * Server-side processing - number of records in the result set
  11576 		 * (i.e. before filtering), Use fnRecordsTotal rather than
  11577 		 * this property to get the value of the number of records, regardless of
  11578 		 * the server-side processing setting.
  11579 		 */
  11580 		"_iRecordsTotal": 0,
  11581 	
  11582 		/**
  11583 		 * Server-side processing - number of records in the current display set
  11584 		 * (i.e. after filtering). Use fnRecordsDisplay rather than
  11585 		 * this property to get the value of the number of records, regardless of
  11586 		 * the server-side processing setting.
  11587 		 */
  11588 		"_iRecordsDisplay": 0,
  11589 	
  11590 		/**
  11591 		 * The classes to use for the table
  11592 		 */
  11593 		"oClasses": {},
  11594 	
  11595 		/**
  11596 		 * Flag attached to the settings object so you can check in the draw
  11597 		 * callback if filtering has been done in the draw. Deprecated in favour of
  11598 		 * events.
  11599 		 *  @deprecated
  11600 		 */
  11601 		"bFiltered": false,
  11602 	
  11603 		/**
  11604 		 * Flag attached to the settings object so you can check in the draw
  11605 		 * callback if sorting has been done in the draw. Deprecated in favour of
  11606 		 * events.
  11607 		 *  @deprecated
  11608 		 */
  11609 		"bSorted": false,
  11610 	
  11611 		/**
  11612 		 * Indicate that if multiple rows are in the header and there is more than
  11613 		 * one unique cell per column, if the top one (true) or bottom one (false)
  11614 		 * should be used for sorting / title by DataTables.
  11615 		 * Note that this parameter will be set by the initialisation routine. To
  11616 		 * set a default use {@link DataTable.defaults}.
  11617 		 */
  11618 		"bSortCellsTop": null,
  11619 	
  11620 		/**
  11621 		 * Initialisation object that is used for the table
  11622 		 */
  11623 		"oInit": null,
  11624 	
  11625 		/**
  11626 		 * Destroy callback functions - for plug-ins to attach themselves to the
  11627 		 * destroy so they can clean up markup and events.
  11628 		 */
  11629 		"aoDestroyCallback": [],
  11630 	
  11631 	
  11632 		/**
  11633 		 * Get the number of records in the current record set, before filtering
  11634 		 */
  11635 		"fnRecordsTotal": function ()
  11636 		{
  11637 			return _fnDataSource( this ) == 'ssp' ?
  11638 				this._iRecordsTotal * 1 :
  11639 				this.aiDisplayMaster.length;
  11640 		},
  11641 	
  11642 		/**
  11643 		 * Get the number of records in the current record set, after filtering
  11644 		 */
  11645 		"fnRecordsDisplay": function ()
  11646 		{
  11647 			return _fnDataSource( this ) == 'ssp' ?
  11648 				this._iRecordsDisplay * 1 :
  11649 				this.aiDisplay.length;
  11650 		},
  11651 	
  11652 		/**
  11653 		 * Get the display end point - aiDisplay index
  11654 		 */
  11655 		"fnDisplayEnd": function ()
  11656 		{
  11657 			var
  11658 				len      = this._iDisplayLength,
  11659 				start    = this._iDisplayStart,
  11660 				calc     = start + len,
  11661 				records  = this.aiDisplay.length,
  11662 				features = this.oFeatures,
  11663 				paginate = features.bPaginate;
  11664 	
  11665 			if ( features.bServerSide ) {
  11666 				return paginate === false || len === -1 ?
  11667 					start + records :
  11668 					Math.min( start+len, this._iRecordsDisplay );
  11669 			}
  11670 			else {
  11671 				return ! paginate || calc>records || len===-1 ?
  11672 					records :
  11673 					calc;
  11674 			}
  11675 		},
  11676 	
  11677 		/**
  11678 		 * The DataTables object for this table
  11679 		 */
  11680 		"oInstance": null,
  11681 	
  11682 		/**
  11683 		 * Unique identifier for each instance of the DataTables object. If there
  11684 		 * is an ID on the table node, then it takes that value, otherwise an
  11685 		 * incrementing internal counter is used.
  11686 		 */
  11687 		"sInstance": null,
  11688 	
  11689 		/**
  11690 		 * tabindex attribute value that is added to DataTables control elements, allowing
  11691 		 * keyboard navigation of the table and its controls.
  11692 		 */
  11693 		"iTabIndex": 0,
  11694 	
  11695 		/**
  11696 		 * DIV container for the footer scrolling table if scrolling
  11697 		 */
  11698 		"nScrollHead": null,
  11699 	
  11700 		/**
  11701 		 * DIV container for the footer scrolling table if scrolling
  11702 		 */
  11703 		"nScrollFoot": null,
  11704 	
  11705 		/**
  11706 		 * Last applied sort
  11707 		 */
  11708 		"aLastSort": [],
  11709 	
  11710 		/**
  11711 		 * Stored plug-in instances
  11712 		 */
  11713 		"oPlugins": {},
  11714 	
  11715 		/**
  11716 		 * Function used to get a row's id from the row's data
  11717 		 */
  11718 		"rowIdFn": null,
  11719 	
  11720 		/**
  11721 		 * Data location where to store a row's id
  11722 		 */
  11723 		"rowId": null,
  11724 	
  11725 		caption: '',
  11726 	
  11727 		captionNode: null,
  11728 	
  11729 		colgroup: null
  11730 	};
  11731 	
  11732 	/**
  11733 	 * Extension object for DataTables that is used to provide all extension
  11734 	 * options.
  11735 	 *
  11736 	 * Note that the `DataTable.ext` object is available through
  11737 	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
  11738 	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
  11739 	 *  @namespace
  11740 	 *  @extends DataTable.models.ext
  11741 	 */
  11742 	
  11743 	
  11744 	var extPagination = DataTable.ext.pager;
  11745 	
  11746 	// Paging buttons configuration
  11747 	$.extend( extPagination, {
  11748 		simple: function () {
  11749 			return [ 'previous', 'next' ];
  11750 		},
  11751 	
  11752 		full: function () {
  11753 			return [  'first', 'previous', 'next', 'last' ];
  11754 		},
  11755 	
  11756 		numbers: function () {
  11757 			return [ 'numbers' ];
  11758 		},
  11759 	
  11760 		simple_numbers: function () {
  11761 			return [ 'previous', 'numbers', 'next' ];
  11762 		},
  11763 	
  11764 		full_numbers: function () {
  11765 			return [ 'first', 'previous', 'numbers', 'next', 'last' ];
  11766 		},
  11767 		
  11768 		first_last: function () {
  11769 			return ['first', 'last'];
  11770 		},
  11771 		
  11772 		first_last_numbers: function () {
  11773 			return ['first', 'numbers', 'last'];
  11774 		},
  11775 	
  11776 		// For testing and plug-ins to use
  11777 		_numbers: _pagingNumbers,
  11778 	
  11779 		// Number of number buttons - legacy, use `numbers` option for paging feature
  11780 		numbers_length: 7
  11781 	} );
  11782 	
  11783 	
  11784 	$.extend( true, DataTable.ext.renderer, {
  11785 		pagingButton: {
  11786 			_: function (settings, buttonType, content, active, disabled) {
  11787 				var classes = settings.oClasses.paging;
  11788 				var btnClasses = [classes.button];
  11789 				var btn;
  11790 	
  11791 				if (active) {
  11792 					btnClasses.push(classes.active);
  11793 				}
  11794 	
  11795 				if (disabled) {
  11796 					btnClasses.push(classes.disabled)
  11797 				}
  11798 	
  11799 				if (buttonType === 'ellipsis') {
  11800 					btn = $('<span class="ellipsis"></span>').html(content)[0];
  11801 				}
  11802 				else {
  11803 					btn = $('<button>', {
  11804 						class: btnClasses.join(' '),
  11805 						role: 'link',
  11806 						type: 'button'
  11807 					}).html(content);
  11808 				}
  11809 	
  11810 				return {
  11811 					display: btn,
  11812 					clicker: btn
  11813 				}
  11814 			}
  11815 		},
  11816 	
  11817 		pagingContainer: {
  11818 			_: function (settings, buttons) {
  11819 				// No wrapping element - just append directly to the host
  11820 				return buttons;
  11821 			}
  11822 		}
  11823 	} );
  11824 	
  11825 	// Common function to remove new lines, strip HTML and diacritic control
  11826 	var _filterString = function (stripHtml, normalize) {
  11827 		return function (str) {
  11828 			if (_empty(str) || typeof str !== 'string') {
  11829 				return str;
  11830 			}
  11831 	
  11832 			str = str.replace( _re_new_lines, " " );
  11833 	
  11834 			if (stripHtml) {
  11835 				str = _stripHtml(str);
  11836 			}
  11837 	
  11838 			if (normalize) {
  11839 				str = _normalize(str, false);
  11840 			}
  11841 	
  11842 			return str;
  11843 		};
  11844 	}
  11845 	
  11846 	/*
  11847 	 * Public helper functions. These aren't used internally by DataTables, or
  11848 	 * called by any of the options passed into DataTables, but they can be used
  11849 	 * externally by developers working with DataTables. They are helper functions
  11850 	 * to make working with DataTables a little bit easier.
  11851 	 */
  11852 	
  11853 	function __mldFnName(name) {
  11854 		return name.replace(/[\W]/g, '_')
  11855 	}
  11856 	
  11857 	// Common logic for moment, luxon or a date action
  11858 	function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) {
  11859 		if (window.moment) {
  11860 			return dt[momentFn]( arg1 );
  11861 		}
  11862 		else if (window.luxon) {
  11863 			return dt[luxonFn]( arg1 );
  11864 		}
  11865 		
  11866 		return dateFn ? dt[dateFn]( arg1 ) : dt;
  11867 	}
  11868 	
  11869 	
  11870 	var __mlWarning = false;
  11871 	function __mldObj (d, format, locale) {
  11872 		var dt;
  11873 	
  11874 		if (window.moment) {
  11875 			dt = window.moment.utc( d, format, locale, true );
  11876 	
  11877 			if (! dt.isValid()) {
  11878 				return null;
  11879 			}
  11880 		}
  11881 		else if (window.luxon) {
  11882 			dt = format && typeof d === 'string'
  11883 				? window.luxon.DateTime.fromFormat( d, format )
  11884 				: window.luxon.DateTime.fromISO( d );
  11885 	
  11886 			if (! dt.isValid) {
  11887 				return null;
  11888 			}
  11889 	
  11890 			dt.setLocale(locale);
  11891 		}
  11892 		else if (! format) {
  11893 			// No format given, must be ISO
  11894 			dt = new Date(d);
  11895 		}
  11896 		else {
  11897 			if (! __mlWarning) {
  11898 				alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
  11899 			}
  11900 	
  11901 			__mlWarning = true;
  11902 		}
  11903 	
  11904 		return dt;
  11905 	}
  11906 	
  11907 	// Wrapper for date, datetime and time which all operate the same way with the exception of
  11908 	// the output string for auto locale support
  11909 	function __mlHelper (localeString) {
  11910 		return function ( from, to, locale, def ) {
  11911 			// Luxon and Moment support
  11912 			// Argument shifting
  11913 			if ( arguments.length === 0 ) {
  11914 				locale = 'en';
  11915 				to = null; // means toLocaleString
  11916 				from = null; // means iso8601
  11917 			}
  11918 			else if ( arguments.length === 1 ) {
  11919 				locale = 'en';
  11920 				to = from;
  11921 				from = null;
  11922 			}
  11923 			else if ( arguments.length === 2 ) {
  11924 				locale = to;
  11925 				to = from;
  11926 				from = null;
  11927 			}
  11928 	
  11929 			var typeName = 'datetime' + (to ? '-' + __mldFnName(to) : '');
  11930 	
  11931 			// Add type detection and sorting specific to this date format - we need to be able to identify
  11932 			// date type columns as such, rather than as numbers in extensions. Hence the need for this.
  11933 			if (! DataTable.ext.type.order[typeName]) {
  11934 				DataTable.type(typeName, {
  11935 					detect: function (d) {
  11936 						// The renderer will give the value to type detect as the type!
  11937 						return d === typeName ? typeName : false;
  11938 					},
  11939 					order: {
  11940 						pre: function (d) {
  11941 							// The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
  11942 							// `valueOf` which gives milliseconds epoch
  11943 							return d.valueOf();
  11944 						}
  11945 					},
  11946 					className: 'dt-right'
  11947 				});
  11948 			}
  11949 		
  11950 			return function ( d, type ) {
  11951 				// Allow for a default value
  11952 				if (d === null || d === undefined) {
  11953 					if (def === '--now') {
  11954 						// We treat everything as UTC further down, so no changes are
  11955 						// made, as such need to get the local date / time as if it were
  11956 						// UTC
  11957 						var local = new Date();
  11958 						d = new Date( Date.UTC(
  11959 							local.getFullYear(), local.getMonth(), local.getDate(),
  11960 							local.getHours(), local.getMinutes(), local.getSeconds()
  11961 						) );
  11962 					}
  11963 					else {
  11964 						d = '';
  11965 					}
  11966 				}
  11967 	
  11968 				if (type === 'type') {
  11969 					// Typing uses the type name for fast matching
  11970 					return typeName;
  11971 				}
  11972 	
  11973 				if (d === '') {
  11974 					return type !== 'sort'
  11975 						? ''
  11976 						: __mldObj('0000-01-01 00:00:00', null, locale);
  11977 				}
  11978 	
  11979 				// Shortcut. If `from` and `to` are the same, we are using the renderer to
  11980 				// format for ordering, not display - its already in the display format.
  11981 				if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) {
  11982 					return d;
  11983 				}
  11984 	
  11985 				var dt = __mldObj(d, from, locale);
  11986 	
  11987 				if (dt === null) {
  11988 					return d;
  11989 				}
  11990 	
  11991 				if (type === 'sort') {
  11992 					return dt;
  11993 				}
  11994 				
  11995 				var formatted = to === null
  11996 					? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
  11997 					: __mld(dt, 'format', 'toFormat', 'toISOString', to);
  11998 	
  11999 				// XSS protection
  12000 				return type === 'display' ?
  12001 					_escapeHtml( formatted ) :
  12002 					formatted;
  12003 			};
  12004 		}
  12005 	}
  12006 	
  12007 	// Based on locale, determine standard number formatting
  12008 	// Fallback for legacy browsers is US English
  12009 	var __thousands = ',';
  12010 	var __decimal = '.';
  12011 	
  12012 	if (window.Intl !== undefined) {
  12013 		try {
  12014 			var num = new Intl.NumberFormat().formatToParts(100000.1);
  12015 		
  12016 			for (var i=0 ; i<num.length ; i++) {
  12017 				if (num[i].type === 'group') {
  12018 					__thousands = num[i].value;
  12019 				}
  12020 				else if (num[i].type === 'decimal') {
  12021 					__decimal = num[i].value;
  12022 				}
  12023 			}
  12024 		}
  12025 		catch (e) {
  12026 			// noop
  12027 		}
  12028 	}
  12029 	
  12030 	// Formatted date time detection - use by declaring the formats you are going to use
  12031 	DataTable.datetime = function ( format, locale ) {
  12032 		var typeName = 'datetime-detect-' + __mldFnName(format);
  12033 	
  12034 		if (! locale) {
  12035 			locale = 'en';
  12036 		}
  12037 	
  12038 		if (! DataTable.ext.type.order[typeName]) {
  12039 			DataTable.type(typeName, {
  12040 				detect: function (d) {
  12041 					var dt = __mldObj(d, format, locale);
  12042 					return d === '' || dt ? typeName : false;
  12043 				},
  12044 				order: {
  12045 					pre: function (d) {
  12046 						return __mldObj(d, format, locale) || 0;
  12047 					}
  12048 				},
  12049 				className: 'dt-right'
  12050 			});
  12051 		}
  12052 	}
  12053 	
  12054 	/**
  12055 	 * Helpers for `columns.render`.
  12056 	 *
  12057 	 * The options defined here can be used with the `columns.render` initialisation
  12058 	 * option to provide a display renderer. The following functions are defined:
  12059 	 *
  12060 	 * * `moment` - Uses the MomentJS library to convert from a given format into another.
  12061 	 * This renderer has three overloads:
  12062 	 *   * 1 parameter:
  12063 	 *     * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
  12064 	 *   * 2 parameters:
  12065 	 *     * `string` - Format to convert from
  12066 	 *     * `string` - Format to convert to. Assumes `en` locale
  12067 	 *   * 3 parameters:
  12068 	 *     * `string` - Format to convert from
  12069 	 *     * `string` - Format to convert to
  12070 	 *     * `string` - Locale
  12071 	 * * `number` - Will format numeric data (defined by `columns.data`) for
  12072 	 *   display, retaining the original unformatted data for sorting and filtering.
  12073 	 *   It takes 5 parameters:
  12074 	 *   * `string` - Thousands grouping separator
  12075 	 *   * `string` - Decimal point indicator
  12076 	 *   * `integer` - Number of decimal points to show
  12077 	 *   * `string` (optional) - Prefix.
  12078 	 *   * `string` (optional) - Postfix (/suffix).
  12079 	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
  12080 	 *   parameters.
  12081 	 *
  12082 	 * @example
  12083 	 *   // Column definition using the number renderer
  12084 	 *   {
  12085 	 *     data: "salary",
  12086 	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
  12087 	 *   }
  12088 	 *
  12089 	 * @namespace
  12090 	 */
  12091 	DataTable.render = {
  12092 		date: __mlHelper('toLocaleDateString'),
  12093 		datetime: __mlHelper('toLocaleString'),
  12094 		time: __mlHelper('toLocaleTimeString'),
  12095 		number: function ( thousands, decimal, precision, prefix, postfix ) {
  12096 			// Auto locale detection
  12097 			if (thousands === null || thousands === undefined) {
  12098 				thousands = __thousands;
  12099 			}
  12100 	
  12101 			if (decimal === null || decimal === undefined) {
  12102 				decimal = __decimal;
  12103 			}
  12104 	
  12105 			return {
  12106 				display: function ( d ) {
  12107 					if ( typeof d !== 'number' && typeof d !== 'string' ) {
  12108 						return d;
  12109 					}
  12110 	
  12111 					if (d === '' || d === null) {
  12112 						return d;
  12113 					}
  12114 	
  12115 					var negative = d < 0 ? '-' : '';
  12116 					var flo = parseFloat( d );
  12117 					var abs = Math.abs(flo);
  12118 	
  12119 					// Scientific notation for large and small numbers
  12120 					if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0) ) {
  12121 						var exp = flo.toExponential(precision).split(/e\+?/);
  12122 						return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
  12123 					}
  12124 	
  12125 					// If NaN then there isn't much formatting that we can do - just
  12126 					// return immediately, escaping any HTML (this was supposed to
  12127 					// be a number after all)
  12128 					if ( isNaN( flo ) ) {
  12129 						return _escapeHtml( d );
  12130 					}
  12131 	
  12132 					flo = flo.toFixed( precision );
  12133 					d = Math.abs( flo );
  12134 	
  12135 					var intPart = parseInt( d, 10 );
  12136 					var floatPart = precision ?
  12137 						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
  12138 						'';
  12139 	
  12140 					// If zero, then can't have a negative prefix
  12141 					if (intPart === 0 && parseFloat(floatPart) === 0) {
  12142 						negative = '';
  12143 					}
  12144 	
  12145 					return negative + (prefix||'') +
  12146 						intPart.toString().replace(
  12147 							/\B(?=(\d{3})+(?!\d))/g, thousands
  12148 						) +
  12149 						floatPart +
  12150 						(postfix||'');
  12151 				}
  12152 			};
  12153 		},
  12154 	
  12155 		text: function () {
  12156 			return {
  12157 				display: _escapeHtml,
  12158 				filter: _escapeHtml
  12159 			};
  12160 		}
  12161 	};
  12162 	
  12163 	
  12164 	var _extTypes = DataTable.ext.type;
  12165 	
  12166 	// Get / set type
  12167 	DataTable.type = function (name, prop, val) {
  12168 		if (! prop) {
  12169 			return {
  12170 				className: _extTypes.className[name],
  12171 				detect: _extTypes.detect.find(function (fn) {
  12172 					return fn.name === name;
  12173 				}),
  12174 				order: {
  12175 					pre: _extTypes.order[name + '-pre'],
  12176 					asc: _extTypes.order[name + '-asc'],
  12177 					desc: _extTypes.order[name + '-desc']
  12178 				},
  12179 				render: _extTypes.render[name],
  12180 				search: _extTypes.search[name]
  12181 			};
  12182 		}
  12183 	
  12184 		var setProp = function(prop, propVal) {
  12185 			_extTypes[prop][name] = propVal;
  12186 		};
  12187 		var setDetect = function (fn) {
  12188 			// Wrap to allow the function to return `true` rather than
  12189 			// specifying the type name.
  12190 			var cb = function (d, s) {
  12191 				var ret = fn(d, s);
  12192 	
  12193 				return ret === true
  12194 					? name
  12195 					: ret;
  12196 			};
  12197 			Object.defineProperty(cb, "name", {value: name});
  12198 	
  12199 			var idx = _extTypes.detect.findIndex(function (fn) {
  12200 				return fn.name === name;
  12201 			});
  12202 	
  12203 			if (idx === -1) {
  12204 				_extTypes.detect.unshift(cb);
  12205 			}
  12206 			else {
  12207 				_extTypes.detect.splice(idx, 1, cb);
  12208 			}
  12209 		};
  12210 		var setOrder = function (obj) {
  12211 			_extTypes.order[name + '-pre'] = obj.pre; // can be undefined
  12212 			_extTypes.order[name + '-asc'] = obj.asc; // can be undefined
  12213 			_extTypes.order[name + '-desc'] = obj.desc; // can be undefined
  12214 		};
  12215 	
  12216 		// prop is optional
  12217 		if (val === undefined) {
  12218 			val = prop;
  12219 			prop = null;
  12220 		}
  12221 	
  12222 		if (prop === 'className') {
  12223 			setProp('className', val);
  12224 		}
  12225 		else if (prop === 'detect') {
  12226 			setDetect(val);
  12227 		}
  12228 		else if (prop === 'order') {
  12229 			setOrder(val);
  12230 		}
  12231 		else if (prop === 'render') {
  12232 			setProp('render', val);
  12233 		}
  12234 		else if (prop === 'search') {
  12235 			setProp('search', val);
  12236 		}
  12237 		else if (! prop) {
  12238 			if (val.className) {
  12239 				setProp('className', val.className);
  12240 			}
  12241 	
  12242 			if (val.detect !== undefined) {
  12243 				setDetect(val.detect);
  12244 			}
  12245 	
  12246 			if (val.order) {
  12247 				setOrder(val.order);
  12248 			}
  12249 	
  12250 			if (val.render !== undefined) {
  12251 				setProp('render', val.render);
  12252 			}
  12253 	
  12254 			if (val.search !== undefined) {
  12255 				setProp('search', val.search);
  12256 			}
  12257 		}
  12258 	}
  12259 	
  12260 	// Get a list of types
  12261 	DataTable.types = function () {
  12262 		return _extTypes.detect.map(function (fn) {
  12263 			return fn.name;
  12264 		});
  12265 	};
  12266 	
  12267 	//
  12268 	// Built in data types
  12269 	//
  12270 	
  12271 	DataTable.type('string', {
  12272 		detect: function () {
  12273 			return 'string';
  12274 		},
  12275 		order: {
  12276 			pre: function ( a ) {
  12277 				// This is a little complex, but faster than always calling toString,
  12278 				// http://jsperf.com/tostring-v-check
  12279 				return _empty(a) ?
  12280 					'' :
  12281 					typeof a === 'string' ?
  12282 						a.toLowerCase() :
  12283 						! a.toString ?
  12284 							'' :
  12285 							a.toString();
  12286 			}
  12287 		},
  12288 		search: _filterString(false, true)
  12289 	});
  12290 	
  12291 	
  12292 	DataTable.type('html', {
  12293 		detect: function ( d ) {
  12294 			return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
  12295 				'html' : null;
  12296 		},
  12297 		order: {
  12298 			pre: function ( a ) {
  12299 				return _empty(a) ?
  12300 					'' :
  12301 					a.replace ?
  12302 						_stripHtml(a).trim().toLowerCase() :
  12303 						a+'';
  12304 			}
  12305 		},
  12306 		search: _filterString(true, true)
  12307 	});
  12308 	
  12309 	
  12310 	DataTable.type('date', {
  12311 		className: 'dt-type-date',
  12312 		detect: function ( d )
  12313 		{
  12314 			// V8 tries _very_ hard to make a string passed into `Date.parse()`
  12315 			// valid, so we need to use a regex to restrict date formats. Use a
  12316 			// plug-in for anything other than ISO8601 style strings
  12317 			if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
  12318 				return null;
  12319 			}
  12320 			var parsed = Date.parse(d);
  12321 			return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
  12322 		},
  12323 		order: {
  12324 			pre: function ( d ) {
  12325 				var ts = Date.parse( d );
  12326 				return isNaN(ts) ? -Infinity : ts;
  12327 			}
  12328 		}
  12329 	});
  12330 	
  12331 	
  12332 	DataTable.type('html-num-fmt', {
  12333 		className: 'dt-type-numeric',
  12334 		detect: function ( d, settings )
  12335 		{
  12336 			var decimal = settings.oLanguage.sDecimal;
  12337 			return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt' : null;
  12338 		},
  12339 		order: {
  12340 			pre: function ( d, s ) {
  12341 				var dp = s.oLanguage.sDecimal;
  12342 				return __numericReplace( d, dp, _re_html, _re_formatted_numeric );
  12343 			}
  12344 		},
  12345 		search: _filterString(true, true)
  12346 	});
  12347 	
  12348 	
  12349 	DataTable.type('html-num', {
  12350 		className: 'dt-type-numeric',
  12351 		detect: function ( d, settings )
  12352 		{
  12353 			var decimal = settings.oLanguage.sDecimal;
  12354 			return _htmlNumeric( d, decimal ) ? 'html-num' : null;
  12355 		},
  12356 		order: {
  12357 			pre: function ( d, s ) {
  12358 				var dp = s.oLanguage.sDecimal;
  12359 				return __numericReplace( d, dp, _re_html );
  12360 			}
  12361 		},
  12362 		search: _filterString(true, true)
  12363 	});
  12364 	
  12365 	
  12366 	DataTable.type('num-fmt', {
  12367 		className: 'dt-type-numeric',
  12368 		detect: function ( d, settings )
  12369 		{
  12370 			var decimal = settings.oLanguage.sDecimal;
  12371 			return _isNumber( d, decimal, true ) ? 'num-fmt' : null;
  12372 		},
  12373 		order: {
  12374 			pre: function ( d, s ) {
  12375 				var dp = s.oLanguage.sDecimal;
  12376 				return __numericReplace( d, dp, _re_formatted_numeric );
  12377 			}
  12378 		}
  12379 	});
  12380 	
  12381 	
  12382 	DataTable.type('num', {
  12383 		className: 'dt-type-numeric',
  12384 		detect: function ( d, settings )
  12385 		{
  12386 			var decimal = settings.oLanguage.sDecimal;
  12387 			return _isNumber( d, decimal ) ? 'num' : null;
  12388 		},
  12389 		order: {
  12390 			pre: function (d, s) {
  12391 				var dp = s.oLanguage.sDecimal;
  12392 				return __numericReplace( d, dp );
  12393 			}
  12394 		}
  12395 	});
  12396 	
  12397 	
  12398 	
  12399 	
  12400 	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
  12401 		if ( d !== 0 && (!d || d === '-') ) {
  12402 			return -Infinity;
  12403 		}
  12404 		
  12405 		var type = typeof d;
  12406 	
  12407 		if (type === 'number' || type === 'bigint') {
  12408 			return d;
  12409 		}
  12410 	
  12411 		// If a decimal place other than `.` is used, it needs to be given to the
  12412 		// function so we can detect it and replace with a `.` which is the only
  12413 		// decimal place Javascript recognises - it is not locale aware.
  12414 		if ( decimalPlace ) {
  12415 			d = _numToDecimal( d, decimalPlace );
  12416 		}
  12417 	
  12418 		if ( d.replace ) {
  12419 			if ( re1 ) {
  12420 				d = d.replace( re1, '' );
  12421 			}
  12422 	
  12423 			if ( re2 ) {
  12424 				d = d.replace( re2, '' );
  12425 			}
  12426 		}
  12427 	
  12428 		return d * 1;
  12429 	};
  12430 	
  12431 	
  12432 	$.extend( true, DataTable.ext.renderer, {
  12433 		footer: {
  12434 			_: function ( settings, cell, classes ) {
  12435 				cell.addClass(classes.tfoot.cell);
  12436 			}
  12437 		},
  12438 	
  12439 		header: {
  12440 			_: function ( settings, cell, classes ) {
  12441 				cell.addClass(classes.thead.cell);
  12442 	
  12443 				if (! settings.oFeatures.bSort) {
  12444 					cell.addClass(classes.order.none);
  12445 				}
  12446 	
  12447 				var legacyTop = settings.bSortCellsTop;
  12448 				var headerRows = cell.closest('thead').find('tr');
  12449 				var rowIdx = cell.parent().index();
  12450 	
  12451 				// Conditions to not apply the ordering icons
  12452 				if (
  12453 					// Cells and rows which have the attribute to disable the icons
  12454 					cell.attr('data-dt-order') === 'disable' ||
  12455 					cell.parent().attr('data-dt-order') === 'disable' ||
  12456 	
  12457 					// Legacy support for `orderCellsTop`. If it is set, then cells
  12458 					// which are not in the top or bottom row of the header (depending
  12459 					// on the value) do not get the sorting classes applied to them
  12460 					(legacyTop === true && rowIdx !== 0) ||
  12461 					(legacyTop === false && rowIdx !== headerRows.length - 1)
  12462 				) {
  12463 					return;
  12464 				}
  12465 	
  12466 				// No additional mark-up required
  12467 				// Attach a sort listener to update on sort - note that using the
  12468 				// `DT` namespace will allow the event to be removed automatically
  12469 				// on destroy, while the `dt` namespaced event is the one we are
  12470 				// listening for
  12471 				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting ) {
  12472 					if ( settings !== ctx ) { // need to check this this is the host
  12473 						return;               // table, not a nested one
  12474 					}
  12475 	
  12476 					var orderClasses = classes.order;
  12477 					var columns = ctx.api.columns( cell );
  12478 					var col = settings.aoColumns[columns.flatten()[0]];
  12479 					var orderable = columns.orderable().includes(true);
  12480 					var ariaType = '';
  12481 					var indexes = columns.indexes();
  12482 					var sortDirs = columns.orderable(true).flatten();
  12483 					var orderedColumns = ',' + sorting.map( function (val) {
  12484 						return val.col;
  12485 					} ).join(',') + ',';
  12486 	
  12487 					cell
  12488 						.removeClass(
  12489 							orderClasses.isAsc +' '+
  12490 							orderClasses.isDesc
  12491 						)
  12492 						.toggleClass( orderClasses.none, ! orderable )
  12493 						.toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
  12494 						.toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
  12495 					
  12496 					var sortIdx = orderedColumns.indexOf( ',' + indexes.toArray().join(',') + ',' );
  12497 	
  12498 					if ( sortIdx !== -1 ) {
  12499 						// Get the ordering direction for the columns under this cell
  12500 						// Note that it is possible for a cell to be asc and desc sorting
  12501 						// (column spanning cells)
  12502 						var orderDirs = columns.order();
  12503 	
  12504 						cell.addClass(
  12505 							orderDirs.includes('asc') ? orderClasses.isAsc : '' +
  12506 							orderDirs.includes('desc') ? orderClasses.isDesc : ''
  12507 						);
  12508 					}
  12509 	
  12510 					// The ARIA spec says that only one column should be marked with aria-sort
  12511 					if ( sortIdx === 0 ) {
  12512 						var firstSort = sorting[0];
  12513 						var sortOrder = col.asSorting;
  12514 	
  12515 						cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
  12516 	
  12517 						// Determine if the next click will remove sorting or change the sort
  12518 						ariaType = ! sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
  12519 					}
  12520 					else {
  12521 						cell.removeAttr('aria-sort');
  12522 					}
  12523 	
  12524 					cell.attr('aria-label', orderable
  12525 						? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
  12526 						: col.ariaTitle
  12527 					);
  12528 	
  12529 					if (orderable) {
  12530 						cell.find('.dt-column-title').attr('role', 'button');
  12531 						cell.attr('tabindex', 0)
  12532 					}
  12533 				} );
  12534 			}
  12535 		},
  12536 	
  12537 		layout: {
  12538 			_: function ( settings, container, items ) {
  12539 				var row = $('<div/>')
  12540 					.addClass('dt-layout-row')
  12541 					.appendTo( container );
  12542 	
  12543 				$.each( items, function (key, val) {
  12544 					var klass = ! val.table ?
  12545 						'dt-'+key+' ' :
  12546 						'';
  12547 	
  12548 					if (val.table) {
  12549 						row.addClass('dt-layout-table');
  12550 					}
  12551 	
  12552 					$('<div/>')
  12553 						.attr({
  12554 							id: val.id || null,
  12555 							"class": 'dt-layout-cell '+klass+(val.className || '')
  12556 						})
  12557 						.append( val.contents )
  12558 						.appendTo( row );
  12559 				} );
  12560 			}
  12561 		}
  12562 	} );
  12563 	
  12564 	
  12565 	DataTable.feature = {};
  12566 	
  12567 	// Third parameter is internal only!
  12568 	DataTable.feature.register = function ( name, cb, legacy ) {
  12569 		DataTable.ext.features[ name ] = cb;
  12570 	
  12571 		if (legacy) {
  12572 			_ext.feature.push({
  12573 				cFeature: legacy,
  12574 				fnInit: cb
  12575 			});
  12576 		}
  12577 	};
  12578 	
  12579 	DataTable.feature.register( 'info', function ( settings, opts ) {
  12580 		// For compatibility with the legacy `info` top level option
  12581 		if (! settings.oFeatures.bInfo) {
  12582 			return null;
  12583 		}
  12584 	
  12585 		var
  12586 			lang  = settings.oLanguage,
  12587 			tid = settings.sTableId,
  12588 			n = $('<div/>', {
  12589 				'class': settings.oClasses.info.container,
  12590 			} );
  12591 	
  12592 		opts = $.extend({
  12593 			callback: lang.fnInfoCallback,
  12594 			empty: lang.sInfoEmpty,
  12595 			postfix: lang.sInfoPostFix,
  12596 			search: lang.sInfoFiltered,
  12597 			text: lang.sInfo,
  12598 		}, opts);
  12599 	
  12600 	
  12601 		// Update display on each draw
  12602 		settings.aoDrawCallback.push(function (s) {
  12603 			_fnUpdateInfo(s, opts, n);
  12604 		});
  12605 	
  12606 		// For the first info display in the table, we add a callback and aria information.
  12607 		if (! settings._infoEl) {
  12608 			n.attr({
  12609 				'aria-live': 'polite',
  12610 				id: tid+'_info',
  12611 				role: 'status'
  12612 			});
  12613 	
  12614 			// Table is described by our info div
  12615 			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
  12616 	
  12617 			settings._infoEl = n;
  12618 		}
  12619 	
  12620 		return n;
  12621 	}, 'i' );
  12622 	
  12623 	/**
  12624 	 * Update the information elements in the display
  12625 	 *  @param {object} settings dataTables settings object
  12626 	 *  @memberof DataTable#oApi
  12627 	 */
  12628 	function _fnUpdateInfo ( settings, opts, node )
  12629 	{
  12630 		var
  12631 			start = settings._iDisplayStart+1,
  12632 			end   = settings.fnDisplayEnd(),
  12633 			max   = settings.fnRecordsTotal(),
  12634 			total = settings.fnRecordsDisplay(),
  12635 			out   = total
  12636 				? opts.text
  12637 				: opts.empty;
  12638 	
  12639 		if ( total !== max ) {
  12640 			// Record set after filtering
  12641 			out += ' ' + opts.search;
  12642 		}
  12643 	
  12644 		// Convert the macros
  12645 		out += opts.postfix;
  12646 		out = _fnMacros( settings, out );
  12647 	
  12648 		if ( opts.callback ) {
  12649 			out = opts.callback.call( settings.oInstance,
  12650 				settings, start, end, max, total, out
  12651 			);
  12652 		}
  12653 	
  12654 		node.html( out );
  12655 	
  12656 		_fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
  12657 	}
  12658 	
  12659 	var __searchCounter = 0;
  12660 	
  12661 	// opts
  12662 	// - text
  12663 	// - placeholder
  12664 	DataTable.feature.register( 'search', function ( settings, opts ) {
  12665 		// Don't show the input if filtering isn't available on the table
  12666 		if (! settings.oFeatures.bFilter) {
  12667 			return null;
  12668 		}
  12669 	
  12670 		var classes = settings.oClasses.search;
  12671 		var tableId = settings.sTableId;
  12672 		var language = settings.oLanguage;
  12673 		var previousSearch = settings.oPreviousSearch;
  12674 		var input = '<input type="search" class="'+classes.input+'"/>';
  12675 	
  12676 		opts = $.extend({
  12677 			placeholder: language.sSearchPlaceholder,
  12678 			text: language.sSearch
  12679 		}, opts);
  12680 	
  12681 		// The _INPUT_ is optional - is appended if not present
  12682 		if (opts.text.indexOf('_INPUT_') === -1) {
  12683 			opts.text += '_INPUT_';
  12684 		}
  12685 	
  12686 		opts.text = _fnMacros(settings, opts.text);
  12687 	
  12688 		// We can put the <input> outside of the label if it is at the start or end
  12689 		// which helps improve accessability (not all screen readers like implicit
  12690 		// for elements).
  12691 		var end = opts.text.match(/_INPUT_$/);
  12692 		var start = opts.text.match(/^_INPUT_/);
  12693 		var removed = opts.text.replace(/_INPUT_/, '');
  12694 		var str = '<label>' + opts.text + '</label>';
  12695 	
  12696 		if (start) {
  12697 			str = '_INPUT_<label>' + removed + '</label>';
  12698 		}
  12699 		else if (end) {
  12700 			str = '<label>' + removed + '</label>_INPUT_';
  12701 		}
  12702 	
  12703 		var filter = $('<div>')
  12704 			.addClass(classes.container)
  12705 			.append(str.replace(/_INPUT_/, input));
  12706 	
  12707 		// add for and id to label and input
  12708 		filter.find('label').attr('for', 'dt-search-' + __searchCounter);
  12709 		filter.find('input').attr('id', 'dt-search-' + __searchCounter);
  12710 		__searchCounter++;
  12711 	
  12712 		var searchFn = function(event) {
  12713 			var val = this.value;
  12714 	
  12715 			if(previousSearch.return && event.key !== "Enter") {
  12716 				return;
  12717 			}
  12718 	
  12719 			/* Now do the filter */
  12720 			if ( val != previousSearch.search ) {
  12721 				previousSearch.search = val;
  12722 	
  12723 				_fnFilterComplete( settings, previousSearch );
  12724 	
  12725 				// Need to redraw, without resorting
  12726 				settings._iDisplayStart = 0;
  12727 				_fnDraw( settings );
  12728 			}
  12729 		};
  12730 	
  12731 		var searchDelay = settings.searchDelay !== null ?
  12732 			settings.searchDelay :
  12733 			0;
  12734 	
  12735 		var jqFilter = $('input', filter)
  12736 			.val( previousSearch.search )
  12737 			.attr( 'placeholder', opts.placeholder )
  12738 			.on(
  12739 				'keyup.DT search.DT input.DT paste.DT cut.DT',
  12740 				searchDelay ?
  12741 					DataTable.util.debounce( searchFn, searchDelay ) :
  12742 					searchFn
  12743 			)
  12744 			.on( 'mouseup.DT', function(e) {
  12745 				// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
  12746 				// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
  12747 				// checks the value to see if it has changed. In other browsers it won't have.
  12748 				setTimeout( function () {
  12749 					searchFn.call(jqFilter[0], e);
  12750 				}, 10);
  12751 			} )
  12752 			.on( 'keypress.DT', function(e) {
  12753 				/* Prevent form submission */
  12754 				if ( e.keyCode == 13 ) {
  12755 					return false;
  12756 				}
  12757 			} )
  12758 			.attr('aria-controls', tableId);
  12759 	
  12760 		// Update the input elements whenever the table is filtered
  12761 		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
  12762 			if ( settings === s && jqFilter[0] !== document.activeElement ) {
  12763 				jqFilter.val( typeof previousSearch.search !== 'function'
  12764 					? previousSearch.search
  12765 					: ''
  12766 				);
  12767 			}
  12768 		} );
  12769 	
  12770 		return filter;
  12771 	}, 'f' );
  12772 	
  12773 	// opts
  12774 	// - type - button configuration
  12775 	// - buttons - number of buttons to show - must be odd
  12776 	DataTable.feature.register( 'paging', function ( settings, opts ) {
  12777 		// Don't show the paging input if the table doesn't have paging enabled
  12778 		if (! settings.oFeatures.bPaginate) {
  12779 			return null;
  12780 		}
  12781 	
  12782 		opts = $.extend({
  12783 			buttons: DataTable.ext.pager.numbers_length,
  12784 			type: settings.sPaginationType,
  12785 			boundaryNumbers: true
  12786 		}, opts);
  12787 	
  12788 		// To be removed in 2.1
  12789 		if (opts.numbers) {
  12790 			opts.buttons = opts.numbers;
  12791 		}
  12792 	
  12793 		var host = $('<div/>').addClass( settings.oClasses.paging.container + ' paging_' + opts.type );
  12794 		var draw = function () {
  12795 			_pagingDraw(settings, host, opts);
  12796 		};
  12797 	
  12798 		settings.aoDrawCallback.push(draw);
  12799 	
  12800 		// Responsive redraw of paging control
  12801 		$(settings.nTable).on('column-sizing.dt.DT', draw);
  12802 	
  12803 		return host;
  12804 	}, 'p' );
  12805 	
  12806 	function _pagingDraw(settings, host, opts) {
  12807 		if (! settings._bInitComplete) {
  12808 			return;
  12809 		}
  12810 	
  12811 		var
  12812 			plugin = DataTable.ext.pager[ opts.type ],
  12813 			aria = settings.oLanguage.oAria.paginate || {},
  12814 			start      = settings._iDisplayStart,
  12815 			len        = settings._iDisplayLength,
  12816 			visRecords = settings.fnRecordsDisplay(),
  12817 			all        = len === -1,
  12818 			page = all ? 0 : Math.ceil( start / len ),
  12819 			pages = all ? 1 : Math.ceil( visRecords / len ),
  12820 			buttons = plugin()
  12821 				.map(function (val) {
  12822 					return val === 'numbers'
  12823 						? _pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
  12824 						: val;
  12825 				})
  12826 				.flat();
  12827 	
  12828 		var buttonEls = [];
  12829 	
  12830 		for (var i=0 ; i<buttons.length ; i++) {
  12831 			var button = buttons[i];
  12832 	
  12833 			var btnInfo = _pagingButtonInfo(settings, button, page, pages);
  12834 			var btn = _fnRenderer( settings, 'pagingButton' )(
  12835 				settings,
  12836 				button,
  12837 				btnInfo.display,
  12838 				btnInfo.active,
  12839 				btnInfo.disabled
  12840 			);
  12841 	
  12842 			// Common attributes
  12843 			$(btn.clicker).attr({
  12844 				'aria-controls': settings.sTableId,
  12845 				'aria-disabled': btnInfo.disabled ? 'true' : null,
  12846 				'aria-current': btnInfo.active ? 'page' : null,
  12847 				'aria-label': aria[ button ],
  12848 				'data-dt-idx': button,
  12849 				'tabIndex': btnInfo.disabled ? -1 : settings.iTabIndex,
  12850 			});
  12851 	
  12852 			if (typeof button !== 'number') {
  12853 				$(btn.clicker).addClass(button);
  12854 			}
  12855 	
  12856 			_fnBindAction(
  12857 				btn.clicker, {action: button}, function(e) {
  12858 					e.preventDefault();
  12859 	
  12860 					_fnPageChange( settings, e.data.action, true );
  12861 				}
  12862 			);
  12863 	
  12864 			buttonEls.push(btn.display);
  12865 		}
  12866 	
  12867 		var wrapped = _fnRenderer(settings, 'pagingContainer')(
  12868 			settings, buttonEls
  12869 		);
  12870 	
  12871 		var activeEl = host.find(document.activeElement).data('dt-idx');
  12872 	
  12873 		host.empty().append(wrapped);
  12874 	
  12875 		if ( activeEl !== undefined ) {
  12876 			host.find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
  12877 		}
  12878 	
  12879 		// Responsive - check if the buttons are over two lines based on the
  12880 		// height of the buttons and the container.
  12881 		if (
  12882 			buttonEls.length && // any buttons
  12883 			opts.numbers > 1 && // prevent infinite
  12884 			$(host).height() >= ($(buttonEls[0]).outerHeight() * 2) - 10
  12885 		) {
  12886 			_pagingDraw(settings, host, $.extend({}, opts, { numbers: opts.numbers - 2 }));
  12887 		}
  12888 	}
  12889 	
  12890 	/**
  12891 	 * Get properties for a button based on the current paging state of the table
  12892 	 *
  12893 	 * @param {*} settings DT settings object
  12894 	 * @param {*} button The button type in question
  12895 	 * @param {*} page Table's current page
  12896 	 * @param {*} pages Number of pages
  12897 	 * @returns Info object
  12898 	 */
  12899 	function _pagingButtonInfo(settings, button, page, pages) {
  12900 		var lang = settings.oLanguage.oPaginate;
  12901 		var o = {
  12902 			display: '',
  12903 			active: false,
  12904 			disabled: false
  12905 		};
  12906 	
  12907 		switch ( button ) {
  12908 			case 'ellipsis':
  12909 				o.display = '&#x2026;';
  12910 				o.disabled = true;
  12911 				break;
  12912 	
  12913 			case 'first':
  12914 				o.display = lang.sFirst;
  12915 	
  12916 				if (page === 0) {
  12917 					o.disabled = true;
  12918 				}
  12919 				break;
  12920 	
  12921 			case 'previous':
  12922 				o.display = lang.sPrevious;
  12923 	
  12924 				if ( page === 0 ) {
  12925 					o.disabled = true;
  12926 				}
  12927 				break;
  12928 	
  12929 			case 'next':
  12930 				o.display = lang.sNext;
  12931 	
  12932 				if ( pages === 0 || page === pages-1 ) {
  12933 					o.disabled = true;
  12934 				}
  12935 				break;
  12936 	
  12937 			case 'last':
  12938 				o.display = lang.sLast;
  12939 	
  12940 				if ( pages === 0 || page === pages-1 ) {
  12941 					o.disabled = true;
  12942 				}
  12943 				break;
  12944 	
  12945 			default:
  12946 				if ( typeof button === 'number' ) {
  12947 					o.display = settings.fnFormatNumber( button + 1 );
  12948 					
  12949 					if (page === button) {
  12950 						o.active = true;
  12951 					}
  12952 				}
  12953 				break;
  12954 		}
  12955 	
  12956 		return o;
  12957 	}
  12958 	
  12959 	/**
  12960 	 * Compute what number buttons to show in the paging control
  12961 	 *
  12962 	 * @param {*} page Current page
  12963 	 * @param {*} pages Total number of pages
  12964 	 * @param {*} buttons Target number of number buttons
  12965 	 * @param {boolean} addFirstLast Indicate if page 1 and end should be included
  12966 	 * @returns Buttons to show
  12967 	 */
  12968 	function _pagingNumbers ( page, pages, buttons, addFirstLast ) {
  12969 		var
  12970 			numbers = [],
  12971 			half = Math.floor(buttons / 2),
  12972 			before = addFirstLast ? 2 : 1,
  12973 			after = addFirstLast ? 1 : 0;
  12974 	
  12975 		if ( pages <= buttons ) {
  12976 			numbers = _range(0, pages);
  12977 		}
  12978 		else if (buttons === 1) {
  12979 			// Single button - current page only
  12980 			numbers = [page];
  12981 		}
  12982 		else if (buttons === 3) {
  12983 			// Special logic for just three buttons
  12984 			if (page <= 1) {
  12985 				numbers = [0, 1, 'ellipsis'];
  12986 			}
  12987 			else if (page >= pages - 2) {
  12988 				numbers = _range(pages-2, pages);
  12989 				numbers.unshift('ellipsis');
  12990 			}
  12991 			else {
  12992 				numbers = ['ellipsis', page, 'ellipsis'];
  12993 			}
  12994 		}
  12995 		else if ( page <= half ) {
  12996 			numbers = _range(0, buttons-before);
  12997 			numbers.push('ellipsis');
  12998 	
  12999 			if (addFirstLast) {
  13000 				numbers.push(pages-1);
  13001 			}
  13002 		}
  13003 		else if ( page >= pages - 1 - half ) {
  13004 			numbers = _range(pages-(buttons-before), pages);
  13005 			numbers.unshift('ellipsis');
  13006 	
  13007 			if (addFirstLast) {
  13008 				numbers.unshift(0);
  13009 			}
  13010 		}
  13011 		else {
  13012 			numbers = _range(page-half+before, page+half-after);
  13013 			numbers.push('ellipsis');
  13014 			numbers.unshift('ellipsis');
  13015 	
  13016 			if (addFirstLast) {
  13017 				numbers.push(pages-1);
  13018 				numbers.unshift(0);
  13019 			}
  13020 		}
  13021 	
  13022 		return numbers;
  13023 	}
  13024 	
  13025 	var __lengthCounter = 0;
  13026 	
  13027 	// opts
  13028 	// - menu
  13029 	// - text
  13030 	DataTable.feature.register( 'pageLength', function ( settings, opts ) {
  13031 		var features = settings.oFeatures;
  13032 	
  13033 		// For compatibility with the legacy `pageLength` top level option
  13034 		if (! features.bPaginate || ! features.bLengthChange) {
  13035 			return null;
  13036 		}
  13037 	
  13038 		opts = $.extend({
  13039 			menu: settings.aLengthMenu,
  13040 			text: settings.oLanguage.sLengthMenu
  13041 		}, opts);
  13042 	
  13043 		var
  13044 			classes  = settings.oClasses.length,
  13045 			tableId  = settings.sTableId,
  13046 			menu     = opts.menu,
  13047 			lengths  = [],
  13048 			language = [],
  13049 			i;
  13050 	
  13051 		// Options can be given in a number of ways
  13052 		if (Array.isArray( menu[0] )) {
  13053 			// Old 1.x style - 2D array
  13054 			lengths = menu[0];
  13055 			language = menu[1];
  13056 		}
  13057 		else {
  13058 			for ( i=0 ; i<menu.length ; i++ ) {
  13059 				// An object with different label and value
  13060 				if ($.isPlainObject(menu[i])) {
  13061 					lengths.push(menu[i].value);
  13062 					language.push(menu[i].label);
  13063 				}
  13064 				else {
  13065 					// Or just a number to display and use
  13066 					lengths.push(menu[i]);
  13067 					language.push(menu[i]);
  13068 				}
  13069 			}
  13070 		}
  13071 	
  13072 		// We can put the <select> outside of the label if it is at the start or
  13073 		// end which helps improve accessability (not all screen readers like
  13074 		// implicit for elements).
  13075 		var end = opts.text.match(/_MENU_$/);
  13076 		var start = opts.text.match(/^_MENU_/);
  13077 		var removed = opts.text.replace(/_MENU_/, '');
  13078 		var str = '<label>' + opts.text + '</label>';
  13079 	
  13080 		if (start) {
  13081 			str = '_MENU_<label>' + removed + '</label>';
  13082 		}
  13083 		else if (end) {
  13084 			str = '<label>' + removed + '</label>_MENU_';
  13085 		}
  13086 	
  13087 		// Wrapper element - use a span as a holder for where the select will go
  13088 		var div = $('<div/>')
  13089 			.addClass( classes.container )
  13090 			.append(
  13091 				str.replace( '_MENU_', '<span></span>' )
  13092 			);
  13093 	
  13094 		// Save text node content for macro updating
  13095 		var textNodes = [];
  13096 		div.find('label')[0].childNodes.forEach(function (el) {
  13097 			if (el.nodeType === Node.TEXT_NODE) {
  13098 				textNodes.push({
  13099 					el: el,
  13100 					text: el.textContent
  13101 				});
  13102 			}
  13103 		})
  13104 	
  13105 		// Update the label text in case it has an entries value
  13106 		var updateEntries = function (len) {
  13107 			textNodes.forEach(function (node) {
  13108 				node.el.textContent = _fnMacros(settings, node.text, len);
  13109 			});
  13110 		}
  13111 	
  13112 		// Next, the select itself, along with the options
  13113 		var select = $('<select/>', {
  13114 			'name':          tableId+'_length',
  13115 			'aria-controls': tableId,
  13116 			'class':         classes.select
  13117 		} );
  13118 	
  13119 		for ( i=0 ; i<lengths.length ; i++ ) {
  13120 			select[0][ i ] = new Option(
  13121 				typeof language[i] === 'number' ?
  13122 					settings.fnFormatNumber( language[i] ) :
  13123 					language[i],
  13124 				lengths[i]
  13125 			);
  13126 		}
  13127 	
  13128 		// add for and id to label and input
  13129 		div.find('label').attr('for', 'dt-length-' + __lengthCounter);
  13130 		select.attr('id', 'dt-length-' + __lengthCounter);
  13131 		__lengthCounter++;
  13132 	
  13133 		// Swap in the select list
  13134 		div.find('span').replaceWith(select);
  13135 	
  13136 		// Can't use `select` variable as user might provide their own and the
  13137 		// reference is broken by the use of outerHTML
  13138 		$('select', div)
  13139 			.val( settings._iDisplayLength )
  13140 			.on( 'change.DT', function() {
  13141 				_fnLengthChange( settings, $(this).val() );
  13142 				_fnDraw( settings );
  13143 			} );
  13144 	
  13145 		// Update node value whenever anything changes the table's length
  13146 		$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
  13147 			if ( settings === s ) {
  13148 				$('select', div).val( len );
  13149 	
  13150 				// Resolve plurals in the text for the new length
  13151 				updateEntries(len);
  13152 			}
  13153 		} );
  13154 	
  13155 		updateEntries(settings._iDisplayLength);
  13156 	
  13157 		return div;
  13158 	}, 'l' );
  13159 	
  13160 	// jQuery access
  13161 	$.fn.dataTable = DataTable;
  13162 	
  13163 	// Provide access to the host jQuery object (circular reference)
  13164 	DataTable.$ = $;
  13165 	
  13166 	// Legacy aliases
  13167 	$.fn.dataTableSettings = DataTable.settings;
  13168 	$.fn.dataTableExt = DataTable.ext;
  13169 	
  13170 	// With a capital `D` we return a DataTables API instance rather than a
  13171 	// jQuery object
  13172 	$.fn.DataTable = function ( opts ) {
  13173 		return $(this).dataTable( opts ).api();
  13174 	};
  13175 	
  13176 	// All properties that are available to $.fn.dataTable should also be
  13177 	// available on $.fn.DataTable
  13178 	$.each( DataTable, function ( prop, val ) {
  13179 		$.fn.DataTable[ prop ] = val;
  13180 	} );
  13181 
  13182 	return DataTable;
  13183 }));
  13184 
  13185 
  13186 /*! DataTables Bootstrap 5 integration
  13187  * © SpryMedia Ltd - datatables.net/license
  13188  */
  13189 
  13190 (function( factory ){
  13191 	if ( typeof define === 'function' && define.amd ) {
  13192 		// AMD
  13193 		define( ['jquery', 'datatables.net'], function ( $ ) {
  13194 			return factory( $, window, document );
  13195 		} );
  13196 	}
  13197 	else if ( typeof exports === 'object' ) {
  13198 		// CommonJS
  13199 		var jq = require('jquery');
  13200 		var cjsRequires = function (root, $) {
  13201 			if ( ! $.fn.dataTable ) {
  13202 				require('datatables.net')(root, $);
  13203 			}
  13204 		};
  13205 
  13206 		if (typeof window === 'undefined') {
  13207 			module.exports = function (root, $) {
  13208 				if ( ! root ) {
  13209 					// CommonJS environments without a window global must pass a
  13210 					// root. This will give an error otherwise
  13211 					root = window;
  13212 				}
  13213 
  13214 				if ( ! $ ) {
  13215 					$ = jq( root );
  13216 				}
  13217 
  13218 				cjsRequires( root, $ );
  13219 				return factory( $, root, root.document );
  13220 			};
  13221 		}
  13222 		else {
  13223 			cjsRequires( window, jq );
  13224 			module.exports = factory( jq, window, window.document );
  13225 		}
  13226 	}
  13227 	else {
  13228 		// Browser
  13229 		factory( jQuery, window, document );
  13230 	}
  13231 }(function( $, window, document ) {
  13232 'use strict';
  13233 var DataTable = $.fn.dataTable;
  13234 
  13235 
  13236 
  13237 /**
  13238  * DataTables integration for Bootstrap 5.
  13239  *
  13240  * This file sets the defaults and adds options to DataTables to style its
  13241  * controls using Bootstrap. See https://datatables.net/manual/styling/bootstrap
  13242  * for further information.
  13243  */
  13244 
  13245 /* Set the defaults for DataTables initialisation */
  13246 $.extend( true, DataTable.defaults, {
  13247 	renderer: 'bootstrap'
  13248 } );
  13249 
  13250 
  13251 /* Default class modification */
  13252 $.extend( true, DataTable.ext.classes, {
  13253 	container: "dt-container dt-bootstrap5",
  13254 	search: {
  13255 		input: "form-control form-control-sm"
  13256 	},
  13257 	length: {
  13258 		select: "form-select form-select-sm"
  13259 	},
  13260 	processing: {
  13261 		container: "dt-processing card"
  13262 	}
  13263 } );
  13264 
  13265 
  13266 /* Bootstrap paging button renderer */
  13267 DataTable.ext.renderer.pagingButton.bootstrap = function (settings, buttonType, content, active, disabled) {
  13268 	var btnClasses = ['dt-paging-button', 'page-item'];
  13269 
  13270 	if (active) {
  13271 		btnClasses.push('active');
  13272 	}
  13273 
  13274 	if (disabled) {
  13275 		btnClasses.push('disabled')
  13276 	}
  13277 
  13278 	var li = $('<li>').addClass(btnClasses.join(' '));
  13279 	var a = $('<a>', {
  13280 		'href': disabled ? null : '#',
  13281 		'class': 'page-link'
  13282 	})
  13283 		.html(content)
  13284 		.appendTo(li);
  13285 
  13286 	return {
  13287 		display: li,
  13288 		clicker: a
  13289 	};
  13290 };
  13291 
  13292 DataTable.ext.renderer.pagingContainer.bootstrap = function (settings, buttonEls) {
  13293 	return $('<ul/>').addClass('pagination').append(buttonEls);
  13294 };
  13295 
  13296 DataTable.ext.renderer.layout.bootstrap = function ( settings, container, items ) {
  13297 	var row = $( '<div/>', {
  13298 			"class": items.full ?
  13299 				'row mt-2 justify-content-md-center' :
  13300 				'row mt-2 justify-content-between'
  13301 		} )
  13302 		.appendTo( container );
  13303 
  13304 	$.each( items, function (key, val) {
  13305 		var klass;
  13306 
  13307 		// Apply start / end (left / right when ltr) margins
  13308 		if (val.table) {
  13309 			klass = 'col-12';
  13310 		}
  13311 		else if (key === 'start') {
  13312 			klass = 'col-md-auto me-auto';
  13313 		}
  13314 		else if (key === 'end') {
  13315 			klass = 'col-md-auto ms-auto';
  13316 		}
  13317 		else {
  13318 			klass = 'col-md';
  13319 		}
  13320 
  13321 		$( '<div/>', {
  13322 				id: val.id || null,
  13323 				"class": klass + ' ' + (val.className || '')
  13324 			} )
  13325 			.append( val.contents )
  13326 			.appendTo( row );
  13327 	} );
  13328 };
  13329 
  13330 
  13331 return DataTable;
  13332 }));
  13333 
  13334