PageSourceSearch

https://puertocarreno-vichada.gov.co/Style%20Library/Datatables/assets/js/dataTables.js

js puertocarreno-vichada.gov.co collected 2026-09-24 10:18:09 UTC 384,586 bytes, 13,843 lines download raw bytes

1/*! DataTables 2.2.2
2 * © SpryMedia Ltd - datatables.net/license
3 */
4
5(function( factory ) {
6	"use strict";
7
8	if ( typeof define === 'function' && define.amd ) {
9		// AMD
10		define( ['jquery'], function ( $ ) {
11			return factory( $, window, document );
12		} );
13	}
14	else if ( typeof exports === 'object' ) {
15		// CommonJS
16		// jQuery's factory checks for a global window - if it isn't present then it
17		// returns a factory function that expects the window object
18		var jq = require('jquery');
19
20		if (typeof window === 'undefined') {
21			module.exports = function (root, $) {
22				if ( ! root ) {
23					// CommonJS environments without a window global must pass a
24					// root. This will give an error otherwise
25					root = window;
26				}
27
28				if ( ! $ ) {
29					$ = jq( root );
30				}
31
32				return factory( $, root, root.document );
33			};
34		}
35		else {
36			module.exports = factory( jq, window, window.document );
37		}
38	}
39	else {
40		// Browser
41		window.DataTable = factory( jQuery, window, document );
42	}
43}(function( $, window, document ) {
44	"use strict";
45
46	
47	var DataTable = function ( selector, options )
48	{
49		// Check if called with a window or jQuery object for DOM less applications
50		// This is for backwards compatibility
51		if (DataTable.factory(selector, options)) {
52			return DataTable;
53		}
54	
55		// When creating with `new`, create a new DataTable, returning the API instance
56		if (this instanceof DataTable) {
57			return $(selector).DataTable(options);
58		}
59		else {
60			// Argument switching
61			options = selector;
62		}
63	
64		var _that = this;
65		var emptyInit = options === undefined;
66		var len = this.length;
67	
68		if ( emptyInit ) {
69			options = {};
70		}
71	
72		// Method to get DT API instance from jQuery object
73		this.api = function ()
74		{
75			return new _Api( this );
76		};
77	
78		this.each(function() {
79			// For each initialisation we want to give it a clean initialisation
80			// object that can be bashed around
81			var o = {};
82			var oInit = len > 1 ? // optimisation for single table case
83				_fnExtend( o, options, true ) :
84				options;
85	
86			
87			var i=0, iLen;
88			var sId = this.getAttribute( 'id' );
89			var defaults = DataTable.defaults;
90			var $this = $(this);
91			
92			
93			/* Sanity check */
94			if ( this.nodeName.toLowerCase() != 'table' )
95			{
96				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
97				return;
98			}
99			
100			$(this).trigger( 'options.dt', oInit );
101			
102			/* Backwards compatibility for the defaults */
103			_fnCompatOpts( defaults );
104			_fnCompatCols( defaults.column );
105			
106			/* Convert the camel-case defaults to Hungarian */
107			_fnCamelToHungarian( defaults, defaults, true );
108			_fnCamelToHungarian( defaults.column, defaults.column, true );
109			
110			/* Setting up the initialisation object */
111			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
112			
113			
114			
115			/* Check to see if we are re-initialising a table */
116			var allSettings = DataTable.settings;
117			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
118			{
119				var s = allSettings[i];
120			
121				/* Base check on table node */
122				if (
123					s.nTable == this ||
124					(s.nTHead && s.nTHead.parentNode == this) ||
125					(s.nTFoot && s.nTFoot.parentNode == this)
126				) {
127					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
128					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
129			
130					if ( emptyInit || bRetrieve )
131					{
132						return s.oInstance;
133					}
134					else if ( bDestroy )
135					{
136						new DataTable.Api(s).destroy();
137						break;
138					}
139					else
140					{
141						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
142						return;
143					}
144				}
145			
146				/* If the element we are initialising has the same ID as a table which was previously
147				 * initialised, but the table nodes don't match (from before) then we destroy the old
148				 * instance by simply deleting it. This is under the assumption that the table has been
149				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
150				 */
151				if ( s.sTableId == this.id )
152				{
153					allSettings.splice( i, 1 );
154					break;
155				}
156			}
157			
158			/* Ensure the table has an ID - required for accessibility */
159			if ( sId === null || sId === "" )
160			{
161				sId = "DataTables_Table_"+(DataTable.ext._unique++);
162				this.id = sId;
163			}
164			
165			/* Create the settings object for this table and set some of the default parameters */
166			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
167				"sDestroyWidth": $this[0].style.width,
168				"sInstance":     sId,
169				"sTableId":      sId,
170				colgroup: $('<colgroup>').prependTo(this),
171				fastData: function (row, column, type) {
172					return _fnGetCellData(oSettings, row, column, type);
173				}
174			} );
175			oSettings.nTable = this;
176			oSettings.oInit  = oInit;
177			
178			allSettings.push( oSettings );
179			
180			// Make a single API instance available for internal handling
181			oSettings.api = new _Api( oSettings );
182			
183			// Need to add the instance after the instance after the settings object has been added
184			// to the settings array, so we can self reference the table instance if more than one
185			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
186			
187			// Backwards compatibility, before we apply all the defaults
188			_fnCompatOpts( oInit );
189			
190			// If the length menu is given, but the init display length is not, use the length menu
191			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
192			{
193				oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
194					? oInit.aLengthMenu[0][0]
195					: $.isPlainObject( oInit.aLengthMenu[0] )
196						? oInit.aLengthMenu[0].value
197						: oInit.aLengthMenu[0];
198			}
199			
200			// Apply the defaults and init options to make a single init object will all
201			// options defined from defaults and instance options.
202			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
203			
204			
205			// Map the initialisation options onto the settings object
206			_fnMap( oSettings.oFeatures, oInit, [
207				"bPaginate",
208				"bLengthChange",
209				"bFilter",
210				"bSort",
211				"bSortMulti",
212				"bInfo",
213				"bProcessing",
214				"bAutoWidth",
215				"bSortClasses",
216				"bServerSide",
217				"bDeferRender"
218			] );
219			_fnMap( oSettings, oInit, [
220				"ajax",
221				"fnFormatNumber",
222				"sServerMethod",
223				"aaSorting",
224				"aaSortingFixed",
225				"aLengthMenu",
226				"sPaginationType",
227				"iStateDuration",
228				"bSortCellsTop",
229				"iTabIndex",
230				"sDom",
231				"fnStateLoadCallback",
232				"fnStateSaveCallback",
233				"renderer",
234				"searchDelay",
235				"rowId",
236				"caption",
237				"layout",
238				"orderDescReverse",
239				"typeDetect",
240				[ "iCookieDuration", "iStateDuration" ], // backwards compat
241				[ "oSearch", "oPreviousSearch" ],
242				[ "aoSearchCols", "aoPreSearchCols" ],
243				[ "iDisplayLength", "_iDisplayLength" ]
244			] );
245			_fnMap( oSettings.oScroll, oInit, [
246				[ "sScrollX", "sX" ],
247				[ "sScrollXInner", "sXInner" ],
248				[ "sScrollY", "sY" ],
249				[ "bScrollCollapse", "bCollapse" ]
250			] );
251			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
252			
253			/* Callback functions which are array driven */
254			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback );
255			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams );
256			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams );
257			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded );
258			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback );
259			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
260			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback );
261			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback );
262			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete );
263			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback );
264			
265			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
266			
267			/* Browser support detection */
268			_fnBrowserDetect( oSettings );
269			
270			var oClasses = oSettings.oClasses;
271			
272			$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
273			$this.addClass( oClasses.table );
274			
275			if (! oSettings.oFeatures.bPaginate) {
276				oInit.iDisplayStart = 0;
277			}
278			
279			if ( oSettings.iInitDisplayStart === undefined )
280			{
281				/* Display start point, taking into account the save saving */
282				oSettings.iInitDisplayStart = oInit.iDisplayStart;
283				oSettings._iDisplayStart = oInit.iDisplayStart;
284			}
285			
286			var defer = oInit.iDeferLoading;
287			if ( defer !== null )
288			{
289				oSettings.deferLoading = true;
290			
291				var tmp = Array.isArray(defer);
292				oSettings._iRecordsDisplay = tmp ? defer[0] : defer;
293				oSettings._iRecordsTotal = tmp ? defer[1] : defer;
294			}
295			
296			/*
297			 * Columns
298			 * See if we should load columns automatically or use defined ones
299			 */
300			var columnsInit = [];
301			var thead = this.getElementsByTagName('thead');
302			var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
303			
304			// If we don't have a columns array, then generate one with nulls
305			if ( oInit.aoColumns ) {
306				columnsInit = oInit.aoColumns;
307			}
308			else if ( initHeaderLayout.length ) {
309				for ( i=0, iLen=initHeaderLayout[0].length ; i<iLen ; i++ ) {
310					columnsInit.push( null );
311				}
312			}
313			
314			// Add the columns
315			for ( i=0, iLen=columnsInit.length ; i<iLen ; i++ ) {
316				_fnAddColumn( oSettings );
317			}
318			
319			// Apply the column definitions
320			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
321				_fnColumnOptions( oSettings, iCol, oDef );
322			} );
323			
324			/* HTML5 attribute detection - build an mData object automatically if the
325			 * attributes are found
326			 */
327			var rowOne = $this.children('tbody').find('tr').eq(0);
328			
329			if ( rowOne.length ) {
330				var a = function ( cell, name ) {
331					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
332				};
333			
334				$( rowOne[0] ).children('th, td').each( function (i, cell) {
335					var col = oSettings.aoColumns[i];
336			
337					if (! col) {
338						_fnLog( oSettings, 0, 'Incorrect column count', 18 );
339					}
340			
341					if ( col.mData === i ) {
342						var sort = a( cell, 'sort' ) || a( cell, 'order' );
343						var filter = a( cell, 'filter' ) || a( cell, 'search' );
344			
345						if ( sort !== null || filter !== null ) {
346							col.mData = {
347								_:      i+'.display',
348								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
349								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
350								filter: filter !== null ? i+'.@data-'+filter : undefined
351							};
352							col._isArrayHost = true;
353			
354							_fnColumnOptions( oSettings, i );
355						}
356					}
357				} );
358			}
359			
360			// Must be done after everything which can be overridden by the state saving!
361			_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState );
362			
363			var features = oSettings.oFeatures;
364			if ( oInit.bStateSave )
365			{
366				features.bStateSave = true;
367			}
368			
369			// If aaSorting is not defined, then we use the first indicator in asSorting
370			// in case that has been altered, so the default sort reflects that option
371			if ( oInit.aaSorting === undefined ) {
372				var sorting = oSettings.aaSorting;
373				for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
374					sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
375				}
376			}
377			
378			// Do a first pass on the sorting classes (allows any size changes to be taken into
379			// account, and also will apply sorting disabled classes if disabled
380			_fnSortingClasses( oSettings );
381			
382			_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
383				if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
384					_fnSortingClasses( oSettings );
385				}
386			} );
387			
388			
389			/*
390			 * Table HTML init
391			 * Cache the header, body and footer as required, creating them if needed
392			 */
393			var caption = $this.children('caption');
394			
395			if ( oSettings.caption ) {
396				if ( caption.length === 0 ) {
397					caption = $('<caption/>').appendTo( $this );
398				}
399			
400				caption.html( oSettings.caption );
401			}
402			
403			// Store the caption side, so we can remove the element from the document
404			// when creating the element
405			if (caption.length) {
406				caption[0]._captionSide = caption.css('caption-side');
407				oSettings.captionNode = caption[0];
408			}
409			
410			if ( thead.length === 0 ) {
411				thead = $('<thead/>').appendTo($this);
412			}
413			oSettings.nTHead = thead[0];
414			
415			var tbody = $this.children('tbody');
416			if ( tbody.length === 0 ) {
417				tbody = $('<tbody/>').insertAfter(thead);
418			}
419			oSettings.nTBody = tbody[0];
420			
421			var tfoot = $this.children('tfoot');
422			if ( tfoot.length === 0 ) {
423				// If we are a scrolling table, and no footer has been given, then we need to create
424				// a tfoot element for the caption element to be appended to
425				tfoot = $('<tfoot/>').appendTo($this);
426			}
427			oSettings.nTFoot = tfoot[0];
428			
429			// Copy the data index array
430			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
431			
432			// Initialisation complete - table can be drawn
433			oSettings.bInitialised = true;
434			
435			// Language definitions
436			var oLanguage = oSettings.oLanguage;
437			$.extend( true, oLanguage, oInit.oLanguage );
438			
439			if ( oLanguage.sUrl ) {
440				// Get the language definitions from a file
441				$.ajax( {
442					dataType: 'json',
443					url: oLanguage.sUrl,
444					success: function ( json ) {
445						_fnCamelToHungarian( defaults.oLanguage, json );
446						$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
447			
448						_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
449						_fnInitialise( oSettings );
450					},
451					error: function () {
452						// Error occurred loading language file
453						_fnLog( oSettings, 0, 'i18n file loading error', 21 );
454			
455						// Continue on as best we can
456						_fnInitialise( oSettings );
457					}
458				} );
459			}
460			else {
461				_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
462				_fnInitialise( oSettings );
463			}
464		} );
465		_that = null;
466		return this;
467	};
468	
469	
470	
471	/**
472	 * DataTables extensions
473	 * 
474	 * This namespace acts as a collection area for plug-ins that can be used to
475	 * extend DataTables capabilities. Indeed many of the build in methods
476	 * use this method to provide their own capabilities (sorting methods for
477	 * example).
478	 *
479	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
480	 * reasons
481	 *
482	 *  @namespace
483	 */
484	DataTable.ext = _ext = {
485		/**
486		 * Buttons. For use with the Buttons extension for DataTables. This is
487		 * defined here so other extensions can define buttons regardless of load
488		 * order. It is _not_ used by DataTables core.
489		 *
490		 *  @type object
491		 *  @default {}
492		 */
493		buttons: {},
494	
495	
496		/**
497		 * Element class names
498		 *
499		 *  @type object
500		 *  @default {}
501		 */
502		classes: {},
503	
504	
505		/**
506		 * DataTables build type (expanded by the download builder)
507		 *
508		 *  @type string
509		 */
510		builder: "-source-",
511	
512	
513		/**
514		 * Error reporting.
515		 * 
516		 * How should DataTables report an error. Can take the value 'alert',
517		 * 'throw', 'none' or a function.
518		 *
519		 *  @type string|function
520		 *  @default alert
521		 */
522		errMode: "alert",
523	
524	
525		/**
526		 * Legacy so v1 plug-ins don't throw js errors on load
527		 */
528		feature: [],
529	
530		/**
531		 * Feature plug-ins.
532		 * 
533		 * This is an object of callbacks which provide the features for DataTables
534		 * to be initialised via the `layout` option.
535		 */
536		features: {},
537	
538	
539		/**
540		 * Row searching.
541		 * 
542		 * This method of searching is complimentary to the default type based
543		 * searching, and a lot more comprehensive as it allows you complete control
544		 * over the searching logic. Each element in this array is a function
545		 * (parameters described below) that is called for every row in the table,
546		 * and your logic decides if it should be included in the searching data set
547		 * or not.
548		 *
549		 * Searching functions have the following input parameters:
550		 *
551		 * 1. `{object}` DataTables settings object: see
552		 *    {@link DataTable.models.oSettings}
553		 * 2. `{array|object}` Data for the row to be processed (same as the
554		 *    original format that was passed in as the data source, or an array
555		 *    from a DOM data source
556		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
557		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
558		 *
559		 * And the following return is expected:
560		 *
561		 * * {boolean} Include the row in the searched result set (true) or not
562		 *   (false)
563		 *
564		 * Note that as with the main search ability in DataTables, technically this
565		 * is "filtering", since it is subtractive. However, for consistency in
566		 * naming we call it searching here.
567		 *
568		 *  @type array
569		 *  @default []
570		 *
571		 *  @example
572		 *    // The following example shows custom search being applied to the
573		 *    // fourth column (i.e. the data[3] index) based on two input values
574		 *    // from the end-user, matching the data in a certain range.
575		 *    $.fn.dataTable.ext.search.push(
576		 *      function( settings, data, dataIndex ) {
577		 *        var min = document.getElementById('min').value * 1;
578		 *        var max = document.getElementById('max').value * 1;
579		 *        var version = data[3] == "-" ? 0 : data[3]*1;
580		 *
581		 *        if ( min == "" && max == "" ) {
582		 *          return true;
583		 *        }
584		 *        else if ( min == "" && version < max ) {
585		 *          return true;
586		 *        }
587		 *        else if ( min < version && "" == max ) {
588		 *          return true;
589		 *        }
590		 *        else if ( min < version && version < max ) {
591		 *          return true;
592		 *        }
593		 *        return false;
594		 *      }
595		 *    );
596		 */
597		search: [],
598	
599	
600		/**
601		 * Selector extensions
602		 *
603		 * The `selector` option can be used to extend the options available for the
604		 * selector modifier options (`selector-modifier` object data type) that
605		 * each of the three built in selector types offer (row, column and cell +
606		 * their plural counterparts). For example the Select extension uses this
607		 * mechanism to provide an option to select only rows, columns and cells
608		 * that have been marked as selected by the end user (`{selected: true}`),
609		 * which can be used in conjunction with the existing built in selector
610		 * options.
611		 *
612		 * Each property is an array to which functions can be pushed. The functions
613		 * take three attributes:
614		 *
615		 * * Settings object for the host table
616		 * * Options object (`selector-modifier` object type)
617		 * * Array of selected item indexes
618		 *
619		 * The return is an array of the resulting item indexes after the custom
620		 * selector has been applied.
621		 *
622		 *  @type object
623		 */
624		selector: {
625			cell: [],
626			column: [],
627			row: []
628		},
629	
630	
631		/**
632		 * Legacy configuration options. Enable and disable legacy options that
633		 * are available in DataTables.
634		 *
635		 *  @type object
636		 */
637		legacy: {
638			/**
639			 * Enable / disable DataTables 1.9 compatible server-side processing
640			 * requests
641			 *
642			 *  @type boolean
643			 *  @default null
644			 */
645			ajax: null
646		},
647	
648	
649		/**
650		 * Pagination plug-in methods.
651		 * 
652		 * Each entry in this object is a function and defines which buttons should
653		 * be shown by the pagination rendering method that is used for the table:
654		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
655		 * buttons are displayed in the document, while the functions here tell it
656		 * what buttons to display. This is done by returning an array of button
657		 * descriptions (what each button will do).
658		 *
659		 * Pagination types (the four built in options and any additional plug-in
660		 * options defined here) can be used through the `paginationType`
661		 * initialisation parameter.
662		 *
663		 * The functions defined take two parameters:
664		 *
665		 * 1. `{int} page` The current page index
666		 * 2. `{int} pages` The number of pages in the table
667		 *
668		 * Each function is expected to return an array where each element of the
669		 * array can be one of:
670		 *
671		 * * `first` - Jump to first page when activated
672		 * * `last` - Jump to last page when activated
673		 * * `previous` - Show previous page when activated
674		 * * `next` - Show next page when activated
675		 * * `{int}` - Show page of the index given
676		 * * `{array}` - A nested array containing the above elements to add a
677		 *   containing 'DIV' element (might be useful for styling).
678		 *
679		 * Note that DataTables v1.9- used this object slightly differently whereby
680		 * an object with two functions would be defined for each plug-in. That
681		 * ability is still supported by DataTables 1.10+ to provide backwards
682		 * compatibility, but this option of use is now decremented and no longer
683		 * documented in DataTables 1.10+.
684		 *
685		 *  @type object
686		 *  @default {}
687		 *
688		 *  @example
689		 *    // Show previous, next and current page buttons only
690		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
691		 *      return [ 'previous', page, 'next' ];
692		 *    };
693		 */
694		pager: {},
695	
696	
697		renderer: {
698			pageButton: {},
699			header: {}
700		},
701	
702	
703		/**
704		 * Ordering plug-ins - custom data source
705		 * 
706		 * The extension options for ordering of data available here is complimentary
707		 * to the default type based ordering that DataTables typically uses. It
708		 * allows much greater control over the the data that is being used to
709		 * order a column, but is necessarily therefore more complex.
710		 * 
711		 * This type of ordering is useful if you want to do ordering based on data
712		 * live from the DOM (for example the contents of an 'input' element) rather
713		 * than just the static string that DataTables knows of.
714		 * 
715		 * The way these plug-ins work is that you create an array of the values you
716		 * wish to be ordering for the column in question and then return that
717		 * array. The data in the array much be in the index order of the rows in
718		 * the table (not the currently ordering order!). Which order data gathering
719		 * function is run here depends on the `dt-init columns.orderDataType`
720		 * parameter that is used for the column (if any).
721		 *
722		 * The functions defined take two parameters:
723		 *
724		 * 1. `{object}` DataTables settings object: see
725		 *    {@link DataTable.models.oSettings}
726		 * 2. `{int}` Target column index
727		 *
728		 * Each function is expected to return an array:
729		 *
730		 * * `{array}` Data for the column to be ordering upon
731		 *
732		 *  @type array
733		 *
734		 *  @example
735		 *    // Ordering using `input` node values
736		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
737		 *    {
738		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
739		 *        return $('input', td).val();
740		 *      } );
741		 *    }
742		 */
743		order: {},
744	
745	
746		/**
747		 * Type based plug-ins.
748		 *
749		 * Each column in DataTables has a type assigned to it, either by automatic
750		 * detection or by direct assignment using the `type` option for the column.
751		 * The type of a column will effect how it is ordering and search (plug-ins
752		 * can also make use of the column type if required).
753		 *
754		 * @namespace
755		 */
756		type: {
757			/**
758			 * Automatic column class assignment
759			 */
760			className: {},
761	
762			/**
763			 * Type detection functions.
764			 *
765			 * The functions defined in this object are used to automatically detect
766			 * a column's type, making initialisation of DataTables super easy, even
767			 * when complex data is in the table.
768			 *
769			 * The functions defined take two parameters:
770			 *
771		     *  1. `{*}` Data from the column cell to be analysed
772		     *  2. `{settings}` DataTables settings object. This can be used to
773		     *     perform context specific type detection - for example detection
774		     *     based on language settings such as using a comma for a decimal
775		     *     place. Generally speaking the options from the settings will not
776		     *     be required
777			 *
778			 * Each function is expected to return:
779			 *
780			 * * `{string|null}` Data type detected, or null if unknown (and thus
781			 *   pass it on to the other type detection functions.
782			 *
783			 *  @type array
784			 *
785			 *  @example
786			 *    // Currency type detection plug-in:
787			 *    $.fn.dataTable.ext.type.detect.push(
788			 *      function ( data, settings ) {
789			 *        // Check the numeric part
790			 *        if ( ! data.substring(1).match(/[0-9]/) ) {
791			 *          return null;
792			 *        }
793			 *
794			 *        // Check prefixed by currency
795			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
796			 *          return 'currency';
797			 *        }
798			 *        return null;
799			 *      }
800			 *    );
801			 */
802			detect: [],
803	
804			/**
805			 * Automatic renderer assignment
806			 */
807			render: {},
808	
809	
810			/**
811			 * Type based search formatting.
812			 *
813			 * The type based searching functions can be used to pre-format the
814			 * data to be search on. For example, it can be used to strip HTML
815			 * tags or to de-format telephone numbers for numeric only searching.
816			 *
817			 * Note that is a search is not defined for a column of a given type,
818			 * no search formatting will be performed.
819			 * 
820			 * Pre-processing of searching data plug-ins - When you assign the sType
821			 * for a column (or have it automatically detected for you by DataTables
822			 * or a type detection plug-in), you will typically be using this for
823			 * custom sorting, but it can also be used to provide custom searching
824			 * by allowing you to pre-processing the data and returning the data in
825			 * the format that should be searched upon. This is done by adding
826			 * functions this object with a parameter name which matches the sType
827			 * for that target column. This is the corollary of <i>afnSortData</i>
828			 * for searching data.
829			 *
830			 * The functions defined take a single parameter:
831			 *
832		     *  1. `{*}` Data from the column cell to be prepared for searching
833			 *
834			 * Each function is expected to return:
835			 *
836			 * * `{string|null}` Formatted string that will be used for the searching.
837			 *
838			 *  @type object
839			 *  @default {}
840			 *
841			 *  @example
842			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
843			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
844			 *    }
845			 */
846			search: {},
847	
848	
849			/**
850			 * Type based ordering.
851			 *
852			 * The column type tells DataTables what ordering to apply to the table
853			 * when a column is sorted upon. The order for each type that is defined,
854			 * is defined by the functions available in this object.
855			 *
856			 * Each ordering option can be described by three properties added to
857			 * this object:
858			 *
859			 * * `{type}-pre` - Pre-formatting function
860			 * * `{type}-asc` - Ascending order function
861			 * * `{type}-desc` - Descending order function
862			 *
863			 * All three can be used together, only `{type}-pre` or only
864			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
865			 * that only `{type}-pre` is used, as this provides the optimal
866			 * implementation in terms of speed, although the others are provided
867			 * for compatibility with existing Javascript sort functions.
868			 *
869			 * `{type}-pre`: Functions defined take a single parameter:
870			 *
871		     *  1. `{*}` Data from the column cell to be prepared for ordering
872			 *
873			 * And return:
874			 *
875			 * * `{*}` Data to be sorted upon
876			 *
877			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
878			 * functions, taking two parameters:
879			 *
880		     *  1. `{*}` Data to compare to the second parameter
881		     *  2. `{*}` Data to compare to the first parameter
882			 *
883			 * And returning:
884			 *
885			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
886			 *   than the second parameter, ===0 if the two parameters are equal and
887			 *   >0 if the first parameter should be sorted height than the second
888			 *   parameter.
889			 * 
890			 *  @type object
891			 *  @default {}
892			 *
893			 *  @example
894			 *    // Numeric ordering of formatted numbers with a pre-formatter
895			 *    $.extend( $.fn.dataTable.ext.type.order, {
896			 *      "string-pre": function(x) {
897			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
898			 *        return parseFloat( a );
899			 *      }
900			 *    } );
901			 *
902			 *  @example
903			 *    // Case-sensitive string ordering, with no pre-formatting method
904			 *    $.extend( $.fn.dataTable.ext.order, {
905			 *      "string-case-asc": function(x,y) {
906			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
907			 *      },
908			 *      "string-case-desc": function(x,y) {
909			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
910			 *      }
911			 *    } );
912			 */
913			order: {}
914		},
915	
916		/**
917		 * Unique DataTables instance counter
918		 *
919		 * @type int
920		 * @private
921		 */
922		_unique: 0,
923	
924	
925		//
926		// Depreciated
927		// The following properties are retained for backwards compatibility only.
928		// The should not be used in new projects and will be removed in a future
929		// version
930		//
931	
932		/**
933		 * Version check function.
934		 *  @type function
935		 *  @depreciated Since 1.10
936		 */
937		fnVersionCheck: DataTable.fnVersionCheck,
938	
939	
940		/**
941		 * Index for what 'this' index API functions should use
942		 *  @type int
943		 *  @deprecated Since v1.10
944		 */
945		iApiIndex: 0,
946	
947	
948		/**
949		 * Software version
950		 *  @type string
951		 *  @deprecated Since v1.10
952		 */
953		sVersion: DataTable.version
954	};
955	
956	
957	//
958	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
959	//
960	$.extend( _ext, {
961		afnFiltering: _ext.search,
962		aTypes:       _ext.type.detect,
963		ofnSearch:    _ext.type.search,
964		oSort:        _ext.type.order,
965		afnSortData:  _ext.order,
966		aoFeatures:   _ext.feature,
967		oStdClasses:  _ext.classes,
968		oPagination:  _ext.pager
969	} );
970	
971	
972	$.extend( DataTable.ext.classes, {
973		container: 'dt-container',
974		empty: {
975			row: 'dt-empty'
976		},
977		info: {
978			container: 'dt-info'
979		},
980		layout: {
981			row: 'dt-layout-row',
982			cell: 'dt-layout-cell',
983			tableRow: 'dt-layout-table',
984			tableCell: '',
985			start: 'dt-layout-start',
986			end: 'dt-layout-end',
987			full: 'dt-layout-full'
988		},
989		length: {
990			container: 'dt-length',
991			select: 'dt-input'
992		},
993		order: {
994			canAsc: 'dt-orderable-asc',
995			canDesc: 'dt-orderable-desc',
996			isAsc: 'dt-ordering-asc',
997			isDesc: 'dt-ordering-desc',
998			none: 'dt-orderable-none',
999			position: 'sorting_'
1000		},
1001		processing: {
1002			container: 'dt-processing'
1003		},
1004		scrolling: {
1005			body: 'dt-scroll-body',
1006			container: 'dt-scroll',
1007			footer: {
1008				self: 'dt-scroll-foot',
1009				inner: 'dt-scroll-footInner'
1010			},
1011			header: {
1012				self: 'dt-scroll-head',
1013				inner: 'dt-scroll-headInner'
1014			}
1015		},
1016		search: {
1017			container: 'dt-search',
1018			input: 'dt-input'
1019		},
1020		table: 'dataTable',	
1021		tbody: {
1022			cell: '',
1023			row: ''
1024		},
1025		thead: {
1026			cell: '',
1027			row: ''
1028		},
1029		tfoot: {
1030			cell: '',
1031			row: ''
1032		},
1033		paging: {
1034			active: 'current',
1035			button: 'dt-paging-button',
1036			container: 'dt-paging',
1037			disabled: 'disabled',
1038			nav: ''
1039		}
1040	} );
1041	
1042	
1043	/*
1044	 * It is useful to have variables which are scoped locally so only the
1045	 * DataTables functions can access them and they don't leak into global space.
1046	 * At the same time these functions are often useful over multiple files in the
1047	 * core and API, so we list, or at least document, all variables which are used
1048	 * by DataTables as private variables here. This also ensures that there is no
1049	 * clashing of variable names and that they can easily referenced for reuse.
1050	 */
1051	
1052	
1053	// Defined else where
1054	//  _selector_run
1055	//  _selector_opts
1056	//  _selector_row_indexes
1057	
1058	var _ext; // DataTable.ext
1059	var _Api; // DataTable.Api
1060	var _api_register; // DataTable.Api.register
1061	var _api_registerPlural; // DataTable.Api.registerPlural
1062	
1063	var _re_dic = {};
1064	var _re_new_lines = /[\r\n\u2028]/g;
1065	var _re_html = /<([^>]*>)/g;
1066	var _max_str_len = Math.pow(2, 28);
1067	
1068	// This is not strict ISO8601 - Date.parse() is quite lax, although
1069	// implementations differ between browsers.
1070	var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
1071	
1072	// Escape regular expression special characters
1073	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1074	
1075	// https://en.wikipedia.org/wiki/Foreign_exchange_market
1076	// - \u20BD - Russian ruble.
1077	// - \u20a9 - South Korean Won
1078	// - \u20BA - Turkish Lira
1079	// - \u20B9 - Indian Rupee
1080	// - R - Brazil (R$) and South Africa
1081	// - fr - Swiss Franc
1082	// - kr - Swedish krona, Norwegian krone and Danish krone
1083	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1084	// - Ƀ - Bitcoin
1085	// - Ξ - Ethereum
1086	//   standards as thousands separators.
1087	var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1088	
1089	
1090	var _empty = function ( d ) {
1091		return !d || d === true || d === '-' ? true : false;
1092	};
1093	
1094	
1095	var _intVal = function ( s ) {
1096		var integer = parseInt( s, 10 );
1097		return !isNaN(integer) && isFinite(s) ? integer : null;
1098	};
1099	
1100	// Convert from a formatted number with characters other than `.` as the
1101	// decimal place, to a Javascript number
1102	var _numToDecimal = function ( num, decimalPoint ) {
1103		// Cache created regular expressions for speed as this function is called often
1104		if ( ! _re_dic[ decimalPoint ] ) {
1105			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1106		}
1107		return typeof num === 'string' && decimalPoint !== '.' ?
1108			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1109			num;
1110	};
1111	
1112	
1113	var _isNumber = function ( d, decimalPoint, formatted, allowEmpty ) {
1114		var type = typeof d;
1115		var strType = type === 'string';
1116	
1117		if ( type === 'number' || type === 'bigint') {
1118			return true;
1119		}
1120	
1121		// If empty return immediately so there must be a number if it is a
1122		// formatted string (this stops the string "k", or "kr", etc being detected
1123		// as a formatted number for currency
1124		if ( allowEmpty && _empty( d ) ) {
1125			return true;
1126		}
1127	
1128		if ( decimalPoint && strType ) {
1129			d = _numToDecimal( d, decimalPoint );
1130		}
1131	
1132		if ( formatted && strType ) {
1133			d = d.replace( _re_formatted_numeric, '' );
1134		}
1135	
1136		return !isNaN( parseFloat(d) ) && isFinite( d );
1137	};
1138	
1139	
1140	// A string without HTML in it can be considered to be HTML still
1141	var _isHtml = function ( d ) {
1142		return _empty( d ) || typeof d === 'string';
1143	};
1144	
1145	// Is a string a number surrounded by HTML?
1146	var _htmlNumeric = function ( d, decimalPoint, formatted, allowEmpty ) {
1147		if ( allowEmpty && _empty( d ) ) {
1148			return true;
1149		}
1150	
1151		// input and select strings mean that this isn't just a number
1152		if (typeof d === 'string' && d.match(/<(input|select)/i)) {
1153			return null;
1154		}
1155	
1156		var html = _isHtml( d );
1157		return ! html ?
1158			null :
1159			_isNumber( _stripHtml( d ), decimalPoint, formatted, allowEmpty ) ?
1160				true :
1161				null;
1162	};
1163	
1164	
1165	var _pluck = function ( a, prop, prop2 ) {
1166		var out = [];
1167		var i=0, ien=a.length;
1168	
1169		// Could have the test in the loop for slightly smaller code, but speed
1170		// is essential here
1171		if ( prop2 !== undefined ) {
1172			for ( ; i<ien ; i++ ) {
1173				if ( a[i] && a[i][ prop ] ) {
1174					out.push( a[i][ prop ][ prop2 ] );
1175				}
1176			}
1177		}
1178		else {
1179			for ( ; i<ien ; i++ ) {
1180				if ( a[i] ) {
1181					out.push( a[i][ prop ] );
1182				}
1183			}
1184		}
1185	
1186		return out;
1187	};
1188	
1189	
1190	// Basically the same as _pluck, but rather than looping over `a` we use `order`
1191	// as the indexes to pick from `a`
1192	var _pluck_order = function ( a, order, prop, prop2 )
1193	{
1194		var out = [];
1195		var i=0, ien=order.length;
1196	
1197		// Could have the test in the loop for slightly smaller code, but speed
1198		// is essential here
1199		if ( prop2 !== undefined ) {
1200			for ( ; i<ien ; i++ ) {
1201				if ( a[ order[i] ] && a[ order[i] ][ prop ] ) {
1202					out.push( a[ order[i] ][ prop ][ prop2 ] );
1203				}
1204			}
1205		}
1206		else {
1207			for ( ; i<ien ; i++ ) {
1208				if ( a[ order[i] ] ) {
1209					out.push( a[ order[i] ][ prop ] );
1210				}
1211			}
1212		}
1213	
1214		return out;
1215	};
1216	
1217	
1218	var _range = function ( len, start )
1219	{
1220		var out = [];
1221		var end;
1222	
1223		if ( start === undefined ) {
1224			start = 0;
1225			end = len;
1226		}
1227		else {
1228			end = start;
1229			start = len;
1230		}
1231	
1232		for ( var i=start ; i<end ; i++ ) {
1233			out.push( i );
1234		}
1235	
1236		return out;
1237	};
1238	
1239	
1240	var _removeEmpty = function ( a )
1241	{
1242		var out = [];
1243	
1244		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1245			if ( a[i] ) { // careful - will remove all falsy values!
1246				out.push( a[i] );
1247			}
1248		}
1249	
1250		return out;
1251	};
1252	
1253	// Replaceable function in api.util
1254	var _stripHtml = function (input) {
1255		if (! input || typeof input !== 'string') {
1256			return input;
1257		}
1258	
1259		// Irrelevant check to workaround CodeQL's false positive on the regex
1260		if (input.length > _max_str_len) {
1261			throw new Error('Exceeded max str len');
1262		}
1263	
1264		var previous;
1265	
1266		input = input.replace(_re_html, ''); // Complete tags
1267	
1268		// Safety for incomplete script tag - use do / while to ensure that
1269		// we get all instances
1270		do {
1271			previous = input;
1272			input = input.replace(/<script/i, '');
1273		} while (input !== previous);
1274	
1275		return previous;
1276	};
1277	
1278	// Replaceable function in api.util
1279	var _escapeHtml = function ( d ) {
1280		if (Array.isArray(d)) {
1281			d = d.join(',');
1282		}
1283	
1284		return typeof d === 'string' ?
1285			d
1286				.replace(/&/g, '&amp;')
1287				.replace(/</g, '&lt;')
1288				.replace(/>/g, '&gt;')
1289				.replace(/"/g, '&quot;') :
1290			d;
1291	};
1292	
1293	// Remove diacritics from a string by decomposing it and then removing
1294	// non-ascii characters
1295	var _normalize = function (str, both) {
1296		if (typeof str !== 'string') {
1297			return str;
1298		}
1299	
1300		// It is faster to just run `normalize` than it is to check if
1301		// we need to with a regex! (Check as it isn't available in old
1302		// Safari)
1303		var res = str.normalize
1304			? str.normalize("NFD")
1305			: str;
1306	
1307		// Equally, here we check if a regex is needed or not
1308		return res.length !== str.length
1309			? (both === true ? str + ' ' : '' ) + res.replace(/[\u0300-\u036f]/g, "")
1310			: res;
1311	}
1312	
1313	/**
1314	 * Determine if all values in the array are unique. This means we can short
1315	 * cut the _unique method at the cost of a single loop. A sorted array is used
1316	 * to easily check the values.
1317	 *
1318	 * @param  {array} src Source array
1319	 * @return {boolean} true if all unique, false otherwise
1320	 * @ignore
1321	 */
1322	var _areAllUnique = function ( src ) {
1323		if ( src.length < 2 ) {
1324			return true;
1325		}
1326	
1327		var sorted = src.slice().sort();
1328		var last = sorted[0];
1329	
1330		for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1331			if ( sorted[i] === last ) {
1332				return false;
1333			}
1334	
1335			last = sorted[i];
1336		}
1337	
1338		return true;
1339	};
1340	
1341	
1342	/**
1343	 * Find the unique elements in a source array.
1344	 *
1345	 * @param  {array} src Source array
1346	 * @return {array} Array of unique items
1347	 * @ignore
1348	 */
1349	var _unique = function ( src )
1350	{
1351		if (Array.from && Set) {
1352			return Array.from(new Set(src));
1353		}
1354	
1355		if ( _areAllUnique( src ) ) {
1356			return src.slice();
1357		}
1358	
1359		// A faster unique method is to use object keys to identify used values,
1360		// but this doesn't work with arrays or objects, which we must also
1361		// consider. See jsperf.app/compare-array-unique-versions/4 for more
1362		// information.
1363		var
1364			out = [],
1365			val,
1366			i, ien=src.length,
1367			j, k=0;
1368	
1369		again: for ( i=0 ; i<ien ; i++ ) {
1370			val = src[i];
1371	
1372			for ( j=0 ; j<k ; j++ ) {
1373				if ( out[j] === val ) {
1374					continue again;
1375				}
1376			}
1377	
1378			out.push( val );
1379			k++;
1380		}
1381	
1382		return out;
1383	};
1384	
1385	// Surprisingly this is faster than [].concat.apply
1386	// https://jsperf.com/flatten-an-array-loop-vs-reduce/2
1387	var _flatten = function (out, val) {
1388		if (Array.isArray(val)) {
1389			for (var i=0 ; i<val.length ; i++) {
1390				_flatten(out, val[i]);
1391			}
1392		}
1393		else {
1394			out.push(val);
1395		}
1396	
1397		return out;
1398	}
1399	
1400	// Similar to jQuery's addClass, but use classList.add
1401	function _addClass(el, name) {
1402		if (name) {
1403			name.split(' ').forEach(function (n) {
1404				if (n) {
1405					// `add` does deduplication, so no need to check `contains`
1406					el.classList.add(n);
1407				}
1408			});
1409		}
1410	}
1411	
1412	/**
1413	 * DataTables utility methods
1414	 * 
1415	 * This namespace provides helper methods that DataTables uses internally to
1416	 * create a DataTable, but which are not exclusively used only for DataTables.
1417	 * These methods can be used by extension authors to save the duplication of
1418	 * code.
1419	 *
1420	 *  @namespace
1421	 */
1422	DataTable.util = {
1423		/**
1424		 * Return a string with diacritic characters decomposed
1425		 * @param {*} mixed Function or string to normalize
1426		 * @param {*} both Return original string and the normalized string
1427		 * @returns String or undefined
1428		 */
1429		diacritics: function (mixed, both) {
1430			var type = typeof mixed;
1431	
1432			if (type !== 'function') {
1433				return _normalize(mixed, both);
1434			}
1435			_normalize = mixed;
1436		},
1437	
1438		/**
1439		 * Debounce a function
1440		 *
1441		 * @param {function} fn Function to be called
1442		 * @param {integer} freq Call frequency in mS
1443		 * @return {function} Wrapped function
1444		 */
1445		debounce: function ( fn, timeout ) {
1446			var timer;
1447	
1448			return function () {
1449				var that = this;
1450				var args = arguments;
1451	
1452				clearTimeout(timer);
1453	
1454				timer = setTimeout( function () {
1455					fn.apply(that, args);
1456				}, timeout || 250 );
1457			};
1458		},
1459	
1460		/**
1461		 * Throttle the calls to a function. Arguments and context are maintained
1462		 * for the throttled function.
1463		 *
1464		 * @param {function} fn Function to be called
1465		 * @param {integer} freq Call frequency in mS
1466		 * @return {function} Wrapped function
1467		 */
1468		throttle: function ( fn, freq ) {
1469			var
1470				frequency = freq !== undefined ? freq : 200,
1471				last,
1472				timer;
1473	
1474			return function () {
1475				var
1476					that = this,
1477					now  = +new Date(),
1478					args = arguments;
1479	
1480				if ( last && now < last + frequency ) {
1481					clearTimeout( timer );
1482	
1483					timer = setTimeout( function () {
1484						last = undefined;
1485						fn.apply( that, args );
1486					}, frequency );
1487				}
1488				else {
1489					last = now;
1490					fn.apply( that, args );
1491				}
1492			};
1493		},
1494	
1495		/**
1496		 * Escape a string such that it can be used in a regular expression
1497		 *
1498		 *  @param {string} val string to escape
1499		 *  @returns {string} escaped string
1500		 */
1501		escapeRegex: function ( val ) {
1502			return val.replace( _re_escape_regex, '\\$1' );
1503		},
1504	
1505		/**
1506		 * Create a function that will write to a nested object or array
1507		 * @param {*} source JSON notation string
1508		 * @returns Write function
1509		 */
1510		set: function ( source ) {
1511			if ( $.isPlainObject( source ) ) {
1512				/* Unlike get, only the underscore (global) option is used for for
1513				 * setting data since we don't know the type here. This is why an object
1514				 * option is not documented for `mData` (which is read/write), but it is
1515				 * for `mRender` which is read only.
1516				 */
1517				return DataTable.util.set( source._ );
1518			}
1519			else if ( source === null ) {
1520				// Nothing to do when the data source is null
1521				return function () {};
1522			}
1523			else if ( typeof source === 'function' ) {
1524				return function (data, val, meta) {
1525					source( data, 'set', val, meta );
1526				};
1527			}
1528			else if (
1529				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1530				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1531			) {
1532				// Like the get, we need to get data from a nested object
1533				var setData = function (data, val, src) {
1534					var a = _fnSplitObjNotation( src ), b;
1535					var aLast = a[a.length-1];
1536					var arrayNotation, funcNotation, o, innerSrc;
1537		
1538					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {
1539						// Protect against prototype pollution
1540						if (a[i] === '__proto__' || a[i] === 'constructor') {
1541							throw new Error('Cannot set prototype values');
1542						}
1543		
1544						// Check if we are dealing with an array notation request
1545						arrayNotation = a[i].match(__reArray);
1546						funcNotation = a[i].match(__reFn);
1547		
1548						if ( arrayNotation ) {
1549							a[i] = a[i].replace(__reArray, '');
1550							data[ a[i] ] = [];
1551		
1552							// Get the remainder of the nested object to set so we can recurse
1553							b = a.slice();
1554							b.splice( 0, i+1 );
1555							innerSrc = b.join('.');
1556		
1557							// Traverse each entry in the array setting the properties requested
1558							if ( Array.isArray( val ) ) {
1559								for ( var j=0, jLen=val.length ; j<jLen ; j++ ) {
1560									o = {};
1561									setData( o, val[j], innerSrc );
1562									data[ a[i] ].push( o );
1563								}
1564							}
1565							else {
1566								// We've been asked to save data to an array, but it
1567								// isn't array data to be saved. Best that can be done
1568								// is to just save the value.
1569								data[ a[i] ] = val;
1570							}
1571		
1572							// The inner call to setData has already traversed through the remainder
1573							// of the source and has set the data, thus we can exit here
1574							return;
1575						}
1576						else if ( funcNotation ) {
1577							// Function call
1578							a[i] = a[i].replace(__reFn, '');
1579							data = data[ a[i] ]( val );
1580						}
1581		
1582						// If the nested object doesn't currently exist - since we are
1583						// trying to set the value - create it
1584						if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {
1585							data[ a[i] ] = {};
1586						}
1587						data = data[ a[i] ];
1588					}
1589		
1590					// Last item in the input - i.e, the actual set
1591					if ( aLast.match(__reFn ) ) {
1592						// Function call
1593						data = data[ aLast.replace(__reFn, '') ]( val );
1594					}
1595					else {
1596						// If array notation is used, we just want to strip it and use the property name
1597						// and assign the value. If it isn't used, then we get the result we want anyway
1598						data[ aLast.replace(__reArray, '') ] = val;
1599					}
1600				};
1601		
1602				return function (data, val) { // meta is also passed in, but not used
1603					return setData( data, val, source );
1604				};
1605			}
1606			else {
1607				// Array or flat object mapping
1608				return function (data, val) { // meta is also passed in, but not used
1609					data[source] = val;
1610				};
1611			}
1612		},
1613	
1614		/**
1615		 * Create a function that will read nested objects from arrays, based on JSON notation
1616		 * @param {*} source JSON notation string
1617		 * @returns Value read
1618		 */
1619		get: function ( source ) {
1620			if ( $.isPlainObject( source ) ) {
1621				// Build an object of get functions, and wrap them in a single call
1622				var o = {};
1623				$.each( source, function (key, val) {
1624					if ( val ) {
1625						o[key] = DataTable.util.get( val );
1626					}
1627				} );
1628		
1629				return function (data, type, row, meta) {
1630					var t = o[type] || o._;
1631					return t !== undefined ?
1632						t(data, type, row, meta) :
1633						data;
1634				};
1635			}
1636			else if ( source === null ) {
1637				// Give an empty string for rendering / sorting etc
1638				return function (data) { // type, row and meta also passed, but not used
1639					return data;
1640				};
1641			}
1642			else if ( typeof source === 'function' ) {
1643				return function (data, type, row, meta) {
1644					return source( data, type, row, meta );
1645				};
1646			}
1647			else if (
1648				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1649				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1650			) {
1651				/* If there is a . in the source string then the data source is in a
1652				 * nested object so we loop over the data for each level to get the next
1653				 * level down. On each loop we test for undefined, and if found immediately
1654				 * return. This allows entire objects to be missing and sDefaultContent to
1655				 * be used if defined, rather than throwing an error
1656				 */
1657				var fetchData = function (data, type, src) {
1658					var arrayNotation, funcNotation, out, innerSrc;
1659		
1660					if ( src !== "" ) {
1661						var a = _fnSplitObjNotation( src );
1662		
1663						for ( var i=0, iLen=a.length ; i<iLen ; i++ ) {
1664							// Check if we are dealing with special notation
1665							arrayNotation = a[i].match(__reArray);
1666							funcNotation = a[i].match(__reFn);
1667		
1668							if ( arrayNotation ) {
1669								// Array notation
1670								a[i] = a[i].replace(__reArray, '');
1671		
1672								// Condition allows simply [] to be passed in
1673								if ( a[i] !== "" ) {
1674									data = data[ a[i] ];
1675								}
1676								out = [];
1677		
1678								// Get the remainder of the nested object to get
1679								a.splice( 0, i+1 );
1680								innerSrc = a.join('.');
1681		
1682								// Traverse each entry in the array getting the properties requested
1683								if ( Array.isArray( data ) ) {
1684									for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1685										out.push( fetchData( data[j], type, innerSrc ) );
1686									}
1687								}
1688		
1689								// If a string is given in between the array notation indicators, that
1690								// is used to join the strings together, otherwise an array is returned
1691								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1692								data = (join==="") ? out : out.join(join);
1693		
1694								// The inner call to fetchData has already traversed through the remainder
1695								// of the source requested, so we exit from the loop
1696								break;
1697							}
1698							else if ( funcNotation ) {
1699								// Function call
1700								a[i] = a[i].replace(__reFn, '');
1701								data = data[ a[i] ]();
1702								continue;
1703							}
1704		
1705							if (data === null || data[ a[i] ] === null) {
1706								return null;
1707							}
1708							else if ( data === undefined || data[ a[i] ] === undefined ) {
1709								return undefined;
1710							}
1711	
1712							data = data[ a[i] ];
1713						}
1714					}
1715		
1716					return data;
1717				};
1718		
1719				return function (data, type) { // row and meta also passed, but not used
1720					return fetchData( data, type, source );
1721				};
1722			}
1723			else {
1724				// Array or flat object mapping
1725				return function (data) { // row and meta also passed, but not used
1726					return data[source];
1727				};
1728			}
1729		},
1730	
1731		stripHtml: function (mixed) {
1732			var type = typeof mixed;
1733	
1734			if (type === 'function') {
1735				_stripHtml = mixed;
1736				return;
1737			}
1738			else if (type === 'string') {
1739				return _stripHtml(mixed);
1740			}
1741			return mixed;
1742		},
1743	
1744		escapeHtml: function (mixed) {
1745			var type = typeof mixed;
1746	
1747			if (type === 'function') {
1748				_escapeHtml = mixed;
1749				return;
1750			}
1751			else if (type === 'string' || Array.isArray(mixed)) {
1752				return _escapeHtml(mixed);
1753			}
1754			return mixed;
1755		},
1756	
1757		unique: _unique
1758	};
1759	
1760	
1761	
1762	/**
1763	 * Create a mapping object that allows camel case parameters to be looked up
1764	 * for their Hungarian counterparts. The mapping is stored in a private
1765	 * parameter called `_hungarianMap` which can be accessed on the source object.
1766	 *  @param {object} o
1767	 *  @memberof DataTable#oApi
1768	 */
1769	function _fnHungarianMap ( o )
1770	{
1771		var
1772			hungarian = 'a aa ai ao as b fn i m o s ',
1773			match,
1774			newKey,
1775			map = {};
1776	
1777		$.each( o, function (key) {
1778			match = key.match(/^([^A-Z]+?)([A-Z])/);
1779	
1780			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1781			{
1782				newKey = key.replace( match[0], match[2].toLowerCase() );
1783				map[ newKey ] = key;
1784	
1785				if ( match[1] === 'o' )
1786				{
1787					_fnHungarianMap( o[key] );
1788				}
1789			}
1790		} );
1791	
1792		o._hungarianMap = map;
1793	}
1794	
1795	
1796	/**
1797	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1798	 * created by _fnHungarianMap.
1799	 *  @param {object} src The model object which holds all parameters that can be
1800	 *    mapped.
1801	 *  @param {object} user The object to convert from camel case to Hungarian.
1802	 *  @param {boolean} force When set to `true`, properties which already have a
1803	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
1804	 *    won't be.
1805	 *  @memberof DataTable#oApi
1806	 */
1807	function _fnCamelToHungarian ( src, user, force )
1808	{
1809		if ( ! src._hungarianMap ) {
1810			_fnHungarianMap( src );
1811		}
1812	
1813		var hungarianKey;
1814	
1815		$.each( user, function (key) {
1816			hungarianKey = src._hungarianMap[ key ];
1817	
1818			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1819			{
1820				// For objects, we need to buzz down into the object to copy parameters
1821				if ( hungarianKey.charAt(0) === 'o' )
1822				{
1823					// Copy the camelCase options over to the hungarian
1824					if ( ! user[ hungarianKey ] ) {
1825						user[ hungarianKey ] = {};
1826					}
1827					$.extend( true, user[hungarianKey], user[key] );
1828	
1829					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1830				}
1831				else {
1832					user[hungarianKey] = user[ key ];
1833				}
1834			}
1835		} );
1836	}
1837	
1838	/**
1839	 * Map one parameter onto another
1840	 *  @param {object} o Object to map
1841	 *  @param {*} knew The new parameter name
1842	 *  @param {*} old The old parameter name
1843	 */
1844	var _fnCompatMap = function ( o, knew, old ) {
1845		if ( o[ knew ] !== undefined ) {
1846			o[ old ] = o[ knew ];
1847		}
1848	};
1849	
1850	
1851	/**
1852	 * Provide backwards compatibility for the main DT options. Note that the new
1853	 * options are mapped onto the old parameters, so this is an external interface
1854	 * change only.
1855	 *  @param {object} init Object to map
1856	 */
1857	function _fnCompatOpts ( init )
1858	{
1859		_fnCompatMap( init, 'ordering',      'bSort' );
1860		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
1861		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
1862		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1863		_fnCompatMap( init, 'order',         'aaSorting' );
1864		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
1865		_fnCompatMap( init, 'paging',        'bPaginate' );
1866		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
1867		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
1868		_fnCompatMap( init, 'searching',     'bFilter' );
1869	
1870		// Boolean initialisation of x-scrolling
1871		if ( typeof init.sScrollX === 'boolean' ) {
1872			init.sScrollX = init.sScrollX ? '100%' : '';
1873		}
1874		if ( typeof init.scrollX === 'boolean' ) {
1875			init.scrollX = init.scrollX ? '100%' : '';
1876		}
1877	
1878		// Column search objects are in an array, so it needs to be converted
1879		// element by element
1880		var searchCols = init.aoSearchCols;
1881	
1882		if ( searchCols ) {
1883			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1884				if ( searchCols[i] ) {
1885					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1886				}
1887			}
1888		}
1889	
1890		// Enable search delay if server-side processing is enabled
1891		if (init.serverSide && ! init.searchDelay) {
1892			init.searchDelay = 400;
1893		}
1894	}
1895	
1896	
1897	/**
1898	 * Provide backwards compatibility for column options. Note that the new options
1899	 * are mapped onto the old parameters, so this is an external interface change
1900	 * only.
1901	 *  @param {object} init Object to map
1902	 */
1903	function _fnCompatCols ( init )
1904	{
1905		_fnCompatMap( init, 'orderable',     'bSortable' );
1906		_fnCompatMap( init, 'orderData',     'aDataSort' );
1907		_fnCompatMap( init, 'orderSequence', 'asSorting' );
1908		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
1909	
1910		// orderData can be given as an integer
1911		var dataSort = init.aDataSort;
1912		if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {
1913			init.aDataSort = [ dataSort ];
1914		}
1915	}
1916	
1917	
1918	/**
1919	 * Browser feature detection for capabilities, quirks
1920	 *  @param {object} settings dataTables settings object
1921	 *  @memberof DataTable#oApi
1922	 */
1923	function _fnBrowserDetect( settings )
1924	{
1925		// We don't need to do this every time DataTables is constructed, the values
1926		// calculated are specific to the browser and OS configuration which we
1927		// don't expect to change between initialisations
1928		if ( ! DataTable.__browser ) {
1929			var browser = {};
1930			DataTable.__browser = browser;
1931	
1932			// Scrolling feature / quirks detection
1933			var n = $('<div/>')
1934				.css( {
1935					position: 'fixed',
1936					top: 0,
1937					left: -1 * window.pageXOffset, // allow for scrolling
1938					height: 1,
1939					width: 1,
1940					overflow: 'hidden'
1941				} )
1942				.append(
1943					$('<div/>')
1944						.css( {
1945							position: 'absolute',
1946							top: 1,
1947							left: 1,
1948							width: 100,
1949							overflow: 'scroll'
1950						} )
1951						.append(
1952							$('<div/>')
1953								.css( {
1954									width: '100%',
1955									height: 10
1956								} )
1957						)
1958				)
1959				.appendTo( 'body' );
1960	
1961			var outer = n.children();
1962			var inner = outer.children();
1963	
1964			// Get scrollbar width
1965			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1966	
1967			// In rtl text layout, some browsers (most, but not all) will place the
1968			// scrollbar on the left, rather than the right.
1969			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1970	
1971			n.remove();
1972		}
1973	
1974		$.extend( settings.oBrowser, DataTable.__browser );
1975		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1976	}
1977	
1978	/**
1979	 * Add a column to the list used for the table with default values
1980	 *  @param {object} oSettings dataTables settings object
1981	 *  @memberof DataTable#oApi
1982	 */
1983	function _fnAddColumn( oSettings )
1984	{
1985		// Add column to aoColumns array
1986		var oDefaults = DataTable.defaults.column;
1987		var iCol = oSettings.aoColumns.length;
1988		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
1989			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1990			"mData": oDefaults.mData ? oDefaults.mData : iCol,
1991			idx: iCol,
1992			searchFixed: {},
1993			colEl: $('<col>').attr('data-dt-column', iCol)
1994		} );
1995		oSettings.aoColumns.push( oCol );
1996	
1997		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
1998		// passed into extend can be undefined. This allows the user to give a default
1999		// with only some of the parameters defined, and also not give a default
2000		var searchCols = oSettings.aoPreSearchCols;
2001		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
2002	}
2003	
2004	
2005	/**
2006	 * Apply options for a column
2007	 *  @param {object} oSettings dataTables settings object
2008	 *  @param {int} iCol column index to consider
2009	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
2010	 *  @memberof DataTable#oApi
2011	 */
2012	function _fnColumnOptions( oSettings, iCol, oOptions )
2013	{
2014		var oCol = oSettings.aoColumns[ iCol ];
2015	
2016		/* User specified column options */
2017		if ( oOptions !== undefined && oOptions !== null )
2018		{
2019			// Backwards compatibility
2020			_fnCompatCols( oOptions );
2021	
2022			// Map camel case parameters to their Hungarian counterparts
2023			_fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
2024	
2025			/* Backwards compatibility for mDataProp */
2026			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2027			{
2028				oOptions.mData = oOptions.mDataProp;
2029			}
2030	
2031			if ( oOptions.sType )
2032			{
2033				oCol._sManualType = oOptions.sType;
2034			}
2035		
2036			// `class` is a reserved word in Javascript, so we need to provide
2037			// the ability to use a valid name for the camel case input
2038			if ( oOptions.className && ! oOptions.sClass )
2039			{
2040				oOptions.sClass = oOptions.className;
2041			}
2042	
2043			var origClass = oCol.sClass;
2044	
2045			$.extend( oCol, oOptions );
2046			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2047	
2048			// Merge class from previously defined classes with this one, rather than just
2049			// overwriting it in the extend above
2050			if (origClass !== oCol.sClass) {
2051				oCol.sClass = origClass + ' ' + oCol.sClass;
2052			}
2053	
2054			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
2055			 * priority if defined
2056			 */
2057			if ( oOptions.iDataSort !== undefined )
2058			{
2059				oCol.aDataSort = [ oOptions.iDataSort ];
2060			}
2061			_fnMap( oCol, oOptions, "aDataSort" );
2062		}
2063	
2064		/* Cache the data get and set functions for speed */
2065		var mDataSrc = oCol.mData;
2066		var mData = _fnGetObjectDataFn( mDataSrc );
2067	
2068		// The `render` option can be given as an array to access the helper rendering methods.
2069		// The first element is the rendering method to use, the rest are the parameters to pass
2070		if ( oCol.mRender && Array.isArray( oCol.mRender ) ) {
2071			var copy = oCol.mRender.slice();
2072			var name = copy.shift();
2073	
2074			oCol.mRender = DataTable.render[name].apply(window, copy);
2075		}
2076	
2077		oCol._render = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2078	
2079		var attrTest = function( src ) {
2080			return typeof src === 'string' && src.indexOf('@') !== -1;
2081		};
2082		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2083			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2084		);
2085		oCol._setter = null;
2086	
2087		oCol.fnGetData = function (rowData, type, meta) {
2088			var innerData = mData( rowData, type, undefined, meta );
2089	
2090			return oCol._render && type ?
2091				oCol._render( innerData, type, rowData, meta ) :
2092				innerData;
2093		};
2094		oCol.fnSetData = function ( rowData, val, meta ) {
2095			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2096		};
2097	
2098		// Indicate if DataTables should read DOM data as an object or array
2099		// Used in _fnGetRowElements
2100		if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) {
2101			oSettings._rowReadObject = true;
2102		}
2103	
2104		/* Feature sorting overrides column specific when off */
2105		if ( !oSettings.oFeatures.bSort )
2106		{
2107			oCol.bSortable = false;
2108		}
2109	}
2110	
2111	
2112	/**
2113	 * Adjust the table column widths for new data. Note: you would probably want to
2114	 * do a redraw after calling this function!
2115	 *  @param {object} settings dataTables settings object
2116	 *  @memberof DataTable#oApi
2117	 */
2118	function _fnAdjustColumnSizing ( settings )
2119	{
2120		_fnCalculateColumnWidths( settings );
2121		_fnColumnSizes( settings );
2122	
2123		var scroll = settings.oScroll;
2124		if ( scroll.sY !== '' || scroll.sX !== '') {
2125			_fnScrollDraw( settings );
2126		}
2127	
2128		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
2129	}
2130	
2131	/**
2132	 * Apply column sizes
2133	 *
2134	 * @param {*} settings DataTables settings object
2135	 */
2136	function _fnColumnSizes ( settings )
2137	{
2138		var cols = settings.aoColumns;
2139	
2140		for (var i=0 ; i<cols.length ; i++) {
2141			var width = _fnColumnsSumWidth(settings, [i], false, false);
2142	
2143			cols[i].colEl.css('width', width);
2144	
2145			if (settings.oScroll.sX) {
2146				cols[i].colEl.css('min-width', width);
2147			}
2148		}
2149	}
2150	
2151	
2152	/**
2153	 * Convert the index of a visible column to the index in the data array (take account
2154	 * of hidden columns)
2155	 *  @param {object} oSettings dataTables settings object
2156	 *  @param {int} iMatch Visible column index to lookup
2157	 *  @returns {int} i the data index
2158	 *  @memberof DataTable#oApi
2159	 */
2160	function _fnVisibleToColumnIndex( oSettings, iMatch )
2161	{
2162		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2163	
2164		return typeof aiVis[iMatch] === 'number' ?
2165			aiVis[iMatch] :
2166			null;
2167	}
2168	
2169	
2170	/**
2171	 * Convert the index of an index in the data array and convert it to the visible
2172	 *   column index (take account of hidden columns)
2173	 *  @param {int} iMatch Column index to lookup
2174	 *  @param {object} oSettings dataTables settings object
2175	 *  @returns {int} i the data index
2176	 *  @memberof DataTable#oApi
2177	 */
2178	function _fnColumnIndexToVisible( oSettings, iMatch )
2179	{
2180		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2181		var iPos = aiVis.indexOf(iMatch);
2182	
2183		return iPos !== -1 ? iPos : null;
2184	}
2185	
2186	
2187	/**
2188	 * Get the number of visible columns
2189	 *  @param {object} oSettings dataTables settings object
2190	 *  @returns {int} i the number of visible columns
2191	 *  @memberof DataTable#oApi
2192	 */
2193	function _fnVisbleColumns( settings )
2194	{
2195		var layout = settings.aoHeader;
2196		var columns = settings.aoColumns;
2197		var vis = 0;
2198	
2199		if ( layout.length ) {
2200			for ( var i=0, ien=layout[0].length ; i<ien ; i++ ) {
2201				if ( columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none' ) {
2202					vis++;
2203				}
2204			}
2205		}
2206	
2207		return vis;
2208	}
2209	
2210	
2211	/**
2212	 * Get an array of column indexes that match a given property
2213	 *  @param {object} oSettings dataTables settings object
2214	 *  @param {string} sParam Parameter in aoColumns to look for - typically
2215	 *    bVisible or bSearchable
2216	 *  @returns {array} Array of indexes with matched properties
2217	 *  @memberof DataTable#oApi
2218	 */
2219	function _fnGetColumns( oSettings, sParam )
2220	{
2221		var a = [];
2222	
2223		oSettings.aoColumns.map( function(val, i) {
2224			if ( val[sParam] ) {
2225				a.push( i );
2226			}
2227		} );
2228	
2229		return a;
2230	}
2231	
2232	/**
2233	 * Allow the result from a type detection function to be `true` while
2234	 * translating that into a string. Old type detection functions will
2235	 * return the type name if it passes. An obect store would be better,
2236	 * but not backwards compatible.
2237	 *
2238	 * @param {*} typeDetect Object or function for type detection
2239	 * @param {*} res Result from the type detection function
2240	 * @returns Type name or false
2241	 */
2242	function _typeResult (typeDetect, res) {
2243		return res === true
2244			? typeDetect._name
2245			: res;
2246	}
2247	
2248	/**
2249	 * Calculate the 'type' of a column
2250	 *  @param {object} settings dataTables settings object
2251	 *  @memberof DataTable#oApi
2252	 */
2253	function _fnColumnTypes ( settings )
2254	{
2255		var columns = settings.aoColumns;
2256		var data = settings.aoData;
2257		var types = DataTable.ext.type.detect;
2258		var i, ien, j, jen, k, ken;
2259		var col, detectedType, cache;
2260	
2261		// For each column, spin over the data type detection functions, seeing if one matches
2262		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2263			col = columns[i];
2264			cache = [];
2265	
2266			if ( ! col.sType && col._sManualType ) {
2267				col.sType = col._sManualType;
2268			}
2269			else if ( ! col.sType ) {
2270				// With SSP type detection can be unreliable and error prone, so we provide a way
2271				// to turn it off.
2272				if (! settings.typeDetect) {
2273					return;
2274				}
2275	
2276				for ( j=0, jen=types.length ; j<jen ; j++ ) {
2277					var typeDetect = types[j];
2278	
2279					// There can be either one, or three type detection functions
2280					var oneOf = typeDetect.oneOf;
2281					var allOf = typeDetect.allOf || typeDetect;
2282					var init = typeDetect.init;
2283					var one = false;
2284	
2285					detectedType = null;
2286	
2287					// Fast detect based on column assignment
2288					if (init) {
2289						detectedType = _typeResult(typeDetect, init(settings, col, i));
2290	
2291						if (detectedType) {
2292							col.sType = detectedType;
2293							break;
2294						}
2295					}
2296	
2297					for ( k=0, ken=data.length ; k<ken ; k++ ) {
2298						if (! data[k]) {
2299							continue;
2300						}
2301	
2302						// Use a cache array so we only need to get the type data
2303						// from the formatter once (when using multiple detectors)
2304						if ( cache[k] === undefined ) {
2305							cache[k] = _fnGetCellData( settings, k, i, 'type' );
2306						}
2307	
2308						// Only one data point in the column needs to match this function
2309						if (oneOf && ! one) {
2310							one = _typeResult(typeDetect, oneOf( cache[k], settings ));
2311						}
2312	
2313						// All data points need to match this function
2314						detectedType = _typeResult(typeDetect, allOf( cache[k], settings ));
2315	
2316						// If null, then this type can't apply to this column, so
2317						// rather than testing all cells, break out. There is an
2318						// exception for the last type which is `html`. We need to
2319						// scan all rows since it is possible to mix string and HTML
2320						// types
2321						if ( ! detectedType && j !== types.length-3 ) {
2322							break;
2323						}
2324	
2325						// Only a single match is needed for html type since it is
2326						// bottom of the pile and very similar to string - but it
2327						// must not be empty
2328						if ( detectedType === 'html' && ! _empty(cache[k]) ) {
2329							break;
2330						}
2331					}
2332	
2333					// Type is valid for all data points in the column - use this
2334					// type
2335					if ( (oneOf && one && detectedType) || (!oneOf && detectedType) ) {
2336						col.sType = detectedType;
2337						break;
2338					}
2339				}
2340	
2341				// Fall back - if no type was detected, always use string
2342				if ( ! col.sType ) {
2343					col.sType = 'string';
2344				}
2345			}
2346	
2347			// Set class names for header / footer for auto type classes
2348			var autoClass = _ext.type.className[col.sType];
2349	
2350			if (autoClass) {
2351				_columnAutoClass(settings.aoHeader, i, autoClass);
2352				_columnAutoClass(settings.aoFooter, i, autoClass);
2353			}
2354	
2355			var renderer = _ext.type.render[col.sType];
2356	
2357			// This can only happen once! There is no way to remove
2358			// a renderer. After the first time the renderer has
2359			// already been set so createTr will run the renderer itself.
2360			if (renderer && ! col._render) {
2361				col._render = DataTable.util.get(renderer);
2362	
2363				_columnAutoRender(settings, i);
2364			}
2365		}
2366	}
2367	
2368	/**
2369	 * Apply an auto detected renderer to data which doesn't yet have
2370	 * a renderer
2371	 */
2372	function _columnAutoRender(settings, colIdx) {
2373		var data = settings.aoData;
2374	
2375		for (var i=0 ; i<data.length ; i++) {
2376			if (data[i].nTr) {
2377				// We have to update the display here since there is no
2378				// invalidation check for the data
2379				var display = _fnGetCellData( settings, i, colIdx, 'display' );
2380	
2381				data[i].displayData[colIdx] = display;
2382				_fnWriteCell(data[i].anCells[colIdx], display);
2383	
2384				// No need to update sort / filter data since it has
2385				// been invalidated and will be re-read with the
2386				// renderer now applied
2387			}
2388		}
2389	}
2390	
2391	/**
2392	 * Apply a class name to a column's header cells
2393	 */
2394	function _columnAutoClass(container, colIdx, className) {
2395		container.forEach(function (row) {
2396			if (row[colIdx] && row[colIdx].unique) {
2397				_addClass(row[colIdx].cell, className);
2398			}
2399		});
2400	}
2401	
2402	/**
2403	 * Take the column definitions and static columns arrays and calculate how
2404	 * they relate to column indexes. The callback function will then apply the
2405	 * definition found for a column to a suitable configuration object.
2406	 *  @param {object} oSettings dataTables settings object
2407	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
2408	 *  @param {array} aoCols The aoColumns array that defines columns individually
2409	 *  @param {array} headerLayout Layout for header as it was loaded
2410	 *  @param {function} fn Callback function - takes two parameters, the calculated
2411	 *    column index and the definition for that column.
2412	 *  @memberof DataTable#oApi
2413	 */
2414	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, headerLayout, fn )
2415	{
2416		var i, iLen, j, jLen, k, kLen, def;
2417		var columns = oSettings.aoColumns;
2418	
2419		if ( aoCols ) {
2420			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2421				if (aoCols[i] && aoCols[i].name) {
2422					columns[i].sName = aoCols[i].name;
2423				}
2424			}
2425		}
2426	
2427		// Column definitions with aTargets
2428		if ( aoColDefs )
2429		{
2430			/* Loop over the definitions array - loop in reverse so first instance has priority */
2431			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2432			{
2433				def = aoColDefs[i];
2434	
2435				/* Each definition can target multiple columns, as it is an array */
2436				var aTargets = def.target !== undefined
2437					? def.target
2438					: def.targets !== undefined
2439						? def.targets
2440						: def.aTargets;
2441	
2442				if ( ! Array.isArray( aTargets ) )
2443				{
2444					aTargets = [ aTargets ];
2445				}
2446	
2447				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2448				{
2449					var target = aTargets[j];
2450	
2451					if ( typeof target === 'number' && target >= 0 )
2452					{
2453						/* Add columns that we don't yet know about */
2454						while( columns.length <= target )
2455						{
2456							_fnAddColumn( oSettings );
2457						}
2458	
2459						/* Integer, basic index */
2460						fn( target, def );
2461					}
2462					else if ( typeof target === 'number' && target < 0 )
2463					{
2464						/* Negative integer, right to left column counting */
2465						fn( columns.length+target, def );
2466					}
2467					else if ( typeof target === 'string' )
2468					{
2469						for ( k=0, kLen=columns.length ; k<kLen ; k++ ) {
2470							if (target === '_all') {
2471								// Apply to all columns
2472								fn( k, def );
2473							}
2474							else if (target.indexOf(':name') !== -1) {
2475								// Column selector
2476								if (columns[k].sName === target.replace(':name', '')) {
2477									fn( k, def );
2478								}
2479							}
2480							else {
2481								// Cell selector
2482								headerLayout.forEach(function (row) {
2483									if (row[k]) {
2484										var cell = $(row[k].cell);
2485	
2486										// Legacy support. Note that it means that we don't support
2487										// an element name selector only, since they are treated as
2488										// class names for 1.x compat.
2489										if (target.match(/^[a-z][\w-]*$/i)) {
2490											target = '.' + target;
2491										}
2492	
2493										if (cell.is( target )) {
2494											fn( k, def );
2495										}
2496									}
2497								});
2498							}
2499						}
2500					}
2501				}
2502			}
2503		}
2504	
2505		// Statically defined columns array
2506		if ( aoCols ) {
2507			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2508				fn( i, aoCols[i] );
2509			}
2510		}
2511	}
2512	
2513	
2514	/**
2515	 * Get the width for a given set of columns
2516	 *
2517	 * @param {*} settings DataTables settings object
2518	 * @param {*} targets Columns - comma separated string or array of numbers
2519	 * @param {*} original Use the original width (true) or calculated (false)
2520	 * @param {*} incVisible Include visible columns (true) or not (false)
2521	 * @returns Combined CSS value
2522	 */
2523	function _fnColumnsSumWidth( settings, targets, original, incVisible ) {
2524		if ( ! Array.isArray( targets ) ) {
2525			targets = _fnColumnsFromHeader( targets );
2526		}
2527	
2528		var sum = 0;
2529		var unit;
2530		var columns = settings.aoColumns;
2531		
2532		for ( var i=0, ien=targets.length ; i<ien ; i++ ) {
2533			var column = columns[ targets[i] ];
2534			var definedWidth = original ?
2535				column.sWidthOrig :
2536				column.sWidth;
2537	
2538			if ( ! incVisible && column.bVisible === false ) {
2539				continue;
2540			}
2541	
2542			if ( definedWidth === null || definedWidth === undefined ) {
2543				return null; // can't determine a defined width - browser defined
2544			}
2545			else if ( typeof definedWidth === 'number' ) {
2546				unit = 'px';
2547				sum += definedWidth;
2548			}
2549			else {
2550				var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
2551	
2552				if ( matched ) {
2553					sum += matched[1] * 1;
2554					unit = matched.length === 3 ?
2555						matched[2] :
2556						'px';
2557				}
2558			}
2559		}
2560	
2561		return sum + unit;
2562	}
2563	
2564	function _fnColumnsFromHeader( cell )
2565	{
2566		var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
2567	
2568		if ( ! attr ) {
2569			return [];
2570		}
2571	
2572		return attr.split(',').map( function (val) {
2573			return val * 1;
2574		} );
2575	}
2576	/**
2577	 * Add a data array to the table, creating DOM node etc. This is the parallel to
2578	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2579	 * DOM source.
2580	 *  @param {object} settings dataTables settings object
2581	 *  @param {array} data data array to be added
2582	 *  @param {node} [tr] TR element to add to the table - optional. If not given,
2583	 *    DataTables will create a row automatically
2584	 *  @param {array} [tds] Array of TD|TH elements for the row - must be given
2585	 *    if nTr is.
2586	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2587	 *  @memberof DataTable#oApi
2588	 */
2589	function _fnAddData ( settings, dataIn, tr, tds )
2590	{
2591		/* Create the object for storing information about this new row */
2592		var rowIdx = settings.aoData.length;
2593		var rowModel = $.extend( true, {}, DataTable.models.oRow, {
2594			src: tr ? 'dom' : 'data',
2595			idx: rowIdx
2596		} );
2597	
2598		rowModel._aData = dataIn;
2599		settings.aoData.push( rowModel );
2600	
2601		var columns = settings.aoColumns;
2602	
2603		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2604		{
2605			// Invalidate the column types as the new data needs to be revalidated
2606			columns[i].sType = null;
2607		}
2608	
2609		/* Add to the display array */
2610		settings.aiDisplayMaster.push( rowIdx );
2611	
2612		var id = settings.rowIdFn( dataIn );
2613		if ( id !== undefined ) {
2614			settings.aIds[ id ] = rowModel;
2615		}
2616	
2617		/* Create the DOM information, or register it if already present */
2618		if ( tr || ! settings.oFeatures.bDeferRender )
2619		{
2620			_fnCreateTr( settings, rowIdx, tr, tds );
2621		}
2622	
2623		return rowIdx;
2624	}
2625	
2626	
2627	/**
2628	 * Add one or more TR elements to the table. Generally we'd expect to
2629	 * use this for reading data from a DOM sourced table, but it could be
2630	 * used for an TR element. Note that if a TR is given, it is used (i.e.
2631	 * it is not cloned).
2632	 *  @param {object} settings dataTables settings object
2633	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
2634	 *  @returns {array} Array of indexes for the added rows
2635	 *  @memberof DataTable#oApi
2636	 */
2637	function _fnAddTr( settings, trs )
2638	{
2639		var row;
2640	
2641		// Allow an individual node to be passed in
2642		if ( ! (trs instanceof $) ) {
2643			trs = $(trs);
2644		}
2645	
2646		return trs.map( function (i, el) {
2647			row = _fnGetRowElements( settings, el );
2648			return _fnAddData( settings, row.data, el, row.cells );
2649		} );
2650	}
2651	
2652	
2653	/**
2654	 * Get the data for a given cell from the internal cache, taking into account data mapping
2655	 *  @param {object} settings dataTables settings object
2656	 *  @param {int} rowIdx aoData row id
2657	 *  @param {int} colIdx Column index
2658	 *  @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
2659	 *  @returns {*} Cell data
2660	 *  @memberof DataTable#oApi
2661	 */
2662	function _fnGetCellData( settings, rowIdx, colIdx, type )
2663	{
2664		if (type === 'search') {
2665			type = 'filter';
2666		}
2667		else if (type === 'order') {
2668			type = 'sort';
2669		}
2670	
2671		var row = settings.aoData[rowIdx];
2672	
2673		if (! row) {
2674			return undefined;
2675		}
2676	
2677		var draw           = settings.iDraw;
2678		var col            = settings.aoColumns[colIdx];
2679		var rowData        = row._aData;
2680		var defaultContent = col.sDefaultContent;
2681		var cellData       = col.fnGetData( rowData, type, {
2682			settings: settings,
2683			row:      rowIdx,
2684			col:      colIdx
2685		} );
2686	
2687		// Allow for a node being returned for non-display types
2688		if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
2689			cellData = cellData.innerHTML;
2690		}
2691	
2692		if ( cellData === undefined ) {
2693			if ( settings.iDrawError != draw && defaultContent === null ) {
2694				_fnLog( settings, 0, "Requested unknown parameter "+
2695					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2696					" for row "+rowIdx+", column "+colIdx, 4 );
2697				settings.iDrawError = draw;
2698			}
2699			return defaultContent;
2700		}
2701	
2702		// When the data source is null and a specific data type is requested (i.e.
2703		// not the original data), we can use default column data
2704		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2705			cellData = defaultContent;
2706		}
2707		else if ( typeof cellData === 'function' ) {
2708			// If the data source is a function, then we run it and use the return,
2709			// executing in the scope of the data object (for instances)
2710			return cellData.call( rowData );
2711		}
2712	
2713		if ( cellData === null && type === 'display' ) {
2714			return '';
2715		}
2716	
2717		if ( type === 'filter' ) {
2718			var fomatters = DataTable.ext.type.search;
2719	
2720			if ( fomatters[ col.sType ] ) {
2721				cellData = fomatters[ col.sType ]( cellData );
2722			}
2723		}
2724	
2725		return cellData;
2726	}
2727	
2728	
2729	/**
2730	 * Set the value for a specific cell, into the internal data cache
2731	 *  @param {object} settings dataTables settings object
2732	 *  @param {int} rowIdx aoData row id
2733	 *  @param {int} colIdx Column index
2734	 *  @param {*} val Value to set
2735	 *  @memberof DataTable#oApi
2736	 */
2737	function _fnSetCellData( settings, rowIdx, colIdx, val )
2738	{
2739		var col     = settings.aoColumns[colIdx];
2740		var rowData = settings.aoData[rowIdx]._aData;
2741	
2742		col.fnSetData( rowData, val, {
2743			settings: settings,
2744			row:      rowIdx,
2745			col:      colIdx
2746		}  );
2747	}
2748	
2749	/**
2750	 * Write a value to a cell
2751	 * @param {*} td Cell
2752	 * @param {*} val Value
2753	 */
2754	function _fnWriteCell(td, val)
2755	{
2756		if (val && typeof val === 'object' && val.nodeName) {
2757			$(td)
2758				.empty()
2759				.append(val);
2760		}
2761		else {
2762			td.innerHTML = val;
2763		}
2764	}
2765	
2766	
2767	// Private variable that is used to match action syntax in the data property object
2768	var __reArray = /\[.*?\]$/;
2769	var __reFn = /\(\)$/;
2770	
2771	/**
2772	 * Split string on periods, taking into account escaped periods
2773	 * @param  {string} str String to split
2774	 * @return {array} Split string
2775	 */
2776	function _fnSplitObjNotation( str )
2777	{
2778		var parts = str.match(/(\\.|[^.])+/g) || [''];
2779	
2780		return parts.map( function ( s ) {
2781			return s.replace(/\\\./g, '.');
2782		} );
2783	}
2784	
2785	
2786	/**
2787	 * Return a function that can be used to get data from a source object, taking
2788	 * into account the ability to use nested objects as a source
2789	 *  @param {string|int|function} mSource The data source for the object
2790	 *  @returns {function} Data get function
2791	 *  @memberof DataTable#oApi
2792	 */
2793	var _fnGetObjectDataFn = DataTable.util.get;
2794	
2795	
2796	/**
2797	 * Return a function that can be used to set data from a source object, taking
2798	 * into account the ability to use nested objects as a source
2799	 *  @param {string|int|function} mSource The data source for the object
2800	 *  @returns {function} Data set function
2801	 *  @memberof DataTable#oApi
2802	 */
2803	var _fnSetObjectDataFn = DataTable.util.set;
2804	
2805	
2806	/**
2807	 * Return an array with the full table data
2808	 *  @param {object} oSettings dataTables settings object
2809	 *  @returns array {array} aData Master data array
2810	 *  @memberof DataTable#oApi
2811	 */
2812	function _fnGetDataMaster ( settings )
2813	{
2814		return _pluck( settings.aoData, '_aData' );
2815	}
2816	
2817	
2818	/**
2819	 * Nuke the table
2820	 *  @param {object} oSettings dataTables settings object
2821	 *  @memberof DataTable#oApi
2822	 */
2823	function _fnClearTable( settings )
2824	{
2825		settings.aoData.length = 0;
2826		settings.aiDisplayMaster.length = 0;
2827		settings.aiDisplay.length = 0;
2828		settings.aIds = {};
2829	}
2830	
2831	
2832	/**
2833	 * Mark cached data as invalid such that a re-read of the data will occur when
2834	 * the cached data is next requested. Also update from the data source object.
2835	 *
2836	 * @param {object} settings DataTables settings object
2837	 * @param {int}    rowIdx   Row index to invalidate
2838	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
2839	 *     or 'data'
2840	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
2841	 *     row will be invalidated
2842	 * @memberof DataTable#oApi
2843	 *
2844	 * @todo For the modularisation of v1.11 this will need to become a callback, so
2845	 *   the sort and filter methods can subscribe to it. That will required
2846	 *   initialisation options for sorting, which is why it is not already baked in
2847	 */
2848	function _fnInvalidate( settings, rowIdx, src, colIdx )
2849	{
2850		var row = settings.aoData[ rowIdx ];
2851		var i, ien;
2852	
2853		// Remove the cached data for the row
2854		row._aSortData = null;
2855		row._aFilterData = null;
2856		row.displayData = null;
2857	
2858		// Are we reading last data from DOM or the data object?
2859		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2860			// Read the data from the DOM
2861			row._aData = _fnGetRowElements(
2862					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2863				)
2864				.data;
2865		}
2866		else {
2867			// Reading from data object, update the DOM
2868			var cells = row.anCells;
2869			var display = _fnGetRowDisplay(settings, rowIdx);
2870	
2871			if ( cells ) {
2872				if ( colIdx !== undefined ) {
2873					_fnWriteCell(cells[colIdx], display[colIdx]);
2874				}
2875				else {
2876					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2877						_fnWriteCell(cells[i], display[i]);
2878					}
2879				}
2880			}
2881		}
2882	
2883		// Column specific invalidation
2884		var cols = settings.aoColumns;
2885		if ( colIdx !== undefined ) {
2886			// Type - the data might have changed
2887			cols[ colIdx ].sType = null;
2888	
2889			// Max length string. Its a fairly cheep recalculation, so not worth
2890			// something more complicated
2891			cols[ colIdx ].maxLenString = null;
2892		}
2893		else {
2894			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2895				cols[i].sType = null;
2896				cols[i].maxLenString = null;
2897			}
2898	
2899			// Update DataTables special `DT_*` attributes for the row
2900			_fnRowAttributes( settings, row );
2901		}
2902	}
2903	
2904	
2905	/**
2906	 * Build a data source object from an HTML row, reading the contents of the
2907	 * cells that are in the row.
2908	 *
2909	 * @param {object} settings DataTables settings object
2910	 * @param {node|object} TR element from which to read data or existing row
2911	 *   object from which to re-read the data from the cells
2912	 * @param {int} [colIdx] Optional column index
2913	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2914	 *   parameter should also be given and will be used to write the data into.
2915	 *   Only the column in question will be written
2916	 * @returns {object} Object with two parameters: `data` the data read, in
2917	 *   document order, and `cells` and array of nodes (they can be useful to the
2918	 *   caller, so rather than needing a second traversal to get them, just return
2919	 *   them from here).
2920	 * @memberof DataTable#oApi
2921	 */
2922	function _fnGetRowElements( settings, row, colIdx, d )
2923	{
2924		var
2925			tds = [],
2926			td = row.firstChild,
2927			name, col, i=0, contents,
2928			columns = settings.aoColumns,
2929			objectRead = settings._rowReadObject;
2930	
2931		// Allow the data object to be passed in, or construct
2932		d = d !== undefined ?
2933			d :
2934			objectRead ?
2935				{} :
2936				[];
2937	
2938		var attr = function ( str, td  ) {
2939			if ( typeof str === 'string' ) {
2940				var idx = str.indexOf('@');
2941	
2942				if ( idx !== -1 ) {
2943					var attr = str.substring( idx+1 );
2944					var setter = _fnSetObjectDataFn( str );
2945					setter( d, td.getAttribute( attr ) );
2946				}
2947			}
2948		};
2949	
2950		// Read data from a cell and store into the data object
2951		var cellProcess = function ( cell ) {
2952			if ( colIdx === undefined || colIdx === i ) {
2953				col = columns[i];
2954				contents = (cell.innerHTML).trim();
2955	
2956				if ( col && col._bAttrSrc ) {
2957					var setter = _fnSetObjectDataFn( col.mData._ );
2958					setter( d, contents );
2959	
2960					attr( col.mData.sort, cell );
2961					attr( col.mData.type, cell );
2962					attr( col.mData.filter, cell );
2963				}
2964				else {
2965					// Depending on the `data` option for the columns the data can
2966					// be read to either an object or an array.
2967					if ( objectRead ) {
2968						if ( ! col._setter ) {
2969							// Cache the setter function
2970							col._setter = _fnSetObjectDataFn( col.mData );
2971						}
2972						col._setter( d, contents );
2973					}
2974					else {
2975						d[i] = contents;
2976					}
2977				}
2978			}
2979	
2980			i++;
2981		};
2982	
2983		if ( td ) {
2984			// `tr` element was passed in
2985			while ( td ) {
2986				name = td.nodeName.toUpperCase();
2987	
2988				if ( name == "TD" || name == "TH" ) {
2989					cellProcess( td );
2990					tds.push( td );
2991				}
2992	
2993				td = td.nextSibling;
2994			}
2995		}
2996		else {
2997			// Existing row object passed in
2998			tds = row.anCells;
2999	
3000			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3001				cellProcess( tds[j] );
3002			}
3003		}
3004	
3005		// Read the ID from the DOM if present
3006		var rowNode = row.firstChild ? row : row.nTr;
3007	
3008		if ( rowNode ) {
3009			var id = rowNode.getAttribute( 'id' );
3010	
3011			if ( id ) {
3012				_fnSetObjectDataFn( settings.rowId )( d, id );
3013			}
3014		}
3015	
3016		return {
3017			data: d,
3018			cells: tds
3019		};
3020	}
3021	
3022	/**
3023	 * Render and cache a row's display data for the columns, if required
3024	 * @returns 
3025	 */
3026	function _fnGetRowDisplay (settings, rowIdx) {
3027		var rowModal = settings.aoData[rowIdx];
3028		var columns = settings.aoColumns;
3029	
3030		if (! rowModal.displayData) {
3031			// Need to render and cache
3032			rowModal.displayData = [];
3033		
3034			for ( var colIdx=0, len=columns.length ; colIdx<len ; colIdx++ ) {
3035				rowModal.displayData.push(
3036					_fnGetCellData( settings, rowIdx, colIdx, 'display' )
3037				);
3038			}
3039		}
3040	
3041		return rowModal.displayData;
3042	}
3043	
3044	/**
3045	 * Create a new TR element (and it's TD children) for a row
3046	 *  @param {object} oSettings dataTables settings object
3047	 *  @param {int} iRow Row to consider
3048	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3049	 *    DataTables will create a row automatically
3050	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
3051	 *    if nTr is.
3052	 *  @memberof DataTable#oApi
3053	 */
3054	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3055	{
3056		var
3057			row = oSettings.aoData[iRow],
3058			rowData = row._aData,
3059			cells = [],
3060			nTr, nTd, oCol,
3061			i, iLen, create,
3062			trClass = oSettings.oClasses.tbody.row;
3063	
3064		if ( row.nTr === null )
3065		{
3066			nTr = nTrIn || document.createElement('tr');
3067	
3068			row.nTr = nTr;
3069			row.anCells = cells;
3070	
3071			_addClass(nTr, trClass);
3072	
3073			/* Use a private property on the node to allow reserve mapping from the node
3074			 * to the aoData array for fast look up
3075			 */
3076			nTr._DT_RowIndex = iRow;
3077	
3078			/* Special parameters can be given by the data source to be used on the row */
3079			_fnRowAttributes( oSettings, row );
3080	
3081			/* Process each column */
3082			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3083			{
3084				oCol = oSettings.aoColumns[i];
3085				create = nTrIn && anTds[i] ? false : true;
3086	
3087				nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
3088	
3089				if (! nTd) {
3090					_fnLog( oSettings, 0, 'Incorrect column count', 18 );
3091				}
3092	
3093				nTd._DT_CellIndex = {
3094					row: iRow,
3095					column: i
3096				};
3097				
3098				cells.push( nTd );
3099				
3100				var display = _fnGetRowDisplay(oSettings, iRow);
3101	
3102				// Need to create the HTML if new, or if a rendering function is defined
3103				if (
3104					create ||
3105					(
3106						(oCol.mRender || oCol.mData !== i) &&
3107						(!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3108					)
3109				) {
3110					_fnWriteCell(nTd, display[i]);
3111				}
3112	
3113				// column class
3114				_addClass(nTd, oCol.sClass);
3115	
3116				// Visibility - add or remove as required
3117				if ( oCol.bVisible && create )
3118				{
3119					nTr.appendChild( nTd );
3120				}
3121				else if ( ! oCol.bVisible && ! create )
3122				{
3123					nTd.parentNode.removeChild( nTd );
3124				}
3125	
3126				if ( oCol.fnCreatedCell )
3127				{
3128					oCol.fnCreatedCell.call( oSettings.oInstance,
3129						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3130					);
3131				}
3132			}
3133	
3134			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells] );
3135		}
3136		else {
3137			_addClass(row.nTr, trClass);
3138		}
3139	}
3140	
3141	
3142	/**
3143	 * Add attributes to a row based on the special `DT_*` parameters in a data
3144	 * source object.
3145	 *  @param {object} settings DataTables settings object
3146	 *  @param {object} DataTables row object for the row to be modified
3147	 *  @memberof DataTable#oApi
3148	 */
3149	function _fnRowAttributes( settings, row )
3150	{
3151		var tr = row.nTr;
3152		var data = row._aData;
3153	
3154		if ( tr ) {
3155			var id = settings.rowIdFn( data );
3156	
3157			if ( id ) {
3158				tr.id = id;
3159			}
3160	
3161			if ( data.DT_RowClass ) {
3162				// Remove any classes added by DT_RowClass before
3163				var a = data.DT_RowClass.split(' ');
3164				row.__rowc = row.__rowc ?
3165					_unique( row.__rowc.concat( a ) ) :
3166					a;
3167	
3168				$(tr)
3169					.removeClass( row.__rowc.join(' ') )
3170					.addClass( data.DT_RowClass );
3171			}
3172	
3173			if ( data.DT_RowAttr ) {
3174				$(tr).attr( data.DT_RowAttr );
3175			}
3176	
3177			if ( data.DT_RowData ) {
3178				$(tr).data( data.DT_RowData );
3179			}
3180		}
3181	}
3182	
3183	
3184	/**
3185	 * Create the HTML header for the table
3186	 *  @param {object} oSettings dataTables settings object
3187	 *  @memberof DataTable#oApi
3188	 */
3189	function _fnBuildHead( settings, side )
3190	{
3191		var classes = settings.oClasses;
3192		var columns = settings.aoColumns;
3193		var i, ien, row;
3194		var target = side === 'header'
3195			? settings.nTHead
3196			: settings.nTFoot;
3197		var titleProp = side === 'header' ? 'sTitle' : side;
3198	
3199		// Footer might be defined
3200		if (! target) {
3201			return;
3202		}
3203	
3204		// If no cells yet and we have content for them, then create
3205		if (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) {
3206			row = $('tr', target);
3207	
3208			// Add a row if needed
3209			if (! row.length) {
3210				row = $('<tr/>').appendTo(target)
3211			}
3212	
3213			// Add the number of cells needed to make up to the number of columns
3214			if (row.length === 1) {
3215				var cellCount = 0;
3216				
3217				$('td, th', row).each(function () {
3218					cellCount += this.colSpan;
3219				});
3220	
3221				for ( i=cellCount, ien=columns.length ; i<ien ; i++ ) {
3222					$('<th/>')
3223						.html( columns[i][titleProp] || '' )
3224						.appendTo( row );
3225				}
3226			}
3227		}
3228	
3229		var detected = _fnDetectHeader( settings, target, true );
3230	
3231		if (side === 'header') {
3232			settings.aoHeader = detected;
3233			$('tr', target).addClass(classes.thead.row);
3234		}
3235		else {
3236			settings.aoFooter = detected;
3237			$('tr', target).addClass(classes.tfoot.row);
3238		}
3239	
3240		// Every cell needs to be passed through the renderer
3241		$(target).children('tr').children('th, td')
3242			.each( function () {
3243				_fnRenderer( settings, side )(
3244					settings, $(this), classes
3245				);
3246			} );
3247	}
3248	
3249	/**
3250	 * Build a layout structure for a header or footer
3251	 *
3252	 * @param {*} settings DataTables settings
3253	 * @param {*} source Source layout array
3254	 * @param {*} incColumns What columns should be included
3255	 * @returns Layout array
3256	 */
3257	function _fnHeaderLayout( settings, source, incColumns )
3258	{
3259		var row, column, cell;
3260		var local = [];
3261		var structure = [];
3262		var columns = settings.aoColumns;
3263		var columnCount = columns.length;
3264		var rowspan, colspan;
3265	
3266		if ( ! source ) {
3267			return;
3268		}
3269	
3270		// Default is to work on only visible columns
3271		if ( ! incColumns ) {
3272			incColumns = _range(columnCount)
3273				.filter(function (idx) {
3274					return columns[idx].bVisible;
3275				});
3276		}
3277	
3278		// Make a copy of the master layout array, but with only the columns we want
3279		for ( row=0 ; row<source.length ; row++ ) {
3280			// Remove any columns we haven't selected
3281			local[row] = source[row].slice().filter(function (cell, i) {
3282				return incColumns.includes(i);
3283			});
3284	
3285			// Prep the structure array - it needs an element for each row
3286			structure.push( [] );
3287		}
3288	
3289		for ( row=0 ; row<local.length ; row++ ) {
3290			for ( column=0 ; column<local[row].length ; column++ ) {
3291				rowspan = 1;
3292				colspan = 1;
3293	
3294				// Check to see if there is already a cell (row/colspan) covering our target
3295				// insert point. If there is, then there is nothing to do.
3296				if ( structure[row][column] === undefined ) {
3297					cell = local[row][column].cell;
3298	
3299					// Expand for rowspan
3300					while (
3301						local[row+rowspan] !== undefined &&
3302						local[row][column].cell == local[row+rowspan][column].cell
3303					) {
3304						structure[row+rowspan][column] = null;
3305						rowspan++;
3306					}
3307	
3308					// And for colspan
3309					while (
3310						local[row][column+colspan] !== undefined &&
3311						local[row][column].cell == local[row][column+colspan].cell
3312					) {
3313						// Which also needs to go over rows
3314						for ( var k=0 ; k<rowspan ; k++ ) {
3315							structure[row+k][column+colspan] = null;
3316						}
3317	
3318						colspan++;
3319					}
3320	
3321					var titleSpan = $('span.dt-column-title', cell);
3322	
3323					structure[row][column] = {
3324						cell: cell,
3325						colspan: colspan,
3326						rowspan: rowspan,
3327						title: titleSpan.length
3328							? titleSpan.html()
3329							: $(cell).html()
3330					};
3331				}
3332			}
3333		}
3334	
3335		return structure;
3336	}
3337	
3338	
3339	/**
3340	 * Draw the header (or footer) element based on the column visibility states.
3341	 *
3342	 *  @param object oSettings dataTables settings object
3343	 *  @param array aoSource Layout array from _fnDetectHeader
3344	 *  @memberof DataTable#oApi
3345	 */
3346	function _fnDrawHead( settings, source )
3347	{
3348		var layout = _fnHeaderLayout(settings, source);
3349		var tr, n;
3350	
3351		for ( var row=0 ; row<source.length ; row++ ) {
3352			tr = source[row].row;
3353	
3354			// All cells are going to be replaced, so empty out the row
3355			// Can't use $().empty() as that kills event handlers
3356			if (tr) {
3357				while( (n = tr.firstChild) ) {
3358					tr.removeChild( n );
3359				}
3360			}
3361	
3362			for ( var column=0 ; column<layout[row].length ; column++ ) {
3363				var point = layout[row][column];
3364	
3365				if (point) {
3366					$(point.cell)
3367						.appendTo(tr)
3368						.attr('rowspan', point.rowspan)
3369						.attr('colspan', point.colspan);
3370				}
3371			}
3372		}
3373	}
3374	
3375	
3376	/**
3377	 * Insert the required TR nodes into the table for display
3378	 *  @param {object} oSettings dataTables settings object
3379	 *  @param ajaxComplete true after ajax call to complete rendering
3380	 *  @memberof DataTable#oApi
3381	 */
3382	function _fnDraw( oSettings, ajaxComplete )
3383	{
3384		// Allow for state saving and a custom start position
3385		_fnStart( oSettings );
3386	
3387		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3388		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3389		if ( aPreDraw.indexOf(false) !== -1 )
3390		{
3391			_fnProcessingDisplay( oSettings, false );
3392			return;
3393		}
3394	
3395		var anRows = [];
3396		var iRowCount = 0;
3397		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3398		var aiDisplay = oSettings.aiDisplay;
3399		var iDisplayStart = oSettings._iDisplayStart;
3400		var iDisplayEnd = oSettings.fnDisplayEnd();
3401		var columns = oSettings.aoColumns;
3402		var body = $(oSettings.nTBody);
3403	
3404		oSettings.bDrawing = true;
3405	
3406		/* Server-side processing draw intercept */
3407		if ( oSettings.deferLoading )
3408		{
3409			oSettings.deferLoading = false;
3410			oSettings.iDraw++;
3411			_fnProcessingDisplay( oSettings, false );
3412		}
3413		else if ( !bServerSide )
3414		{
3415			oSettings.iDraw++;
3416		}
3417		else if ( !oSettings.bDestroying && !ajaxComplete)
3418		{
3419			// Show loading message for server-side processing
3420			if (oSettings.iDraw === 0) {
3421				body.empty().append(_emptyRow(oSettings));
3422			}
3423	
3424			_fnAjaxUpdate( oSettings );
3425			return;
3426		}
3427	
3428		if ( aiDisplay.length !== 0 )
3429		{
3430			var iStart = bServerSide ? 0 : iDisplayStart;
3431			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3432	
3433			for ( var j=iStart ; j<iEnd ; j++ )
3434			{
3435				var iDataIndex = aiDisplay[j];
3436				var aoData = oSettings.aoData[ iDataIndex ];
3437				if ( aoData.nTr === null )
3438				{
3439					_fnCreateTr( oSettings, iDataIndex );
3440				}
3441	
3442				var nRow = aoData.nTr;
3443	
3444				// Add various classes as needed
3445				for (var i=0 ; i<columns.length ; i++) {
3446					var col = columns[i];
3447					var td = aoData.anCells[i];
3448	
3449					_addClass(td, _ext.type.className[col.sType]); // auto class
3450					_addClass(td, oSettings.oClasses.tbody.cell); // all cells
3451				}
3452	
3453				// Row callback functions - might want to manipulate the row
3454				// iRowCount and j are not currently documented. Are they at all
3455				// useful?
3456				_fnCallbackFire( oSettings, 'aoRowCallback', null,
3457					[nRow, aoData._aData, iRowCount, j, iDataIndex] );
3458	
3459				anRows.push( nRow );
3460				iRowCount++;
3461			}
3462		}
3463		else
3464		{
3465			anRows[ 0 ] = _emptyRow(oSettings);
3466		}
3467	
3468		/* Header and footer callbacks */
3469		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3470			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3471	
3472		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3473			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3474	
3475		// replaceChildren is faster, but only became widespread in 2020,
3476		// so a fall back in jQuery is provided for older browsers.
3477		if (body[0].replaceChildren) {
3478			body[0].replaceChildren.apply(body[0], anRows);
3479		}
3480		else {
3481			body.children().detach();
3482			body.append( $(anRows) );
3483		}
3484	
3485		// Empty table needs a specific class
3486		$(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
3487	
3488		/* Call all required callback functions for the end of a draw */
3489		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings], true );
3490	
3491		/* Draw is complete, sorting and filtering must be as well */
3492		oSettings.bSorted = false;
3493		oSettings.bFiltered = false;
3494		oSettings.bDrawing = false;
3495	}
3496	
3497	
3498	/**
3499	 * Redraw the table - taking account of the various features which are enabled
3500	 *  @param {object} oSettings dataTables settings object
3501	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
3502	 *    the paging is reset to the first page
3503	 *  @memberof DataTable#oApi
3504	 */
3505	function _fnReDraw( settings, holdPosition, recompute )
3506	{
3507		var
3508			features = settings.oFeatures,
3509			sort     = features.bSort,
3510			filter   = features.bFilter;
3511	
3512		if (recompute === undefined || recompute === true) {
3513			// Resolve any column types that are unknown due to addition or invalidation
3514			_fnColumnTypes( settings );
3515	
3516			if ( sort ) {
3517				_fnSort( settings );
3518			}
3519	
3520			if ( filter ) {
3521				_fnFilterComplete( settings, settings.oPreviousSearch );
3522			}
3523			else {
3524				// No filtering, so we want to just use the display master
3525				settings.aiDisplay = settings.aiDisplayMaster.slice();
3526			}
3527		}
3528	
3529		if ( holdPosition !== true ) {
3530			settings._iDisplayStart = 0;
3531		}
3532	
3533		// Let any modules know about the draw hold position state (used by
3534		// scrolling internally)
3535		settings._drawHold = holdPosition;
3536	
3537		_fnDraw( settings );
3538	
3539		settings._drawHold = false;
3540	}
3541	
3542	
3543	/*
3544	 * Table is empty - create a row with an empty message in it
3545	 */
3546	function _emptyRow ( settings ) {
3547		var oLang = settings.oLanguage;
3548		var zero = oLang.sZeroRecords;
3549		var dataSrc = _fnDataSource( settings );
3550	
3551		if (
3552			(settings.iDraw < 1 && dataSrc === 'ssp') ||
3553			(settings.iDraw <= 1 && dataSrc === 'ajax')
3554		) {
3555			zero = oLang.sLoadingRecords;
3556		}
3557		else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
3558		{
3559			zero = oLang.sEmptyTable;
3560		}
3561	
3562		return $( '<tr/>' )
3563			.append( $('<td />', {
3564				'colSpan': _fnVisbleColumns( settings ),
3565				'class':   settings.oClasses.empty.row
3566			} ).html( zero ) )[0];
3567	}
3568	
3569	
3570	/**
3571	 * Expand the layout items into an object for the rendering function
3572	 */
3573	function _layoutItems (row, align, items) {
3574		if ( Array.isArray(items)) {
3575			for (var i=0 ; i<items.length ; i++) {
3576				_layoutItems(row, align, items[i]);
3577			}
3578	
3579			return;
3580		}
3581	
3582		var rowCell = row[align];
3583	
3584		// If it is an object, then there can be multiple features contained in it
3585		if ( $.isPlainObject( items ) ) {
3586			// A feature plugin cannot be named "features" due to this check
3587			if (items.features) {
3588				if (items.rowId) {
3589					row.id = items.rowId;
3590				}
3591				if (items.rowClass) {
3592					row.className = items.rowClass;
3593				}
3594	
3595				rowCell.id = items.id;
3596				rowCell.className = items.className;
3597	
3598				_layoutItems(row, align, items.features);
3599			}
3600			else {
3601				Object.keys(items).map(function (key) {
3602					rowCell.contents.push( {
3603						feature: key,
3604						opts: items[key]
3605					});
3606				});
3607			}
3608		}
3609		else {
3610			rowCell.contents.push(items);
3611		}
3612	}
3613	
3614	/**
3615	 * Find, or create a layout row
3616	 */
3617	function _layoutGetRow(rows, rowNum, align) {
3618		var row;
3619	
3620		// Find existing rows
3621		for (var i=0; i<rows.length; i++) {
3622			row = rows[i];
3623	
3624			if (row.rowNum === rowNum) {
3625				// full is on its own, but start and end share a row
3626				if (
3627					(align === 'full' && row.full) ||
3628					((align === 'start' || align === 'end') && (row.start || row.end))
3629				) {
3630					if (! row[align]) {
3631						row[align] = {
3632							contents: []
3633						};
3634					}
3635	
3636					return row;
3637				}
3638			}
3639		}
3640	
3641		// If we get this far, then there was no match, create a new row
3642		row = {
3643			rowNum: rowNum	
3644		};
3645	
3646		row[align] = {
3647			contents: []
3648		};
3649	
3650		rows.push(row);
3651	
3652		return row;
3653	}
3654	
3655	/**
3656	 * Convert a `layout` object given by a user to the object structure needed
3657	 * for the renderer. This is done twice, once for above and once for below
3658	 * the table. Ordering must also be considered.
3659	 *
3660	 * @param {*} settings DataTables settings object
3661	 * @param {*} layout Layout object to convert
3662	 * @param {string} side `top` or `bottom`
3663	 * @returns Converted array structure - one item for each row.
3664	 */
3665	function _layoutArray ( settings, layout, side ) {
3666		var rows = [];
3667		
3668		// Split out into an array
3669		$.each( layout, function ( pos, items ) {
3670			if (items === null) {
3671				return;
3672			}
3673	
3674			var parts = pos.match(/^([a-z]+)([0-9]*)([A-Za-z]*)$/);
3675			var rowNum = parts[2]
3676				? parts[2] * 1
3677				: 0;
3678			var align = parts[3]
3679				? parts[3].toLowerCase()
3680				: 'full';
3681	
3682			// Filter out the side we aren't interested in
3683			if (parts[1] !== side) {
3684				return;
3685			}
3686	
3687			// Get or create the row we should attach to
3688			var row = _layoutGetRow(rows, rowNum, align);
3689	
3690			_layoutItems(row, align, items);
3691		});
3692	
3693		// Order by item identifier
3694		rows.sort( function ( a, b ) {
3695			var order1 = a.rowNum;
3696			var order2 = b.rowNum;
3697	
3698			// If both in the same row, then the row with `full` comes first
3699			if (order1 === order2) {
3700				var ret = a.full && ! b.full ? -1 : 1;
3701	
3702				return side === 'bottom'
3703					? ret * -1
3704					: ret;
3705			}
3706	
3707			return order2 - order1;
3708		} );
3709	
3710		// Invert for below the table
3711		if ( side === 'bottom' ) {
3712			rows.reverse();
3713		}
3714	
3715		for (var row = 0; row<rows.length; row++) {
3716			delete rows[row].rowNum;
3717	
3718			_layoutResolve(settings, rows[row]);
3719		}
3720	
3721		return rows;
3722	}
3723	
3724	
3725	/**
3726	 * Convert the contents of a row's layout object to nodes that can be inserted
3727	 * into the document by a renderer. Execute functions, look up plug-ins, etc.
3728	 *
3729	 * @param {*} settings DataTables settings object
3730	 * @param {*} row Layout object for this row
3731	 */
3732	function _layoutResolve( settings, row ) {
3733		var getFeature = function (feature, opts) {
3734			if ( ! _ext.features[ feature ] ) {
3735				_fnLog( settings, 0, 'Unknown feature: '+ feature );
3736			}
3737	
3738			return _ext.features[ feature ].apply( this, [settings, opts] );
3739		};
3740	
3741		var resolve = function ( item ) {
3742			if (! row[ item ]) {
3743				return;
3744			}
3745	
3746			var line = row[ item ].contents;
3747	
3748			for ( var i=0, ien=line.length ; i<ien ; i++ ) {
3749				if ( ! line[i] ) {
3750					continue;
3751				}
3752				else if ( typeof line[i] === 'string' ) {
3753					line[i] = getFeature( line[i], null );
3754				}
3755				else if ( $.isPlainObject(line[i]) ) {
3756					// If it's an object, it just has feature and opts properties from
3757					// the transform in _layoutArray
3758					line[i] = getFeature(line[i].feature, line[i].opts);
3759				}
3760				else if ( typeof line[i].node === 'function' ) {
3761					line[i] = line[i].node( settings );
3762				}
3763				else if ( typeof line[i] === 'function' ) {
3764					var inst = line[i]( settings );
3765	
3766					line[i] = typeof inst.node === 'function' ?
3767						inst.node() :
3768						inst;
3769				}
3770			}
3771		};
3772	
3773		resolve('start');
3774		resolve('end');
3775		resolve('full');
3776	}
3777	
3778	
3779	/**
3780	 * Add the options to the page HTML for the table
3781	 *  @param {object} settings DataTables settings object
3782	 *  @memberof DataTable#oApi
3783	 */
3784	function _fnAddOptionsHtml ( settings )
3785	{
3786		var classes = settings.oClasses;
3787		var table = $(settings.nTable);
3788	
3789		// Wrapper div around everything DataTables controls
3790		var insert = $('<div/>')
3791			.attr({
3792				id:      settings.sTableId+'_wrapper',
3793				'class': classes.container
3794			})
3795			.insertBefore(table);
3796	
3797		settings.nTableWrapper = insert[0];
3798	
3799		if (settings.sDom) {
3800			// Legacy
3801			_fnLayoutDom(settings, settings.sDom, insert);
3802		}
3803		else {
3804			var top = _layoutArray( settings, settings.layout, 'top' );
3805			var bottom = _layoutArray( settings, settings.layout, 'bottom' );
3806			var renderer = _fnRenderer( settings, 'layout' );
3807		
3808			// Everything above - the renderer will actually insert the contents into the document
3809			top.forEach(function (item) {
3810				renderer( settings, insert, item );
3811			});
3812	
3813			// The table - always the center of attention
3814			renderer( settings, insert, {
3815				full: {
3816					table: true,
3817					contents: [ _fnFeatureHtmlTable(settings) ]
3818				}
3819			} );
3820	
3821			// Everything below
3822			bottom.forEach(function (item) {
3823				renderer( settings, insert, item );
3824			});
3825		}
3826	
3827		// Processing floats on top, so it isn't an inserted feature
3828		_processingHtml( settings );
3829	}
3830	
3831	/**
3832	 * Draw the table with the legacy DOM property
3833	 * @param {*} settings DT settings object
3834	 * @param {*} dom DOM string
3835	 * @param {*} insert Insert point
3836	 */
3837	function _fnLayoutDom( settings, dom, insert )
3838	{
3839		var parts = dom.match(/(".*?")|('.*?')|./g);
3840		var featureNode, option, newNode, next, attr;
3841	
3842		for ( var i=0 ; i<parts.length ; i++ ) {
3843			featureNode = null;
3844			option = parts[i];
3845	
3846			if ( option == '<' ) {
3847				// New container div
3848				newNode = $('<div/>');
3849	
3850				// Check to see if we should append an id and/or a class name to the container
3851				next = parts[i+1];
3852	
3853				if ( next[0] == "'" || next[0] == '"' ) {
3854					attr = next.replace(/['"]/g, '');
3855	
3856					var id = '', className;
3857	
3858					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3859					 * breaks the string into parts and applies them as needed
3860					 */
3861					if ( attr.indexOf('.') != -1 ) {
3862						var split = attr.split('.');
3863	
3864						id = split[0];
3865						className = split[1];
3866					}
3867					else if ( attr[0] == "#" ) {
3868						id = attr;
3869					}
3870					else {
3871						className = attr;
3872					}
3873	
3874					newNode
3875						.attr('id', id.substring(1))
3876						.addClass(className);
3877	
3878					i++; // Move along the position array
3879				}
3880	
3881				insert.append( newNode );
3882				insert = newNode;
3883			}
3884			else if ( option == '>' ) {
3885				// End container div
3886				insert = insert.parent();
3887			}
3888			else if ( option == 't' ) {
3889				// Table
3890				featureNode = _fnFeatureHtmlTable( settings );
3891			}
3892			else
3893			{
3894				DataTable.ext.feature.forEach(function(feature) {
3895					if ( option == feature.cFeature ) {
3896						featureNode = feature.fnInit( settings );
3897					}
3898				});
3899			}
3900	
3901			// Add to the display
3902			if ( featureNode ) {
3903				insert.append( featureNode );
3904			}
3905		}
3906	}
3907	
3908	
3909	/**
3910	 * Use the DOM source to create up an array of header cells. The idea here is to
3911	 * create a layout grid (array) of rows x columns, which contains a reference
3912	 * to the cell that that point in the grid (regardless of col/rowspan), such that
3913	 * any column / row could be removed and the new grid constructed
3914	 *  @param {node} thead The header/footer element for the table
3915	 *  @returns {array} Calculated layout array
3916	 *  @memberof DataTable#oApi
3917	 */
3918	function _fnDetectHeader ( settings, thead, write )
3919	{
3920		var columns = settings.aoColumns;
3921		var rows = $(thead).children('tr');
3922		var row, cell;
3923		var i, k, l, iLen, shifted, column, colspan, rowspan;
3924		var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3925		var layout = [];
3926		var unique;
3927		var shift = function ( a, i, j ) {
3928			var k = a[i];
3929			while ( k[j] ) {
3930				j++;
3931			}
3932			return j;
3933		};
3934	
3935		// We know how many rows there are in the layout - so prep it
3936		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3937			layout.push( [] );
3938		}
3939	
3940		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3941			row = rows[i];
3942			column = 0;
3943	
3944			// For every cell in the row..
3945			cell = row.firstChild;
3946			while ( cell ) {
3947				if (
3948					cell.nodeName.toUpperCase() == 'TD' ||
3949					cell.nodeName.toUpperCase() == 'TH'
3950				) {
3951					var cols = [];
3952	
3953					// Get the col and rowspan attributes from the DOM and sanitise them
3954					colspan = cell.getAttribute('colspan') * 1;
3955					rowspan = cell.getAttribute('rowspan') * 1;
3956					colspan = (!colspan || colspan===0 || colspan===1) ? 1 : colspan;
3957					rowspan = (!rowspan || rowspan===0 || rowspan===1) ? 1 : rowspan;
3958	
3959					// There might be colspan cells already in this row, so shift our target
3960					// accordingly
3961					shifted = shift( layout, i, column );
3962	
3963					// Cache calculation for unique columns
3964					unique = colspan === 1 ?
3965						true :
3966						false;
3967					
3968					// Perform header setup
3969					if ( write ) {
3970						if (unique) {
3971							// Allow column options to be set from HTML attributes
3972							_fnColumnOptions( settings, shifted, $(cell).data() );
3973							
3974							// Get the width for the column. This can be defined from the
3975							// width attribute, style attribute or `columns.width` option
3976							var columnDef = columns[shifted];
3977							var width = cell.getAttribute('width') || null;
3978							var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
3979							if ( t ) {
3980								width = t[1];
3981							}
3982	
3983							columnDef.sWidthOrig = columnDef.sWidth || width;
3984	
3985							if (isHeader) {
3986								// Column title handling - can be user set, or read from the DOM
3987								// This happens before the render, so the original is still in place
3988								if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
3989									cell.innerHTML = columnDef.sTitle;
3990								}
3991	
3992								if (! columnDef.sTitle && unique) {
3993									columnDef.sTitle = _stripHtml(cell.innerHTML);
3994									columnDef.autoTitle = true;
3995								}
3996							}
3997							else {
3998								// Footer specific operations
3999								if (columnDef.footer) {
4000									cell.innerHTML = columnDef.footer;
4001								}
4002							}
4003	
4004							// Fall back to the aria-label attribute on the table header if no ariaTitle is
4005							// provided.
4006							if (! columnDef.ariaTitle) {
4007								columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
4008							}
4009	
4010							// Column specific class names
4011							if ( columnDef.className ) {
4012								$(cell).addClass( columnDef.className );
4013							}
4014						}
4015	
4016						// Wrap the column title so we can write to it in future
4017						if ( $('span.dt-column-title', cell).length === 0) {
4018							$('<span>')
4019								.addClass('dt-column-title')
4020								.append(cell.childNodes)
4021								.appendTo(cell);
4022						}
4023	
4024						if ( isHeader && $('span.dt-column-order', cell).length === 0) {
4025							$('<span>')
4026								.addClass('dt-column-order')
4027								.appendTo(cell);
4028						}
4029					}
4030	
4031					// If there is col / rowspan, copy the information into the layout grid
4032					for ( l=0 ; l<colspan ; l++ ) {
4033						for ( k=0 ; k<rowspan ; k++ ) {
4034							layout[i+k][shifted+l] = {
4035								cell: cell,
4036								unique: unique
4037							};
4038	
4039							layout[i+k].row = row;
4040						}
4041	
4042						cols.push( shifted+l );
4043					}
4044	
4045					// Assign an attribute so spanning cells can still be identified
4046					// as belonging to a column
4047					cell.setAttribute('data-dt-column', _unique(cols).join(','));
4048				}
4049	
4050				cell = cell.nextSibling;
4051			}
4052		}
4053	
4054		return layout;
4055	}
4056	
4057	/**
4058	 * Set the start position for draw
4059	 *  @param {object} oSettings dataTables settings object
4060	 */
4061	function _fnStart( oSettings )
4062	{
4063		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
4064		var iInitDisplayStart = oSettings.iInitDisplayStart;
4065	
4066		// Check and see if we have an initial draw position from state saving
4067		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
4068		{
4069			oSettings._iDisplayStart = bServerSide ?
4070				iInitDisplayStart :
4071				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
4072					0 :
4073					iInitDisplayStart;
4074	
4075			oSettings.iInitDisplayStart = -1;
4076		}
4077	}
4078	
4079	/**
4080	 * Create an Ajax call based on the table's settings, taking into account that
4081	 * parameters can have multiple forms, and backwards compatibility.
4082	 *
4083	 * @param {object} oSettings dataTables settings object
4084	 * @param {array} data Data to send to the server, required by
4085	 *     DataTables - may be augmented by developer callbacks
4086	 * @param {function} fn Callback function to run when data is obtained
4087	 */
4088	function _fnBuildAjax( oSettings, data, fn )
4089	{
4090		var ajaxData;
4091		var ajax = oSettings.ajax;
4092		var instance = oSettings.oInstance;
4093		var callback = function ( json ) {
4094			var status = oSettings.jqXHR
4095				? oSettings.jqXHR.status
4096				: null;
4097	
4098			if ( json === null || (typeof status === 'number' && status == 204 ) ) {
4099				json = {};
4100				_fnAjaxDataSrc( oSettings, json, [] );
4101			}
4102	
4103			var error = json.error || json.sError;
4104			if ( error ) {
4105				_fnLog( oSettings, 0, error );
4106			}
4107	
4108			// Microsoft often wrap JSON as a string in another JSON object
4109			// Let's handle that automatically
4110			if (json.d && typeof json.d === 'string') {
4111				try {
4112					json = JSON.parse(json.d);
4113				}
4114				catch (e) {
4115					// noop
4116				}
4117			}
4118	
4119			oSettings.json = json;
4120	
4121			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
4122			fn( json );
4123		};
4124	
4125		if ( $.isPlainObject( ajax ) && ajax.data )
4126		{
4127			ajaxData = ajax.data;
4128	
4129			var newData = typeof ajaxData === 'function' ?
4130				ajaxData( data, oSettings ) :  // fn can manipulate data or return
4131				ajaxData;                      // an object object or array to merge
4132	
4133			// If the function returned something, use that alone
4134			data = typeof ajaxData === 'function' && newData ?
4135				newData :
4136				$.extend( true, data, newData );
4137	
4138			// Remove the data property as we've resolved it already and don't want
4139			// jQuery to do it again (it is restored at the end of the function)
4140			delete ajax.data;
4141		}
4142	
4143		var baseAjax = {
4144			"url": typeof ajax === 'string' ?
4145				ajax :
4146				'',
4147			"data": data,
4148			"success": callback,
4149			"dataType": "json",
4150			"cache": false,
4151			"type": oSettings.sServerMethod,
4152			"error": function (xhr, error) {
4153				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
4154	
4155				if ( ret.indexOf(true) === -1 ) {
4156					if ( error == "parsererror" ) {
4157						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
4158					}
4159					else if ( xhr.readyState === 4 ) {
4160						_fnLog( oSettings, 0, 'Ajax error', 7 );
4161					}
4162				}
4163	
4164				_fnProcessingDisplay( oSettings, false );
4165			}
4166		};
4167	
4168		// If `ajax` option is an object, extend and override our default base
4169		if ( $.isPlainObject( ajax ) ) {
4170			$.extend( baseAjax, ajax )
4171		}
4172	
4173		// Store the data submitted for the API
4174		oSettings.oAjaxData = data;
4175	
4176		// Allow plug-ins and external processes to modify the data
4177		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4178	
4179		if ( typeof ajax === 'function' )
4180		{
4181			// Is a function - let the caller define what needs to be done
4182			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
4183		}
4184		else if (ajax.url === '') {
4185			// No url, so don't load any data. Just apply an empty data array
4186			// to the object for the callback.
4187			var empty = {};
4188	
4189			DataTable.util.set(ajax.dataSrc)(empty, []);
4190			callback(empty);
4191		}
4192		else {
4193			// Object to extend the base settings
4194			oSettings.jqXHR = $.ajax( baseAjax );
4195		}
4196	
4197		// Restore for next time around
4198		if ( ajaxData ) {
4199			ajax.data = ajaxData;
4200		}
4201	}
4202	
4203	
4204	/**
4205	 * Update the table using an Ajax call
4206	 *  @param {object} settings dataTables settings object
4207	 *  @returns {boolean} Block the table drawing or not
4208	 *  @memberof DataTable#oApi
4209	 */
4210	function _fnAjaxUpdate( settings )
4211	{
4212		settings.iDraw++;
4213		_fnProcessingDisplay( settings, true );
4214	
4215		_fnBuildAjax(
4216			settings,
4217			_fnAjaxParameters( settings ),
4218			function(json) {
4219				_fnAjaxUpdateDraw( settings, json );
4220			}
4221		);
4222	}
4223	
4224	
4225	/**
4226	 * Build up the parameters in an object needed for a server-side processing
4227	 * request.
4228	 *  @param {object} oSettings dataTables settings object
4229	 *  @returns {bool} block the table drawing or not
4230	 *  @memberof DataTable#oApi
4231	 */
4232	function _fnAjaxParameters( settings )
4233	{
4234		var
4235			columns = settings.aoColumns,
4236			features = settings.oFeatures,
4237			preSearch = settings.oPreviousSearch,
4238			preColSearch = settings.aoPreSearchCols,
4239			colData = function ( idx, prop ) {
4240				return typeof columns[idx][prop] === 'function' ?
4241					'function' :
4242					columns[idx][prop];
4243			};
4244	
4245		return {
4246			draw: settings.iDraw,
4247			columns: columns.map( function ( column, i ) {
4248				return {
4249					data: colData(i, 'mData'),
4250					name: column.sName,
4251					searchable: column.bSearchable,
4252					orderable: column.bSortable,
4253					search: {
4254						value: preColSearch[i].search,
4255						regex: preColSearch[i].regex,
4256						fixed: Object.keys(column.searchFixed).map( function(name) {
4257							return {
4258								name: name,
4259								term: column.searchFixed[name].toString()
4260							}
4261						})
4262					}
4263				};
4264			} ),
4265			order: _fnSortFlatten( settings ).map( function ( val ) {
4266				return {
4267					column: val.col,
4268					dir: val.dir,
4269					name: colData(val.col, 'sName')
4270				};
4271			} ),
4272			start: settings._iDisplayStart,
4273			length: features.bPaginate ?
4274				settings._iDisplayLength :
4275				-1,
4276			search: {
4277				value: preSearch.search,
4278				regex: preSearch.regex,
4279				fixed: Object.keys(settings.searchFixed).map( function(name) {
4280					return {
4281						name: name,
4282						term: settings.searchFixed[name].toString()
4283					}
4284				})
4285			}
4286		};
4287	}
4288	
4289	
4290	/**
4291	 * Data the data from the server (nuking the old) and redraw the table
4292	 *  @param {object} oSettings dataTables settings object
4293	 *  @param {object} json json data return from the server.
4294	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
4295	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4296	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4297	 *  @param {array} json.aaData The data to display on this page
4298	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4299	 *  @memberof DataTable#oApi
4300	 */
4301	function _fnAjaxUpdateDraw ( settings, json )
4302	{
4303		var data = _fnAjaxDataSrc(settings, json);
4304		var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
4305		var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
4306		var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
4307	
4308		if ( draw !== undefined ) {
4309			// Protect against out of sequence returns
4310			if ( draw*1 < settings.iDraw ) {
4311				return;
4312			}
4313			settings.iDraw = draw * 1;
4314		}
4315	
4316		// No data in returned object, so rather than an array, we show an empty table
4317		if ( ! data ) {
4318			data = [];
4319		}
4320	
4321		_fnClearTable( settings );
4322		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
4323		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4324	
4325		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4326			_fnAddData( settings, data[i] );
4327		}
4328		settings.aiDisplay = settings.aiDisplayMaster.slice();
4329	
4330		_fnColumnTypes(settings);
4331		_fnDraw( settings, true );
4332		_fnInitComplete( settings );
4333		_fnProcessingDisplay( settings, false );
4334	}
4335	
4336	
4337	/**
4338	 * Get the data from the JSON data source to use for drawing a table. Using
4339	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4340	 * source object, or from a processing function.
4341	 *  @param {object} settings dataTables settings object
4342	 *  @param  {object} json Data source object / array from the server
4343	 *  @return {array} Array of data to use
4344	 */
4345	function _fnAjaxDataSrc ( settings, json, write )
4346	{
4347		var dataProp = 'data';
4348	
4349		if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
4350			// Could in inside a `dataSrc` object, or not!
4351			var dataSrc = settings.ajax.dataSrc;
4352	
4353			// string, function and object are valid types
4354			if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
4355				dataProp = dataSrc;
4356			}
4357			else if (dataSrc.data !== undefined) {
4358				dataProp = dataSrc.data;
4359			}
4360		}
4361	
4362		if ( ! write ) {
4363			if ( dataProp === 'data' ) {
4364				// If the default, then we still want to support the old style, and safely ignore
4365				// it if possible
4366				return json.aaData || json[dataProp];
4367			}
4368	
4369			return dataProp !== "" ?
4370				_fnGetObjectDataFn( dataProp )( json ) :
4371				json;
4372		}
4373		
4374		// set
4375		_fnSetObjectDataFn( dataProp )( json, write );
4376	}
4377	
4378	/**
4379	 * Very similar to _fnAjaxDataSrc, but for the other SSP properties
4380	 * @param {*} settings DataTables settings object
4381	 * @param {*} param Target parameter
4382	 * @param {*} json JSON data
4383	 * @returns Resolved value
4384	 */
4385	function _fnAjaxDataSrcParam (settings, param, json) {
4386		var dataSrc = $.isPlainObject( settings.ajax )
4387			? settings.ajax.dataSrc
4388			: null;
4389	
4390		if (dataSrc && dataSrc[param]) {
4391			// Get from custom location
4392			return _fnGetObjectDataFn( dataSrc[param] )( json );
4393		}
4394	
4395		// else - Default behaviour
4396		var old = '';
4397	
4398		// Legacy support
4399		if (param === 'draw') {
4400			old = 'sEcho';
4401		}
4402		else if (param === 'recordsTotal') {
4403			old = 'iTotalRecords';
4404		}
4405		else if (param === 'recordsFiltered') {
4406			old = 'iTotalDisplayRecords';
4407		}
4408	
4409		return json[old] !== undefined
4410			? json[old]
4411			: json[param];
4412	}
4413	
4414	
4415	/**
4416	 * Filter the table using both the global filter and column based filtering
4417	 *  @param {object} settings dataTables settings object
4418	 *  @param {object} input search information
4419	 *  @memberof DataTable#oApi
4420	 */
4421	function _fnFilterComplete ( settings, input )
4422	{
4423		var columnsSearch = settings.aoPreSearchCols;
4424	
4425		// In server-side processing all filtering is done by the server, so no point hanging around here
4426		if ( _fnDataSource( settings ) != 'ssp' )
4427		{
4428			// Check if any of the rows were invalidated
4429			_fnFilterData( settings );
4430	
4431			// Start from the full data set
4432			settings.aiDisplay = settings.aiDisplayMaster.slice();
4433	
4434			// Global filter first
4435			_fnFilter( settings.aiDisplay, settings, input.search, input );
4436	
4437			$.each(settings.searchFixed, function (name, term) {
4438				_fnFilter(settings.aiDisplay, settings, term, {});
4439			});
4440	
4441			// Then individual column filters
4442			for ( var i=0 ; i<columnsSearch.length ; i++ )
4443			{
4444				var col = columnsSearch[i];
4445	
4446				_fnFilter(
4447					settings.aiDisplay,
4448					settings,
4449					col.search,
4450					col,
4451					i
4452				);
4453	
4454				$.each(settings.aoColumns[i].searchFixed, function (name, term) {
4455					_fnFilter(settings.aiDisplay, settings, term, {}, i);
4456				});
4457			}
4458	
4459			// And finally global filtering
4460			_fnFilterCustom( settings );
4461		}
4462	
4463		// Tell the draw function we have been filtering
4464		settings.bFiltered = true;
4465	
4466		_fnCallbackFire( settings, null, 'search', [settings] );
4467	}
4468	
4469	
4470	/**
4471	 * Apply custom filtering functions
4472	 * 
4473	 * This is legacy now that we have named functions, but it is widely used
4474	 * from 1.x, so it is not yet deprecated.
4475	 *  @param {object} oSettings dataTables settings object
4476	 *  @memberof DataTable#oApi
4477	 */
4478	function _fnFilterCustom( settings )
4479	{
4480		var filters = DataTable.ext.search;
4481		var displayRows = settings.aiDisplay;
4482		var row, rowIdx;
4483	
4484		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4485			var rows = [];
4486	
4487			// Loop over each row and see if it should be included
4488			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4489				rowIdx = displayRows[ j ];
4490				row = settings.aoData[ rowIdx ];
4491	
4492				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4493					rows.push( rowIdx );
4494				}
4495			}
4496	
4497			// So the array reference doesn't break set the results into the
4498			// existing array
4499			displayRows.length = 0;
4500			_fnArrayApply(displayRows, rows);
4501		}
4502	}
4503	
4504	
4505	/**
4506	 * Filter the data table based on user input and draw the table
4507	 */
4508	function _fnFilter( searchRows, settings, input, options, column )
4509	{
4510		if ( input === '' ) {
4511			return;
4512		}
4513	
4514		var i = 0;
4515		var matched = [];
4516	
4517		// Search term can be a function, regex or string - if a string we apply our
4518		// smart filtering regex (assuming the options require that)
4519		var searchFunc = typeof input === 'function' ? input : null;
4520		var rpSearch = input instanceof RegExp
4521			? input
4522			: searchFunc
4523				? null
4524				: _fnFilterCreateSearch( input, options );
4525	
4526		// Then for each row, does the test pass. If not, lop the row from the array
4527		for (i=0 ; i<searchRows.length ; i++) {
4528			var row = settings.aoData[ searchRows[i] ];
4529			var data = column === undefined
4530				? row._sFilterRow
4531				: row._aFilterData[ column ];
4532	
4533			if ( (searchFunc && searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && rpSearch.test(data)) ) {
4534				matched.push(searchRows[i]);
4535			}
4536		}
4537	
4538		// Mutate the searchRows array
4539		searchRows.length = matched.length;
4540	
4541		for (i=0 ; i<matched.length ; i++) {
4542			searchRows[i] = matched[i];
4543		}
4544	}
4545	
4546	
4547	/**
4548	 * Build a regular expression object suitable for searching a table
4549	 *  @param {string} sSearch string to search for
4550	 *  @param {bool} bRegex treat as a regular expression or not
4551	 *  @param {bool} bSmart perform smart filtering or not
4552	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4553	 *  @returns {RegExp} constructed object
4554	 *  @memberof DataTable#oApi
4555	 */
4556	function _fnFilterCreateSearch( search, inOpts )
4557	{
4558		var not = [];
4559		var options = $.extend({}, {
4560			boundary: false,
4561			caseInsensitive: true,
4562			exact: false,
4563			regex: false,
4564			smart: true
4565		}, inOpts);
4566	
4567		if (typeof search !== 'string') {
4568			search = search.toString();
4569		}
4570	
4571		// Remove diacritics if normalize is set up to do so
4572		search = _normalize(search);
4573	
4574		if (options.exact) {
4575			return new RegExp(
4576				'^'+_fnEscapeRegex(search)+'$',
4577				options.caseInsensitive ? 'i' : ''
4578			);
4579		}
4580	
4581		search = options.regex ?
4582			search :
4583			_fnEscapeRegex( search );
4584		
4585		if ( options.smart ) {
4586			/* For smart filtering we want to allow the search to work regardless of
4587			 * word order. We also want double quoted text to be preserved, so word
4588			 * order is important - a la google. And a negative look around for
4589			 * finding rows which don't contain a given string.
4590			 * 
4591			 * So this is the sort of thing we want to generate:
4592			 * 
4593			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4594			 */
4595			var parts = search.match( /!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''];
4596			var a = parts.map( function ( word ) {
4597				var negative = false;
4598				var m;
4599	
4600				// Determine if it is a "does not include"
4601				if ( word.charAt(0) === '!' ) {
4602					negative = true;
4603					word = word.substring(1);
4604				}
4605	
4606				// Strip the quotes from around matched phrases
4607				if ( word.charAt(0) === '"' ) {
4608					m = word.match( /^"(.*)"$/ );
4609					word = m ? m[1] : word;
4610				}
4611				else if ( word.charAt(0) === '\u201C' ) {
4612					// Smart quote match (iPhone users)
4613					m = word.match( /^\u201C(.*)\u201D$/ );
4614					word = m ? m[1] : word;
4615				}
4616	
4617				// For our "not" case, we need to modify the string that is
4618				// allowed to match at the end of the expression.
4619				if (negative) {
4620					if (word.length > 1) {
4621						not.push('(?!'+word+')');
4622					}
4623	
4624					word = '';
4625				}
4626	
4627				return word.replace(/"/g, '');
4628			} );
4629	
4630			var match = not.length
4631				? not.join('')
4632				: '';
4633	
4634			var boundary = options.boundary
4635				? '\\b'
4636				: '';
4637	
4638			search = '^(?=.*?'+boundary+a.join( ')(?=.*?'+boundary )+')('+match+'.)*$';
4639		}
4640	
4641		return new RegExp( search, options.caseInsensitive ? 'i' : '' );
4642	}
4643	
4644	
4645	/**
4646	 * Escape a string such that it can be used in a regular expression
4647	 *  @param {string} sVal string to escape
4648	 *  @returns {string} escaped string
4649	 *  @memberof DataTable#oApi
4650	 */
4651	var _fnEscapeRegex = DataTable.util.escapeRegex;
4652	
4653	var __filter_div = $('<div>')[0];
4654	var __filter_div_textContent = __filter_div.textContent !== undefined;
4655	
4656	// Update the filtering data for each row if needed (by invalidation or first run)
4657	function _fnFilterData ( settings )
4658	{
4659		var columns = settings.aoColumns;
4660		var data = settings.aoData;
4661		var column;
4662		var j, jen, filterData, cellData, row;
4663		var wasInvalidated = false;
4664	
4665		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
4666			if (! data[rowIdx]) {
4667				continue;
4668			}
4669	
4670			row = data[rowIdx];
4671	
4672			if ( ! row._aFilterData ) {
4673				filterData = [];
4674	
4675				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4676					column = columns[j];
4677	
4678					if ( column.bSearchable ) {
4679						cellData = _fnGetCellData( settings, rowIdx, j, 'filter' );
4680	
4681						// Search in DataTables is string based
4682						if ( cellData === null ) {
4683							cellData = '';
4684						}
4685	
4686						if ( typeof cellData !== 'string' && cellData.toString ) {
4687							cellData = cellData.toString();
4688						}
4689					}
4690					else {
4691						cellData = '';
4692					}
4693	
4694					// If it looks like there is an HTML entity in the string,
4695					// attempt to decode it so sorting works as expected. Note that
4696					// we could use a single line of jQuery to do this, but the DOM
4697					// method used here is much faster https://jsperf.com/html-decode
4698					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4699						__filter_div.innerHTML = cellData;
4700						cellData = __filter_div_textContent ?
4701							__filter_div.textContent :
4702							__filter_div.innerText;
4703					}
4704	
4705					if ( cellData.replace ) {
4706						cellData = cellData.replace(/[\r\n\u2028]/g, '');
4707					}
4708	
4709					filterData.push( cellData );
4710				}
4711	
4712				row._aFilterData = filterData;
4713				row._sFilterRow = filterData.join('  ');
4714				wasInvalidated = true;
4715			}
4716		}
4717	
4718		return wasInvalidated;
4719	}
4720	
4721	
4722	/**
4723	 * Draw the table for the first time, adding all required features
4724	 *  @param {object} settings dataTables settings object
4725	 *  @memberof DataTable#oApi
4726	 */
4727	function _fnInitialise ( settings )
4728	{
4729		var i;
4730		var init = settings.oInit;
4731		var deferLoading = settings.deferLoading;
4732		var dataSrc = _fnDataSource( settings );
4733	
4734		// Ensure that the table data is fully initialised
4735		if ( ! settings.bInitialised ) {
4736			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4737			return;
4738		}
4739	
4740		// Build the header / footer for the table
4741		_fnBuildHead( settings, 'header' );
4742		_fnBuildHead( settings, 'footer' );
4743	
4744		// Load the table's state (if needed) and then render around it and draw
4745		_fnLoadState( settings, init, function () {
4746			// Then draw the header / footer
4747			_fnDrawHead( settings, settings.aoHeader );
4748			_fnDrawHead( settings, settings.aoFooter );
4749	
4750			// Cache the paging start point, as the first redraw will reset it
4751			var iAjaxStart = settings.iInitDisplayStart
4752	
4753			// Local data load
4754			// Check if there is data passing into the constructor
4755			if ( init.aaData ) {
4756				for ( i=0 ; i<init.aaData.length ; i++ ) {
4757					_fnAddData( settings, init.aaData[ i ] );
4758				}
4759			}
4760			else if ( deferLoading || dataSrc == 'dom' ) {
4761				// Grab the data from the page
4762				_fnAddTr( settings, $(settings.nTBody).children('tr') );
4763			}
4764	
4765			// Filter not yet applied - copy the display master
4766			settings.aiDisplay = settings.aiDisplayMaster.slice();
4767	
4768			// Enable features
4769			_fnAddOptionsHtml( settings );
4770			_fnSortInit( settings );
4771	
4772			_colGroup( settings );
4773	
4774			/* Okay to show that something is going on now */
4775			_fnProcessingDisplay( settings, true );
4776	
4777			_fnCallbackFire( settings, null, 'preInit', [settings], true );
4778	
4779			// If there is default sorting required - let's do it. The sort function
4780			// will do the drawing for us. Otherwise we draw the table regardless of the
4781			// Ajax source - this allows the table to look initialised for Ajax sourcing
4782			// data (show 'loading' message possibly)
4783			_fnReDraw( settings );
4784	
4785			// Server-side processing init complete is done by _fnAjaxUpdateDraw
4786			if ( dataSrc != 'ssp' || deferLoading ) {
4787				// if there is an ajax source load the data
4788				if ( dataSrc == 'ajax' ) {
4789					_fnBuildAjax( settings, {}, function(json) {
4790						var aData = _fnAjaxDataSrc( settings, json );
4791	
4792						// Got the data - add it to the table
4793						for ( i=0 ; i<aData.length ; i++ ) {
4794							_fnAddData( settings, aData[i] );
4795						}
4796	
4797						// Reset the init display for cookie saving. We've already done
4798						// a filter, and therefore cleared it before. So we need to make
4799						// it appear 'fresh'
4800						settings.iInitDisplayStart = iAjaxStart;
4801	
4802						_fnReDraw( settings );
4803						_fnProcessingDisplay( settings, false );
4804						_fnInitComplete( settings );
4805					}, settings );
4806				}
4807				else {
4808					_fnInitComplete( settings );
4809					_fnProcessingDisplay( settings, false );
4810				}
4811			}
4812		} );
4813	}
4814	
4815	
4816	/**
4817	 * Draw the table for the first time, adding all required features
4818	 *  @param {object} settings dataTables settings object
4819	 *  @memberof DataTable#oApi
4820	 */
4821	function _fnInitComplete ( settings )
4822	{
4823		if (settings._bInitComplete) {
4824			return;
4825		}
4826	
4827		var args = [settings, settings.json];
4828	
4829		settings._bInitComplete = true;
4830	
4831		// Table is fully set up and we have data, so calculate the
4832		// column widths
4833		_fnAdjustColumnSizing( settings );
4834	
4835		_fnCallbackFire( settings, null, 'plugin-init', args, true );
4836		_fnCallbackFire( settings, 'aoInitComplete', 'init', args, true );
4837	}
4838	
4839	function _fnLengthChange ( settings, val )
4840	{
4841		var len = parseInt( val, 10 );
4842		settings._iDisplayLength = len;
4843	
4844		_fnLengthOverflow( settings );
4845	
4846		// Fire length change event
4847		_fnCallbackFire( settings, null, 'length', [settings, len] );
4848	}
4849	
4850	/**
4851	 * Alter the display settings to change the page
4852	 *  @param {object} settings DataTables settings object
4853	 *  @param {string|int} action Paging action to take: "first", "previous",
4854	 *    "next" or "last" or page number to jump to (integer)
4855	 *  @param [bool] redraw Automatically draw the update or not
4856	 *  @returns {bool} true page has changed, false - no change
4857	 *  @memberof DataTable#oApi
4858	 */
4859	function _fnPageChange ( settings, action, redraw )
4860	{
4861		var
4862			start     = settings._iDisplayStart,
4863			len       = settings._iDisplayLength,
4864			records   = settings.fnRecordsDisplay();
4865	
4866		if ( records === 0 || len === -1 )
4867		{
4868			start = 0;
4869		}
4870		else if ( typeof action === "number" )
4871		{
4872			start = action * len;
4873	
4874			if ( start > records )
4875			{
4876				start = 0;
4877			}
4878		}
4879		else if ( action == "first" )
4880		{
4881			start = 0;
4882		}
4883		else if ( action == "previous" )
4884		{
4885			start = len >= 0 ?
4886				start - len :
4887				0;
4888	
4889			if ( start < 0 )
4890			{
4891				start = 0;
4892			}
4893		}
4894		else if ( action == "next" )
4895		{
4896			if ( start + len < records )
4897			{
4898				start += len;
4899			}
4900		}
4901		else if ( action == "last" )
4902		{
4903			start = Math.floor( (records-1) / len) * len;
4904		}
4905		else if ( action === 'ellipsis' )
4906		{
4907			return;
4908		}
4909		else
4910		{
4911			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4912		}
4913	
4914		var changed = settings._iDisplayStart !== start;
4915		settings._iDisplayStart = start;
4916	
4917		_fnCallbackFire( settings, null, changed ? 'page' : 'page-nc', [settings] );
4918	
4919		if ( changed && redraw ) {
4920			_fnDraw( settings );
4921		}
4922	
4923		return changed;
4924	}
4925	
4926	
4927	/**
4928	 * Generate the node required for the processing node
4929	 *  @param {object} settings DataTables settings object
4930	 */
4931	function _processingHtml ( settings )
4932	{
4933		var table = settings.nTable;
4934		var scrolling = settings.oScroll.sX !== '' || settings.oScroll.sY !== '';
4935	
4936		if ( settings.oFeatures.bProcessing ) {
4937			var n = $('<div/>', {
4938					'id': settings.sTableId + '_processing',
4939					'class': settings.oClasses.processing.container,
4940					'role': 'status'
4941				} )
4942				.html( settings.oLanguage.sProcessing )
4943				.append('<div><div></div><div></div><div></div><div></div></div>');
4944	
4945			// Different positioning depending on if scrolling is enabled or not
4946			if (scrolling) {
4947				n.prependTo( $('div.dt-scroll', settings.nTableWrapper) );
4948			}
4949			else {
4950				n.insertBefore( table );
4951			}
4952	
4953			$(table).on( 'processing.dt.DT', function (e, s, show) {
4954				n.css( 'display', show ? 'block' : 'none' );
4955			} );
4956		}
4957	}
4958	
4959	
4960	/**
4961	 * Display or hide the processing indicator
4962	 *  @param {object} settings DataTables settings object
4963	 *  @param {bool} show Show the processing indicator (true) or not (false)
4964	 */
4965	function _fnProcessingDisplay ( settings, show )
4966	{
4967		// Ignore cases when we are still redrawing
4968		if (settings.bDrawing && show === false) {
4969			return;
4970		}
4971	
4972		_fnCallbackFire( settings, null, 'processing', [settings, show] );
4973	}
4974	
4975	/**
4976	 * Show the processing element if an action takes longer than a given time
4977	 *
4978	 * @param {*} settings DataTables settings object
4979	 * @param {*} enable Do (true) or not (false) async processing (local feature enablement)
4980	 * @param {*} run Function to run
4981	 */
4982	function _fnProcessingRun( settings, enable, run ) {
4983		if (! enable) {
4984			// Immediate execution, synchronous
4985			run();
4986		}
4987		else {
4988			_fnProcessingDisplay(settings, true);
4989			
4990			// Allow the processing display to show if needed
4991			setTimeout(function () {
4992				run();
4993	
4994				_fnProcessingDisplay(settings, false);
4995			}, 0);
4996		}
4997	}
4998	/**
4999	 * Add any control elements for the table - specifically scrolling
5000	 *  @param {object} settings dataTables settings object
5001	 *  @returns {node} Node to add to the DOM
5002	 *  @memberof DataTable#oApi
5003	 */
5004	function _fnFeatureHtmlTable ( settings )
5005	{
5006		var table = $(settings.nTable);
5007	
5008		// Scrolling from here on in
5009		var scroll = settings.oScroll;
5010	
5011		if ( scroll.sX === '' && scroll.sY === '' ) {
5012			return settings.nTable;
5013		}
5014	
5015		var scrollX = scroll.sX;
5016		var scrollY = scroll.sY;
5017		var classes = settings.oClasses.scrolling;
5018		var caption = settings.captionNode;
5019		var captionSide = caption ? caption._captionSide : null;
5020		var headerClone = $( table[0].cloneNode(false) );
5021		var footerClone = $( table[0].cloneNode(false) );
5022		var footer = table.children('tfoot');
5023		var _div = '<div/>';
5024		var size = function ( s ) {
5025			return !s ? null : _fnStringToCss( s );
5026		};
5027	
5028		if ( ! footer.length ) {
5029			footer = null;
5030		}
5031	
5032		/*
5033		 * The HTML structure that we want to generate in this function is:
5034		 *  div - scroller
5035		 *    div - scroll head
5036		 *      div - scroll head inner
5037		 *        table - scroll head table
5038		 *          thead - thead
5039		 *    div - scroll body
5040		 *      table - table (master table)
5041		 *        thead - thead clone for sizing
5042		 *        tbody - tbody
5043		 *    div - scroll foot
5044		 *      div - scroll foot inner
5045		 *        table - scroll foot table
5046		 *          tfoot - tfoot
5047		 */
5048		var scroller = $( _div, { 'class': classes.container } )
5049			.append(
5050				$(_div, { 'class': classes.header.self } )
5051					.css( {
5052						overflow: 'hidden',
5053						position: 'relative',
5054						border: 0,
5055						width: scrollX ? size(scrollX) : '100%'
5056					} )
5057					.append(
5058						$(_div, { 'class': classes.header.inner } )
5059							.css( {
5060								'box-sizing': 'content-box',
5061								width: scroll.sXInner || '100%'
5062							} )
5063							.append(
5064								headerClone
5065									.removeAttr('id')
5066									.css( 'margin-left', 0 )
5067									.append( captionSide === 'top' ? caption : null )
5068									.append(
5069										table.children('thead')
5070									)
5071							)
5072					)
5073			)
5074			.append(
5075				$(_div, { 'class': classes.body } )
5076					.css( {
5077						position: 'relative',
5078						overflow: 'auto',
5079						width: size( scrollX )
5080					} )
5081					.append( table )
5082			);
5083	
5084		if ( footer ) {
5085			scroller.append(
5086				$(_div, { 'class': classes.footer.self } )
5087					.css( {
5088						overflow: 'hidden',
5089						border: 0,
5090						width: scrollX ? size(scrollX) : '100%'
5091					} )
5092					.append(
5093						$(_div, { 'class': classes.footer.inner } )
5094							.append(
5095								footerClone
5096									.removeAttr('id')
5097									.css( 'margin-left', 0 )
5098									.append( captionSide === 'bottom' ? caption : null )
5099									.append(
5100										table.children('tfoot')
5101									)
5102							)
5103					)
5104			);
5105		}
5106	
5107		var children = scroller.children();
5108		var scrollHead = children[0];
5109		var scrollBody = children[1];
5110		var scrollFoot = footer ? children[2] : null;
5111	
5112		// When the body is scrolled, then we also want to scroll the headers
5113		$(scrollBody).on( 'scroll.DT', function () {
5114			var scrollLeft = this.scrollLeft;
5115	
5116			scrollHead.scrollLeft = scrollLeft;
5117	
5118			if ( footer ) {
5119				scrollFoot.scrollLeft = scrollLeft;
5120			}
5121		} );
5122	
5123		// When focus is put on the header cells, we might need to scroll the body
5124		$('th, td', scrollHead).on('focus', function () {
5125			var scrollLeft = scrollHead.scrollLeft;
5126	
5127			scrollBody.scrollLeft = scrollLeft;
5128	
5129			if ( footer ) {
5130				scrollBody.scrollLeft = scrollLeft;
5131			}
5132		});
5133	
5134		$(scrollBody).css('max-height', scrollY);
5135		if (! scroll.bCollapse) {
5136			$(scrollBody).css('height', scrollY);
5137		}
5138	
5139		settings.nScrollHead = scrollHead;
5140		settings.nScrollBody = scrollBody;
5141		settings.nScrollFoot = scrollFoot;
5142	
5143		// On redraw - align columns
5144		settings.aoDrawCallback.push(_fnScrollDraw);
5145	
5146		return scroller[0];
5147	}
5148	
5149	
5150	
5151	/**
5152	 * Update the header, footer and body tables for resizing - i.e. column
5153	 * alignment.
5154	 *
5155	 * Welcome to the most horrible function DataTables. The process that this
5156	 * function follows is basically:
5157	 *   1. Re-create the table inside the scrolling div
5158	 *   2. Correct colgroup > col values if needed
5159	 *   3. Copy colgroup > col over to header and footer
5160	 *   4. Clean up
5161	 *
5162	 *  @param {object} settings dataTables settings object
5163	 *  @memberof DataTable#oApi
5164	 */
5165	function _fnScrollDraw ( settings )
5166	{
5167		// Given that this is such a monster function, a lot of variables are use
5168		// to try and keep the minimised size as small as possible
5169		var
5170			scroll         = settings.oScroll,
5171			barWidth       = scroll.iBarWidth,
5172			divHeader      = $(settings.nScrollHead),
5173			divHeaderInner = divHeader.children('div'),
5174			divHeaderTable = divHeaderInner.children('table'),
5175			divBodyEl      = settings.nScrollBody,
5176			divBody        = $(divBodyEl),
5177			divFooter      = $(settings.nScrollFoot),
5178			divFooterInner = divFooter.children('div'),
5179			divFooterTable = divFooterInner.children('table'),
5180			header         = $(settings.nTHead),
5181			table          = $(settings.nTable),
5182			footer         = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
5183			browser        = settings.oBrowser,
5184			headerCopy, footerCopy;
5185	
5186		// If the scrollbar visibility has changed from the last draw, we need to
5187		// adjust the column sizes as the table width will have changed to account
5188		// for the scrollbar
5189		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5190		
5191		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5192			settings.scrollBarVis = scrollBarVis;
5193			_fnAdjustColumnSizing( settings );
5194			return; // adjust column sizing will call this function again
5195		}
5196		else {
5197			settings.scrollBarVis = scrollBarVis;
5198		}
5199	
5200		// 1. Re-create the table inside the scrolling div
5201		// Remove the old minimised thead and tfoot elements in the inner table
5202		table.children('thead, tfoot').remove();
5203	
5204		// Clone the current header and footer elements and then place it into the inner table
5205		headerCopy = header.clone().prependTo( table );
5206		headerCopy.find('th, td').removeAttr('tabindex');
5207		headerCopy.find('[id]').removeAttr('id');
5208	
5209		if ( footer ) {
5210			footerCopy = footer.clone().prependTo( table );
5211			footerCopy.find('[id]').removeAttr('id');
5212		}
5213	
5214		// 2. Correct colgroup > col values if needed
5215		// It is possible that the cell sizes are smaller than the content, so we need to
5216		// correct colgroup>col for such cases. This can happen if the auto width detection
5217		// uses a cell which has a longer string, but isn't the widest! For example 
5218		// "Chief Executive Officer (CEO)" is the longest string in the demo, but
5219		// "Systems Administrator" is actually the widest string since it doesn't collapse.
5220		// Note the use of translating into a column index to get the `col` element. This
5221		// is because of Responsive which might remove `col` elements, knocking the alignment
5222		// of the indexes out.
5223		if (settings.aiDisplay.length) {
5224			// Get the column sizes from the first row in the table. This should really be a
5225			// [].find, but it wasn't supported in Chrome until Sept 2015, and DT has 10 year
5226			// browser support
5227			var firstTr = null;
5228			var start = _fnDataSource( settings ) !== 'ssp'
5229				? settings._iDisplayStart
5230				: 0;
5231	
5232			for (i=start ; i<start + settings.aiDisplay.length ; i++) {
5233				var idx = settings.aiDisplay[i];
5234				var tr = settings.aoData[idx].nTr;
5235	
5236				if (tr) {
5237					firstTr = tr;
5238					break;
5239				}
5240			}
5241	
5242			if (firstTr) {
5243				var colSizes = $(firstTr).children('th, td').map(function (vis) {
5244					return {
5245						idx: _fnVisibleToColumnIndex(settings, vis),
5246						width: $(this).outerWidth()
5247					};
5248				});
5249	
5250				// Check against what the colgroup > col is set to and correct if needed
5251				for (var i=0 ; i<colSizes.length ; i++) {
5252					var colEl = settings.aoColumns[ colSizes[i].idx ].colEl[0];
5253					var colWidth = colEl.style.width.replace('px', '');
5254	
5255					if (colWidth !== colSizes[i].width) {
5256						colEl.style.width = colSizes[i].width + 'px';
5257	
5258						if (scroll.sX) {
5259							colEl.style.minWidth = colSizes[i].width + 'px';
5260						}
5261					}
5262				}
5263			}
5264		}
5265	
5266		// 3. Copy the colgroup over to the header and footer
5267		divHeaderTable
5268			.find('colgroup')
5269			.remove();
5270	
5271		divHeaderTable.append(settings.colgroup.clone());
5272	
5273		if ( footer ) {
5274			divFooterTable
5275				.find('colgroup')
5276				.remove();
5277	
5278			divFooterTable.append(settings.colgroup.clone());
5279		}
5280	
5281		// "Hide" the header and footer that we used for the sizing. We need to keep
5282		// the content of the cell so that the width applied to the header and body
5283		// both match, but we want to hide it completely.
5284		$('th, td', headerCopy).each(function () {
5285			$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5286		});
5287	
5288		if ( footer ) {
5289			$('th, td', footerCopy).each(function () {
5290				$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5291			});
5292		}
5293	
5294		// 4. Clean up
5295		// Figure out if there are scrollbar present - if so then we need a the header and footer to
5296		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5297		var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5298		var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5299	
5300		// Set the width's of the header and footer tables
5301		var outerWidth = table.outerWidth();
5302	
5303		divHeaderTable.css('width', _fnStringToCss( outerWidth ));
5304		divHeaderInner
5305			.css('width', _fnStringToCss( outerWidth ))
5306			.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5307	
5308		if ( footer ) {
5309			divFooterTable.css('width', _fnStringToCss( outerWidth ));
5310			divFooterInner
5311				.css('width', _fnStringToCss( outerWidth ))
5312				.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5313		}
5314	
5315		// Correct DOM ordering for colgroup - comes before the thead
5316		table.children('colgroup').prependTo(table);
5317	
5318		// Adjust the position of the header in case we loose the y-scrollbar
5319		divBody.trigger('scroll');
5320	
5321		// If sorting or filtering has occurred, jump the scrolling back to the top
5322		// only if we aren't holding the position
5323		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5324			divBodyEl.scrollTop = 0;
5325		}
5326	}
5327	
5328	/**
5329	 * Calculate the width of columns for the table
5330	 *  @param {object} settings dataTables settings object
5331	 *  @memberof DataTable#oApi
5332	 */
5333	function _fnCalculateColumnWidths ( settings )
5334	{
5335		// Not interested in doing column width calculation if auto-width is disabled
5336		if (! settings.oFeatures.bAutoWidth) {
5337			return;
5338		}
5339	
5340		var
5341			table = settings.nTable,
5342			columns = settings.aoColumns,
5343			scroll = settings.oScroll,
5344			scrollY = scroll.sY,
5345			scrollX = scroll.sX,
5346			scrollXInner = scroll.sXInner,
5347			visibleColumns = _fnGetColumns( settings, 'bVisible' ),
5348			tableWidthAttr = table.getAttribute('width'), // from DOM element
5349			tableContainer = table.parentNode,
5350			i, column, columnIdx;
5351			
5352		var styleWidth = table.style.width;
5353		var containerWidth = _fnWrapperWidth(settings);
5354	
5355		// Don't re-run for the same width as the last time
5356		if (containerWidth === settings.containerWidth) {
5357			return false;
5358		}
5359	
5360		settings.containerWidth = containerWidth;
5361	
5362		// If there is no width applied as a CSS style or as an attribute, we assume that
5363		// the width is intended to be 100%, which is usually is in CSS, but it is very
5364		// difficult to correctly parse the rules to get the final result.
5365		if ( ! styleWidth && ! tableWidthAttr) {
5366			table.style.width = '100%';
5367			styleWidth = '100%';
5368		}
5369	
5370		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5371			tableWidthAttr = styleWidth;
5372		}
5373	
5374		// Let plug-ins know that we are doing a recalc, in case they have changed any of the
5375		// visible columns their own way (e.g. Responsive uses display:none).
5376		_fnCallbackFire(
5377			settings,
5378			null,
5379			'column-calc',
5380			{visible: visibleColumns},
5381			false
5382		);
5383	
5384		// Construct a single row, worst case, table with the widest
5385		// node in the data, assign any user defined widths, then insert it into
5386		// the DOM and allow the browser to do all the hard work of calculating
5387		// table widths
5388		var tmpTable = $(table.cloneNode())
5389			.css( 'visibility', 'hidden' )
5390			.removeAttr( 'id' );
5391	
5392		// Clean up the table body
5393		tmpTable.append('<tbody>')
5394		var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5395	
5396		// Clone the table header and footer - we can't use the header / footer
5397		// from the cloned table, since if scrolling is active, the table's
5398		// real header and footer are contained in different table tags
5399		tmpTable
5400			.append( $(settings.nTHead).clone() )
5401			.append( $(settings.nTFoot).clone() );
5402	
5403		// Remove any assigned widths from the footer (from scrolling)
5404		tmpTable.find('tfoot th, tfoot td').css('width', '');
5405	
5406		// Apply custom sizing to the cloned header
5407		tmpTable.find('thead th, thead td').each( function () {
5408			// Get the `width` from the header layout
5409			var width = _fnColumnsSumWidth( settings, this, true, false );
5410	
5411			if ( width ) {
5412				this.style.width = width;
5413	
5414				// For scrollX we need to force the column width otherwise the
5415				// browser will collapse it. If this width is smaller than the
5416				// width the column requires, then it will have no effect
5417				if ( scrollX ) {
5418					this.style.minWidth = width;
5419	
5420					$( this ).append( $('<div/>').css( {
5421						width: width,
5422						margin: 0,
5423						padding: 0,
5424						border: 0,
5425						height: 1
5426					} ) );
5427				}
5428			}
5429			else {
5430				this.style.width = '';
5431			}
5432		} );
5433	
5434		// Find the widest piece of data for each column and put it into the table
5435		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5436			columnIdx = visibleColumns[i];
5437			column = columns[ columnIdx ];
5438	
5439			var longest = _fnGetMaxLenString(settings, columnIdx);
5440			var autoClass = _ext.type.className[column.sType];
5441			var text = longest + column.sContentPadding;
5442			var insert = longest.indexOf('<') === -1
5443				? document.createTextNode(text)
5444				: text
5445			
5446			$('<td/>')
5447				.addClass(autoClass)
5448				.addClass(column.sClass)
5449				.append(insert)
5450				.appendTo(tr);
5451		}
5452	
5453		// Tidy the temporary table - remove name attributes so there aren't
5454		// duplicated in the dom (radio elements for example)
5455		$('[name]', tmpTable).removeAttr('name');
5456	
5457		// Table has been built, attach to the document so we can work with it.
5458		// A holding element is used, positioned at the top of the container
5459		// with minimal height, so it has no effect on if the container scrolls
5460		// or not. Otherwise it might trigger scrolling when it actually isn't
5461		// needed
5462		var holder = $('<div/>').css( scrollX || scrollY ?
5463				{
5464					position: 'absolute',
5465					top: 0,
5466					left: 0,
5467					height: 1,
5468					right: 0,
5469					overflow: 'hidden'
5470				} :
5471				{}
5472			)
5473			.append( tmpTable )
5474			.appendTo( tableContainer );
5475	
5476		// When scrolling (X or Y) we want to set the width of the table as 
5477		// appropriate. However, when not scrolling leave the table width as it
5478		// is. This results in slightly different, but I think correct behaviour
5479		if ( scrollX && scrollXInner ) {
5480			tmpTable.width( scrollXInner );
5481		}
5482		else if ( scrollX ) {
5483			tmpTable.css( 'width', 'auto' );
5484			tmpTable.removeAttr('width');
5485	
5486			// If there is no width attribute or style, then allow the table to
5487			// collapse
5488			if ( tmpTable.outerWidth() < tableContainer.clientWidth && tableWidthAttr ) {
5489				tmpTable.outerWidth( tableContainer.clientWidth );
5490			}
5491		}
5492		else if ( scrollY ) {
5493			tmpTable.outerWidth( tableContainer.clientWidth );
5494		}
5495		else if ( tableWidthAttr ) {
5496			tmpTable.outerWidth( tableWidthAttr );
5497		}
5498	
5499		// Get the width of each column in the constructed table
5500		var total = 0;
5501		var bodyCells = tmpTable.find('tbody tr').eq(0).children();
5502	
5503		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5504			// Use getBounding for sub-pixel accuracy, which we then want to round up!
5505			var bounding = bodyCells[i].getBoundingClientRect().width;
5506	
5507			// Total is tracked to remove any sub-pixel errors as the outerWidth
5508			// of the table might not equal the total given here
5509			total += bounding;
5510	
5511			// Width for each column to use
5512			columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding );
5513		}
5514	
5515		table.style.width = _fnStringToCss( total );
5516	
5517		// Finished with the table - ditch it
5518		holder.remove();
5519	
5520		// If there is a width attr, we want to attach an event listener which
5521		// allows the table sizing to automatically adjust when the window is
5522		// resized. Use the width attr rather than CSS, since we can't know if the
5523		// CSS is a relative value or absolute - DOM read is always px.
5524		if ( tableWidthAttr ) {
5525			table.style.width = _fnStringToCss( tableWidthAttr );
5526		}
5527	
5528		if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
5529			var resize = DataTable.util.throttle( function () {
5530				var newWidth = _fnWrapperWidth(settings);
5531	
5532				// Don't do it if destroying or the container width is 0
5533				if (! settings.bDestroying && newWidth !== 0) {
5534					_fnAdjustColumnSizing( settings );
5535				}
5536			} );
5537	
5538			// For browsers that support it (~2020 onwards for wide support) we can watch for the
5539			// container changing width.
5540			if (window.ResizeObserver) {
5541				// This is a tricky beast - if the element is visible when `.observe()` is called,
5542				// then the callback is immediately run. Which we don't want. If the element isn't
5543				// visible, then it isn't run, but we want it to run when it is then made visible.
5544				// This flag allows the above to be satisfied.
5545				var first = $(settings.nTableWrapper).is(':visible');
5546	
5547				// Use an empty div to attach the observer so it isn't impacted by height changes
5548				var resizer = $('<div>')
5549					.css({
5550						width: '100%',
5551						height: 0
5552					})
5553					.addClass('dt-autosize')
5554					.appendTo(settings.nTableWrapper);
5555	
5556				settings.resizeObserver = new ResizeObserver(function (e) {
5557					if (first) {
5558						first = false;
5559					}
5560					else {
5561						resize();
5562					}
5563				});
5564	
5565				settings.resizeObserver.observe(resizer[0]);
5566			}
5567			else {
5568				// For old browsers, the best we can do is listen for a window resize
5569				$(window).on('resize.DT-'+settings.sInstance, resize);
5570			}
5571	
5572			settings._reszEvt = true;
5573		}
5574	}
5575	
5576	/**
5577	 * Get the width of the DataTables wrapper element
5578	 *
5579	 * @param {*} settings DataTables settings object
5580	 * @returns Width
5581	 */
5582	function _fnWrapperWidth(settings) {
5583		return $(settings.nTableWrapper).is(':visible')
5584			? $(settings.nTableWrapper).width()
5585			: 0;
5586	}
5587	
5588	/**
5589	 * Get the maximum strlen for each data column
5590	 *  @param {object} settings dataTables settings object
5591	 *  @param {int} colIdx column of interest
5592	 *  @returns {string} string of the max length
5593	 *  @memberof DataTable#oApi
5594	 */
5595	function _fnGetMaxLenString( settings, colIdx )
5596	{
5597		var column = settings.aoColumns[colIdx];
5598	
5599		if (! column.maxLenString) {
5600			var s, max='', maxLen = -1;
5601		
5602			for ( var i=0, ien=settings.aiDisplayMaster.length ; i<ien ; i++ ) {
5603				var rowIdx = settings.aiDisplayMaster[i];
5604				var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
5605	
5606				var cellString = data && typeof data === 'object' && data.nodeType
5607					? data.innerHTML
5608					: data+'';
5609	
5610				// Remove id / name attributes from elements so they
5611				// don't interfere with existing elements
5612				cellString = cellString
5613					.replace(/id=".*?"/g, '')
5614					.replace(/name=".*?"/g, '');
5615	
5616				s = _stripHtml(cellString)
5617					.replace( /&nbsp;/g, ' ' );
5618		
5619				if ( s.length > maxLen ) {
5620					// We want the HTML in the string, but the length that
5621					// is important is the stripped string
5622					max = cellString;
5623					maxLen = s.length;
5624				}
5625			}
5626	
5627			column.maxLenString = max;
5628		}
5629	
5630		return column.maxLenString;
5631	}
5632	
5633	
5634	/**
5635	 * Append a CSS unit (only if required) to a string
5636	 *  @param {string} value to css-ify
5637	 *  @returns {string} value with css unit
5638	 *  @memberof DataTable#oApi
5639	 */
5640	function _fnStringToCss( s )
5641	{
5642		if ( s === null ) {
5643			return '0px';
5644		}
5645	
5646		if ( typeof s == 'number' ) {
5647			return s < 0 ?
5648				'0px' :
5649				s+'px';
5650		}
5651	
5652		// Check it has a unit character already
5653		return s.match(/\d$/) ?
5654			s+'px' :
5655			s;
5656	}
5657	
5658	/**
5659	 * Re-insert the `col` elements for current visibility
5660	 *
5661	 * @param {*} settings DT settings
5662	 */
5663	function _colGroup( settings ) {
5664		var cols = settings.aoColumns;
5665	
5666		settings.colgroup.empty();
5667	
5668		for (i=0 ; i<cols.length ; i++) {
5669			if (cols[i].bVisible) {
5670				settings.colgroup.append(cols[i].colEl);
5671			}
5672		}
5673	}
5674	
5675	
5676	function _fnSortInit( settings ) {
5677		var target = settings.nTHead;
5678		var headerRows = target.querySelectorAll('tr');
5679		var legacyTop = settings.bSortCellsTop;
5680		var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5681		
5682		// Legacy support for `orderCellsTop`
5683		if (legacyTop === true) {
5684			target = headerRows[0];
5685		}
5686		else if (legacyTop === false) {
5687			target = headerRows[ headerRows.length - 1 ];
5688		}
5689	
5690		_fnSortAttachListener(
5691			settings,
5692			target,
5693			target === settings.nTHead
5694				? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5695				: 'th'+notSelector+', td'+notSelector
5696		);
5697	
5698		// Need to resolve the user input array into our internal structure
5699		var order = [];
5700		_fnSortResolve( settings, order, settings.aaSorting );
5701	
5702		settings.aaSorting = order;
5703	}
5704	
5705	
5706	function _fnSortAttachListener(settings, node, selector, column, callback) {
5707		_fnBindAction( node, selector, function (e) {
5708			var run = false;
5709			var columns = column === undefined
5710				? _fnColumnsFromHeader( e.target )
5711				: [column];
5712	
5713			if ( columns.length ) {
5714				for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
5715					var ret = _fnSortAdd( settings, columns[i], i, e.shiftKey );
5716	
5717					if (ret !== false) {
5718						run = true;
5719					}					
5720	
5721					// If the first entry is no sort, then subsequent
5722					// sort columns are ignored
5723					if (settings.aaSorting.length === 1 && settings.aaSorting[0][1] === '') {
5724						break;
5725					}
5726				}
5727	
5728				if (run) {
5729					_fnProcessingRun(settings, true, function () {
5730						_fnSort( settings );
5731						_fnSortDisplay( settings, settings.aiDisplay );
5732	
5733						_fnReDraw( settings, false, false );
5734	
5735						if (callback) {
5736							callback();
5737						}
5738					});
5739				}
5740			}
5741		} );
5742	}
5743	
5744	/**
5745	 * Sort the display array to match the master's order
5746	 * @param {*} settings
5747	 */
5748	function _fnSortDisplay(settings, display) {
5749		if (display.length < 2) {
5750			return;
5751		}
5752	
5753		var master = settings.aiDisplayMaster;
5754		var masterMap = {};
5755		var map = {};
5756		var i;
5757	
5758		// Rather than needing an `indexOf` on master array, we can create a map
5759		for (i=0 ; i<master.length ; i++) {
5760			masterMap[master[i]] = i;
5761		}
5762	
5763		// And then cache what would be the indexOf fom the display
5764		for (i=0 ; i<display.length ; i++) {
5765			map[display[i]] = masterMap[display[i]];
5766		}
5767	
5768		display.sort(function(a, b){
5769			// Short version of this function is simply `master.indexOf(a) - master.indexOf(b);`
5770			return map[a] - map[b];
5771		});
5772	}
5773	
5774	
5775	function _fnSortResolve (settings, nestedSort, sort) {
5776		var push = function ( a ) {
5777			if ($.isPlainObject(a)) {
5778				if (a.idx !== undefined) {
5779					// Index based ordering
5780					nestedSort.push([a.idx, a.dir]);
5781				}
5782				else if (a.name) {
5783					// Name based ordering
5784					var cols = _pluck( settings.aoColumns, 'sName');
5785					var idx = cols.indexOf(a.name);
5786	
5787					if (idx !== -1) {
5788						nestedSort.push([idx, a.dir]);
5789					}
5790				}
5791			}
5792			else {
5793				// Plain column index and direction pair
5794				nestedSort.push(a);
5795			}
5796		};
5797	
5798		if ( $.isPlainObject(sort) ) {
5799			// Object
5800			push(sort);
5801		}
5802		else if ( sort.length && typeof sort[0] === 'number' ) {
5803			// 1D array
5804			push(sort);
5805		}
5806		else if ( sort.length ) {
5807			// 2D array
5808			for (var z=0; z<sort.length; z++) {
5809				push(sort[z]); // Object or array
5810			}
5811		}
5812	}
5813	
5814	
5815	function _fnSortFlatten ( settings )
5816	{
5817		var
5818			i, k, kLen,
5819			aSort = [],
5820			extSort = DataTable.ext.type.order,
5821			aoColumns = settings.aoColumns,
5822			aDataSort, iCol, sType, srcCol,
5823			fixed = settings.aaSortingFixed,
5824			fixedObj = $.isPlainObject( fixed ),
5825			nestedSort = [];
5826		
5827		if ( ! settings.oFeatures.bSort ) {
5828			return aSort;
5829		}
5830	
5831		// Build the sort array, with pre-fix and post-fix options if they have been
5832		// specified
5833		if ( Array.isArray( fixed ) ) {
5834			_fnSortResolve( settings, nestedSort, fixed );
5835		}
5836	
5837		if ( fixedObj && fixed.pre ) {
5838			_fnSortResolve( settings, nestedSort, fixed.pre );
5839		}
5840	
5841		_fnSortResolve( settings, nestedSort, settings.aaSorting );
5842	
5843		if (fixedObj && fixed.post ) {
5844			_fnSortResolve( settings, nestedSort, fixed.post );
5845		}
5846	
5847		for ( i=0 ; i<nestedSort.length ; i++ )
5848		{
5849			srcCol = nestedSort[i][0];
5850	
5851			if ( aoColumns[ srcCol ] ) {
5852				aDataSort = aoColumns[ srcCol ].aDataSort;
5853	
5854				for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5855				{
5856					iCol = aDataSort[k];
5857					sType = aoColumns[ iCol ].sType || 'string';
5858	
5859					if ( nestedSort[i]._idx === undefined ) {
5860						nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
5861					}
5862	
5863					if ( nestedSort[i][1] ) {
5864						aSort.push( {
5865							src:       srcCol,
5866							col:       iCol,
5867							dir:       nestedSort[i][1],
5868							index:     nestedSort[i]._idx,
5869							type:      sType,
5870							formatter: extSort[ sType+"-pre" ],
5871							sorter:    extSort[ sType+"-"+nestedSort[i][1] ]
5872						} );
5873					}
5874				}
5875			}
5876		}
5877	
5878		return aSort;
5879	}
5880	
5881	/**
5882	 * Change the order of the table
5883	 *  @param {object} oSettings dataTables settings object
5884	 *  @memberof DataTable#oApi
5885	 */
5886	function _fnSort ( oSettings, col, dir )
5887	{
5888		var
5889			i, ien, iLen,
5890			aiOrig = [],
5891			extSort = DataTable.ext.type.order,
5892			aoData = oSettings.aoData,
5893			sortCol,
5894			displayMaster = oSettings.aiDisplayMaster,
5895			aSort;
5896	
5897		// Make sure the columns all have types defined
5898		_fnColumnTypes(oSettings);
5899	
5900		// Allow a specific column to be sorted, which will _not_ alter the display
5901		// master
5902		if (col !== undefined) {
5903			var srcCol = oSettings.aoColumns[col];
5904	
5905			aSort = [{
5906				src:       col,
5907				col:       col,
5908				dir:       dir,
5909				index:     0,
5910				type:      srcCol.sType,
5911				formatter: extSort[ srcCol.sType+"-pre" ],
5912				sorter:    extSort[ srcCol.sType+"-"+dir ]
5913			}];
5914			displayMaster = displayMaster.slice();
5915		}
5916		else {
5917			aSort = _fnSortFlatten( oSettings );
5918		}
5919	
5920		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5921			sortCol = aSort[i];
5922	
5923			// Load the data needed for the sort, for each cell
5924			_fnSortData( oSettings, sortCol.col );
5925		}
5926	
5927		/* No sorting required if server-side or no sorting array */
5928		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5929		{
5930			// Reset the initial positions on each pass so we get a stable sort
5931			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5932				aiOrig[ i ] = i;
5933			}
5934	
5935			// If the first sort is desc, then reverse the array to preserve original
5936			// order, just in reverse
5937			if (aSort.length && aSort[0].dir === 'desc' && oSettings.orderDescReverse) {
5938				aiOrig.reverse();
5939			}
5940	
5941			/* Do the sort - here we want multi-column sorting based on a given data source (column)
5942			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5943			 * follow on it's own, but this is what we want (example two column sorting):
5944			 *  fnLocalSorting = function(a,b){
5945			 *    var test;
5946			 *    test = oSort['string-asc']('data11', 'data12');
5947			 *      if (test !== 0)
5948			 *        return test;
5949			 *    test = oSort['numeric-desc']('data21', 'data22');
5950			 *    if (test !== 0)
5951			 *      return test;
5952			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5953			 *  }
5954			 * Basically we have a test for each sorting column, if the data in that column is equal,
5955			 * test the next column. If all columns match, then we use a numeric sort on the row
5956			 * positions in the original data array to provide a stable sort.
5957			 */
5958			displayMaster.sort( function ( a, b ) {
5959				var
5960					x, y, k, test, sort,
5961					len=aSort.length,
5962					dataA = aoData[a]._aSortData,
5963					dataB = aoData[b]._aSortData;
5964	
5965				for ( k=0 ; k<len ; k++ ) {
5966					sort = aSort[k];
5967	
5968					// Data, which may have already been through a `-pre` function
5969					x = dataA[ sort.col ];
5970					y = dataB[ sort.col ];
5971	
5972					if (sort.sorter) {
5973						// If there is a custom sorter (`-asc` or `-desc`) for this
5974						// data type, use it
5975						test = sort.sorter(x, y);
5976	
5977						if ( test !== 0 ) {
5978							return test;
5979						}
5980					}
5981					else {
5982						// Otherwise, use generic sorting
5983						test = x<y ? -1 : x>y ? 1 : 0;
5984	
5985						if ( test !== 0 ) {
5986							return sort.dir === 'asc' ? test : -test;
5987						}
5988					}
5989				}
5990	
5991				x = aiOrig[a];
5992				y = aiOrig[b];
5993	
5994				return x<y ? -1 : x>y ? 1 : 0;
5995			} );
5996		}
5997		else if ( aSort.length === 0 ) {
5998			// Apply index order
5999			displayMaster.sort(function (x, y) {
6000				return x<y ? -1 : x>y ? 1 : 0;
6001			});
6002		}
6003	
6004		if (col === undefined) {
6005			// Tell the draw function that we have sorted the data
6006			oSettings.bSorted = true;
6007			oSettings.sortDetails = aSort;
6008	
6009			_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort] );
6010		}
6011	
6012		return displayMaster;
6013	}
6014	
6015	
6016	/**
6017	 * Function to run on user sort request
6018	 *  @param {object} settings dataTables settings object
6019	 *  @param {node} attachTo node to attach the handler to
6020	 *  @param {int} colIdx column sorting index
6021	 *  @param {int} addIndex Counter
6022	 *  @param {boolean} [shift=false] Shift click add
6023	 *  @param {function} [callback] callback function
6024	 *  @memberof DataTable#oApi
6025	 */
6026	function _fnSortAdd ( settings, colIdx, addIndex, shift )
6027	{
6028		var col = settings.aoColumns[ colIdx ];
6029		var sorting = settings.aaSorting;
6030		var asSorting = col.asSorting;
6031		var nextSortIdx;
6032		var next = function ( a, overflow ) {
6033			var idx = a._idx;
6034			if ( idx === undefined ) {
6035				idx = asSorting.indexOf(a[1]);
6036			}
6037	
6038			return idx+1 < asSorting.length ?
6039				idx+1 :
6040				overflow ?
6041					null :
6042					0;
6043		};
6044	
6045		if ( ! col.bSortable ) {
6046			return false;
6047		}
6048	
6049		// Convert to 2D array if needed
6050		if ( typeof sorting[0] === 'number' ) {
6051			sorting = settings.aaSorting = [ sorting ];
6052		}
6053	
6054		// If appending the sort then we are multi-column sorting
6055		if ( (shift || addIndex) && settings.oFeatures.bSortMulti ) {
6056			// Are we already doing some kind of sort on this column?
6057			var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
6058	
6059			if ( sortIdx !== -1 ) {
6060				// Yes, modify the sort
6061				nextSortIdx = next( sorting[sortIdx], true );
6062	
6063				if ( nextSortIdx === null && sorting.length === 1 ) {
6064					nextSortIdx = 0; // can't remove sorting completely
6065				}
6066	
6067				if ( nextSortIdx === null ) {
6068					sorting.splice( sortIdx, 1 );
6069				}
6070				else {
6071					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6072					sorting[sortIdx]._idx = nextSortIdx;
6073				}
6074			}
6075			else if (shift) {
6076				// No sort on this column yet, being added by shift click
6077				// add it as itself
6078				sorting.push( [ colIdx, asSorting[0], 0 ] );
6079				sorting[sorting.length-1]._idx = 0;
6080			}
6081			else {
6082				// No sort on this column yet, being added from a colspan
6083				// so add with same direction as first column
6084				sorting.push( [ colIdx, sorting[0][1], 0 ] );
6085				sorting[sorting.length-1]._idx = 0;
6086			}
6087		}
6088		else if ( sorting.length && sorting[0][0] == colIdx ) {
6089			// Single column - already sorting on this column, modify the sort
6090			nextSortIdx = next( sorting[0] );
6091	
6092			sorting.length = 1;
6093			sorting[0][1] = asSorting[ nextSortIdx ];
6094			sorting[0]._idx = nextSortIdx;
6095		}
6096		else {
6097			// Single column - sort only on this column
6098			sorting.length = 0;
6099			sorting.push( [ colIdx, asSorting[0] ] );
6100			sorting[0]._idx = 0;
6101		}
6102	}
6103	
6104	
6105	/**
6106	 * Set the sorting classes on table's body, Note: it is safe to call this function
6107	 * when bSort and bSortClasses are false
6108	 *  @param {object} oSettings dataTables settings object
6109	 *  @memberof DataTable#oApi
6110	 */
6111	function _fnSortingClasses( settings )
6112	{
6113		var oldSort = settings.aLastSort;
6114		var sortClass = settings.oClasses.order.position;
6115		var sort = _fnSortFlatten( settings );
6116		var features = settings.oFeatures;
6117		var i, ien, colIdx;
6118	
6119		if ( features.bSort && features.bSortClasses ) {
6120			// Remove old sorting classes
6121			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6122				colIdx = oldSort[i].src;
6123	
6124				// Remove column sorting
6125				$( _pluck( settings.aoData, 'anCells', colIdx ) )
6126					.removeClass( sortClass + (i<2 ? i+1 : 3) );
6127			}
6128	
6129			// Add new column sorting
6130			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6131				colIdx = sort[i].src;
6132	
6133				$( _pluck( settings.aoData, 'anCells', colIdx ) )
6134					.addClass( sortClass + (i<2 ? i+1 : 3) );
6135			}
6136		}
6137	
6138		settings.aLastSort = sort;
6139	}
6140	
6141	
6142	// Get the data to sort a column, be it from cache, fresh (populating the
6143	// cache), or from a sort formatter
6144	function _fnSortData( settings, colIdx )
6145	{
6146		// Custom sorting function - provided by the sort data type
6147		var column = settings.aoColumns[ colIdx ];
6148		var customSort = DataTable.ext.order[ column.sSortDataType ];
6149		var customData;
6150	
6151		if ( customSort ) {
6152			customData = customSort.call( settings.oInstance, settings, colIdx,
6153				_fnColumnIndexToVisible( settings, colIdx )
6154			);
6155		}
6156	
6157		// Use / populate cache
6158		var row, cellData;
6159		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6160		var data = settings.aoData;
6161	
6162		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
6163			// Sparse array
6164			if (! data[rowIdx]) {
6165				continue;
6166			}
6167	
6168			row = data[rowIdx];
6169	
6170			if ( ! row._aSortData ) {
6171				row._aSortData = [];
6172			}
6173	
6174			if ( ! row._aSortData[colIdx] || customSort ) {
6175				cellData = customSort ?
6176					customData[rowIdx] : // If there was a custom sort function, use data from there
6177					_fnGetCellData( settings, rowIdx, colIdx, 'sort' );
6178	
6179				row._aSortData[ colIdx ] = formatter ?
6180					formatter( cellData, settings ) :
6181					cellData;
6182			}
6183		}
6184	}
6185	
6186	
6187	/**
6188	 * State information for a table
6189	 *
6190	 * @param {*} settings
6191	 * @returns State object
6192	 */
6193	function _fnSaveState ( settings )
6194	{
6195		if (settings._bLoadingState) {
6196			return;
6197		}
6198	
6199		// Sort state saving uses [[idx, order]] structure.
6200		var sorting = [];
6201		_fnSortResolve(settings, sorting, settings.aaSorting );
6202	
6203		/* Store the interesting variables */
6204		var columns = settings.aoColumns;
6205		var state = {
6206			time:    +new Date(),
6207			start:   settings._iDisplayStart,
6208			length:  settings._iDisplayLength,
6209			order:   sorting.map(function (sort) {
6210				// If a column name is available, use it
6211				return columns[sort[0]] && columns[sort[0]].sName
6212					? [ columns[sort[0]].sName, sort[1] ]
6213					: sort.slice();
6214			} ),
6215			search:  $.extend({}, settings.oPreviousSearch),
6216			columns: settings.aoColumns.map( function ( col, i ) {
6217				return {
6218					name: col.sName,
6219					visible: col.bVisible,
6220					search: $.extend({}, settings.aoPreSearchCols[i])
6221				};
6222			} )
6223		};
6224	
6225		settings.oSavedState = state;
6226		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6227		
6228		if ( settings.oFeatures.bStateSave && !settings.bDestroying )
6229		{
6230			settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6231		}	
6232	}
6233	
6234	
6235	/**
6236	 * Attempt to load a saved table state
6237	 *  @param {object} oSettings dataTables settings object
6238	 *  @param {object} oInit DataTables init object so we can override settings
6239	 *  @param {function} callback Callback to execute when the state has been loaded
6240	 *  @memberof DataTable#oApi
6241	 */
6242	function _fnLoadState ( settings, init, callback )
6243	{
6244		if ( ! settings.oFeatures.bStateSave ) {
6245			callback();
6246			return;
6247		}
6248	
6249		var loaded = function(state) {
6250			_fnImplementState(settings, state, callback);
6251		}
6252	
6253		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6254	
6255		if ( state !== undefined ) {
6256			_fnImplementState( settings, state, callback );
6257		}
6258		// otherwise, wait for the loaded callback to be executed
6259	
6260		return true;
6261	}
6262	
6263	function _fnImplementState ( settings, s, callback) {
6264		var i, ien;
6265		var columns = settings.aoColumns;
6266		var currentNames = _pluck(settings.aoColumns, 'sName');
6267	
6268		settings._bLoadingState = true;
6269	
6270		// When StateRestore was introduced the state could now be implemented at any time
6271		// Not just initialisation. To do this an api instance is required in some places
6272		var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
6273	
6274		if ( ! s || ! s.time ) {
6275			settings._bLoadingState = false;
6276			callback();
6277			return;
6278		}
6279	
6280		// Reject old data
6281		var duration = settings.iStateDuration;
6282		if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6283			settings._bLoadingState = false;
6284			callback();
6285			return;
6286		}
6287	
6288		// Allow custom and plug-in manipulation functions to alter the saved data set and
6289		// cancelling of loading by returning false
6290		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6291		if ( abStateLoad.indexOf(false) !== -1 ) {
6292			settings._bLoadingState = false;
6293			callback();
6294			return;
6295		}
6296	
6297		// Store the saved state so it might be accessed at any time
6298		settings.oLoadedState = $.extend( true, {}, s );
6299	
6300		// This is needed for ColReorder, which has to happen first to allow all
6301		// the stored indexes to be usable. It is not publicly documented.
6302		_fnCallbackFire( settings, null, 'stateLoadInit', [settings, s], true );
6303	
6304		// Page Length
6305		if ( s.length !== undefined ) {
6306			// If already initialised just set the value directly so that the select element is also updated
6307			if (api) {
6308				api.page.len(s.length)
6309			}
6310			else {
6311				settings._iDisplayLength   = s.length;
6312			}
6313		}
6314	
6315		// Restore key features
6316		if ( s.start !== undefined ) {
6317			if(api === null) {
6318				settings._iDisplayStart    = s.start;
6319				settings.iInitDisplayStart = s.start;
6320			}
6321			else {
6322				_fnPageChange(settings, s.start/settings._iDisplayLength);
6323			}
6324		}
6325	
6326		// Order
6327		if ( s.order !== undefined ) {
6328			settings.aaSorting = [];
6329			$.each( s.order, function ( i, col ) {
6330				var set = [ col[0], col[1] ];
6331	
6332				// A column name was stored and should be used for restore
6333				if (typeof col[0] === 'string') {
6334					var idx = currentNames.indexOf(col[0]);
6335	
6336					// Find the name from the current list of column names, or fallback to index 0
6337					set[0] = idx >= 0
6338						? idx
6339						: 0;
6340				}
6341				else if (set[0] >= columns.length) {
6342					// If a column name, but it is out of bounds, set to 0
6343					set[0] = 0;
6344				}
6345	
6346				settings.aaSorting.push(set);
6347			} );
6348		}
6349	
6350		// Search
6351		if ( s.search !== undefined ) {
6352			$.extend( settings.oPreviousSearch, s.search );
6353		}
6354	
6355		// Columns
6356		if ( s.columns ) {
6357			var set = s.columns;
6358			var incoming = _pluck(s.columns, 'name');
6359	
6360			// Check if it is a 2.2 style state object with a `name` property for the columns, and if
6361			// the name was defined. If so, then create a new array that will map the state object
6362			// given, to the current columns (don't bother if they are already matching tho).
6363			if (incoming.join('').length && incoming.join('') !== currentNames.join('')) {
6364				set = [];
6365	
6366				// For each column, try to find the name in the incoming array
6367				for (i=0 ; i<currentNames.length ; i++) {
6368					if (currentNames[i] != '') {
6369						var idx = incoming.indexOf(currentNames[i]);
6370	
6371						if (idx >= 0) {
6372							set.push(s.columns[idx]);
6373						}
6374						else {
6375							// No matching column name in the state's columns, so this might be a new
6376							// column and thus can't have a state already.
6377							set.push({});
6378						}
6379					}
6380					else {
6381						// If no name, but other columns did have a name, then there is no knowing
6382						// where this one came from originally so it can't be restored.
6383						set.push({});
6384					}
6385				}
6386			}
6387	
6388			// If the number of columns to restore is different from current, then all bets are off.
6389			if (set.length === columns.length) {
6390				for ( i=0, ien=set.length ; i<ien ; i++ ) {
6391					var col = set[i];
6392	
6393					// Visibility
6394					if ( col.visible !== undefined ) {
6395						// If the api is defined, the table has been initialised so we need to use it rather than internal settings
6396						if (api) {
6397							// Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6398							api.column(i).visible(col.visible, false);
6399						}
6400						else {
6401							columns[i].bVisible = col.visible;
6402						}
6403					}
6404	
6405					// Search
6406					if ( col.search !== undefined ) {
6407						$.extend( settings.aoPreSearchCols[i], col.search );
6408					}
6409				}
6410	
6411				// If the api is defined then we need to adjust the columns once the visibility has been changed
6412				if (api) {
6413					api.columns.adjust();
6414				}
6415			}
6416		}
6417	
6418		settings._bLoadingState = false;
6419		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6420		callback();
6421	}
6422	
6423	/**
6424	 * Log an error message
6425	 *  @param {object} settings dataTables settings object
6426	 *  @param {int} level log error messages, or display them to the user
6427	 *  @param {string} msg error message
6428	 *  @param {int} tn Technical note id to get more information about the error.
6429	 *  @memberof DataTable#oApi
6430	 */
6431	function _fnLog( settings, level, msg, tn )
6432	{
6433		msg = 'DataTables warning: '+
6434			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6435	
6436		if ( tn ) {
6437			msg += '. For more information about this error, please see '+
6438			'https://datatables.net/tn/'+tn;
6439		}
6440	
6441		if ( ! level  ) {
6442			// Backwards compatibility pre 1.10
6443			var ext = DataTable.ext;
6444			var type = ext.sErrMode || ext.errMode;
6445	
6446			if ( settings ) {
6447				_fnCallbackFire( settings, null, 'dt-error', [ settings, tn, msg ], true );
6448			}
6449	
6450			if ( type == 'alert' ) {
6451				alert( msg );
6452			}
6453			else if ( type == 'throw' ) {
6454				throw new Error(msg);
6455			}
6456			else if ( typeof type == 'function' ) {
6457				type( settings, tn, msg );
6458			}
6459		}
6460		else if ( window.console && console.log ) {
6461			console.log( msg );
6462		}
6463	}
6464	
6465	
6466	/**
6467	 * See if a property is defined on one object, if so assign it to the other object
6468	 *  @param {object} ret target object
6469	 *  @param {object} src source object
6470	 *  @param {string} name property
6471	 *  @param {string} [mappedName] name to map too - optional, name used if not given
6472	 *  @memberof DataTable#oApi
6473	 */
6474	function _fnMap( ret, src, name, mappedName )
6475	{
6476		if ( Array.isArray( name ) ) {
6477			$.each( name, function (i, val) {
6478				if ( Array.isArray( val ) ) {
6479					_fnMap( ret, src, val[0], val[1] );
6480				}
6481				else {
6482					_fnMap( ret, src, val );
6483				}
6484			} );
6485	
6486			return;
6487		}
6488	
6489		if ( mappedName === undefined ) {
6490			mappedName = name;
6491		}
6492	
6493		if ( src[name] !== undefined ) {
6494			ret[mappedName] = src[name];
6495		}
6496	}
6497	
6498	
6499	/**
6500	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6501	 * shallow copy arrays. The reason we need to do this, is that we don't want to
6502	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6503	 * able to override them, but we do want to deep copy arrays.
6504	 *  @param {object} out Object to extend
6505	 *  @param {object} extender Object from which the properties will be applied to
6506	 *      out
6507	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6508	 *      independent copy with the exception of the `data` or `aaData` parameters
6509	 *      if they are present. This is so you can pass in a collection to
6510	 *      DataTables and have that used as your data source without breaking the
6511	 *      references
6512	 *  @returns {object} out Reference, just for convenience - out === the return.
6513	 *  @memberof DataTable#oApi
6514	 *  @todo This doesn't take account of arrays inside the deep copied objects.
6515	 */
6516	function _fnExtend( out, extender, breakRefs )
6517	{
6518		var val;
6519	
6520		for ( var prop in extender ) {
6521			if ( Object.prototype.hasOwnProperty.call(extender, prop) ) {
6522				val = extender[prop];
6523	
6524				if ( $.isPlainObject( val ) ) {
6525					if ( ! $.isPlainObject( out[prop] ) ) {
6526						out[prop] = {};
6527					}
6528					$.extend( true, out[prop], val );
6529				}
6530				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {
6531					out[prop] = val.slice();
6532				}
6533				else {
6534					out[prop] = val;
6535				}
6536			}
6537		}
6538	
6539		return out;
6540	}
6541	
6542	
6543	/**
6544	 * Bind an event handers to allow a click or return key to activate the callback.
6545	 * This is good for accessibility since a return on the keyboard will have the
6546	 * same effect as a click, if the element has focus.
6547	 *  @param {element} n Element to bind the action to
6548	 *  @param {object|string} selector Selector (for delegated events) or data object
6549	 *   to pass to the triggered function
6550	 *  @param {function} fn Callback function for when the event is triggered
6551	 *  @memberof DataTable#oApi
6552	 */
6553	function _fnBindAction( n, selector, fn )
6554	{
6555		$(n)
6556			.on( 'click.DT', selector, function (e) {
6557				fn(e);
6558			} )
6559			.on( 'keypress.DT', selector, function (e){
6560				if ( e.which === 13 ) {
6561					e.preventDefault();
6562					fn(e);
6563				}
6564			} )
6565			.on( 'selectstart.DT', selector, function () {
6566				// Don't want a double click resulting in text selection
6567				return false;
6568			} );
6569	}
6570	
6571	
6572	/**
6573	 * Register a callback function. Easily allows a callback function to be added to
6574	 * an array store of callback functions that can then all be called together.
6575	 *  @param {object} settings dataTables settings object
6576	 *  @param {string} store Name of the array storage for the callbacks in oSettings
6577	 *  @param {function} fn Function to be called back
6578	 *  @memberof DataTable#oApi
6579	 */
6580	function _fnCallbackReg( settings, store, fn )
6581	{
6582		if ( fn ) {
6583			settings[store].push(fn);
6584		}
6585	}
6586	
6587	
6588	/**
6589	 * Fire callback functions and trigger events. Note that the loop over the
6590	 * callback array store is done backwards! Further note that you do not want to
6591	 * fire off triggers in time sensitive applications (for example cell creation)
6592	 * as its slow.
6593	 *  @param {object} settings dataTables settings object
6594	 *  @param {string} callbackArr Name of the array storage for the callbacks in
6595	 *      oSettings
6596	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
6597	 *      null no trigger is fired
6598	 *  @param {array} args Array of arguments to pass to the callback function /
6599	 *      trigger
6600	 *  @param {boolean} [bubbles] True if the event should bubble
6601	 *  @memberof DataTable#oApi
6602	 */
6603	function _fnCallbackFire( settings, callbackArr, eventName, args, bubbles )
6604	{
6605		var ret = [];
6606	
6607		if ( callbackArr ) {
6608			ret = settings[callbackArr].slice().reverse().map( function (val) {
6609				return val.apply( settings.oInstance, args );
6610			} );
6611		}
6612	
6613		if ( eventName !== null) {
6614			var e = $.Event( eventName+'.dt' );
6615			var table = $(settings.nTable);
6616			
6617			// Expose the DataTables API on the event object for easy access
6618			e.dt = settings.api;
6619	
6620			table[bubbles ?  'trigger' : 'triggerHandler']( e, args );
6621	
6622			// If not yet attached to the document, trigger the event
6623			// on the body directly to sort of simulate the bubble
6624			if (bubbles && table.parents('body').length === 0) {
6625				$('body').trigger( e, args );
6626			}
6627	
6628			ret.push( e.result );
6629		}
6630	
6631		return ret;
6632	}
6633	
6634	
6635	function _fnLengthOverflow ( settings )
6636	{
6637		var
6638			start = settings._iDisplayStart,
6639			end = settings.fnDisplayEnd(),
6640			len = settings._iDisplayLength;
6641	
6642		/* If we have space to show extra rows (backing up from the end point - then do so */
6643		if ( start >= end )
6644		{
6645			start = end - len;
6646		}
6647	
6648		// Keep the start record on the current page
6649		start -= (start % len);
6650	
6651		if ( len === -1 || start < 0 )
6652		{
6653			start = 0;
6654		}
6655	
6656		settings._iDisplayStart = start;
6657	}
6658	
6659	
6660	function _fnRenderer( settings, type )
6661	{
6662		var renderer = settings.renderer;
6663		var host = DataTable.ext.renderer[type];
6664	
6665		if ( $.isPlainObject( renderer ) && renderer[type] ) {
6666			// Specific renderer for this type. If available use it, otherwise use
6667			// the default.
6668			return host[renderer[type]] || host._;
6669		}
6670		else if ( typeof renderer === 'string' ) {
6671			// Common renderer - if there is one available for this type use it,
6672			// otherwise use the default
6673			return host[renderer] || host._;
6674		}
6675	
6676		// Use the default
6677		return host._;
6678	}
6679	
6680	
6681	/**
6682	 * Detect the data source being used for the table. Used to simplify the code
6683	 * a little (ajax) and to make it compress a little smaller.
6684	 *
6685	 *  @param {object} settings dataTables settings object
6686	 *  @returns {string} Data source
6687	 *  @memberof DataTable#oApi
6688	 */
6689	function _fnDataSource ( settings )
6690	{
6691		if ( settings.oFeatures.bServerSide ) {
6692			return 'ssp';
6693		}
6694		else if ( settings.ajax ) {
6695			return 'ajax';
6696		}
6697		return 'dom';
6698	}
6699	
6700	/**
6701	 * Common replacement for language strings
6702	 *
6703	 * @param {*} settings DT settings object
6704	 * @param {*} str String with values to replace
6705	 * @param {*} entries Plural number for _ENTRIES_ - can be undefined
6706	 * @returns String
6707	 */
6708	function _fnMacros ( settings, str, entries )
6709	{
6710		// When infinite scrolling, we are always starting at 1. _iDisplayStart is
6711		// used only internally
6712		var
6713			formatter  = settings.fnFormatNumber,
6714			start      = settings._iDisplayStart+1,
6715			len        = settings._iDisplayLength,
6716			vis        = settings.fnRecordsDisplay(),
6717			max        = settings.fnRecordsTotal(),
6718			all        = len === -1;
6719	
6720		return str.
6721			replace(/_START_/g, formatter.call( settings, start ) ).
6722			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
6723			replace(/_MAX_/g,   formatter.call( settings, max ) ).
6724			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
6725			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
6726			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ).
6727			replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries) ).
6728			replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max) ).
6729			replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
6730	}
6731	
6732	/**
6733	 * Add elements to an array as quickly as possible, but stack stafe.
6734	 *
6735	 * @param {*} arr Array to add the data to
6736	 * @param {*} data Data array that is to be added
6737	 * @returns 
6738	 */
6739	function _fnArrayApply(arr, data) {
6740		if (! data) {
6741			return;
6742		}
6743	
6744		// Chrome can throw a max stack error if apply is called with
6745		// too large an array, but apply is faster.
6746		if (data.length < 10000) {
6747			arr.push.apply(arr, data);
6748		}
6749		else {
6750			for (i=0 ; i<data.length ; i++) {
6751				arr.push(data[i]);
6752			}
6753		}
6754	}
6755	
6756	
6757	
6758	/**
6759	 * Computed structure of the DataTables API, defined by the options passed to
6760	 * `DataTable.Api.register()` when building the API.
6761	 *
6762	 * The structure is built in order to speed creation and extension of the Api
6763	 * objects since the extensions are effectively pre-parsed.
6764	 *
6765	 * The array is an array of objects with the following structure, where this
6766	 * base array represents the Api prototype base:
6767	 *
6768	 *     [
6769	 *       {
6770	 *         name:      'data'                -- string   - Property name
6771	 *         val:       function () {},       -- function - Api method (or undefined if just an object
6772	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6773	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6774	 *       },
6775	 *       {
6776	 *         name:     'row'
6777	 *         val:       {},
6778	 *         methodExt: [ ... ],
6779	 *         propExt:   [
6780	 *           {
6781	 *             name:      'data'
6782	 *             val:       function () {},
6783	 *             methodExt: [ ... ],
6784	 *             propExt:   [ ... ]
6785	 *           },
6786	 *           ...
6787	 *         ]
6788	 *       }
6789	 *     ]
6790	 *
6791	 * @type {Array}
6792	 * @ignore
6793	 */
6794	var __apiStruct = [];
6795	
6796	
6797	/**
6798	 * `Array.prototype` reference.
6799	 *
6800	 * @type object
6801	 * @ignore
6802	 */
6803	var __arrayProto = Array.prototype;
6804	
6805	
6806	/**
6807	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6808	 * take several different forms for ease of use.
6809	 *
6810	 * Each of the input parameter types will be converted to a DataTables settings
6811	 * object where possible.
6812	 *
6813	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6814	 *   of:
6815	 *
6816	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6817	 *     with be found and used.
6818	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6819	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6820	 *   * `object` - DataTables settings object
6821	 *   * `DataTables.Api` - API instance
6822	 * @return {array|null} Matching DataTables settings objects. `null` or
6823	 *   `undefined` is returned if no matching DataTable is found.
6824	 * @ignore
6825	 */
6826	var _toSettings = function ( mixed )
6827	{
6828		var idx, jq;
6829		var settings = DataTable.settings;
6830		var tables = _pluck(settings, 'nTable');
6831	
6832		if ( ! mixed ) {
6833			return [];
6834		}
6835		else if ( mixed.nTable && mixed.oFeatures ) {
6836			// DataTables settings object
6837			return [ mixed ];
6838		}
6839		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6840			// Table node
6841			idx = tables.indexOf(mixed);
6842			return idx !== -1 ? [ settings[idx] ] : null;
6843		}
6844		else if ( mixed && typeof mixed.settings === 'function' ) {
6845			return mixed.settings().toArray();
6846		}
6847		else if ( typeof mixed === 'string' ) {
6848			// jQuery selector
6849			jq = $(mixed).get();
6850		}
6851		else if ( mixed instanceof $ ) {
6852			// jQuery object (also DataTables instance)
6853			jq = mixed.get();
6854		}
6855	
6856		if ( jq ) {
6857			return settings.filter(function (v, idx) {
6858				return jq.includes(tables[idx]);
6859			});
6860		}
6861	};
6862	
6863	
6864	/**
6865	 * DataTables API class - used to control and interface with  one or more
6866	 * DataTables enhanced tables.
6867	 *
6868	 * The API class is heavily based on jQuery, presenting a chainable interface
6869	 * that you can use to interact with tables. Each instance of the API class has
6870	 * a "context" - i.e. the tables that it will operate on. This could be a single
6871	 * table, all tables on a page or a sub-set thereof.
6872	 *
6873	 * Additionally the API is designed to allow you to easily work with the data in
6874	 * the tables, retrieving and manipulating it as required. This is done by
6875	 * presenting the API class as an array like interface. The contents of the
6876	 * array depend upon the actions requested by each method (for example
6877	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6878	 * return an array of objects or arrays depending upon your table's
6879	 * configuration). The API object has a number of array like methods (`push`,
6880	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6881	 * `unique` etc) to assist your working with the data held in a table.
6882	 *
6883	 * Most methods (those which return an Api instance) are chainable, which means
6884	 * the return from a method call also has all of the methods available that the
6885	 * top level object had. For example, these two calls are equivalent:
6886	 *
6887	 *     // Not chained
6888	 *     api.row.add( {...} );
6889	 *     api.draw();
6890	 *
6891	 *     // Chained
6892	 *     api.row.add( {...} ).draw();
6893	 *
6894	 * @class DataTable.Api
6895	 * @param {array|object|string|jQuery} context DataTable identifier. This is
6896	 *   used to define which DataTables enhanced tables this API will operate on.
6897	 *   Can be one of:
6898	 *
6899	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6900	 *     with be found and used.
6901	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6902	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6903	 *   * `object` - DataTables settings object
6904	 * @param {array} [data] Data to initialise the Api instance with.
6905	 *
6906	 * @example
6907	 *   // Direct initialisation during DataTables construction
6908	 *   var api = $('#example').DataTable();
6909	 *
6910	 * @example
6911	 *   // Initialisation using a DataTables jQuery object
6912	 *   var api = $('#example').dataTable().api();
6913	 *
6914	 * @example
6915	 *   // Initialisation as a constructor
6916	 *   var api = new DataTable.Api( 'table.dataTable' );
6917	 */
6918	_Api = function ( context, data )
6919	{
6920		if ( ! (this instanceof _Api) ) {
6921			return new _Api( context, data );
6922		}
6923	
6924		var i;
6925		var settings = [];
6926		var ctxSettings = function ( o ) {
6927			var a = _toSettings( o );
6928			if ( a ) {
6929				settings.push.apply( settings, a );
6930			}
6931		};
6932	
6933		if ( Array.isArray( context ) ) {
6934			for ( i=0 ; i<context.length ; i++ ) {
6935				ctxSettings( context[i] );
6936			}
6937		}
6938		else {
6939			ctxSettings( context );
6940		}
6941	
6942		// Remove duplicates
6943		this.context = settings.length > 1
6944			? _unique( settings )
6945			: settings;
6946	
6947		// Initial data
6948		_fnArrayApply(this, data);
6949	
6950		// selector
6951		this.selector = {
6952			rows: null,
6953			cols: null,
6954			opts: null
6955		};
6956	
6957		_Api.extend( this, this, __apiStruct );
6958	};
6959	
6960	DataTable.Api = _Api;
6961	
6962	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6963	// isPlainObject.
6964	$.extend( _Api.prototype, {
6965		any: function ()
6966		{
6967			return this.count() !== 0;
6968		},
6969	
6970		context: [], // array of table settings objects
6971	
6972		count: function ()
6973		{
6974			return this.flatten().length;
6975		},
6976	
6977		each: function ( fn )
6978		{
6979			for ( var i=0, ien=this.length ; i<ien; i++ ) {
6980				fn.call( this, this[i], i, this );
6981			}
6982	
6983			return this;
6984		},
6985	
6986		eq: function ( idx )
6987		{
6988			var ctx = this.context;
6989	
6990			return ctx.length > idx ?
6991				new _Api( ctx[idx], this[idx] ) :
6992				null;
6993		},
6994	
6995		filter: function ( fn )
6996		{
6997			var a = __arrayProto.filter.call( this, fn, this );
6998	
6999			return new _Api( this.context, a );
7000		},
7001	
7002		flatten: function ()
7003		{
7004			var a = [];
7005	
7006			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
7007		},
7008	
7009		get: function ( idx )
7010		{
7011			return this[ idx ];
7012		},
7013	
7014		join:    __arrayProto.join,
7015	
7016		includes: function ( find ) {
7017			return this.indexOf( find ) === -1 ? false : true;
7018		},
7019	
7020		indexOf: __arrayProto.indexOf,
7021	
7022		iterator: function ( flatten, type, fn, alwaysNew ) {
7023			var
7024				a = [], ret,
7025				i, ien, j, jen,
7026				context = this.context,
7027				rows, items, item,
7028				selector = this.selector;
7029	
7030			// Argument shifting
7031			if ( typeof flatten === 'string' ) {
7032				alwaysNew = fn;
7033				fn = type;
7034				type = flatten;
7035				flatten = false;
7036			}
7037	
7038			for ( i=0, ien=context.length ; i<ien ; i++ ) {
7039				var apiInst = new _Api( context[i] );
7040	
7041				if ( type === 'table' ) {
7042					ret = fn.call( apiInst, context[i], i );
7043	
7044					if ( ret !== undefined ) {
7045						a.push( ret );
7046					}
7047				}
7048				else if ( type === 'columns' || type === 'rows' ) {
7049					// this has same length as context - one entry for each table
7050					ret = fn.call( apiInst, context[i], this[i], i );
7051	
7052					if ( ret !== undefined ) {
7053						a.push( ret );
7054					}
7055				}
7056				else if ( type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7057					// columns and rows share the same structure.
7058					// 'this' is an array of column indexes for each context
7059					items = this[i];
7060	
7061					if ( type === 'column-rows' ) {
7062						rows = _selector_row_indexes( context[i], selector.opts );
7063					}
7064	
7065					for ( j=0, jen=items.length ; j<jen ; j++ ) {
7066						item = items[j];
7067	
7068						if ( type === 'cell' ) {
7069							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7070						}
7071						else {
7072							ret = fn.call( apiInst, context[i], item, i, j, rows );
7073						}
7074	
7075						if ( ret !== undefined ) {
7076							a.push( ret );
7077						}
7078					}
7079				}
7080			}
7081	
7082			if ( a.length || alwaysNew ) {
7083				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7084				var apiSelector = api.selector;
7085				apiSelector.rows = selector.rows;
7086				apiSelector.cols = selector.cols;
7087				apiSelector.opts = selector.opts;
7088				return api;
7089			}
7090			return this;
7091		},
7092	
7093		lastIndexOf: __arrayProto.lastIndexOf,
7094	
7095		length:  0,
7096	
7097		map: function ( fn )
7098		{
7099			var a = __arrayProto.map.call( this, fn, this );
7100	
7101			return new _Api( this.context, a );
7102		},
7103	
7104		pluck: function ( prop )
7105		{
7106			var fn = DataTable.util.get(prop);
7107	
7108			return this.map( function ( el ) {
7109				return fn(el);
7110			} );
7111		},
7112	
7113		pop:     __arrayProto.pop,
7114	
7115		push:    __arrayProto.push,
7116	
7117		reduce: __arrayProto.reduce,
7118	
7119		reduceRight: __arrayProto.reduceRight,
7120	
7121		reverse: __arrayProto.reverse,
7122	
7123		// Object with rows, columns and opts
7124		selector: null,
7125	
7126		shift:   __arrayProto.shift,
7127	
7128		slice: function () {
7129			return new _Api( this.context, this );
7130		},
7131	
7132		sort:    __arrayProto.sort,
7133	
7134		splice:  __arrayProto.splice,
7135	
7136		toArray: function ()
7137		{
7138			return __arrayProto.slice.call( this );
7139		},
7140	
7141		to$: function ()
7142		{
7143			return $( this );
7144		},
7145	
7146		toJQuery: function ()
7147		{
7148			return $( this );
7149		},
7150	
7151		unique: function ()
7152		{
7153			return new _Api( this.context, _unique(this.toArray()) );
7154		},
7155	
7156		unshift: __arrayProto.unshift
7157	} );
7158	
7159	
7160	function _api_scope( scope, fn, struc ) {
7161		return function () {
7162			var ret = fn.apply( scope || this, arguments );
7163	
7164			// Method extension
7165			_Api.extend( ret, ret, struc.methodExt );
7166			return ret;
7167		};
7168	}
7169	
7170	function _api_find( src, name ) {
7171		for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7172			if ( src[i].name === name ) {
7173				return src[i];
7174			}
7175		}
7176		return null;
7177	}
7178	
7179	window.__apiStruct = __apiStruct;
7180	
7181	_Api.extend = function ( scope, obj, ext )
7182	{
7183		// Only extend API instances and static properties of the API
7184		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7185			return;
7186		}
7187	
7188		var
7189			i, ien,
7190			struct;
7191	
7192		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7193			struct = ext[i];
7194	
7195			if (struct.name === '__proto__') {
7196				continue;
7197			}
7198	
7199			// Value
7200			obj[ struct.name ] = struct.type === 'function' ?
7201				_api_scope( scope, struct.val, struct ) :
7202				struct.type === 'object' ?
7203					{} :
7204					struct.val;
7205	
7206			obj[ struct.name ].__dt_wrapper = true;
7207	
7208			// Property extension
7209			_Api.extend( scope, obj[ struct.name ], struct.propExt );
7210		}
7211	};
7212	
7213	//     [
7214	//       {
7215	//         name:      'data'                -- string   - Property name
7216	//         val:       function () {},       -- function - Api method (or undefined if just an object
7217	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
7218	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
7219	//       },
7220	//       {
7221	//         name:     'row'
7222	//         val:       {},
7223	//         methodExt: [ ... ],
7224	//         propExt:   [
7225	//           {
7226	//             name:      'data'
7227	//             val:       function () {},
7228	//             methodExt: [ ... ],
7229	//             propExt:   [ ... ]
7230	//           },
7231	//           ...
7232	//         ]
7233	//       }
7234	//     ]
7235	
7236	
7237	_Api.register = _api_register = function ( name, val )
7238	{
7239		if ( Array.isArray( name ) ) {
7240			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7241				_Api.register( name[j], val );
7242			}
7243			return;
7244		}
7245	
7246		var
7247			i, ien,
7248			heir = name.split('.'),
7249			struct = __apiStruct,
7250			key, method;
7251	
7252		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7253			method = heir[i].indexOf('()') !== -1;
7254			key = method ?
7255				heir[i].replace('()', '') :
7256				heir[i];
7257	
7258			var src = _api_find( struct, key );
7259			if ( ! src ) {
7260				src = {
7261					name:      key,
7262					val:       {},
7263					methodExt: [],
7264					propExt:   [],
7265					type:      'object'
7266				};
7267				struct.push( src );
7268			}
7269	
7270			if ( i === ien-1 ) {
7271				src.val = val;
7272				src.type = typeof val === 'function' ?
7273					'function' :
7274					$.isPlainObject( val ) ?
7275						'object' :
7276						'other';
7277			}
7278			else {
7279				struct = method ?
7280					src.methodExt :
7281					src.propExt;
7282			}
7283		}
7284	};
7285	
7286	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7287		_Api.register( pluralName, val );
7288	
7289		_Api.register( singularName, function () {
7290			var ret = val.apply( this, arguments );
7291	
7292			if ( ret === this ) {
7293				// Returned item is the API instance that was passed in, return it
7294				return this;
7295			}
7296			else if ( ret instanceof _Api ) {
7297				// New API instance returned, want the value from the first item
7298				// in the returned array for the singular result.
7299				return ret.length ?
7300					Array.isArray( ret[0] ) ?
7301						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7302						ret[0] :
7303					undefined;
7304			}
7305	
7306			// Non-API return - just fire it back
7307			return ret;
7308		} );
7309	};
7310	
7311	
7312	/**
7313	 * Selector for HTML tables. Apply the given selector to the give array of
7314	 * DataTables settings objects.
7315	 *
7316	 * @param {string|integer} [selector] jQuery selector string or integer
7317	 * @param  {array} Array of DataTables settings objects to be filtered
7318	 * @return {array}
7319	 * @ignore
7320	 */
7321	var __table_selector = function ( selector, a )
7322	{
7323		if ( Array.isArray(selector) ) {
7324			var result = [];
7325	
7326			selector.forEach(function (sel) {
7327				var inner = __table_selector(sel, a);
7328	
7329				_fnArrayApply(result, inner);
7330			});
7331	
7332			return result.filter( function (item) {
7333				return item;
7334			});
7335		}
7336	
7337		// Integer is used to pick out a table by index
7338		if ( typeof selector === 'number' ) {
7339			return [ a[ selector ] ];
7340		}
7341	
7342		// Perform a jQuery selector on the table nodes
7343		var nodes = a.map( function (el) {
7344			return el.nTable;
7345		} );
7346	
7347		return $(nodes)
7348			.filter( selector )
7349			.map( function () {
7350				// Need to translate back from the table node to the settings
7351				var idx = nodes.indexOf(this);
7352				return a[ idx ];
7353			} )
7354			.toArray();
7355	};
7356	
7357	
7358	
7359	/**
7360	 * Context selector for the API's context (i.e. the tables the API instance
7361	 * refers to.
7362	 *
7363	 * @name    DataTable.Api#tables
7364	 * @param {string|integer} [selector] Selector to pick which tables the iterator
7365	 *   should operate on. If not given, all tables in the current context are
7366	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7367	 *   select multiple tables or as an integer to select a single table.
7368	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7369	 */
7370	_api_register( 'tables()', function ( selector ) {
7371		// A new instance is created if there was a selector specified
7372		return selector !== undefined && selector !== null ?
7373			new _Api( __table_selector( selector, this.context ) ) :
7374			this;
7375	} );
7376	
7377	
7378	_api_register( 'table()', function ( selector ) {
7379		var tables = this.tables( selector );
7380		var ctx = tables.context;
7381	
7382		// Truncate to the first matched table
7383		return ctx.length ?
7384			new _Api( ctx[0] ) :
7385			tables;
7386	} );
7387	
7388	// Common methods, combined to reduce size
7389	[
7390		['nodes', 'node', 'nTable'],
7391		['body', 'body', 'nTBody'],
7392		['header', 'header', 'nTHead'],
7393		['footer', 'footer', 'nTFoot'],
7394	].forEach(function (item) {
7395		_api_registerPlural(
7396			'tables().' + item[0] + '()',
7397			'table().' + item[1] + '()' ,
7398			function () {
7399				return this.iterator( 'table', function ( ctx ) {
7400					return ctx[item[2]];
7401				}, 1 );
7402			}
7403		);
7404	});
7405	
7406	// Structure methods
7407	[
7408		['header', 'aoHeader'],
7409		['footer', 'aoFooter'],
7410	].forEach(function (item) {
7411		_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
7412			var indexes = this.columns(selector).indexes().flatten();
7413			var ctx = this.context[0];
7414			
7415			return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7416		} );
7417	})
7418	
7419	
7420	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7421		return this.iterator( 'table', function ( ctx ) {
7422			return ctx.nTableWrapper;
7423		}, 1 );
7424	} );
7425	
7426	_api_register( 'tables().every()', function ( fn ) {
7427		var that = this;
7428	
7429		return this.iterator('table', function (s, i) {
7430			fn.call(that.table(i), i);
7431		});
7432	});
7433	
7434	_api_register( 'caption()', function ( value, side ) {
7435		var context = this.context;
7436	
7437		// Getter - return existing node's content
7438		if ( value === undefined ) {
7439			var caption = context[0].captionNode;
7440	
7441			return caption && context.length ?
7442				caption.innerHTML : 
7443				null;
7444		}
7445	
7446		return this.iterator( 'table', function ( ctx ) {
7447			var table = $(ctx.nTable);
7448			var caption = $(ctx.captionNode);
7449			var container = $(ctx.nTableWrapper);
7450	
7451			// Create the node if it doesn't exist yet
7452			if ( ! caption.length ) {
7453				caption = $('<caption/>').html( value );
7454				ctx.captionNode = caption[0];
7455	
7456				// If side isn't set, we need to insert into the document to let the
7457				// CSS decide so we can read it back, otherwise there is no way to
7458				// know if the CSS would put it top or bottom for scrolling
7459				if (! side) {
7460					table.prepend(caption);
7461	
7462					side = caption.css('caption-side');
7463				}
7464			}
7465	
7466			caption.html( value );
7467	
7468			if ( side ) {
7469				caption.css( 'caption-side', side );
7470				caption[0]._captionSide = side;
7471			}
7472	
7473			if (container.find('div.dataTables_scroll').length) {
7474				var selector = (side === 'top' ? 'Head' : 'Foot');
7475	
7476				container.find('div.dataTables_scroll'+ selector +' table').prepend(caption);
7477			}
7478			else {
7479				table.prepend(caption);
7480			}
7481		}, 1 );
7482	} );
7483	
7484	_api_register( 'caption.node()', function () {
7485		var ctx = this.context;
7486	
7487		return ctx.length ? ctx[0].captionNode : null;
7488	} );
7489	
7490	
7491	/**
7492	 * Redraw the tables in the current context.
7493	 */
7494	_api_register( 'draw()', function ( paging ) {
7495		return this.iterator( 'table', function ( settings ) {
7496			if ( paging === 'page' ) {
7497				_fnDraw( settings );
7498			}
7499			else {
7500				if ( typeof paging === 'string' ) {
7501					paging = paging === 'full-hold' ?
7502						false :
7503						true;
7504				}
7505	
7506				_fnReDraw( settings, paging===false );
7507			}
7508		} );
7509	} );
7510	
7511	
7512	
7513	/**
7514	 * Get the current page index.
7515	 *
7516	 * @return {integer} Current page index (zero based)
7517	 *//**
7518	 * Set the current page.
7519	 *
7520	 * Note that if you attempt to show a page which does not exist, DataTables will
7521	 * not throw an error, but rather reset the paging.
7522	 *
7523	 * @param {integer|string} action The paging action to take. This can be one of:
7524	 *  * `integer` - The page index to jump to
7525	 *  * `string` - An action to take:
7526	 *    * `first` - Jump to first page.
7527	 *    * `next` - Jump to the next page
7528	 *    * `previous` - Jump to previous page
7529	 *    * `last` - Jump to the last page.
7530	 * @returns {DataTables.Api} this
7531	 */
7532	_api_register( 'page()', function ( action ) {
7533		if ( action === undefined ) {
7534			return this.page.info().page; // not an expensive call
7535		}
7536	
7537		// else, have an action to take on all tables
7538		return this.iterator( 'table', function ( settings ) {
7539			_fnPageChange( settings, action );
7540		} );
7541	} );
7542	
7543	
7544	/**
7545	 * Paging information for the first table in the current context.
7546	 *
7547	 * If you require paging information for another table, use the `table()` method
7548	 * with a suitable selector.
7549	 *
7550	 * @return {object} Object with the following properties set:
7551	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7552	 *  * `pages` - Total number of pages
7553	 *  * `start` - Display index for the first record shown on the current page
7554	 *  * `end` - Display index for the last record shown on the current page
7555	 *  * `length` - Display length (number of records). Note that generally `start
7556	 *    + length = end`, but this is not always true, for example if there are
7557	 *    only 2 records to show on the final page, with a length of 10.
7558	 *  * `recordsTotal` - Full data set length
7559	 *  * `recordsDisplay` - Data set length once the current filtering criterion
7560	 *    are applied.
7561	 */
7562	_api_register( 'page.info()', function () {
7563		if ( this.context.length === 0 ) {
7564			return undefined;
7565		}
7566	
7567		var
7568			settings   = this.context[0],
7569			start      = settings._iDisplayStart,
7570			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7571			visRecords = settings.fnRecordsDisplay(),
7572			all        = len === -1;
7573	
7574		return {
7575			"page":           all ? 0 : Math.floor( start / len ),
7576			"pages":          all ? 1 : Math.ceil( visRecords / len ),
7577			"start":          start,
7578			"end":            settings.fnDisplayEnd(),
7579			"length":         len,
7580			"recordsTotal":   settings.fnRecordsTotal(),
7581			"recordsDisplay": visRecords,
7582			"serverSide":     _fnDataSource( settings ) === 'ssp'
7583		};
7584	} );
7585	
7586	
7587	/**
7588	 * Get the current page length.
7589	 *
7590	 * @return {integer} Current page length. Note `-1` indicates that all records
7591	 *   are to be shown.
7592	 *//**
7593	 * Set the current page length.
7594	 *
7595	 * @param {integer} Page length to set. Use `-1` to show all records.
7596	 * @returns {DataTables.Api} this
7597	 */
7598	_api_register( 'page.len()', function ( len ) {
7599		// Note that we can't call this function 'length()' because `length`
7600		// is a Javascript property of functions which defines how many arguments
7601		// the function expects.
7602		if ( len === undefined ) {
7603			return this.context.length !== 0 ?
7604				this.context[0]._iDisplayLength :
7605				undefined;
7606		}
7607	
7608		// else, set the page length
7609		return this.iterator( 'table', function ( settings ) {
7610			_fnLengthChange( settings, len );
7611		} );
7612	} );
7613	
7614	
7615	
7616	var __reload = function ( settings, holdPosition, callback ) {
7617		// Use the draw event to trigger a callback
7618		if ( callback ) {
7619			var api = new _Api( settings );
7620	
7621			api.one( 'draw', function () {
7622				callback( api.ajax.json() );
7623			} );
7624		}
7625	
7626		if ( _fnDataSource( settings ) == 'ssp' ) {
7627			_fnReDraw( settings, holdPosition );
7628		}
7629		else {
7630			_fnProcessingDisplay( settings, true );
7631	
7632			// Cancel an existing request
7633			var xhr = settings.jqXHR;
7634			if ( xhr && xhr.readyState !== 4 ) {
7635				xhr.abort();
7636			}
7637	
7638			// Trigger xhr
7639			_fnBuildAjax( settings, {}, function( json ) {
7640				_fnClearTable( settings );
7641	
7642				var data = _fnAjaxDataSrc( settings, json );
7643				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7644					_fnAddData( settings, data[i] );
7645				}
7646	
7647				_fnReDraw( settings, holdPosition );
7648				_fnInitComplete( settings );
7649				_fnProcessingDisplay( settings, false );
7650			} );
7651		}
7652	};
7653	
7654	
7655	/**
7656	 * Get the JSON response from the last Ajax request that DataTables made to the
7657	 * server. Note that this returns the JSON from the first table in the current
7658	 * context.
7659	 *
7660	 * @return {object} JSON received from the server.
7661	 */
7662	_api_register( 'ajax.json()', function () {
7663		var ctx = this.context;
7664	
7665		if ( ctx.length > 0 ) {
7666			return ctx[0].json;
7667		}
7668	
7669		// else return undefined;
7670	} );
7671	
7672	
7673	/**
7674	 * Get the data submitted in the last Ajax request
7675	 */
7676	_api_register( 'ajax.params()', function () {
7677		var ctx = this.context;
7678	
7679		if ( ctx.length > 0 ) {
7680			return ctx[0].oAjaxData;
7681		}
7682	
7683		// else return undefined;
7684	} );
7685	
7686	
7687	/**
7688	 * Reload tables from the Ajax data source. Note that this function will
7689	 * automatically re-draw the table when the remote data has been loaded.
7690	 *
7691	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7692	 *   position. A full re-sort and re-filter is performed when this method is
7693	 *   called, which is why the pagination reset is the default action.
7694	 * @returns {DataTables.Api} this
7695	 */
7696	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7697		return this.iterator( 'table', function (settings) {
7698			__reload( settings, resetPaging===false, callback );
7699		} );
7700	} );
7701	
7702	
7703	/**
7704	 * Get the current Ajax URL. Note that this returns the URL from the first
7705	 * table in the current context.
7706	 *
7707	 * @return {string} Current Ajax source URL
7708	 *//**
7709	 * Set the Ajax URL. Note that this will set the URL for all tables in the
7710	 * current context.
7711	 *
7712	 * @param {string} url URL to set.
7713	 * @returns {DataTables.Api} this
7714	 */
7715	_api_register( 'ajax.url()', function ( url ) {
7716		var ctx = this.context;
7717	
7718		if ( url === undefined ) {
7719			// get
7720			if ( ctx.length === 0 ) {
7721				return undefined;
7722			}
7723			ctx = ctx[0];
7724	
7725			return $.isPlainObject( ctx.ajax ) ?
7726				ctx.ajax.url :
7727				ctx.ajax;
7728		}
7729	
7730		// set
7731		return this.iterator( 'table', function ( settings ) {
7732			if ( $.isPlainObject( settings.ajax ) ) {
7733				settings.ajax.url = url;
7734			}
7735			else {
7736				settings.ajax = url;
7737			}
7738		} );
7739	} );
7740	
7741	
7742	/**
7743	 * Load data from the newly set Ajax URL. Note that this method is only
7744	 * available when `ajax.url()` is used to set a URL. Additionally, this method
7745	 * has the same effect as calling `ajax.reload()` but is provided for
7746	 * convenience when setting a new URL. Like `ajax.reload()` it will
7747	 * automatically redraw the table once the remote data has been loaded.
7748	 *
7749	 * @returns {DataTables.Api} this
7750	 */
7751	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7752		// Same as a reload, but makes sense to present it for easy access after a
7753		// url change
7754		return this.iterator( 'table', function ( ctx ) {
7755			__reload( ctx, resetPaging===false, callback );
7756		} );
7757	} );
7758	
7759	
7760	
7761	
7762	var _selector_run = function ( type, selector, selectFn, settings, opts )
7763	{
7764		var
7765			out = [], res,
7766			a, i, ien, j, jen,
7767			selectorType = typeof selector;
7768	
7769		// Can't just check for isArray here, as an API or jQuery instance might be
7770		// given with their array like look
7771		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7772			selector = [ selector ];
7773		}
7774	
7775		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7776			// Only split on simple strings - complex expressions will be jQuery selectors
7777			a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
7778				selector[i].split(',') :
7779				[ selector[i] ];
7780	
7781			for ( j=0, jen=a.length ; j<jen ; j++ ) {
7782				res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
7783	
7784				// Remove empty items
7785				res = res.filter( function (item) {
7786					return item !== null && item !== undefined;
7787				});
7788	
7789				if ( res && res.length ) {
7790					out = out.concat( res );
7791				}
7792			}
7793		}
7794	
7795		// selector extensions
7796		var ext = _ext.selector[ type ];
7797		if ( ext.length ) {
7798			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7799				out = ext[i]( settings, opts, out );
7800			}
7801		}
7802	
7803		return _unique( out );
7804	};
7805	
7806	
7807	var _selector_opts = function ( opts )
7808	{
7809		if ( ! opts ) {
7810			opts = {};
7811		}
7812	
7813		// Backwards compatibility for 1.9- which used the terminology filter rather
7814		// than search
7815		if ( opts.filter && opts.search === undefined ) {
7816			opts.search = opts.filter;
7817		}
7818	
7819		return $.extend( {
7820			search: 'none',
7821			order: 'current',
7822			page: 'all'
7823		}, opts );
7824	};
7825	
7826	
7827	// Reduce the API instance to the first item found
7828	var _selector_first = function ( old )
7829	{
7830		var inst = new _Api(old.context[0]);
7831	
7832		// Use a push rather than passing to the constructor, since it will
7833		// merge arrays down automatically, which isn't what is wanted here
7834		if (old.length) {
7835			inst.push( old[0] );
7836		}
7837	
7838		inst.selector = old.selector;
7839	
7840		// Limit to a single row / column / cell
7841		if (inst.length && inst[0].length > 1) {
7842			inst[0].splice(1);
7843		}
7844	
7845		return inst;
7846	};
7847	
7848	
7849	var _selector_row_indexes = function ( settings, opts )
7850	{
7851		var
7852			i, ien, tmp, a=[],
7853			displayFiltered = settings.aiDisplay,
7854			displayMaster = settings.aiDisplayMaster;
7855	
7856		var
7857			search = opts.search,  // none, applied, removed
7858			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7859			page   = opts.page;    // all, current
7860	
7861		if ( _fnDataSource( settings ) == 'ssp' ) {
7862			// In server-side processing mode, most options are irrelevant since
7863			// rows not shown don't exist and the index order is the applied order
7864			// Removed is a special case - for consistency just return an empty
7865			// array
7866			return search === 'removed' ?
7867				[] :
7868				_range( 0, displayMaster.length );
7869		}
7870	
7871		if ( page == 'current' ) {
7872			// Current page implies that order=current and filter=applied, since it is
7873			// fairly senseless otherwise, regardless of what order and search actually
7874			// are
7875			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7876				a.push( displayFiltered[i] );
7877			}
7878		}
7879		else if ( order == 'current' || order == 'applied' ) {
7880			if ( search == 'none') {
7881				a = displayMaster.slice();
7882			}
7883			else if ( search == 'applied' ) {
7884				a = displayFiltered.slice();
7885			}
7886			else if ( search == 'removed' ) {
7887				// O(n+m) solution by creating a hash map
7888				var displayFilteredMap = {};
7889	
7890				for ( i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7891					displayFilteredMap[displayFiltered[i]] = null;
7892				}
7893	
7894				displayMaster.forEach(function (item) {
7895					if (! Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
7896						a.push(item);
7897					}
7898				});
7899			}
7900		}
7901		else if ( order == 'index' || order == 'original' ) {
7902			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7903				if (! settings.aoData[i]) {
7904					continue;
7905				}
7906	
7907				if ( search == 'none' ) {
7908					a.push( i );
7909				}
7910				else { // applied | removed
7911					tmp = displayFiltered.indexOf(i);
7912	
7913					if ((tmp === -1 && search == 'removed') ||
7914						(tmp >= 0   && search == 'applied') )
7915					{
7916						a.push( i );
7917					}
7918				}
7919			}
7920		}
7921		else if ( typeof order === 'number' ) {
7922			// Order the rows by the given column
7923			var ordered = _fnSort(settings, order, 'asc');
7924	
7925			if (search === 'none') {
7926				a = ordered;
7927			}
7928			else { // applied | removed
7929				for (i=0; i<ordered.length; i++) {
7930					tmp = displayFiltered.indexOf(ordered[i]);
7931	
7932					if ((tmp === -1 && search == 'removed') ||
7933						(tmp >= 0   && search == 'applied') )
7934					{
7935						a.push( ordered[i] );
7936					}
7937				}
7938			}
7939		}
7940	
7941		return a;
7942	};
7943	
7944	
7945	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7946	 * Rows
7947	 *
7948	 * {}          - no selector - use all available rows
7949	 * {integer}   - row aoData index
7950	 * {node}      - TR node
7951	 * {string}    - jQuery selector to apply to the TR elements
7952	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
7953	 *
7954	 */
7955	var __row_selector = function ( settings, selector, opts )
7956	{
7957		var rows;
7958		var run = function ( sel ) {
7959			var selInt = _intVal( sel );
7960			var aoData = settings.aoData;
7961	
7962			// Short cut - selector is a number and no options provided (default is
7963			// all records, so no need to check if the index is in there, since it
7964			// must be - dev error if the index doesn't exist).
7965			if ( selInt !== null && ! opts ) {
7966				return [ selInt ];
7967			}
7968	
7969			if ( ! rows ) {
7970				rows = _selector_row_indexes( settings, opts );
7971			}
7972	
7973			if ( selInt !== null && rows.indexOf(selInt) !== -1 ) {
7974				// Selector - integer
7975				return [ selInt ];
7976			}
7977			else if ( sel === null || sel === undefined || sel === '' ) {
7978				// Selector - none
7979				return rows;
7980			}
7981	
7982			// Selector - function
7983			if ( typeof sel === 'function' ) {
7984				return rows.map( function (idx) {
7985					var row = aoData[ idx ];
7986					return sel( idx, row._aData, row.nTr ) ? idx : null;
7987				} );
7988			}
7989	
7990			// Selector - node
7991			if ( sel.nodeName ) {
7992				var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
7993				var cellIdx = sel._DT_CellIndex;
7994	
7995				if ( rowIdx !== undefined ) {
7996					// Make sure that the row is actually still present in the table
7997					return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7998						[ rowIdx ] :
7999						[];
8000				}
8001				else if ( cellIdx ) {
8002					return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
8003						[ cellIdx.row ] :
8004						[];
8005				}
8006				else {
8007					var host = $(sel).closest('*[data-dt-row]');
8008					return host.length ?
8009						[ host.data('dt-row') ] :
8010						[];
8011				}
8012			}
8013	
8014			// ID selector. Want to always be able to select rows by id, regardless
8015			// of if the tr element has been created or not, so can't rely upon
8016			// jQuery here - hence a custom implementation. This does not match
8017			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
8018			// but to select it using a CSS selector engine (like Sizzle or
8019			// querySelect) it would need to need to be escaped for some characters.
8020			// DataTables simplifies this for row selectors since you can select
8021			// only a row. A # indicates an id any anything that follows is the id -
8022			// unescaped.
8023			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
8024				// get row index from id
8025				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
8026				if ( rowObj !== undefined ) {
8027					return [ rowObj.idx ];
8028				}
8029	
8030				// need to fall through to jQuery in case there is DOM id that
8031				// matches
8032			}
8033			
8034			// Get nodes in the order from the `rows` array with null values removed
8035			var nodes = _removeEmpty(
8036				_pluck_order( settings.aoData, rows, 'nTr' )
8037			);
8038	
8039			// Selector - jQuery selector string, array of nodes or jQuery object/
8040			// As jQuery's .filter() allows jQuery objects to be passed in filter,
8041			// it also allows arrays, so this will cope with all three options
8042			return $(nodes)
8043				.filter( sel )
8044				.map( function () {
8045					return this._DT_RowIndex;
8046				} )
8047				.toArray();
8048		};
8049	
8050		var matched = _selector_run( 'row', selector, run, settings, opts );
8051	
8052		if (opts.order === 'current' || opts.order === 'applied') {
8053			_fnSortDisplay(settings, matched);
8054		}
8055	
8056		return matched;
8057	};
8058	
8059	
8060	_api_register( 'rows()', function ( selector, opts ) {
8061		// argument shifting
8062		if ( selector === undefined ) {
8063			selector = '';
8064		}
8065		else if ( $.isPlainObject( selector ) ) {
8066			opts = selector;
8067			selector = '';
8068		}
8069	
8070		opts = _selector_opts( opts );
8071	
8072		var inst = this.iterator( 'table', function ( settings ) {
8073			return __row_selector( settings, selector, opts );
8074		}, 1 );
8075	
8076		// Want argument shifting here and in __row_selector?
8077		inst.selector.rows = selector;
8078		inst.selector.opts = opts;
8079	
8080		return inst;
8081	} );
8082	
8083	_api_register( 'rows().nodes()', function () {
8084		return this.iterator( 'row', function ( settings, row ) {
8085			return settings.aoData[ row ].nTr || undefined;
8086		}, 1 );
8087	} );
8088	
8089	_api_register( 'rows().data()', function () {
8090		return this.iterator( true, 'rows', function ( settings, rows ) {
8091			return _pluck_order( settings.aoData, rows, '_aData' );
8092		}, 1 );
8093	} );
8094	
8095	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
8096		return this.iterator( 'row', function ( settings, row ) {
8097			var r = settings.aoData[ row ];
8098			return type === 'search' ? r._aFilterData : r._aSortData;
8099		}, 1 );
8100	} );
8101	
8102	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
8103		return this.iterator( 'row', function ( settings, row ) {
8104			_fnInvalidate( settings, row, src );
8105		} );
8106	} );
8107	
8108	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
8109		return this.iterator( 'row', function ( settings, row ) {
8110			return row;
8111		}, 1 );
8112	} );
8113	
8114	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8115		var a = [];
8116		var context = this.context;
8117	
8118		// `iterator` will drop undefined values, but in this case we want them
8119		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8120			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8121				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8122				a.push( (hash === true ? '#' : '' )+ id );
8123			}
8124		}
8125	
8126		return new _Api( context, a );
8127	} );
8128	
8129	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8130		this.iterator( 'row', function ( settings, row ) {
8131			var data = settings.aoData;
8132			var rowData = data[ row ];
8133	
8134			// Delete from the display arrays
8135			var idx = settings.aiDisplayMaster.indexOf(row);
8136			if (idx !== -1) {
8137				settings.aiDisplayMaster.splice(idx, 1);
8138			}
8139	
8140			// For server-side processing tables - subtract the deleted row from the count
8141			if ( settings._iRecordsDisplay > 0 ) {
8142				settings._iRecordsDisplay--;
8143			}
8144	
8145			// Check for an 'overflow' they case for displaying the table
8146			_fnLengthOverflow( settings );
8147	
8148			// Remove the row's ID reference if there is one
8149			var id = settings.rowIdFn( rowData._aData );
8150			if ( id !== undefined ) {
8151				delete settings.aIds[ id ];
8152			}
8153	
8154			data[row] = null;
8155		} );
8156	
8157		return this;
8158	} );
8159	
8160	
8161	_api_register( 'rows.add()', function ( rows ) {
8162		var newRows = this.iterator( 'table', function ( settings ) {
8163				var row, i, ien;
8164				var out = [];
8165	
8166				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8167					row = rows[i];
8168	
8169					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8170						out.push( _fnAddTr( settings, row )[0] );
8171					}
8172					else {
8173						out.push( _fnAddData( settings, row ) );
8174					}
8175				}
8176	
8177				return out;
8178			}, 1 );
8179	
8180		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
8181		var modRows = this.rows( -1 );
8182		modRows.pop();
8183		_fnArrayApply(modRows, newRows);
8184	
8185		return modRows;
8186	} );
8187	
8188	
8189	
8190	
8191	
8192	/**
8193	 *
8194	 */
8195	_api_register( 'row()', function ( selector, opts ) {
8196		return _selector_first( this.rows( selector, opts ) );
8197	} );
8198	
8199	
8200	_api_register( 'row().data()', function ( data ) {
8201		var ctx = this.context;
8202	
8203		if ( data === undefined ) {
8204			// Get
8205			return ctx.length && this.length && this[0].length ?
8206				ctx[0].aoData[ this[0] ]._aData :
8207				undefined;
8208		}
8209	
8210		// Set
8211		var row = ctx[0].aoData[ this[0] ];
8212		row._aData = data;
8213	
8214		// If the DOM has an id, and the data source is an array
8215		if ( Array.isArray( data ) && row.nTr && row.nTr.id ) {
8216			_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
8217		}
8218	
8219		// Automatically invalidate
8220		_fnInvalidate( ctx[0], this[0], 'data' );
8221	
8222		return this;
8223	} );
8224	
8225	
8226	_api_register( 'row().node()', function () {
8227		var ctx = this.context;
8228	
8229		if (ctx.length && this.length && this[0].length) {
8230			var row = ctx[0].aoData[ this[0] ];
8231	
8232			if (row && row.nTr) {
8233				return row.nTr;
8234			}
8235		}
8236	
8237		return null;
8238	} );
8239	
8240	
8241	_api_register( 'row.add()', function ( row ) {
8242		// Allow a jQuery object to be passed in - only a single row is added from
8243		// it though - the first element in the set
8244		if ( row instanceof $ && row.length ) {
8245			row = row[0];
8246		}
8247	
8248		var rows = this.iterator( 'table', function ( settings ) {
8249			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8250				return _fnAddTr( settings, row )[0];
8251			}
8252			return _fnAddData( settings, row );
8253		} );
8254	
8255		// Return an Api.rows() extended instance, with the newly added row selected
8256		return this.row( rows[0] );
8257	} );
8258	
8259	
8260	$(document).on('plugin-init.dt', function (e, context) {
8261		var api = new _Api( context );
8262	
8263		api.on( 'stateSaveParams.DT', function ( e, settings, d ) {
8264			// This could be more compact with the API, but it is a lot faster as a simple
8265			// internal loop
8266			var idFn = settings.rowIdFn;
8267			var rows = settings.aiDisplayMaster;
8268			var ids = [];
8269	
8270			for (var i=0 ; i<rows.length ; i++) {
8271				var rowIdx = rows[i];
8272				var data = settings.aoData[rowIdx];
8273	
8274				if (data._detailsShow) {
8275					ids.push( '#' + idFn(data._aData) );
8276				}
8277			}
8278	
8279			d.childRows = ids;
8280		});
8281	
8282		// For future state loads (e.g. with StateRestore)
8283		api.on( 'stateLoaded.DT', function (e, settings, state) {
8284			__details_state_load( api, state );
8285		});
8286	
8287		// And the initial load state
8288		__details_state_load( api, api.state.loaded() );
8289	});
8290	
8291	var __details_state_load = function (api, state)
8292	{
8293		if ( state && state.childRows ) {
8294			api
8295				.rows( state.childRows.map(function (id) {
8296					// Escape any `:` characters from the row id. Accounts for
8297					// already escaped characters.
8298					return id.replace(/([^:\\]*(?:\\.[^:\\]*)*):/g, "$1\\:");
8299				}) )
8300				.every( function () {
8301					_fnCallbackFire( api.settings()[0], null, 'requestChild', [ this ] )
8302				});
8303		}
8304	}
8305	
8306	var __details_add = function ( ctx, row, data, klass )
8307	{
8308		// Convert to array of TR elements
8309		var rows = [];
8310		var addRow = function ( r, k ) {
8311			// Recursion to allow for arrays of jQuery objects
8312			if ( Array.isArray( r ) || r instanceof $ ) {
8313				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8314					addRow( r[i], k );
8315				}
8316				return;
8317			}
8318	
8319			// If we get a TR element, then just add it directly - up to the dev
8320			// to add the correct number of columns etc
8321			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8322				r.setAttribute( 'data-dt-row', row.idx );
8323				rows.push( r );
8324			}
8325			else {
8326				// Otherwise create a row with a wrapper
8327				var created = $('<tr><td></td></tr>')
8328					.attr( 'data-dt-row', row.idx )
8329					.addClass( k );
8330				
8331				$('td', created)
8332					.addClass( k )
8333					.html( r )[0].colSpan = _fnVisbleColumns( ctx );
8334	
8335				rows.push( created[0] );
8336			}
8337		};
8338	
8339		addRow( data, klass );
8340	
8341		if ( row._details ) {
8342			row._details.detach();
8343		}
8344	
8345		row._details = $(rows);
8346	
8347		// If the children were already shown, that state should be retained
8348		if ( row._detailsShow ) {
8349			row._details.insertAfter( row.nTr );
8350		}
8351	};
8352	
8353	
8354	// Make state saving of child row details async to allow them to be batch processed
8355	var __details_state = DataTable.util.throttle(
8356		function (ctx) {
8357			_fnSaveState( ctx[0] )
8358		},
8359		500
8360	);
8361	
8362	
8363	var __details_remove = function ( api, idx )
8364	{
8365		var ctx = api.context;
8366	
8367		if ( ctx.length ) {
8368			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8369	
8370			if ( row && row._details ) {
8371				row._details.remove();
8372	
8373				row._detailsShow = undefined;
8374				row._details = undefined;
8375				$( row.nTr ).removeClass( 'dt-hasChild' );
8376				__details_state( ctx );
8377			}
8378		}
8379	};
8380	
8381	
8382	var __details_display = function ( api, show ) {
8383		var ctx = api.context;
8384	
8385		if ( ctx.length && api.length ) {
8386			var row = ctx[0].aoData[ api[0] ];
8387	
8388			if ( row._details ) {
8389				row._detailsShow = show;
8390	
8391				if ( show ) {
8392					row._details.insertAfter( row.nTr );
8393					$( row.nTr ).addClass( 'dt-hasChild' );
8394				}
8395				else {
8396					row._details.detach();
8397					$( row.nTr ).removeClass( 'dt-hasChild' );
8398				}
8399	
8400				_fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )
8401	
8402				__details_events( ctx[0] );
8403				__details_state( ctx );
8404			}
8405		}
8406	};
8407	
8408	
8409	var __details_events = function ( settings )
8410	{
8411		var api = new _Api( settings );
8412		var namespace = '.dt.DT_details';
8413		var drawEvent = 'draw'+namespace;
8414		var colvisEvent = 'column-sizing'+namespace;
8415		var destroyEvent = 'destroy'+namespace;
8416		var data = settings.aoData;
8417	
8418		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8419	
8420		if ( _pluck( data, '_details' ).length > 0 ) {
8421			// On each draw, insert the required elements into the document
8422			api.on( drawEvent, function ( e, ctx ) {
8423				if ( settings !== ctx ) {
8424					return;
8425				}
8426	
8427				api.rows( {page:'current'} ).eq(0).each( function (idx) {
8428					// Internal data grab
8429					var row = data[ idx ];
8430	
8431					if ( row._detailsShow ) {
8432						row._details.insertAfter( row.nTr );
8433					}
8434				} );
8435			} );
8436	
8437			// Column visibility change - update the colspan
8438			api.on( colvisEvent, function ( e, ctx ) {
8439				if ( settings !== ctx ) {
8440					return;
8441				}
8442	
8443				// Update the colspan for the details rows (note, only if it already has
8444				// a colspan)
8445				var row, visible = _fnVisbleColumns( ctx );
8446	
8447				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8448					row = data[i];
8449	
8450					if ( row && row._details ) {
8451						row._details.each(function () {
8452							var el = $(this).children('td');
8453	
8454							if (el.length == 1) {
8455								el.attr('colspan', visible);
8456							}
8457						});
8458					}
8459				}
8460			} );
8461	
8462			// Table destroyed - nuke any child rows
8463			api.on( destroyEvent, function ( e, ctx ) {
8464				if ( settings !== ctx ) {
8465					return;
8466				}
8467	
8468				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8469					if ( data[i] && data[i]._details ) {
8470						__details_remove( api, i );
8471					}
8472				}
8473			} );
8474		}
8475	};
8476	
8477	// Strings for the method names to help minification
8478	var _emp = '';
8479	var _child_obj = _emp+'row().child';
8480	var _child_mth = _child_obj+'()';
8481	
8482	// data can be:
8483	//  tr
8484	//  string
8485	//  jQuery or array of any of the above
8486	_api_register( _child_mth, function ( data, klass ) {
8487		var ctx = this.context;
8488	
8489		if ( data === undefined ) {
8490			// get
8491			return ctx.length && this.length && ctx[0].aoData[ this[0] ]
8492				? ctx[0].aoData[ this[0] ]._details
8493				: undefined;
8494		}
8495		else if ( data === true ) {
8496			// show
8497			this.child.show();
8498		}
8499		else if ( data === false ) {
8500			// remove
8501			__details_remove( this );
8502		}
8503		else if ( ctx.length && this.length ) {
8504			// set
8505			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8506		}
8507	
8508		return this;
8509	} );
8510	
8511	
8512	_api_register( [
8513		_child_obj+'.show()',
8514		_child_mth+'.show()' // only when `child()` was called with parameters (without
8515	], function () {         // it returns an object and this method is not executed)
8516		__details_display( this, true );
8517		return this;
8518	} );
8519	
8520	
8521	_api_register( [
8522		_child_obj+'.hide()',
8523		_child_mth+'.hide()' // only when `child()` was called with parameters (without
8524	], function () {         // it returns an object and this method is not executed)
8525		__details_display( this, false );
8526		return this;
8527	} );
8528	
8529	
8530	_api_register( [
8531		_child_obj+'.remove()',
8532		_child_mth+'.remove()' // only when `child()` was called with parameters (without
8533	], function () {           // it returns an object and this method is not executed)
8534		__details_remove( this );
8535		return this;
8536	} );
8537	
8538	
8539	_api_register( _child_obj+'.isShown()', function () {
8540		var ctx = this.context;
8541	
8542		if ( ctx.length && this.length && ctx[0].aoData[ this[0] ] ) {
8543			// _detailsShown as false or undefined will fall through to return false
8544			return ctx[0].aoData[ this[0] ]._detailsShow || false;
8545		}
8546		return false;
8547	} );
8548	
8549	
8550	
8551	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8552	 * Columns
8553	 *
8554	 * {integer}           - column index (>=0 count from left, <0 count from right)
8555	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8556	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8557	 * "{string}:name"     - column name
8558	 * "{string}"          - jQuery selector on column header nodes
8559	 *
8560	 */
8561	
8562	// can be an array of these items, comma separated list, or an array of comma
8563	// separated lists
8564	
8565	var __re_column_selector = /^([^:]+)?:(name|title|visIdx|visible)$/;
8566	
8567	
8568	// r1 and r2 are redundant - but it means that the parameters match for the
8569	// iterator callback in columns().data()
8570	var __columnData = function ( settings, column, r1, r2, rows, type ) {
8571		var a = [];
8572		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8573			a.push( _fnGetCellData( settings, rows[row], column, type ) );
8574		}
8575		return a;
8576	};
8577	
8578	
8579	var __column_header = function ( settings, column, row ) {
8580		var header = settings.aoHeader;
8581		var target = row !== undefined
8582			? row
8583			: settings.bSortCellsTop // legacy support
8584				? 0
8585				: header.length - 1;
8586	
8587		return header[target][column].cell;
8588	};
8589	
8590	var __column_selector = function ( settings, selector, opts )
8591	{
8592		var
8593			columns = settings.aoColumns,
8594			names = _pluck( columns, 'sName' ),
8595			titles = _pluck( columns, 'sTitle' ),
8596			cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
8597			nodes = _unique( _flatten([], cells) );
8598		
8599		var run = function ( s ) {
8600			var selInt = _intVal( s );
8601	
8602			// Selector - all
8603			if ( s === '' ) {
8604				return _range( columns.length );
8605			}
8606	
8607			// Selector - index
8608			if ( selInt !== null ) {
8609				return [ selInt >= 0 ?
8610					selInt : // Count from left
8611					columns.length + selInt // Count from right (+ because its a negative value)
8612				];
8613			}
8614	
8615			// Selector = function
8616			if ( typeof s === 'function' ) {
8617				var rows = _selector_row_indexes( settings, opts );
8618	
8619				return columns.map(function (col, idx) {
8620					return s(
8621							idx,
8622							__columnData( settings, idx, 0, 0, rows ),
8623							__column_header( settings, idx )
8624						) ? idx : null;
8625				});
8626			}
8627	
8628			// jQuery or string selector
8629			var match = typeof s === 'string' ?
8630				s.match( __re_column_selector ) :
8631				'';
8632	
8633			if ( match ) {
8634				switch( match[2] ) {
8635					case 'visIdx':
8636					case 'visible':
8637						// Selector is a column index
8638						if (match[1] && match[1].match(/^\d+$/)) {
8639							var idx = parseInt( match[1], 10 );
8640	
8641							// Visible index given, convert to column index
8642							if ( idx < 0 ) {
8643								// Counting from the right
8644								var visColumns = columns.map( function (col,i) {
8645									return col.bVisible ? i : null;
8646								} );
8647								return [ visColumns[ visColumns.length + idx ] ];
8648							}
8649							// Counting from the left
8650							return [ _fnVisibleToColumnIndex( settings, idx ) ];
8651						}
8652						
8653						return columns.map( function (col, idx) {
8654							// Not visible, can't match
8655							if (! col.bVisible) {
8656								return null;
8657							}
8658	
8659							// Selector
8660							if (match[1]) {
8661								return $(nodes[idx]).filter(match[1]).length > 0 ? idx : null;
8662							}
8663	
8664							// `:visible` on its own
8665							return idx;
8666						} );
8667	
8668					case 'name':
8669						// match by name. `names` is column index complete and in order
8670						return names.map( function (name, i) {
8671							return name === match[1] ? i : null;
8672						} );
8673	
8674					case 'title':
8675						// match by column title
8676						return titles.map( function (title, i) {
8677							return title === match[1] ? i : null;
8678						} );
8679	
8680					default:
8681						return [];
8682				}
8683			}
8684	
8685			// Cell in the table body
8686			if ( s.nodeName && s._DT_CellIndex ) {
8687				return [ s._DT_CellIndex.column ];
8688			}
8689	
8690			// jQuery selector on the TH elements for the columns
8691			var jqResult = $( nodes )
8692				.filter( s )
8693				.map( function () {
8694					return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
8695				} )
8696				.toArray()
8697				.sort(function (a, b) {
8698					return a - b;
8699				});
8700	
8701			if ( jqResult.length || ! s.nodeName ) {
8702				return jqResult;
8703			}
8704	
8705			// Otherwise a node which might have a `dt-column` data attribute, or be
8706			// a child or such an element
8707			var host = $(s).closest('*[data-dt-column]');
8708			return host.length ?
8709				[ host.data('dt-column') ] :
8710				[];
8711		};
8712	
8713		return _selector_run( 'column', selector, run, settings, opts );
8714	};
8715	
8716	
8717	var __setColumnVis = function ( settings, column, vis ) {
8718		var
8719			cols = settings.aoColumns,
8720			col  = cols[ column ],
8721			data = settings.aoData,
8722			cells, i, ien, tr;
8723	
8724		// Get
8725		if ( vis === undefined ) {
8726			return col.bVisible;
8727		}
8728	
8729		// Set
8730		// No change
8731		if ( col.bVisible === vis ) {
8732			return false;
8733		}
8734	
8735		if ( vis ) {
8736			// Insert column
8737			// Need to decide if we should use appendChild or insertBefore
8738			var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column+1);
8739	
8740			for ( i=0, ien=data.length ; i<ien ; i++ ) {
8741				if (data[i]) {
8742					tr = data[i].nTr;
8743					cells = data[i].anCells;
8744	
8745					if ( tr ) {
8746						// insertBefore can act like appendChild if 2nd arg is null
8747						tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8748					}
8749				}
8750			}
8751		}
8752		else {
8753			// Remove column
8754			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
8755		}
8756	
8757		// Common actions
8758		col.bVisible = vis;
8759	
8760		_colGroup(settings);
8761		
8762		return true;
8763	};
8764	
8765	
8766	_api_register( 'columns()', function ( selector, opts ) {
8767		// argument shifting
8768		if ( selector === undefined ) {
8769			selector = '';
8770		}
8771		else if ( $.isPlainObject( selector ) ) {
8772			opts = selector;
8773			selector = '';
8774		}
8775	
8776		opts = _selector_opts( opts );
8777	
8778		var inst = this.iterator( 'table', function ( settings ) {
8779			return __column_selector( settings, selector, opts );
8780		}, 1 );
8781	
8782		// Want argument shifting here and in _row_selector?
8783		inst.selector.cols = selector;
8784		inst.selector.opts = opts;
8785	
8786		return inst;
8787	} );
8788	
8789	_api_registerPlural( 'columns().header()', 'column().header()', function ( row ) {
8790		return this.iterator( 'column', function (settings, column) {
8791			return __column_header(settings, column, row);
8792		}, 1 );
8793	} );
8794	
8795	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( row ) {
8796		return this.iterator( 'column', function ( settings, column ) {
8797			var footer = settings.aoFooter;
8798	
8799			if (! footer.length) {
8800				return null;
8801			}
8802	
8803			return settings.aoFooter[row !== undefined ? row : 0][column].cell;
8804		}, 1 );
8805	} );
8806	
8807	_api_registerPlural( 'columns().data()', 'column().data()', function () {
8808		return this.iterator( 'column-rows', __columnData, 1 );
8809	} );
8810	
8811	_api_registerPlural( 'columns().render()', 'column().render()', function ( type ) {
8812		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8813			return __columnData( settings, column, i, j, rows, type );
8814		}, 1 );
8815	} );
8816	
8817	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8818		return this.iterator( 'column', function ( settings, column ) {
8819			return settings.aoColumns[column].mData;
8820		}, 1 );
8821	} );
8822	
8823	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8824		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8825			return _pluck_order( settings.aoData, rows,
8826				type === 'search' ? '_aFilterData' : '_aSortData', column
8827			);
8828		}, 1 );
8829	} );
8830	
8831	_api_registerPlural( 'columns().init()', 'column().init()', function () {
8832		return this.iterator( 'column', function ( settings, column ) {
8833			return settings.aoColumns[column];
8834		}, 1 );
8835	} );
8836	
8837	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8838		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8839			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8840		}, 1 );
8841	} );
8842	
8843	_api_registerPlural( 'columns().titles()', 'column().title()', function (title, row) {
8844		return this.iterator( 'column', function ( settings, column ) {
8845			// Argument shifting
8846			if (typeof title === 'number') {
8847				row = title;
8848				title = undefined;
8849			}
8850	
8851			var span = $('span.dt-column-title', this.column(column).header(row));
8852	
8853			if (title !== undefined) {
8854				span.html(title);
8855				return this;
8856			}
8857	
8858			return span.html();
8859		}, 1 );
8860	} );
8861	
8862	_api_registerPlural( 'columns().types()', 'column().type()', function () {
8863		return this.iterator( 'column', function ( settings, column ) {
8864			var type = settings.aoColumns[column].sType;
8865	
8866			// If the type was invalidated, then resolve it. This actually does
8867			// all columns at the moment. Would only happen once if getting all
8868			// column's data types.
8869			if (! type) {
8870				_fnColumnTypes(settings);
8871			}
8872	
8873			return type;
8874		}, 1 );
8875	} );
8876	
8877	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8878		var that = this;
8879		var changed = [];
8880		var ret = this.iterator( 'column', function ( settings, column ) {
8881			if ( vis === undefined ) {
8882				return settings.aoColumns[ column ].bVisible;
8883			} // else
8884			
8885			if (__setColumnVis( settings, column, vis )) {
8886				changed.push(column);
8887			}
8888		} );
8889	
8890		// Group the column visibility changes
8891		if ( vis !== undefined ) {
8892			this.iterator( 'table', function ( settings ) {
8893				// Redraw the header after changes
8894				_fnDrawHead( settings, settings.aoHeader );
8895				_fnDrawHead( settings, settings.aoFooter );
8896		
8897				// Update colspan for no records display. Child rows and extensions will use their own
8898				// listeners to do this - only need to update the empty table item here
8899				if ( ! settings.aiDisplay.length ) {
8900					$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8901				}
8902		
8903				_fnSaveState( settings );
8904	
8905				// Second loop once the first is done for events
8906				that.iterator( 'column', function ( settings, column ) {
8907					if (changed.includes(column)) {
8908						_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8909					}
8910				} );
8911	
8912				if ( changed.length && (calc === undefined || calc) ) {
8913					that.columns.adjust();
8914				}
8915			});
8916		}
8917	
8918		return ret;
8919	} );
8920	
8921	_api_registerPlural( 'columns().widths()', 'column().width()', function () {
8922		// Injects a fake row into the table for just a moment so the widths can
8923		// be read, regardless of colspan in the header and rows being present in
8924		// the body
8925		var columns = this.columns(':visible').count();
8926		var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
8927	
8928		$(this.table().body()).append(row);
8929	
8930		var widths = row.children().map(function () {
8931			return $(this).outerWidth();
8932		});
8933	
8934		row.remove();
8935		
8936		return this.iterator( 'column', function ( settings, column ) {
8937			var visIdx = _fnColumnIndexToVisible( settings, column );
8938	
8939			return visIdx !== null ? widths[visIdx] : 0;
8940		}, 1);
8941	} );
8942	
8943	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8944		return this.iterator( 'column', function ( settings, column ) {
8945			return type === 'visible' ?
8946				_fnColumnIndexToVisible( settings, column ) :
8947				column;
8948		}, 1 );
8949	} );
8950	
8951	_api_register( 'columns.adjust()', function () {
8952		return this.iterator( 'table', function ( settings ) {
8953			// Force a column sizing to happen with a manual call - otherwise it can skip
8954			// if the size hasn't changed
8955			settings.containerWidth = -1;
8956	
8957			_fnAdjustColumnSizing( settings );
8958		}, 1 );
8959	} );
8960	
8961	_api_register( 'column.index()', function ( type, idx ) {
8962		if ( this.context.length !== 0 ) {
8963			var ctx = this.context[0];
8964	
8965			if ( type === 'fromVisible' || type === 'toData' ) {
8966				return _fnVisibleToColumnIndex( ctx, idx );
8967			}
8968			else if ( type === 'fromData' || type === 'toVisible' ) {
8969				return _fnColumnIndexToVisible( ctx, idx );
8970			}
8971		}
8972	} );
8973	
8974	_api_register( 'column()', function ( selector, opts ) {
8975		return _selector_first( this.columns( selector, opts ) );
8976	} );
8977	
8978	var __cell_selector = function ( settings, selector, opts )
8979	{
8980		var data = settings.aoData;
8981		var rows = _selector_row_indexes( settings, opts );
8982		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8983		var allCells = $(_flatten( [], cells ));
8984		var row;
8985		var columns = settings.aoColumns.length;
8986		var a, i, ien, j, o, host;
8987	
8988		var run = function ( s ) {
8989			var fnSelector = typeof s === 'function';
8990	
8991			if ( s === null || s === undefined || fnSelector ) {
8992				// All cells and function selectors
8993				a = [];
8994	
8995				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8996					row = rows[i];
8997	
8998					for ( j=0 ; j<columns ; j++ ) {
8999						o = {
9000							row: row,
9001							column: j
9002						};
9003	
9004						if ( fnSelector ) {
9005							// Selector - function
9006							host = data[ row ];
9007	
9008							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
9009								a.push( o );
9010							}
9011						}
9012						else {
9013							// Selector - all
9014							a.push( o );
9015						}
9016					}
9017				}
9018	
9019				return a;
9020			}
9021			
9022			// Selector - index
9023			if ( $.isPlainObject( s ) ) {
9024				// Valid cell index and its in the array of selectable rows
9025				return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
9026					[s] :
9027					[];
9028			}
9029	
9030			// Selector - jQuery filtered cells
9031			var jqResult = allCells
9032				.filter( s )
9033				.map( function (i, el) {
9034					return { // use a new object, in case someone changes the values
9035						row:    el._DT_CellIndex.row,
9036						column: el._DT_CellIndex.column
9037					};
9038				} )
9039				.toArray();
9040	
9041			if ( jqResult.length || ! s.nodeName ) {
9042				return jqResult;
9043			}
9044	
9045			// Otherwise the selector is a node, and there is one last option - the
9046			// element might be a child of an element which has dt-row and dt-column
9047			// data attributes
9048			host = $(s).closest('*[data-dt-row]');
9049			return host.length ?
9050				[ {
9051					row: host.data('dt-row'),
9052					column: host.data('dt-column')
9053				} ] :
9054				[];
9055		};
9056	
9057		return _selector_run( 'cell', selector, run, settings, opts );
9058	};
9059	
9060	
9061	
9062	
9063	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
9064		// Argument shifting
9065		if ( $.isPlainObject( rowSelector ) ) {
9066			// Indexes
9067			if ( rowSelector.row === undefined ) {
9068				// Selector options in first parameter
9069				opts = rowSelector;
9070				rowSelector = null;
9071			}
9072			else {
9073				// Cell index objects in first parameter
9074				opts = columnSelector;
9075				columnSelector = null;
9076			}
9077		}
9078		if ( $.isPlainObject( columnSelector ) ) {
9079			opts = columnSelector;
9080			columnSelector = null;
9081		}
9082	
9083		// Cell selector
9084		if ( columnSelector === null || columnSelector === undefined ) {
9085			return this.iterator( 'table', function ( settings ) {
9086				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
9087			} );
9088		}
9089	
9090		// The default built in options need to apply to row and columns
9091		var internalOpts = opts ? {
9092			page: opts.page,
9093			order: opts.order,
9094			search: opts.search
9095		} : {};
9096	
9097		// Row + column selector
9098		var columns = this.columns( columnSelector, internalOpts );
9099		var rows = this.rows( rowSelector, internalOpts );
9100		var i, ien, j, jen;
9101	
9102		var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
9103			var a = [];
9104	
9105			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
9106				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
9107					a.push( {
9108						row:    rows[idx][i],
9109						column: columns[idx][j]
9110					} );
9111				}
9112			}
9113	
9114			return a;
9115		}, 1 );
9116	
9117		// There is currently only one extension which uses a cell selector extension
9118		// It is a _major_ performance drag to run this if it isn't needed, so this is
9119		// an extension specific check at the moment
9120		var cells = opts && opts.selected ?
9121			this.cells( cellsNoOpts, opts ) :
9122			cellsNoOpts;
9123	
9124		$.extend( cells.selector, {
9125			cols: columnSelector,
9126			rows: rowSelector,
9127			opts: opts
9128		} );
9129	
9130		return cells;
9131	} );
9132	
9133	
9134	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
9135		return this.iterator( 'cell', function ( settings, row, column ) {
9136			var data = settings.aoData[ row ];
9137	
9138			return data && data.anCells ?
9139				data.anCells[ column ] :
9140				undefined;
9141		}, 1 );
9142	} );
9143	
9144	
9145	_api_register( 'cells().data()', function () {
9146		return this.iterator( 'cell', function ( settings, row, column ) {
9147			return _fnGetCellData( settings, row, column );
9148		}, 1 );
9149	} );
9150	
9151	
9152	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
9153		type = type === 'search' ? '_aFilterData' : '_aSortData';
9154	
9155		return this.iterator( 'cell', function ( settings, row, column ) {
9156			return settings.aoData[ row ][ type ][ column ];
9157		}, 1 );
9158	} );
9159	
9160	
9161	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
9162		return this.iterator( 'cell', function ( settings, row, column ) {
9163			return _fnGetCellData( settings, row, column, type );
9164		}, 1 );
9165	} );
9166	
9167	
9168	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
9169		return this.iterator( 'cell', function ( settings, row, column ) {
9170			return {
9171				row: row,
9172				column: column,
9173				columnVisible: _fnColumnIndexToVisible( settings, column )
9174			};
9175		}, 1 );
9176	} );
9177	
9178	
9179	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
9180		return this.iterator( 'cell', function ( settings, row, column ) {
9181			_fnInvalidate( settings, row, src, column );
9182		} );
9183	} );
9184	
9185	
9186	
9187	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
9188		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
9189	} );
9190	
9191	
9192	_api_register( 'cell().data()', function ( data ) {
9193		var ctx = this.context;
9194		var cell = this[0];
9195	
9196		if ( data === undefined ) {
9197			// Get
9198			return ctx.length && cell.length ?
9199				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
9200				undefined;
9201		}
9202	
9203		// Set
9204		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
9205		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
9206	
9207		return this;
9208	} );
9209	
9210	
9211	
9212	/**
9213	 * Get current ordering (sorting) that has been applied to the table.
9214	 *
9215	 * @returns {array} 2D array containing the sorting information for the first
9216	 *   table in the current context. Each element in the parent array represents
9217	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
9218	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
9219	 *   the column index that the sorting condition applies to, the second is the
9220	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
9221	 *   index of the sorting order from the `column.sorting` initialisation array.
9222	 *//**
9223	 * Set the ordering for the table.
9224	 *
9225	 * @param {integer} order Column index to sort upon.
9226	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
9227	 * @returns {DataTables.Api} this
9228	 *//**
9229	 * Set the ordering for the table.
9230	 *
9231	 * @param {array} order 1D array of sorting information to be applied.
9232	 * @param {array} [...] Optional additional sorting conditions
9233	 * @returns {DataTables.Api} this
9234	 *//**
9235	 * Set the ordering for the table.
9236	 *
9237	 * @param {array} order 2D array of sorting information to be applied.
9238	 * @returns {DataTables.Api} this
9239	 */
9240	_api_register( 'order()', function ( order, dir ) {
9241		var ctx = this.context;
9242		var args = Array.prototype.slice.call( arguments );
9243	
9244		if ( order === undefined ) {
9245			// get
9246			return ctx.length !== 0 ?
9247				ctx[0].aaSorting :
9248				undefined;
9249		}
9250	
9251		// set
9252		if ( typeof order === 'number' ) {
9253			// Simple column / direction passed in
9254			order = [ [ order, dir ] ];
9255		}
9256		else if ( args.length > 1 ) {
9257			// Arguments passed in (list of 1D arrays)
9258			order = args;
9259		}
9260		// otherwise a 2D array was passed in
9261	
9262		return this.iterator( 'table', function ( settings ) {
9263			settings.aaSorting = Array.isArray(order) ? order.slice() : order;
9264		} );
9265	} );
9266	
9267	
9268	/**
9269	 * Attach a sort listener to an element for a given column
9270	 *
9271	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
9272	 *   listener to. This can take the form of a single DOM node, a jQuery
9273	 *   collection of nodes or a jQuery selector which will identify the node(s).
9274	 * @param {integer} column the column that a click on this node will sort on
9275	 * @param {function} [callback] callback function when sort is run
9276	 * @returns {DataTables.Api} this
9277	 */
9278	_api_register( 'order.listener()', function ( node, column, callback ) {
9279		return this.iterator( 'table', function ( settings ) {
9280			_fnSortAttachListener(settings, node, {}, column, callback);
9281		} );
9282	} );
9283	
9284	
9285	_api_register( 'order.fixed()', function ( set ) {
9286		if ( ! set ) {
9287			var ctx = this.context;
9288			var fixed = ctx.length ?
9289				ctx[0].aaSortingFixed :
9290				undefined;
9291	
9292			return Array.isArray( fixed ) ?
9293				{ pre: fixed } :
9294				fixed;
9295		}
9296	
9297		return this.iterator( 'table', function ( settings ) {
9298			settings.aaSortingFixed = $.extend( true, {}, set );
9299		} );
9300	} );
9301	
9302	
9303	// Order by the selected column(s)
9304	_api_register( [
9305		'columns().order()',
9306		'column().order()'
9307	], function ( dir ) {
9308		var that = this;
9309	
9310		if ( ! dir ) {
9311			return this.iterator( 'column', function ( settings, idx ) {
9312				var sort = _fnSortFlatten( settings );
9313	
9314				for ( var i=0, ien=sort.length ; i<ien ; i++ ) {
9315					if ( sort[i].col === idx ) {
9316						return sort[i].dir;
9317					}
9318				}
9319	
9320				return null;
9321			}, 1 );
9322		}
9323		else {
9324			return this.iterator( 'table', function ( settings, i ) {
9325				settings.aaSorting = that[i].map( function (col) {
9326					return [ col, dir ];
9327				} );
9328			} );
9329		}
9330	} );
9331	
9332	_api_registerPlural('columns().orderable()', 'column().orderable()', function ( directions ) {
9333		return this.iterator( 'column', function ( settings, idx ) {
9334			var col = settings.aoColumns[idx];
9335	
9336			return directions ?
9337				col.asSorting :
9338				col.bSortable;
9339		}, 1 );
9340	} );
9341	
9342	
9343	_api_register( 'processing()', function ( show ) {
9344		return this.iterator( 'table', function ( ctx ) {
9345			_fnProcessingDisplay( ctx, show );
9346		} );
9347	} );
9348	
9349	
9350	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9351		var ctx = this.context;
9352	
9353		if ( input === undefined ) {
9354			// get
9355			return ctx.length !== 0 ?
9356				ctx[0].oPreviousSearch.search :
9357				undefined;
9358		}
9359	
9360		// set
9361		return this.iterator( 'table', function ( settings ) {
9362			if ( ! settings.oFeatures.bFilter ) {
9363				return;
9364			}
9365	
9366			if (typeof regex === 'object') {
9367				// New style options to pass to the search builder
9368				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, regex, {
9369					search: input
9370				} ) );
9371			}
9372			else {
9373				// Compat for the old options
9374				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, {
9375					search: input,
9376					regex:  regex === null ? false : regex,
9377					smart:  smart === null ? true  : smart,
9378					caseInsensitive: caseInsen === null ? true : caseInsen
9379				} ) );
9380			}
9381		} );
9382	} );
9383	
9384	_api_register( 'search.fixed()', function ( name, search ) {
9385		var ret = this.iterator( true, 'table', function ( settings ) {
9386			var fixed = settings.searchFixed;
9387	
9388			if (! name) {
9389				return Object.keys(fixed)
9390			}
9391			else if (search === undefined) {
9392				return fixed[name];
9393			}
9394			else if (search === null) {
9395				delete fixed[name];
9396			}
9397			else {
9398				fixed[name] = search;
9399			}
9400	
9401			return this;
9402		} );
9403	
9404		return name !== undefined && search === undefined
9405			? ret[0]
9406			: ret;
9407	} );
9408	
9409	_api_registerPlural(
9410		'columns().search()',
9411		'column().search()',
9412		function ( input, regex, smart, caseInsen ) {
9413			return this.iterator( 'column', function ( settings, column ) {
9414				var preSearch = settings.aoPreSearchCols;
9415	
9416				if ( input === undefined ) {
9417					// get
9418					return preSearch[ column ].search;
9419				}
9420	
9421				// set
9422				if ( ! settings.oFeatures.bFilter ) {
9423					return;
9424				}
9425	
9426				if (typeof regex === 'object') {
9427					// New style options to pass to the search builder
9428					$.extend( preSearch[ column ], regex, {
9429						search: input
9430					} );
9431				}
9432				else {
9433					// Old style (with not all options available)
9434					$.extend( preSearch[ column ], {
9435						search: input,
9436						regex:  regex === null ? false : regex,
9437						smart:  smart === null ? true  : smart,
9438						caseInsensitive: caseInsen === null ? true : caseInsen
9439					} );
9440				}
9441	
9442				_fnFilterComplete( settings, settings.oPreviousSearch );
9443			} );
9444		}
9445	);
9446	
9447	_api_register([
9448			'columns().search.fixed()',
9449			'column().search.fixed()'
9450		],
9451		function ( name, search ) {
9452			var ret = this.iterator( true, 'column', function ( settings, colIdx ) {
9453				var fixed = settings.aoColumns[colIdx].searchFixed;
9454	
9455				if (! name) {
9456					return Object.keys(fixed)
9457				}
9458				else if (search === undefined) {
9459					return fixed[name];
9460				}
9461				else if (search === null) {
9462					delete fixed[name];
9463				}
9464				else {
9465					fixed[name] = search;
9466				}
9467	
9468				return this;
9469			} );
9470	
9471			return name !== undefined && search === undefined
9472				? ret[0]
9473				: ret;
9474		}
9475	);
9476	/*
9477	 * State API methods
9478	 */
9479	
9480	_api_register( 'state()', function ( set, ignoreTime ) {
9481		// getter
9482		if ( ! set ) {
9483			return this.context.length ?
9484				this.context[0].oSavedState :
9485				null;
9486		}
9487	
9488		var setMutate = $.extend( true, {}, set );
9489	
9490		// setter
9491		return this.iterator( 'table', function ( settings ) {
9492			if ( ignoreTime !== false ) {
9493				setMutate.time = +new Date() + 100;
9494			}
9495	
9496			_fnImplementState( settings, setMutate, function(){} );
9497		} );
9498	} );
9499	
9500	
9501	_api_register( 'state.clear()', function () {
9502		return this.iterator( 'table', function ( settings ) {
9503			// Save an empty object
9504			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9505		} );
9506	} );
9507	
9508	
9509	_api_register( 'state.loaded()', function () {
9510		return this.context.length ?
9511			this.context[0].oLoadedState :
9512			null;
9513	} );
9514	
9515	
9516	_api_register( 'state.save()', function () {
9517		return this.iterator( 'table', function ( settings ) {
9518			_fnSaveState( settings );
9519		} );
9520	} );
9521	
9522	// Can be assigned in DateTable.use() - note luxon and moment vars are in helpers.js
9523	var __bootstrap;
9524	var __foundation;
9525	
9526	/**
9527	 * Set the libraries that DataTables uses, or the global objects.
9528	 * Note that the arguments can be either way around (legacy support)
9529	 * and the second is optional. See docs.
9530	 */
9531	DataTable.use = function (arg1, arg2) {
9532		// Reverse arguments for legacy support
9533		var module = typeof arg1 === 'string'
9534			? arg2
9535			: arg1;
9536		var type = typeof arg2 === 'string'
9537			? arg2
9538			: arg1;
9539	
9540		// Getter
9541		if (module === undefined && typeof type === 'string') {
9542			switch (type) {
9543				case 'lib':
9544				case 'jq':
9545					return $;
9546	
9547				case 'win':
9548					return window;
9549	
9550				case 'datetime':
9551					return DataTable.DateTime;
9552	
9553				case 'luxon':
9554					return __luxon;
9555	
9556				case 'moment':
9557					return __moment;
9558	
9559				case 'bootstrap':
9560					// Use local if set, otherwise try window, which could be undefined
9561					return __bootstrap || window.bootstrap;
9562	
9563				case 'foundation':
9564					// Ditto
9565					return __foundation || window.Foundation;
9566	
9567				default:
9568					return null;
9569			}
9570		}
9571	
9572		// Setter
9573		if (type === 'lib' || type === 'jq' || (module && module.fn && module.fn.jquery)) {
9574			$ = module;
9575		}
9576		else if (type === 'win' || (module && module.document)) {
9577			window = module;
9578			document = module.document;
9579		}
9580		else if (type === 'datetime' || (module && module.type === 'DateTime')) {
9581			DataTable.DateTime = module;
9582		}
9583		else if (type === 'luxon' || (module && module.FixedOffsetZone)) {
9584			__luxon = module;
9585		}
9586		else if (type === 'moment' || (module && module.isMoment)) {
9587			__moment = module;
9588		}
9589		else if (type === 'bootstrap' || (module && module.Modal && module.Modal.NAME === 'modal'))
9590		{
9591			// This is currently for BS5 only. BS3/4 attach to jQuery, so no need to use `.use()`
9592			__bootstrap = module;
9593		}
9594		else if (type === 'foundation' || (module && module.Reveal)) {
9595			__foundation = module;
9596		}
9597	}
9598	
9599	/**
9600	 * CommonJS factory function pass through. This will check if the arguments
9601	 * given are a window object or a jQuery object. If so they are set
9602	 * accordingly.
9603	 * @param {*} root Window
9604	 * @param {*} jq jQUery
9605	 * @returns {boolean} Indicator
9606	 */
9607	DataTable.factory = function (root, jq) {
9608		var is = false;
9609	
9610		// Test if the first parameter is a window object
9611		if (root && root.document) {
9612			window = root;
9613			document = root.document;
9614		}
9615	
9616		// Test if the second parameter is a jQuery object
9617		if (jq && jq.fn && jq.fn.jquery) {
9618			$ = jq;
9619			is = true;
9620		}
9621	
9622		return is;
9623	}
9624	
9625	/**
9626	 * Provide a common method for plug-ins to check the version of DataTables being
9627	 * used, in order to ensure compatibility.
9628	 *
9629	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
9630	 *    Note that the formats "X" and "X.Y" are also acceptable.
9631	 *  @param {string} [version2=current DataTables version] As above, but optional.
9632	 *   If not given the current DataTables version will be used.
9633	 *  @returns {boolean} true if this version of DataTables is greater or equal to
9634	 *    the required version, or false if this version of DataTales is not
9635	 *    suitable
9636	 *  @static
9637	 *  @dtopt API-Static
9638	 *
9639	 *  @example
9640	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9641	 */
9642	DataTable.versionCheck = function( version, version2 )
9643	{
9644		var aThis = version2 ?
9645			version2.split('.') :
9646			DataTable.version.split('.');
9647		var aThat = version.split('.');
9648		var iThis, iThat;
9649	
9650		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9651			iThis = parseInt( aThis[i], 10 ) || 0;
9652			iThat = parseInt( aThat[i], 10 ) || 0;
9653	
9654			// Parts are the same, keep comparing
9655			if (iThis === iThat) {
9656				continue;
9657			}
9658	
9659			// Parts are different, return immediately
9660			return iThis > iThat;
9661		}
9662	
9663		return true;
9664	};
9665	
9666	
9667	/**
9668	 * Check if a `<table>` node is a DataTable table already or not.
9669	 *
9670	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9671	 *      selector for the table to test. Note that if more than more than one
9672	 *      table is passed on, only the first will be checked
9673	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
9674	 *  @static
9675	 *  @dtopt API-Static
9676	 *
9677	 *  @example
9678	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9679	 *      $('#example').dataTable();
9680	 *    }
9681	 */
9682	DataTable.isDataTable = function ( table )
9683	{
9684		var t = $(table).get(0);
9685		var is = false;
9686	
9687		if ( table instanceof DataTable.Api ) {
9688			return true;
9689		}
9690	
9691		$.each( DataTable.settings, function (i, o) {
9692			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9693			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9694	
9695			if ( o.nTable === t || head === t || foot === t ) {
9696				is = true;
9697			}
9698		} );
9699	
9700		return is;
9701	};
9702	
9703	
9704	/**
9705	 * Get all DataTable tables that have been initialised - optionally you can
9706	 * select to get only currently visible tables.
9707	 *
9708	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9709	 *    or visible tables only.
9710	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9711	 *    DataTables
9712	 *  @static
9713	 *  @dtopt API-Static
9714	 *
9715	 *  @example
9716	 *    $.each( $.fn.dataTable.tables(true), function () {
9717	 *      $(table).DataTable().columns.adjust();
9718	 *    } );
9719	 */
9720	DataTable.tables = function ( visible )
9721	{
9722		var api = false;
9723	
9724		if ( $.isPlainObject( visible ) ) {
9725			api = visible.api;
9726			visible = visible.visible;
9727		}
9728	
9729		var a = DataTable.settings
9730			.filter( function (o) {
9731				return !visible || (visible && $(o.nTable).is(':visible')) 
9732					? true
9733					: false;
9734			} )
9735			.map( function (o) {
9736				return o.nTable;
9737			});
9738	
9739		return api ?
9740			new _Api( a ) :
9741			a;
9742	};
9743	
9744	
9745	/**
9746	 * Convert from camel case parameters to Hungarian notation. This is made public
9747	 * for the extensions to provide the same ability as DataTables core to accept
9748	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9749	 * parameters.
9750	 *
9751	 *  @param {object} src The model object which holds all parameters that can be
9752	 *    mapped.
9753	 *  @param {object} user The object to convert from camel case to Hungarian.
9754	 *  @param {boolean} force When set to `true`, properties which already have a
9755	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
9756	 *    won't be.
9757	 */
9758	DataTable.camelToHungarian = _fnCamelToHungarian;
9759	
9760	
9761	
9762	/**
9763	 *
9764	 */
9765	_api_register( '$()', function ( selector, opts ) {
9766		var
9767			rows   = this.rows( opts ).nodes(), // Get all rows
9768			jqRows = $(rows);
9769	
9770		return $( [].concat(
9771			jqRows.filter( selector ).toArray(),
9772			jqRows.find( selector ).toArray()
9773		) );
9774	} );
9775	
9776	
9777	// jQuery functions to operate on the tables
9778	$.each( [ 'on', 'one', 'off' ], function (i, key) {
9779		_api_register( key+'()', function ( /* event, handler */ ) {
9780			var args = Array.prototype.slice.call(arguments);
9781	
9782			// Add the `dt` namespace automatically if it isn't already present
9783			args[0] = args[0].split( /\s/ ).map( function ( e ) {
9784				return ! e.match(/\.dt\b/) ?
9785					e+'.dt' :
9786					e;
9787				} ).join( ' ' );
9788	
9789			var inst = $( this.tables().nodes() );
9790			inst[key].apply( inst, args );
9791			return this;
9792		} );
9793	} );
9794	
9795	
9796	_api_register( 'clear()', function () {
9797		return this.iterator( 'table', function ( settings ) {
9798			_fnClearTable( settings );
9799		} );
9800	} );
9801	
9802	
9803	_api_register( 'error()', function (msg) {
9804		return this.iterator( 'table', function ( settings ) {
9805			_fnLog( settings, 0, msg );
9806		} );
9807	} );
9808	
9809	
9810	_api_register( 'settings()', function () {
9811		return new _Api( this.context, this.context );
9812	} );
9813	
9814	
9815	_api_register( 'init()', function () {
9816		var ctx = this.context;
9817		return ctx.length ? ctx[0].oInit : null;
9818	} );
9819	
9820	
9821	_api_register( 'data()', function () {
9822		return this.iterator( 'table', function ( settings ) {
9823			return _pluck( settings.aoData, '_aData' );
9824		} ).flatten();
9825	} );
9826	
9827	
9828	_api_register( 'trigger()', function ( name, args, bubbles ) {
9829		return this.iterator( 'table', function ( settings ) {
9830			return _fnCallbackFire( settings, null, name, args, bubbles );
9831		} ).flatten();
9832	} );
9833	
9834	
9835	_api_register( 'ready()', function ( fn ) {
9836		var ctx = this.context;
9837	
9838		// Get status of first table
9839		if (! fn) {
9840			return ctx.length
9841				? (ctx[0]._bInitComplete || false)
9842				: null;
9843		}
9844	
9845		// Function to run either once the table becomes ready or
9846		// immediately if it is already ready.
9847		return this.tables().every(function () {
9848			var api = this;
9849	
9850			if (this.context[0]._bInitComplete) {
9851				fn.call(api);
9852			}
9853			else {
9854				this.on('init.dt.DT', function () {
9855					fn.call(api);
9856				});
9857			}
9858		} );
9859	} );
9860	
9861	
9862	_api_register( 'destroy()', function ( remove ) {
9863		remove = remove || false;
9864	
9865		return this.iterator( 'table', function ( settings ) {
9866			var classes   = settings.oClasses;
9867			var table     = settings.nTable;
9868			var tbody     = settings.nTBody;
9869			var thead     = settings.nTHead;
9870			var tfoot     = settings.nTFoot;
9871			var jqTable   = $(table);
9872			var jqTbody   = $(tbody);
9873			var jqWrapper = $(settings.nTableWrapper);
9874			var rows      = settings.aoData.map( function (r) { return r ? r.nTr : null; } );
9875			var orderClasses = classes.order;
9876	
9877			// Flag to note that the table is currently being destroyed - no action
9878			// should be taken
9879			settings.bDestroying = true;
9880	
9881			// Fire off the destroy callbacks for plug-ins etc
9882			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings], true );
9883	
9884			// If not being removed from the document, make all columns visible
9885			if ( ! remove ) {
9886				new _Api( settings ).columns().visible( true );
9887			}
9888	
9889			// Container width change listener
9890			if (settings.resizeObserver) {
9891				settings.resizeObserver.disconnect();
9892			}
9893	
9894			// Blitz all `DT` namespaced events (these are internal events, the
9895			// lowercase, `dt` events are user subscribed and they are responsible
9896			// for removing them
9897			jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9898			$(window).off('.DT-'+settings.sInstance);
9899	
9900			// When scrolling we had to break the table up - restore it
9901			if ( table != thead.parentNode ) {
9902				jqTable.children('thead').detach();
9903				jqTable.append( thead );
9904			}
9905	
9906			if ( tfoot && table != tfoot.parentNode ) {
9907				jqTable.children('tfoot').detach();
9908				jqTable.append( tfoot );
9909			}
9910	
9911			// Clean up the header
9912			$(thead).find('span.dt-column-order').remove();
9913			$(thead).find('span.dt-column-title').each(function () {
9914				var title = $(this).html();
9915				$(this).parent().append(title);
9916				$(this).remove();
9917			});
9918	
9919			settings.colgroup.remove();
9920	
9921			settings.aaSorting = [];
9922			settings.aaSortingFixed = [];
9923			_fnSortingClasses( settings );
9924	
9925			$(jqTable).find('th, td').removeClass(
9926				$.map(DataTable.ext.type.className, function (v) {
9927					return v;
9928				}).join(' ')
9929			);
9930	
9931			$('th, td', thead)
9932				.removeClass(
9933					orderClasses.none + ' ' +
9934					orderClasses.canAsc + ' ' +
9935					orderClasses.canDesc + ' ' +
9936					orderClasses.isAsc + ' ' +
9937					orderClasses.isDesc
9938				)
9939				.css('width', '')
9940				.removeAttr('data-dt-column')
9941				.removeAttr('aria-sort');
9942	
9943			// Add the TR elements back into the table in their original order
9944			jqTbody.children().detach();
9945			jqTbody.append( rows );
9946	
9947			var orig = settings.nTableWrapper.parentNode;
9948			var insertBefore = settings.nTableWrapper.nextSibling;
9949	
9950			// Remove the DataTables generated nodes, events and classes
9951			var removedMethod = remove ? 'remove' : 'detach';
9952			jqTable[ removedMethod ]();
9953			jqWrapper[ removedMethod ]();
9954	
9955			// If we need to reattach the table to the document
9956			if ( ! remove && orig ) {
9957				// insertBefore acts like appendChild if !arg[1]
9958				orig.insertBefore( table, insertBefore );
9959	
9960				// Restore the width of the original table - was read from the style property,
9961				// so we can restore directly to that
9962				jqTable
9963					.css( 'width', settings.sDestroyWidth )
9964					.removeClass( classes.table );
9965			}
9966	
9967			/* Remove the settings object from the settings array */
9968			var idx = DataTable.settings.indexOf(settings);
9969			if ( idx !== -1 ) {
9970				DataTable.settings.splice( idx, 1 );
9971			}
9972		} );
9973	} );
9974	
9975	
9976	// Add the `every()` method for rows, columns and cells in a compact form
9977	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9978		_api_register( type+'s().every()', function ( fn ) {
9979			var opts = this.selector.opts;
9980			var api = this;
9981			var inst;
9982			var counter = 0;
9983	
9984			return this.iterator( 'every', function ( settings, selectedIdx, tableIdx ) {
9985				inst = api[ type ](selectedIdx, opts);
9986	
9987				if (type === 'cell') {
9988					fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
9989				}
9990				else {
9991					fn.call(inst, selectedIdx, tableIdx, counter);
9992				}
9993	
9994				counter++;
9995			} );
9996		} );
9997	} );
9998	
9999	
10000	// i18n method for extensions to be able to use the language object from the
10001	// DataTable
10002	_api_register( 'i18n()', function ( token, def, plural ) {
10003		var ctx = this.context[0];
10004		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
10005	
10006		if ( resolved === undefined ) {
10007			resolved = def;
10008		}
10009	
10010		if ( $.isPlainObject( resolved ) ) {
10011			resolved = plural !== undefined && resolved[ plural ] !== undefined ?
10012				resolved[ plural ] :
10013				resolved._;
10014		}
10015	
10016		return typeof resolved === 'string'
10017			? resolved.replace( '%d', plural ) // nb: plural might be undefined,
10018			: resolved;
10019	} );
10020	
10021	/**
10022	 * Version string for plug-ins to check compatibility. Allowed format is
10023	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
10024	 * only for non-release builds. See https://semver.org/ for more information.
10025	 *  @member
10026	 *  @type string
10027	 *  @default Version number
10028	 */
10029	DataTable.version = "2.2.2";
10030	
10031	/**
10032	 * Private data store, containing all of the settings objects that are
10033	 * created for the tables on a given page.
10034	 *
10035	 * Note that the `DataTable.settings` object is aliased to
10036	 * `jQuery.fn.dataTableExt` through which it may be accessed and
10037	 * manipulated, or `jQuery.fn.dataTable.settings`.
10038	 *  @member
10039	 *  @type array
10040	 *  @default []
10041	 *  @private
10042	 */
10043	DataTable.settings = [];
10044	
10045	/**
10046	 * Object models container, for the various models that DataTables has
10047	 * available to it. These models define the objects that are used to hold
10048	 * the active state and configuration of the table.
10049	 *  @namespace
10050	 */
10051	DataTable.models = {};
10052	
10053	
10054	
10055	/**
10056	 * Template object for the way in which DataTables holds information about
10057	 * search information for the global filter and individual column filters.
10058	 *  @namespace
10059	 */
10060	DataTable.models.oSearch = {
10061		/**
10062		 * Flag to indicate if the filtering should be case insensitive or not
10063		 */
10064		"caseInsensitive": true,
10065	
10066		/**
10067		 * Applied search term
10068		 */
10069		"search": "",
10070	
10071		/**
10072		 * Flag to indicate if the search term should be interpreted as a
10073		 * regular expression (true) or not (false) and therefore and special
10074		 * regex characters escaped.
10075		 */
10076		"regex": false,
10077	
10078		/**
10079		 * Flag to indicate if DataTables is to use its smart filtering or not.
10080		 */
10081		"smart": true,
10082	
10083		/**
10084		 * Flag to indicate if DataTables should only trigger a search when
10085		 * the return key is pressed.
10086		 */
10087		"return": false
10088	};
10089	
10090	
10091	
10092	
10093	/**
10094	 * Template object for the way in which DataTables holds information about
10095	 * each individual row. This is the object format used for the settings
10096	 * aoData array.
10097	 *  @namespace
10098	 */
10099	DataTable.models.oRow = {
10100		/**
10101		 * TR element for the row
10102		 */
10103		"nTr": null,
10104	
10105		/**
10106		 * Array of TD elements for each row. This is null until the row has been
10107		 * created.
10108		 */
10109		"anCells": null,
10110	
10111		/**
10112		 * Data object from the original data source for the row. This is either
10113		 * an array if using the traditional form of DataTables, or an object if
10114		 * using mData options. The exact type will depend on the passed in
10115		 * data from the data source, or will be an array if using DOM a data
10116		 * source.
10117		 */
10118		"_aData": [],
10119	
10120		/**
10121		 * Sorting data cache - this array is ostensibly the same length as the
10122		 * number of columns (although each index is generated only as it is
10123		 * needed), and holds the data that is used for sorting each column in the
10124		 * row. We do this cache generation at the start of the sort in order that
10125		 * the formatting of the sort data need be done only once for each cell
10126		 * per sort. This array should not be read from or written to by anything
10127		 * other than the master sorting methods.
10128		 */
10129		"_aSortData": null,
10130	
10131		/**
10132		 * Per cell filtering data cache. As per the sort data cache, used to
10133		 * increase the performance of the filtering in DataTables
10134		 */
10135		"_aFilterData": null,
10136	
10137		/**
10138		 * Filtering data cache. This is the same as the cell filtering cache, but
10139		 * in this case a string rather than an array. This is easily computed with
10140		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
10141		 * needed on every search (memory traded for performance)
10142		 */
10143		"_sFilterRow": null,
10144	
10145		/**
10146		 * Denote if the original data source was from the DOM, or the data source
10147		 * object. This is used for invalidating data, so DataTables can
10148		 * automatically read data from the original source, unless uninstructed
10149		 * otherwise.
10150		 */
10151		"src": null,
10152	
10153		/**
10154		 * Index in the aoData array. This saves an indexOf lookup when we have the
10155		 * object, but want to know the index
10156		 */
10157		"idx": -1,
10158	
10159		/**
10160		 * Cached display value
10161		 */
10162		displayData: null
10163	};
10164	
10165	
10166	/**
10167	 * Template object for the column information object in DataTables. This object
10168	 * is held in the settings aoColumns array and contains all the information that
10169	 * DataTables needs about each individual column.
10170	 *
10171	 * Note that this object is related to {@link DataTable.defaults.column}
10172	 * but this one is the internal data store for DataTables's cache of columns.
10173	 * It should NOT be manipulated outside of DataTables. Any configuration should
10174	 * be done through the initialisation options.
10175	 *  @namespace
10176	 */
10177	DataTable.models.oColumn = {
10178		/**
10179		 * Column index.
10180		 */
10181		"idx": null,
10182	
10183		/**
10184		 * A list of the columns that sorting should occur on when this column
10185		 * is sorted. That this property is an array allows multi-column s
10185orting
10186		 * to be defined for a column (for example first name / last name columns
10187		 * would benefit from this). The values are integers pointing to the
10188		 * columns to be sorted on (typically it will be a single integer pointing
10189		 * at itself, but that doesn't need to be the case).
10190		 */
10191		"aDataSort": null,
10192	
10193		/**
10194		 * Define the sorting directions that are applied to the column, in sequence
10195		 * as the column is repeatedly sorted upon - i.e. the first value is used
10196		 * as the sorting direction when the column if first sorted (clicked on).
10197		 * Sort it again (click again) and it will move on to the next index.
10198		 * Repeat until loop.
10199		 */
10200		"asSorting": null,
10201	
10202		/**
10203		 * Flag to indicate if the column is searchable, and thus should be included
10204		 * in the filtering or not.
10205		 */
10206		"bSearchable": null,
10207	
10208		/**
10209		 * Flag to indicate if the column is sortable or not.
10210		 */
10211		"bSortable": null,
10212	
10213		/**
10214		 * Flag to indicate if the column is currently visible in the table or not
10215		 */
10216		"bVisible": null,
10217	
10218		/**
10219		 * Store for manual type assignment using the `column.type` option. This
10220		 * is held in store so we can manipulate the column's `sType` property.
10221		 */
10222		"_sManualType": null,
10223	
10224		/**
10225		 * Flag to indicate if HTML5 data attributes should be used as the data
10226		 * source for filtering or sorting. True is either are.
10227		 */
10228		"_bAttrSrc": false,
10229	
10230		/**
10231		 * Developer definable function that is called whenever a cell is created (Ajax source,
10232		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
10233		 * allowing you to modify the DOM element (add background colour for example) when the
10234		 * element is available.
10235		 */
10236		"fnCreatedCell": null,
10237	
10238		/**
10239		 * Function to get data from a cell in a column. You should <b>never</b>
10240		 * access data directly through _aData internally in DataTables - always use
10241		 * the method attached to this property. It allows mData to function as
10242		 * required. This function is automatically assigned by the column
10243		 * initialisation method
10244		 */
10245		"fnGetData": null,
10246	
10247		/**
10248		 * Function to set data for a cell in the column. You should <b>never</b>
10249		 * set the data directly to _aData internally in DataTables - always use
10250		 * this method. It allows mData to function as required. This function
10251		 * is automatically assigned by the column initialisation method
10252		 */
10253		"fnSetData": null,
10254	
10255		/**
10256		 * Property to read the value for the cells in the column from the data
10257		 * source array / object. If null, then the default content is used, if a
10258		 * function is given then the return from the function is used.
10259		 */
10260		"mData": null,
10261	
10262		/**
10263		 * Partner property to mData which is used (only when defined) to get
10264		 * the data - i.e. it is basically the same as mData, but without the
10265		 * 'set' option, and also the data fed to it is the result from mData.
10266		 * This is the rendering method to match the data method of mData.
10267		 */
10268		"mRender": null,
10269	
10270		/**
10271		 * The class to apply to all TD elements in the table's TBODY for the column
10272		 */
10273		"sClass": null,
10274	
10275		/**
10276		 * When DataTables calculates the column widths to assign to each column,
10277		 * it finds the longest string in each column and then constructs a
10278		 * temporary table and reads the widths from that. The problem with this
10279		 * is that "mmm" is much wider then "iiii", but the latter is a longer
10280		 * string - thus the calculation can go wrong (doing it properly and putting
10281		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
10282		 * a "work around" we provide this option. It will append its value to the
10283		 * text that is found to be the longest string for the column - i.e. padding.
10284		 */
10285		"sContentPadding": null,
10286	
10287		/**
10288		 * Allows a default value to be given for a column's data, and will be used
10289		 * whenever a null data source is encountered (this can be because mData
10290		 * is set to null, or because the data source itself is null).
10291		 */
10292		"sDefaultContent": null,
10293	
10294		/**
10295		 * Name for the column, allowing reference to the column by name as well as
10296		 * by index (needs a lookup to work by name).
10297		 */
10298		"sName": null,
10299	
10300		/**
10301		 * Custom sorting data type - defines which of the available plug-ins in
10302		 * afnSortData the custom sorting will use - if any is defined.
10303		 */
10304		"sSortDataType": 'std',
10305	
10306		/**
10307		 * Class to be applied to the header element when sorting on this column
10308		 */
10309		"sSortingClass": null,
10310	
10311		/**
10312		 * Title of the column - what is seen in the TH element (nTh).
10313		 */
10314		"sTitle": null,
10315	
10316		/**
10317		 * Column sorting and filtering type
10318		 */
10319		"sType": null,
10320	
10321		/**
10322		 * Width of the column
10323		 */
10324		"sWidth": null,
10325	
10326		/**
10327		 * Width of the column when it was first "encountered"
10328		 */
10329		"sWidthOrig": null,
10330	
10331		/** Cached string which is the longest in the column */
10332		maxLenString: null,
10333	
10334		/**
10335		 * Store for named searches
10336		 */
10337		searchFixed: null
10338	};
10339	
10340	
10341	/*
10342	 * Developer note: The properties of the object below are given in Hungarian
10343	 * notation, that was used as the interface for DataTables prior to v1.10, however
10344	 * from v1.10 onwards the primary interface is camel case. In order to avoid
10345	 * breaking backwards compatibility utterly with this change, the Hungarian
10346	 * version is still, internally the primary interface, but is is not documented
10347	 * - hence the @name tags in each doc comment. This allows a Javascript function
10348	 * to create a map from Hungarian notation to camel case (going the other direction
10349	 * would require each property to be listed, which would add around 3K to the size
10350	 * of DataTables, while this method is about a 0.5K hit).
10351	 *
10352	 * Ultimately this does pave the way for Hungarian notation to be dropped
10353	 * completely, but that is a massive amount of work and will break current
10354	 * installs (therefore is on-hold until v2).
10355	 */
10356	
10357	/**
10358	 * Initialisation options that can be given to DataTables at initialisation
10359	 * time.
10360	 *  @namespace
10361	 */
10362	DataTable.defaults = {
10363		/**
10364		 * An array of data to use for the table, passed in at initialisation which
10365		 * will be used in preference to any data which is already in the DOM. This is
10366		 * particularly useful for constructing tables purely in Javascript, for
10367		 * example with a custom Ajax call.
10368		 */
10369		"aaData": null,
10370	
10371	
10372		/**
10373		 * If ordering is enabled, then DataTables will perform a first pass sort on
10374		 * initialisation. You can define which column(s) the sort is performed
10375		 * upon, and the sorting direction, with this variable. The `sorting` array
10376		 * should contain an array for each column to be sorted initially containing
10377		 * the column's index and a direction string ('asc' or 'desc').
10378		 */
10379		"aaSorting": [[0,'asc']],
10380	
10381	
10382		/**
10383		 * This parameter is basically identical to the `sorting` parameter, but
10384		 * cannot be overridden by user interaction with the table. What this means
10385		 * is that you could have a column (visible or hidden) which the sorting
10386		 * will always be forced on first - any sorting after that (from the user)
10387		 * will then be performed as required. This can be useful for grouping rows
10388		 * together.
10389		 */
10390		"aaSortingFixed": [],
10391	
10392	
10393		/**
10394		 * DataTables can be instructed to load data to display in the table from a
10395		 * Ajax source. This option defines how that Ajax call is made and where to.
10396		 *
10397		 * The `ajax` property has three different modes of operation, depending on
10398		 * how it is defined. These are:
10399		 *
10400		 * * `string` - Set the URL from where the data should be loaded from.
10401		 * * `object` - Define properties for `jQuery.ajax`.
10402		 * * `function` - Custom data get function
10403		 *
10404		 * `string`
10405		 * --------
10406		 *
10407		 * As a string, the `ajax` property simply defines the URL from which
10408		 * DataTables will load data.
10409		 *
10410		 * `object`
10411		 * --------
10412		 *
10413		 * As an object, the parameters in the object are passed to
10414		 * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
10415		 * of the Ajax request. DataTables has a number of default parameters which
10416		 * you can override using this option. Please refer to the jQuery
10417		 * documentation for a full description of the options available, although
10418		 * the following parameters provide additional options in DataTables or
10419		 * require special consideration:
10420		 *
10421		 * * `data` - As with jQuery, `data` can be provided as an object, but it
10422		 *   can also be used as a function to manipulate the data DataTables sends
10423		 *   to the server. The function takes a single parameter, an object of
10424		 *   parameters with the values that DataTables has readied for sending. An
10425		 *   object may be returned which will be merged into the DataTables
10426		 *   defaults, or you can add the items to the object that was passed in and
10427		 *   not return anything from the function. This supersedes `fnServerParams`
10428		 *   from DataTables 1.9-.
10429		 *
10430		 * * `dataSrc` - By default DataTables will look for the property `data` (or
10431		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
10432		 *   from an Ajax source or for server-side processing - this parameter
10433		 *   allows that property to be changed. You can use Javascript dotted
10434		 *   object notation to get a data source for multiple levels of nesting, or
10435		 *   it my be used as a function. As a function it takes a single parameter,
10436		 *   the JSON returned from the server, which can be manipulated as
10437		 *   required, with the returned value being that used by DataTables as the
10438		 *   data source for the table.
10439		 *
10440		 * * `success` - Should not be overridden it is used internally in
10441		 *   DataTables. To manipulate / transform the data returned by the server
10442		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10443		 *
10444		 * `function`
10445		 * ----------
10446		 *
10447		 * As a function, making the Ajax call is left up to yourself allowing
10448		 * complete control of the Ajax request. Indeed, if desired, a method other
10449		 * than Ajax could be used to obtain the required data, such as Web storage
10450		 * or an AIR database.
10451		 *
10452		 * The function is given four parameters and no return is required. The
10453		 * parameters are:
10454		 *
10455		 * 1. _object_ - Data to send to the server
10456		 * 2. _function_ - Callback function that must be executed when the required
10457		 *    data has been obtained. That data should be passed into the callback
10458		 *    as the only parameter
10459		 * 3. _object_ - DataTables settings object for the table
10460		 */
10461		"ajax": null,
10462	
10463	
10464		/**
10465		 * This parameter allows you to readily specify the entries in the length drop
10466		 * down menu that DataTables shows when pagination is enabled. It can be
10467		 * either a 1D array of options which will be used for both the displayed
10468		 * option and the value, or a 2D array which will use the array in the first
10469		 * position as the value, and the array in the second position as the
10470		 * displayed options (useful for language strings such as 'All').
10471		 *
10472		 * Note that the `pageLength` property will be automatically set to the
10473		 * first value given in this array, unless `pageLength` is also provided.
10474		 */
10475		"aLengthMenu": [ 10, 25, 50, 100 ],
10476	
10477	
10478		/**
10479		 * The `columns` option in the initialisation parameter allows you to define
10480		 * details about the way individual columns behave. For a full list of
10481		 * column options that can be set, please see
10482		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10483		 * define your columns, you must have an entry in the array for every single
10484		 * column that you have in your table (these can be null if you don't which
10485		 * to specify any options).
10486		 */
10487		"aoColumns": null,
10488	
10489		/**
10490		 * Very similar to `columns`, `columnDefs` allows you to target a specific
10491		 * column, multiple columns, or all columns, using the `targets` property of
10492		 * each object in the array. This allows great flexibility when creating
10493		 * tables, as the `columnDefs` arrays can be of any length, targeting the
10494		 * columns you specifically want. `columnDefs` may use any of the column
10495		 * options available: {@link DataTable.defaults.column}, but it _must_
10496		 * have `targets` defined in each object in the array. Values in the `targets`
10497		 * array may be:
10498		 *   <ul>
10499		 *     <li>a string - class name will be matched on the TH for the column</li>
10500		 *     <li>0 or a positive integer - column index counting from the left</li>
10501		 *     <li>a negative integer - column index counting from the right</li>
10502		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10503		 *   </ul>
10504		 */
10505		"aoColumnDefs": null,
10506	
10507	
10508		/**
10509		 * Basically the same as `search`, this parameter defines the individual column
10510		 * filtering state at initialisation time. The array must be of the same size
10511		 * as the number of columns, and each element be an object with the parameters
10512		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10513		 * accepted and the default will be used.
10514		 */
10515		"aoSearchCols": [],
10516	
10517	
10518		/**
10519		 * Enable or disable automatic column width calculation. This can be disabled
10520		 * as an optimisation (it takes some time to calculate the widths) if the
10521		 * tables widths are passed in using `columns`.
10522		 */
10523		"bAutoWidth": true,
10524	
10525	
10526		/**
10527		 * Deferred rendering can provide DataTables with a huge speed boost when you
10528		 * are using an Ajax or JS data source for the table. This option, when set to
10529		 * true, will cause DataTables to defer the creation of the table elements for
10530		 * each row until they are needed for a draw - saving a significant amount of
10531		 * time.
10532		 */
10533		"bDeferRender": true,
10534	
10535	
10536		/**
10537		 * Replace a DataTable which matches the given selector and replace it with
10538		 * one which has the properties of the new initialisation object passed. If no
10539		 * table matches the selector, then the new DataTable will be constructed as
10540		 * per normal.
10541		 */
10542		"bDestroy": false,
10543	
10544	
10545		/**
10546		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10547		 * that it allows the end user to input multiple words (space separated) and
10548		 * will match a row containing those words, even if not in the order that was
10549		 * specified (this allow matching across multiple columns). Note that if you
10550		 * wish to use filtering in DataTables this must remain 'true' - to remove the
10551		 * default filtering input box and retain filtering abilities, please use
10552		 * {@link DataTable.defaults.dom}.
10553		 */
10554		"bFilter": true,
10555	
10556		/**
10557		 * Used only for compatiblity with DT1
10558		 * @deprecated
10559		 */
10560		"bInfo": true,
10561	
10562		/**
10563		 * Used only for compatiblity with DT1
10564		 * @deprecated
10565		 */
10566		"bLengthChange": true,
10567	
10568		/**
10569		 * Enable or disable pagination.
10570		 */
10571		"bPaginate": true,
10572	
10573	
10574		/**
10575		 * Enable or disable the display of a 'processing' indicator when the table is
10576		 * being processed (e.g. a sort). This is particularly useful for tables with
10577		 * large amounts of data where it can take a noticeable amount of time to sort
10578		 * the entries.
10579		 */
10580		"bProcessing": false,
10581	
10582	
10583		/**
10584		 * Retrieve the DataTables object for the given selector. Note that if the
10585		 * table has already been initialised, this parameter will cause DataTables
10586		 * to simply return the object that has already been set up - it will not take
10587		 * account of any changes you might have made to the initialisation object
10588		 * passed to DataTables (setting this parameter to true is an acknowledgement
10589		 * that you understand this). `destroy` can be used to reinitialise a table if
10590		 * you need.
10591		 */
10592		"bRetrieve": false,
10593	
10594	
10595		/**
10596		 * When vertical (y) scrolling is enabled, DataTables will force the height of
10597		 * the table's viewport to the given height at all times (useful for layout).
10598		 * However, this can look odd when filtering data down to a small data set,
10599		 * and the footer is left "floating" further down. This parameter (when
10600		 * enabled) will cause DataTables to collapse the table's viewport down when
10601		 * the result set will fit within the given Y height.
10602		 */
10603		"bScrollCollapse": false,
10604	
10605	
10606		/**
10607		 * Configure DataTables to use server-side processing. Note that the
10608		 * `ajax` parameter must also be given in order to give DataTables a
10609		 * source to obtain the required data for each draw.
10610		 */
10611		"bServerSide": false,
10612	
10613	
10614		/**
10615		 * Enable or disable sorting of columns. Sorting of individual columns can be
10616		 * disabled by the `sortable` option for each column.
10617		 */
10618		"bSort": true,
10619	
10620	
10621		/**
10622		 * Enable or display DataTables' ability to sort multiple columns at the
10623		 * same time (activated by shift-click by the user).
10624		 */
10625		"bSortMulti": true,
10626	
10627	
10628		/**
10629		 * Allows control over whether DataTables should use the top (true) unique
10630		 * cell that is found for a single column, or the bottom (false - default).
10631		 * This is useful when using complex headers.
10632		 */
10633		"bSortCellsTop": null,
10634	
10635	
10636		/**
10637		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10638		 * `sorting\_3` to the columns which are currently being sorted on. This is
10639		 * presented as a feature switch as it can increase processing time (while
10640		 * classes are removed and added) so for large data sets you might want to
10641		 * turn this off.
10642		 */
10643		"bSortClasses": true,
10644	
10645	
10646		/**
10647		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10648		 * used to save table display information such as pagination information,
10649		 * display length, filtering and sorting. As such when the end user reloads
10650		 * the page the display display will match what thy had previously set up.
10651		 */
10652		"bStateSave": false,
10653	
10654	
10655		/**
10656		 * This function is called when a TR element is created (and all TD child
10657		 * elements have been inserted), or registered if using a DOM source, allowing
10658		 * manipulation of the TR element (adding classes etc).
10659		 */
10660		"fnCreatedRow": null,
10661	
10662	
10663		/**
10664		 * This function is called on every 'draw' event, and allows you to
10665		 * dynamically modify any aspect you want about the created DOM.
10666		 */
10667		"fnDrawCallback": null,
10668	
10669	
10670		/**
10671		 * Identical to fnHeaderCallback() but for the table footer this function
10672		 * allows you to modify the table footer on every 'draw' event.
10673		 */
10674		"fnFooterCallback": null,
10675	
10676	
10677		/**
10678		 * When rendering large numbers in the information element for the table
10679		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10680		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10681		 * rendered as "1,000,000") to help readability for the end user. This
10682		 * function will override the default method DataTables uses.
10683		 */
10684		"fnFormatNumber": function ( toFormat ) {
10685			return toFormat.toString().replace(
10686				/\B(?=(\d{3})+(?!\d))/g,
10687				this.oLanguage.sThousands
10688			);
10689		},
10690	
10691	
10692		/**
10693		 * This function is called on every 'draw' event, and allows you to
10694		 * dynamically modify the header row. This can be used to calculate and
10695		 * display useful information about the table.
10696		 */
10697		"fnHeaderCallback": null,
10698	
10699	
10700		/**
10701		 * The information element can be used to convey information about the current
10702		 * state of the table. Although the internationalisation options presented by
10703		 * DataTables are quite capable of dealing with most customisations, there may
10704		 * be times where you wish to customise the string further. This callback
10705		 * allows you to do exactly that.
10706		 */
10707		"fnInfoCallback": null,
10708	
10709	
10710		/**
10711		 * Called when the table has been initialised. Normally DataTables will
10712		 * initialise sequentially and there will be no need for this function,
10713		 * however, this does not hold true when using external language information
10714		 * since that is obtained using an async XHR call.
10715		 */
10716		"fnInitComplete": null,
10717	
10718	
10719		/**
10720		 * Called at the very start of each table draw and can be used to cancel the
10721		 * draw by returning false, any other return (including undefined) results in
10722		 * the full draw occurring).
10723		 */
10724		"fnPreDrawCallback": null,
10725	
10726	
10727		/**
10728		 * This function allows you to 'post process' each row after it have been
10729		 * generated for each table draw, but before it is rendered on screen. This
10730		 * function might be used for setting the row class name etc.
10731		 */
10732		"fnRowCallback": null,
10733	
10734	
10735		/**
10736		 * Load the table state. With this function you can define from where, and how, the
10737		 * state of a table is loaded. By default DataTables will load from `localStorage`
10738		 * but you might wish to use a server-side database or cookies.
10739		 */
10740		"fnStateLoadCallback": function ( settings ) {
10741			try {
10742				return JSON.parse(
10743					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10744						'DataTables_'+settings.sInstance+'_'+location.pathname
10745					)
10746				);
10747			} catch (e) {
10748				return {};
10749			}
10750		},
10751	
10752	
10753		/**
10754		 * Callback which allows modification of the saved state prior to loading that state.
10755		 * This callback is called when the table is loading state from the stored data, but
10756		 * prior to the settings object being modified by the saved state. Note that for
10757		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10758		 * a plug-in.
10759		 */
10760		"fnStateLoadParams": null,
10761	
10762	
10763		/**
10764		 * Callback that is called when the state has been loaded from the state saving method
10765		 * and the DataTables settings object has been modified as a result of the loaded state.
10766		 */
10767		"fnStateLoaded": null,
10768	
10769	
10770		/**
10771		 * Save the table state. This function allows you to define where and how the state
10772		 * information for the table is stored By default DataTables will use `localStorage`
10773		 * but you might wish to use a server-side database or cookies.
10774		 */
10775		"fnStateSaveCallback": function ( settings, data ) {
10776			try {
10777				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10778					'DataTables_'+settings.sInstance+'_'+location.pathname,
10779					JSON.stringify( data )
10780				);
10781			} catch (e) {
10782				// noop
10783			}
10784		},
10785	
10786	
10787		/**
10788		 * Callback which allows modification of the state to be saved. Called when the table
10789		 * has changed state a new state save is required. This method allows modification of
10790		 * the state saving object prior to actually doing the save, including addition or
10791		 * other state properties or modification. Note that for plug-in authors, you should
10792		 * use the `stateSaveParams` event to save parameters for a plug-in.
10793		 */
10794		"fnStateSaveParams": null,
10795	
10796	
10797		/**
10798		 * Duration for which the saved state information is considered valid. After this period
10799		 * has elapsed the state will be returned to the default.
10800		 * Value is given in seconds.
10801		 */
10802		"iStateDuration": 7200,
10803	
10804	
10805		/**
10806		 * Number of rows to display on a single page when using pagination. If
10807		 * feature enabled (`lengthChange`) then the end user will be able to override
10808		 * this to a custom setting using a pop-up menu.
10809		 */
10810		"iDisplayLength": 10,
10811	
10812	
10813		/**
10814		 * Define the starting point for data display when using DataTables with
10815		 * pagination. Note that this parameter is the number of records, rather than
10816		 * the page number, so if you have 10 records per page and want to start on
10817		 * the third page, it should be "20".
10818		 */
10819		"iDisplayStart": 0,
10820	
10821	
10822		/**
10823		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10824		 * and filtering) by adding a `tabindex` attribute to the required elements. This
10825		 * allows you to tab through the controls and press the enter key to activate them.
10826		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10827		 * You can overrule this using this parameter if you wish. Use a value of -1 to
10828		 * disable built-in keyboard navigation.
10829		 */
10830		"iTabIndex": 0,
10831	
10832	
10833		/**
10834		 * Classes that DataTables assigns to the various components and features
10835		 * that it adds to the HTML table. This allows classes to be configured
10836		 * during initialisation in addition to through the static
10837		 * {@link DataTable.ext.oStdClasses} object).
10838		 */
10839		"oClasses": {},
10840	
10841	
10842		/**
10843		 * All strings that DataTables uses in the user interface that it creates
10844		 * are defined in this object, allowing you to modified them individually or
10845		 * completely replace them all as required.
10846		 */
10847		"oLanguage": {
10848			/**
10849			 * Strings that are used for WAI-ARIA labels and controls only (these are not
10850			 * actually visible on the page, but will be read by screenreaders, and thus
10851			 * must be internationalised as well).
10852			 */
10853			"oAria": {
10854				/**
10855				 * ARIA label that is added to the table headers when the column may be sorted
10856				 */
10857				"orderable": ": Activate to sort",
10858	
10859				/**
10860				 * ARIA label that is added to the table headers when the column is currently being sorted
10861				 */
10862				"orderableReverse": ": Activate to invert sorting",
10863	
10864				/**
10865				 * ARIA label that is added to the table headers when the column is currently being 
10866				 * sorted and next step is to remove sorting
10867				 */
10868				"orderableRemove": ": Activate to remove sorting",
10869	
10870				paginate: {
10871					first: 'First',
10872					last: 'Last',
10873					next: 'Next',
10874					previous: 'Previous',
10875					number: ''
10876				}
10877			},
10878	
10879			/**
10880			 * Pagination string used by DataTables for the built-in pagination
10881			 * control types.
10882			 */
10883			"oPaginate": {
10884				/**
10885				 * Label and character for first page button («)
10886				 */
10887				"sFirst": "\u00AB",
10888	
10889				/**
10890				 * Last page button (»)
10891				 */
10892				"sLast": "\u00BB",
10893	
10894				/**
10895				 * Next page button (›)
10896				 */
10897				"sNext": "\u203A",
10898	
10899				/**
10900				 * Previous page button (‹)
10901				 */
10902				"sPrevious": "\u2039",
10903			},
10904	
10905			/**
10906			 * Plural object for the data type the table is showing
10907			 */
10908			entries: {
10909				_: "entries",
10910				1: "entry"
10911			},
10912	
10913			/**
10914			 * This string is shown in preference to `zeroRecords` when the table is
10915			 * empty of data (regardless of filtering). Note that this is an optional
10916			 * parameter - if it is not given, the value of `zeroRecords` will be used
10917			 * instead (either the default or given value).
10918			 */
10919			"sEmptyTable": "No data available in table",
10920	
10921	
10922			/**
10923			 * This string gives information to the end user about the information
10924			 * that is current on display on the page. The following tokens can be
10925			 * used in the string and will be dynamically replaced as the table
10926			 * display updates. This tokens can be placed anywhere in the string, or
10927			 * removed as needed by the language requires:
10928			 *
10929			 * * `\_START\_` - Display index of the first record on the current page
10930			 * * `\_END\_` - Display index of the last record on the current page
10931			 * * `\_TOTAL\_` - Number of records in the table after filtering
10932			 * * `\_MAX\_` - Number of records in the table without filtering
10933			 * * `\_PAGE\_` - Current page number
10934			 * * `\_PAGES\_` - Total number of pages of data in the table
10935			 */
10936			"sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
10937	
10938	
10939			/**
10940			 * Display information string for when the table is empty. Typically the
10941			 * format of this string should match `info`.
10942			 */
10943			"sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
10944	
10945	
10946			/**
10947			 * When a user filters the information in a table, this string is appended
10948			 * to the information (`info`) to give an idea of how strong the filtering
10949			 * is. The variable _MAX_ is dynamically updated.
10950			 */
10951			"sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
10952	
10953	
10954			/**
10955			 * If can be useful to append extra information to the info string at times,
10956			 * and this variable does exactly that. This information will be appended to
10957			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
10958			 * being used) at all times.
10959			 */
10960			"sInfoPostFix": "",
10961	
10962	
10963			/**
10964			 * This decimal place operator is a little different from the other
10965			 * language options since DataTables doesn't output floating point
10966			 * numbers, so it won't ever use this for display of a number. Rather,
10967			 * what this parameter does is modify the sort methods of the table so
10968			 * that numbers which are in a format which has a character other than
10969			 * a period (`.`) as a decimal place will be sorted numerically.
10970			 *
10971			 * Note that numbers with different decimal places cannot be shown in
10972			 * the same table and still be sortable, the table must be consistent.
10973			 * However, multiple different tables on the page can use different
10974			 * decimal place characters.
10975			 */
10976			"sDecimal": "",
10977	
10978	
10979			/**
10980			 * DataTables has a build in number formatter (`formatNumber`) which is
10981			 * used to format large numbers that are used in the table information.
10982			 * By default a comma is used, but this can be trivially changed to any
10983			 * character you wish with this parameter.
10984			 */
10985			"sThousands": ",",
10986	
10987	
10988			/**
10989			 * Detail the action that will be taken when the drop down menu for the
10990			 * pagination length option is changed. The '_MENU_' variable is replaced
10991			 * with a default select list of 10, 25, 50 and 100, and can be replaced
10992			 * with a custom select box if required.
10993			 */
10994			"sLengthMenu": "_MENU_ _ENTRIES_ per page",
10995	
10996	
10997			/**
10998			 * When using Ajax sourced data and during the first draw when DataTables is
10999			 * gathering the data, this message is shown in an empty row in the table to
11000			 * indicate to the end user the the data is being loaded. Note that this
11001			 * parameter is not used when loading data by server-side processing, just
11002			 * Ajax sourced data with client-side processing.
11003			 */
11004			"sLoadingRecords": "Loading...",
11005	
11006	
11007			/**
11008			 * Text which is displayed when the table is processing a user action
11009			 * (usually a sort command or similar).
11010			 */
11011			"sProcessing": "",
11012	
11013	
11014			/**
11015			 * Details the actions that will be taken when the user types into the
11016			 * filtering input text box. The variable "_INPUT_", if used in the string,
11017			 * is replaced with the HTML text box for the filtering input allowing
11018			 * control over where it appears in the string. If "_INPUT_" is not given
11019			 * then the input box is appended to the string automatically.
11020			 */
11021			"sSearch": "Search:",
11022	
11023	
11024			/**
11025			 * Assign a `placeholder` attribute to the search `input` element
11026			 *  @type string
11027			 *  @default 
11028			 *
11029			 *  @dtopt Language
11030			 *  @name DataTable.defaults.language.searchPlaceholder
11031			 */
11032			"sSearchPlaceholder": "",
11033	
11034	
11035			/**
11036			 * All of the language information can be stored in a file on the
11037			 * server-side, which DataTables will look up if this parameter is passed.
11038			 * It must store the URL of the language file, which is in a JSON format,
11039			 * and the object has the same properties as the oLanguage object in the
11040			 * initialiser object (i.e. the above parameters). Please refer to one of
11041			 * the example language files to see how this works in action.
11042			 */
11043			"sUrl": "",
11044	
11045	
11046			/**
11047			 * Text shown inside the table records when the is no information to be
11048			 * displayed after filtering. `emptyTable` is shown when there is simply no
11049			 * information in the table at all (regardless of filtering).
11050			 */
11051			"sZeroRecords": "No matching records found"
11052		},
11053	
11054	
11055		/** The initial data order is reversed when `desc` ordering */
11056		orderDescReverse: true,
11057	
11058	
11059		/**
11060		 * This parameter allows you to have define the global filtering state at
11061		 * initialisation time. As an object the `search` parameter must be
11062		 * defined, but all other parameters are optional. When `regex` is true,
11063		 * the search string will be treated as a regular expression, when false
11064		 * (default) it will be treated as a straight string. When `smart`
11065		 * DataTables will use it's smart filtering methods (to word match at
11066		 * any point in the data), when false this will not be done.
11067		 */
11068		"oSearch": $.extend( {}, DataTable.models.oSearch ),
11069	
11070	
11071		/**
11072		 * Table and control layout. This replaces the legacy `dom` option.
11073		 */
11074		layout: {
11075			topStart: 'pageLength',
11076			topEnd: 'search',
11077			bottomStart: 'info',
11078			bottomEnd: 'paging'
11079		},
11080	
11081	
11082		/**
11083		 * Legacy DOM layout option
11084		 */
11085		"sDom": null,
11086	
11087	
11088		/**
11089		 * Search delay option. This will throttle full table searches that use the
11090		 * DataTables provided search input element (it does not effect calls to
11091		 * `dt-api search()`, providing a delay before the search is made.
11092		 */
11093		"searchDelay": null,
11094	
11095	
11096		/**
11097		 * DataTables features six different built-in options for the buttons to
11098		 * display for pagination control:
11099		 *
11100		 * * `numbers` - Page number buttons only
11101		 * * `simple` - 'Previous' and 'Next' buttons only
11102		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11103		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11104		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11105		 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11106		 */
11107		"sPaginationType": "",
11108	
11109	
11110		/**
11111		 * Enable horizontal scrolling. When a table is too wide to fit into a
11112		 * certain layout, or you have a large number of columns in the table, you
11113		 * can enable x-scrolling to show the table in a viewport, which can be
11114		 * scrolled. This property can be `true` which will allow the table to
11115		 * scroll horizontally when needed, or any CSS unit, or a number (in which
11116		 * case it will be treated as a pixel measurement). Setting as simply `true`
11117		 * is recommended.
11118		 */
11119		"sScrollX": "",
11120	
11121	
11122		/**
11123		 * This property can be used to force a DataTable to use more width than it
11124		 * might otherwise do when x-scrolling is enabled. For example if you have a
11125		 * table which requires to be well spaced, this parameter is useful for
11126		 * "over-sizing" the table, and thus forcing scrolling. This property can by
11127		 * any CSS unit, or a number (in which case it will be treated as a pixel
11128		 * measurement).
11129		 */
11130		"sScrollXInner": "",
11131	
11132	
11133		/**
11134		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11135		 * to the given height, and enable scrolling for any data which overflows the
11136		 * current viewport. This can be used as an alternative to paging to display
11137		 * a lot of data in a small area (although paging and scrolling can both be
11138		 * enabled at the same time). This property can be any CSS unit, or a number
11139		 * (in which case it will be treated as a pixel measurement).
11140		 */
11141		"sScrollY": "",
11142	
11143	
11144		/**
11145		 * __Deprecated__ The functionality provided by this parameter has now been
11146		 * superseded by that provided through `ajax`, which should be used instead.
11147		 *
11148		 * Set the HTTP method that is used to make the Ajax call for server-side
11149		 * processing or Ajax sourced data.
11150		 */
11151		"sServerMethod": "GET",
11152	
11153	
11154		/**
11155		 * DataTables makes use of renderers when displaying HTML elements for
11156		 * a table. These renderers can be added or modified by plug-ins to
11157		 * generate suitable mark-up for a site. For example the Bootstrap
11158		 * integration plug-in for DataTables uses a paging button renderer to
11159		 * display pagination buttons in the mark-up required by Bootstrap.
11160		 *
11161		 * For further information about the renderers available see
11162		 * DataTable.ext.renderer
11163		 */
11164		"renderer": null,
11165	
11166	
11167		/**
11168		 * Set the data property name that DataTables should use to get a row's id
11169		 * to set as the `id` property in the node.
11170		 */
11171		"rowId": "DT_RowId",
11172	
11173	
11174		/**
11175		 * Caption value
11176		 */
11177		"caption": null,
11178	
11179	
11180		/**
11181		 * For server-side processing - use the data from the DOM for the first draw
11182		 */
11183		iDeferLoading: null
11184	};
11185	
11186	_fnHungarianMap( DataTable.defaults );
11187	
11188	
11189	
11190	/*
11191	 * Developer note - See note in model.defaults.js about the use of Hungarian
11192	 * notation and camel case.
11193	 */
11194	
11195	/**
11196	 * Column options that can be given to DataTables at initialisation time.
11197	 *  @namespace
11198	 */
11199	DataTable.defaults.column = {
11200		/**
11201		 * Define which column(s) an order will occur on for this column. This
11202		 * allows a column's ordering to take multiple columns into account when
11203		 * doing a sort or use the data from a different column. For example first
11204		 * name / last name columns make sense to do a multi-column sort over the
11205		 * two columns.
11206		 */
11207		"aDataSort": null,
11208		"iDataSort": -1,
11209	
11210		ariaTitle: '',
11211	
11212	
11213		/**
11214		 * You can control the default ordering direction, and even alter the
11215		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11216		 * using this parameter.
11217		 */
11218		"asSorting": [ 'asc', 'desc', '' ],
11219	
11220	
11221		/**
11222		 * Enable or disable filtering on the data in this column.
11223		 */
11224		"bSearchable": true,
11225	
11226	
11227		/**
11228		 * Enable or disable ordering on this column.
11229		 */
11230		"bSortable": true,
11231	
11232	
11233		/**
11234		 * Enable or disable the display of this column.
11235		 */
11236		"bVisible": true,
11237	
11238	
11239		/**
11240		 * Developer definable function that is called whenever a cell is created (Ajax source,
11241		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11242		 * allowing you to modify the DOM element (add background colour for example) when the
11243		 * element is available.
11244		 */
11245		"fnCreatedCell": null,
11246	
11247	
11248		/**
11249		 * This property can be used to read data from any data source property,
11250		 * including deeply nested objects / properties. `data` can be given in a
11251		 * number of different ways which effect its behaviour:
11252		 *
11253		 * * `integer` - treated as an array index for the data source. This is the
11254		 *   default that DataTables uses (incrementally increased for each column).
11255		 * * `string` - read an object property from the data source. There are
11256		 *   three 'special' options that can be used in the string to alter how
11257		 *   DataTables reads the data from the source object:
11258		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
11259		 *      Javascript to read from nested objects, so to can the options
11260		 *      specified in `data`. For example: `browser.version` or
11261		 *      `browser.name`. If your object parameter name contains a period, use
11262		 *      `\\` to escape it - i.e. `first\\.name`.
11263		 *    * `[]` - Array notation. DataTables can automatically combine data
11264		 *      from and array source, joining the data with the characters provided
11265		 *      between the two brackets. For example: `name[, ]` would provide a
11266		 *      comma-space separated list from the source array. If no characters
11267		 *      are provided between the brackets, the original array source is
11268		 *      returned.
11269		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
11270		 *      execute a function of the name given. For example: `browser()` for a
11271		 *      simple function on the data source, `browser.version()` for a
11272		 *      function in a nested property or even `browser().version` to get an
11273		 *      object property if the function called returns an object. Note that
11274		 *      function notation is recommended for use in `render` rather than
11275		 *      `data` as it is much simpler to use as a renderer.
11276		 * * `null` - use the original data source for the row rather than plucking
11277		 *   data directly from it. This action has effects on two other
11278		 *   initialisation options:
11279		 *    * `defaultContent` - When null is given as the `data` option and
11280		 *      `defaultContent` is specified for the column, the value defined by
11281		 *      `defaultContent` will be used for the cell.
11282		 *    * `render` - When null is used for the `data` option and the `render`
11283		 *      option is specified for the column, the whole data source for the
11284		 *      row is used for the renderer.
11285		 * * `function` - the function given will be executed whenever DataTables
11286		 *   needs to set or get the data for a cell in the column. The function
11287		 *   takes three parameters:
11288		 *    * Parameters:
11289		 *      * `{array|object}` The data source for the row
11290		 *      * `{string}` The type call data requested - this will be 'set' when
11291		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
11292		 *        when gathering data. Note that when `undefined` is given for the
11293		 *        type DataTables expects to get the raw data for the object back<
11294		 *      * `{*}` Data to set when the second parameter is 'set'.
11295		 *    * Return:
11296		 *      * The return value from the function is not required when '
11296set' is
11297		 *        the type of call, but otherwise the return is what will be used
11298		 *        for the data requested.
11299		 *
11300		 * Note that `data` is a getter and setter option. If you just require
11301		 * formatting of data for output, you will likely want to use `render` which
11302		 * is simply a getter and thus simpler to use.
11303		 *
11304		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
11305		 * name change reflects the flexibility of this property and is consistent
11306		 * with the naming of mRender. If 'mDataProp' is given, then it will still
11307		 * be used by DataTables, as it automatically maps the old name to the new
11308		 * if required.
11309		 */
11310		"mData": null,
11311	
11312	
11313		/**
11314		 * This property is the rendering partner to `data` and it is suggested that
11315		 * when you want to manipulate data for display (including filtering,
11316		 * sorting etc) without altering the underlying data for the table, use this
11317		 * property. `render` can be considered to be the the read only companion to
11318		 * `data` which is read / write (then as such more complex). Like `data`
11319		 * this option can be given in a number of different ways to effect its
11320		 * behaviour:
11321		 *
11322		 * * `integer` - treated as an array index for the data source. This is the
11323		 *   default that DataTables uses (incrementally increased for each column).
11324		 * * `string` - read an object property from the data source. There are
11325		 *   three 'special' options that can be used in the string to alter how
11326		 *   DataTables reads the data from the source object:
11327		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
11328		 *      Javascript to read from nested objects, so to can the options
11329		 *      specified in `data`. For example: `browser.version` or
11330		 *      `browser.name`. If your object parameter name contains a period, use
11331		 *      `\\` to escape it - i.e. `first\\.name`.
11332		 *    * `[]` - Array notation. DataTables can automatically combine data
11333		 *      from and array source, joining the data with the characters provided
11334		 *      between the two brackets. For example: `name[, ]` would provide a
11335		 *      comma-space separated list from the source array. If no characters
11336		 *      are provided between the brackets, the original array source is
11337		 *      returned.
11338		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
11339		 *      execute a function of the name given. For example: `browser()` for a
11340		 *      simple function on the data source, `browser.version()` for a
11341		 *      function in a nested property or even `browser().version` to get an
11342		 *      object property if the function called returns an object.
11343		 * * `object` - use different data for the different data types requested by
11344		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
11345		 *   of the object is the data type the property refers to and the value can
11346		 *   defined using an integer, string or function using the same rules as
11347		 *   `render` normally does. Note that an `_` option _must_ be specified.
11348		 *   This is the default value to use if you haven't specified a value for
11349		 *   the data type requested by DataTables.
11350		 * * `function` - the function given will be executed whenever DataTables
11351		 *   needs to set or get the data for a cell in the column. The function
11352		 *   takes three parameters:
11353		 *    * Parameters:
11354		 *      * {array|object} The data source for the row (based on `data`)
11355		 *      * {string} The type call data requested - this will be 'filter',
11356		 *        'display', 'type' or 'sort'.
11357		 *      * {array|object} The full data source for the row (not based on
11358		 *        `data`)
11359		 *    * Return:
11360		 *      * The return value from the function is what will be used for the
11361		 *        data requested.
11362		 */
11363		"mRender": null,
11364	
11365	
11366		/**
11367		 * Change the cell type created for the column - either TD cells or TH cells. This
11368		 * can be useful as TH cells have semantic meaning in the table body, allowing them
11369		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
11370		 */
11371		"sCellType": "td",
11372	
11373	
11374		/**
11375		 * Class to give to each cell in this column.
11376		 */
11377		"sClass": "",
11378	
11379		/**
11380		 * When DataTables calculates the column widths to assign to each column,
11381		 * it finds the longest string in each column and then constructs a
11382		 * temporary table and reads the widths from that. The problem with this
11383		 * is that "mmm" is much wider then "iiii", but the latter is a longer
11384		 * string - thus the calculation can go wrong (doing it properly and putting
11385		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
11386		 * a "work around" we provide this option. It will append its value to the
11387		 * text that is found to be the longest string for the column - i.e. padding.
11388		 * Generally you shouldn't need this!
11389		 */
11390		"sContentPadding": "",
11391	
11392	
11393		/**
11394		 * Allows a default value to be given for a column's data, and will be used
11395		 * whenever a null data source is encountered (this can be because `data`
11396		 * is set to null, or because the data source itself is null).
11397		 */
11398		"sDefaultContent": null,
11399	
11400	
11401		/**
11402		 * This parameter is only used in DataTables' server-side processing. It can
11403		 * be exceptionally useful to know what columns are being displayed on the
11404		 * client side, and to map these to database fields. When defined, the names
11405		 * also allow DataTables to reorder information from the server if it comes
11406		 * back in an unexpected order (i.e. if you switch your columns around on the
11407		 * client-side, your server-side code does not also need updating).
11408		 */
11409		"sName": "",
11410	
11411	
11412		/**
11413		 * Defines a data source type for the ordering which can be used to read
11414		 * real-time information from the table (updating the internally cached
11415		 * version) prior to ordering. This allows ordering to occur on user
11416		 * editable elements such as form inputs.
11417		 */
11418		"sSortDataType": "std",
11419	
11420	
11421		/**
11422		 * The title of this column.
11423		 */
11424		"sTitle": null,
11425	
11426	
11427		/**
11428		 * The type allows you to specify how the data for this column will be
11429		 * ordered. Four types (string, numeric, date and html (which will strip
11430		 * HTML tags before ordering)) are currently available. Note that only date
11431		 * formats understood by Javascript's Date() object will be accepted as type
11432		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
11433		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
11434		 * through plug-ins.
11435		 */
11436		"sType": null,
11437	
11438	
11439		/**
11440		 * Defining the width of the column, this parameter may take any CSS value
11441		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
11442		 * been given a specific width through this interface ensuring that the table
11443		 * remains readable.
11444		 */
11445		"sWidth": null
11446	};
11447	
11448	_fnHungarianMap( DataTable.defaults.column );
11449	
11450	
11451	
11452	/**
11453	 * DataTables settings object - this holds all the information needed for a
11454	 * given table, including configuration, data and current application of the
11455	 * table options. DataTables does not have a single instance for each DataTable
11456	 * with the settings attached to that instance, but rather instances of the
11457	 * DataTable "class" are created on-the-fly as needed (typically by a
11458	 * $().dataTable() call) and the settings object is then applied to that
11459	 * instance.
11460	 *
11461	 * Note that this object is related to {@link DataTable.defaults} but this
11462	 * one is the internal data store for DataTables's cache of columns. It should
11463	 * NOT be manipulated outside of DataTables. Any configuration should be done
11464	 * through the initialisation options.
11465	 */
11466	DataTable.models.oSettings = {
11467		/**
11468		 * Primary features of DataTables and their enablement state.
11469		 */
11470		"oFeatures": {
11471	
11472			/**
11473			 * Flag to say if DataTables should automatically try to calculate the
11474			 * optimum table and columns widths (true) or not (false).
11475			 * Note that this parameter will be set by the initialisation routine. To
11476			 * set a default use {@link DataTable.defaults}.
11477			 */
11478			"bAutoWidth": null,
11479	
11480			/**
11481			 * Delay the creation of TR and TD elements until they are actually
11482			 * needed by a driven page draw. This can give a significant speed
11483			 * increase for Ajax source and Javascript source data, but makes no
11484			 * difference at all for DOM and server-side processing tables.
11485			 * Note that this parameter will be set by the initialisation routine. To
11486			 * set a default use {@link DataTable.defaults}.
11487			 */
11488			"bDeferRender": null,
11489	
11490			/**
11491			 * Enable filtering on the table or not. Note that if this is disabled
11492			 * then there is no filtering at all on the table, including fnFilter.
11493			 * To just remove the filtering input use sDom and remove the 'f' option.
11494			 * Note that this parameter will be set by the initialisation routine. To
11495			 * set a default use {@link DataTable.defaults}.
11496			 */
11497			"bFilter": null,
11498	
11499			/**
11500			 * Used only for compatiblity with DT1
11501			 * @deprecated
11502			 */
11503			"bInfo": true,
11504	
11505			/**
11506			 * Used only for compatiblity with DT1
11507			 * @deprecated
11508			 */
11509			"bLengthChange": true,
11510	
11511			/**
11512			 * Pagination enabled or not. Note that if this is disabled then length
11513			 * changing must also be disabled.
11514			 * Note that this parameter will be set by the initialisation routine. To
11515			 * set a default use {@link DataTable.defaults}.
11516			 */
11517			"bPaginate": null,
11518	
11519			/**
11520			 * Processing indicator enable flag whenever DataTables is enacting a
11521			 * user request - typically an Ajax request for server-side processing.
11522			 * Note that this parameter will be set by the initialisation routine. To
11523			 * set a default use {@link DataTable.defaults}.
11524			 */
11525			"bProcessing": null,
11526	
11527			/**
11528			 * Server-side processing enabled flag - when enabled DataTables will
11529			 * get all data from the server for every draw - there is no filtering,
11530			 * sorting or paging done on the client-side.
11531			 * Note that this parameter will be set by the initialisation routine. To
11532			 * set a default use {@link DataTable.defaults}.
11533			 */
11534			"bServerSide": null,
11535	
11536			/**
11537			 * Sorting enablement flag.
11538			 * Note that this parameter will be set by the initialisation routine. To
11539			 * set a default use {@link DataTable.defaults}.
11540			 */
11541			"bSort": null,
11542	
11543			/**
11544			 * Multi-column sorting
11545			 * Note that this parameter will be set by the initialisation routine. To
11546			 * set a default use {@link DataTable.defaults}.
11547			 */
11548			"bSortMulti": null,
11549	
11550			/**
11551			 * Apply a class to the columns which are being sorted to provide a
11552			 * visual highlight or not. This can slow things down when enabled since
11553			 * there is a lot of DOM interaction.
11554			 * Note that this parameter will be set by the initialisation routine. To
11555			 * set a default use {@link DataTable.defaults}.
11556			 */
11557			"bSortClasses": null,
11558	
11559			/**
11560			 * State saving enablement flag.
11561			 * Note that this parameter will be set by the initialisation routine. To
11562			 * set a default use {@link DataTable.defaults}.
11563			 */
11564			"bStateSave": null
11565		},
11566	
11567	
11568		/**
11569		 * Scrolling settings for a table.
11570		 */
11571		"oScroll": {
11572			/**
11573			 * When the table is shorter in height than sScrollY, collapse the
11574			 * table container down to the height of the table (when true).
11575			 * Note that this parameter will be set by the initialisation routine. To
11576			 * set a default use {@link DataTable.defaults}.
11577			 */
11578			"bCollapse": null,
11579	
11580			/**
11581			 * Width of the scrollbar for the web-browser's platform. Calculated
11582			 * during table initialisation.
11583			 */
11584			"iBarWidth": 0,
11585	
11586			/**
11587			 * Viewport width for horizontal scrolling. Horizontal scrolling is
11588			 * disabled if an empty string.
11589			 * Note that this parameter will be set by the initialisation routine. To
11590			 * set a default use {@link DataTable.defaults}.
11591			 */
11592			"sX": null,
11593	
11594			/**
11595			 * Width to expand the table to when using x-scrolling. Typically you
11596			 * should not need to use this.
11597			 * Note that this parameter will be set by the initialisation routine. To
11598			 * set a default use {@link DataTable.defaults}.
11599			 *  @deprecated
11600			 */
11601			"sXInner": null,
11602	
11603			/**
11604			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
11605			 * if an empty string.
11606			 * Note that this parameter will be set by the initialisation routine. To
11607			 * set a default use {@link DataTable.defaults}.
11608			 */
11609			"sY": null
11610		},
11611	
11612		/**
11613		 * Language information for the table.
11614		 */
11615		"oLanguage": {
11616			/**
11617			 * Information callback function. See
11618			 * {@link DataTable.defaults.fnInfoCallback}
11619			 */
11620			"fnInfoCallback": null
11621		},
11622	
11623		/**
11624		 * Browser support parameters
11625		 */
11626		"oBrowser": {
11627			/**
11628			 * Determine if the vertical scrollbar is on the right or left of the
11629			 * scrolling container - needed for rtl language layout, although not
11630			 * all browsers move the scrollbar (Safari).
11631			 */
11632			"bScrollbarLeft": false,
11633	
11634			/**
11635			 * Browser scrollbar width
11636			 */
11637			"barWidth": 0
11638		},
11639	
11640	
11641		"ajax": null,
11642	
11643	
11644		/**
11645		 * Array referencing the nodes which are used for the features. The
11646		 * parameters of this object match what is allowed by sDom - i.e.
11647		 *   <ul>
11648		 *     <li>'l' - Length changing</li>
11649		 *     <li>'f' - Filtering input</li>
11650		 *     <li>'t' - The table!</li>
11651		 *     <li>'i' - Information</li>
11652		 *     <li>'p' - Pagination</li>
11653		 *     <li>'r' - pRocessing</li>
11654		 *   </ul>
11655		 */
11656		"aanFeatures": [],
11657	
11658		/**
11659		 * Store data information - see {@link DataTable.models.oRow} for detailed
11660		 * information.
11661		 */
11662		"aoData": [],
11663	
11664		/**
11665		 * Array of indexes which are in the current display (after filtering etc)
11666		 */
11667		"aiDisplay": [],
11668	
11669		/**
11670		 * Array of indexes for display - no filtering
11671		 */
11672		"aiDisplayMaster": [],
11673	
11674		/**
11675		 * Map of row ids to data indexes
11676		 */
11677		"aIds": {},
11678	
11679		/**
11680		 * Store information about each column that is in use
11681		 */
11682		"aoColumns": [],
11683	
11684		/**
11685		 * Store information about the table's header
11686		 */
11687		"aoHeader": [],
11688	
11689		/**
11690		 * Store information about the table's footer
11691		 */
11692		"aoFooter": [],
11693	
11694		/**
11695		 * Store the applied global search information in case we want to force a
11696		 * research or compare the old search to a new one.
11697		 * Note that this parameter will be set by the initialisation routine. To
11698		 * set a default use {@link DataTable.defaults}.
11699		 */
11700		"oPreviousSearch": {},
11701	
11702		/**
11703		 * Store for named searches
11704		 */
11705		searchFixed: {},
11706	
11707		/**
11708		 * Store the applied search for each column - see
11709		 * {@link DataTable.models.oSearch} for the format that is used for the
11710		 * filtering information for each column.
11711		 */
11712		"aoPreSearchCols": [],
11713	
11714		/**
11715		 * Sorting that is applied to the table. Note that the inner arrays are
11716		 * used in the following manner:
11717		 * <ul>
11718		 *   <li>Index 0 - column number</li>
11719		 *   <li>Index 1 - current sorting direction</li>
11720		 * </ul>
11721		 * Note that this parameter will be set by the initialisation routine. To
11722		 * set a default use {@link DataTable.defaults}.
11723		 */
11724		"aaSorting": null,
11725	
11726		/**
11727		 * Sorting that is always applied to the table (i.e. prefixed in front of
11728		 * aaSorting).
11729		 * Note that this parameter will be set by the initialisation routine. To
11730		 * set a default use {@link DataTable.defaults}.
11731		 */
11732		"aaSortingFixed": [],
11733	
11734		/**
11735		 * If restoring a table - we should restore its width
11736		 */
11737		"sDestroyWidth": 0,
11738	
11739		/**
11740		 * Callback functions array for every time a row is inserted (i.e. on a draw).
11741		 */
11742		"aoRowCallback": [],
11743	
11744		/**
11745		 * Callback functions for the header on each draw.
11746		 */
11747		"aoHeaderCallback": [],
11748	
11749		/**
11750		 * Callback function for the footer on each draw.
11751		 */
11752		"aoFooterCallback": [],
11753	
11754		/**
11755		 * Array of callback functions for draw callback functions
11756		 */
11757		"aoDrawCallback": [],
11758	
11759		/**
11760		 * Array of callback functions for row created function
11761		 */
11762		"aoRowCreatedCallback": [],
11763	
11764		/**
11765		 * Callback functions for just before the table is redrawn. A return of
11766		 * false will be used to cancel the draw.
11767		 */
11768		"aoPreDrawCallback": [],
11769	
11770		/**
11771		 * Callback functions for when the table has been initialised.
11772		 */
11773		"aoInitComplete": [],
11774	
11775	
11776		/**
11777		 * Callbacks for modifying the settings to be stored for state saving, prior to
11778		 * saving state.
11779		 */
11780		"aoStateSaveParams": [],
11781	
11782		/**
11783		 * Callbacks for modifying the settings that have been stored for state saving
11784		 * prior to using the stored values to restore the state.
11785		 */
11786		"aoStateLoadParams": [],
11787	
11788		/**
11789		 * Callbacks for operating on the settings object once the saved state has been
11790		 * loaded
11791		 */
11792		"aoStateLoaded": [],
11793	
11794		/**
11795		 * Cache the table ID for quick access
11796		 */
11797		"sTableId": "",
11798	
11799		/**
11800		 * The TABLE node for the main table
11801		 */
11802		"nTable": null,
11803	
11804		/**
11805		 * Permanent ref to the thead element
11806		 */
11807		"nTHead": null,
11808	
11809		/**
11810		 * Permanent ref to the tfoot element - if it exists
11811		 */
11812		"nTFoot": null,
11813	
11814		/**
11815		 * Permanent ref to the tbody element
11816		 */
11817		"nTBody": null,
11818	
11819		/**
11820		 * Cache the wrapper node (contains all DataTables controlled elements)
11821		 */
11822		"nTableWrapper": null,
11823	
11824		/**
11825		 * Indicate if all required information has been read in
11826		 */
11827		"bInitialised": false,
11828	
11829		/**
11830		 * Information about open rows. Each object in the array has the parameters
11831		 * 'nTr' and 'nParent'
11832		 */
11833		"aoOpenRows": [],
11834	
11835		/**
11836		 * Dictate the positioning of DataTables' control elements - see
11837		 * {@link DataTable.model.oInit.sDom}.
11838		 * Note that this parameter will be set by the initialisation routine. To
11839		 * set a default use {@link DataTable.defaults}.
11840		 */
11841		"sDom": null,
11842	
11843		/**
11844		 * Search delay (in mS)
11845		 */
11846		"searchDelay": null,
11847	
11848		/**
11849		 * Which type of pagination should be used.
11850		 * Note that this parameter will be set by the initialisation routine. To
11851		 * set a default use {@link DataTable.defaults}.
11852		 */
11853		"sPaginationType": "two_button",
11854	
11855		/**
11856		 * Number of paging controls on the page. Only used for backwards compatibility
11857		 */
11858		pagingControls: 0,
11859	
11860		/**
11861		 * The state duration (for `stateSave`) in seconds.
11862		 * Note that this parameter will be set by the initialisation routine. To
11863		 * set a default use {@link DataTable.defaults}.
11864		 */
11865		"iStateDuration": 0,
11866	
11867		/**
11868		 * Array of callback functions for state saving. Each array element is an
11869		 * object with the following parameters:
11870		 *   <ul>
11871		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11872		 *       and the JSON string to save that has been thus far created. Returns
11873		 *       a JSON string to be inserted into a json object
11874		 *       (i.e. '"param": [ 0, 1, 2]')</li>
11875		 *     <li>string:sName - name of callback</li>
11876		 *   </ul>
11877		 */
11878		"aoStateSave": [],
11879	
11880		/**
11881		 * Array of callback functions for state loading. Each array element is an
11882		 * object with the following parameters:
11883		 *   <ul>
11884		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11885		 *       and the object stored. May return false to cancel state loading</li>
11886		 *     <li>string:sName - name of callback</li>
11887		 *   </ul>
11888		 */
11889		"aoStateLoad": [],
11890	
11891		/**
11892		 * State that was saved. Useful for back reference
11893		 */
11894		"oSavedState": null,
11895	
11896		/**
11897		 * State that was loaded. Useful for back reference
11898		 */
11899		"oLoadedState": null,
11900	
11901		/**
11902		 * Note if draw should be blocked while getting data
11903		 */
11904		"bAjaxDataGet": true,
11905	
11906		/**
11907		 * The last jQuery XHR object that was used for server-side data gathering.
11908		 * This can be used for working with the XHR information in one of the
11909		 * callbacks
11910		 */
11911		"jqXHR": null,
11912	
11913		/**
11914		 * JSON returned from the server in the last Ajax request
11915		 */
11916		"json": undefined,
11917	
11918		/**
11919		 * Data submitted as part of the last Ajax request
11920		 */
11921		"oAjaxData": undefined,
11922	
11923		/**
11924		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
11925		 * required).
11926		 * Note that this parameter will be set by the initialisation routine. To
11927		 * set a default use {@link DataTable.defaults}.
11928		 */
11929		"sServerMethod": null,
11930	
11931		/**
11932		 * Format numbers for display.
11933		 * Note that this parameter will be set by the initialisation routine. To
11934		 * set a default use {@link DataTable.defaults}.
11935		 */
11936		"fnFormatNumber": null,
11937	
11938		/**
11939		 * List of options that can be used for the user selectable length menu.
11940		 * Note that this parameter will be set by the initialisation routine. To
11941		 * set a default use {@link DataTable.defaults}.
11942		 */
11943		"aLengthMenu": null,
11944	
11945		/**
11946		 * Counter for the draws that the table does. Also used as a tracker for
11947		 * server-side processing
11948		 */
11949		"iDraw": 0,
11950	
11951		/**
11952		 * Indicate if a redraw is being done - useful for Ajax
11953		 */
11954		"bDrawing": false,
11955	
11956		/**
11957		 * Draw index (iDraw) of the last error when parsing the returned data
11958		 */
11959		"iDrawError": -1,
11960	
11961		/**
11962		 * Paging display length
11963		 */
11964		"_iDisplayLength": 10,
11965	
11966		/**
11967		 * Paging start point - aiDisplay index
11968		 */
11969		"_iDisplayStart": 0,
11970	
11971		/**
11972		 * Server-side processing - number of records in the result set
11973		 * (i.e. before filtering), Use fnRecordsTotal rather than
11974		 * this property to get the value of the number of records, regardless of
11975		 * the server-side processing setting.
11976		 */
11977		"_iRecordsTotal": 0,
11978	
11979		/**
11980		 * Server-side processing - number of records in the current display set
11981		 * (i.e. after filtering). Use fnRecordsDisplay rather than
11982		 * this property to get the value of the number of records, regardless of
11983		 * the server-side processing setting.
11984		 */
11985		"_iRecordsDisplay": 0,
11986	
11987		/**
11988		 * The classes to use for the table
11989		 */
11990		"oClasses": {},
11991	
11992		/**
11993		 * Flag attached to the settings object so you can check in the draw
11994		 * callback if filtering has been done in the draw. Deprecated in favour of
11995		 * events.
11996		 *  @deprecated
11997		 */
11998		"bFiltered": false,
11999	
12000		/**
12001		 * Flag attached to the settings object so you can check in the draw
12002		 * callback if sorting has been done in the draw. Deprecated in favour of
12003		 * events.
12004		 *  @deprecated
12005		 */
12006		"bSorted": false,
12007	
12008		/**
12009		 * Indicate that if multiple rows are in the header and there is more than
12010		 * one unique cell per column, if the top one (true) or bottom one (false)
12011		 * should be used for sorting / title by DataTables.
12012		 * Note that this parameter will be set by the initialisation routine. To
12013		 * set a default use {@link DataTable.defaults}.
12014		 */
12015		"bSortCellsTop": null,
12016	
12017		/**
12018		 * Initialisation object that is used for the table
12019		 */
12020		"oInit": null,
12021	
12022		/**
12023		 * Destroy callback functions - for plug-ins to attach themselves to the
12024		 * destroy so they can clean up markup and events.
12025		 */
12026		"aoDestroyCallback": [],
12027	
12028	
12029		/**
12030		 * Get the number of records in the current record set, before filtering
12031		 */
12032		"fnRecordsTotal": function ()
12033		{
12034			return _fnDataSource( this ) == 'ssp' ?
12035				this._iRecordsTotal * 1 :
12036				this.aiDisplayMaster.length;
12037		},
12038	
12039		/**
12040		 * Get the number of records in the current record set, after filtering
12041		 */
12042		"fnRecordsDisplay": function ()
12043		{
12044			return _fnDataSource( this ) == 'ssp' ?
12045				this._iRecordsDisplay * 1 :
12046				this.aiDisplay.length;
12047		},
12048	
12049		/**
12050		 * Get the display end point - aiDisplay index
12051		 */
12052		"fnDisplayEnd": function ()
12053		{
12054			var
12055				len      = this._iDisplayLength,
12056				start    = this._iDisplayStart,
12057				calc     = start + len,
12058				records  = this.aiDisplay.length,
12059				features = this.oFeatures,
12060				paginate = features.bPaginate;
12061	
12062			if ( features.bServerSide ) {
12063				return paginate === false || len === -1 ?
12064					start + records :
12065					Math.min( start+len, this._iRecordsDisplay );
12066			}
12067			else {
12068				return ! paginate || calc>records || len===-1 ?
12069					records :
12070					calc;
12071			}
12072		},
12073	
12074		/**
12075		 * The DataTables object for this table
12076		 */
12077		"oInstance": null,
12078	
12079		/**
12080		 * Unique identifier for each instance of the DataTables object. If there
12081		 * is an ID on the table node, then it takes that value, otherwise an
12082		 * incrementing internal counter is used.
12083		 */
12084		"sInstance": null,
12085	
12086		/**
12087		 * tabindex attribute value that is added to DataTables control elements, allowing
12088		 * keyboard navigation of the table and its controls.
12089		 */
12090		"iTabIndex": 0,
12091	
12092		/**
12093		 * DIV container for the footer scrolling table if scrolling
12094		 */
12095		"nScrollHead": null,
12096	
12097		/**
12098		 * DIV container for the footer scrolling table if scrolling
12099		 */
12100		"nScrollFoot": null,
12101	
12102		/**
12103		 * Last applied sort
12104		 */
12105		"aLastSort": [],
12106	
12107		/**
12108		 * Stored plug-in instances
12109		 */
12110		"oPlugins": {},
12111	
12112		/**
12113		 * Function used to get a row's id from the row's data
12114		 */
12115		"rowIdFn": null,
12116	
12117		/**
12118		 * Data location where to store a row's id
12119		 */
12120		"rowId": null,
12121	
12122		caption: '',
12123	
12124		captionNode: null,
12125	
12126		colgroup: null,
12127	
12128		/** Delay loading of data */
12129		deferLoading: null,
12130	
12131		/** Allow auto type detection */
12132		typeDetect: true,
12133	
12134		/** ResizeObserver for the container div */
12135		resizeObserver: null,
12136	
12137		/** Keep a record of the last size of the container, so we can skip duplicates */
12138		containerWidth: -1
12139	};
12140	
12141	/**
12142	 * Extension object for DataTables that is used to provide all extension
12143	 * options.
12144	 *
12145	 * Note that the `DataTable.ext` object is available through
12146	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
12147	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
12148	 *  @namespace
12149	 *  @extends DataTable.models.ext
12150	 */
12151	
12152	
12153	var extPagination = DataTable.ext.pager;
12154	
12155	// Paging buttons configuration
12156	$.extend( extPagination, {
12157		simple: function () {
12158			return [ 'previous', 'next' ];
12159		},
12160	
12161		full: function () {
12162			return [ 'first', 'previous', 'next', 'last' ];
12163		},
12164	
12165		numbers: function () {
12166			return [ 'numbers' ];
12167		},
12168	
12169		simple_numbers: function () {
12170			return [ 'previous', 'numbers', 'next' ];
12171		},
12172	
12173		full_numbers: function () {
12174			return [ 'first', 'previous', 'numbers', 'next', 'last' ];
12175		},
12176	
12177		first_last: function () {
12178			return ['first', 'last'];
12179		},
12180	
12181		first_last_numbers: function () {
12182			return ['first', 'numbers', 'last'];
12183		},
12184	
12185		// For testing and plug-ins to use
12186		_numbers: _pagingNumbers,
12187	
12188		// Number of number buttons - legacy, use `numbers` option for paging feature
12189		numbers_length: 7
12190	} );
12191	
12192	
12193	$.extend( true, DataTable.ext.renderer, {
12194		pagingButton: {
12195			_: function (settings, buttonType, content, active, disabled) {
12196				var classes = settings.oClasses.paging;
12197				var btnClasses = [classes.button];
12198				var btn;
12199	
12200				if (active) {
12201					btnClasses.push(classes.active);
12202				}
12203	
12204				if (disabled) {
12205					btnClasses.push(classes.disabled)
12206				}
12207	
12208				if (buttonType === 'ellipsis') {
12209					btn = $('<span class="ellipsis"></span>').html(content)[0];
12210				}
12211				else {
12212					btn = $('<button>', {
12213						class: btnClasses.join(' '),
12214						role: 'link',
12215						type: 'button'
12216					}).html(content);
12217				}
12218	
12219				return {
12220					display: btn,
12221					clicker: btn
12222				}
12223			}
12224		},
12225	
12226		pagingContainer: {
12227			_: function (settings, buttons) {
12228				// No wrapping element - just append directly to the host
12229				return buttons;
12230			}
12231		}
12232	} );
12233	
12234	// Common function to remove new lines, strip HTML and diacritic control
12235	var _filterString = function (stripHtml, normalize) {
12236		return function (str) {
12237			if (_empty(str) || typeof str !== 'string') {
12238				return str;
12239			}
12240	
12241			str = str.replace( _re_new_lines, " " );
12242	
12243			if (stripHtml) {
12244				str = _stripHtml(str);
12245			}
12246	
12247			if (normalize) {
12248				str = _normalize(str, false);
12249			}
12250	
12251			return str;
12252		};
12253	}
12254	
12255	/*
12256	 * Public helper functions. These aren't used internally by DataTables, or
12257	 * called by any of the options passed into DataTables, but they can be used
12258	 * externally by developers working with DataTables. They are helper functions
12259	 * to make working with DataTables a little bit easier.
12260	 */
12261	
12262	/**
12263	 * Common logic for moment, luxon or a date action.
12264	 *
12265	 * Happens after __mldObj, so don't need to call `resolveWindowsLibs` again
12266	 */
12267	function __mld( dtLib, momentFn, luxonFn, dateFn, arg1 ) {
12268		if (__moment) {
12269			return dtLib[momentFn]( arg1 );
12270		}
12271		else if (__luxon) {
12272			return dtLib[luxonFn]( arg1 );
12273		}
12274		
12275		return dateFn ? dtLib[dateFn]( arg1 ) : dtLib;
12276	}
12277	
12278	
12279	var __mlWarning = false;
12280	var __luxon; // Can be assigned in DateTable.use()
12281	var __moment; // Can be assigned in DateTable.use()
12282	
12283	/**
12284	 * 
12285	 */
12286	function resolveWindowLibs() {
12287		if (window.luxon && ! __luxon) {
12288			__luxon = window.luxon;
12289		}
12290		
12291		if (window.moment && ! __moment) {
12292			__moment = window.moment;
12293		}
12294	}
12295	
12296	function __mldObj (d, format, locale) {
12297		var dt;
12298	
12299		resolveWindowLibs();
12300	
12301		if (__moment) {
12302			dt = __moment.utc( d, format, locale, true );
12303	
12304			if (! dt.isValid()) {
12305				return null;
12306			}
12307		}
12308		else if (__luxon) {
12309			dt = format && typeof d === 'string'
12310				? __luxon.DateTime.fromFormat( d, format )
12311				: __luxon.DateTime.fromISO( d );
12312	
12313			if (! dt.isValid) {
12314				return null;
12315			}
12316	
12317			dt = dt.setLocale(locale);
12318		}
12319		else if (! format) {
12320			// No format given, must be ISO
12321			dt = new Date(d);
12322		}
12323		else {
12324			if (! __mlWarning) {
12325				alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
12326			}
12327	
12328			__mlWarning = true;
12329		}
12330	
12331		return dt;
12332	}
12333	
12334	// Wrapper for date, datetime and time which all operate the same way with the exception of
12335	// the output string for auto locale support
12336	function __mlHelper (localeString) {
12337		return function ( from, to, locale, def ) {
12338			// Luxon and Moment support
12339			// Argument shifting
12340			if ( arguments.length === 0 ) {
12341				locale = 'en';
12342				to = null; // means toLocaleString
12343				from = null; // means iso8601
12344			}
12345			else if ( arguments.length === 1 ) {
12346				locale = 'en';
12347				to = from;
12348				from = null;
12349			}
12350			else if ( arguments.length === 2 ) {
12351				locale = to;
12352				to = from;
12353				from = null;
12354			}
12355	
12356			var typeName = 'datetime' + (to ? '-' + to : '');
12357	
12358			// Add type detection and sorting specific to this date format - we need to be able to identify
12359			// date type columns as such, rather than as numbers in extensions. Hence the need for this.
12360			if (! DataTable.ext.type.order[typeName + '-pre']) {
12361				DataTable.type(typeName, {
12362					detect: function (d) {
12363						// The renderer will give the value to type detect as the type!
12364						return d === typeName ? typeName : false;
12365					},
12366					order: {
12367						pre: function (d) {
12368							// The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
12369							// `valueOf` which gives milliseconds epoch
12370							return d.valueOf();
12371						}
12372					},
12373					className: 'dt-right'
12374				});
12375			}
12376		
12377			return function ( d, type ) {
12378				// Allow for a default value
12379				if (d === null || d === undefined) {
12380					if (def === '--now') {
12381						// We treat everything as UTC further down, so no changes are
12382						// made, as such need to get the local date / time as if it were
12383						// UTC
12384						var local = new Date();
12385						d = new Date( Date.UTC(
12386							local.getFullYear(), local.getMonth(), local.getDate(),
12387							local.getHours(), local.getMinutes(), local.getSeconds()
12388						) );
12389					}
12390					else {
12391						d = '';
12392					}
12393				}
12394	
12395				if (type === 'type') {
12396					// Typing uses the type name for fast matching
12397					return typeName;
12398				}
12399	
12400				if (d === '') {
12401					return type !== 'sort'
12402						? ''
12403						: __mldObj('0000-01-01 00:00:00', null, locale);
12404				}
12405	
12406				// Shortcut. If `from` and `to` are the same, we are using the renderer to
12407				// format for ordering, not display - its already in the display format.
12408				if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) {
12409					return d;
12410				}
12411	
12412				var dt = __mldObj(d, from, locale);
12413	
12414				if (dt === null) {
12415					return d;
12416				}
12417	
12418				if (type === 'sort') {
12419					return dt;
12420				}
12421				
12422				var formatted = to === null
12423					? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
12424					: __mld(dt, 'format', 'toFormat', 'toISOString', to);
12425	
12426				// XSS protection
12427				return type === 'display' ?
12428					_escapeHtml( formatted ) :
12429					formatted;
12430			};
12431		}
12432	}
12433	
12434	// Based on locale, determine standard number formatting
12435	// Fallback for legacy browsers is US English
12436	var __thousands = ',';
12437	var __decimal = '.';
12438	
12439	if (window.Intl !== undefined) {
12440		try {
12441			var num = new Intl.NumberFormat().formatToParts(100000.1);
12442		
12443			for (var i=0 ; i<num.length ; i++) {
12444				if (num[i].type === 'group') {
12445					__thousands = num[i].value;
12446				}
12447				else if (num[i].type === 'decimal') {
12448					__decimal = num[i].value;
12449				}
12450			}
12451		}
12452		catch (e) {
12453			// noop
12454		}
12455	}
12456	
12457	// Formatted date time detection - use by declaring the formats you are going to use
12458	DataTable.datetime = function ( format, locale ) {
12459		var typeName = 'datetime-' + format;
12460	
12461		if (! locale) {
12462			locale = 'en';
12463		}
12464	
12465		if (! DataTable.ext.type.order[typeName]) {
12466			DataTable.type(typeName, {
12467				detect: function (d) {
12468					var dt = __mldObj(d, format, locale);
12469					return d === '' || dt ? typeName : false;
12470				},
12471				order: {
12472					pre: function (d) {
12473						return __mldObj(d, format, locale) || 0;
12474					}
12475				},
12476				className: 'dt-right'
12477			});
12478		}
12479	}
12480	
12481	/**
12482	 * Helpers for `columns.render`.
12483	 *
12484	 * The options defined here can be used with the `columns.render` initialisation
12485	 * option to provide a display renderer. The following functions are defined:
12486	 *
12487	 * * `moment` - Uses the MomentJS library to convert from a given format into another.
12488	 * This renderer has three overloads:
12489	 *   * 1 parameter:
12490	 *     * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
12491	 *   * 2 parameters:
12492	 *     * `string` - Format to convert from
12493	 *     * `string` - Format to convert to. Assumes `en` locale
12494	 *   * 3 parameters:
12495	 *     * `string` - Format to convert from
12496	 *     * `string` - Format to convert to
12497	 *     * `string` - Locale
12498	 * * `number` - Will format numeric data (defined by `columns.data`) for
12499	 *   display, retaining the original unformatted data for sorting and filtering.
12500	 *   It takes 5 parameters:
12501	 *   * `string` - Thousands grouping separator
12502	 *   * `string` - Decimal point indicator
12503	 *   * `integer` - Number of decimal points to show
12504	 *   * `string` (optional) - Prefix.
12505	 *   * `string` (optional) - Postfix (/suffix).
12506	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
12507	 *   parameters.
12508	 *
12509	 * @example
12510	 *   // Column definition using the number renderer
12511	 *   {
12512	 *     data: "salary",
12513	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
12514	 *   }
12515	 *
12516	 * @namespace
12517	 */
12518	DataTable.render = {
12519		date: __mlHelper('toLocaleDateString'),
12520		datetime: __mlHelper('toLocaleString'),
12521		time: __mlHelper('toLocaleTimeString'),
12522		number: function ( thousands, decimal, precision, prefix, postfix ) {
12523			// Auto locale detection
12524			if (thousands === null || thousands === undefined) {
12525				thousands = __thousands;
12526			}
12527	
12528			if (decimal === null || decimal === undefined) {
12529				decimal = __decimal;
12530			}
12531	
12532			return {
12533				display: function ( d ) {
12534					if ( typeof d !== 'number' && typeof d !== 'string' ) {
12535						return d;
12536					}
12537	
12538					if (d === '' || d === null) {
12539						return d;
12540					}
12541	
12542					var negative = d < 0 ? '-' : '';
12543					var flo = parseFloat( d );
12544					var abs = Math.abs(flo);
12545	
12546					// Scientific notation for large and small numbers
12547					if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0) ) {
12548						var exp = flo.toExponential(precision).split(/e\+?/);
12549						return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
12550					}
12551	
12552					// If NaN then there isn't much formatting that we can do - just
12553					// return immediately, escaping any HTML (this was supposed to
12554					// be a number after all)
12555					if ( isNaN( flo ) ) {
12556						return _escapeHtml( d );
12557					}
12558	
12559					flo = flo.toFixed( precision );
12560					d = Math.abs( flo );
12561	
12562					var intPart = parseInt( d, 10 );
12563					var floatPart = precision ?
12564						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
12565						'';
12566	
12567					// If zero, then can't have a negative prefix
12568					if (intPart === 0 && parseFloat(floatPart) === 0) {
12569						negative = '';
12570					}
12571	
12572					return negative + (prefix||'') +
12573						intPart.toString().replace(
12574							/\B(?=(\d{3})+(?!\d))/g, thousands
12575						) +
12576						floatPart +
12577						(postfix||'');
12578				}
12579			};
12580		},
12581	
12582		text: function () {
12583			return {
12584				display: _escapeHtml,
12585				filter: _escapeHtml
12586			};
12587		}
12588	};
12589	
12590	
12591	var _extTypes = DataTable.ext.type;
12592	
12593	// Get / set type
12594	DataTable.type = function (name, prop, val) {
12595		if (! prop) {
12596			return {
12597				className: _extTypes.className[name],
12598				detect: _extTypes.detect.find(function (fn) {
12599					return fn._name === name;
12600				}),
12601				order: {
12602					pre: _extTypes.order[name + '-pre'],
12603					asc: _extTypes.order[name + '-asc'],
12604					desc: _extTypes.order[name + '-desc']
12605				},
12606				render: _extTypes.render[name],
12607				search: _extTypes.search[name]
12608			};
12609		}
12610	
12611		var setProp = function(prop, propVal) {
12612			_extTypes[prop][name] = propVal;
12613		};
12614		var setDetect = function (detect) {
12615			// `detect` can be a function or an object - we set a name
12616			// property for either - that is used for the detection
12617			Object.defineProperty(detect, "_name", {value: name});
12618	
12619			var idx = _extTypes.detect.findIndex(function (item) {
12620				return item._name === name;
12621			});
12622	
12623			if (idx === -1) {
12624				_extTypes.detect.unshift(detect);
12625			}
12626			else {
12627				_extTypes.detect.splice(idx, 1, detect);
12628			}
12629		};
12630		var setOrder = function (obj) {
12631			_extTypes.order[name + '-pre'] = obj.pre; // can be undefined
12632			_extTypes.order[name + '-asc'] = obj.asc; // can be undefined
12633			_extTypes.order[name + '-desc'] = obj.desc; // can be undefined
12634		};
12635	
12636		// prop is optional
12637		if (val === undefined) {
12638			val = prop;
12639			prop = null;
12640		}
12641	
12642		if (prop === 'className') {
12643			setProp('className', val);
12644		}
12645		else if (prop === 'detect') {
12646			setDetect(val);
12647		}
12648		else if (prop === 'order') {
12649			setOrder(val);
12650		}
12651		else if (prop === 'render') {
12652			setProp('render', val);
12653		}
12654		else if (prop === 'search') {
12655			setProp('search', val);
12656		}
12657		else if (! prop) {
12658			if (val.className) {
12659				setProp('className', val.className);
12660			}
12661	
12662			if (val.detect !== undefined) {
12663				setDetect(val.detect);
12664			}
12665	
12666			if (val.order) {
12667				setOrder(val.order);
12668			}
12669	
12670			if (val.render !== undefined) {
12671				setProp('render', val.render);
12672			}
12673	
12674			if (val.search !== undefined) {
12675				setProp('search', val.search);
12676			}
12677		}
12678	}
12679	
12680	// Get a list of types
12681	DataTable.types = function () {
12682		return _extTypes.detect.map(function (fn) {
12683			return fn._name;
12684		});
12685	};
12686	
12687	var __diacriticSort = function (a, b) {
12688		a = a !== null && a !== undefined ? a.toString().toLowerCase() : '';
12689		b = b !== null && b !== undefined ? b.toString().toLowerCase() : '';
12690	
12691		// Checked for `navigator.languages` support in `oneOf` so this code can't execute in old
12692		// Safari and thus can disable this check
12693		// eslint-disable-next-line compat/compat
12694		return a.localeCompare(b, navigator.languages[0] || navigator.language, {
12695			numeric: true,
12696			ignorePunctuation: true,
12697		});
12698	}
12699	
12700	var __diacriticHtmlSort = function (a, b) {
12701		a = _stripHtml(a);
12702		b = _stripHtml(b);
12703	
12704		return __diacriticSort(a, b);
12705	}
12706	
12707	//
12708	// Built in data types
12709	//
12710	
12711	DataTable.type('string', {
12712		detect: function () {
12713			return 'string';
12714		},
12715		order: {
12716			pre: function ( a ) {
12717				// This is a little complex, but faster than always calling toString,
12718				// http://jsperf.com/tostring-v-check
12719				return _empty(a) && typeof a !== 'boolean' ?
12720					'' :
12721					typeof a === 'string' ?
12722						a.toLowerCase() :
12723						! a.toString ?
12724							'' :
12725							a.toString();
12726			}
12727		},
12728		search: _filterString(false, true)
12729	});
12730	
12731	DataTable.type('string-utf8', {
12732		detect: {
12733			allOf: function ( d ) {
12734				return true;
12735			},
12736			oneOf: function ( d ) {
12737				// At least one data point must contain a non-ASCII character
12738				// This line will also check if navigator.languages is supported or not. If not (Safari 10.0-)
12739				// this data type won't be supported.
12740				// eslint-disable-next-line compat/compat
12741				return ! _empty( d ) && navigator.languages && typeof d === 'string' && d.match(/[^\x00-\x7F]/);
12742			}
12743		},
12744		order: {
12745			asc: __diacriticSort,
12746			desc: function (a, b) {
12747				return __diacriticSort(a, b) * -1;
12748			}
12749		},
12750		search: _filterString(false, true)
12751	});
12752	
12753	
12754	DataTable.type('html', {
12755		detect: {
12756			allOf: function ( d ) {
12757				return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1);
12758			},
12759			oneOf: function ( d ) {
12760				// At least one data point must contain a `<`
12761				return ! _empty( d ) && typeof d === 'string' && d.indexOf('<') !== -1;
12762			}
12763		},
12764		order: {
12765			pre: function ( a ) {
12766				return _empty(a) ?
12767					'' :
12768					a.replace ?
12769						_stripHtml(a).trim().toLowerCase() :
12770						a+'';
12771			}
12772		},
12773		search: _filterString(true, true)
12774	});
12775	
12776	
12777	DataTable.type('html-utf8', {
12778		detect: {
12779			allOf: function ( d ) {
12780				return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1);
12781			},
12782			oneOf: function ( d ) {
12783				// At least one data point must contain a `<` and a non-ASCII character
12784				// eslint-disable-next-line compat/compat
12785				return navigator.languages &&
12786					! _empty( d ) &&
12787					typeof d === 'string' &&
12788					d.indexOf('<') !== -1 &&
12789					typeof d === 'string' && d.match(/[^\x00-\x7F]/);
12790			}
12791		},
12792		order: {
12793			asc: __diacriticHtmlSort,
12794			desc: function (a, b) {
12795				return __diacriticHtmlSort(a, b) * -1;
12796			}
12797		},
12798		search: _filterString(true, true)
12799	});
12800	
12801	
12802	DataTable.type('date', {
12803		className: 'dt-type-date',
12804		detect: {
12805			allOf: function ( d ) {
12806				// V8 tries _very_ hard to make a string passed into `Date.parse()`
12807				// valid, so we need to use a regex to restrict date formats. Use a
12808				// plug-in for anything other than ISO8601 style strings
12809				if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
12810					return null;
12811				}
12812				var parsed = Date.parse(d);
12813				return (parsed !== null && !isNaN(parsed)) || _empty(d);
12814			},
12815			oneOf: function ( d ) {
12816				// At least one entry must be a date or a string with a date
12817				return (d instanceof Date) || (typeof d === 'string' && _re_date.test(d));
12818			}
12819		},
12820		order: {
12821			pre: function ( d ) {
12822				var ts = Date.parse( d );
12823				return isNaN(ts) ? -Infinity : ts;
12824			}
12825		}
12826	});
12827	
12828	
12829	DataTable.type('html-num-fmt', {
12830		className: 'dt-type-numeric',
12831		detect: {
12832			allOf: function ( d, settings ) {
12833				var decimal = settings.oLanguage.sDecimal;
12834				return _htmlNumeric( d, decimal, true, false );
12835			},
12836			oneOf: function (d, settings) {
12837				// At least one data point must contain a numeric value
12838				var decimal = settings.oLanguage.sDecimal;
12839				return _htmlNumeric( d, decimal, true, false );
12840			}
12841		},
12842		order: {
12843			pre: function ( d, s ) {
12844				var dp = s.oLanguage.sDecimal;
12845				return __numericReplace( d, dp, _re_html, _re_formatted_numeric );
12846			}
12847		},
12848		search: _filterString(true, true)
12849	});
12850	
12851	
12852	DataTable.type('html-num', {
12853		className: 'dt-type-numeric',
12854		detect: {
12855			allOf: function ( d, settings ) {
12856				var decimal = settings.oLanguage.sDecimal;
12857				return _htmlNumeric( d, decimal, false, true );
12858			},
12859			oneOf: function (d, settings) {
12860				// At least one data point must contain a numeric value
12861				var decimal = settings.oLanguage.sDecimal;
12862				return _htmlNumeric( d, decimal, false, false );
12863			}
12864		},
12865		order: {
12866			pre: function ( d, s ) {
12867				var dp = s.oLanguage.sDecimal;
12868				return __numericReplace( d, dp, _re_html );
12869			}
12870		},
12871		search: _filterString(true, true)
12872	});
12873	
12874	
12875	DataTable.type('num-fmt', {
12876		className: 'dt-type-numeric',
12877		detect: {
12878			allOf: function ( d, settings ) {
12879				var decimal = settings.oLanguage.sDecimal;
12880				return _isNumber( d, decimal, true, true );
12881			},
12882			oneOf: function (d, settings) {
12883				// At least one data point must contain a numeric value
12884				var decimal = settings.oLanguage.sDecimal;
12885				return _isNumber( d, decimal, true, false );
12886			}
12887		},
12888		order: {
12889			pre: function ( d, s ) {
12890				var dp = s.oLanguage.sDecimal;
12891				return __numericReplace( d, dp, _re_formatted_numeric );
12892			}
12893		}
12894	});
12895	
12896	
12897	DataTable.type('num', {
12898		className: 'dt-type-numeric',
12899		detect: {
12900			allOf: function ( d, settings ) {
12901				var decimal = settings.oLanguage.sDecimal;
12902				return _isNumber( d, decimal, false, true );
12903			},
12904			oneOf: function (d, settings) {
12905				// At least one data point must contain a numeric value
12906				var decimal = settings.oLanguage.sDecimal;
12907				return _isNumber( d, decimal, false, false );
12908			}
12909		},
12910		order: {
12911			pre: function (d, s) {
12912				var dp = s.oLanguage.sDecimal;
12913				return __numericReplace( d, dp );
12914			}
12915		}
12916	});
12917	
12918	
12919	
12920	
12921	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
12922		if ( d !== 0 && (!d || d === '-') ) {
12923			return -Infinity;
12924		}
12925		
12926		var type = typeof d;
12927	
12928		if (type === 'number' || type === 'bigint') {
12929			return d;
12930		}
12931	
12932		// If a decimal place other than `.` is used, it needs to be given to the
12933		// function so we can detect it and replace with a `.` which is the only
12934		// decimal place Javascript recognises - it is not locale aware.
12935		if ( decimalPlace ) {
12936			d = _numToDecimal( d, decimalPlace );
12937		}
12938	
12939		if ( d.replace ) {
12940			if ( re1 ) {
12941				d = d.replace( re1, '' );
12942			}
12943	
12944			if ( re2 ) {
12945				d = d.replace( re2, '' );
12946			}
12947		}
12948	
12949		return d * 1;
12950	};
12951	
12952	
12953	$.extend( true, DataTable.ext.renderer, {
12954		footer: {
12955			_: function ( settings, cell, classes ) {
12956				cell.addClass(classes.tfoot.cell);
12957			}
12958		},
12959	
12960		header: {
12961			_: function ( settings, cell, classes ) {
12962				cell.addClass(classes.thead.cell);
12963	
12964				if (! settings.oFeatures.bSort) {
12965					cell.addClass(classes.order.none);
12966				}
12967	
12968				var legacyTop = settings.bSortCellsTop;
12969				var headerRows = cell.closest('thead').find('tr');
12970				var rowIdx = cell.parent().index();
12971	
12972				// Conditions to not apply the ordering icons
12973				if (
12974					// Cells and rows which have the attribute to disable the icons
12975					cell.attr('data-dt-order') === 'disable' ||
12976					cell.parent().attr('data-dt-order') === 'disable' ||
12977	
12978					// Legacy support for `orderCellsTop`. If it is set, then cells
12979					// which are not in the top or bottom row of the header (depending
12980					// on the value) do not get the sorting classes applied to them
12981					(legacyTop === true && rowIdx !== 0) ||
12982					(legacyTop === false && rowIdx !== headerRows.length - 1)
12983				) {
12984					return;
12985				}
12986	
12987				// No additional mark-up required
12988				// Attach a sort listener to update on sort - note that using the
12989				// `DT` namespace will allow the event to be removed automatically
12990				// on destroy, while the `dt` namespaced event is the one we are
12991				// listening for
12992				$(settings.nTable).on( 'order.dt.DT column-visibility.dt.DT', function ( e, ctx ) {
12993					if ( settings !== ctx ) { // need to check this this is the host
12994						return;               // table, not a nested one
12995					}
12996	
12997					var sorting = ctx.sortDetails;
12998	
12999					if (! sorting) {
13000						return;
13001					}
13002	
13003					var i;
13004					var orderClasses = classes.order;
13005					var columns = ctx.api.columns( cell );
13006					var col = settings.aoColumns[columns.flatten()[0]];
13007					var orderable = columns.orderable().includes(true);
13008					var ariaType = '';
13009					var indexes = columns.indexes();
13010					var sortDirs = columns.orderable(true).flatten();
13011					var orderedColumns = _pluck(sorting, 'col');
13012					var tabIndex = settings.iTabIndex;
13013	
13014					cell
13015						.removeClass(
13016							orderClasses.isAsc +' '+
13017							orderClasses.isDesc
13018						)
13019						.toggleClass( orderClasses.none, ! orderable )
13020						.toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
13021						.toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
13022	
13023					// Determine if all of the columns that this cell covers are included in the
13024					// current ordering
13025					var isOrdering = true;
13026					
13027					for (i=0; i<indexes.length; i++) {
13028						if (! orderedColumns.includes(indexes[i])) {
13029							isOrdering = false;
13030						}
13031					}
13032	
13033					if ( isOrdering ) {
13034						// Get the ordering direction for the columns under this cell
13035						// Note that it is possible for a cell to be asc and desc sorting
13036						// (column spanning cells)
13037						var orderDirs = columns.order();
13038	
13039						cell.addClass(
13040							orderDirs.includes('asc') ? orderClasses.isAsc : '' +
13041							orderDirs.includes('desc') ? orderClasses.isDesc : ''
13042						);
13043					}
13044	
13045					// Find the first visible column that has ordering applied to it - it get's
13046					// the aria information, as the ARIA spec says that only one column should
13047					// be marked with aria-sort
13048					var firstVis = -1; // column index
13049	
13050					for (i=0; i<orderedColumns.length; i++) {
13051						if (settings.aoColumns[orderedColumns[i]].bVisible) {
13052							firstVis = orderedColumns[i];
13053							break;
13054						}
13055					}
13056	
13057					if (indexes[0] == firstVis) {
13058						var firstSort = sorting[0];
13059						var sortOrder = col.asSorting;
13060	
13061						cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
13062	
13063						// Determine if the next click will remove sorting or change the sort
13064						ariaType = ! sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
13065					}
13066					else {
13067						cell.removeAttr('aria-sort');
13068					}
13069	
13070					// Make the headers tab-able for keyboard navigation
13071					if (orderable) {
13072						var orderSpan = cell.find('.dt-column-order');
13073						
13074						orderSpan
13075							.attr('role', 'button')
13076							.attr('aria-label', orderable
13077								? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
13078								: col.ariaTitle
13079							);
13080	
13081						if (tabIndex !== -1) {
13082							orderSpan.attr('tabindex', tabIndex);
13083						}
13084					}
13085				} );
13086			}
13087		},
13088	
13089		layout: {
13090			_: function ( settings, container, items ) {
13091				var classes = settings.oClasses.layout;
13092				var row = $('<div/>')
13093					.attr('id', items.id || null)
13094					.addClass(items.className || classes.row)
13095					.appendTo( container );
13096	
13097				DataTable.ext.renderer.layout._forLayoutRow(items, function (key, val) {
13098					if (key === 'id' || key === 'className') {
13099						return;
13100					}
13101	
13102					var klass = '';
13103	
13104					if (val.table) {
13105						row.addClass(classes.tableRow);
13106						klass += classes.tableCell + ' ';
13107					}
13108	
13109					if (key === 'start') {
13110						klass += classes.start;
13111					}
13112					else if (key === 'end') {
13113						klass += classes.end;
13114					}
13115					else {
13116						klass += classes.full;
13117					}
13118	
13119					$('<div/>')
13120						.attr({
13121							id: val.id || null,
13122							"class": val.className
13123								? val.className
13124								: classes.cell + ' ' + klass
13125						})
13126						.append( val.contents )
13127						.appendTo( row );
13128				});
13129			},
13130	
13131			// Shared for use by the styling frameworks
13132			_forLayoutRow: function (items, fn) {
13133				// As we are inserting dom elements, we need start / end in a
13134				// specific order, this function is used for sorting the layout
13135				// keys.
13136				var layoutEnum = function (x) {
13137					switch (x) {
13138						case '': return 0;
13139						case 'start': return 1;
13140						case 'end': return 2;
13141						default: return 3;
13142					}
13143				};
13144	
13145				Object
13146					.keys(items)
13147					.sort(function (a, b) {
13148						return layoutEnum(a) - layoutEnum(b);
13149					})
13150					.forEach(function (key) {
13151						fn(key, items[key]);
13152					});
13153			}
13154		}
13155	} );
13156	
13157	
13158	DataTable.feature = {};
13159	
13160	// Third parameter is internal only!
13161	DataTable.feature.register = function ( name, cb, legacy ) {
13162		DataTable.ext.features[ name ] = cb;
13163	
13164		if (legacy) {
13165			_ext.feature.push({
13166				cFeature: legacy,
13167				fnInit: cb
13168			});
13169		}
13170	};
13171	
13172	function _divProp(el, prop, val) {
13173		if (val) {
13174			el[prop] = val;
13175		}
13176	}
13177	
13178	DataTable.feature.register( 'div', function ( settings, opts ) {
13179		var n = $('<div>')[0];
13180	
13181		if (opts) {
13182			_divProp(n, 'className', opts.className);
13183			_divProp(n, 'id', opts.id);
13184			_divProp(n, 'innerHTML', opts.html);
13185			_divProp(n, 'textContent', opts.text);
13186		}
13187	
13188		return n;
13189	} );
13190	
13191	DataTable.feature.register( 'info', function ( settings, opts ) {
13192		// For compatibility with the legacy `info` top level option
13193		if (! settings.oFeatures.bInfo) {
13194			return null;
13195		}
13196	
13197		var
13198			lang  = settings.oLanguage,
13199			tid = settings.sTableId,
13200			n = $('<div/>', {
13201				'class': settings.oClasses.info.container,
13202			} );
13203	
13204		opts = $.extend({
13205			callback: lang.fnInfoCallback,
13206			empty: lang.sInfoEmpty,
13207			postfix: lang.sInfoPostFix,
13208			search: lang.sInfoFiltered,
13209			text: lang.sInfo,
13210		}, opts);
13211	
13212	
13213		// Update display on each draw
13214		settings.aoDrawCallback.push(function (s) {
13215			_fnUpdateInfo(s, opts, n);
13216		});
13217	
13218		// For the first info display in the table, we add a callback and aria information.
13219		if (! settings._infoEl) {
13220			n.attr({
13221				'aria-live': 'polite',
13222				id: tid+'_info',
13223				role: 'status'
13224			});
13225	
13226			// Table is described by our info div
13227			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
13228	
13229			settings._infoEl = n;
13230		}
13231	
13232		return n;
13233	}, 'i' );
13234	
13235	/**
13236	 * Update the information elements in the display
13237	 *  @param {object} settings dataTables settings object
13238	 *  @memberof DataTable#oApi
13239	 */
13240	function _fnUpdateInfo ( settings, opts, node )
13241	{
13242		var
13243			start = settings._iDisplayStart+1,
13244			end   = settings.fnDisplayEnd(),
13245			max   = settings.fnRecordsTotal(),
13246			total = settings.fnRecordsDisplay(),
13247			out   = total
13248				? opts.text
13249				: opts.empty;
13250	
13251		if ( total !== max ) {
13252			// Record set after filtering
13253			out += ' ' + opts.search;
13254		}
13255	
13256		// Convert the macros
13257		out += opts.postfix;
13258		out = _fnMacros( settings, out );
13259	
13260		if ( opts.callback ) {
13261			out = opts.callback.call( settings.oInstance,
13262				settings, start, end, max, total, out
13263			);
13264		}
13265	
13266		node.html( out );
13267	
13268		_fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
13269	}
13270	
13271	var __searchCounter = 0;
13272	
13273	// opts
13274	// - text
13275	// - placeholder
13276	DataTable.feature.register( 'search', function ( settings, opts ) {
13277		// Don't show the input if filtering isn't available on the table
13278		if (! settings.oFeatures.bFilter) {
13279			return null;
13280		}
13281	
13282		var classes = settings.oClasses.search;
13283		var tableId = settings.sTableId;
13284		var language = settings.oLanguage;
13285		var previousSearch = settings.oPreviousSearch;
13286		var input = '<input type="search" class="'+classes.input+'"/>';
13287	
13288		opts = $.extend({
13289			placeholder: language.sSearchPlaceholder,
13290			processing: false,
13291			text: language.sSearch
13292		}, opts);
13293	
13294		// The _INPUT_ is optional - is appended if not present
13295		if (opts.text.indexOf('_INPUT_') === -1) {
13296			opts.text += '_INPUT_';
13297		}
13298	
13299		opts.text = _fnMacros(settings, opts.text);
13300	
13301		// We can put the <input> outside of the label if it is at the start or end
13302		// which helps improve accessability (not all screen readers like implicit
13303		// for elements).
13304		var end = opts.text.match(/_INPUT_$/);
13305		var start = opts.text.match(/^_INPUT_/);
13306		var removed = opts.text.replace(/_INPUT_/, '');
13307		var str = '<label>' + opts.text + '</label>';
13308	
13309		if (start) {
13310			str = '_INPUT_<label>' + removed + '</label>';
13311		}
13312		else if (end) {
13313			str = '<label>' + removed + '</label>_INPUT_';
13314		}
13315	
13316		var filter = $('<div>')
13317			.addClass(classes.container)
13318			.append(str.replace(/_INPUT_/, input));
13319	
13320		// add for and id to label and input
13321		filter.find('label').attr('for', 'dt-search-' + __searchCounter);
13322		filter.find('input').attr('id', 'dt-search-' + __searchCounter);
13323		__searchCounter++;
13324	
13325		var searchFn = function(event) {
13326			var val = this.value;
13327	
13328			if(previousSearch.return && event.key !== "Enter") {
13329				return;
13330			}
13331	
13332			/* Now do the filter */
13333			if ( val != previousSearch.search ) {
13334				_fnProcessingRun(settings, opts.processing, function () {
13335					previousSearch.search = val;
13336			
13337					_fnFilterComplete( settings, previousSearch );
13338			
13339					// Need to redraw, without resorting
13340					settings._iDisplayStart = 0;
13341					_fnDraw( settings );
13342				});
13343			}
13344		};
13345	
13346		var searchDelay = settings.searchDelay !== null ?
13347			settings.searchDelay :
13348			0;
13349	
13350		var jqFilter = $('input', filter)
13351			.val( previousSearch.search )
13352			.attr( 'placeholder', opts.placeholder )
13353			.on(
13354				'keyup.DT search.DT input.DT paste.DT cut.DT',
13355				searchDelay ?
13356					DataTable.util.debounce( searchFn, searchDelay ) :
13357					searchFn
13358			)
13359			.on( 'mouseup.DT', function(e) {
13360				// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
13361				// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
13362				// checks the value to see if it has changed. In other browsers it won't have.
13363				setTimeout( function () {
13364					searchFn.call(jqFilter[0], e);
13365				}, 10);
13366			} )
13367			.on( 'keypress.DT', function(e) {
13368				/* Prevent form submission */
13369				if ( e.keyCode == 13 ) {
13370					return false;
13371				}
13372			} )
13373			.attr('aria-controls', tableId);
13374	
13375		// Update the input elements whenever the table is filtered
13376		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
13377			if ( settings === s && jqFilter[0] !== document.activeElement ) {
13378				jqFilter.val( typeof previousSearch.search !== 'function'
13379					? previousSearch.search
13380					: ''
13381				);
13382			}
13383		} );
13384	
13385		return filter;
13386	}, 'f' );
13387	
13388	// opts
13389	// - type - button configuration
13390	// - buttons - number of buttons to show - must be odd
13391	DataTable.feature.register( 'paging', function ( settings, opts ) {
13392		// Don't show the paging input if the table doesn't have paging enabled
13393		if (! settings.oFeatures.bPaginate) {
13394			return null;
13395		}
13396	
13397		opts = $.extend({
13398			buttons: DataTable.ext.pager.numbers_length,
13399			type: settings.sPaginationType,
13400			boundaryNumbers: true,
13401			firstLast: true,
13402			previousNext: true,
13403			numbers: true
13404		}, opts);
13405	
13406		var host = $('<div/>')
13407			.addClass(settings.oClasses.paging.container + (opts.type ? ' paging_' + opts.type : ''))
13408			.append(
13409				$('<nav>')
13410					.attr('aria-label', 'pagination')
13411					.addClass(settings.oClasses.paging.nav)
13412			);
13413		var draw = function () {
13414			_pagingDraw(settings, host.children(), opts);
13415		};
13416	
13417		settings.aoDrawCallback.push(draw);
13418	
13419		// Responsive redraw of paging control
13420		$(settings.nTable).on('column-sizing.dt.DT', draw);
13421	
13422		return host;
13423	}, 'p' );
13424	
13425	/**
13426	 * Dynamically create the button type array based on the configuration options.
13427	 * This will only happen if the paging type is not defined.
13428	 */
13429	function _pagingDynamic(opts) {
13430		var out = [];
13431	
13432		if (opts.numbers) {
13433			out.push('numbers');
13434		}
13435	
13436		if (opts.previousNext) {
13437			out.unshift('previous');
13438			out.push('next');
13439		}
13440	
13441		if (opts.firstLast) {
13442			out.unshift('first');
13443			out.push('last');
13444		}
13445	
13446		return out;
13447	}
13448	
13449	function _pagingDraw(settings, host, opts) {
13450		if (! settings._bInitComplete) {
13451			return;
13452		}
13453	
13454		var
13455			plugin = opts.type
13456				? DataTable.ext.pager[ opts.type ]
13457				: _pagingDynamic,
13458			aria = settings.oLanguage.oAria.paginate || {},
13459			start      = settings._iDisplayStart,
13460			len        = settings._iDisplayLength,
13461			visRecords = settings.fnRecordsDisplay(),
13462			all        = len === -1,
13463			page = all ? 0 : Math.ceil( start / len ),
13464			pages = all ? 1 : Math.ceil( visRecords / len ),
13465			buttons = [],
13466			buttonEls = [],
13467			buttonsNested = plugin(opts)
13468				.map(function (val) {
13469					return val === 'numbers'
13470						? _pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
13471						: val;
13472				});
13473	
13474		// .flat() would be better, but not supported in old Safari
13475		buttons = buttons.concat.apply(buttons, buttonsNested);
13476	
13477		for (var i=0 ; i<buttons.length ; i++) {
13478			var button = buttons[i];
13479	
13480			var btnInfo = _pagingButtonInfo(settings, button, page, pages);
13481			var btn = _fnRenderer( settings, 'pagingButton' )(
13482				settings,
13483				button,
13484				btnInfo.display,
13485				btnInfo.active,
13486				btnInfo.disabled
13487			);
13488	
13489			var ariaLabel = typeof button === 'string'
13490				? aria[ button ]
13491				: aria.number
13492					? aria.number + (button+1)
13493					: null;
13494	
13495			// Common attributes
13496			$(btn.clicker).attr({
13497				'aria-controls': settings.sTableId,
13498				'aria-disabled': btnInfo.disabled ? 'true' : null,
13499				'aria-current': btnInfo.active ? 'page' : null,
13500				'aria-label': ariaLabel,
13501				'data-dt-idx': button,
13502				'tabIndex': btnInfo.disabled
13503					? -1
13504					: settings.iTabIndex && btn.clicker[0].nodeName.toLowerCase() !== 'span'
13505						? settings.iTabIndex
13506						: null, // `0` doesn't need a tabIndex since it is the default
13507			});
13508	
13509			if (typeof button !== 'number') {
13510				$(btn.clicker).addClass(button);
13511			}
13512	
13513			_fnBindAction(
13514				btn.clicker, {action: button}, function(e) {
13515					e.preventDefault();
13516	
13517					_fnPageChange( settings, e.data.action, true );
13518				}
13519			);
13520	
13521			buttonEls.push(btn.display);
13522		}
13523	
13524		var wrapped = _fnRenderer(settings, 'pagingContainer')(
13525			settings, buttonEls
13526		);
13527	
13528		var activeEl = host.find(document.activeElement).data('dt-idx');
13529	
13530		host.empty().append(wrapped);
13531	
13532		if ( activeEl !== undefined ) {
13533			host.find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
13534		}
13535	
13536		// Responsive - check if the buttons are over two lines based on the
13537		// height of the buttons and the container.
13538		if (buttonEls.length) {
13539			var outerHeight = $(buttonEls[0]).outerHeight();
13540		
13541			if (
13542				opts.buttons > 1 && // prevent infinite
13543				outerHeight > 0 && // will be 0 if hidden
13544				$(host).height() >= (outerHeight * 2) - 10
13545			) {
13546				_pagingDraw(settings, host, $.extend({}, opts, { buttons: opts.buttons - 2 }));
13547			}
13548		}
13549	}
13550	
13551	/**
13552	 * Get properties for a button based on the current paging state of the table
13553	 *
13554	 * @param {*} settings DT settings object
13555	 * @param {*} button The button type in question
13556	 * @param {*} page Table's current page
13557	 * @param {*} pages Number of pages
13558	 * @returns Info object
13559	 */
13560	function _pagingButtonInfo(settings, button, page, pages) {
13561		var lang = settings.oLanguage.oPaginate;
13562		var o = {
13563			display: '',
13564			active: false,
13565			disabled: false
13566		};
13567	
13568		switch ( button ) {
13569			case 'ellipsis':
13570				o.display = '&#x2026;';
13571				break;
13572	
13573			case 'first':
13574				o.display = lang.sFirst;
13575	
13576				if (page === 0) {
13577					o.disabled = true;
13578				}
13579				break;
13580	
13581			case 'previous':
13582				o.display = lang.sPrevious;
13583	
13584				if ( page === 0 ) {
13585					o.disabled = true;
13586				}
13587				break;
13588	
13589			case 'next':
13590				o.display = lang.sNext;
13591	
13592				if ( pages === 0 || page === pages-1 ) {
13593					o.disabled = true;
13594				}
13595				break;
13596	
13597			case 'last':
13598				o.display = lang.sLast;
13599	
13600				if ( pages === 0 || page === pages-1 ) {
13601					o.disabled = true;
13602				}
13603				break;
13604	
13605			default:
13606				if ( typeof button === 'number' ) {
13607					o.display = settings.fnFormatNumber( button + 1 );
13608					
13609					if (page === button) {
13610						o.active = true;
13611					}
13612				}
13613				break;
13614		}
13615	
13616		return o;
13617	}
13618	
13619	/**
13620	 * Compute what number buttons to show in the paging control
13621	 *
13622	 * @param {*} page Current page
13623	 * @param {*} pages Total number of pages
13624	 * @param {*} buttons Target number of number buttons
13625	 * @param {boolean} addFirstLast Indicate if page 1 and end should be included
13626	 * @returns Buttons to show
13627	 */
13628	function _pagingNumbers ( page, pages, buttons, addFirstLast ) {
13629		var
13630			numbers = [],
13631			half = Math.floor(buttons / 2),
13632			before = addFirstLast ? 2 : 1,
13633			after = addFirstLast ? 1 : 0;
13634	
13635		if ( pages <= buttons ) {
13636			numbers = _range(0, pages);
13637		}
13638		else if (buttons === 1) {
13639			// Single button - current page only
13640			numbers = [page];
13641		}
13642		else if (buttons === 3) {
13643			// Special logic for just three buttons
13644			if (page <= 1) {
13645				numbers = [0, 1, 'ellipsis'];
13646			}
13647			else if (page >= pages - 2) {
13648				numbers = _range(pages-2, pages);
13649				numbers.unshift('ellipsis');
13650			}
13651			else {
13652				numbers = ['ellipsis', page, 'ellipsis'];
13653			}
13654		}
13655		else if ( page <= half ) {
13656			numbers = _range(0, buttons-before);
13657			numbers.push('ellipsis');
13658	
13659			if (addFirstLast) {
13660				numbers.push(pages-1);
13661			}
13662		}
13663		else if ( page >= pages - 1 - half ) {
13664			numbers = _range(pages-(buttons-before), pages);
13665			numbers.unshift('ellipsis');
13666	
13667			if (addFirstLast) {
13668				numbers.unshift(0);
13669			}
13670		}
13671		else {
13672			numbers = _range(page-half+before, page+half-after);
13673			numbers.push('ellipsis');
13674			numbers.unshift('ellipsis');
13675	
13676			if (addFirstLast) {
13677				numbers.push(pages-1);
13678				numbers.unshift(0);
13679			}
13680		}
13681	
13682		return numbers;
13683	}
13684	
13685	var __lengthCounter = 0;
13686	
13687	// opts
13688	// - menu
13689	// - text
13690	DataTable.feature.register( 'pageLength', function ( settings, opts ) {
13691		var features = settings.oFeatures;
13692	
13693		// For compatibility with the legacy `pageLength` top level option
13694		if (! features.bPaginate || ! features.bLengthChange) {
13695			return null;
13696		}
13697	
13698		opts = $.extend({
13699			menu: settings.aLengthMenu,
13700			text: settings.oLanguage.sLengthMenu
13701		}, opts);
13702	
13703		var
13704			classes  = settings.oClasses.length,
13705			tableId  = settings.sTableId,
13706			menu     = opts.menu,
13707			lengths  = [],
13708			language = [],
13709			i;
13710	
13711		// Options can be given in a number of ways
13712		if (Array.isArray( menu[0] )) {
13713			// Old 1.x style - 2D array
13714			lengths = menu[0];
13715			language = menu[1];
13716		}
13717		else {
13718			for ( i=0 ; i<menu.length ; i++ ) {
13719				// An object with different label and value
13720				if ($.isPlainObject(menu[i])) {
13721					lengths.push(menu[i].value);
13722					language.push(menu[i].label);
13723				}
13724				else {
13725					// Or just a number to display and use
13726					lengths.push(menu[i]);
13727					language.push(menu[i]);
13728				}
13729			}
13730		}
13731	
13732		// We can put the <select> outside of the label if it is at the start or
13733		// end which helps improve accessability (not all screen readers like
13734		// implicit for elements).
13735		var end = opts.text.match(/_MENU_$/);
13736		var start = opts.text.match(/^_MENU_/);
13737		var removed = opts.text.replace(/_MENU_/, '');
13738		var str = '<label>' + opts.text + '</label>';
13739	
13740		if (start) {
13741			str = '_MENU_<label>' + removed + '</label>';
13742		}
13743		else if (end) {
13744			str = '<label>' + removed + '</label>_MENU_';
13745		}
13746	
13747		// Wrapper element - use a span as a holder for where the select will go
13748		var tmpId = 'tmp-' + (+new Date())
13749		var div = $('<div/>')
13750			.addClass( classes.container )
13751			.append(
13752				str.replace( '_MENU_', '<span id="'+tmpId+'"></span>' )
13753			);
13754	
13755		// Save text node content for macro updating
13756		var textNodes = [];
13757		Array.prototype.slice.call(div.find('label')[0].childNodes).forEach(function (el) {
13758			if (el.nodeType === Node.TEXT_NODE) {
13759				textNodes.push({
13760					el: el,
13761					text: el.textContent
13762				});
13763			}
13764		});
13765	
13766		// Update the label text in case it has an entries value
13767		var updateEntries = function (len) {
13768			textNodes.forEach(function (node) {
13769				node.el.textContent = _fnMacros(settings, node.text, len);
13770			});
13771		}
13772	
13773		// Next, the select itself, along with the options
13774		var select = $('<select/>', {
13775			'aria-controls': tableId,
13776			'class':         classes.select
13777		} );
13778	
13779		for ( i=0 ; i<lengths.length ; i++ ) {
13780			select[0][ i ] = new Option(
13781				typeof language[i] === 'number' ?
13782					settings.fnFormatNumber( language[i] ) :
13783					language[i],
13784				lengths[i]
13785			);
13786		}
13787	
13788		// add for and id to label and input
13789		div.find('label').attr('for', 'dt-length-' + __lengthCounter);
13790		select.attr('id', 'dt-length-' + __lengthCounter);
13791		__lengthCounter++;
13792	
13793		// Swap in the select list
13794		div.find('#' + tmpId).replaceWith(select);
13795	
13796		// Can't use `select` variable as user might provide their own and the
13797		// reference is broken by the use of outerHTML
13798		$('select', div)
13799			.val( settings._iDisplayLength )
13800			.on( 'change.DT', function() {
13801				_fnLengthChange( settings, $(this).val() );
13802				_fnDraw( settings );
13803			} );
13804	
13805		// Update node value whenever anything changes the table's length
13806		$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
13807			if ( settings === s ) {
13808				$('select', div).val( len );
13809	
13810				// Resolve plurals in the text for the new length
13811				updateEntries(len);
13812			}
13813		} );
13814	
13815		updateEntries(settings._iDisplayLength);
13816	
13817		return div;
13818	}, 'l' );
13819	
13820	// jQuery access
13821	$.fn.dataTable = DataTable;
13822	
13823	// Provide access to the host jQuery object (circular reference)
13824	DataTable.$ = $;
13825	
13826	// Legacy aliases
13827	$.fn.dataTableSettings = DataTable.settings;
13828	$.fn.dataTableExt = DataTable.ext;
13829	
13830	// With a capital `D` we return a DataTables API instance rather than a
13831	// jQuery object
13832	$.fn.DataTable = function ( opts ) {
13833		return $(this).dataTable( opts ).api();
13834	};
13835	
13836	// All properties that are available to $.fn.dataTable should also be
13837	// available on $.fn.DataTable
13838	$.each( DataTable, function ( prop, val ) {
13839		$.fn.DataTable[ prop ] = val;
13840	} );
13841
13842	return DataTable;
13843}));

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