PageSourceSearch

https://silencedturkey.org/wp-content/themes/silencedturkey/assets/js/datatables.js

js silencedturkey.org collected 2026-09-24 11:32:50 UTC 390,181 bytes, 14,053 lines download raw bytes

1/*! DataTables 2.3.1
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			// Sanity check
93			if ( this.nodeName.toLowerCase() != 'table' )
94			{
95				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
96				return;
97			}
98			
99			// Special case for options
100			if (oInit.on && oInit.on.options) {
101				_fnListener($this, 'options', oInit.on.options);	
102			}
103			
104			$this.trigger( 'options.dt', oInit );
105			
106			/* Backwards compatibility for the defaults */
107			_fnCompatOpts( defaults );
108			_fnCompatCols( defaults.column );
109			
110			/* Convert the camel-case defaults to Hungarian */
111			_fnCamelToHungarian( defaults, defaults, true );
112			_fnCamelToHungarian( defaults.column, defaults.column, true );
113			
114			/* Setting up the initialisation object */
115			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
116			
117			
118			
119			/* Check to see if we are re-initialising a table */
120			var allSettings = DataTable.settings;
121			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
122			{
123				var s = allSettings[i];
124			
125				/* Base check on table node */
126				if (
127					s.nTable == this ||
128					(s.nTHead && s.nTHead.parentNode == this) ||
129					(s.nTFoot && s.nTFoot.parentNode == this)
130				) {
131					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
132					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
133			
134					if ( emptyInit || bRetrieve )
135					{
136						return s.oInstance;
137					}
138					else if ( bDestroy )
139					{
140						new DataTable.Api(s).destroy();
141						break;
142					}
143					else
144					{
145						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
146						return;
147					}
148				}
149			
150				/* If the element we are initialising has the same ID as a table which was previously
151				 * initialised, but the table nodes don't match (from before) then we destroy the old
152				 * instance by simply deleting it. This is under the assumption that the table has been
153				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
154				 */
155				if ( s.sTableId == this.id )
156				{
157					allSettings.splice( i, 1 );
158					break;
159				}
160			}
161			
162			/* Ensure the table has an ID - required for accessibility */
163			if ( sId === null || sId === "" )
164			{
165				sId = "DataTables_Table_"+(DataTable.ext._unique++);
166				this.id = sId;
167			}
168			
169			/* Create the settings object for this table and set some of the default parameters */
170			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
171				"sDestroyWidth": $this[0].style.width,
172				"sInstance":     sId,
173				"sTableId":      sId,
174				colgroup: $('<colgroup>').prependTo(this),
175				fastData: function (row, column, type) {
176					return _fnGetCellData(oSettings, row, column, type);
177				}
178			} );
179			oSettings.nTable = this;
180			oSettings.oInit  = oInit;
181			
182			allSettings.push( oSettings );
183			
184			// Make a single API instance available for internal handling
185			oSettings.api = new _Api( oSettings );
186			
187			// Need to add the instance after the instance after the settings object has been added
188			// to the settings array, so we can self reference the table instance if more than one
189			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
190			
191			// Backwards compatibility, before we apply all the defaults
192			_fnCompatOpts( oInit );
193			
194			// If the length menu is given, but the init display length is not, use the length menu
195			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
196			{
197				oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
198					? oInit.aLengthMenu[0][0]
199					: $.isPlainObject( oInit.aLengthMenu[0] )
200						? oInit.aLengthMenu[0].value
201						: oInit.aLengthMenu[0];
202			}
203			
204			// Apply the defaults and init options to make a single init object will all
205			// options defined from defaults and instance options.
206			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
207			
208			
209			// Map the initialisation options onto the settings object
210			_fnMap( oSettings.oFeatures, oInit, [
211				"bPaginate",
212				"bLengthChange",
213				"bFilter",
214				"bSort",
215				"bSortMulti",
216				"bInfo",
217				"bProcessing",
218				"bAutoWidth",
219				"bSortClasses",
220				"bServerSide",
221				"bDeferRender"
222			] );
223			_fnMap( oSettings, oInit, [
224				"ajax",
225				"fnFormatNumber",
226				"sServerMethod",
227				"aaSorting",
228				"aaSortingFixed",
229				"aLengthMenu",
230				"sPaginationType",
231				"iStateDuration",
232				"bSortCellsTop",
233				"iTabIndex",
234				"sDom",
235				"fnStateLoadCallback",
236				"fnStateSaveCallback",
237				"renderer",
238				"searchDelay",
239				"rowId",
240				"caption",
241				"layout",
242				"orderDescReverse",
243				"orderIndicators",
244				"orderHandler",
245				"titleRow",
246				"typeDetect",
247				[ "iCookieDuration", "iStateDuration" ], // backwards compat
248				[ "oSearch", "oPreviousSearch" ],
249				[ "aoSearchCols", "aoPreSearchCols" ],
250				[ "iDisplayLength", "_iDisplayLength" ]
251			] );
252			_fnMap( oSettings.oScroll, oInit, [
253				[ "sScrollX", "sX" ],
254				[ "sScrollXInner", "sXInner" ],
255				[ "sScrollY", "sY" ],
256				[ "bScrollCollapse", "bCollapse" ]
257			] );
258			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
259			
260			/* Callback functions which are array driven */
261			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback );
262			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams );
263			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams );
264			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded );
265			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback );
266			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
267			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback );
268			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback );
269			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete );
270			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback );
271			
272			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
273			
274			// Add event listeners
275			if (oInit.on) {
276				Object.keys(oInit.on).forEach(function (key) {
277					_fnListener($this, key, oInit.on[key]);
278				});
279			}
280			
281			/* Browser support detection */
282			_fnBrowserDetect( oSettings );
283			
284			var oClasses = oSettings.oClasses;
285			
286			$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
287			$this.addClass( oClasses.table );
288			
289			if (! oSettings.oFeatures.bPaginate) {
290				oInit.iDisplayStart = 0;
291			}
292			
293			if ( oSettings.iInitDisplayStart === undefined )
294			{
295				/* Display start point, taking into account the save saving */
296				oSettings.iInitDisplayStart = oInit.iDisplayStart;
297				oSettings._iDisplayStart = oInit.iDisplayStart;
298			}
299			
300			var defer = oInit.iDeferLoading;
301			if ( defer !== null )
302			{
303				oSettings.deferLoading = true;
304			
305				var tmp = Array.isArray(defer);
306				oSettings._iRecordsDisplay = tmp ? defer[0] : defer;
307				oSettings._iRecordsTotal = tmp ? defer[1] : defer;
308			}
309			
310			/*
311			 * Columns
312			 * See if we should load columns automatically or use defined ones
313			 */
314			var columnsInit = [];
315			var thead = this.getElementsByTagName('thead');
316			var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
317			
318			// If we don't have a columns array, then generate one with nulls
319			if ( oInit.aoColumns ) {
320				columnsInit = oInit.aoColumns;
321			}
322			else if ( initHeaderLayout.length ) {
323				for ( i=0, iLen=initHeaderLayout[0].length ; i<iLen ; i++ ) {
324					columnsInit.push( null );
325				}
326			}
327			
328			// Add the columns
329			for ( i=0, iLen=columnsInit.length ; i<iLen ; i++ ) {
330				_fnAddColumn( oSettings );
331			}
332			
333			// Apply the column definitions
334			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
335				_fnColumnOptions( oSettings, iCol, oDef );
336			} );
337			
338			/* HTML5 attribute detection - build an mData object automatically if the
339			 * attributes are found
340			 */
341			var rowOne = $this.children('tbody').find('tr:first-child').eq(0);
342			
343			if ( rowOne.length ) {
344				var a = function ( cell, name ) {
345					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
346				};
347			
348				$( rowOne[0] ).children('th, td').each( function (i, cell) {
349					var col = oSettings.aoColumns[i];
350			
351					if (! col) {
352						_fnLog( oSettings, 0, 'Incorrect column count', 18 );
353					}
354			
355					if ( col.mData === i ) {
356						var sort = a( cell, 'sort' ) || a( cell, 'order' );
357						var filter = a( cell, 'filter' ) || a( cell, 'search' );
358			
359						if ( sort !== null || filter !== null ) {
360							col.mData = {
361								_:      i+'.display',
362								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
363								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
364								filter: filter !== null ? i+'.@data-'+filter : undefined
365							};
366							col._isArrayHost = true;
367			
368							_fnColumnOptions( oSettings, i );
369						}
370					}
371				} );
372			}
373			
374			// Must be done after everything which can be overridden by the state saving!
375			_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState );
376			
377			var features = oSettings.oFeatures;
378			if ( oInit.bStateSave )
379			{
380				features.bStateSave = true;
381			}
382			
383			// If aaSorting is not defined, then we use the first indicator in asSorting
384			// in case that has been altered, so the default sort reflects that option
385			if ( oInit.aaSorting === undefined ) {
386				var sorting = oSettings.aaSorting;
387				for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
388					sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
389				}
390			}
391			
392			// Do a first pass on the sorting classes (allows any size changes to be taken into
393			// account, and also will apply sorting disabled classes if disabled
394			_fnSortingClasses( oSettings );
395			
396			_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
397				if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
398					_fnSortingClasses( oSettings );
399				}
400			} );
401			
402			
403			/*
404			 * Table HTML init
405			 * Cache the header, body and footer as required, creating them if needed
406			 */
407			var caption = $this.children('caption');
408			
409			if ( oSettings.caption ) {
410				if ( caption.length === 0 ) {
411					caption = $('<caption/>').appendTo( $this );
412				}
413			
414				caption.html( oSettings.caption );
415			}
416			
417			// Store the caption side, so we can remove the element from the document
418			// when creating the element
419			if (caption.length) {
420				caption[0]._captionSide = caption.css('caption-side');
421				oSettings.captionNode = caption[0];
422			}
423			
424			if ( thead.length === 0 ) {
425				thead = $('<thead/>').appendTo($this);
426			}
427			oSettings.nTHead = thead[0];
428			
429			var tbody = $this.children('tbody');
430			if ( tbody.length === 0 ) {
431				tbody = $('<tbody/>').insertAfter(thead);
432			}
433			oSettings.nTBody = tbody[0];
434			
435			var tfoot = $this.children('tfoot');
436			if ( tfoot.length === 0 ) {
437				// If we are a scrolling table, and no footer has been given, then we need to create
438				// a tfoot element for the caption element to be appended to
439				tfoot = $('<tfoot/>').appendTo($this);
440			}
441			oSettings.nTFoot = tfoot[0];
442			
443			// Copy the data index array
444			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
445			
446			// Initialisation complete - table can be drawn
447			oSettings.bInitialised = true;
448			
449			// Language definitions
450			var oLanguage = oSettings.oLanguage;
451			$.extend( true, oLanguage, oInit.oLanguage );
452			
453			if ( oLanguage.sUrl ) {
454				// Get the language definitions from a file
455				$.ajax( {
456					dataType: 'json',
457					url: oLanguage.sUrl,
458					success: function ( json ) {
459						_fnCamelToHungarian( defaults.oLanguage, json );
460						$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
461			
462						_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
463						_fnInitialise( oSettings );
464					},
465					error: function () {
466						// Error occurred loading language file
467						_fnLog( oSettings, 0, 'i18n file loading error', 21 );
468			
469						// Continue on as best we can
470						_fnInitialise( oSettings );
471					}
472				} );
473			}
474			else {
475				_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
476				_fnInitialise( oSettings );
477			}
478		} );
479		_that = null;
480		return this;
481	};
482	
483	
484	
485	/**
486	 * DataTables extensions
487	 * 
488	 * This namespace acts as a collection area for plug-ins that can be used to
489	 * extend DataTables capabilities. Indeed many of the build in methods
490	 * use this method to provide their own capabilities (sorting methods for
491	 * example).
492	 *
493	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
494	 * reasons
495	 *
496	 *  @namespace
497	 */
498	DataTable.ext = _ext = {
499		/**
500		 * DataTables build type (expanded by the download builder)
501		 *
502		 *  @type string
503		 */
504		builder: "-source-",
505	
506		/**
507		 * Buttons. For use with the Buttons extension for DataTables. This is
508		 * defined here so other extensions can define buttons regardless of load
509		 * order. It is _not_ used by DataTables core.
510		 *
511		 *  @type object
512		 *  @default {}
513		 */
514		buttons: {},
515	
516	
517		/**
518		 * ColumnControl buttons and content
519		 *
520		 *  @type object
521		 */
522		ccContent: {},
523	
524	
525		/**
526		 * Element class names
527		 *
528		 *  @type object
529		 *  @default {}
530		 */
531		classes: {},
532	
533	
534		/**
535		 * Error reporting.
536		 * 
537		 * How should DataTables report an error. Can take the value 'alert',
538		 * 'throw', 'none' or a function.
539		 *
540		 *  @type string|function
541		 *  @default alert
542		 */
543		errMode: "alert",
544	
545	
546		/**
547		 * Legacy so v1 plug-ins don't throw js errors on load
548		 */
549		feature: [],
550	
551		/**
552		 * Feature plug-ins.
553		 * 
554		 * This is an object of callbacks which provide the features for DataTables
555		 * to be initialised via the `layout` option.
556		 */
557		features: {},
558	
559	
560		/**
561		 * Row searching.
562		 * 
563		 * This method of searching is complimentary to the default type based
564		 * searching, and a lot more comprehensive as it allows you complete control
565		 * over the searching logic. Each element in this array is a function
566		 * (parameters described below) that is called for every row in the table,
567		 * and your logic decides if it should be included in the searching data set
568		 * or not.
569		 *
570		 * Searching functions have the following input parameters:
571		 *
572		 * 1. `{object}` DataTables settings object: see
573		 *    {@link DataTable.models.oSettings}
574		 * 2. `{array|object}` Data for the row to be processed (same as the
575		 *    original format that was passed in as the data source, or an array
576		 *    from a DOM data source
577		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
578		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
579		 *
580		 * And the following return is expected:
581		 *
582		 * * {boolean} Include the row in the searched result set (true) or not
583		 *   (false)
584		 *
585		 * Note that as with the main search ability in DataTables, technically this
586		 * is "filtering", since it is subtractive. However, for consistency in
587		 * naming we call it searching here.
588		 *
589		 *  @type array
590		 *  @default []
591		 *
592		 *  @example
593		 *    // The following example shows custom search being applied to the
594		 *    // fourth column (i.e. the data[3] index) based on two input values
595		 *    // from the end-user, matching the data in a certain range.
596		 *    $.fn.dataTable.ext.search.push(
597		 *      function( settings, data, dataIndex ) {
598		 *        var min = document.getElementById('min').value * 1;
599		 *        var max = document.getElementById('max').value * 1;
600		 *        var version = data[3] == "-" ? 0 : data[3]*1;
601		 *
602		 *        if ( min == "" && max == "" ) {
603		 *          return true;
604		 *        }
605		 *        else if ( min == "" && version < max ) {
606		 *          return true;
607		 *        }
608		 *        else if ( min < version && "" == max ) {
609		 *          return true;
610		 *        }
611		 *        else if ( min < version && version < max ) {
612		 *          return true;
613		 *        }
614		 *        return false;
615		 *      }
616		 *    );
617		 */
618		search: [],
619	
620	
621		/**
622		 * Selector extensions
623		 *
624		 * The `selector` option can be used to extend the options available for the
625		 * selector modifier options (`selector-modifier` object data type) that
626		 * each of the three built in selector types offer (row, column and cell +
627		 * their plural counterparts). For example the Select extension uses this
628		 * mechanism to provide an option to select only rows, columns and cells
629		 * that have been marked as selected by the end user (`{selected: true}`),
630		 * which can be used in conjunction with the existing built in selector
631		 * options.
632		 *
633		 * Each property is an array to which functions can be pushed. The functions
634		 * take three attributes:
635		 *
636		 * * Settings object for the host table
637		 * * Options object (`selector-modifier` object type)
638		 * * Array of selected item indexes
639		 *
640		 * The return is an array of the resulting item indexes after the custom
641		 * selector has been applied.
642		 *
643		 *  @type object
644		 */
645		selector: {
646			cell: [],
647			column: [],
648			row: []
649		},
650	
651	
652		/**
653		 * Legacy configuration options. Enable and disable legacy options that
654		 * are available in DataTables.
655		 *
656		 *  @type object
657		 */
658		legacy: {
659			/**
660			 * Enable / disable DataTables 1.9 compatible server-side processing
661			 * requests
662			 *
663			 *  @type boolean
664			 *  @default null
665			 */
666			ajax: null
667		},
668	
669	
670		/**
671		 * Pagination plug-in methods.
672		 * 
673		 * Each entry in this object is a function and defines which buttons should
674		 * be shown by the pagination rendering method that is used for the table:
675		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
676		 * buttons are displayed in the document, while the functions here tell it
677		 * what buttons to display. This is done by returning an array of button
678		 * descriptions (what each button will do).
679		 *
680		 * Pagination types (the four built in options and any additional plug-in
681		 * options defined here) can be used through the `paginationType`
682		 * initialisation parameter.
683		 *
684		 * The functions defined take two parameters:
685		 *
686		 * 1. `{int} page` The current page index
687		 * 2. `{int} pages` The number of pages in the table
688		 *
689		 * Each function is expected to return an array where each element of the
690		 * array can be one of:
691		 *
692		 * * `first` - Jump to first page when activated
693		 * * `last` - Jump to last page when activated
694		 * * `previous` - Show previous page when activated
695		 * * `next` - Show next page when activated
696		 * * `{int}` - Show page of the index given
697		 * * `{array}` - A nested array containing the above elements to add a
698		 *   containing 'DIV' element (might be useful for styling).
699		 *
700		 * Note that DataTables v1.9- used this object slightly differently whereby
701		 * an object with two functions would be defined for each plug-in. That
702		 * ability is still supported by DataTables 1.10+ to provide backwards
703		 * compatibility, but this option of use is now decremented and no longer
704		 * documented in DataTables 1.10+.
705		 *
706		 *  @type object
707		 *  @default {}
708		 *
709		 *  @example
710		 *    // Show previous, next and current page buttons only
711		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
712		 *      return [ 'previous', page, 'next' ];
713		 *    };
714		 */
715		pager: {},
716	
717	
718		renderer: {
719			pageButton: {},
720			header: {}
721		},
722	
723	
724		/**
725		 * Ordering plug-ins - custom data source
726		 * 
727		 * The extension options for ordering of data available here is complimentary
728		 * to the default type based ordering that DataTables typically uses. It
729		 * allows much greater control over the the data that is being used to
730		 * order a column, but is necessarily therefore more complex.
731		 * 
732		 * This type of ordering is useful if you want to do ordering based on data
733		 * live from the DOM (for example the contents of an 'input' element) rather
734		 * than just the static string that DataTables knows of.
735		 * 
736		 * The way these plug-ins work is that you create an array of the values you
737		 * wish to be ordering for the column in question and then return that
738		 * array. The data in the array much be in the index order of the rows in
739		 * the table (not the currently ordering order!). Which order data gathering
740		 * function is run here depends on the `dt-init columns.orderDataType`
741		 * parameter that is used for the column (if any).
742		 *
743		 * The functions defined take two parameters:
744		 *
745		 * 1. `{object}` DataTables settings object: see
746		 *    {@link DataTable.models.oSettings}
747		 * 2. `{int}` Target column index
748		 *
749		 * Each function is expected to return an array:
750		 *
751		 * * `{array}` Data for the column to be ordering upon
752		 *
753		 *  @type array
754		 *
755		 *  @example
756		 *    // Ordering using `input` node values
757		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
758		 *    {
759		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
760		 *        return $('input', td).val();
761		 *      } );
762		 *    }
763		 */
764		order: {},
765	
766	
767		/**
768		 * Type based plug-ins.
769		 *
770		 * Each column in DataTables has a type assigned to it, either by automatic
771		 * detection or by direct assignment using the `type` option for the column.
772		 * The type of a column will effect how it is ordering and search (plug-ins
773		 * can also make use of the column type if required).
774		 *
775		 * @namespace
776		 */
777		type: {
778			/**
779			 * Automatic column class assignment
780			 */
781			className: {},
782	
783			/**
784			 * Type detection functions.
785			 *
786			 * The functions defined in this object are used to automatically detect
787			 * a column's type, making initialisation of DataTables super easy, even
788			 * when complex data is in the table.
789			 *
790			 * The functions defined take two parameters:
791			 *
792		     *  1. `{*}` Data from the column cell to be analysed
793		     *  2. `{settings}` DataTables settings object. This can be used to
794		     *     perform context specific type detection - for example detection
795		     *     based on language settings such as using a comma for a decimal
796		     *     place. Generally speaking the options from the settings will not
797		     *     be required
798			 *
799			 * Each function is expected to return:
800			 *
801			 * * `{string|null}` Data type detected, or null if unknown (and thus
802			 *   pass it on to the other type detection functions.
803			 *
804			 *  @type array
805			 *
806			 *  @example
807			 *    // Currency type detection plug-in:
808			 *    $.fn.dataTable.ext.type.detect.push(
809			 *      function ( data, settings ) {
810			 *        // Check the numeric part
811			 *        if ( ! data.substring(1).match(/[0-9]/) ) {
812			 *          return null;
813			 *        }
814			 *
815			 *        // Check prefixed by currency
816			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
817			 *          return 'currency';
818			 *        }
819			 *        return null;
820			 *      }
821			 *    );
822			 */
823			detect: [],
824	
825			/**
826			 * Automatic renderer assignment
827			 */
828			render: {},
829	
830	
831			/**
832			 * Type based search formatting.
833			 *
834			 * The type based searching functions can be used to pre-format the
835			 * data to be search on. For example, it can be used to strip HTML
836			 * tags or to de-format telephone numbers for numeric only searching.
837			 *
838			 * Note that is a search is not defined for a column of a given type,
839			 * no search formatting will be performed.
840			 * 
841			 * Pre-processing of searching data plug-ins - When you assign the sType
842			 * for a column (or have it automatically detected for you by DataTables
843			 * or a type detection plug-in), you will typically be using this for
844			 * custom sorting, but it can also be used to provide custom searching
845			 * by allowing you to pre-processing the data and returning the data in
846			 * the format that should be searched upon. This is done by adding
847			 * functions this object with a parameter name which matches the sType
848			 * for that target column. This is the corollary of <i>afnSortData</i>
849			 * for searching data.
850			 *
851			 * The functions defined take a single parameter:
852			 *
853		     *  1. `{*}` Data from the column cell to be prepared for searching
854			 *
855			 * Each function is expected to return:
856			 *
857			 * * `{string|null}` Formatted string that will be used for the searching.
858			 *
859			 *  @type object
860			 *  @default {}
861			 *
862			 *  @example
863			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
864			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
865			 *    }
866			 */
867			search: {},
868	
869	
870			/**
871			 * Type based ordering.
872			 *
873			 * The column type tells DataTables what ordering to apply to the table
874			 * when a column is sorted upon. The order for each type that is defined,
875			 * is defined by the functions available in this object.
876			 *
877			 * Each ordering option can be described by three properties added to
878			 * this object:
879			 *
880			 * * `{type}-pre` - Pre-formatting function
881			 * * `{type}-asc` - Ascending order function
882			 * * `{type}-desc` - Descending order function
883			 *
884			 * All three can be used together, only `{type}-pre` or only
885			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
886			 * that only `{type}-pre` is used, as this provides the optimal
887			 * implementation in terms of speed, although the others are provided
888			 * for compatibility with existing Javascript sort functions.
889			 *
890			 * `{type}-pre`: Functions defined take a single parameter:
891			 *
892		     *  1. `{*}` Data from the column cell to be prepared for ordering
893			 *
894			 * And return:
895			 *
896			 * * `{*}` Data to be sorted upon
897			 *
898			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
899			 * functions, taking two parameters:
900			 *
901		     *  1. `{*}` Data to compare to the second parameter
902		     *  2. `{*}` Data to compare to the first parameter
903			 *
904			 * And returning:
905			 *
906			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
907			 *   than the second parameter, ===0 if the two parameters are equal and
908			 *   >0 if the first parameter should be sorted height than the second
909			 *   parameter.
910			 * 
911			 *  @type object
912			 *  @default {}
913			 *
914			 *  @example
915			 *    // Numeric ordering of formatted numbers with a pre-formatter
916			 *    $.extend( $.fn.dataTable.ext.type.order, {
917			 *      "string-pre": function(x) {
918			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
919			 *        return parseFloat( a );
920			 *      }
921			 *    } );
922			 *
923			 *  @example
924			 *    // Case-sensitive string ordering, with no pre-formatting method
925			 *    $.extend( $.fn.dataTable.ext.order, {
926			 *      "string-case-asc": function(x,y) {
927			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
928			 *      },
929			 *      "string-case-desc": function(x,y) {
930			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
931			 *      }
932			 *    } );
933			 */
934			order: {}
935		},
936	
937		/**
938		 * Unique DataTables instance counter
939		 *
940		 * @type int
941		 * @private
942		 */
943		_unique: 0,
944	
945	
946		//
947		// Depreciated
948		// The following properties are retained for backwards compatibility only.
949		// The should not be used in new projects and will be removed in a future
950		// version
951		//
952	
953		/**
954		 * Version check function.
955		 *  @type function
956		 *  @depreciated Since 1.10
957		 */
958		fnVersionCheck: DataTable.fnVersionCheck,
959	
960	
961		/**
962		 * Index for what 'this' index API functions should use
963		 *  @type int
964		 *  @deprecated Since v1.10
965		 */
966		iApiIndex: 0,
967	
968	
969		/**
970		 * Software version
971		 *  @type string
972		 *  @deprecated Since v1.10
973		 */
974		sVersion: DataTable.version
975	};
976	
977	
978	//
979	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
980	//
981	$.extend( _ext, {
982		afnFiltering: _ext.search,
983		aTypes:       _ext.type.detect,
984		ofnSearch:    _ext.type.search,
985		oSort:        _ext.type.order,
986		afnSortData:  _ext.order,
987		aoFeatures:   _ext.feature,
988		oStdClasses:  _ext.classes,
989		oPagination:  _ext.pager
990	} );
991	
992	
993	$.extend( DataTable.ext.classes, {
994		container: 'dt-container',
995		empty: {
996			row: 'dt-empty'
997		},
998		info: {
999			container: 'dt-info'
1000		},
1001		layout: {
1002			row: 'dt-layout-row',
1003			cell: 'dt-layout-cell',
1004			tableRow: 'dt-layout-table',
1005			tableCell: '',
1006			start: 'dt-layout-start',
1007			end: 'dt-layout-end',
1008			full: 'dt-layout-full'
1009		},
1010		length: {
1011			container: 'dt-length',
1012			select: 'dt-input'
1013		},
1014		order: {
1015			canAsc: 'dt-orderable-asc',
1016			canDesc: 'dt-orderable-desc',
1017			isAsc: 'dt-ordering-asc',
1018			isDesc: 'dt-ordering-desc',
1019			none: 'dt-orderable-none',
1020			position: 'sorting_'
1021		},
1022		processing: {
1023			container: 'dt-processing'
1024		},
1025		scrolling: {
1026			body: 'dt-scroll-body',
1027			container: 'dt-scroll',
1028			footer: {
1029				self: 'dt-scroll-foot',
1030				inner: 'dt-scroll-footInner'
1031			},
1032			header: {
1033				self: 'dt-scroll-head',
1034				inner: 'dt-scroll-headInner'
1035			}
1036		},
1037		search: {
1038			container: 'dt-search',
1039			input: 'dt-input'
1040		},
1041		table: 'dataTable',	
1042		tbody: {
1043			cell: '',
1044			row: ''
1045		},
1046		thead: {
1047			cell: '',
1048			row: ''
1049		},
1050		tfoot: {
1051			cell: '',
1052			row: ''
1053		},
1054		paging: {
1055			active: 'current',
1056			button: 'dt-paging-button',
1057			container: 'dt-paging',
1058			disabled: 'disabled',
1059			nav: ''
1060		}
1061	} );
1062	
1063	
1064	/*
1065	 * It is useful to have variables which are scoped locally so only the
1066	 * DataTables functions can access them and they don't leak into global space.
1067	 * At the same time these functions are often useful over multiple files in the
1068	 * core and API, so we list, or at least document, all variables which are used
1069	 * by DataTables as private variables here. This also ensures that there is no
1070	 * clashing of variable names and that they can easily referenced for reuse.
1071	 */
1072	
1073	
1074	// Defined else where
1075	//  _selector_run
1076	//  _selector_opts
1077	//  _selector_row_indexes
1078	
1079	var _ext; // DataTable.ext
1080	var _Api; // DataTable.Api
1081	var _api_register; // DataTable.Api.register
1082	var _api_registerPlural; // DataTable.Api.registerPlural
1083	
1084	var _re_dic = {};
1085	var _re_new_lines = /[\r\n\u2028]/g;
1086	var _re_html = /<([^>]*>)/g;
1087	var _max_str_len = Math.pow(2, 28);
1088	
1089	// This is not strict ISO8601 - Date.parse() is quite lax, although
1090	// implementations differ between browsers.
1091	var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
1092	
1093	// Escape regular expression special characters
1094	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1095	
1096	// https://en.wikipedia.org/wiki/Foreign_exchange_market
1097	// - \u20BD - Russian ruble.
1098	// - \u20a9 - South Korean Won
1099	// - \u20BA - Turkish Lira
1100	// - \u20B9 - Indian Rupee
1101	// - R - Brazil (R$) and South Africa
1102	// - fr - Swiss Franc
1103	// - kr - Swedish krona, Norwegian krone and Danish krone
1104	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1105	// - Ƀ - Bitcoin
1106	// - Ξ - Ethereum
1107	//   standards as thousands separators.
1108	var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1109	
1110	
1111	var _empty = function ( d ) {
1112		return !d || d === true || d === '-' ? true : false;
1113	};
1114	
1115	
1116	var _intVal = function ( s ) {
1117		var integer = parseInt( s, 10 );
1118		return !isNaN(integer) && isFinite(s) ? integer : null;
1119	};
1120	
1121	// Convert from a formatted number with characters other than `.` as the
1122	// decimal place, to a Javascript number
1123	var _numToDecimal = function ( num, decimalPoint ) {
1124		// Cache created regular expressions for speed as this function is called often
1125		if ( ! _re_dic[ decimalPoint ] ) {
1126			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1127		}
1128		return typeof num === 'string' && decimalPoint !== '.' ?
1129			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1130			num;
1131	};
1132	
1133	
1134	var _isNumber = function ( d, decimalPoint, formatted, allowEmpty ) {
1135		var type = typeof d;
1136		var strType = type === 'string';
1137	
1138		if ( type === 'number' || type === 'bigint') {
1139			return true;
1140		}
1141	
1142		// If empty return immediately so there must be a number if it is a
1143		// formatted string (this stops the string "k", or "kr", etc being detected
1144		// as a formatted number for currency
1145		if ( allowEmpty && _empty( d ) ) {
1146			return true;
1147		}
1148	
1149		if ( decimalPoint && strType ) {
1150			d = _numToDecimal( d, decimalPoint );
1151		}
1152	
1153		if ( formatted && strType ) {
1154			d = d.replace( _re_formatted_numeric, '' );
1155		}
1156	
1157		return !isNaN( parseFloat(d) ) && isFinite( d );
1158	};
1159	
1160	
1161	// A string without HTML in it can be considered to be HTML still
1162	var _isHtml = function ( d ) {
1163		return _empty( d ) || typeof d === 'string';
1164	};
1165	
1166	// Is a string a number surrounded by HTML?
1167	var _htmlNumeric = function ( d, decimalPoint, formatted, allowEmpty ) {
1168		if ( allowEmpty && _empty( d ) ) {
1169			return true;
1170		}
1171	
1172		// input and select strings mean that this isn't just a number
1173		if (typeof d === 'string' && d.match(/<(input|select)/i)) {
1174			return null;
1175		}
1176	
1177		var html = _isHtml( d );
1178		return ! html ?
1179			null :
1180			_isNumber( _stripHtml( d ), decimalPoint, formatted, allowEmpty ) ?
1181				true :
1182				null;
1183	};
1184	
1185	
1186	var _pluck = function ( a, prop, prop2 ) {
1187		var out = [];
1188		var i=0, ien=a.length;
1189	
1190		// Could have the test in the loop for slightly smaller code, but speed
1191		// is essential here
1192		if ( prop2 !== undefined ) {
1193			for ( ; i<ien ; i++ ) {
1194				if ( a[i] && a[i][ prop ] ) {
1195					out.push( a[i][ prop ][ prop2 ] );
1196				}
1197			}
1198		}
1199		else {
1200			for ( ; i<ien ; i++ ) {
1201				if ( a[i] ) {
1202					out.push( a[i][ prop ] );
1203				}
1204			}
1205		}
1206	
1207		return out;
1208	};
1209	
1210	
1211	// Basically the same as _pluck, but rather than looping over `a` we use `order`
1212	// as the indexes to pick from `a`
1213	var _pluck_order = function ( a, order, prop, prop2 )
1214	{
1215		var out = [];
1216		var i=0, ien=order.length;
1217	
1218		// Could have the test in the loop for slightly smaller code, but speed
1219		// is essential here
1220		if ( prop2 !== undefined ) {
1221			for ( ; i<ien ; i++ ) {
1222				if ( a[ order[i] ] && a[ order[i] ][ prop ] ) {
1223					out.push( a[ order[i] ][ prop ][ prop2 ] );
1224				}
1225			}
1226		}
1227		else {
1228			for ( ; i<ien ; i++ ) {
1229				if ( a[ order[i] ] ) {
1230					out.push( a[ order[i] ][ prop ] );
1231				}
1232			}
1233		}
1234	
1235		return out;
1236	};
1237	
1238	
1239	var _range = function ( len, start )
1240	{
1241		var out = [];
1242		var end;
1243	
1244		if ( start === undefined ) {
1245			start = 0;
1246			end = len;
1247		}
1248		else {
1249			end = start;
1250			start = len;
1251		}
1252	
1253		for ( var i=start ; i<end ; i++ ) {
1254			out.push( i );
1255		}
1256	
1257		return out;
1258	};
1259	
1260	
1261	var _removeEmpty = function ( a )
1262	{
1263		var out = [];
1264	
1265		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1266			if ( a[i] ) { // careful - will remove all falsy values!
1267				out.push( a[i] );
1268			}
1269		}
1270	
1271		return out;
1272	};
1273	
1274	// Replaceable function in api.util
1275	var _stripHtml = function (input) {
1276		if (! input || typeof input !== 'string') {
1277			return input;
1278		}
1279	
1280		// Irrelevant check to workaround CodeQL's false positive on the regex
1281		if (input.length > _max_str_len) {
1282			throw new Error('Exceeded max str len');
1283		}
1284	
1285		var previous;
1286	
1287		input = input.replace(_re_html, ''); // Complete tags
1288	
1289		// Safety for incomplete script tag - use do / while to ensure that
1290		// we get all instances
1291		do {
1292			previous = input;
1293			input = input.replace(/<script/i, '');
1294		} while (input !== previous);
1295	
1296		return previous;
1297	};
1298	
1299	// Replaceable function in api.util
1300	var _escapeHtml = function ( d ) {
1301		if (Array.isArray(d)) {
1302			d = d.join(',');
1303		}
1304	
1305		return typeof d === 'string' ?
1306			d
1307				.replace(/&/g, '&amp;')
1308				.replace(/</g, '&lt;')
1309				.replace(/>/g, '&gt;')
1310				.replace(/"/g, '&quot;') :
1311			d;
1312	};
1313	
1314	// Remove diacritics from a string by decomposing it and then removing
1315	// non-ascii characters
1316	var _normalize = function (str, both) {
1317		if (typeof str !== 'string') {
1318			return str;
1319		}
1320	
1321		// It is faster to just run `normalize` than it is to check if
1322		// we need to with a regex! (Check as it isn't available in old
1323		// Safari)
1324		var res = str.normalize
1325			? str.normalize("NFD")
1326			: str;
1327	
1328		// Equally, here we check if a regex is needed or not
1329		return res.length !== str.length
1330			? (both === true ? str + ' ' : '' ) + res.replace(/[\u0300-\u036f]/g, "")
1331			: res;
1332	}
1333	
1334	/**
1335	 * Determine if all values in the array are unique. This means we can short
1336	 * cut the _unique method at the cost of a single loop. A sorted array is used
1337	 * to easily check the values.
1338	 *
1339	 * @param  {array} src Source array
1340	 * @return {boolean} true if all unique, false otherwise
1341	 * @ignore
1342	 */
1343	var _areAllUnique = function ( src ) {
1344		if ( src.length < 2 ) {
1345			return true;
1346		}
1347	
1348		var sorted = src.slice().sort();
1349		var last = sorted[0];
1350	
1351		for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1352			if ( sorted[i] === last ) {
1353				return false;
1354			}
1355	
1356			last = sorted[i];
1357		}
1358	
1359		return true;
1360	};
1361	
1362	
1363	/**
1364	 * Find the unique elements in a source array.
1365	 *
1366	 * @param  {array} src Source array
1367	 * @return {array} Array of unique items
1368	 * @ignore
1369	 */
1370	var _unique = function ( src )
1371	{
1372		if (Array.from && Set) {
1373			return Array.from(new Set(src));
1374		}
1375	
1376		if ( _areAllUnique( src ) ) {
1377			return src.slice();
1378		}
1379	
1380		// A faster unique method is to use object keys to identify used values,
1381		// but this doesn't work with arrays or objects, which we must also
1382		// consider. See jsperf.app/compare-array-unique-versions/4 for more
1383		// information.
1384		var
1385			out = [],
1386			val,
1387			i, ien=src.length,
1388			j, k=0;
1389	
1390		again: for ( i=0 ; i<ien ; i++ ) {
1391			val = src[i];
1392	
1393			for ( j=0 ; j<k ; j++ ) {
1394				if ( out[j] === val ) {
1395					continue again;
1396				}
1397			}
1398	
1399			out.push( val );
1400			k++;
1401		}
1402	
1403		return out;
1404	};
1405	
1406	// Surprisingly this is faster than [].concat.apply
1407	// https://jsperf.com/flatten-an-array-loop-vs-reduce/2
1408	var _flatten = function (out, val) {
1409		if (Array.isArray(val)) {
1410			for (var i=0 ; i<val.length ; i++) {
1411				_flatten(out, val[i]);
1412			}
1413		}
1414		else {
1415			out.push(val);
1416		}
1417	
1418		return out;
1419	}
1420	
1421	// Similar to jQuery's addClass, but use classList.add
1422	function _addClass(el, name) {
1423		if (name) {
1424			name.split(' ').forEach(function (n) {
1425				if (n) {
1426					// `add` does deduplication, so no need to check `contains`
1427					el.classList.add(n);
1428				}
1429			});
1430		}
1431	}
1432	
1433	/**
1434	 * DataTables utility methods
1435	 * 
1436	 * This namespace provides helper methods that DataTables uses internally to
1437	 * create a DataTable, but which are not exclusively used only for DataTables.
1438	 * These methods can be used by extension authors to save the duplication of
1439	 * code.
1440	 *
1441	 *  @namespace
1442	 */
1443	DataTable.util = {
1444		/**
1445		 * Return a string with diacritic characters decomposed
1446		 * @param {*} mixed Function or string to normalize
1447		 * @param {*} both Return original string and the normalized string
1448		 * @returns String or undefined
1449		 */
1450		diacritics: function (mixed, both) {
1451			var type = typeof mixed;
1452	
1453			if (type !== 'function') {
1454				return _normalize(mixed, both);
1455			}
1456			_normalize = mixed;
1457		},
1458	
1459		/**
1460		 * Debounce a function
1461		 *
1462		 * @param {function} fn Function to be called
1463		 * @param {integer} freq Call frequency in mS
1464		 * @return {function} Wrapped function
1465		 */
1466		debounce: function ( fn, timeout ) {
1467			var timer;
1468	
1469			return function () {
1470				var that = this;
1471				var args = arguments;
1472	
1473				clearTimeout(timer);
1474	
1475				timer = setTimeout( function () {
1476					fn.apply(that, args);
1477				}, timeout || 250 );
1478			};
1479		},
1480	
1481		/**
1482		 * Throttle the calls to a function. Arguments and context are maintained
1483		 * for the throttled function.
1484		 *
1485		 * @param {function} fn Function to be called
1486		 * @param {integer} freq Call frequency in mS
1487		 * @return {function} Wrapped function
1488		 */
1489		throttle: function ( fn, freq ) {
1490			var
1491				frequency = freq !== undefined ? freq : 200,
1492				last,
1493				timer;
1494	
1495			return function () {
1496				var
1497					that = this,
1498					now  = +new Date(),
1499					args = arguments;
1500	
1501				if ( last && now < last + frequency ) {
1502					clearTimeout( timer );
1503	
1504					timer = setTimeout( function () {
1505						last = undefined;
1506						fn.apply( that, args );
1507					}, frequency );
1508				}
1509				else {
1510					last = now;
1511					fn.apply( that, args );
1512				}
1513			};
1514		},
1515	
1516		/**
1517		 * Escape a string such that it can be used in a regular expression
1518		 *
1519		 *  @param {string} val string to escape
1520		 *  @returns {string} escaped string
1521		 */
1522		escapeRegex: function ( val ) {
1523			return val.replace( _re_escape_regex, '\\$1' );
1524		},
1525	
1526		/**
1527		 * Create a function that will write to a nested object or array
1528		 * @param {*} source JSON notation string
1529		 * @returns Write function
1530		 */
1531		set: function ( source ) {
1532			if ( $.isPlainObject( source ) ) {
1533				/* Unlike get, only the underscore (global) option is used for for
1534				 * setting data since we don't know the type here. This is why an object
1535				 * option is not documented for `mData` (which is read/write), but it is
1536				 * for `mRender` which is read only.
1537				 */
1538				return DataTable.util.set( source._ );
1539			}
1540			else if ( source === null ) {
1541				// Nothing to do when the data source is null
1542				return function () {};
1543			}
1544			else if ( typeof source === 'function' ) {
1545				return function (data, val, meta) {
1546					source( data, 'set', val, meta );
1547				};
1548			}
1549			else if (
1550				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1551				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1552			) {
1553				// Like the get, we need to get data from a nested object
1554				var setData = function (data, val, src) {
1555					var a = _fnSplitObjNotation( src ), b;
1556					var aLast = a[a.length-1];
1557					var arrayNotation, funcNotation, o, innerSrc;
1558		
1559					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {
1560						// Protect against prototype pollution
1561						if (a[i] === '__proto__' || a[i] === 'constructor') {
1562							throw new Error('Cannot set prototype values');
1563						}
1564		
1565						// Check if we are dealing with an array notation request
1566						arrayNotation = a[i].match(__reArray);
1567						funcNotation = a[i].match(__reFn);
1568		
1569						if ( arrayNotation ) {
1570							a[i] = a[i].replace(__reArray, '');
1571							data[ a[i] ] = [];
1572		
1573							// Get the remainder of the nested object to set so we can recurse
1574							b = a.slice();
1575							b.splice( 0, i+1 );
1576							innerSrc = b.join('.');
1577		
1578							// Traverse each entry in the array setting the properties requested
1579							if ( Array.isArray( val ) ) {
1580								for ( var j=0, jLen=val.length ; j<jLen ; j++ ) {
1581									o = {};
1582									setData( o, val[j], innerSrc );
1583									data[ a[i] ].push( o );
1584								}
1585							}
1586							else {
1587								// We've been asked to save data to an array, but it
1588								// isn't array data to be saved. Best that can be done
1589								// is to just save the value.
1590								data[ a[i] ] = val;
1591							}
1592		
1593							// The inner call to setData has already traversed through the remainder
1594							// of the source and has set the data, thus we can exit here
1595							return;
1596						}
1597						else if ( funcNotation ) {
1598							// Function call
1599							a[i] = a[i].replace(__reFn, '');
1600							data = data[ a[i] ]( val );
1601						}
1602		
1603						// If the nested object doesn't currently exist - since we are
1604						// trying to set the value - create it
1605						if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {
1606							data[ a[i] ] = {};
1607						}
1608						data = data[ a[i] ];
1609					}
1610		
1611					// Last item in the input - i.e, the actual set
1612					if ( aLast.match(__reFn ) ) {
1613						// Function call
1614						data = data[ aLast.replace(__reFn, '') ]( val );
1615					}
1616					else {
1617						// If array notation is used, we just want to strip it and use the property name
1618						// and assign the value. If it isn't used, then we get the result we want anyway
1619						data[ aLast.replace(__reArray, '') ] = val;
1620					}
1621				};
1622		
1623				return function (data, val) { // meta is also passed in, but not used
1624					return setData( data, val, source );
1625				};
1626			}
1627			else {
1628				// Array or flat object mapping
1629				return function (data, val) { // meta is also passed in, but not used
1630					data[source] = val;
1631				};
1632			}
1633		},
1634	
1635		/**
1636		 * Create a function that will read nested objects from arrays, based on JSON notation
1637		 * @param {*} source JSON notation string
1638		 * @returns Value read
1639		 */
1640		get: function ( source ) {
1641			if ( $.isPlainObject( source ) ) {
1642				// Build an object of get functions, and wrap them in a single call
1643				var o = {};
1644				$.each( source, function (key, val) {
1645					if ( val ) {
1646						o[key] = DataTable.util.get( val );
1647					}
1648				} );
1649		
1650				return function (data, type, row, meta) {
1651					var t = o[type] || o._;
1652					return t !== undefined ?
1653						t(data, type, row, meta) :
1654						data;
1655				};
1656			}
1657			else if ( source === null ) {
1658				// Give an empty string for rendering / sorting etc
1659				return function (data) { // type, row and meta also passed, but not used
1660					return data;
1661				};
1662			}
1663			else if ( typeof source === 'function' ) {
1664				return function (data, type, row, meta) {
1665					return source( data, type, row, meta );
1666				};
1667			}
1668			else if (
1669				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1670				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1671			) {
1672				/* If there is a . in the source string then the data source is in a
1673				 * nested object so we loop over the data for each level to get the next
1674				 * level down. On each loop we test for undefined, and if found immediately
1675				 * return. This allows entire objects to be missing and sDefaultContent to
1676				 * be used if defined, rather than throwing an error
1677				 */
1678				var fetchData = function (data, type, src) {
1679					var arrayNotation, funcNotation, out, innerSrc;
1680		
1681					if ( src !== "" ) {
1682						var a = _fnSplitObjNotation( src );
1683		
1684						for ( var i=0, iLen=a.length ; i<iLen ; i++ ) {
1685							// Check if we are dealing with special notation
1686							arrayNotation = a[i].match(__reArray);
1687							funcNotation = a[i].match(__reFn);
1688		
1689							if ( arrayNotation ) {
1690								// Array notation
1691								a[i] = a[i].replace(__reArray, '');
1692		
1693								// Condition allows simply [] to be passed in
1694								if ( a[i] !== "" ) {
1695									data = data[ a[i] ];
1696								}
1697								out = [];
1698		
1699								// Get the remainder of the nested object to get
1700								a.splice( 0, i+1 );
1701								innerSrc = a.join('.');
1702		
1703								// Traverse each entry in the array getting the properties requested
1704								if ( Array.isArray( data ) ) {
1705									for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1706										out.push( fetchData( data[j], type, innerSrc ) );
1707									}
1708								}
1709		
1710								// If a string is given in between the array notation indicators, that
1711								// is used to join the strings together, otherwise an array is returned
1712								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1713								data = (join==="") ? out : out.join(join);
1714		
1715								// The inner call to fetchData has already traversed through the remainder
1716								// of the source requested, so we exit from the loop
1717								break;
1718							}
1719							else if ( funcNotation ) {
1720								// Function call
1721								a[i] = a[i].replace(__reFn, '');
1722								data = data[ a[i] ]();
1723								continue;
1724							}
1725		
1726							if (data === null || data[ a[i] ] === null) {
1727								return null;
1728							}
1729							else if ( data === undefined || data[ a[i] ] === undefined ) {
1730								return undefined;
1731							}
1732	
1733							data = data[ a[i] ];
1734						}
1735					}
1736		
1737					return data;
1738				};
1739		
1740				return function (data, type) { // row and meta also passed, but not used
1741					return fetchData( data, type, source );
1742				};
1743			}
1744			else {
1745				// Array or flat object mapping
1746				return function (data) { // row and meta also passed, but not used
1747					return data[source];
1748				};
1749			}
1750		},
1751	
1752		stripHtml: function (mixed) {
1753			var type = typeof mixed;
1754	
1755			if (type === 'function') {
1756				_stripHtml = mixed;
1757				return;
1758			}
1759			else if (type === 'string') {
1760				return _stripHtml(mixed);
1761			}
1762			return mixed;
1763		},
1764	
1765		escapeHtml: function (mixed) {
1766			var type = typeof mixed;
1767	
1768			if (type === 'function') {
1769				_escapeHtml = mixed;
1770				return;
1771			}
1772			else if (type === 'string' || Array.isArray(mixed)) {
1773				return _escapeHtml(mixed);
1774			}
1775			return mixed;
1776		},
1777	
1778		unique: _unique
1779	};
1780	
1781	
1782	
1783	/**
1784	 * Create a mapping object that allows camel case parameters to be looked up
1785	 * for their Hungarian counterparts. The mapping is stored in a private
1786	 * parameter called `_hungarianMap` which can be accessed on the source object.
1787	 *  @param {object} o
1788	 *  @memberof DataTable#oApi
1789	 */
1790	function _fnHungarianMap ( o )
1791	{
1792		var
1793			hungarian = 'a aa ai ao as b fn i m o s ',
1794			match,
1795			newKey,
1796			map = {};
1797	
1798		$.each( o, function (key) {
1799			match = key.match(/^([^A-Z]+?)([A-Z])/);
1800	
1801			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1802			{
1803				newKey = key.replace( match[0], match[2].toLowerCase() );
1804				map[ newKey ] = key;
1805	
1806				if ( match[1] === 'o' )
1807				{
1808					_fnHungarianMap( o[key] );
1809				}
1810			}
1811		} );
1812	
1813		o._hungarianMap = map;
1814	}
1815	
1816	
1817	/**
1818	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1819	 * created by _fnHungarianMap.
1820	 *  @param {object} src The model object which holds all parameters that can be
1821	 *    mapped.
1822	 *  @param {object} user The object to convert from camel case to Hungarian.
1823	 *  @param {boolean} force When set to `true`, properties which already have a
1824	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
1825	 *    won't be.
1826	 *  @memberof DataTable#oApi
1827	 */
1828	function _fnCamelToHungarian ( src, user, force )
1829	{
1830		if ( ! src._hungarianMap ) {
1831			_fnHungarianMap( src );
1832		}
1833	
1834		var hungarianKey;
1835	
1836		$.each( user, function (key) {
1837			hungarianKey = src._hungarianMap[ key ];
1838	
1839			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1840			{
1841				// For objects, we need to buzz down into the object to copy parameters
1842				if ( hungarianKey.charAt(0) === 'o' )
1843				{
1844					// Copy the camelCase options over to the hungarian
1845					if ( ! user[ hungarianKey ] ) {
1846						user[ hungarianKey ] = {};
1847					}
1848					$.extend( true, user[hungarianKey], user[key] );
1849	
1850					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1851				}
1852				else {
1853					user[hungarianKey] = user[ key ];
1854				}
1855			}
1856		} );
1857	}
1858	
1859	/**
1860	 * Map one parameter onto another
1861	 *  @param {object} o Object to map
1862	 *  @param {*} knew The new parameter name
1863	 *  @param {*} old The old parameter name
1864	 */
1865	var _fnCompatMap = function ( o, knew, old ) {
1866		if ( o[ knew ] !== undefined ) {
1867			o[ old ] = o[ knew ];
1868		}
1869	};
1870	
1871	
1872	/**
1873	 * Provide backwards compatibility for the main DT options. Note that the new
1874	 * options are mapped onto the old parameters, so this is an external interface
1875	 * change only.
1876	 *  @param {object} init Object to map
1877	 */
1878	function _fnCompatOpts ( init )
1879	{
1880		_fnCompatMap( init, 'ordering',      'bSort' );
1881		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
1882		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
1883		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1884		_fnCompatMap( init, 'order',         'aaSorting' );
1885		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
1886		_fnCompatMap( init, 'paging',        'bPaginate' );
1887		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
1888		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
1889		_fnCompatMap( init, 'searching',     'bFilter' );
1890	
1891		// Boolean initialisation of x-scrolling
1892		if ( typeof init.sScrollX === 'boolean' ) {
1893			init.sScrollX = init.sScrollX ? '100%' : '';
1894		}
1895		if ( typeof init.scrollX === 'boolean' ) {
1896			init.scrollX = init.scrollX ? '100%' : '';
1897		}
1898	
1899		// Objects for ordering
1900		if ( typeof init.bSort === 'object' ) {
1901			init.orderIndicators = init.bSort.indicators !== undefined ? init.bSort.indicators : true;
1902			init.orderHandler = init.bSort.handler !== undefined ? init.bSort.handler : true;
1903			init.bSort = true;
1904		}
1905		else if (init.bSort === false) {
1906			init.orderIndicators = false;
1907			init.orderHandler = false;
1908		}
1909		else if (init.bSort === true) {
1910			init.orderIndicators = true;
1911			init.orderHandler = true;
1912		}
1913	
1914		// Which cells are the title cells?
1915		if (typeof init.bSortCellsTop === 'boolean') {
1916			init.titleRow = init.bSortCellsTop;
1917		}
1918	
1919		// Column search objects are in an array, so it needs to be converted
1920		// element by element
1921		var searchCols = init.aoSearchCols;
1922	
1923		if ( searchCols ) {
1924			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1925				if ( searchCols[i] ) {
1926					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1927				}
1928			}
1929		}
1930	
1931		// Enable search delay if server-side processing is enabled
1932		if (init.serverSide && ! init.searchDelay) {
1933			init.searchDelay = 400;
1934		}
1935	}
1936	
1937	
1938	/**
1939	 * Provide backwards compatibility for column options. Note that the new options
1940	 * are mapped onto the old parameters, so this is an external interface change
1941	 * only.
1942	 *  @param {object} init Object to map
1943	 */
1944	function _fnCompatCols ( init )
1945	{
1946		_fnCompatMap( init, 'orderable',     'bSortable' );
1947		_fnCompatMap( init, 'orderData',     'aDataSort' );
1948		_fnCompatMap( init, 'orderSequence', 'asSorting' );
1949		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
1950	
1951		// orderData can be given as an integer
1952		var dataSort = init.aDataSort;
1953		if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {
1954			init.aDataSort = [ dataSort ];
1955		}
1956	}
1957	
1958	
1959	/**
1960	 * Browser feature detection for capabilities, quirks
1961	 *  @param {object} settings dataTables settings object
1962	 *  @memberof DataTable#oApi
1963	 */
1964	function _fnBrowserDetect( settings )
1965	{
1966		// We don't need to do this every time DataTables is constructed, the values
1967		// calculated are specific to the browser and OS configuration which we
1968		// don't expect to change between initialisations
1969		if ( ! DataTable.__browser ) {
1970			var browser = {};
1971			DataTable.__browser = browser;
1972	
1973			// Scrolling feature / quirks detection
1974			var n = $('<div/>')
1975				.css( {
1976					position: 'fixed',
1977					top: 0,
1978					left: -1 * window.pageXOffset, // allow for scrolling
1979					height: 1,
1980					width: 1,
1981					overflow: 'hidden'
1982				} )
1983				.append(
1984					$('<div/>')
1985						.css( {
1986							position: 'absolute',
1987							top: 1,
1988							left: 1,
1989							width: 100,
1990							overflow: 'scroll'
1991						} )
1992						.append(
1993							$('<div/>')
1994								.css( {
1995									width: '100%',
1996									height: 10
1997								} )
1998						)
1999				)
2000				.appendTo( 'body' );
2001	
2002			var outer = n.children();
2003			var inner = outer.children();
2004	
2005			// Get scrollbar width
2006			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
2007	
2008			// In rtl text layout, some browsers (most, but not all) will place the
2009			// scrollbar on the left, rather than the right.
2010			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
2011	
2012			n.remove();
2013		}
2014	
2015		$.extend( settings.oBrowser, DataTable.__browser );
2016		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
2017	}
2018	
2019	/**
2020	 * Add a column to the list used for the table with default values
2021	 *  @param {object} oSettings dataTables settings object
2022	 *  @memberof DataTable#oApi
2023	 */
2024	function _fnAddColumn( oSettings )
2025	{
2026		// Add column to aoColumns array
2027		var oDefaults = DataTable.defaults.column;
2028		var iCol = oSettings.aoColumns.length;
2029		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
2030			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
2031			"mData": oDefaults.mData ? oDefaults.mData : iCol,
2032			idx: iCol,
2033			searchFixed: {},
2034			colEl: $('<col>').attr('data-dt-column', iCol)
2035		} );
2036		oSettings.aoColumns.push( oCol );
2037	
2038		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
2039		// passed into extend can be undefined. This allows the user to give a default
2040		// with only some of the parameters defined, and also not give a default
2041		var searchCols = oSettings.aoPreSearchCols;
2042		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
2043	}
2044	
2045	
2046	/**
2047	 * Apply options for a column
2048	 *  @param {object} oSettings dataTables settings object
2049	 *  @param {int} iCol column index to consider
2050	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
2051	 *  @memberof DataTable#oApi
2052	 */
2053	function _fnColumnOptions( oSettings, iCol, oOptions )
2054	{
2055		var oCol = oSettings.aoColumns[ iCol ];
2056	
2057		/* User specified column options */
2058		if ( oOptions !== undefined && oOptions !== null )
2059		{
2060			// Backwards compatibility
2061			_fnCompatCols( oOptions );
2062	
2063			// Map camel case parameters to their Hungarian counterparts
2064			_fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
2065	
2066			/* Backwards compatibility for mDataProp */
2067			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2068			{
2069				oOptions.mData = oOptions.mDataProp;
2070			}
2071	
2072			if ( oOptions.sType )
2073			{
2074				oCol._sManualType = oOptions.sType;
2075			}
2076		
2077			// `class` is a reserved word in Javascript, so we need to provide
2078			// the ability to use a valid name for the camel case input
2079			if ( oOptions.className && ! oOptions.sClass )
2080			{
2081				oOptions.sClass = oOptions.className;
2082			}
2083	
2084			var origClass = oCol.sClass;
2085	
2086			$.extend( oCol, oOptions );
2087			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2088	
2089			// Merge class from previously defined classes with this one, rather than just
2090			// overwriting it in the extend above
2091			if (origClass !== oCol.sClass) {
2092				oCol.sClass = origClass + ' ' + oCol.sClass;
2093			}
2094	
2095			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
2096			 * priority if defined
2097			 */
2098			if ( oOptions.iDataSort !== undefined )
2099			{
2100				oCol.aDataSort = [ oOptions.iDataSort ];
2101			}
2102			_fnMap( oCol, oOptions, "aDataSort" );
2103		}
2104	
2105		/* Cache the data get and set functions for speed */
2106		var mDataSrc = oCol.mData;
2107		var mData = _fnGetObjectDataFn( mDataSrc );
2108	
2109		// The `render` option can be given as an array to access the helper rendering methods.
2110		// The first element is the rendering method to use, the rest are the parameters to pass
2111		if ( oCol.mRender && Array.isArray( oCol.mRender ) ) {
2112			var copy = oCol.mRender.slice();
2113			var name = copy.shift();
2114	
2115			oCol.mRender = DataTable.render[name].apply(window, copy);
2116		}
2117	
2118		oCol._render = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2119	
2120		var attrTest = function( src ) {
2121			return typeof src === 'string' && src.indexOf('@') !== -1;
2122		};
2123		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2124			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2125		);
2126		oCol._setter = null;
2127	
2128		oCol.fnGetData = function (rowData, type, meta) {
2129			var innerData = mData( rowData, type, undefined, meta );
2130	
2131			return oCol._render && type ?
2132				oCol._render( innerData, type, rowData, meta ) :
2133				innerData;
2134		};
2135		oCol.fnSetData = function ( rowData, val, meta ) {
2136			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2137		};
2138	
2139		// Indicate if DataTables should read DOM data as an object or array
2140		// Used in _fnGetRowElements
2141		if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) {
2142			oSettings._rowReadObject = true;
2143		}
2144	
2145		/* Feature sorting overrides column specific when off */
2146		if ( !oSettings.oFeatures.bSort )
2147		{
2148			oCol.bSortable = false;
2149		}
2150	}
2151	
2152	
2153	/**
2154	 * Adjust the table column widths for new data. Note: you would probably want to
2155	 * do a redraw after calling this function!
2156	 *  @param {object} settings dataTables settings object
2157	 *  @memberof DataTable#oApi
2158	 */
2159	function _fnAdjustColumnSizing ( settings )
2160	{
2161		_fnCalculateColumnWidths( settings );
2162		_fnColumnSizes( settings );
2163	
2164		var scroll = settings.oScroll;
2165		if ( scroll.sY !== '' || scroll.sX !== '') {
2166			_fnScrollDraw( settings );
2167		}
2168	
2169		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
2170	}
2171	
2172	/**
2173	 * Apply column sizes
2174	 *
2175	 * @param {*} settings DataTables settings object
2176	 */
2177	function _fnColumnSizes ( settings )
2178	{
2179		var cols = settings.aoColumns;
2180	
2181		for (var i=0 ; i<cols.length ; i++) {
2182			var width = _fnColumnsSumWidth(settings, [i], false, false);
2183	
2184			cols[i].colEl.css('width', width);
2185	
2186			if (settings.oScroll.sX) {
2187				cols[i].colEl.css('min-width', width);
2188			}
2189		}
2190	}
2191	
2192	
2193	/**
2194	 * Convert the index of a visible column to the index in the data array (take account
2195	 * of hidden columns)
2196	 *  @param {object} oSettings dataTables settings object
2197	 *  @param {int} iMatch Visible column index to lookup
2198	 *  @returns {int} i the data index
2199	 *  @memberof DataTable#oApi
2200	 */
2201	function _fnVisibleToColumnIndex( oSettings, iMatch )
2202	{
2203		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2204	
2205		return typeof aiVis[iMatch] === 'number' ?
2206			aiVis[iMatch] :
2207			null;
2208	}
2209	
2210	
2211	/**
2212	 * Convert the index of an index in the data array and convert it to the visible
2213	 *   column index (take account of hidden columns)
2214	 *  @param {int} iMatch Column index to lookup
2215	 *  @param {object} oSettings dataTables settings object
2216	 *  @returns {int} i the data index
2217	 *  @memberof DataTable#oApi
2218	 */
2219	function _fnColumnIndexToVisible( oSettings, iMatch )
2220	{
2221		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2222		var iPos = aiVis.indexOf(iMatch);
2223	
2224		return iPos !== -1 ? iPos : null;
2225	}
2226	
2227	
2228	/**
2229	 * Get the number of visible columns
2230	 *  @param {object} oSettings dataTables settings object
2231	 *  @returns {int} i the number of visible columns
2232	 *  @memberof DataTable#oApi
2233	 */
2234	function _fnVisbleColumns( settings )
2235	{
2236		var layout = settings.aoHeader;
2237		var columns = settings.aoColumns;
2238		var vis = 0;
2239	
2240		if ( layout.length ) {
2241			for ( var i=0, ien=layout[0].length ; i<ien ; i++ ) {
2242				if ( columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none' ) {
2243					vis++;
2244				}
2245			}
2246		}
2247	
2248		return vis;
2249	}
2250	
2251	
2252	/**
2253	 * Get an array of column indexes that match a given property
2254	 *  @param {object} oSettings dataTables settings object
2255	 *  @param {string} sParam Parameter in aoColumns to look for - typically
2256	 *    bVisible or bSearchable
2257	 *  @returns {array} Array of indexes with matched properties
2258	 *  @memberof DataTable#oApi
2259	 */
2260	function _fnGetColumns( oSettings, sParam )
2261	{
2262		var a = [];
2263	
2264		oSettings.aoColumns.map( function(val, i) {
2265			if ( val[sParam] ) {
2266				a.push( i );
2267			}
2268		} );
2269	
2270		return a;
2271	}
2272	
2273	/**
2274	 * Allow the result from a type detection function to be `true` while
2275	 * translating that into a string. Old type detection functions will
2276	 * return the type name if it passes. An obect store would be better,
2277	 * but not backwards compatible.
2278	 *
2279	 * @param {*} typeDetect Object or function for type detection
2280	 * @param {*} res Result from the type detection function
2281	 * @returns Type name or false
2282	 */
2283	function _typeResult (typeDetect, res) {
2284		return res === true
2285			? typeDetect._name
2286			: res;
2287	}
2288	
2289	/**
2290	 * Calculate the 'type' of a column
2291	 *  @param {object} settings dataTables settings object
2292	 *  @memberof DataTable#oApi
2293	 */
2294	function _fnColumnTypes ( settings )
2295	{
2296		var columns = settings.aoColumns;
2297		var data = settings.aoData;
2298		var types = DataTable.ext.type.detect;
2299		var i, ien, j, jen, k, ken;
2300		var col, detectedType, cache;
2301	
2302		// For each column, spin over the data type detection functions, seeing if one matches
2303		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2304			col = columns[i];
2305			cache = [];
2306	
2307			if ( ! col.sType && col._sManualType ) {
2308				col.sType = col._sManualType;
2309			}
2310			else if ( ! col.sType ) {
2311				// With SSP type detection can be unreliable and error prone, so we provide a way
2312				// to turn it off.
2313				if (! settings.typeDetect) {
2314					return;
2315				}
2316	
2317				for ( j=0, jen=types.length ; j<jen ; j++ ) {
2318					var typeDetect = types[j];
2319	
2320					// There can be either one, or three type detection functions
2321					var oneOf = typeDetect.oneOf;
2322					var allOf = typeDetect.allOf || typeDetect;
2323					var init = typeDetect.init;
2324					var one = false;
2325	
2326					detectedType = null;
2327	
2328					// Fast detect based on column assignment
2329					if (init) {
2330						detectedType = _typeResult(typeDetect, init(settings, col, i));
2331	
2332						if (detectedType) {
2333							col.sType = detectedType;
2334							break;
2335						}
2336					}
2337	
2338					for ( k=0, ken=data.length ; k<ken ; k++ ) {
2339						if (! data[k]) {
2340							continue;
2341						}
2342	
2343						// Use a cache array so we only need to get the type data
2344						// from the formatter once (when using multiple detectors)
2345						if ( cache[k] === undefined ) {
2346							cache[k] = _fnGetCellData( settings, k, i, 'type' );
2347						}
2348	
2349						// Only one data point in the column needs to match this function
2350						if (oneOf && ! one) {
2351							one = _typeResult(typeDetect, oneOf( cache[k], settings ));
2352						}
2353	
2354						// All data points need to match this function
2355						detectedType = _typeResult(typeDetect, allOf( cache[k], settings ));
2356	
2357						// If null, then this type can't apply to this column, so
2358						// rather than testing all cells, break out. There is an
2359						// exception for the last type which is `html`. We need to
2360						// scan all rows since it is possible to mix string and HTML
2361						// types
2362						if ( ! detectedType && j !== types.length-3 ) {
2363							break;
2364						}
2365	
2366						// Only a single match is needed for html type since it is
2367						// bottom of the pile and very similar to string - but it
2368						// must not be empty
2369						if ( detectedType === 'html' && ! _empty(cache[k]) ) {
2370							break;
2371						}
2372					}
2373	
2374					// Type is valid for all data points in the column - use this
2375					// type
2376					if ( (oneOf && one && detectedType) || (!oneOf && detectedType) ) {
2377						col.sType = detectedType;
2378						break;
2379					}
2380				}
2381	
2382				// Fall back - if no type was detected, always use string
2383				if ( ! col.sType ) {
2384					col.sType = 'string';
2385				}
2386			}
2387	
2388			// Set class names for header / footer for auto type classes
2389			var autoClass = _ext.type.className[col.sType];
2390	
2391			if (autoClass) {
2392				_columnAutoClass(settings.aoHeader, i, autoClass);
2393				_columnAutoClass(settings.aoFooter, i, autoClass);
2394			}
2395	
2396			var renderer = _ext.type.render[col.sType];
2397	
2398			// This can only happen once! There is no way to remove
2399			// a renderer. After the first time the renderer has
2400			// already been set so createTr will run the renderer itself.
2401			if (renderer && ! col._render) {
2402				col._render = DataTable.util.get(renderer);
2403	
2404				_columnAutoRender(settings, i);
2405			}
2406		}
2407	}
2408	
2409	/**
2410	 * Apply an auto detected renderer to data which doesn't yet have
2411	 * a renderer
2412	 */
2413	function _columnAutoRender(settings, colIdx) {
2414		var data = settings.aoData;
2415	
2416		for (var i=0 ; i<data.length ; i++) {
2417			if (data[i].nTr) {
2418				// We have to update the display here since there is no
2419				// invalidation check for the data
2420				var display = _fnGetCellData( settings, i, colIdx, 'display' );
2421	
2422				data[i].displayData[colIdx] = display;
2423				_fnWriteCell(data[i].anCells[colIdx], display);
2424	
2425				// No need to update sort / filter data since it has
2426				// been invalidated and will be re-read with the
2427				// renderer now applied
2428			}
2429		}
2430	}
2431	
2432	/**
2433	 * Apply a class name to a column's header cells
2434	 */
2435	function _columnAutoClass(container, colIdx, className) {
2436		container.forEach(function (row) {
2437			if (row[colIdx] && row[colIdx].unique) {
2438				_addClass(row[colIdx].cell, className);
2439			}
2440		});
2441	}
2442	
2443	/**
2444	 * Take the column definitions and static columns arrays and calculate how
2445	 * they relate to column indexes. The callback function will then apply the
2446	 * definition found for a column to a suitable configuration object.
2447	 *  @param {object} oSettings dataTables settings object
2448	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
2449	 *  @param {array} aoCols The aoColumns array that defines columns individually
2450	 *  @param {array} headerLayout Layout for header as it was loaded
2451	 *  @param {function} fn Callback function - takes two parameters, the calculated
2452	 *    column index and the definition for that column.
2453	 *  @memberof DataTable#oApi
2454	 */
2455	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, headerLayout, fn )
2456	{
2457		var i, iLen, j, jLen, k, kLen, def;
2458		var columns = oSettings.aoColumns;
2459	
2460		if ( aoCols ) {
2461			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2462				if (aoCols[i] && aoCols[i].name) {
2463					columns[i].sName = aoCols[i].name;
2464				}
2465			}
2466		}
2467	
2468		// Column definitions with aTargets
2469		if ( aoColDefs )
2470		{
2471			/* Loop over the definitions array - loop in reverse so first instance has priority */
2472			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2473			{
2474				def = aoColDefs[i];
2475	
2476				/* Each definition can target multiple columns, as it is an array */
2477				var aTargets = def.target !== undefined
2478					? def.target
2479					: def.targets !== undefined
2480						? def.targets
2481						: def.aTargets;
2482	
2483				if ( ! Array.isArray( aTargets ) )
2484				{
2485					aTargets = [ aTargets ];
2486				}
2487	
2488				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2489				{
2490					var target = aTargets[j];
2491	
2492					if ( typeof target === 'number' && target >= 0 )
2493					{
2494						/* Add columns that we don't yet know about */
2495						while( columns.length <= target )
2496						{
2497							_fnAddColumn( oSettings );
2498						}
2499	
2500						/* Integer, basic index */
2501						fn( target, def );
2502					}
2503					else if ( typeof target === 'number' && target < 0 )
2504					{
2505						/* Negative integer, right to left column counting */
2506						fn( columns.length+target, def );
2507					}
2508					else if ( typeof target === 'string' )
2509					{
2510						for ( k=0, kLen=columns.length ; k<kLen ; k++ ) {
2511							if (target === '_all') {
2512								// Apply to all columns
2513								fn( k, def );
2514							}
2515							else if (target.indexOf(':name') !== -1) {
2516								// Column selector
2517								if (columns[k].sName === target.replace(':name', '')) {
2518									fn( k, def );
2519								}
2520							}
2521							else {
2522								// Cell selector
2523								headerLayout.forEach(function (row) {
2524									if (row[k]) {
2525										var cell = $(row[k].cell);
2526	
2527										// Legacy support. Note that it means that we don't support
2528										// an element name selector only, since they are treated as
2529										// class names for 1.x compat.
2530										if (target.match(/^[a-z][\w-]*$/i)) {
2531											target = '.' + target;
2532										}
2533	
2534										if (cell.is( target )) {
2535											fn( k, def );
2536										}
2537									}
2538								});
2539							}
2540						}
2541					}
2542				}
2543			}
2544		}
2545	
2546		// Statically defined columns array
2547		if ( aoCols ) {
2548			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2549				fn( i, aoCols[i] );
2550			}
2551		}
2552	}
2553	
2554	
2555	/**
2556	 * Get the width for a given set of columns
2557	 *
2558	 * @param {*} settings DataTables settings object
2559	 * @param {*} targets Columns - comma separated string or array of numbers
2560	 * @param {*} original Use the original width (true) or calculated (false)
2561	 * @param {*} incVisible Include visible columns (true) or not (false)
2562	 * @returns Combined CSS value
2563	 */
2564	function _fnColumnsSumWidth( settings, targets, original, incVisible ) {
2565		if ( ! Array.isArray( targets ) ) {
2566			targets = _fnColumnsFromHeader( targets );
2567		}
2568	
2569		var sum = 0;
2570		var unit;
2571		var columns = settings.aoColumns;
2572		
2573		for ( var i=0, ien=targets.length ; i<ien ; i++ ) {
2574			var column = columns[ targets[i] ];
2575			var definedWidth = original ?
2576				column.sWidthOrig :
2577				column.sWidth;
2578	
2579			if ( ! incVisible && column.bVisible === false ) {
2580				continue;
2581			}
2582	
2583			if ( definedWidth === null || definedWidth === undefined ) {
2584				return null; // can't determine a defined width - browser defined
2585			}
2586			else if ( typeof definedWidth === 'number' ) {
2587				unit = 'px';
2588				sum += definedWidth;
2589			}
2590			else {
2591				var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
2592	
2593				if ( matched ) {
2594					sum += matched[1] * 1;
2595					unit = matched.length === 3 ?
2596						matched[2] :
2597						'px';
2598				}
2599			}
2600		}
2601	
2602		return sum + unit;
2603	}
2604	
2605	function _fnColumnsFromHeader( cell )
2606	{
2607		var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
2608	
2609		if ( ! attr ) {
2610			return [];
2611		}
2612	
2613		return attr.split(',').map( function (val) {
2614			return val * 1;
2615		} );
2616	}
2617	/**
2618	 * Add a data array to the table, creating DOM node etc. This is the parallel to
2619	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2620	 * DOM source.
2621	 *  @param {object} settings dataTables settings object
2622	 *  @param {array} data data array to be added
2623	 *  @param {node} [tr] TR element to add to the table - optional. If not given,
2624	 *    DataTables will create a row automatically
2625	 *  @param {array} [tds] Array of TD|TH elements for the row - must be given
2626	 *    if nTr is.
2627	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2628	 *  @memberof DataTable#oApi
2629	 */
2630	function _fnAddData ( settings, dataIn, tr, tds )
2631	{
2632		/* Create the object for storing information about this new row */
2633		var rowIdx = settings.aoData.length;
2634		var rowModel = $.extend( true, {}, DataTable.models.oRow, {
2635			src: tr ? 'dom' : 'data',
2636			idx: rowIdx
2637		} );
2638	
2639		rowModel._aData = dataIn;
2640		settings.aoData.push( rowModel );
2641	
2642		var columns = settings.aoColumns;
2643	
2644		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2645		{
2646			// Invalidate the column types as the new data needs to be revalidated
2647			columns[i].sType = null;
2648		}
2649	
2650		/* Add to the display array */
2651		settings.aiDisplayMaster.push( rowIdx );
2652	
2653		var id = settings.rowIdFn( dataIn );
2654		if ( id !== undefined ) {
2655			settings.aIds[ id ] = rowModel;
2656		}
2657	
2658		/* Create the DOM information, or register it if already present */
2659		if ( tr || ! settings.oFeatures.bDeferRender )
2660		{
2661			_fnCreateTr( settings, rowIdx, tr, tds );
2662		}
2663	
2664		return rowIdx;
2665	}
2666	
2667	
2668	/**
2669	 * Add one or more TR elements to the table. Generally we'd expect to
2670	 * use this for reading data from a DOM sourced table, but it could be
2671	 * used for an TR element. Note that if a TR is given, it is used (i.e.
2672	 * it is not cloned).
2673	 *  @param {object} settings dataTables settings object
2674	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
2675	 *  @returns {array} Array of indexes for the added rows
2676	 *  @memberof DataTable#oApi
2677	 */
2678	function _fnAddTr( settings, trs )
2679	{
2680		var row;
2681	
2682		// Allow an individual node to be passed in
2683		if ( ! (trs instanceof $) ) {
2684			trs = $(trs);
2685		}
2686	
2687		return trs.map( function (i, el) {
2688			row = _fnGetRowElements( settings, el );
2689			return _fnAddData( settings, row.data, el, row.cells );
2690		} );
2691	}
2692	
2693	
2694	/**
2695	 * Get the data for a given cell from the internal cache, taking into account data mapping
2696	 *  @param {object} settings dataTables settings object
2697	 *  @param {int} rowIdx aoData row id
2698	 *  @param {int} colIdx Column index
2699	 *  @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
2700	 *  @returns {*} Cell data
2701	 *  @memberof DataTable#oApi
2702	 */
2703	function _fnGetCellData( settings, rowIdx, colIdx, type )
2704	{
2705		if (type === 'search') {
2706			type = 'filter';
2707		}
2708		else if (type === 'order') {
2709			type = 'sort';
2710		}
2711	
2712		var row = settings.aoData[rowIdx];
2713	
2714		if (! row) {
2715			return undefined;
2716		}
2717	
2718		var draw           = settings.iDraw;
2719		var col            = settings.aoColumns[colIdx];
2720		var rowData        = row._aData;
2721		var defaultContent = col.sDefaultContent;
2722		var cellData       = col.fnGetData( rowData, type, {
2723			settings: settings,
2724			row:      rowIdx,
2725			col:      colIdx
2726		} );
2727	
2728		// Allow for a node being returned for non-display types
2729		if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
2730			cellData = cellData.innerHTML;
2731		}
2732	
2733		if ( cellData === undefined ) {
2734			if ( settings.iDrawError != draw && defaultContent === null ) {
2735				_fnLog( settings, 0, "Requested unknown parameter "+
2736					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2737					" for row "+rowIdx+", column "+colIdx, 4 );
2738				settings.iDrawError = draw;
2739			}
2740			return defaultContent;
2741		}
2742	
2743		// When the data source is null and a specific data type is requested (i.e.
2744		// not the original data), we can use default column data
2745		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2746			cellData = defaultContent;
2747		}
2748		else if ( typeof cellData === 'function' ) {
2749			// If the data source is a function, then we run it and use the return,
2750			// executing in the scope of the data object (for instances)
2751			return cellData.call( rowData );
2752		}
2753	
2754		if ( cellData === null && type === 'display' ) {
2755			return '';
2756		}
2757	
2758		if ( type === 'filter' ) {
2759			var fomatters = DataTable.ext.type.search;
2760	
2761			if ( fomatters[ col.sType ] ) {
2762				cellData = fomatters[ col.sType ]( cellData );
2763			}
2764		}
2765	
2766		return cellData;
2767	}
2768	
2769	
2770	/**
2771	 * Set the value for a specific cell, into the internal data cache
2772	 *  @param {object} settings dataTables settings object
2773	 *  @param {int} rowIdx aoData row id
2774	 *  @param {int} colIdx Column index
2775	 *  @param {*} val Value to set
2776	 *  @memberof DataTable#oApi
2777	 */
2778	function _fnSetCellData( settings, rowIdx, colIdx, val )
2779	{
2780		var col     = settings.aoColumns[colIdx];
2781		var rowData = settings.aoData[rowIdx]._aData;
2782	
2783		col.fnSetData( rowData, val, {
2784			settings: settings,
2785			row:      rowIdx,
2786			col:      colIdx
2787		}  );
2788	}
2789	
2790	/**
2791	 * Write a value to a cell
2792	 * @param {*} td Cell
2793	 * @param {*} val Value
2794	 */
2795	function _fnWriteCell(td, val)
2796	{
2797		if (val && typeof val === 'object' && val.nodeName) {
2798			$(td)
2799				.empty()
2800				.append(val);
2801		}
2802		else {
2803			td.innerHTML = val;
2804		}
2805	}
2806	
2807	
2808	// Private variable that is used to match action syntax in the data property object
2809	var __reArray = /\[.*?\]$/;
2810	var __reFn = /\(\)$/;
2811	
2812	/**
2813	 * Split string on periods, taking into account escaped periods
2814	 * @param  {string} str String to split
2815	 * @return {array} Split string
2816	 */
2817	function _fnSplitObjNotation( str )
2818	{
2819		var parts = str.match(/(\\.|[^.])+/g) || [''];
2820	
2821		return parts.map( function ( s ) {
2822			return s.replace(/\\\./g, '.');
2823		} );
2824	}
2825	
2826	
2827	/**
2828	 * Return a function that can be used to get data from a source object, taking
2829	 * into account the ability to use nested objects as a source
2830	 *  @param {string|int|function} mSource The data source for the object
2831	 *  @returns {function} Data get function
2832	 *  @memberof DataTable#oApi
2833	 */
2834	var _fnGetObjectDataFn = DataTable.util.get;
2835	
2836	
2837	/**
2838	 * Return a function that can be used to set data from a source object, taking
2839	 * into account the ability to use nested objects as a source
2840	 *  @param {string|int|function} mSource The data source for the object
2841	 *  @returns {function} Data set function
2842	 *  @memberof DataTable#oApi
2843	 */
2844	var _fnSetObjectDataFn = DataTable.util.set;
2845	
2846	
2847	/**
2848	 * Return an array with the full table data
2849	 *  @param {object} oSettings dataTables settings object
2850	 *  @returns array {array} aData Master data array
2851	 *  @memberof DataTable#oApi
2852	 */
2853	function _fnGetDataMaster ( settings )
2854	{
2855		return _pluck( settings.aoData, '_aData' );
2856	}
2857	
2858	
2859	/**
2860	 * Nuke the table
2861	 *  @param {object} oSettings dataTables settings object
2862	 *  @memberof DataTable#oApi
2863	 */
2864	function _fnClearTable( settings )
2865	{
2866		settings.aoData.length = 0;
2867		settings.aiDisplayMaster.length = 0;
2868		settings.aiDisplay.length = 0;
2869		settings.aIds = {};
2870	}
2871	
2872	
2873	/**
2874	 * Mark cached data as invalid such that a re-read of the data will occur when
2875	 * the cached data is next requested. Also update from the data source object.
2876	 *
2877	 * @param {object} settings DataTables settings object
2878	 * @param {int}    rowIdx   Row index to invalidate
2879	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
2880	 *     or 'data'
2881	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
2882	 *     row will be invalidated
2883	 * @memberof DataTable#oApi
2884	 *
2885	 * @todo For the modularisation of v1.11 this will need to become a callback, so
2886	 *   the sort and filter methods can subscribe to it. That will required
2887	 *   initialisation options for sorting, which is why it is not already baked in
2888	 */
2889	function _fnInvalidate( settings, rowIdx, src, colIdx )
2890	{
2891		var row = settings.aoData[ rowIdx ];
2892		var i, ien;
2893	
2894		// Remove the cached data for the row
2895		row._aSortData = null;
2896		row._aFilterData = null;
2897		row.displayData = null;
2898	
2899		// Are we reading last data from DOM or the data object?
2900		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2901			// Read the data from the DOM
2902			row._aData = _fnGetRowElements(
2903					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2904				)
2905				.data;
2906		}
2907		else {
2908			// Reading from data object, update the DOM
2909			var cells = row.anCells;
2910			var display = _fnGetRowDisplay(settings, rowIdx);
2911	
2912			if ( cells ) {
2913				if ( colIdx !== undefined ) {
2914					_fnWriteCell(cells[colIdx], display[colIdx]);
2915				}
2916				else {
2917					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2918						_fnWriteCell(cells[i], display[i]);
2919					}
2920				}
2921			}
2922		}
2923	
2924		// Column specific invalidation
2925		var cols = settings.aoColumns;
2926		if ( colIdx !== undefined ) {
2927			// Type - the data might have changed
2928			cols[ colIdx ].sType = null;
2929	
2930			// Max length string. Its a fairly cheep recalculation, so not worth
2931			// something more complicated
2932			cols[ colIdx ].maxLenString = null;
2933		}
2934		else {
2935			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2936				cols[i].sType = null;
2937				cols[i].maxLenString = null;
2938			}
2939	
2940			// Update DataTables special `DT_*` attributes for the row
2941			_fnRowAttributes( settings, row );
2942		}
2943	}
2944	
2945	
2946	/**
2947	 * Build a data source object from an HTML row, reading the contents of the
2948	 * cells that are in the row.
2949	 *
2950	 * @param {object} settings DataTables settings object
2951	 * @param {node|object} TR element from which to read data or existing row
2952	 *   object from which to re-read the data from the cells
2953	 * @param {int} [colIdx] Optional column index
2954	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2955	 *   parameter should also be given and will be used to write the data into.
2956	 *   Only the column in question will be written
2957	 * @returns {object} Object with two parameters: `data` the data read, in
2958	 *   document order, and `cells` and array of nodes (they can be useful to the
2959	 *   caller, so rather than needing a second traversal to get them, just return
2960	 *   them from here).
2961	 * @memberof DataTable#oApi
2962	 */
2963	function _fnGetRowElements( settings, row, colIdx, d )
2964	{
2965		var
2966			tds = [],
2967			td = row.firstChild,
2968			name, col, i=0, contents,
2969			columns = settings.aoColumns,
2970			objectRead = settings._rowReadObject;
2971	
2972		// Allow the data object to be passed in, or construct
2973		d = d !== undefined ?
2974			d :
2975			objectRead ?
2976				{} :
2977				[];
2978	
2979		var attr = function ( str, td  ) {
2980			if ( typeof str === 'string' ) {
2981				var idx = str.indexOf('@');
2982	
2983				if ( idx !== -1 ) {
2984					var attr = str.substring( idx+1 );
2985					var setter = _fnSetObjectDataFn( str );
2986					setter( d, td.getAttribute( attr ) );
2987				}
2988			}
2989		};
2990	
2991		// Read data from a cell and store into the data object
2992		var cellProcess = function ( cell ) {
2993			if ( colIdx === undefined || colIdx === i ) {
2994				col = columns[i];
2995				contents = (cell.innerHTML).trim();
2996	
2997				if ( col && col._bAttrSrc ) {
2998					var setter = _fnSetObjectDataFn( col.mData._ );
2999					setter( d, contents );
3000	
3001					attr( col.mData.sort, cell );
3002					attr( col.mData.type, cell );
3003					attr( col.mData.filter, cell );
3004				}
3005				else {
3006					// Depending on the `data` option for the columns the data can
3007					// be read to either an object or an array.
3008					if ( objectRead ) {
3009						if ( ! col._setter ) {
3010							// Cache the setter function
3011							col._setter = _fnSetObjectDataFn( col.mData );
3012						}
3013						col._setter( d, contents );
3014					}
3015					else {
3016						d[i] = contents;
3017					}
3018				}
3019			}
3020	
3021			i++;
3022		};
3023	
3024		if ( td ) {
3025			// `tr` element was passed in
3026			while ( td ) {
3027				name = td.nodeName.toUpperCase();
3028	
3029				if ( name == "TD" || name == "TH" ) {
3030					cellProcess( td );
3031					tds.push( td );
3032				}
3033	
3034				td = td.nextSibling;
3035			}
3036		}
3037		else {
3038			// Existing row object passed in
3039			tds = row.anCells;
3040	
3041			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3042				cellProcess( tds[j] );
3043			}
3044		}
3045	
3046		// Read the ID from the DOM if present
3047		var rowNode = row.firstChild ? row : row.nTr;
3048	
3049		if ( rowNode ) {
3050			var id = rowNode.getAttribute( 'id' );
3051	
3052			if ( id ) {
3053				_fnSetObjectDataFn( settings.rowId )( d, id );
3054			}
3055		}
3056	
3057		return {
3058			data: d,
3059			cells: tds
3060		};
3061	}
3062	
3063	/**
3064	 * Render and cache a row's display data for the columns, if required
3065	 * @returns 
3066	 */
3067	function _fnGetRowDisplay (settings, rowIdx) {
3068		var rowModal = settings.aoData[rowIdx];
3069		var columns = settings.aoColumns;
3070	
3071		if (! rowModal.displayData) {
3072			// Need to render and cache
3073			rowModal.displayData = [];
3074		
3075			for ( var colIdx=0, len=columns.length ; colIdx<len ; colIdx++ ) {
3076				rowModal.displayData.push(
3077					_fnGetCellData( settings, rowIdx, colIdx, 'display' )
3078				);
3079			}
3080		}
3081	
3082		return rowModal.displayData;
3083	}
3084	
3085	/**
3086	 * Create a new TR element (and it's TD children) for a row
3087	 *  @param {object} oSettings dataTables settings object
3088	 *  @param {int} iRow Row to consider
3089	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3090	 *    DataTables will create a row automatically
3091	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
3092	 *    if nTr is.
3093	 *  @memberof DataTable#oApi
3094	 */
3095	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3096	{
3097		var
3098			row = oSettings.aoData[iRow],
3099			rowData = row._aData,
3100			cells = [],
3101			nTr, nTd, oCol,
3102			i, iLen, create,
3103			trClass = oSettings.oClasses.tbody.row;
3104	
3105		if ( row.nTr === null )
3106		{
3107			nTr = nTrIn || document.createElement('tr');
3108	
3109			row.nTr = nTr;
3110			row.anCells = cells;
3111	
3112			_addClass(nTr, trClass);
3113	
3114			/* Use a private property on the node to allow reserve mapping from the node
3115			 * to the aoData array for fast look up
3116			 */
3117			nTr._DT_RowIndex = iRow;
3118	
3119			/* Special parameters can be given by the data source to be used on the row */
3120			_fnRowAttributes( oSettings, row );
3121	
3122			/* Process each column */
3123			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3124			{
3125				oCol = oSettings.aoColumns[i];
3126				create = nTrIn && anTds[i] ? false : true;
3127	
3128				nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
3129	
3130				if (! nTd) {
3131					_fnLog( oSettings, 0, 'Incorrect column count', 18 );
3132				}
3133	
3134				nTd._DT_CellIndex = {
3135					row: iRow,
3136					column: i
3137				};
3138				
3139				cells.push( nTd );
3140				
3141				var display = _fnGetRowDisplay(oSettings, iRow);
3142	
3143				// Need to create the HTML if new, or if a rendering function is defined
3144				if (
3145					create ||
3146					(
3147						(oCol.mRender || oCol.mData !== i) &&
3148						(!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3149					)
3150				) {
3151					_fnWriteCell(nTd, display[i]);
3152				}
3153	
3154				// column class
3155				_addClass(nTd, oCol.sClass);
3156	
3157				// Visibility - add or remove as required
3158				if ( oCol.bVisible && create )
3159				{
3160					nTr.appendChild( nTd );
3161				}
3162				else if ( ! oCol.bVisible && ! create )
3163				{
3164					nTd.parentNode.removeChild( nTd );
3165				}
3166	
3167				if ( oCol.fnCreatedCell )
3168				{
3169					oCol.fnCreatedCell.call( oSettings.oInstance,
3170						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3171					);
3172				}
3173			}
3174	
3175			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells] );
3176		}
3177		else {
3178			_addClass(row.nTr, trClass);
3179		}
3180	}
3181	
3182	
3183	/**
3184	 * Add attributes to a row based on the special `DT_*` parameters in a data
3185	 * source object.
3186	 *  @param {object} settings DataTables settings object
3187	 *  @param {object} DataTables row object for the row to be modified
3188	 *  @memberof DataTable#oApi
3189	 */
3190	function _fnRowAttributes( settings, row )
3191	{
3192		var tr = row.nTr;
3193		var data = row._aData;
3194	
3195		if ( tr ) {
3196			var id = settings.rowIdFn( data );
3197	
3198			if ( id ) {
3199				tr.id = id;
3200			}
3201	
3202			if ( data.DT_RowClass ) {
3203				// Remove any classes added by DT_RowClass before
3204				var a = data.DT_RowClass.split(' ');
3205				row.__rowc = row.__rowc ?
3206					_unique( row.__rowc.concat( a ) ) :
3207					a;
3208	
3209				$(tr)
3210					.removeClass( row.__rowc.join(' ') )
3211					.addClass( data.DT_RowClass );
3212			}
3213	
3214			if ( data.DT_RowAttr ) {
3215				$(tr).attr( data.DT_RowAttr );
3216			}
3217	
3218			if ( data.DT_RowData ) {
3219				$(tr).data( data.DT_RowData );
3220			}
3221		}
3222	}
3223	
3224	
3225	/**
3226	 * Create the HTML header for the table
3227	 *  @param {object} oSettings dataTables settings object
3228	 *  @memberof DataTable#oApi
3229	 */
3230	function _fnBuildHead( settings, side )
3231	{
3232		var classes = settings.oClasses;
3233		var columns = settings.aoColumns;
3234		var i, ien, row;
3235		var target = side === 'header'
3236			? settings.nTHead
3237			: settings.nTFoot;
3238		var titleProp = side === 'header' ? 'sTitle' : side;
3239	
3240		// Footer might be defined
3241		if (! target) {
3242			return;
3243		}
3244	
3245		// If no cells yet and we have content for them, then create
3246		if (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) {
3247			row = $('tr', target);
3248	
3249			// Add a row if needed
3250			if (! row.length) {
3251				row = $('<tr/>').appendTo(target)
3252			}
3253	
3254			// Add the number of cells needed to make up to the number of columns
3255			if (row.length === 1) {
3256				var cellCount = 0;
3257				
3258				$('td, th', row).each(function () {
3259					cellCount += this.colSpan;
3260				});
3261	
3262				for ( i=cellCount, ien=columns.length ; i<ien ; i++ ) {
3263					$('<th/>')
3264						.html( columns[i][titleProp] || '' )
3265						.appendTo( row );
3266				}
3267			}
3268		}
3269	
3270		var detected = _fnDetectHeader( settings, target, true );
3271	
3272		if (side === 'header') {
3273			settings.aoHeader = detected;
3274			$('tr', target).addClass(classes.thead.row);
3275		}
3276		else {
3277			settings.aoFooter = detected;
3278			$('tr', target).addClass(classes.tfoot.row);
3279		}
3280	
3281		// Every cell needs to be passed through the renderer
3282		$(target).children('tr').children('th, td')
3283			.each( function () {
3284				_fnRenderer( settings, side )(
3285					settings, $(this), classes
3286				);
3287			} );
3288	}
3289	
3290	/**
3291	 * Build a layout structure for a header or footer
3292	 *
3293	 * @param {*} settings DataTables settings
3294	 * @param {*} source Source layout array
3295	 * @param {*} incColumns What columns should be included
3296	 * @returns Layout array in column index order
3297	 */
3298	function _fnHeaderLayout( settings, source, incColumns )
3299	{
3300		var row, column, cell;
3301		var local = [];
3302		var structure = [];
3303		var columns = settings.aoColumns;
3304		var columnCount = columns.length;
3305		var rowspan, colspan;
3306	
3307		if ( ! source ) {
3308			return;
3309		}
3310	
3311		// Default is to work on only visible columns
3312		if ( ! incColumns ) {
3313			incColumns = _range(columnCount)
3314				.filter(function (idx) {
3315					return columns[idx].bVisible;
3316				});
3317		}
3318	
3319		// Make a copy of the master layout array, but with only the columns we want
3320		for ( row=0 ; row<source.length ; row++ ) {
3321			// Remove any columns we haven't selected
3322			local[row] = source[row].slice().filter(function (cell, i) {
3323				return incColumns.includes(i);
3324			});
3325	
3326			// Prep the structure array - it needs an element for each row
3327			structure.push( [] );
3328		}
3329	
3330		for ( row=0 ; row<local.length ; row++ ) {
3331			for ( column=0 ; column<local[row].length ; column++ ) {
3332				rowspan = 1;
3333				colspan = 1;
3334	
3335				// Check to see if there is already a cell (row/colspan) covering our target
3336				// insert point. If there is, then there is nothing to do.
3337				if ( structure[row][column] === undefined ) {
3338					cell = local[row][column].cell;
3339	
3340					// Expand for rowspan
3341					while (
3342						local[row+rowspan] !== undefined &&
3343						local[row][column].cell == local[row+rowspan][column].cell
3344					) {
3345						structure[row+rowspan][column] = null;
3346						rowspan++;
3347					}
3348	
3349					// And for colspan
3350					while (
3351						local[row][column+colspan] !== undefined &&
3352						local[row][column].cell == local[row][column+colspan].cell
3353					) {
3354						// Which also needs to go over rows
3355						for ( var k=0 ; k<rowspan ; k++ ) {
3356							structure[row+k][column+colspan] = null;
3357						}
3358	
3359						colspan++;
3360					}
3361	
3362					var titleSpan = $('span.dt-column-title', cell);
3363	
3364					structure[row][column] = {
3365						cell: cell,
3366						colspan: colspan,
3367						rowspan: rowspan,
3368						title: titleSpan.length
3369							? titleSpan.html()
3370							: $(cell).html()
3371					};
3372				}
3373			}
3374		}
3375	
3376		return structure;
3377	}
3378	
3379	
3380	/**
3381	 * Draw the header (or footer) element based on the column visibility states.
3382	 *
3383	 *  @param object oSettings dataTables settings object
3384	 *  @param array aoSource Layout array from _fnDetectHeader
3385	 *  @memberof DataTable#oApi
3386	 */
3387	function _fnDrawHead( settings, source )
3388	{
3389		var layout = _fnHeaderLayout(settings, source);
3390		var tr, n;
3391	
3392		for ( var row=0 ; row<source.length ; row++ ) {
3393			tr = source[row].row;
3394	
3395			// All cells are going to be replaced, so empty out the row
3396			// Can't use $().empty() as that kills event handlers
3397			if (tr) {
3398				while( (n = tr.firstChild) ) {
3399					tr.removeChild( n );
3400				}
3401			}
3402	
3403			for ( var column=0 ; column<layout[row].length ; column++ ) {
3404				var point = layout[row][column];
3405	
3406				if (point) {
3407					$(point.cell)
3408						.appendTo(tr)
3409						.attr('rowspan', point.rowspan)
3410						.attr('colspan', point.colspan);
3411				}
3412			}
3413		}
3414	}
3415	
3416	
3417	/**
3418	 * Insert the required TR nodes into the table for display
3419	 *  @param {object} oSettings dataTables settings object
3420	 *  @param ajaxComplete true after ajax call to complete rendering
3421	 *  @memberof DataTable#oApi
3422	 */
3423	function _fnDraw( oSettings, ajaxComplete )
3424	{
3425		// Allow for state saving and a custom start position
3426		_fnStart( oSettings );
3427	
3428		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3429		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3430		if ( aPreDraw.indexOf(false) !== -1 )
3431		{
3432			_fnProcessingDisplay( oSettings, false );
3433			return;
3434		}
3435	
3436		var anRows = [];
3437		var iRowCount = 0;
3438		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3439		var aiDisplay = oSettings.aiDisplay;
3440		var iDisplayStart = oSettings._iDisplayStart;
3441		var iDisplayEnd = oSettings.fnDisplayEnd();
3442		var columns = oSettings.aoColumns;
3443		var body = $(oSettings.nTBody);
3444	
3445		oSettings.bDrawing = true;
3446	
3447		/* Server-side processing draw intercept */
3448		if ( oSettings.deferLoading )
3449		{
3450			oSettings.deferLoading = false;
3451			oSettings.iDraw++;
3452			_fnProcessingDisplay( oSettings, false );
3453		}
3454		else if ( !bServerSide )
3455		{
3456			oSettings.iDraw++;
3457		}
3458		else if ( !oSettings.bDestroying && !ajaxComplete)
3459		{
3460			// Show loading message for server-side processing
3461			if (oSettings.iDraw === 0) {
3462				body.empty().append(_emptyRow(oSettings));
3463			}
3464	
3465			_fnAjaxUpdate( oSettings );
3466			return;
3467		}
3468	
3469		if ( aiDisplay.length !== 0 )
3470		{
3471			var iStart = bServerSide ? 0 : iDisplayStart;
3472			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3473	
3474			for ( var j=iStart ; j<iEnd ; j++ )
3475			{
3476				var iDataIndex = aiDisplay[j];
3477				var aoData = oSettings.aoData[ iDataIndex ];
3478				if ( aoData.nTr === null )
3479				{
3480					_fnCreateTr( oSettings, iDataIndex );
3481				}
3482	
3483				var nRow = aoData.nTr;
3484	
3485				// Add various classes as needed
3486				for (var i=0 ; i<columns.length ; i++) {
3487					var col = columns[i];
3488					var td = aoData.anCells[i];
3489	
3490					_addClass(td, _ext.type.className[col.sType]); // auto class
3491					_addClass(td, oSettings.oClasses.tbody.cell); // all cells
3492				}
3493	
3494				// Row callback functions - might want to manipulate the row
3495				// iRowCount and j are not currently documented. Are they at all
3496				// useful?
3497				_fnCallbackFire( oSettings, 'aoRowCallback', null,
3498					[nRow, aoData._aData, iRowCount, j, iDataIndex] );
3499	
3500				anRows.push( nRow );
3501				iRowCount++;
3502			}
3503		}
3504		else
3505		{
3506			anRows[ 0 ] = _emptyRow(oSettings);
3507		}
3508	
3509		/* Header and footer callbacks */
3510		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3511			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3512	
3513		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3514			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3515	
3516		// replaceChildren is faster, but only became widespread in 2020,
3517		// so a fall back in jQuery is provided for older browsers.
3518		if (body[0].replaceChildren) {
3519			body[0].replaceChildren.apply(body[0], anRows);
3520		}
3521		else {
3522			body.children().detach();
3523			body.append( $(anRows) );
3524		}
3525	
3526		// Empty table needs a specific class
3527		$(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
3528	
3529		/* Call all required callback functions for the end of a draw */
3530		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings], true );
3531	
3532		/* Draw is complete, sorting and filtering must be as well */
3533		oSettings.bSorted = false;
3534		oSettings.bFiltered = false;
3535		oSettings.bDrawing = false;
3536	}
3537	
3538	
3539	/**
3540	 * Redraw the table - taking account of the various features which are enabled
3541	 *  @param {object} oSettings dataTables settings object
3542	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
3543	 *    the paging is reset to the first page
3544	 *  @memberof DataTable#oApi
3545	 */
3546	function _fnReDraw( settings, holdPosition, recompute )
3547	{
3548		var
3549			features = settings.oFeatures,
3550			sort     = features.bSort,
3551			filter   = features.bFilter;
3552	
3553		if (recompute === undefined || recompute === true) {
3554			// Resolve any column types that are unknown due to addition or invalidation
3555			_fnColumnTypes( settings );
3556	
3557			if ( sort ) {
3558				_fnSort( settings );
3559			}
3560	
3561			if ( filter ) {
3562				_fnFilterComplete( settings, settings.oPreviousSearch );
3563			}
3564			else {
3565				// No filtering, so we want to just use the display master
3566				settings.aiDisplay = settings.aiDisplayMaster.slice();
3567			}
3568		}
3569	
3570		if ( holdPosition !== true ) {
3571			settings._iDisplayStart = 0;
3572		}
3573	
3574		// Let any modules know about the draw hold position state (used by
3575		// scrolling internally)
3576		settings._drawHold = holdPosition;
3577	
3578		_fnDraw( settings );
3579	
3580		settings.api.one('draw', function () {
3581			settings._drawHold = false;
3582		});
3583	}
3584	
3585	
3586	/*
3587	 * Table is empty - create a row with an empty message in it
3588	 */
3589	function _emptyRow ( settings ) {
3590		var oLang = settings.oLanguage;
3591		var zero = oLang.sZeroRecords;
3592		var dataSrc = _fnDataSource( settings );
3593	
3594		// Make use of the fact that settings.json is only set once the initial data has
3595		// been loaded. Show loading when that isn't the case
3596		if ((dataSrc === 'ssp' || dataSrc === 'ajax') && ! settings.json) {
3597			zero = oLang.sLoadingRecords;
3598		}
3599		else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
3600		{
3601			zero = oLang.sEmptyTable;
3602		}
3603	
3604		return $( '<tr/>' )
3605			.append( $('<td />', {
3606				'colSpan': _fnVisbleColumns( settings ),
3607				'class':   settings.oClasses.empty.row
3608			} ).html( zero ) )[0];
3609	}
3610	
3611	
3612	/**
3613	 * Expand the layout items into an object for the rendering function
3614	 */
3615	function _layoutItems (row, align, items) {
3616		if ( Array.isArray(items)) {
3617			for (var i=0 ; i<items.length ; i++) {
3618				_layoutItems(row, align, items[i]);
3619			}
3620	
3621			return;
3622		}
3623	
3624		var rowCell = row[align];
3625	
3626		// If it is an object, then there can be multiple features contained in it
3627		if ( $.isPlainObject( items ) ) {
3628			// A feature plugin cannot be named "features" due to this check
3629			if (items.features) {
3630				if (items.rowId) {
3631					row.id = items.rowId;
3632				}
3633				if (items.rowClass) {
3634					row.className = items.rowClass;
3635				}
3636	
3637				rowCell.id = items.id;
3638				rowCell.className = items.className;
3639	
3640				_layoutItems(row, align, items.features);
3641			}
3642			else {
3643				Object.keys(items).map(function (key) {
3644					rowCell.contents.push( {
3645						feature: key,
3646						opts: items[key]
3647					});
3648				});
3649			}
3650		}
3651		else {
3652			rowCell.contents.push(items);
3653		}
3654	}
3655	
3656	/**
3657	 * Find, or create a layout row
3658	 */
3659	function _layoutGetRow(rows, rowNum, align) {
3660		var row;
3661	
3662		// Find existing rows
3663		for (var i=0; i<rows.length; i++) {
3664			row = rows[i];
3665	
3666			if (row.rowNum === rowNum) {
3667				// full is on its own, but start and end share a row
3668				if (
3669					(align === 'full' && row.full) ||
3670					((align === 'start' || align === 'end') && (row.start || row.end))
3671				) {
3672					if (! row[align]) {
3673						row[align] = {
3674							contents: []
3675						};
3676					}
3677	
3678					return row;
3679				}
3680			}
3681		}
3682	
3683		// If we get this far, then there was no match, create a new row
3684		row = {
3685			rowNum: rowNum	
3686		};
3687	
3688		row[align] = {
3689			contents: []
3690		};
3691	
3692		rows.push(row);
3693	
3694		return row;
3695	}
3696	
3697	/**
3698	 * Convert a `layout` object given by a user to the object structure needed
3699	 * for the renderer. This is done twice, once for above and once for below
3700	 * the table. Ordering must also be considered.
3701	 *
3702	 * @param {*} settings DataTables settings object
3703	 * @param {*} layout Layout object to convert
3704	 * @param {string} side `top` or `bottom`
3705	 * @returns Converted array structure - one item for each row.
3706	 */
3707	function _layoutArray ( settings, layout, side ) {
3708		var rows = [];
3709		
3710		// Split out into an array
3711		$.each( layout, function ( pos, items ) {
3712			if (items === null) {
3713				return;
3714			}
3715	
3716			var parts = pos.match(/^([a-z]+)([0-9]*)([A-Za-z]*)$/);
3717			var rowNum = parts[2]
3718				? parts[2] * 1
3719				: 0;
3720			var align = parts[3]
3721				? parts[3].toLowerCase()
3722				: 'full';
3723	
3724			// Filter out the side we aren't interested in
3725			if (parts[1] !== side) {
3726				return;
3727			}
3728	
3729			// Get or create the row we should attach to
3730			var row = _layoutGetRow(rows, rowNum, align);
3731	
3732			_layoutItems(row, align, items);
3733		});
3734	
3735		// Order by item identifier
3736		rows.sort( function ( a, b ) {
3737			var order1 = a.rowNum;
3738			var order2 = b.rowNum;
3739	
3740			// If both in the same row, then the row with `full` comes first
3741			if (order1 === order2) {
3742				var ret = a.full && ! b.full ? -1 : 1;
3743	
3744				return side === 'bottom'
3745					? ret * -1
3746					: ret;
3747			}
3748	
3749			return order2 - order1;
3750		} );
3751	
3752		// Invert for below the table
3753		if ( side === 'bottom' ) {
3754			rows.reverse();
3755		}
3756	
3757		for (var row = 0; row<rows.length; row++) {
3758			delete rows[row].rowNum;
3759	
3760			_layoutResolve(settings, rows[row]);
3761		}
3762	
3763		return rows;
3764	}
3765	
3766	
3767	/**
3768	 * Convert the contents of a row's layout object to nodes that can be inserted
3769	 * into the document by a renderer. Execute functions, look up plug-ins, etc.
3770	 *
3771	 * @param {*} settings DataTables settings object
3772	 * @param {*} row Layout object for this row
3773	 */
3774	function _layoutResolve( settings, row ) {
3775		var getFeature = function (feature, opts) {
3776			if ( ! _ext.features[ feature ] ) {
3777				_fnLog( settings, 0, 'Unknown feature: '+ feature );
3778			}
3779	
3780			return _ext.features[ feature ].apply( this, [settings, opts] );
3781		};
3782	
3783		var resolve = function ( item ) {
3784			if (! row[ item ]) {
3785				return;
3786			}
3787	
3788			var line = row[ item ].contents;
3789	
3790			for ( var i=0, ien=line.length ; i<ien ; i++ ) {
3791				if ( ! line[i] ) {
3792					continue;
3793				}
3794				else if ( typeof line[i] === 'string' ) {
3795					line[i] = getFeature( line[i], null );
3796				}
3797				else if ( $.isPlainObject(line[i]) ) {
3798					// If it's an object, it just has feature and opts properties from
3799					// the transform in _layoutArray
3800					line[i] = getFeature(line[i].feature, line[i].opts);
3801				}
3802				else if ( typeof line[i].node === 'function' ) {
3803					line[i] = line[i].node( settings );
3804				}
3805				else if ( typeof line[i] === 'function' ) {
3806					var inst = line[i]( settings );
3807	
3808					line[i] = typeof inst.node === 'function' ?
3809						inst.node() :
3810						inst;
3811				}
3812			}
3813		};
3814	
3815		resolve('start');
3816		resolve('end');
3817		resolve('full');
3818	}
3819	
3820	
3821	/**
3822	 * Add the options to the page HTML for the table
3823	 *  @param {object} settings DataTables settings object
3824	 *  @memberof DataTable#oApi
3825	 */
3826	function _fnAddOptionsHtml ( settings )
3827	{
3828		var classes = settings.oClasses;
3829		var table = $(settings.nTable);
3830	
3831		// Wrapper div around everything DataTables controls
3832		var insert = $('<div/>')
3833			.attr({
3834				id:      settings.sTableId+'_wrapper',
3835				'class': classes.container
3836			})
3837			.insertBefore(table);
3838	
3839		settings.nTableWrapper = insert[0];
3840	
3841		if (settings.sDom) {
3842			// Legacy
3843			_fnLayoutDom(settings, settings.sDom, insert);
3844		}
3845		else {
3846			var top = _layoutArray( settings, settings.layout, 'top' );
3847			var bottom = _layoutArray( settings, settings.layout, 'bottom' );
3848			var renderer = _fnRenderer( settings, 'layout' );
3849		
3850			// Everything above - the renderer will actually insert the contents into the document
3851			top.forEach(function (item) {
3852				renderer( settings, insert, item );
3853			});
3854	
3855			// The table - always the center of attention
3856			renderer( settings, insert, {
3857				full: {
3858					table: true,
3859					contents: [ _fnFeatureHtmlTable(settings) ]
3860				}
3861			} );
3862	
3863			// Everything below
3864			bottom.forEach(function (item) {
3865				renderer( settings, insert, item );
3866			});
3867		}
3868	
3869		// Processing floats on top, so it isn't an inserted feature
3870		_processingHtml( settings );
3871	}
3872	
3873	/**
3874	 * Draw the table with the legacy DOM property
3875	 * @param {*} settings DT settings object
3876	 * @param {*} dom DOM string
3877	 * @param {*} insert Insert point
3878	 */
3879	function _fnLayoutDom( settings, dom, insert )
3880	{
3881		var parts = dom.match(/(".*?")|('.*?')|./g);
3882		var featureNode, option, newNode, next, attr;
3883	
3884		for ( var i=0 ; i<parts.length ; i++ ) {
3885			featureNode = null;
3886			option = parts[i];
3887	
3888			if ( option == '<' ) {
3889				// New container div
3890				newNode = $('<div/>');
3891	
3892				// Check to see if we should append an id and/or a class name to the container
3893				next = parts[i+1];
3894	
3895				if ( next[0] == "'" || next[0] == '"' ) {
3896					attr = next.replace(/['"]/g, '');
3897	
3898					var id = '', className;
3899	
3900					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3901					 * breaks the string into parts and applies them as needed
3902					 */
3903					if ( attr.indexOf('.') != -1 ) {
3904						var split = attr.split('.');
3905	
3906						id = split[0];
3907						className = split[1];
3908					}
3909					else if ( attr[0] == "#" ) {
3910						id = attr;
3911					}
3912					else {
3913						className = attr;
3914					}
3915	
3916					newNode
3917						.attr('id', id.substring(1))
3918						.addClass(className);
3919	
3920					i++; // Move along the position array
3921				}
3922	
3923				insert.append( newNode );
3924				insert = newNode;
3925			}
3926			else if ( option == '>' ) {
3927				// End container div
3928				insert = insert.parent();
3929			}
3930			else if ( option == 't' ) {
3931				// Table
3932				featureNode = _fnFeatureHtmlTable( settings );
3933			}
3934			else
3935			{
3936				DataTable.ext.feature.forEach(function(feature) {
3937					if ( option == feature.cFeature ) {
3938						featureNode = feature.fnInit( settings );
3939					}
3940				});
3941			}
3942	
3943			// Add to the display
3944			if ( featureNode ) {
3945				insert.append( featureNode );
3946			}
3947		}
3948	}
3949	
3950	
3951	/**
3952	 * Use the DOM source to create up an array of header cells. The idea here is to
3953	 * create a layout grid (array) of rows x columns, which contains a reference
3954	 * to the cell that that point in the grid (regardless of col/rowspan), such that
3955	 * any column / row could be removed and the new grid constructed
3956	 *  @param {node} thead The header/footer element for the table
3957	 *  @returns {array} Calculated layout array
3958	 *  @memberof DataTable#oApi
3959	 */
3960	function _fnDetectHeader ( settings, thead, write )
3961	{
3962		var columns = settings.aoColumns;
3963		var rows = $(thead).children('tr');
3964		var row, cell;
3965		var i, k, l, iLen, shifted, column, colspan, rowspan;
3966		var titleRow = settings.titleRow;
3967		var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3968		var layout = [];
3969		var unique;
3970		var shift = function ( a, i, j ) {
3971			var k = a[i];
3972			while ( k[j] ) {
3973				j++;
3974			}
3975			return j;
3976		};
3977	
3978		// We know how many rows there are in the layout - so prep it
3979		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3980			layout.push( [] );
3981		}
3982	
3983		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3984			row = rows[i];
3985			column = 0;
3986	
3987			// For every cell in the row..
3988			cell = row.firstChild;
3989			while ( cell ) {
3990				if (
3991					cell.nodeName.toUpperCase() == 'TD' ||
3992					cell.nodeName.toUpperCase() == 'TH'
3993				) {
3994					var cols = [];
3995					var jqCell = $(cell);
3996	
3997					// Get the col and rowspan attributes from the DOM and sanitise them
3998					colspan = cell.getAttribute('colspan') * 1;
3999					rowspan = cell.getAttribute('rowspan') * 1;
4000					colspan = (!colspan || colspan===0 || colspan===1) ? 1 : colspan;
4001					rowspan = (!rowspan || rowspan===0 || rowspan===1) ? 1 : rowspan;
4002	
4003					// There might be colspan cells already in this row, so shift our target
4004					// accordingly
4005					shifted = shift( layout, i, column );
4006	
4007					// Cache calculation for unique columns
4008					unique = colspan === 1 ?
4009						true :
4010						false;
4011					
4012					// Perform header setup
4013					if ( write ) {
4014						if (unique) {
4015							// Allow column options to be set from HTML attributes
4016							_fnColumnOptions( settings, shifted, jqCell.data() );
4017							
4018							// Get the width for the column. This can be defined from the
4019							// width attribute, style attribute or `columns.width` option
4020							var columnDef = columns[shifted];
4021							var width = cell.getAttribute('width') || null;
4022							var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
4023							if ( t ) {
4024								width = t[1];
4025							}
4026	
4027							columnDef.sWidthOrig = columnDef.sWidth || width;
4028	
4029							if (isHeader) {
4030								// Column title handling - can be user set, or read from the DOM
4031								// This happens before the render, so the original is still in place
4032								if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
4033									if (
4034										(titleRow === true && i === 0) || // top row
4035										(titleRow === false && i === rows.length -1) || // bottom row
4036										(titleRow === i) || // specific row
4037										(titleRow === null)
4038									) {
4039										cell.innerHTML = columnDef.sTitle;
4040									}
4041								}
4042	
4043								if (! columnDef.sTitle && unique) {
4044									columnDef.sTitle = _stripHtml(cell.innerHTML);
4045									columnDef.autoTitle = true;
4046								}
4047							}
4048							else {
4049								// Footer specific operations
4050								if (columnDef.footer) {
4051									cell.innerHTML = columnDef.footer;
4052								}
4053							}
4054	
4055							// Fall back to the aria-label attribute on the table header if no ariaTitle is
4056							// provided.
4057							if (! columnDef.ariaTitle) {
4058								columnDef.ariaTitle = jqCell.attr("aria-label") || columnDef.sTitle;
4059							}
4060	
4061							// Column specific class names
4062							if ( columnDef.className ) {
4063								jqCell.addClass( columnDef.className );
4064							}
4065						}
4066	
4067						// Wrap the column title so we can write to it in future
4068						if ( $('span.dt-column-title', cell).length === 0) {
4069							$('<span>')
4070								.addClass('dt-column-title')
4071								.append(cell.childNodes)
4072								.appendTo(cell);
4073						}
4074	
4075						if (
4076							settings.orderIndicators &&
4077							isHeader &&
4078							jqCell.filter(':not([data-dt-order=disable])').length !== 0 &&
4079							jqCell.parent(':not([data-dt-order=disable])').length !== 0 &&
4080							$('span.dt-column-order', cell).length === 0
4081						) {
4082							$('<span>')
4083								.addClass('dt-column-order')
4084								.appendTo(cell);
4085						}
4086	
4087						// We need to wrap the elements in the header in another element to use flexbox
4088						// layout for those elements
4089						var headerFooter = isHeader ? 'header' : 'footer';
4090	
4091						if ( $('span.dt-column-' + headerFooter, cell).length === 0) {
4092							$('<div>')
4093								.addClass('dt-column-' + headerFooter)
4094								.append(cell.childNodes)
4095								.appendTo(cell);
4096						}
4097					}
4098	
4099					// If there is col / rowspan, copy the information into the layout grid
4100					for ( l=0 ; l<colspan ; l++ ) {
4101						for ( k=0 ; k<rowspan ; k++ ) {
4102							layout[i+k][shifted+l] = {
4103								cell: cell,
4104								unique: unique
4105							};
4106	
4107							layout[i+k].row = row;
4108						}
4109	
4110						cols.push( shifted+l );
4111					}
4112	
4113					// Assign an attribute so spanning cells can still be identified
4114					// as belonging to a column
4115					cell.setAttribute('data-dt-column', _unique(cols).join(','));
4116				}
4117	
4118				cell = cell.nextSibling;
4119			}
4120		}
4121	
4122		return layout;
4123	}
4124	
4125	/**
4126	 * Set the start position for draw
4127	 *  @param {object} oSettings dataTables settings object
4128	 */
4129	function _fnStart( oSettings )
4130	{
4131		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
4132		var iInitDisplayStart = oSettings.iInitDisplayStart;
4133	
4134		// Check and see if we have an initial draw position from state saving
4135		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
4136		{
4137			oSettings._iDisplayStart = bServerSide ?
4138				iInitDisplayStart :
4139				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
4140					0 :
4141					iInitDisplayStart;
4142	
4143			oSettings.iInitDisplayStart = -1;
4144		}
4145	}
4146	
4147	/**
4148	 * Create an Ajax call based on the table's settings, taking into account that
4149	 * parameters can have multiple forms, and backwards compatibility.
4150	 *
4151	 * @param {object} oSettings dataTables settings object
4152	 * @param {array} data Data to send to the server, required by
4153	 *     DataTables - may be augmented by developer callbacks
4154	 * @param {function} fn Callback function to run when data is obtained
4155	 */
4156	function _fnBuildAjax( oSettings, data, fn )
4157	{
4158		var ajaxData;
4159		var ajax = oSettings.ajax;
4160		var instance = oSettings.oInstance;
4161		var callback = function ( json ) {
4162			var status = oSettings.jqXHR
4163				? oSettings.jqXHR.status
4164				: null;
4165	
4166			if ( json === null || (typeof status === 'number' && status == 204 ) ) {
4167				json = {};
4168				_fnAjaxDataSrc( oSettings, json, [] );
4169			}
4170	
4171			var error = json.error || json.sError;
4172			if ( error ) {
4173				_fnLog( oSettings, 0, error );
4174			}
4175	
4176			// Microsoft often wrap JSON as a string in another JSON object
4177			// Let's handle that automatically
4178			if (json.d && typeof json.d === 'string') {
4179				try {
4180					json = JSON.parse(json.d);
4181				}
4182				catch (e) {
4183					// noop
4184				}
4185			}
4186	
4187			oSettings.json = json;
4188	
4189			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
4190			fn( json );
4191		};
4192	
4193		if ( $.isPlainObject( ajax ) && ajax.data )
4194		{
4195			ajaxData = ajax.data;
4196	
4197			var newData = typeof ajaxData === 'function' ?
4198				ajaxData( data, oSettings ) :  // fn can manipulate data or return
4199				ajaxData;                      // an object object or array to merge
4200	
4201			// If the function returned something, use that alone
4202			data = typeof ajaxData === 'function' && newData ?
4203				newData :
4204				$.extend( true, data, newData );
4205	
4206			// Remove the data property as we've resolved it already and don't want
4207			// jQuery to do it again (it is restored at the end of the function)
4208			delete ajax.data;
4209		}
4210	
4211		var baseAjax = {
4212			"url": typeof ajax === 'string' ?
4213				ajax :
4214				'',
4215			"data": data,
4216			"success": callback,
4217			"dataType": "json",
4218			"cache": false,
4219			"type": oSettings.sServerMethod,
4220			"error": function (xhr, error) {
4221				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
4222	
4223				if ( ret.indexOf(true) === -1 ) {
4224					if ( error == "parsererror" ) {
4225						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
4226					}
4227					else if ( xhr.readyState === 4 ) {
4228						_fnLog( oSettings, 0, 'Ajax error', 7 );
4229					}
4230				}
4231	
4232				_fnProcessingDisplay( oSettings, false );
4233			}
4234		};
4235	
4236		// If `ajax` option is an object, extend and override our default base
4237		if ( $.isPlainObject( ajax ) ) {
4238			$.extend( baseAjax, ajax )
4239		}
4240	
4241		// Store the data submitted for the API
4242		oSettings.oAjaxData = data;
4243	
4244		// Allow plug-ins and external processes to modify the data
4245		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4246	
4247		// Custom Ajax option to submit the parameters as a JSON string
4248		if (baseAjax.submitAs === 'json' && typeof data === 'object') {
4249			baseAjax.data = JSON.stringify(data);
4250		}
4251	
4252		if ( typeof ajax === 'function' )
4253		{
4254			// Is a function - let the caller define what needs to be done
4255			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
4256		}
4257		else if (ajax.url === '') {
4258			// No url, so don't load any data. Just apply an empty data array
4259			// to the object for the callback.
4260			var empty = {};
4261	
4262			DataTable.util.set(ajax.dataSrc)(empty, []);
4263			callback(empty);
4264		}
4265		else {
4266			// Object to extend the base settings
4267			oSettings.jqXHR = $.ajax( baseAjax );
4268		}
4269	
4270		// Restore for next time around
4271		if ( ajaxData ) {
4272			ajax.data = ajaxData;
4273		}
4274	}
4275	
4276	
4277	/**
4278	 * Update the table using an Ajax call
4279	 *  @param {object} settings dataTables settings object
4280	 *  @returns {boolean} Block the table drawing or not
4281	 *  @memberof DataTable#oApi
4282	 */
4283	function _fnAjaxUpdate( settings )
4284	{
4285		settings.iDraw++;
4286		_fnProcessingDisplay( settings, true );
4287	
4288		_fnBuildAjax(
4289			settings,
4290			_fnAjaxParameters( settings ),
4291			function(json) {
4292				_fnAjaxUpdateDraw( settings, json );
4293			}
4294		);
4295	}
4296	
4297	
4298	/**
4299	 * Build up the parameters in an object needed for a server-side processing
4300	 * request.
4301	 *  @param {object} oSettings dataTables settings object
4302	 *  @returns {bool} block the table drawing or not
4303	 *  @memberof DataTable#oApi
4304	 */
4305	function _fnAjaxParameters( settings )
4306	{
4307		var
4308			columns = settings.aoColumns,
4309			features = settings.oFeatures,
4310			preSearch = settings.oPreviousSearch,
4311			preColSearch = settings.aoPreSearchCols,
4312			colData = function ( idx, prop ) {
4313				return typeof columns[idx][prop] === 'function' ?
4314					'function' :
4315					columns[idx][prop];
4316			};
4317	
4318		return {
4319			draw: settings.iDraw,
4320			columns: columns.map( function ( column, i ) {
4321				return {
4322					data: colData(i, 'mData'),
4323					name: column.sName,
4324					searchable: column.bSearchable,
4325					orderable: column.bSortable,
4326					search: {
4327						value: preColSearch[i].search,
4328						regex: preColSearch[i].regex,
4329						fixed: Object.keys(column.searchFixed).map( function(name) {
4330							return {
4331								name: name,
4332								term: column.searchFixed[name].toString()
4333							}
4334						})
4335					}
4336				};
4337			} ),
4338			order: _fnSortFlatten( settings ).map( function ( val ) {
4339				return {
4340					column: val.col,
4341					dir: val.dir,
4342					name: colData(val.col, 'sName')
4343				};
4344			} ),
4345			start: settings._iDisplayStart,
4346			length: features.bPaginate ?
4347				settings._iDisplayLength :
4348				-1,
4349			search: {
4350				value: preSearch.search,
4351				regex: preSearch.regex,
4352				fixed: Object.keys(settings.searchFixed).map( function(name) {
4353					return {
4354						name: name,
4355						term: settings.searchFixed[name].toString()
4356					}
4357				})
4358			}
4359		};
4360	}
4361	
4362	
4363	/**
4364	 * Data the data from the server (nuking the old) and redraw the table
4365	 *  @param {object} oSettings dataTables settings object
4366	 *  @param {object} json json data return from the server.
4367	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
4368	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4369	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4370	 *  @param {array} json.aaData The data to display on this page
4371	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4372	 *  @memberof DataTable#oApi
4373	 */
4374	function _fnAjaxUpdateDraw ( settings, json )
4375	{
4376		var data = _fnAjaxDataSrc(settings, json);
4377		var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
4378		var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
4379		var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
4380	
4381		if ( draw !== undefined ) {
4382			// Protect against out of sequence returns
4383			if ( draw*1 < settings.iDraw ) {
4384				return;
4385			}
4386			settings.iDraw = draw * 1;
4387		}
4388	
4389		// No data in returned object, so rather than an array, we show an empty table
4390		if ( ! data ) {
4391			data = [];
4392		}
4393	
4394		_fnClearTable( settings );
4395		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
4396		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4397	
4398		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4399			_fnAddData( settings, data[i] );
4400		}
4401		settings.aiDisplay = settings.aiDisplayMaster.slice();
4402	
4403		_fnColumnTypes(settings);
4404		_fnDraw( settings, true );
4405		_fnInitComplete( settings );
4406		_fnProcessingDisplay( settings, false );
4407	}
4408	
4409	
4410	/**
4411	 * Get the data from the JSON data source to use for drawing a table. Using
4412	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4413	 * source object, or from a processing function.
4414	 *  @param {object} settings dataTables settings object
4415	 *  @param  {object} json Data source object / array from the server
4416	 *  @return {array} Array of data to use
4417	 */
4418	function _fnAjaxDataSrc ( settings, json, write )
4419	{
4420		var dataProp = 'data';
4421	
4422		if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
4423			// Could in inside a `dataSrc` object, or not!
4424			var dataSrc = settings.ajax.dataSrc;
4425	
4426			// string, function and object are valid types
4427			if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
4428				dataProp = dataSrc;
4429			}
4430			else if (dataSrc.data !== undefined) {
4431				dataProp = dataSrc.data;
4432			}
4433		}
4434	
4435		if ( ! write ) {
4436			if ( dataProp === 'data' ) {
4437				// If the default, then we still want to support the old style, and safely ignore
4438				// it if possible
4439				return json.aaData || json[dataProp];
4440			}
4441	
4442			return dataProp !== "" ?
4443				_fnGetObjectDataFn( dataProp )( json ) :
4444				json;
4445		}
4446		
4447		// set
4448		_fnSetObjectDataFn( dataProp )( json, write );
4449	}
4450	
4451	/**
4452	 * Very similar to _fnAjaxDataSrc, but for the other SSP properties
4453	 * @param {*} settings DataTables settings object
4454	 * @param {*} param Target parameter
4455	 * @param {*} json JSON data
4456	 * @returns Resolved value
4457	 */
4458	function _fnAjaxDataSrcParam (settings, param, json) {
4459		var dataSrc = $.isPlainObject( settings.ajax )
4460			? settings.ajax.dataSrc
4461			: null;
4462	
4463		if (dataSrc && dataSrc[param]) {
4464			// Get from custom location
4465			return _fnGetObjectDataFn( dataSrc[param] )( json );
4466		}
4467	
4468		// else - Default behaviour
4469		var old = '';
4470	
4471		// Legacy support
4472		if (param === 'draw') {
4473			old = 'sEcho';
4474		}
4475		else if (param === 'recordsTotal') {
4476			old = 'iTotalRecords';
4477		}
4478		else if (param === 'recordsFiltered') {
4479			old = 'iTotalDisplayRecords';
4480		}
4481	
4482		return json[old] !== undefined
4483			? json[old]
4484			: json[param];
4485	}
4486	
4487	
4488	/**
4489	 * Filter the table using both the global filter and column based filtering
4490	 *  @param {object} settings dataTables settings object
4491	 *  @param {object} input search information
4492	 *  @memberof DataTable#oApi
4493	 */
4494	function _fnFilterComplete ( settings, input )
4495	{
4496		var columnsSearch = settings.aoPreSearchCols;
4497	
4498		// In server-side processing all filtering is done by the server, so no point hanging around here
4499		if ( _fnDataSource( settings ) != 'ssp' )
4500		{
4501			// Check if any of the rows were invalidated
4502			_fnFilterData( settings );
4503	
4504			// Start from the full data set
4505			settings.aiDisplay = settings.aiDisplayMaster.slice();
4506	
4507			// Global filter first
4508			_fnFilter( settings.aiDisplay, settings, input.search, input );
4509	
4510			$.each(settings.searchFixed, function (name, term) {
4511				_fnFilter(settings.aiDisplay, settings, term, {});
4512			});
4513	
4514			// Then individual column filters
4515			for ( var i=0 ; i<columnsSearch.length ; i++ )
4516			{
4517				var col = columnsSearch[i];
4518	
4519				_fnFilter(
4520					settings.aiDisplay,
4521					settings,
4522					col.search,
4523					col,
4524					i
4525				);
4526	
4527				$.each(settings.aoColumns[i].searchFixed, function (name, term) {
4528					_fnFilter(settings.aiDisplay, settings, term, {}, i);
4529				});
4530			}
4531	
4532			// And finally global filtering
4533			_fnFilterCustom( settings );
4534		}
4535	
4536		// Tell the draw function we have been filtering
4537		settings.bFiltered = true;
4538	
4539		_fnCallbackFire( settings, null, 'search', [settings] );
4540	}
4541	
4542	
4543	/**
4544	 * Apply custom filtering functions
4545	 * 
4546	 * This is legacy now that we have named functions, but it is widely used
4547	 * from 1.x, so it is not yet deprecated.
4548	 *  @param {object} oSettings dataTables settings object
4549	 *  @memberof DataTable#oApi
4550	 */
4551	function _fnFilterCustom( settings )
4552	{
4553		var filters = DataTable.ext.search;
4554		var displayRows = settings.aiDisplay;
4555		var row, rowIdx;
4556	
4557		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4558			var rows = [];
4559	
4560			// Loop over each row and see if it should be included
4561			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4562				rowIdx = displayRows[ j ];
4563				row = settings.aoData[ rowIdx ];
4564	
4565				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4566					rows.push( rowIdx );
4567				}
4568			}
4569	
4570			// So the array reference doesn't break set the results into the
4571			// existing array
4572			displayRows.length = 0;
4573			_fnArrayApply(displayRows, rows);
4574		}
4575	}
4576	
4577	
4578	/**
4579	 * Filter the data table based on user input and draw the table
4580	 */
4581	function _fnFilter( searchRows, settings, input, options, column )
4582	{
4583		if ( input === '' ) {
4584			return;
4585		}
4586	
4587		var i = 0;
4588		var matched = [];
4589	
4590		// Search term can be a function, regex or string - if a string we apply our
4591		// smart filtering regex (assuming the options require that)
4592		var searchFunc = typeof input === 'function' ? input : null;
4593		var rpSearch = input instanceof RegExp
4594			? input
4595			: searchFunc
4596				? null
4597				: _fnFilterCreateSearch( input, options );
4598	
4599		// Then for each row, does the test pass. If not, lop the row from the array
4600		for (i=0 ; i<searchRows.length ; i++) {
4601			var row = settings.aoData[ searchRows[i] ];
4602			var data = column === undefined
4603				? row._sFilterRow
4604				: row._aFilterData[ column ];
4605	
4606			if ( (searchFunc && searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && rpSearch.test(data)) ) {
4607				matched.push(searchRows[i]);
4608			}
4609		}
4610	
4611		// Mutate the searchRows array
4612		searchRows.length = matched.length;
4613	
4614		for (i=0 ; i<matched.length ; i++) {
4615			searchRows[i] = matched[i];
4616		}
4617	}
4618	
4619	
4620	/**
4621	 * Build a regular expression object suitable for searching a table
4622	 *  @param {string} sSearch string to search for
4623	 *  @param {bool} bRegex treat as a regular expression or not
4624	 *  @param {bool} bSmart perform smart filtering or not
4625	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4626	 *  @returns {RegExp} constructed object
4627	 *  @memberof DataTable#oApi
4628	 */
4629	function _fnFilterCreateSearch( search, inOpts )
4630	{
4631		var not = [];
4632		var options = $.extend({}, {
4633			boundary: false,
4634			caseInsensitive: true,
4635			exact: false,
4636			regex: false,
4637			smart: true
4638		}, inOpts);
4639	
4640		if (typeof search !== 'string') {
4641			search = search.toString();
4642		}
4643	
4644		// Remove diacritics if normalize is set up to do so
4645		search = _normalize(search);
4646	
4647		if (options.exact) {
4648			return new RegExp(
4649				'^'+_fnEscapeRegex(search)+'$',
4650				options.caseInsensitive ? 'i' : ''
4651			);
4652		}
4653	
4654		search = options.regex ?
4655			search :
4656			_fnEscapeRegex( search );
4657		
4658		if ( options.smart ) {
4659			/* For smart filtering we want to allow the search to work regardless of
4660			 * word order. We also want double quoted text to be preserved, so word
4661			 * order is important - a la google. And a negative look around for
4662			 * finding rows which don't contain a given string.
4663			 * 
4664			 * So this is the sort of thing we want to generate:
4665			 * 
4666			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4667			 */
4668			var parts = search.match( /!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''];
4669			var a = parts.map( function ( word ) {
4670				var negative = false;
4671				var m;
4672	
4673				// Determine if it is a "does not include"
4674				if ( word.charAt(0) === '!' ) {
4675					negative = true;
4676					word = word.substring(1);
4677				}
4678	
4679				// Strip the quotes from around matched phrases
4680				if ( word.charAt(0) === '"' ) {
4681					m = word.match( /^"(.*)"$/ );
4682					word = m ? m[1] : word;
4683				}
4684				else if ( word.charAt(0) === '\u201C' ) {
4685					// Smart quote match (iPhone users)
4686					m = word.match( /^\u201C(.*)\u201D$/ );
4687					word = m ? m[1] : word;
4688				}
4689	
4690				// For our "not" case, we need to modify the string that is
4691				// allowed to match at the end of the expression.
4692				if (negative) {
4693					if (word.length > 1) {
4694						not.push('(?!'+word+')');
4695					}
4696	
4697					word = '';
4698				}
4699	
4700				return word.replace(/"/g, '');
4701			} );
4702	
4703			var match = not.length
4704				? not.join('')
4705				: '';
4706	
4707			var boundary = options.boundary
4708				? '\\b'
4709				: '';
4710	
4711			search = '^(?=.*?'+boundary+a.join( ')(?=.*?'+boundary )+')('+match+'.)*$';
4712		}
4713	
4714		return new RegExp( search, options.caseInsensitive ? 'i' : '' );
4715	}
4716	
4717	
4718	/**
4719	 * Escape a string such that it can be used in a regular expression
4720	 *  @param {string} sVal string to escape
4721	 *  @returns {string} escaped string
4722	 *  @memberof DataTable#oApi
4723	 */
4724	var _fnEscapeRegex = DataTable.util.escapeRegex;
4725	
4726	var __filter_div = $('<div>')[0];
4727	var __filter_div_textContent = __filter_div.textContent !== undefined;
4728	
4729	// Update the filtering data for each row if needed (by invalidation or first run)
4730	function _fnFilterData ( settings )
4731	{
4732		var columns = settings.aoColumns;
4733		var data = settings.aoData;
4734		var column;
4735		var j, jen, filterData, cellData, row;
4736		var wasInvalidated = false;
4737	
4738		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
4739			if (! data[rowIdx]) {
4740				continue;
4741			}
4742	
4743			row = data[rowIdx];
4744	
4745			if ( ! row._aFilterData ) {
4746				filterData = [];
4747	
4748				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4749					column = columns[j];
4750	
4751					if ( column.bSearchable ) {
4752						cellData = _fnGetCellData( settings, rowIdx, j, 'filter' );
4753	
4754						// Search in DataTables is string based
4755						if ( cellData === null ) {
4756							cellData = '';
4757						}
4758	
4759						if ( typeof cellData !== 'string' && cellData.toString ) {
4760							cellData = cellData.toString();
4761						}
4762					}
4763					else {
4764						cellData = '';
4765					}
4766	
4767					// If it looks like there is an HTML entity in the string,
4768					// attempt to decode it so sorting works as expected. Note that
4769					// we could use a single line of jQuery to do this, but the DOM
4770					// method used here is much faster https://jsperf.com/html-decode
4771					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4772						__filter_div.innerHTML = cellData;
4773						cellData = __filter_div_textContent ?
4774							__filter_div.textContent :
4775							__filter_div.innerText;
4776					}
4777	
4778					if ( cellData.replace ) {
4779						cellData = cellData.replace(/[\r\n\u2028]/g, '');
4780					}
4781	
4782					filterData.push( cellData );
4783				}
4784	
4785				row._aFilterData = filterData;
4786				row._sFilterRow = filterData.join('  ');
4787				wasInvalidated = true;
4788			}
4789		}
4790	
4791		return wasInvalidated;
4792	}
4793	
4794	
4795	/**
4796	 * Draw the table for the first time, adding all required features
4797	 *  @param {object} settings dataTables settings object
4798	 *  @memberof DataTable#oApi
4799	 */
4800	function _fnInitialise ( settings )
4801	{
4802		var i;
4803		var init = settings.oInit;
4804		var deferLoading = settings.deferLoading;
4805		var dataSrc = _fnDataSource( settings );
4806	
4807		// Ensure that the table data is fully initialised
4808		if ( ! settings.bInitialised ) {
4809			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4810			return;
4811		}
4812	
4813		// Build the header / footer for the table
4814		_fnBuildHead( settings, 'header' );
4815		_fnBuildHead( settings, 'footer' );
4816	
4817		// Load the table's state (if needed) and then render around it and draw
4818		_fnLoadState( settings, init, function () {
4819			// Then draw the header / footer
4820			_fnDrawHead( settings, settings.aoHeader );
4821			_fnDrawHead( settings, settings.aoFooter );
4822	
4823			// Cache the paging start point, as the first redraw will reset it
4824			var iAjaxStart = settings.iInitDisplayStart
4825	
4826			// Local data load
4827			// Check if there is data passing into the constructor
4828			if ( init.aaData ) {
4829				for ( i=0 ; i<init.aaData.length ; i++ ) {
4830					_fnAddData( settings, init.aaData[ i ] );
4831				}
4832			}
4833			else if ( deferLoading || dataSrc == 'dom' ) {
4834				// Grab the data from the page
4835				_fnAddTr( settings, $(settings.nTBody).children('tr') );
4836			}
4837	
4838			// Filter not yet applied - copy the display master
4839			settings.aiDisplay = settings.aiDisplayMaster.slice();
4840	
4841			// Enable features
4842			_fnAddOptionsHtml( settings );
4843			_fnSortInit( settings );
4844	
4845			_colGroup( settings );
4846	
4847			/* Okay to show that something is going on now */
4848			_fnProcessingDisplay( settings, true );
4849	
4850			_fnCallbackFire( settings, null, 'preInit', [settings], true );
4851	
4852			// If there is default sorting required - let's do it. The sort function
4853			// will do the drawing for us. Otherwise we draw the table regardless of the
4854			// Ajax source - this allows the table to look initialised for Ajax sourcing
4855			// data (show 'loading' message possibly)
4856			_fnReDraw( settings );
4857	
4858			// Server-side processing init complete is done by _fnAjaxUpdateDraw
4859			if ( dataSrc != 'ssp' || deferLoading ) {
4860				// if there is an ajax source load the data
4861				if ( dataSrc == 'ajax' ) {
4862					_fnBuildAjax( settings, {}, function(json) {
4863						var aData = _fnAjaxDataSrc( settings, json );
4864	
4865						// Got the data - add it to the table
4866						for ( i=0 ; i<aData.length ; i++ ) {
4867							_fnAddData( settings, aData[i] );
4868						}
4869	
4870						// Reset the init display for cookie saving. We've already done
4871						// a filter, and therefore cleared it before. So we need to make
4872						// it appear 'fresh'
4873						settings.iInitDisplayStart = iAjaxStart;
4874	
4875						_fnReDraw( settings );
4876						_fnProcessingDisplay( settings, false );
4877						_fnInitComplete( settings );
4878					}, settings );
4879				}
4880				else {
4881					_fnInitComplete( settings );
4882					_fnProcessingDisplay( settings, false );
4883				}
4884			}
4885		} );
4886	}
4887	
4888	
4889	/**
4890	 * Draw the table for the first time, adding all required features
4891	 *  @param {object} settings dataTables settings object
4892	 *  @memberof DataTable#oApi
4893	 */
4894	function _fnInitComplete ( settings )
4895	{
4896		if (settings._bInitComplete) {
4897			return;
4898		}
4899	
4900		var args = [settings, settings.json];
4901	
4902		settings._bInitComplete = true;
4903	
4904		// Table is fully set up and we have data, so calculate the
4905		// column widths
4906		_fnAdjustColumnSizing( settings );
4907	
4908		_fnCallbackFire( settings, null, 'plugin-init', args, true );
4909		_fnCallbackFire( settings, 'aoInitComplete', 'init', args, true );
4910	}
4911	
4912	function _fnLengthChange ( settings, val )
4913	{
4914		var len = parseInt( val, 10 );
4915		settings._iDisplayLength = len;
4916	
4917		_fnLengthOverflow( settings );
4918	
4919		// Fire length change event
4920		_fnCallbackFire( settings, null, 'length', [settings, len] );
4921	}
4922	
4923	/**
4924	 * Alter the display settings to change the page
4925	 *  @param {object} settings DataTables settings object
4926	 *  @param {string|int} action Paging action to take: "first", "previous",
4927	 *    "next" or "last" or page number to jump to (integer)
4928	 *  @param [bool] redraw Automatically draw the update or not
4929	 *  @returns {bool} true page has changed, false - no change
4930	 *  @memberof DataTable#oApi
4931	 */
4932	function _fnPageChange ( settings, action, redraw )
4933	{
4934		var
4935			start     = settings._iDisplayStart,
4936			len       = settings._iDisplayLength,
4937			records   = settings.fnRecordsDisplay();
4938	
4939		if ( records === 0 || len === -1 )
4940		{
4941			start = 0;
4942		}
4943		else if ( typeof action === "number" )
4944		{
4945			start = action * len;
4946	
4947			if ( start > records )
4948			{
4949				start = 0;
4950			}
4951		}
4952		else if ( action == "first" )
4953		{
4954			start = 0;
4955		}
4956		else if ( action == "previous" )
4957		{
4958			start = len >= 0 ?
4959				start - len :
4960				0;
4961	
4962			if ( start < 0 )
4963			{
4964				start = 0;
4965			}
4966		}
4967		else if ( action == "next" )
4968		{
4969			if ( start + len < records )
4970			{
4971				start += len;
4972			}
4973		}
4974		else if ( action == "last" )
4975		{
4976			start = Math.floor( (records-1) / len) * len;
4977		}
4978		else if ( action === 'ellipsis' )
4979		{
4980			return;
4981		}
4982		else
4983		{
4984			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4985		}
4986	
4987		var changed = settings._iDisplayStart !== start;
4988		settings._iDisplayStart = start;
4989	
4990		_fnCallbackFire( settings, null, changed ? 'page' : 'page-nc', [settings] );
4991	
4992		if ( changed && redraw ) {
4993			_fnDraw( settings );
4994		}
4995	
4996		return changed;
4997	}
4998	
4999	
5000	/**
5001	 * Generate the node required for the processing node
5002	 *  @param {object} settings DataTables settings object
5003	 */
5004	function _processingHtml ( settings )
5005	{
5006		var table = settings.nTable;
5007		var scrolling = settings.oScroll.sX !== '' || settings.oScroll.sY !== '';
5008	
5009		if ( settings.oFeatures.bProcessing ) {
5010			var n = $('<div/>', {
5011					'id': settings.sTableId + '_processing',
5012					'class': settings.oClasses.processing.container,
5013					'role': 'status'
5014				} )
5015				.html( settings.oLanguage.sProcessing )
5016				.append('<div><div></div><div></div><div></div><div></div></div>');
5017	
5018			// Different positioning depending on if scrolling is enabled or not
5019			if (scrolling) {
5020				n.prependTo( $('div.dt-scroll', settings.nTableWrapper) );
5021			}
5022			else {
5023				n.insertBefore( table );
5024			}
5025	
5026			$(table).on( 'processing.dt.DT', function (e, s, show) {
5027				n.css( 'display', show ? 'block' : 'none' );
5028			} );
5029		}
5030	}
5031	
5032	
5033	/**
5034	 * Display or hide the processing indicator
5035	 *  @param {object} settings DataTables settings object
5036	 *  @param {bool} show Show the processing indicator (true) or not (false)
5037	 */
5038	function _fnProcessingDisplay ( settings, show )
5039	{
5040		// Ignore cases when we are still redrawing
5041		if (settings.bDrawing && show === false) {
5042			return;
5043		}
5044	
5045		_fnCallbackFire( settings, null, 'processing', [settings, show] );
5046	}
5047	
5048	/**
5049	 * Show the processing element if an action takes longer than a given time
5050	 *
5051	 * @param {*} settings DataTables settings object
5052	 * @param {*} enable Do (true) or not (false) async processing (local feature enablement)
5053	 * @param {*} run Function to run
5054	 */
5055	function _fnProcessingRun( settings, enable, run ) {
5056		if (! enable) {
5057			// Immediate execution, synchronous
5058			run();
5059		}
5060		else {
5061			_fnProcessingDisplay(settings, true);
5062			
5063			// Allow the processing display to show if needed
5064			setTimeout(function () {
5065				run();
5066	
5067				_fnProcessingDisplay(settings, false);
5068			}, 0);
5069		}
5070	}
5071	/**
5072	 * Add any control elements for the table - specifically scrolling
5073	 *  @param {object} settings dataTables settings object
5074	 *  @returns {node} Node to add to the DOM
5075	 *  @memberof DataTable#oApi
5076	 */
5077	function _fnFeatureHtmlTable ( settings )
5078	{
5079		var table = $(settings.nTable);
5080	
5081		// Scrolling from here on in
5082		var scroll = settings.oScroll;
5083	
5084		if ( scroll.sX === '' && scroll.sY === '' ) {
5085			return settings.nTable;
5086		}
5087	
5088		var scrollX = scroll.sX;
5089		var scrollY = scroll.sY;
5090		var classes = settings.oClasses.scrolling;
5091		var caption = settings.captionNode;
5092		var captionSide = caption ? caption._captionSide : null;
5093		var headerClone = $( table[0].cloneNode(false) );
5094		var footerClone = $( table[0].cloneNode(false) );
5095		var footer = table.children('tfoot');
5096		var _div = '<div/>';
5097		var size = function ( s ) {
5098			return !s ? null : _fnStringToCss( s );
5099		};
5100	
5101		if ( ! footer.length ) {
5102			footer = null;
5103		}
5104	
5105		/*
5106		 * The HTML structure that we want to generate in this function is:
5107		 *  div - scroller
5108		 *    div - scroll head
5109		 *      div - scroll head inner
5110		 *        table - scroll head table
5111		 *          thead - thead
5112		 *    div - scroll body
5113		 *      table - table (master table)
5114		 *        thead - thead clone for sizing
5115		 *        tbody - tbody
5116		 *    div - scroll foot
5117		 *      div - scroll foot inner
5118		 *        table - scroll foot table
5119		 *          tfoot - tfoot
5120		 */
5121		var scroller = $( _div, { 'class': classes.container } )
5122			.append(
5123				$(_div, { 'class': classes.header.self } )
5124					.css( {
5125						overflow: 'hidden',
5126						position: 'relative',
5127						border: 0,
5128						width: scrollX ? size(scrollX) : '100%'
5129					} )
5130					.append(
5131						$(_div, { 'class': classes.header.inner } )
5132							.css( {
5133								'box-sizing': 'content-box',
5134								width: scroll.sXInner || '100%'
5135							} )
5136							.append(
5137								headerClone
5138									.removeAttr('id')
5139									.css( 'margin-left', 0 )
5140									.append( captionSide === 'top' ? caption : null )
5141									.append(
5142										table.children('thead')
5143									)
5144							)
5145					)
5146			)
5147			.append(
5148				$(_div, { 'class': classes.body } )
5149					.css( {
5150						position: 'relative',
5151						overflow: 'auto',
5152						width: size( scrollX )
5153					} )
5154					.append( table )
5155			);
5156	
5157		if ( footer ) {
5158			scroller.append(
5159				$(_div, { 'class': classes.footer.self } )
5160					.css( {
5161						overflow: 'hidden',
5162						border: 0,
5163						width: scrollX ? size(scrollX) : '100%'
5164					} )
5165					.append(
5166						$(_div, { 'class': classes.footer.inner } )
5167							.append(
5168								footerClone
5169									.removeAttr('id')
5170									.css( 'margin-left', 0 )
5171									.append( captionSide === 'bottom' ? caption : null )
5172									.append(
5173										table.children('tfoot')
5174									)
5175							)
5176					)
5177			);
5178		}
5179	
5180		var children = scroller.children();
5181		var scrollHead = children[0];
5182		var scrollBody = children[1];
5183		var scrollFoot = footer ? children[2] : null;
5184	
5185		// When the body is scrolled, then we also want to scroll the headers
5186		$(scrollBody).on( 'scroll.DT', function () {
5187			var scrollLeft = this.scrollLeft;
5188	
5189			scrollHead.scrollLeft = scrollLeft;
5190	
5191			if ( footer ) {
5192				scrollFoot.scrollLeft = scrollLeft;
5193			}
5194		} );
5195	
5196		// When focus is put on the header cells, we might need to scroll the body
5197		$('th, td', scrollHead).on('focus', function () {
5198			var scrollLeft = scrollHead.scrollLeft;
5199	
5200			scrollBody.scrollLeft = scrollLeft;
5201	
5202			if ( footer ) {
5203				scrollBody.scrollLeft = scrollLeft;
5204			}
5205		});
5206	
5207		$(scrollBody).css('max-height', scrollY);
5208		if (! scroll.bCollapse) {
5209			$(scrollBody).css('height', scrollY);
5210		}
5211	
5212		settings.nScrollHead = scrollHead;
5213		settings.nScrollBody = scrollBody;
5214		settings.nScrollFoot = scrollFoot;
5215	
5216		// On redraw - align columns
5217		settings.aoDrawCallback.push(_fnScrollDraw);
5218	
5219		return scroller[0];
5220	}
5221	
5222	
5223	
5224	/**
5225	 * Update the header, footer and body tables for resizing - i.e. column
5226	 * alignment.
5227	 *
5228	 * Welcome to the most horrible function DataTables. The process that this
5229	 * function follows is basically:
5230	 *   1. Re-create the table inside the scrolling div
5231	 *   2. Correct colgroup > col values if needed
5232	 *   3. Copy colgroup > col over to header and footer
5233	 *   4. Clean up
5234	 *
5235	 *  @param {object} settings dataTables settings object
5236	 *  @memberof DataTable#oApi
5237	 */
5238	function _fnScrollDraw ( settings )
5239	{
5240		// Given that this is such a monster function, a lot of variables are use
5241		// to try and keep the minimised size as small as possible
5242		var
5243			scroll         = settings.oScroll,
5244			barWidth       = scroll.iBarWidth,
5245			divHeader      = $(settings.nScrollHead),
5246			divHeaderInner = divHeader.children('div'),
5247			divHeaderTable = divHeaderInner.children('table'),
5248			divBodyEl      = settings.nScrollBody,
5249			divBody        = $(divBodyEl),
5250			divFooter      = $(settings.nScrollFoot),
5251			divFooterInner = divFooter.children('div'),
5252			divFooterTable = divFooterInner.children('table'),
5253			header         = $(settings.nTHead),
5254			table          = $(settings.nTable),
5255			footer         = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
5256			browser        = settings.oBrowser,
5257			headerCopy, footerCopy;
5258	
5259		// If the scrollbar visibility has changed from the last draw, we need to
5260		// adjust the column sizes as the table width will have changed to account
5261		// for the scrollbar
5262		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5263		
5264		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5265			settings.scrollBarVis = scrollBarVis;
5266			_fnAdjustColumnSizing( settings );
5267			return; // adjust column sizing will call this function again
5268		}
5269		else {
5270			settings.scrollBarVis = scrollBarVis;
5271		}
5272	
5273		// 1. Re-create the table inside the scrolling div
5274		// Remove the old minimised thead and tfoot elements in the inner table
5275		table.children('thead, tfoot').remove();
5276	
5277		// Clone the current header and footer elements and then place it into the inner table
5278		headerCopy = header.clone().prependTo( table );
5279		headerCopy.find('th, td').removeAttr('tabindex');
5280		headerCopy.find('[id]').removeAttr('id');
5281	
5282		if ( footer ) {
5283			footerCopy = footer.clone().prependTo( table );
5284			footerCopy.find('[id]').removeAttr('id');
5285		}
5286	
5287		// 2. Correct colgroup > col values if needed
5288		// It is possible that the cell sizes are smaller than the content, so we need to
5289		// correct colgroup>col for such cases. This can happen if the auto width detection
5290		// uses a cell which has a longer string, but isn't the widest! For example 
5291		// "Chief Executive Officer (CEO)" is the longest string in the demo, but
5292		// "Systems Administrator" is actually the widest string since it doesn't collapse.
5293		// Note the use of translating into a column index to get the `col` element. This
5294		// is because of Responsive which might remove `col` elements, knocking the alignment
5295		// of the indexes out.
5296		if (settings.aiDisplay.length) {
5297			// Get the column sizes from the first row in the table. This should really be a
5298			// [].find, but it wasn't supported in Chrome until Sept 2015, and DT has 10 year
5299			// browser support
5300			var firstTr = null;
5301			var start = _fnDataSource( settings ) !== 'ssp'
5302				? settings._iDisplayStart
5303				: 0;
5304	
5305			for (i=start ; i<start + settings.aiDisplay.length ; i++) {
5306				var idx = settings.aiDisplay[i];
5307				var tr = settings.aoData[idx].nTr;
5308	
5309				if (tr) {
5310					firstTr = tr;
5311					break;
5312				}
5313			}
5314	
5315			if (firstTr) {
5316				var colSizes = $(firstTr).children('th, td').map(function (vis) {
5317					return {
5318						idx: _fnVisibleToColumnIndex(settings, vis),
5319						width: $(this).outerWidth()
5320					};
5321				});
5322	
5323				// Check against what the colgroup > col is set to and correct if needed
5324				for (var i=0 ; i<colSizes.length ; i++) {
5325					var colEl = settings.aoColumns[ colSizes[i].idx ].colEl[0];
5326					var colWidth = colEl.style.width.replace('px', '');
5327	
5328					if (colWidth !== colSizes[i].width) {
5329						colEl.style.width = colSizes[i].width + 'px';
5330	
5331						if (scroll.sX) {
5332							colEl.style.minWidth = colSizes[i].width + 'px';
5333						}
5334					}
5335				}
5336			}
5337		}
5338	
5339		// 3. Copy the colgroup over to the header and footer
5340		divHeaderTable
5341			.find('colgroup')
5342			.remove();
5343	
5344		divHeaderTable.append(settings.colgroup.clone());
5345	
5346		if ( footer ) {
5347			divFooterTable
5348				.find('colgroup')
5349				.remove();
5350	
5351			divFooterTable.append(settings.colgroup.clone());
5352		}
5353	
5354		// "Hide" the header and footer that we used for the sizing. We need to keep
5355		// the content of the cell so that the width applied to the header and body
5356		// both match, but we want to hide it completely.
5357		$('th, td', headerCopy).each(function () {
5358			$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5359		});
5360	
5361		if ( footer ) {
5362			$('th, td', footerCopy).each(function () {
5363				$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5364			});
5365		}
5366	
5367		// 4. Clean up
5368		// Figure out if there are scrollbar present - if so then we need a the header and footer to
5369		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5370		var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5371		var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5372	
5373		// Set the width's of the header and footer tables
5374		var outerWidth = table.outerWidth();
5375	
5376		divHeaderTable.css('width', _fnStringToCss( outerWidth ));
5377		divHeaderInner
5378			.css('width', _fnStringToCss( outerWidth ))
5379			.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5380	
5381		if ( footer ) {
5382			divFooterTable.css('width', _fnStringToCss( outerWidth ));
5383			divFooterInner
5384				.css('width', _fnStringToCss( outerWidth ))
5385				.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5386		}
5387	
5388		// Correct DOM ordering for colgroup - comes before the thead
5389		table.children('colgroup').prependTo(table);
5390	
5391		// Adjust the position of the header in case we loose the y-scrollbar
5392		divBody.trigger('scroll');
5393	
5394		// If sorting or filtering has occurred, jump the scrolling back to the top
5395		// only if we aren't holding the position
5396		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5397			divBodyEl.scrollTop = 0;
5398		}
5399	}
5400	
5401	/**
5402	 * Calculate the width of columns for the table
5403	 *  @param {object} settings dataTables settings object
5404	 *  @memberof DataTable#oApi
5405	 */
5406	function _fnCalculateColumnWidths ( settings )
5407	{
5408		// Not interested in doing column width calculation if auto-width is disabled
5409		if (! settings.oFeatures.bAutoWidth) {
5410			return;
5411		}
5412	
5413		var
5414			table = settings.nTable,
5415			columns = settings.aoColumns,
5416			scroll = settings.oScroll,
5417			scrollY = scroll.sY,
5418			scrollX = scroll.sX,
5419			scrollXInner = scroll.sXInner,
5420			visibleColumns = _fnGetColumns( settings, 'bVisible' ),
5421			tableWidthAttr = table.getAttribute('width'), // from DOM element
5422			tableContainer = table.parentNode,
5423			i, column, columnIdx;
5424			
5425		var styleWidth = table.style.width;
5426		var containerWidth = _fnWrapperWidth(settings);
5427	
5428		// Don't re-run for the same width as the last time
5429		if (containerWidth === settings.containerWidth) {
5430			return false;
5431		}
5432	
5433		settings.containerWidth = containerWidth;
5434	
5435		// If there is no width applied as a CSS style or as an attribute, we assume that
5436		// the width is intended to be 100%, which is usually is in CSS, but it is very
5437		// difficult to correctly parse the rules to get the final result.
5438		if ( ! styleWidth && ! tableWidthAttr) {
5439			table.style.width = '100%';
5440			styleWidth = '100%';
5441		}
5442	
5443		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5444			tableWidthAttr = styleWidth;
5445		}
5446	
5447		// Let plug-ins know that we are doing a recalc, in case they have changed any of the
5448		// visible columns their own way (e.g. Responsive uses display:none).
5449		_fnCallbackFire(
5450			settings,
5451			null,
5452			'column-calc',
5453			{visible: visibleColumns},
5454			false
5455		);
5456	
5457		// Construct a single row, worst case, table with the widest
5458		// node in the data, assign any user defined widths, then insert it into
5459		// the DOM and allow the browser to do all the hard work of calculating
5460		// table widths
5461		var tmpTable = $(table.cloneNode())
5462			.css( 'visibility', 'hidden' )
5463			.removeAttr( 'id' );
5464	
5465		// Clean up the table body
5466		tmpTable.append('<tbody>')
5467		var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5468	
5469		// Clone the table header and footer - we can't use the header / footer
5470		// from the cloned table, since if scrolling is active, the table's
5471		// real header and footer are contained in different table tags
5472		tmpTable
5473			.append( $(settings.nTHead).clone() )
5474			.append( $(settings.nTFoot).clone() );
5475	
5476		// Remove any assigned widths from the footer (from scrolling)
5477		tmpTable.find('tfoot th, tfoot td').css('width', '');
5478	
5479		// Apply custom sizing to the cloned header
5480		tmpTable.find('thead th, thead td').each( function () {
5481			// Get the `width` from the header layout
5482			var width = _fnColumnsSumWidth( settings, this, true, false );
5483	
5484			if ( width ) {
5485				this.style.width = width;
5486	
5487				// For scrollX we need to force the column width otherwise the
5488				// browser will collapse it. If this width is smaller than the
5489				// width the column requires, then it will have no effect
5490				if ( scrollX ) {
5491					this.style.minWidth = width;
5492	
5493					$( this ).append( $('<div/>').css( {
5494						width: width,
5495						margin: 0,
5496						padding: 0,
5497						border: 0,
5498						height: 1
5499					} ) );
5500				}
5501			}
5502			else {
5503				this.style.width = '';
5504			}
5505		} );
5506	
5507		// Find the widest piece of data for each column and put it into the table
5508		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5509			columnIdx = visibleColumns[i];
5510			column = columns[ columnIdx ];
5511	
5512			var longest = _fnGetMaxLenString(settings, columnIdx);
5513			var autoClass = _ext.type.className[column.sType];
5514			var text = longest + column.sContentPadding;
5515			var insert = longest.indexOf('<') === -1
5516				? document.createTextNode(text)
5517				: text
5518			
5519			$('<td/>')
5520				.addClass(autoClass)
5521				.addClass(column.sClass)
5522				.append(insert)
5523				.appendTo(tr);
5524		}
5525	
5526		// Tidy the temporary table - remove name attributes so there aren't
5527		// duplicated in the dom (radio elements for example)
5528		$('[name]', tmpTable).removeAttr('name');
5529	
5530		// Table has been built, attach to the document so we can work with it.
5531		// A holding element is used, positioned at the top of the container
5532		// with minimal height, so it has no effect on if the container scrolls
5533		// or not. Otherwise it might trigger scrolling when it actually isn't
5534		// needed
5535		var holder = $('<div/>').css( scrollX || scrollY ?
5536				{
5537					position: 'absolute',
5538					top: 0,
5539					left: 0,
5540					height: 1,
5541					right: 0,
5542					overflow: 'hidden'
5543				} :
5544				{}
5545			)
5546			.append( tmpTable )
5547			.appendTo( tableContainer );
5548	
5549		// When scrolling (X or Y) we want to set the width of the table as 
5550		// appropriate. However, when not scrolling leave the table width as it
5551		// is. This results in slightly different, but I think correct behaviour
5552		if ( scrollX && scrollXInner ) {
5553			tmpTable.width( scrollXInner );
5554		}
5555		else if ( scrollX ) {
5556			tmpTable.css( 'width', 'auto' );
5557			tmpTable.removeAttr('width');
5558	
5559			// If there is no width attribute or style, then allow the table to
5560			// collapse
5561			if ( tmpTable.outerWidth() < tableContainer.clientWidth && tableWidthAttr ) {
5562				tmpTable.outerWidth( tableContainer.clientWidth );
5563			}
5564		}
5565		else if ( scrollY ) {
5566			tmpTable.outerWidth( tableContainer.clientWidth );
5567		}
5568		else if ( tableWidthAttr ) {
5569			tmpTable.outerWidth( tableWidthAttr );
5570		}
5571	
5572		// Get the width of each column in the constructed table
5573		var total = 0;
5574		var bodyCells = tmpTable.find('tbody tr').eq(0).children();
5575	
5576		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5577			// Use getBounding for sub-pixel accuracy, which we then want to round up!
5578			var bounding = bodyCells[i].getBoundingClientRect().width;
5579	
5580			// Total is tracked to remove any sub-pixel errors as the outerWidth
5581			// of the table might not equal the total given here
5582			total += bounding;
5583	
5584			// Width for each column to use
5585			columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding );
5586		}
5587	
5588		table.style.width = _fnStringToCss( total );
5589	
5590		// Finished with the table - ditch it
5591		holder.remove();
5592	
5593		// If there is a width attr, we want to attach an event listener which
5594		// allows the table sizing to automatically adjust when the window is
5595		// resized. Use the width attr rather than CSS, since we can't know if the
5596		// CSS is a relative value or absolute - DOM read is always px.
5597		if ( tableWidthAttr ) {
5598			table.style.width = _fnStringToCss( tableWidthAttr );
5599		}
5600	
5601		if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
5602			var resize = DataTable.util.throttle( function () {
5603				var newWidth = _fnWrapperWidth(settings);
5604	
5605				// Don't do it if destroying or the container width is 0
5606				if (! settings.bDestroying && newWidth !== 0) {
5607					_fnAdjustColumnSizing( settings );
5608				}
5609			} );
5610	
5611			// For browsers that support it (~2020 onwards for wide support) we can watch for the
5612			// container changing width.
5613			if (window.ResizeObserver) {
5614				// This is a tricky beast - if the element is visible when `.observe()` is called,
5615				// then the callback is immediately run. Which we don't want. If the element isn't
5616				// visible, then it isn't run, but we want it to run when it is then made visible.
5617				// This flag allows the above to be satisfied.
5618				var first = $(settings.nTableWrapper).is(':visible');
5619	
5620				// Use an empty div to attach the observer so it isn't impacted by height changes
5621				var resizer = $('<div>')
5622					.css({
5623						width: '100%',
5624						height: 0
5625					})
5626					.addClass('dt-autosize')
5627					.appendTo(settings.nTableWrapper);
5628	
5629				settings.resizeObserver = new ResizeObserver(function (e) {
5630					if (first) {
5631						first = false;
5632					}
5633					else {
5634						resize();
5635					}
5636				});
5637	
5638				settings.resizeObserver.observe(resizer[0]);
5639			}
5640			else {
5641				// For old browsers, the best we can do is listen for a window resize
5642				$(window).on('resize.DT-'+settings.sInstance, resize);
5643			}
5644	
5645			settings._reszEvt = true;
5646		}
5647	}
5648	
5649	/**
5650	 * Get the width of the DataTables wrapper element
5651	 *
5652	 * @param {*} settings DataTables settings object
5653	 * @returns Width
5654	 */
5655	function _fnWrapperWidth(settings) {
5656		return $(settings.nTableWrapper).is(':visible')
5657			? $(settings.nTableWrapper).width()
5658			: 0;
5659	}
5660	
5661	/**
5662	 * Get the maximum strlen for each data column
5663	 *  @param {object} settings dataTables settings object
5664	 *  @param {int} colIdx column of interest
5665	 *  @returns {string} string of the max length
5666	 *  @memberof DataTable#oApi
5667	 */
5668	function _fnGetMaxLenString( settings, colIdx )
5669	{
5670		var column = settings.aoColumns[colIdx];
5671	
5672		if (! column.maxLenString) {
5673			var s, max='', maxLen = -1;
5674		
5675			for ( var i=0, ien=settings.aiDisplayMaster.length ; i<ien ; i++ ) {
5676				var rowIdx = settings.aiDisplayMaster[i];
5677				var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
5678	
5679				var cellString = data && typeof data === 'object' && data.nodeType
5680					? data.innerHTML
5681					: data+'';
5682	
5683				// Remove id / name attributes from elements so they
5684				// don't interfere with existing elements
5685				cellString = cellString
5686					.replace(/id=".*?"/g, '')
5687					.replace(/name=".*?"/g, '');
5688	
5689				s = _stripHtml(cellString)
5690					.replace( /&nbsp;/g, ' ' );
5691		
5692				if ( s.length > maxLen ) {
5693					// We want the HTML in the string, but the length that
5694					// is important is the stripped string
5695					max = cellString;
5696					maxLen = s.length;
5697				}
5698			}
5699	
5700			column.maxLenString = max;
5701		}
5702	
5703		return column.maxLenString;
5704	}
5705	
5706	
5707	/**
5708	 * Append a CSS unit (only if required) to a string
5709	 *  @param {string} value to css-ify
5710	 *  @returns {string} value with css unit
5711	 *  @memberof DataTable#oApi
5712	 */
5713	function _fnStringToCss( s )
5714	{
5715		if ( s === null ) {
5716			return '0px';
5717		}
5718	
5719		if ( typeof s == 'number' ) {
5720			return s < 0 ?
5721				'0px' :
5722				s+'px';
5723		}
5724	
5725		// Check it has a unit character already
5726		return s.match(/\d$/) ?
5727			s+'px' :
5728			s;
5729	}
5730	
5731	/**
5732	 * Re-insert the `col` elements for current visibility
5733	 *
5734	 * @param {*} settings DT settings
5735	 */
5736	function _colGroup( settings ) {
5737		var cols = settings.aoColumns;
5738	
5739		settings.colgroup.empty();
5740	
5741		for (i=0 ; i<cols.length ; i++) {
5742			if (cols[i].bVisible) {
5743				settings.colgroup.append(cols[i].colEl);
5744			}
5745		}
5746	}
5747	
5748	
5749	function _fnSortInit( settings ) {
5750		var target = settings.nTHead;
5751		var headerRows = target.querySelectorAll('tr');
5752		var titleRow = settings.titleRow;
5753		var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5754		
5755		// Legacy support for `orderCellsTop`
5756		if (titleRow === true) {
5757			target = headerRows[0];
5758		}
5759		else if (titleRow === false) {
5760			target = headerRows[ headerRows.length - 1 ];
5761		}
5762		else if (titleRow !== null) {
5763			target = headerRows[titleRow];
5764		}
5765		// else - all rows
5766	
5767		if (settings.orderHandler) {
5768			_fnSortAttachListener(
5769				settings,
5770				target,
5771				target === settings.nTHead
5772					? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5773					: 'th'+notSelector+', td'+notSelector
5774			);
5775		}
5776	
5777		// Need to resolve the user input array into our internal structure
5778		var order = [];
5779		_fnSortResolve( settings, order, settings.aaSorting );
5780	
5781		settings.aaSorting = order;
5782	}
5783	
5784	
5785	function _fnSortAttachListener(settings, node, selector, column, callback) {
5786		_fnBindAction( node, selector, function (e) {
5787			var run = false;
5788			var columns = column === undefined
5789				? _fnColumnsFromHeader( e.target )
5790				: Array.isArray(column)
5791					? column
5792					: [column];
5793	
5794			if ( columns.length ) {
5795				for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
5796					var ret = _fnSortAdd( settings, columns[i], i, e.shiftKey );
5797	
5798					if (ret !== false) {
5799						run = true;
5800					}					
5801	
5802					// If the first entry is no sort, then subsequent
5803					// sort columns are ignored
5804					if (settings.aaSorting.length === 1 && settings.aaSorting[0][1] === '') {
5805						break;
5806					}
5807				}
5808	
5809				if (run) {
5810					_fnProcessingRun(settings, true, function () {
5811						_fnSort( settings );
5812						_fnSortDisplay( settings, settings.aiDisplay );
5813	
5814						_fnReDraw( settings, false, false );
5815	
5816						if (callback) {
5817							callback();
5818						}
5819					});
5820				}
5821			}
5822		} );
5823	}
5824	
5825	/**
5826	 * Sort the display array to match the master's order
5827	 * @param {*} settings
5828	 */
5829	function _fnSortDisplay(settings, display) {
5830		if (display.length < 2) {
5831			return;
5832		}
5833	
5834		var master = settings.aiDisplayMaster;
5835		var masterMap = {};
5836		var map = {};
5837		var i;
5838	
5839		// Rather than needing an `indexOf` on master array, we can create a map
5840		for (i=0 ; i<master.length ; i++) {
5841			masterMap[master[i]] = i;
5842		}
5843	
5844		// And then cache what would be the indexOf fom the display
5845		for (i=0 ; i<display.length ; i++) {
5846			map[display[i]] = masterMap[display[i]];
5847		}
5848	
5849		display.sort(function(a, b){
5850			// Short version of this function is simply `master.indexOf(a) - master.indexOf(b);`
5851			return map[a] - map[b];
5852		});
5853	}
5854	
5855	
5856	function _fnSortResolve (settings, nestedSort, sort) {
5857		var push = function ( a ) {
5858			if ($.isPlainObject(a)) {
5859				if (a.idx !== undefined) {
5860					// Index based ordering
5861					nestedSort.push([a.idx, a.dir]);
5862				}
5863				else if (a.name) {
5864					// Name based ordering
5865					var cols = _pluck( settings.aoColumns, 'sName');
5866					var idx = cols.indexOf(a.name);
5867	
5868					if (idx !== -1) {
5869						nestedSort.push([idx, a.dir]);
5870					}
5871				}
5872			}
5873			else {
5874				// Plain column index and direction pair
5875				nestedSort.push(a);
5876			}
5877		};
5878	
5879		if ( $.isPlainObject(sort) ) {
5880			// Object
5881			push(sort);
5882		}
5883		else if ( sort.length && typeof sort[0] === 'number' ) {
5884			// 1D array
5885			push(sort);
5886		}
5887		else if ( sort.length ) {
5888			// 2D array
5889			for (var z=0; z<sort.length; z++) {
5890				push(sort[z]); // Object or array
5891			}
5892		}
5893	}
5894	
5895	
5896	function _fnSortFlatten ( settings )
5897	{
5898		var
5899			i, k, kLen,
5900			aSort = [],
5901			extSort = DataTable.ext.type.order,
5902			aoColumns = settings.aoColumns,
5903			aDataSort, iCol, sType, srcCol,
5904			fixed = settings.aaSortingFixed,
5905			fixedObj = $.isPlainObject( fixed ),
5906			nestedSort = [];
5907		
5908		if ( ! settings.oFeatures.bSort ) {
5909			return aSort;
5910		}
5911	
5912		// Build the sort array, with pre-fix and post-fix options if they have been
5913		// specified
5914		if ( Array.isArray( fixed ) ) {
5915			_fnSortResolve( settings, nestedSort, fixed );
5916		}
5917	
5918		if ( fixedObj && fixed.pre ) {
5919			_fnSortResolve( settings, nestedSort, fixed.pre );
5920		}
5921	
5922		_fnSortResolve( settings, nestedSort, settings.aaSorting );
5923	
5924		if (fixedObj && fixed.post ) {
5925			_fnSortResolve( settings, nestedSort, fixed.post );
5926		}
5927	
5928		for ( i=0 ; i<nestedSort.length ; i++ )
5929		{
5930			srcCol = nestedSort[i][0];
5931	
5932			if ( aoColumns[ srcCol ] ) {
5933				aDataSort = aoColumns[ srcCol ].aDataSort;
5934	
5935				for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5936				{
5937					iCol = aDataSort[k];
5938					sType = aoColumns[ iCol ].sType || 'string';
5939	
5940					if ( nestedSort[i]._idx === undefined ) {
5941						nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
5942					}
5943	
5944					if ( nestedSort[i][1] ) {
5945						aSort.push( {
5946							src:       srcCol,
5947							col:       iCol,
5948							dir:       nestedSort[i][1],
5949							index:     nestedSort[i]._idx,
5950							type:      sType,
5951							formatter: extSort[ sType+"-pre" ],
5952							sorter:    extSort[ sType+"-"+nestedSort[i][1] ]
5953						} );
5954					}
5955				}
5956			}
5957		}
5958	
5959		return aSort;
5960	}
5961	
5962	/**
5963	 * Change the order of the table
5964	 *  @param {object} oSettings dataTables settings object
5965	 *  @memberof DataTable#oApi
5966	 */
5967	function _fnSort ( oSettings, col, dir )
5968	{
5969		var
5970			i, ien, iLen,
5971			aiOrig = [],
5972			extSort = DataTable.ext.type.order,
5973			aoData = oSettings.aoData,
5974			sortCol,
5975			displayMaster = oSettings.aiDisplayMaster,
5976			aSort;
5977	
5978		// Make sure the columns all have types defined
5979		_fnColumnTypes(oSettings);
5980	
5981		// Allow a specific column to be sorted, which will _not_ alter the display
5982		// master
5983		if (col !== undefined) {
5984			var srcCol = oSettings.aoColumns[col];
5985	
5986			aSort = [{
5987				src:       col,
5988				col:       col,
5989				dir:       dir,
5990				index:     0,
5991				type:      srcCol.sType,
5992				formatter: extSort[ srcCol.sType+"-pre" ],
5993				sorter:    extSort[ srcCol.sType+"-"+dir ]
5994			}];
5995			displayMaster = displayMaster.slice();
5996		}
5997		else {
5998			aSort = _fnSortFlatten( oSettings );
5999		}
6000	
6001		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
6002			sortCol = aSort[i];
6003	
6004			// Load the data needed for the sort, for each cell
6005			_fnSortData( oSettings, sortCol.col );
6006		}
6007	
6008		/* No sorting required if server-side or no sorting array */
6009		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
6010		{
6011			// Reset the initial positions on each pass so we get a stable sort
6012			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
6013				aiOrig[ i ] = i;
6014			}
6015	
6016			// If the first sort is desc, then reverse the array to preserve original
6017			// order, just in reverse
6018			if (aSort.length && aSort[0].dir === 'desc' && oSettings.orderDescReverse) {
6019				aiOrig.reverse();
6020			}
6021	
6022			/* Do the sort - here we want multi-column sorting based on a given data source (column)
6023			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
6024			 * follow on it's own, but this is what we want (example two column sorting):
6025			 *  fnLocalSorting = function(a,b){
6026			 *    var test;
6027			 *    test = oSort['string-asc']('data11', 'data12');
6028			 *      if (test !== 0)
6029			 *        return test;
6030			 *    test = oSort['numeric-desc']('data21', 'data22');
6031			 *    if (test !== 0)
6032			 *      return test;
6033			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
6034			 *  }
6035			 * Basically we have a test for each sorting column, if the data in that column is equal,
6036			 * test the next column. If all columns match, then we use a numeric sort on the row
6037			 * positions in the original data array to provide a stable sort.
6038			 */
6039			displayMaster.sort( function ( a, b ) {
6040				var
6041					x, y, k, test, sort,
6042					len=aSort.length,
6043					dataA = aoData[a]._aSortData,
6044					dataB = aoData[b]._aSortData;
6045	
6046				for ( k=0 ; k<len ; k++ ) {
6047					sort = aSort[k];
6048	
6049					// Data, which may have already been through a `-pre` function
6050					x = dataA[ sort.col ];
6051					y = dataB[ sort.col ];
6052	
6053					if (sort.sorter) {
6054						// If there is a custom sorter (`-asc` or `-desc`) for this
6055						// data type, use it
6056						test = sort.sorter(x, y);
6057	
6058						if ( test !== 0 ) {
6059							return test;
6060						}
6061					}
6062					else {
6063						// Otherwise, use generic sorting
6064						test = x<y ? -1 : x>y ? 1 : 0;
6065	
6066						if ( test !== 0 ) {
6067							return sort.dir === 'asc' ? test : -test;
6068						}
6069					}
6070				}
6071	
6072				x = aiOrig[a];
6073				y = aiOrig[b];
6074	
6075				return x<y ? -1 : x>y ? 1 : 0;
6076			} );
6077		}
6078		else if ( aSort.length === 0 ) {
6079			// Apply index order
6080			displayMaster.sort(function (x, y) {
6081				return x<y ? -1 : x>y ? 1 : 0;
6082			});
6083		}
6084	
6085		if (col === undefined) {
6086			// Tell the draw function that we have sorted the data
6087			oSettings.bSorted = true;
6088			oSettings.sortDetails = aSort;
6089	
6090			_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort] );
6091		}
6092	
6093		return displayMaster;
6094	}
6095	
6096	
6097	/**
6098	 * Function to run on user sort request
6099	 *  @param {object} settings dataTables settings object
6100	 *  @param {node} attachTo node to attach the handler to
6101	 *  @param {int} colIdx column sorting index
6102	 *  @param {int} addIndex Counter
6103	 *  @param {boolean} [shift=false] Shift click add
6104	 *  @param {function} [callback] callback function
6105	 *  @memberof DataTable#oApi
6106	 */
6107	function _fnSortAdd ( settings, colIdx, addIndex, shift )
6108	{
6109		var col = settings.aoColumns[ colIdx ];
6110		var sorting = settings.aaSorting;
6111		var asSorting = col.asSorting;
6112		var nextSortIdx;
6113		var next = function ( a, overflow ) {
6114			var idx = a._idx;
6115			if ( idx === undefined ) {
6116				idx = asSorting.indexOf(a[1]);
6117			}
6118	
6119			return idx+1 < asSorting.length ?
6120				idx+1 :
6121				overflow ?
6122					null :
6123					0;
6124		};
6125	
6126		if ( ! col.bSortable ) {
6127			return false;
6128		}
6129	
6130		// Convert to 2D array if needed
6131		if ( typeof sorting[0] === 'number' ) {
6132			sorting = settings.aaSorting = [ sorting ];
6133		}
6134	
6135		// If appending the sort then we are multi-column sorting
6136		if ( (shift || addIndex) && settings.oFeatures.bSortMulti ) {
6137			// Are we already doing some kind of sort on this column?
6138			var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
6139	
6140			if ( sortIdx !== -1 ) {
6141				// Yes, modify the sort
6142				nextSortIdx = next( sorting[sortIdx], true );
6143	
6144				if ( nextSortIdx === null && sorting.length === 1 ) {
6145					nextSortIdx = 0; // can't remove sorting completely
6146				}
6147	
6148				if ( nextSortIdx === null ) {
6149					sorting.splice( sortIdx, 1 );
6150				}
6151				else {
6152					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6153					sorting[sortIdx]._idx = nextSortIdx;
6154				}
6155			}
6156			else if (shift) {
6157				// No sort on this column yet, being added by shift click
6158				// add it as itself
6159				sorting.push( [ colIdx, asSorting[0], 0 ] );
6160				sorting[sorting.length-1]._idx = 0;
6161			}
6162			else {
6163				// No sort on this column yet, being added from a colspan
6164				// so add with same direction as first column
6165				sorting.push( [ colIdx, sorting[0][1], 0 ] );
6166				sorting[sorting.length-1]._idx = 0;
6167			}
6168		}
6169		else if ( sorting.length && sorting[0][0] == colIdx ) {
6170			// Single column - already sorting on this column, modify the sort
6171			nextSortIdx = next( sorting[0] );
6172	
6173			sorting.length = 1;
6174			sorting[0][1] = asSorting[ nextSortIdx ];
6175			sorting[0]._idx = nextSortIdx;
6176		}
6177		else {
6178			// Single column - sort only on this column
6179			sorting.length = 0;
6180			sorting.push( [ colIdx, asSorting[0] ] );
6181			sorting[0]._idx = 0;
6182		}
6183	}
6184	
6185	
6186	/**
6187	 * Set the sorting classes on table's body, Note: it is safe to call this function
6188	 * when bSort and bSortClasses are false
6189	 *  @param {object} oSettings dataTables settings object
6190	 *  @memberof DataTable#oApi
6191	 */
6192	function _fnSortingClasses( settings )
6193	{
6194		var oldSort = settings.aLastSort;
6195		var sortClass = settings.oClasses.order.position;
6196		var sort = _fnSortFlatten( settings );
6197		var features = settings.oFeatures;
6198		var i, ien, colIdx;
6199	
6200		if ( features.bSort && features.bSortClasses ) {
6201			// Remove old sorting classes
6202			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6203				colIdx = oldSort[i].src;
6204	
6205				// Remove column sorting
6206				$( _pluck( settings.aoData, 'anCells', colIdx ) )
6207					.removeClass( sortClass + (i<2 ? i+1 : 3) );
6208			}
6209	
6210			// Add new column sorting
6211			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6212				colIdx = sort[i].src;
6213	
6214				$( _pluck( settings.aoData, 'anCells', colIdx ) )
6215					.addClass( sortClass + (i<2 ? i+1 : 3) );
6216			}
6217		}
6218	
6219		settings.aLastSort = sort;
6220	}
6221	
6222	
6223	// Get the data to sort a column, be it from cache, fresh (populating the
6224	// cache), or from a sort formatter
6225	function _fnSortData( settings, colIdx )
6226	{
6227		// Custom sorting function - provided by the sort data type
6228		var column = settings.aoColumns[ colIdx ];
6229		var customSort = DataTable.ext.order[ column.sSortDataType ];
6230		var customData;
6231	
6232		if ( customSort ) {
6233			customData = customSort.call( settings.oInstance, settings, colIdx,
6234				_fnColumnIndexToVisible( settings, colIdx )
6235			);
6236		}
6237	
6238		// Use / populate cache
6239		var row, cellData;
6240		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6241		var data = settings.aoData;
6242	
6243		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
6244			// Sparse array
6245			if (! data[rowIdx]) {
6246				continue;
6247			}
6248	
6249			row = data[rowIdx];
6250	
6251			if ( ! row._aSortData ) {
6252				row._aSortData = [];
6253			}
6254	
6255			if ( ! row._aSortData[colIdx] || customSort ) {
6256				cellData = customSort ?
6257					customData[rowIdx] : // If there was a custom sort function, use data from there
6258					_fnGetCellData( settings, rowIdx, colIdx, 'sort' );
6259	
6260				row._aSortData[ colIdx ] = formatter ?
6261					formatter( cellData, settings ) :
6262					cellData;
6263			}
6264		}
6265	}
6266	
6267	
6268	/**
6269	 * State information for a table
6270	 *
6271	 * @param {*} settings
6272	 * @returns State object
6273	 */
6274	function _fnSaveState ( settings )
6275	{
6276		if (settings._bLoadingState) {
6277			return;
6278		}
6279	
6280		// Sort state saving uses [[idx, order]] structure.
6281		var sorting = [];
6282		_fnSortResolve(settings, sorting, settings.aaSorting );
6283	
6284		/* Store the interesting variables */
6285		var columns = settings.aoColumns;
6286		var state = {
6287			time:    +new Date(),
6288			start:   settings._iDisplayStart,
6289			length:  settings._iDisplayLength,
6290			order:   sorting.map(function (sort) {
6291				// If a column name is available, use it
6292				return columns[sort[0]] && columns[sort[0]].sName
6293					? [ columns[sort[0]].sName, sort[1] ]
6294					: sort.slice();
6295			} ),
6296			search:  $.extend({}, settings.oPreviousSearch),
6297			columns: settings.aoColumns.map( function ( col, i ) {
6298				return {
6299					name: col.sName,
6300					visible: col.bVisible,
6301					search: $.extend({}, settings.aoPreSearchCols[i])
6302				};
6303			} )
6304		};
6305	
6306		settings.oSavedState = state;
6307		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6308		
6309		if ( settings.oFeatures.bStateSave && !settings.bDestroying )
6310		{
6311			settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6312		}	
6313	}
6314	
6315	
6316	/**
6317	 * Attempt to load a saved table state
6318	 *  @param {object} oSettings dataTables settings object
6319	 *  @param {object} oInit DataTables init object so we can override settings
6320	 *  @param {function} callback Callback to execute when the state has been loaded
6321	 *  @memberof DataTable#oApi
6322	 */
6323	function _fnLoadState ( settings, init, callback )
6324	{
6325		if ( ! settings.oFeatures.bStateSave ) {
6326			callback();
6327			return;
6328		}
6329	
6330		var loaded = function(state) {
6331			_fnImplementState(settings, state, callback);
6332		}
6333	
6334		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6335	
6336		if ( state !== undefined ) {
6337			_fnImplementState( settings, state, callback );
6338		}
6339		// otherwise, wait for the loaded callback to be executed
6340	
6341		return true;
6342	}
6343	
6344	function _fnImplementState ( settings, s, callback) {
6345		var i, ien;
6346		var columns = settings.aoColumns;
6347		var currentNames = _pluck(settings.aoColumns, 'sName');
6348	
6349		settings._bLoadingState = true;
6350	
6351		// When StateRestore was introduced the state could now be implemented at any time
6352		// Not just initialisation. To do this an api instance is required in some places
6353		var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
6354	
6355		if ( ! s || ! s.time ) {
6356			settings._bLoadingState = false;
6357			callback();
6358			return;
6359		}
6360	
6361		// Reject old data
6362		var duration = settings.iStateDuration;
6363		if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6364			settings._bLoadingState = false;
6365			callback();
6366			return;
6367		}
6368	
6369		// Allow custom and plug-in manipulation functions to alter the saved data set and
6370		// cancelling of loading by returning false
6371		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6372		if ( abStateLoad.indexOf(false) !== -1 ) {
6373			settings._bLoadingState = false;
6374			callback();
6375			return;
6376		}
6377	
6378		// Store the saved state so it might be accessed at any time
6379		settings.oLoadedState = $.extend( true, {}, s );
6380	
6381		// This is needed for ColReorder, which has to happen first to allow all
6382		// the stored indexes to be usable. It is not publicly documented.
6383		_fnCallbackFire( settings, null, 'stateLoadInit', [settings, s], true );
6384	
6385		// Page Length
6386		if ( s.length !== undefined ) {
6387			// If already initialised just set the value directly so that the select element is also updated
6388			if (api) {
6389				api.page.len(s.length)
6390			}
6391			else {
6392				settings._iDisplayLength   = s.length;
6393			}
6394		}
6395	
6396		// Restore key features
6397		if ( s.start !== undefined ) {
6398			if(api === null) {
6399				settings._iDisplayStart    = s.start;
6400				settings.iInitDisplayStart = s.start;
6401			}
6402			else {
6403				_fnPageChange(settings, s.start/settings._iDisplayLength);
6404			}
6405		}
6406	
6407		// Order
6408		if ( s.order !== undefined ) {
6409			settings.aaSorting = [];
6410			$.each( s.order, function ( i, col ) {
6411				var set = [ col[0], col[1] ];
6412	
6413				// A column name was stored and should be used for restore
6414				if (typeof col[0] === 'string') {
6415					// Find the name from the current list of column names
6416					var idx = currentNames.indexOf(col[0]);
6417	
6418					if (idx < 0) {
6419						// If the column was not found ignore it and continue
6420						return;
6421					}
6422	
6423					set[0] = idx;
6424				}
6425				else if (set[0] >= columns.length) {
6426					// If the column index is out of bounds ignore it and continue
6427					return;
6428				}
6429	
6430				settings.aaSorting.push(set);
6431			} );
6432		}
6433	
6434		// Search
6435		if ( s.search !== undefined ) {
6436			$.extend( settings.oPreviousSearch, s.search );
6437		}
6438	
6439		// Columns
6440		if ( s.columns ) {
6441			var set = s.columns;
6442			var incoming = _pluck(s.columns, 'name');
6443	
6444			// Check if it is a 2.2 style state object with a `name` property for the columns, and if
6445			// the name was defined. If so, then create a new array that will map the state object
6446			// given, to the current columns (don't bother if they are already matching tho).
6447			if (incoming.join('').length && incoming.join('') !== currentNames.join('')) {
6448				set = [];
6449	
6450				// For each column, try to find the name in the incoming array
6451				for (i=0 ; i<currentNames.length ; i++) {
6452					if (currentNames[i] != '') {
6453						var idx = incoming.indexOf(currentNames[i]);
6454	
6455						if (idx >= 0) {
6456							set.push(s.columns[idx]);
6457						}
6458						else {
6459							// No matching column name in the state's columns, so this might be a new
6460							// column and thus can't have a state already.
6461							set.push({});
6462						}
6463					}
6464					else {
6465						// If no name, but other columns did have a name, then there is no knowing
6466						// where this one came from originally so it can't be restored.
6467						set.push({});
6468					}
6469				}
6470			}
6471	
6472			// If the number of columns to restore is different from current, then all bets are off.
6473			if (set.length === columns.length) {
6474				for ( i=0, ien=set.length ; i<ien ; i++ ) {
6475					var col = set[i];
6476	
6477					// Visibility
6478					if ( col.visible !== undefined ) {
6479						// If the api is defined, the table has been initialised so we need to use it rather than internal settings
6480						if (api) {
6481							// Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6482							api.column(i).visible(col.visible, false);
6483						}
6484						else {
6485							columns[i].bVisible = col.visible;
6486						}
6487					}
6488	
6489					// Search
6490					if ( col.search !== undefined ) {
6491						$.extend( settings.aoPreSearchCols[i], col.search );
6492					}
6493				}
6494	
6495				// If the api is defined then we need to adjust the columns once the visibility has been changed
6496				if (api) {
6497					api.columns.adjust();
6498				}
6499			}
6500		}
6501	
6502		settings._bLoadingState = false;
6503		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6504		callback();
6505	}
6506	
6507	/**
6508	 * Log an error message
6509	 *  @param {object} settings dataTables settings object
6510	 *  @param {int} level log error messages, or display them to the user
6511	 *  @param {string} msg error message
6512	 *  @param {int} tn Technical note id to get more information about the error.
6513	 *  @memberof DataTable#oApi
6514	 */
6515	function _fnLog( settings, level, msg, tn )
6516	{
6517		msg = 'DataTables warning: '+
6518			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6519	
6520		if ( tn ) {
6521			msg += '. For more information about this error, please see '+
6522			'https://datatables.net/tn/'+tn;
6523		}
6524	
6525		if ( ! level  ) {
6526			// Backwards compatibility pre 1.10
6527			var ext = DataTable.ext;
6528			var type = ext.sErrMode || ext.errMode;
6529	
6530			if ( settings ) {
6531				_fnCallbackFire( settings, null, 'dt-error', [ settings, tn, msg ], true );
6532			}
6533	
6534			if ( type == 'alert' ) {
6535				alert( msg );
6536			}
6537			else if ( type == 'throw' ) {
6538				throw new Error(msg);
6539			}
6540			else if ( typeof type == 'function' ) {
6541				type( settings, tn, msg );
6542			}
6543		}
6544		else if ( window.console && console.log ) {
6545			console.log( msg );
6546		}
6547	}
6548	
6549	
6550	/**
6551	 * See if a property is defined on one object, if so assign it to the other object
6552	 *  @param {object} ret target object
6553	 *  @param {object} src source object
6554	 *  @param {string} name property
6555	 *  @param {string} [mappedName] name to map too - optional, name used if not given
6556	 *  @memberof DataTable#oApi
6557	 */
6558	function _fnMap( ret, src, name, mappedName )
6559	{
6560		if ( Array.isArray( name ) ) {
6561			$.each( name, function (i, val) {
6562				if ( Array.isArray( val ) ) {
6563					_fnMap( ret, src, val[0], val[1] );
6564				}
6565				else {
6566					_fnMap( ret, src, val );
6567				}
6568			} );
6569	
6570			return;
6571		}
6572	
6573		if ( mappedName === undefined ) {
6574			mappedName = name;
6575		}
6576	
6577		if ( src[name] !== undefined ) {
6578			ret[mappedName] = src[name];
6579		}
6580	}
6581	
6582	
6583	/**
6584	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6585	 * shallow copy arrays. The reason we need to do this, is that we don't want to
6586	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6587	 * able to override them, but we do want to deep copy arrays.
6588	 *  @param {object} out Object to extend
6589	 *  @param {object} extender Object from which the properties will be applied to
6590	 *      out
6591	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6592	 *      independent copy with the exception of the `data` or `aaData` parameters
6593	 *      if they are present. This is so you can pass in a collection to
6594	 *      DataTables and have that used as your data source without breaking the
6595	 *      references
6596	 *  @returns {object} out Reference, just for convenience - out === the return.
6597	 *  @memberof DataTable#oApi
6598	 *  @todo This doesn't take account of arrays inside the deep copied objects.
6599	 */
6600	function _fnExtend( out, extender, breakRefs )
6601	{
6602		var val;
6603	
6604		for ( var prop in extender ) {
6605			if ( Object.prototype.hasOwnProperty.call(extender, prop) ) {
6606				val = extender[prop];
6607	
6608				if ( $.isPlainObject( val ) ) {
6609					if ( ! $.isPlainObject( out[prop] ) ) {
6610						out[prop] = {};
6611					}
6612					$.extend( true, out[prop], val );
6613				}
6614				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {
6615					out[prop] = val.slice();
6616				}
6617				else {
6618					out[prop] = val;
6619				}
6620			}
6621		}
6622	
6623		return out;
6624	}
6625	
6626	
6627	/**
6628	 * Bind an event handers to allow a click or return key to activate the callback.
6629	 * This is good for accessibility since a return on the keyboard will have the
6630	 * same effect as a click, if the element has focus.
6631	 *  @param {element} n Element to bind the action to
6632	 *  @param {object|string} selector Selector (for delegated events) or data object
6633	 *   to pass to the triggered function
6634	 *  @param {function} fn Callback function for when the event is triggered
6635	 *  @memberof DataTable#oApi
6636	 */
6637	function _fnBindAction( n, selector, fn )
6638	{
6639		$(n)
6640			.on( 'click.DT', selector, function (e) {
6641				fn(e);
6642			} )
6643			.on( 'keypress.DT', selector, function (e){
6644				if ( e.which === 13 ) {
6645					e.preventDefault();
6646					fn(e);
6647				}
6648			} )
6649			.on( 'selectstart.DT', selector, function () {
6650				// Don't want a double click resulting in text selection
6651				return false;
6652			} );
6653	}
6654	
6655	
6656	/**
6657	 * Register a callback function. Easily allows a callback function to be added to
6658	 * an array store of callback functions that can then all be called together.
6659	 *  @param {object} settings dataTables settings object
6660	 *  @param {string} store Name of the array storage for the callbacks in oSettings
6661	 *  @param {function} fn Function to be called back
6662	 *  @memberof DataTable#oApi
6663	 */
6664	function _fnCallbackReg( settings, store, fn )
6665	{
6666		if ( fn ) {
6667			settings[store].push(fn);
6668		}
6669	}
6670	
6671	
6672	/**
6673	 * Fire callback functions and trigger events. Note that the loop over the
6674	 * callback array store is done backwards! Further note that you do not want to
6675	 * fire off triggers in time sensitive applications (for example cell creation)
6676	 * as its slow.
6677	 *  @param {object} settings dataTables settings object
6678	 *  @param {string} callbackArr Name of the array storage for the callbacks in
6679	 *      oSettings
6680	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
6681	 *      null no trigger is fired
6682	 *  @param {array} args Array of arguments to pass to the callback function /
6683	 *      trigger
6684	 *  @param {boolean} [bubbles] True if the event should bubble
6685	 *  @memberof DataTable#oApi
6686	 */
6687	function _fnCallbackFire( settings, callbackArr, eventName, args, bubbles )
6688	{
6689		var ret = [];
6690	
6691		if ( callbackArr ) {
6692			ret = settings[callbackArr].slice().reverse().map( function (val) {
6693				return val.apply( settings.oInstance, args );
6694			} );
6695		}
6696	
6697		if ( eventName !== null) {
6698			var e = $.Event( eventName+'.dt' );
6699			var table = $(settings.nTable);
6700			
6701			// Expose the DataTables API on the event object for easy access
6702			e.dt = settings.api;
6703	
6704			table[bubbles ?  'trigger' : 'triggerHandler']( e, args );
6705	
6706			// If not yet attached to the document, trigger the event
6707			// on the body directly to sort of simulate the bubble
6708			if (bubbles && table.parents('body').length === 0) {
6709				$('body').trigger( e, args );
6710			}
6711	
6712			ret.push( e.result );
6713		}
6714	
6715		return ret;
6716	}
6717	
6718	
6719	function _fnLengthOverflow ( settings )
6720	{
6721		var
6722			start = settings._iDisplayStart,
6723			end = settings.fnDisplayEnd(),
6724			len = settings._iDisplayLength;
6725	
6726		/* If we have space to show extra rows (backing up from the end point - then do so */
6727		if ( start >= end )
6728		{
6729			start = end - len;
6730		}
6731	
6732		// Keep the start record on the current page
6733		start -= (start % len);
6734	
6735		if ( len === -1 || start < 0 )
6736		{
6737			start = 0;
6738		}
6739	
6740		settings._iDisplayStart = start;
6741	}
6742	
6743	
6744	function _fnRenderer( settings, type )
6745	{
6746		var renderer = settings.renderer;
6747		var host = DataTable.ext.renderer[type];
6748	
6749		if ( $.isPlainObject( renderer ) && renderer[type] ) {
6750			// Specific renderer for this type. If available use it, otherwise use
6751			// the default.
6752			return host[renderer[type]] || host._;
6753		}
6754		else if ( typeof renderer === 'string' ) {
6755			// Common renderer - if there is one available for this type use it,
6756			// otherwise use the default
6757			return host[renderer] || host._;
6758		}
6759	
6760		// Use the default
6761		return host._;
6762	}
6763	
6764	
6765	/**
6766	 * Detect the data source being used for the table. Used to simplify the code
6767	 * a little (ajax) and to make it compress a little smaller.
6768	 *
6769	 *  @param {object} settings dataTables settings object
6770	 *  @returns {string} Data source
6771	 *  @memberof DataTable#oApi
6772	 */
6773	function _fnDataSource ( settings )
6774	{
6775		if ( settings.oFeatures.bServerSide ) {
6776			return 'ssp';
6777		}
6778		else if ( settings.ajax ) {
6779			return 'ajax';
6780		}
6781		return 'dom';
6782	}
6783	
6784	/**
6785	 * Common replacement for language strings
6786	 *
6787	 * @param {*} settings DT settings object
6788	 * @param {*} str String with values to replace
6789	 * @param {*} entries Plural number for _ENTRIES_ - can be undefined
6790	 * @returns String
6791	 */
6792	function _fnMacros ( settings, str, entries )
6793	{
6794		// When infinite scrolling, we are always starting at 1. _iDisplayStart is
6795		// used only internally
6796		var
6797			formatter  = settings.fnFormatNumber,
6798			start      = settings._iDisplayStart+1,
6799			len        = settings._iDisplayLength,
6800			vis        = settings.fnRecordsDisplay(),
6801			max        = settings.fnRecordsTotal(),
6802			all        = len === -1;
6803	
6804		return str.
6805			replace(/_START_/g, formatter.call( settings, start ) ).
6806			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
6807			replace(/_MAX_/g,   formatter.call( settings, max ) ).
6808			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
6809			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
6810			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ).
6811			replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries) ).
6812			replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max) ).
6813			replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
6814	}
6815	
6816	/**
6817	 * Add elements to an array as quickly as possible, but stack stafe.
6818	 *
6819	 * @param {*} arr Array to add the data to
6820	 * @param {*} data Data array that is to be added
6821	 * @returns 
6822	 */
6823	function _fnArrayApply(arr, data) {
6824		if (! data) {
6825			return;
6826		}
6827	
6828		// Chrome can throw a max stack error if apply is called with
6829		// too large an array, but apply is faster.
6830		if (data.length < 10000) {
6831			arr.push.apply(arr, data);
6832		}
6833		else {
6834			for (i=0 ; i<data.length ; i++) {
6835				arr.push(data[i]);
6836			}
6837		}
6838	}
6839	
6840	/**
6841	 * Add one or more listeners to the table
6842	 *
6843	 * @param {*} that JQ for the table
6844	 * @param {*} name Event name
6845	 * @param {*} src Listener(s)
6846	 */
6847	function _fnListener(that, name, src) {
6848		if (!Array.isArray(src)) {
6849			src = [src];
6850		}
6851	
6852		for (i=0 ; i<src.length ; i++) {
6853			that.on(name + '.dt', src[i]);
6854		}
6855	}
6856	
6857	
6858	
6859	/**
6860	 * Computed structure of the DataTables API, defined by the options passed to
6861	 * `DataTable.Api.register()` when building the API.
6862	 *
6863	 * The structure is built in order to speed creation and extension of the Api
6864	 * objects since the extensions are effectively pre-parsed.
6865	 *
6866	 * The array is an array of objects with the following structure, where this
6867	 * base array represents the Api prototype base:
6868	 *
6869	 *     [
6870	 *       {
6871	 *         name:      'data'                -- string   - Property name
6872	 *         val:       function () {},       -- function - Api method (or undefined if just an object
6873	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6874	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6875	 *       },
6876	 *       {
6877	 *         name:     'row'
6878	 *         val:       {},
6879	 *         methodExt: [ ... ],
6880	 *         propExt:   [
6881	 *           {
6882	 *             name:      'data'
6883	 *             val:       function () {},
6884	 *             methodExt: [ ... ],
6885	 *             propExt:   [ ... ]
6886	 *           },
6887	 *           ...
6888	 *         ]
6889	 *       }
6890	 *     ]
6891	 *
6892	 * @type {Array}
6893	 * @ignore
6894	 */
6895	var __apiStruct = [];
6896	
6897	
6898	/**
6899	 * `Array.prototype` reference.
6900	 *
6901	 * @type object
6902	 * @ignore
6903	 */
6904	var __arrayProto = Array.prototype;
6905	
6906	
6907	/**
6908	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6909	 * take several different forms for ease of use.
6910	 *
6911	 * Each of the input parameter types will be converted to a DataTables settings
6912	 * object where possible.
6913	 *
6914	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6915	 *   of:
6916	 *
6917	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6918	 *     with be found and used.
6919	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6920	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6921	 *   * `object` - DataTables settings object
6922	 *   * `DataTables.Api` - API instance
6923	 * @return {array|null} Matching DataTables settings objects. `null` or
6924	 *   `undefined` is returned if no matching DataTable is found.
6925	 * @ignore
6926	 */
6927	var _toSettings = function ( mixed )
6928	{
6929		var idx, jq;
6930		var settings = DataTable.settings;
6931		var tables = _pluck(settings, 'nTable');
6932	
6933		if ( ! mixed ) {
6934			return [];
6935		}
6936		else if ( mixed.nTable && mixed.oFeatures ) {
6937			// DataTables settings object
6938			return [ mixed ];
6939		}
6940		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6941			// Table node
6942			idx = tables.indexOf(mixed);
6943			return idx !== -1 ? [ settings[idx] ] : null;
6944		}
6945		else if ( mixed && typeof mixed.settings === 'function' ) {
6946			return mixed.settings().toArray();
6947		}
6948		else if ( typeof mixed === 'string' ) {
6949			// jQuery selector
6950			jq = $(mixed).get();
6951		}
6952		else if ( mixed instanceof $ ) {
6953			// jQuery object (also DataTables instance)
6954			jq = mixed.get();
6955		}
6956	
6957		if ( jq ) {
6958			return settings.filter(function (v, idx) {
6959				return jq.includes(tables[idx]);
6960			});
6961		}
6962	};
6963	
6964	
6965	/**
6966	 * DataTables API class - used to control and interface with  one or more
6967	 * DataTables enhanced tables.
6968	 *
6969	 * The API class is heavily based on jQuery, presenting a chainable interface
6970	 * that you can use to interact with tables. Each instance of the API class has
6971	 * a "context" - i.e. the tables that it will operate on. This could be a single
6972	 * table, all tables on a page or a sub-set thereof.
6973	 *
6974	 * Additionally the API is designed to allow you to easily work with the data in
6975	 * the tables, retrieving and manipulating it as required. This is done by
6976	 * presenting the API class as an array like interface. The contents of the
6977	 * array depend upon the actions requested by each method (for example
6978	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6979	 * return an array of objects or arrays depending upon your table's
6980	 * configuration). The API object has a number of array like methods (`push`,
6981	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6982	 * `unique` etc) to assist your working with the data held in a table.
6983	 *
6984	 * Most methods (those which return an Api instance) are chainable, which means
6985	 * the return from a method call also has all of the methods available that the
6986	 * top level object had. For example, these two calls are equivalent:
6987	 *
6988	 *     // Not chained
6989	 *     api.row.add( {...} );
6990	 *     api.draw();
6991	 *
6992	 *     // Chained
6993	 *     api.row.add( {...} ).draw();
6994	 *
6995	 * @class DataTable.Api
6996	 * @param {array|object|string|jQuery} context DataTable identifier. This is
6997	 *   used to define which DataTables enhanced tables this API will operate on.
6998	 *   Can be one of:
6999	 *
7000	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
7001	 *     with be found and used.
7002	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
7003	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
7004	 *   * `object` - DataTables settings object
7005	 * @param {array} [data] Data to initialise the Api instance with.
7006	 *
7007	 * @example
7008	 *   // Direct initialisation during DataTables construction
7009	 *   var api = $('#example').DataTable();
7010	 *
7011	 * @example
7012	 *   // Initialisation using a DataTables jQuery object
7013	 *   var api = $('#example').dataTable().api();
7014	 *
7015	 * @example
7016	 *   // Initialisation as a constructor
7017	 *   var api = new DataTable.Api( 'table.dataTable' );
7018	 */
7019	_Api = function ( context, data )
7020	{
7021		if ( ! (this instanceof _Api) ) {
7022			return new _Api( context, data );
7023		}
7024	
7025		var i;
7026		var settings = [];
7027		var ctxSettings = function ( o ) {
7028			var a = _toSettings( o );
7029			if ( a ) {
7030				settings.push.apply( settings, a );
7031			}
7032		};
7033	
7034		if ( Array.isArray( context ) ) {
7035			for ( i=0 ; i<context.length ; i++ ) {
7036				ctxSettings( context[i] );
7037			}
7038		}
7039		else {
7040			ctxSettings( context );
7041		}
7042	
7043		// Remove duplicates
7044		this.context = settings.length > 1
7045			? _unique( settings )
7046			: settings;
7047	
7048		// Initial data
7049		_fnArrayApply(this, data);
7050	
7051		// selector
7052		this.selector = {
7053			rows: null,
7054			cols: null,
7055			opts: null
7056		};
7057	
7058		_Api.extend( this, this, __apiStruct );
7059	};
7060	
7061	DataTable.Api = _Api;
7062	
7063	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
7064	// isPlainObject.
7065	$.extend( _Api.prototype, {
7066		any: function ()
7067		{
7068			return this.count() !== 0;
7069		},
7070	
7071		context: [], // array of table settings objects
7072	
7073		count: function ()
7074		{
7075			return this.flatten().length;
7076		},
7077	
7078		each: function ( fn )
7079		{
7080			for ( var i=0, ien=this.length ; i<ien; i++ ) {
7081				fn.call( this, this[i], i, this );
7082			}
7083	
7084			return this;
7085		},
7086	
7087		eq: function ( idx )
7088		{
7089			var ctx = this.context;
7090	
7091			return ctx.length > idx ?
7092				new _Api( ctx[idx], this[idx] ) :
7093				null;
7094		},
7095	
7096		filter: function ( fn )
7097		{
7098			var a = __arrayProto.filter.call( this, fn, this );
7099	
7100			return new _Api( this.context, a );
7101		},
7102	
7103		flatten: function ()
7104		{
7105			var a = [];
7106	
7107			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
7108		},
7109	
7110		get: function ( idx )
7111		{
7112			return this[ idx ];
7113		},
7114	
7115		join:    __arrayProto.join,
7116	
7117		includes: function ( find ) {
7118			return this.indexOf( find ) === -1 ? false : true;
7119		},
7120	
7121		indexOf: __arrayProto.indexOf,
7122	
7123		iterator: function ( flatten, type, fn, alwaysNew ) {
7124			var
7125				a = [], ret,
7126				i, ien, j, jen,
7127				context = this.context,
7128				rows, items, item,
7129				selector = this.selector;
7130	
7131			// Argument shifting
7132			if ( typeof flatten === 'string' ) {
7133				alwaysNew = fn;
7134				fn = type;
7135				type = flatten;
7136				flatten = false;
7137			}
7138	
7139			for ( i=0, ien=context.length ; i<ien ; i++ ) {
7140				var apiInst = new _Api( context[i] );
7141	
7142				if ( type === 'table' ) {
7143					ret = fn.call( apiInst, context[i], i );
7144	
7145					if ( ret !== undefined ) {
7146						a.push( ret );
7147					}
7148				}
7149				else if ( type === 'columns' || type === 'rows' ) {
7150					// this has same length as context - one entry for each table
7151					ret = fn.call( apiInst, context[i], this[i], i );
7152	
7153					if ( ret !== undefined ) {
7154						a.push( ret );
7155					}
7156				}
7157				else if ( type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7158					// columns and rows share the same structure.
7159					// 'this' is an array of column indexes for each context
7160					items = this[i];
7161	
7162					if ( type === 'column-rows' ) {
7163						rows = _selector_row_indexes( context[i], selector.opts );
7164					}
7165	
7166					for ( j=0, jen=items.length ; j<jen ; j++ ) {
7167						item = items[j];
7168	
7169						if ( type === 'cell' ) {
7170							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7171						}
7172						else {
7173							ret = fn.call( apiInst, context[i], item, i, j, rows );
7174						}
7175	
7176						if ( ret !== undefined ) {
7177							a.push( ret );
7178						}
7179					}
7180				}
7181			}
7182	
7183			if ( a.length || alwaysNew ) {
7184				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7185				var apiSelector = api.selector;
7186				apiSelector.rows = selector.rows;
7187				apiSelector.cols = selector.cols;
7188				apiSelector.opts = selector.opts;
7189				return api;
7190			}
7191			return this;
7192		},
7193	
7194		lastIndexOf: __arrayProto.lastIndexOf,
7195	
7196		length:  0,
7197	
7198		map: function ( fn )
7199		{
7200			var a = __arrayProto.map.call( this, fn, this );
7201	
7202			return new _Api( this.context, a );
7203		},
7204	
7205		pluck: function ( prop )
7206		{
7207			var fn = DataTable.util.get(prop);
7208	
7209			return this.map( function ( el ) {
7210				return fn(el);
7211			} );
7212		},
7213	
7214		pop:     __arrayProto.pop,
7215	
7216		push:    __arrayProto.push,
7217	
7218		reduce: __arrayProto.reduce,
7219	
7220		reduceRight: __arrayProto.reduceRight,
7221	
7222		reverse: __arrayProto.reverse,
7223	
7224		// Object with rows, columns and opts
7225		selector: null,
7226	
7227		shift:   __arrayProto.shift,
7228	
7229		slice: function () {
7230			return new _Api( this.context, this );
7231		},
7232	
7233		sort:    __arrayProto.sort,
7234	
7235		splice:  __arrayProto.splice,
7236	
7237		toArray: function ()
7238		{
7239			return __arrayProto.slice.call( this );
7240		},
7241	
7242		to$: function ()
7243		{
7244			return $( this );
7245		},
7246	
7247		toJQuery: function ()
7248		{
7249			return $( this );
7250		},
7251	
7252		unique: function ()
7253		{
7254			return new _Api( this.context, _unique(this.toArray()) );
7255		},
7256	
7257		unshift: __arrayProto.unshift
7258	} );
7259	
7260	
7261	function _api_scope( scope, fn, struc ) {
7262		return function () {
7263			var ret = fn.apply( scope || this, arguments );
7264	
7265			// Method extension
7266			_Api.extend( ret, ret, struc.methodExt );
7267			return ret;
7268		};
7269	}
7270	
7271	function _api_find( src, name ) {
7272		for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7273			if ( src[i].name === name ) {
7274				return src[i];
7275			}
7276		}
7277		return null;
7278	}
7279	
7280	window.__apiStruct = __apiStruct;
7281	
7282	_Api.extend = function ( scope, obj, ext )
7283	{
7284		// Only extend API instances and static properties of the API
7285		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7286			return;
7287		}
7288	
7289		var
7290			i, ien,
7291			struct;
7292	
7293		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7294			struct = ext[i];
7295	
7296			if (struct.name === '__proto__') {
7297				continue;
7298			}
7299	
7300			// Value
7301			obj[ struct.name ] = struct.type === 'function' ?
7302				_api_scope( scope, struct.val, struct ) :
7303				struct.type === 'object' ?
7304					{} :
7305					struct.val;
7306	
7307			obj[ struct.name ].__dt_wrapper = true;
7308	
7309			// Property extension
7310			_Api.extend( scope, obj[ struct.name ], struct.propExt );
7311		}
7312	};
7313	
7314	//     [
7315	//       {
7316	//         name:      'data'                -- string   - Property name
7317	//         val:       function () {},       -- function - Api method (or undefined if just an object
7318	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
7319	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
7320	//       },
7321	//       {
7322	//         name:     'row'
7323	//         val:       {},
7324	//         methodExt: [ ... ],
7325	//         propExt:   [
7326	//           {
7327	//             name:      'data'
7328	//             val:       function () {},
7329	//             methodExt: [ ... ],
7330	//             propExt:   [ ... ]
7331	//           },
7332	//           ...
7333	//         ]
7334	//       }
7335	//     ]
7336	
7337	
7338	_Api.register = _api_register = function ( name, val )
7339	{
7340		if ( Array.isArray( name ) ) {
7341			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7342				_Api.register( name[j], val );
7343			}
7344			return;
7345		}
7346	
7347		var
7348			i, ien,
7349			heir = name.split('.'),
7350			struct = __apiStruct,
7351			key, method;
7352	
7353		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7354			method = heir[i].indexOf('()') !== -1;
7355			key = method ?
7356				heir[i].replace('()', '') :
7357				heir[i];
7358	
7359			var src = _api_find( struct, key );
7360			if ( ! src ) {
7361				src = {
7362					name:      key,
7363					val:       {},
7364					methodExt: [],
7365					propExt:   [],
7366					type:      'object'
7367				};
7368				struct.push( src );
7369			}
7370	
7371			if ( i === ien-1 ) {
7372				src.val = val;
7373				src.type = typeof val === 'function' ?
7374					'function' :
7375					$.isPlainObject( val ) ?
7376						'object' :
7377						'other';
7378			}
7379			else {
7380				struct = method ?
7381					src.methodExt :
7382					src.propExt;
7383			}
7384		}
7385	};
7386	
7387	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7388		_Api.register( pluralName, val );
7389	
7390		_Api.register( singularName, function () {
7391			var ret = val.apply( this, arguments );
7392	
7393			if ( ret === this ) {
7394				// Returned item is the API instance that was passed in, return it
7395				return this;
7396			}
7397			else if ( ret instanceof _Api ) {
7398				// New API instance returned, want the value from the first item
7399				// in the returned array for the singular result.
7400				return ret.length ?
7401					Array.isArray( ret[0] ) ?
7402						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7403						ret[0] :
7404					undefined;
7405			}
7406	
7407			// Non-API return - just fire it back
7408			return ret;
7409		} );
7410	};
7411	
7412	
7413	/**
7414	 * Selector for HTML tables. Apply the given selector to the give array of
7415	 * DataTables settings objects.
7416	 *
7417	 * @param {string|integer} [selector] jQuery selector string or integer
7418	 * @param  {array} Array of DataTables settings objects to be filtered
7419	 * @return {array}
7420	 * @ignore
7421	 */
7422	var __table_selector = function ( selector, a )
7423	{
7424		if ( Array.isArray(selector) ) {
7425			var result = [];
7426	
7427			selector.forEach(function (sel) {
7428				var inner = __table_selector(sel, a);
7429	
7430				_fnArrayApply(result, inner);
7431			});
7432	
7433			return result.filter( function (item) {
7434				return item;
7435			});
7436		}
7437	
7438		// Integer is used to pick out a table by index
7439		if ( typeof selector === 'number' ) {
7440			return [ a[ selector ] ];
7441		}
7442	
7443		// Perform a jQuery selector on the table nodes
7444		var nodes = a.map( function (el) {
7445			return el.nTable;
7446		} );
7447	
7448		return $(nodes)
7449			.filter( selector )
7450			.map( function () {
7451				// Need to translate back from the table node to the settings
7452				var idx = nodes.indexOf(this);
7453				return a[ idx ];
7454			} )
7455			.toArray();
7456	};
7457	
7458	
7459	
7460	/**
7461	 * Context selector for the API's context (i.e. the tables the API instance
7462	 * refers to.
7463	 *
7464	 * @name    DataTable.Api#tables
7465	 * @param {string|integer} [selector] Selector to pick which tables the iterator
7466	 *   should operate on. If not given, all tables in the current context are
7467	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7468	 *   select multiple tables or as an integer to select a single table.
7469	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7470	 */
7471	_api_register( 'tables()', function ( selector ) {
7472		// A new instance is created if there was a selector specified
7473		return selector !== undefined && selector !== null ?
7474			new _Api( __table_selector( selector, this.context ) ) :
7475			this;
7476	} );
7477	
7478	
7479	_api_register( 'table()', function ( selector ) {
7480		var tables = this.tables( selector );
7481		var ctx = tables.context;
7482	
7483		// Truncate to the first matched table
7484		return ctx.length ?
7485			new _Api( ctx[0] ) :
7486			tables;
7487	} );
7488	
7489	// Common methods, combined to reduce size
7490	[
7491		['nodes', 'node', 'nTable'],
7492		['body', 'body', 'nTBody'],
7493		['header', 'header', 'nTHead'],
7494		['footer', 'footer', 'nTFoot'],
7495	].forEach(function (item) {
7496		_api_registerPlural(
7497			'tables().' + item[0] + '()',
7498			'table().' + item[1] + '()' ,
7499			function () {
7500				return this.iterator( 'table', function ( ctx ) {
7501					return ctx[item[2]];
7502				}, 1 );
7503			}
7504		);
7505	});
7506	
7507	// Structure methods
7508	[
7509		['header', 'aoHeader'],
7510		['footer', 'aoFooter'],
7511	].forEach(function (item) {
7512		_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
7513			var indexes = this.columns(selector).indexes().flatten().toArray();
7514			var ctx = this.context[0];
7515			var structure = _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7516	
7517			// The structure is in column index order - but from this method we want the return to be
7518			// in the columns() selector API order. In order to do that we need to map from one form
7519			// to the other
7520			var orderedIndexes = indexes.slice().sort(function (a, b) {
7521				return a - b;
7522			});
7523	
7524			return structure.map(function (row) {
7525				return indexes.map(function (colIdx) {
7526					return row[orderedIndexes.indexOf(colIdx)];
7527				});
7528			});
7529		});
7530	});
7531	
7532	
7533	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7534		return this.iterator( 'table', function ( ctx ) {
7535			return ctx.nTableWrapper;
7536		}, 1 );
7537	} );
7538	
7539	_api_register( 'tables().every()', function ( fn ) {
7540		var that = this;
7541	
7542		return this.iterator('table', function (s, i) {
7543			fn.call(that.table(i), i);
7544		});
7545	});
7546	
7547	_api_register( 'caption()', function ( value, side ) {
7548		var context = this.context;
7549	
7550		// Getter - return existing node's content
7551		if ( value === undefined ) {
7552			var caption = context[0].captionNode;
7553	
7554			return caption && context.length ?
7555				caption.innerHTML : 
7556				null;
7557		}
7558	
7559		return this.iterator( 'table', function ( ctx ) {
7560			var table = $(ctx.nTable);
7561			var caption = $(ctx.captionNode);
7562			var container = $(ctx.nTableWrapper);
7563	
7564			// Create the node if it doesn't exist yet
7565			if ( ! caption.length ) {
7566				caption = $('<caption/>').html( value );
7567				ctx.captionNode = caption[0];
7568	
7569				// If side isn't set, we need to insert into the document to let the
7570				// CSS decide so we can read it back, otherwise there is no way to
7571				// know if the CSS would put it top or bottom for scrolling
7572				if (! side) {
7573					table.prepend(caption);
7574	
7575					side = caption.css('caption-side');
7576				}
7577			}
7578	
7579			caption.html( value );
7580	
7581			if ( side ) {
7582				caption.css( 'caption-side', side );
7583				caption[0]._captionSide = side;
7584			}
7585	
7586			if (container.find('div.dataTables_scroll').length) {
7587				var selector = (side === 'top' ? 'Head' : 'Foot');
7588	
7589				container.find('div.dataTables_scroll'+ selector +' table').prepend(caption);
7590			}
7591			else {
7592				table.prepend(caption);
7593			}
7594		}, 1 );
7595	} );
7596	
7597	_api_register( 'caption.node()', function () {
7598		var ctx = this.context;
7599	
7600		return ctx.length ? ctx[0].captionNode : null;
7601	} );
7602	
7603	
7604	/**
7605	 * Redraw the tables in the current context.
7606	 */
7607	_api_register( 'draw()', function ( paging ) {
7608		return this.iterator( 'table', function ( settings ) {
7609			if ( paging === 'page' ) {
7610				_fnDraw( settings );
7611			}
7612			else {
7613				if ( typeof paging === 'string' ) {
7614					paging = paging === 'full-hold' ?
7615						false :
7616						true;
7617				}
7618	
7619				_fnReDraw( settings, paging===false );
7620			}
7621		} );
7622	} );
7623	
7624	
7625	
7626	/**
7627	 * Get the current page index.
7628	 *
7629	 * @return {integer} Current page index (zero based)
7630	 *//**
7631	 * Set the current page.
7632	 *
7633	 * Note that if you attempt to show a page which does not exist, DataTables will
7634	 * not throw an error, but rather reset the paging.
7635	 *
7636	 * @param {integer|string} action The paging action to take. This can be one of:
7637	 *  * `integer` - The page index to jump to
7638	 *  * `string` - An action to take:
7639	 *    * `first` - Jump to first page.
7640	 *    * `next` - Jump to the next page
7641	 *    * `previous` - Jump to previous page
7642	 *    * `last` - Jump to the last page.
7643	 * @returns {DataTables.Api} this
7644	 */
7645	_api_register( 'page()', function ( action ) {
7646		if ( action === undefined ) {
7647			return this.page.info().page; // not an expensive call
7648		}
7649	
7650		// else, have an action to take on all tables
7651		return this.iterator( 'table', function ( settings ) {
7652			_fnPageChange( settings, action );
7653		} );
7654	} );
7655	
7656	
7657	/**
7658	 * Paging information for the first table in the current context.
7659	 *
7660	 * If you require paging information for another table, use the `table()` method
7661	 * with a suitable selector.
7662	 *
7663	 * @return {object} Object with the following properties set:
7664	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7665	 *  * `pages` - Total number of pages
7666	 *  * `start` - Display index for the first record shown on the current page
7667	 *  * `end` - Display index for the last record shown on the current page
7668	 *  * `length` - Display length (number of records). Note that generally `start
7669	 *    + length = end`, but this is not always true, for example if there are
7670	 *    only 2 records to show on the final page, with a length of 10.
7671	 *  * `recordsTotal` - Full data set length
7672	 *  * `recordsDisplay` - Data set length once the current filtering criterion
7673	 *    are applied.
7674	 */
7675	_api_register( 'page.info()', function () {
7676		if ( this.context.length === 0 ) {
7677			return undefined;
7678		}
7679	
7680		var
7681			settings   = this.context[0],
7682			start      = settings._iDisplayStart,
7683			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7684			visRecords = settings.fnRecordsDisplay(),
7685			all        = len === -1;
7686	
7687		return {
7688			"page":           all ? 0 : Math.floor( start / len ),
7689			"pages":          all ? 1 : Math.ceil( visRecords / len ),
7690			"start":          start,
7691			"end":            settings.fnDisplayEnd(),
7692			"length":         len,
7693			"recordsTotal":   settings.fnRecordsTotal(),
7694			"recordsDisplay": visRecords,
7695			"serverSide":     _fnDataSource( settings ) === 'ssp'
7696		};
7697	} );
7698	
7699	
7700	/**
7701	 * Get the current page length.
7702	 *
7703	 * @return {integer} Current page length. Note `-1` indicates that all records
7704	 *   are to be shown.
7705	 *//**
7706	 * Set the current page length.
7707	 *
7708	 * @param {integer} Page length to set. Use `-1` to show all records.
7709	 * @returns {DataTables.Api} this
7710	 */
7711	_api_register( 'page.len()', function ( len ) {
7712		// Note that we can't call this function 'length()' because `length`
7713		// is a Javascript property of functions which defines how many arguments
7714		// the function expects.
7715		if ( len === undefined ) {
7716			return this.context.length !== 0 ?
7717				this.context[0]._iDisplayLength :
7718				undefined;
7719		}
7720	
7721		// else, set the page length
7722		return this.iterator( 'table', function ( settings ) {
7723			_fnLengthChange( settings, len );
7724		} );
7725	} );
7726	
7727	
7728	
7729	var __reload = function ( settings, holdPosition, callback ) {
7730		// Use the draw event to trigger a callback
7731		if ( callback ) {
7732			var api = new _Api( settings );
7733	
7734			api.one( 'draw', function () {
7735				callback( api.ajax.json() );
7736			} );
7737		}
7738	
7739		if ( _fnDataSource( settings ) == 'ssp' ) {
7740			_fnReDraw( settings, holdPosition );
7741		}
7742		else {
7743			_fnProcessingDisplay( settings, true );
7744	
7745			// Cancel an existing request
7746			var xhr = settings.jqXHR;
7747			if ( xhr && xhr.readyState !== 4 ) {
7748				xhr.abort();
7749			}
7750	
7751			// Trigger xhr
7752			_fnBuildAjax( settings, {}, function( json ) {
7753				_fnClearTable( settings );
7754	
7755				var data = _fnAjaxDataSrc( settings, json );
7756				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7757					_fnAddData( settings, data[i] );
7758				}
7759	
7760				_fnReDraw( settings, holdPosition );
7761				_fnInitComplete( settings );
7762				_fnProcessingDisplay( settings, false );
7763			} );
7764		}
7765	};
7766	
7767	
7768	/**
7769	 * Get the JSON response from the last Ajax request that DataTables made to the
7770	 * server. Note that this returns the JSON from the first table in the current
7771	 * context.
7772	 *
7773	 * @return {object} JSON received from the server.
7774	 */
7775	_api_register( 'ajax.json()', function () {
7776		var ctx = this.context;
7777	
7778		if ( ctx.length > 0 ) {
7779			return ctx[0].json;
7780		}
7781	
7782		// else return undefined;
7783	} );
7784	
7785	
7786	/**
7787	 * Get the data submitted in the last Ajax request
7788	 */
7789	_api_register( 'ajax.params()', function () {
7790		var ctx = this.context;
7791	
7792		if ( ctx.length > 0 ) {
7793			return ctx[0].oAjaxData;
7794		}
7795	
7796		// else return undefined;
7797	} );
7798	
7799	
7800	/**
7801	 * Reload tables from the Ajax data source. Note that this function will
7802	 * automatically re-draw the table when the remote data has been loaded.
7803	 *
7804	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7805	 *   position. A full re-sort and re-filter is performed when this method is
7806	 *   called, which is why the pagination reset is the default action.
7807	 * @returns {DataTables.Api} this
7808	 */
7809	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7810		return this.iterator( 'table', function (settings) {
7811			__reload( settings, resetPaging===false, callback );
7812		} );
7813	} );
7814	
7815	
7816	/**
7817	 * Get the current Ajax URL. Note that this returns the URL from the first
7818	 * table in the current context.
7819	 *
7820	 * @return {string} Current Ajax source URL
7821	 *//**
7822	 * Set the Ajax URL. Note that this will set the URL for all tables in the
7823	 * current context.
7824	 *
7825	 * @param {string} url URL to set.
7826	 * @returns {DataTables.Api} this
7827	 */
7828	_api_register( 'ajax.url()', function ( url ) {
7829		var ctx = this.context;
7830	
7831		if ( url === undefined ) {
7832			// get
7833			if ( ctx.length === 0 ) {
7834				return undefined;
7835			}
7836			ctx = ctx[0];
7837	
7838			return $.isPlainObject( ctx.ajax ) ?
7839				ctx.ajax.url :
7840				ctx.ajax;
7841		}
7842	
7843		// set
7844		return this.iterator( 'table', function ( settings ) {
7845			if ( $.isPlainObject( settings.ajax ) ) {
7846				settings.ajax.url = url;
7847			}
7848			else {
7849				settings.ajax = url;
7850			}
7851		} );
7852	} );
7853	
7854	
7855	/**
7856	 * Load data from the newly set Ajax URL. Note that this method is only
7857	 * available when `ajax.url()` is used to set a URL. Additionally, this method
7858	 * has the same effect as calling `ajax.reload()` but is provided for
7859	 * convenience when setting a new URL. Like `ajax.reload()` it will
7860	 * automatically redraw the table once the remote data has been loaded.
7861	 *
7862	 * @returns {DataTables.Api} this
7863	 */
7864	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7865		// Same as a reload, but makes sense to present it for easy access after a
7866		// url change
7867		return this.iterator( 'table', function ( ctx ) {
7868			__reload( ctx, resetPaging===false, callback );
7869		} );
7870	} );
7871	
7872	
7873	
7874	
7875	var _selector_run = function ( type, selector, selectFn, settings, opts )
7876	{
7877		var
7878			out = [], res,
7879			i, ien,
7880			selectorType = typeof selector;
7881	
7882		// Can't just check for isArray here, as an API or jQuery instance might be
7883		// given with their array like look
7884		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7885			selector = [ selector ];
7886		}
7887	
7888		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7889			res = selectFn( typeof selector[i] === 'string' ? selector[i].trim() : selector[i] );
7890	
7891			// Remove empty items
7892			res = res.filter( function (item) {
7893				return item !== null && item !== undefined;
7894			});
7895	
7896			if ( res && res.length ) {
7897				out = out.concat( res );
7898			}
7899		}
7900	
7901		// selector extensions
7902		var ext = _ext.selector[ type ];
7903		if ( ext.length ) {
7904			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7905				out = ext[i]( settings, opts, out );
7906			}
7907		}
7908	
7909		return _unique( out );
7910	};
7911	
7912	
7913	var _selector_opts = function ( opts )
7914	{
7915		if ( ! opts ) {
7916			opts = {};
7917		}
7918	
7919		// Backwards compatibility for 1.9- which used the terminology filter rather
7920		// than search
7921		if ( opts.filter && opts.search === undefined ) {
7922			opts.search = opts.filter;
7923		}
7924	
7925		return $.extend( {
7926			columnOrder: 'implied',
7927			search: 'none',
7928			order: 'current',
7929			page: 'all'
7930		}, opts );
7931	};
7932	
7933	
7934	// Reduce the API instance to the first item found
7935	var _selector_first = function ( old )
7936	{
7937		var inst = new _Api(old.context[0]);
7938	
7939		// Use a push rather than passing to the constructor, since it will
7940		// merge arrays down automatically, which isn't what is wanted here
7941		if (old.length) {
7942			inst.push( old[0] );
7943		}
7944	
7945		inst.selector = old.selector;
7946	
7947		// Limit to a single row / column / cell
7948		if (inst.length && inst[0].length > 1) {
7949			inst[0].splice(1);
7950		}
7951	
7952		return inst;
7953	};
7954	
7955	
7956	var _selector_row_indexes = function ( settings, opts )
7957	{
7958		var
7959			i, ien, tmp, a=[],
7960			displayFiltered = settings.aiDisplay,
7961			displayMaster = settings.aiDisplayMaster;
7962	
7963		var
7964			search = opts.search,  // none, applied, removed
7965			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7966			page   = opts.page;    // all, current
7967	
7968		if ( _fnDataSource( settings ) == 'ssp' ) {
7969			// In server-side processing mode, most options are irrelevant since
7970			// rows not shown don't exist and the index order is the applied order
7971			// Removed is a special case - for consistency just return an empty
7972			// array
7973			return search === 'removed' ?
7974				[] :
7975				_range( 0, displayMaster.length );
7976		}
7977	
7978		if ( page == 'current' ) {
7979			// Current page implies that order=current and filter=applied, since it is
7980			// fairly senseless otherwise, regardless of what order and search actually
7981			// are
7982			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7983				a.push( displayFiltered[i] );
7984			}
7985		}
7986		else if ( order == 'current' || order == 'applied' ) {
7987			if ( search == 'none') {
7988				a = displayMaster.slice();
7989			}
7990			else if ( search == 'applied' ) {
7991				a = displayFiltered.slice();
7992			}
7993			else if ( search == 'removed' ) {
7994				// O(n+m) solution by creating a hash map
7995				var displayFilteredMap = {};
7996	
7997				for ( i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7998					displayFilteredMap[displayFiltered[i]] = null;
7999				}
8000	
8001				displayMaster.forEach(function (item) {
8002					if (! Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
8003						a.push(item);
8004					}
8005				});
8006			}
8007		}
8008		else if ( order == 'index' || order == 'original' ) {
8009			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8010				if (! settings.aoData[i]) {
8011					continue;
8012				}
8013	
8014				if ( search == 'none' ) {
8015					a.push( i );
8016				}
8017				else { // applied | removed
8018					tmp = displayFiltered.indexOf(i);
8019	
8020					if ((tmp === -1 && search == 'removed') ||
8021						(tmp >= 0   && search == 'applied') )
8022					{
8023						a.push( i );
8024					}
8025				}
8026			}
8027		}
8028		else if ( typeof order === 'number' ) {
8029			// Order the rows by the given column
8030			var ordered = _fnSort(settings, order, 'asc');
8031	
8032			if (search === 'none') {
8033				a = ordered;
8034			}
8035			else { // applied | removed
8036				for (i=0; i<ordered.length; i++) {
8037					tmp = displayFiltered.indexOf(ordered[i]);
8038	
8039					if ((tmp === -1 && search == 'removed') ||
8040						(tmp >= 0   && search == 'applied') )
8041					{
8042						a.push( ordered[i] );
8043					}
8044				}
8045			}
8046		}
8047	
8048		return a;
8049	};
8050	
8051	
8052	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8053	 * Rows
8054	 *
8055	 * {}          - no selector - use all available rows
8056	 * {integer}   - row aoData index
8057	 * {node}      - TR node
8058	 * {string}    - jQuery selector to apply to the TR elements
8059	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
8060	 *
8061	 */
8062	var __row_selector = function ( settings, selector, opts )
8063	{
8064		var rows;
8065		var run = function ( sel ) {
8066			var selInt = _intVal( sel );
8067			var aoData = settings.aoData;
8068	
8069			// Short cut - selector is a number and no options provided (default is
8070			// all records, so no need to check if the index is in there, since it
8071			// must be - dev error if the index doesn't exist).
8072			if ( selInt !== null && ! opts ) {
8073				return [ selInt ];
8074			}
8075	
8076			if ( ! rows ) {
8077				rows = _selector_row_indexes( settings, opts );
8078			}
8079	
8080			if ( selInt !== null && rows.indexOf(selInt) !== -1 ) {
8081				// Selector - integer
8082				return [ selInt ];
8083			}
8084			else if ( sel === null || sel === undefined || sel === '' ) {
8085				// Selector - none
8086				return rows;
8087			}
8088	
8089			// Selector - function
8090			if ( typeof sel === 'function' ) {
8091				return rows.map( function (idx) {
8092					var row = aoData[ idx ];
8093					return sel( idx, row._aData, row.nTr ) ? idx : null;
8094				} );
8095			}
8096	
8097			// Selector - node
8098			if ( sel.nodeName ) {
8099				var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
8100				var cellIdx = sel._DT_CellIndex;
8101	
8102				if ( rowIdx !== undefined ) {
8103					// Make sure that the row is actually still present in the table
8104					return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
8105						[ rowIdx ] :
8106						[];
8107				}
8108				else if ( cellIdx ) {
8109					return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
8110						[ cellIdx.row ] :
8111						[];
8112				}
8113				else {
8114					var host = $(sel).closest('*[data-dt-row]');
8115					return host.length ?
8116						[ host.data('dt-row') ] :
8117						[];
8118				}
8119			}
8120	
8121			// ID selector. Want to always be able to select rows by id, regardless
8122			// of if the tr element has been created or not, so can't rely upon
8123			// jQuery here - hence a custom implementation. This does not match
8124			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
8125			// but to select it using a CSS selector engine (like Sizzle or
8126			// querySelect) it would need to need to be escaped for some characters.
8127			// DataTables simplifies this for row selectors since you can select
8128			// only a row. A # indicates an id any anything that follows is the id -
8129			// unescaped.
8130			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
8131				// get row index from id
8132				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
8133				if ( rowObj !== undefined ) {
8134					return [ rowObj.idx ];
8135				}
8136	
8137				// need to fall through to jQuery in case there is DOM id that
8138				// matches
8139			}
8140			
8141			// Get nodes in the order from the `rows` array with null values removed
8142			var nodes = _removeEmpty(
8143				_pluck_order( settings.aoData, rows, 'nTr' )
8144			);
8145	
8146			// Selector - jQuery selector string, array of nodes or jQuery object/
8147			// As jQuery's .filter() allows jQuery objects to be passed in filter,
8148			// it also allows arrays, so this will cope with all three options
8149			return $(nodes)
8150				.filter( sel )
8151				.map( function () {
8152					return this._DT_RowIndex;
8153				} )
8154				.toArray();
8155		};
8156	
8157		var matched = _selector_run( 'row', selector, run, settings, opts );
8158	
8159		if (opts.order === 'current' || opts.order === 'applied') {
8160			_fnSortDisplay(settings, matched);
8161		}
8162	
8163		return matched;
8164	};
8165	
8166	
8167	_api_register( 'rows()', function ( selector, opts ) {
8168		// argument shifting
8169		if ( selector === undefined ) {
8170			selector = '';
8171		}
8172		else if ( $.isPlainObject( selector ) ) {
8173			opts = selector;
8174			selector = '';
8175		}
8176	
8177		opts = _selector_opts( opts );
8178	
8179		var inst = this.iterator( 'table', function ( settings ) {
8180			return __row_selector( settings, selector, opts );
8181		}, 1 );
8182	
8183		// Want argument shifting here and in __row_selector?
8184		inst.selector.rows = selector;
8185		inst.selector.opts = opts;
8186	
8187		return inst;
8188	} );
8189	
8190	_api_register( 'rows().nodes()', function () {
8191		return this.iterator( 'row', function ( settings, row ) {
8192			return settings.aoData[ row ].nTr || undefined;
8193		}, 1 );
8194	} );
8195	
8196	_api_register( 'rows().data()', function () {
8197		return this.iterator( true, 'rows', function ( settings, rows ) {
8198			return _pluck_order( settings.aoData, rows, '_aData' );
8199		}, 1 );
8200	} );
8201	
8202	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
8203		return this.iterator( 'row', function ( settings, row ) {
8204			var r = settings.aoData[ row ];
8205			return type === 'search' ? r._aFilterData : r._aSortData;
8206		}, 1 );
8207	} );
8208	
8209	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
8210		return this.iterator( 'row', function ( settings, row ) {
8211			_fnInvalidate( settings, row, src );
8212		} );
8213	} );
8214	
8215	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
8216		return this.iterator( 'row', function ( settings, row ) {
8217			return row;
8218		}, 1 );
8219	} );
8220	
8221	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8222		var a = [];
8223		var context = this.context;
8224	
8225		// `iterator` will drop undefined values, but in this case we want them
8226		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8227			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8228				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8229				a.push( (hash === true ? '#' : '' )+ id );
8230			}
8231		}
8232	
8233		return new _Api( context, a );
8234	} );
8235	
8236	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8237		this.iterator( 'row', function ( settings, row ) {
8238			var data = settings.aoData;
8239			var rowData = data[ row ];
8240	
8241			// Delete from the display arrays
8242			var idx = settings.aiDisplayMaster.indexOf(row);
8243			if (idx !== -1) {
8244				settings.aiDisplayMaster.splice(idx, 1);
8245			}
8246	
8247			// For server-side processing tables - subtract the deleted row from the count
8248			if ( settings._iRecordsDisplay > 0 ) {
8249				settings._iRecordsDisplay--;
8250			}
8251	
8252			// Check for an 'overflow' they case for displaying the table
8253			_fnLengthOverflow( settings );
8254	
8255			// Remove the row's ID reference if there is one
8256			var id = settings.rowIdFn( rowData._aData );
8257			if ( id !== undefined ) {
8258				delete settings.aIds[ id ];
8259			}
8260	
8261			data[row] = null;
8262		} );
8263	
8264		return this;
8265	} );
8266	
8267	
8268	_api_register( 'rows.add()', function ( rows ) {
8269		var newRows = this.iterator( 'table', function ( settings ) {
8270				var row, i, ien;
8271				var out = [];
8272	
8273				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8274					row = rows[i];
8275	
8276					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8277						out.push( _fnAddTr( settings, row )[0] );
8278					}
8279					else {
8280						out.push( _fnAddData( settings, row ) );
8281					}
8282				}
8283	
8284				return out;
8285			}, 1 );
8286	
8287		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
8288		var modRows = this.rows( -1 );
8289		modRows.pop();
8290		_fnArrayApply(modRows, newRows);
8291	
8292		return modRows;
8293	} );
8294	
8295	
8296	
8297	
8298	
8299	/**
8300	 *
8301	 */
8302	_api_register( 'row()', function ( selector, opts ) {
8303		return _selector_first( this.rows( selector, opts ) );
8304	} );
8305	
8306	
8307	_api_register( 'row().data()', function ( data ) {
8308		var ctx = this.context;
8309	
8310		if ( data === undefined ) {
8311			// Get
8312			return ctx.length && this.length && this[0].length ?
8313				ctx[0].aoData[ this[0] ]._aData :
8314				undefined;
8315		}
8316	
8317		// Set
8318		var row = ctx[0].aoData[ this[0] ];
8319		row._aData = data;
8320	
8321		// If the DOM has an id, and the data source is an array
8322		if ( Array.isArray( data ) && row.nTr && row.nTr.id ) {
8323			_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
8324		}
8325	
8326		// Automatically invalidate
8327		_fnInvalidate( ctx[0], this[0], 'data' );
8328	
8329		return this;
8330	} );
8331	
8332	
8333	_api_register( 'row().node()', function () {
8334		var ctx = this.context;
8335	
8336		if (ctx.length && this.length && this[0].length) {
8337			var row = ctx[0].aoData[ this[0] ];
8338	
8339			if (row && row.nTr) {
8340				return row.nTr;
8341			}
8342		}
8343	
8344		return null;
8345	} );
8346	
8347	
8348	_api_register( 'row.add()', function ( row ) {
8349		// Allow a jQuery object to be passed in - only a single row is added from
8350		// it though - the first element in the set
8351		if ( row instanceof $ && row.length ) {
8352			row = row[0];
8353		}
8354	
8355		var rows = this.iterator( 'table', function ( settings ) {
8356			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8357				return _fnAddTr( settings, row )[0];
8358			}
8359			return _fnAddData( settings, row );
8360		} );
8361	
8362		// Return an Api.rows() extended instance, with the newly added row selected
8363		return this.row( rows[0] );
8364	} );
8365	
8366	
8367	$(document).on('plugin-init.dt', function (e, context) {
8368		var api = new _Api( context );
8369	
8370		api.on( 'stateSaveParams.DT', function ( e, settings, d ) {
8371			// This could be more compact with the API, but it is a lot faster as a simple
8372			// internal loop
8373			var idFn = settings.rowIdFn;
8374			var rows = settings.aiDisplayMaster;
8375			var ids = [];
8376	
8377			for (var i=0 ; i<rows.length ; i++) {
8378				var rowIdx = rows[i];
8379				var data = settings.aoData[rowIdx];
8380	
8381				if (data._detailsShow) {
8382					ids.push( '#' + idFn(data._aData) );
8383				}
8384			}
8385	
8386			d.childRows = ids;
8387		});
8388	
8389		// For future state loads (e.g. with StateRestore)
8390		api.on( 'stateLoaded.DT', function (e, settings, state) {
8391			__details_state_load( api, state );
8392		});
8393	
8394		// And the initial load state
8395		__details_state_load( api, api.state.loaded() );
8396	});
8397	
8398	var __details_state_load = function (api, state)
8399	{
8400		if ( state && state.childRows ) {
8401			api
8402				.rows( state.childRows.map(function (id) {
8403					// Escape any `:` characters from the row id. Accounts for
8404					// already escaped characters.
8405					return id.replace(/([^:\\]*(?:\\.[^:\\]*)*):/g, "$1\\:");
8406				}) )
8407				.every( function () {
8408					_fnCallbackFire( api.settings()[0], null, 'requestChild', [ this ] )
8409				});
8410		}
8411	}
8412	
8413	var __details_add = function ( ctx, row, data, klass )
8414	{
8415		// Convert to array of TR elements
8416		var rows = [];
8417		var addRow = function ( r, k ) {
8418			// Recursion to allow for arrays of jQuery objects
8419			if ( Array.isArray( r ) || r instanceof $ ) {
8420				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8421					addRow( r[i], k );
8422				}
8423				return;
8424			}
8425	
8426			// If we get a TR element, then just add it directly - up to the dev
8427			// to add the correct number of columns etc
8428			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8429				r.setAttribute( 'data-dt-row', row.idx );
8430				rows.push( r );
8431			}
8432			else {
8433				// Otherwise create a row with a wrapper
8434				var created = $('<tr><td></td></tr>')
8435					.attr( 'data-dt-row', row.idx )
8436					.addClass( k );
8437				
8438				$('td', created)
8439					.addClass( k )
8440					.html( r )[0].colSpan = _fnVisbleColumns( ctx );
8441	
8442				rows.push( created[0] );
8443			}
8444		};
8445	
8446		addRow( data, klass );
8447	
8448		if ( row._details ) {
8449			row._details.detach();
8450		}
8451	
8452		row._details = $(rows);
8453	
8454		// If the children were already shown, that state should be retained
8455		if ( row._detailsShow ) {
8456			row._details.insertAfter( row.nTr );
8457		}
8458	};
8459	
8460	
8461	// Make state saving of child row details async to allow them to be batch processed
8462	var __details_state = DataTable.util.throttle(
8463		function (ctx) {
8464			_fnSaveState( ctx[0] )
8465		},
8466		500
8467	);
8468	
8469	
8470	var __details_remove = function ( api, idx )
8471	{
8472		var ctx = api.context;
8473	
8474		if ( ctx.length ) {
8475			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8476	
8477			if ( row && row._details ) {
8478				row._details.remove();
8479	
8480				row._detailsShow = undefined;
8481				row._details = undefined;
8482				$( row.nTr ).removeClass( 'dt-hasChild' );
8483				__details_state( ctx );
8484			}
8485		}
8486	};
8487	
8488	
8489	var __details_display = function ( api, show ) {
8490		var ctx = api.context;
8491	
8492		if ( ctx.length && api.length ) {
8493			var row = ctx[0].aoData[ api[0] ];
8494	
8495			if ( row._details ) {
8496				row._detailsShow = show;
8497	
8498				if ( show ) {
8499					row._details.insertAfter( row.nTr );
8500					$( row.nTr ).addClass( 'dt-hasChild' );
8501				}
8502				else {
8503					row._details.detach();
8504					$( row.nTr ).removeClass( 'dt-hasChild' );
8505				}
8506	
8507				_fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )
8508	
8509				__details_events( ctx[0] );
8510				__details_state( ctx );
8511			}
8512		}
8513	};
8514	
8515	
8516	var __details_events = function ( settings )
8517	{
8518		var api = new _Api( settings );
8519		var namespace = '.dt.DT_details';
8520		var drawEvent = 'draw'+namespace;
8521		var colvisEvent = 'column-sizing'+namespace;
8522		var destroyEvent = 'destroy'+namespace;
8523		var data = settings.aoData;
8524	
8525		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8526	
8527		if ( _pluck( data, '_details' ).length > 0 ) {
8528			// On each draw, insert the required elements into the document
8529			api.on( drawEvent, function ( e, ctx ) {
8530				if ( settings !== ctx ) {
8531					return;
8532				}
8533	
8534				api.rows( {page:'current'} ).eq(0).each( function (idx) {
8535					// Internal data grab
8536					var row = data[ idx ];
8537	
8538					if ( row._detailsShow ) {
8539						row._details.insertAfter( row.nTr );
8540					}
8541				} );
8542			} );
8543	
8544			// Column visibility change - update the colspan
8545			api.on( colvisEvent, function ( e, ctx ) {
8546				if ( settings !== ctx ) {
8547					return;
8548				}
8549	
8550				// Update the colspan for the details rows (note, only if it already has
8551				// a colspan)
8552				var row, visible = _fnVisbleColumns( ctx );
8553	
8554				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8555					row = data[i];
8556	
8557					if ( row && row._details ) {
8558						row._details.each(function () {
8559							var el = $(this).children('td');
8560	
8561							if (el.length == 1) {
8562								el.attr('colspan', visible);
8563							}
8564						});
8565					}
8566				}
8567			} );
8568	
8569			// Table destroyed - nuke any child rows
8570			api.on( destroyEvent, function ( e, ctx ) {
8571				if ( settings !== ctx ) {
8572					return;
8573				}
8574	
8575				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8576					if ( data[i] && data[i]._details ) {
8577						__details_remove( api, i );
8578					}
8579				}
8580			} );
8581		}
8582	};
8583	
8584	// Strings for the method names to help minification
8585	var _emp = '';
8586	var _child_obj = _emp+'row().child';
8587	var _child_mth = _child_obj+'()';
8588	
8589	// data can be:
8590	//  tr
8591	//  string
8592	//  jQuery or array of any of the above
8593	_api_register( _child_mth, function ( data, klass ) {
8594		var ctx = this.context;
8595	
8596		if ( data === undefined ) {
8597			// get
8598			return ctx.length && this.length && ctx[0].aoData[ this[0] ]
8599				? ctx[0].aoData[ this[0] ]._details
8600				: undefined;
8601		}
8602		else if ( data === true ) {
8603			// show
8604			this.child.show();
8605		}
8606		else if ( data === false ) {
8607			// remove
8608			__details_remove( this );
8609		}
8610		else if ( ctx.length && this.length ) {
8611			// set
8612			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8613		}
8614	
8615		return this;
8616	} );
8617	
8618	
8619	_api_register( [
8620		_child_obj+'.show()',
8621		_child_mth+'.show()' // only when `child()` was called with parameters (without
8622	], function () {         // it returns an object and this method is not executed)
8623		__details_display( this, true );
8624		return this;
8625	} );
8626	
8627	
8628	_api_register( [
8629		_child_obj+'.hide()',
8630		_child_mth+'.hide()' // only when `child()` was called with parameters (without
8631	], function () {         // it returns an object and this method is not executed)
8632		__details_display( this, false );
8633		return this;
8634	} );
8635	
8636	
8637	_api_register( [
8638		_child_obj+'.remove()',
8639		_child_mth+'.remove()' // only when `child()` was called with parameters (without
8640	], function () {           // it returns an object and this method is not executed)
8641		__details_remove( this );
8642		return this;
8643	} );
8644	
8645	
8646	_api_register( _child_obj+'.isShown()', function () {
8647		var ctx = this.context;
8648	
8649		if ( ctx.length && this.length && ctx[0].aoData[ this[0] ] ) {
8650			// _detailsShown as false or undefined will fall through to return false
8651			return ctx[0].aoData[ this[0] ]._detailsShow || false;
8652		}
8653		return false;
8654	} );
8655	
8656	
8657	
8658	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8659	 * Columns
8660	 *
8661	 * {integer}           - column index (>=0 count from left, <0 count from right)
8662	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8663	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8664	 * "{string}:name"     - column name
8665	 * "{string}"          - jQuery selector on column header nodes
8666	 *
8667	 */
8668	
8669	// can be an array of these items, comma separated list, or an array of comma
8670	// separated lists
8671	
8672	var __re_column_selector = /^([^:]+)?:(name|title|visIdx|visible)$/;
8673	
8674	
8675	// r1 and r2 are redundant - but it means that the parameters match for the
8676	// iterator callback in columns().data()
8677	var __columnData = function ( settings, column, r1, r2, rows, type ) {
8678		var a = [];
8679		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8680			a.push( _fnGetCellData( settings, rows[row], column, type ) );
8681		}
8682		return a;
8683	};
8684	
8685	
8686	var __column_header = function ( settings, column, row ) {
8687		var header = settings.aoHeader;
8688		var titleRow = settings.titleRow;
8689		var target = null;
8690	
8691		if (row !== undefined) {
8692			target = row;
8693		}
8694		else if (titleRow === true) { // legacy orderCellsTop support
8695			target = 0;
8696		}
8697		else if (titleRow === false) {
8698			target = header.length - 1;
8699		}
8700		else if (titleRow !== null) {
8701			target = titleRow;
8702		}
8703		else {
8704			// Automatic - find the _last_ unique cell from the top that is not empty (last for
8705			// backwards compatibility)
8706			for (var i=0 ; i<header.length ; i++) {
8707				if (header[i][column].unique && $('span.dt-column-title', header[i][column].cell).text()) {
8708					target = i;
8709				}
8710			}
8711	
8712			if (target === null) {
8713				target = 0;
8714			}
8715		}
8716	
8717		return header[target][column].cell;
8718	};
8719	
8720	var __column_header_cells = function (header) {
8721		var out = [];
8722	
8723		for (var i=0 ; i<header.length ; i++) {
8724			for (var j=0 ; j<header[i].length ; j++) {
8725				var cell = header[i][j].cell;
8726	
8727				if (!out.includes(cell)) {
8728					out.push(cell);
8729				}
8730			}
8731		}
8732	
8733		return out;
8734	}
8735	
8736	var __column_selector = function ( settings, selector, opts )
8737	{
8738		var
8739			columns = settings.aoColumns,
8740			names, titles,
8741			nodes = __column_header_cells(settings.aoHeader);
8742		
8743		var run = function ( s ) {
8744			var selInt = _intVal( s );
8745	
8746			// Selector - all
8747			if ( s === '' ) {
8748				return _range( columns.length );
8749			}
8750	
8751			// Selector - index
8752			if ( selInt !== null ) {
8753				return [ selInt >= 0 ?
8754					selInt : // Count from left
8755					columns.length + selInt // Count from right (+ because its a negative value)
8756				];
8757			}
8758	
8759			// Selector = function
8760			if ( typeof s === 'function' ) {
8761				var rows = _selector_row_indexes( settings, opts );
8762	
8763				return columns.map(function (col, idx) {
8764					return s(
8765							idx,
8766							__columnData( settings, idx, 0, 0, rows ),
8767							__column_header( settings, idx )
8768						) ? idx : null;
8769				});
8770			}
8771	
8772			// jQuery or string selector
8773			var match = typeof s === 'string' ?
8774				s.match( __re_column_selector ) :
8775				'';
8776	
8777			if ( match ) {
8778				switch( match[2] ) {
8779					case 'visIdx':
8780					case 'visible':
8781						// Selector is a column index
8782						if (match[1] && match[1].match(/^\d+$/)) {
8783							var idx = parseInt( match[1], 10 );
8784	
8785							// Visible index given, convert to column index
8786							if ( idx < 0 ) {
8787								// Counting from the right
8788								var visColumns = columns.map( function (col,i) {
8789									return col.bVisible ? i : null;
8790								} );
8791								return [ visColumns[ visColumns.length + idx ] ];
8792							}
8793							// Counting from the left
8794							return [ _fnVisibleToColumnIndex( settings, idx ) ];
8795						}
8796						
8797						return columns.map( function (col, idx) {
8798							// Not visible, can't match
8799							if (! col.bVisible) {
8800								return null;
8801							}
8802	
8803							// Selector
8804							if (match[1]) {
8805								return $(nodes[idx]).filter(match[1]).length > 0 ? idx : null;
8806							}
8807	
8808							// `:visible` on its own
8809							return idx;
8810						} );
8811	
8812					case 'name':
8813						// Don't get names, unless needed, and only get once if it is
8814						if (!names) {
8815							names = _pluck( columns, 'sName' );
8816						}
8817	
8818						// match by name. `names` is column index complete and in order
8819						return names.map( function (name, i) {
8820							return name === match[1] ? i : null;
8821						} );
8822	
8823					case 'title':
8824						if (!titles) {
8825							titles = _pluck( columns, 'sTitle' );
8826						}
8827	
8828						// match by column title
8829						return titles.map( function (title, i) {
8830							return title === match[1] ? i : null;
8831						} );
8832	
8833					default:
8834						return [];
8835				}
8836			}
8837	
8838			// Cell in the table body
8839			if ( s.nodeName && s._DT_CellIndex ) {
8840				return [ s._DT_CellIndex.column ];
8841			}
8842	
8843			// jQuery selector on the TH elements for the columns
8844			var jqResult = $( nodes )
8845				.filter( s )
8846				.map( function () {
8847					return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
8848				} )
8849				.toArray()
8850				.sort(function (a, b) {
8851					return a - b;
8852				});
8853	
8854			if ( jqResult.length || ! s.nodeName ) {
8855				return jqResult;
8856			}
8857	
8858			// Otherwise a node which might have a `dt-column` data attribute, or be
8859			// a child or such an element
8860			var host = $(s).closest('*[data-dt-column]');
8861			return host.length ?
8862				[ host.data('dt-column') ] :
8863				[];
8864		};
8865	
8866		var selected = _selector_run( 'column', selector, run, settings, opts );
8867	
8868		return opts.columnOrder && opts.columnOrder === 'index'
8869			? selected.sort(function (a, b) { return a - b; })
8870			: selected; // implied
8871	};
8872	
8873	
8874	var __setColumnVis = function ( settings, column, vis ) {
8875		var
8876			cols = settings.aoColumns,
8877			col  = cols[ column ],
8878			data = settings.aoData,
8879			cells, i, ien, tr;
8880	
8881		// Get
8882		if ( vis === undefined ) {
8883			return col.bVisible;
8884		}
8885	
8886		// Set
8887		// No change
8888		if ( col.bVisible === vis ) {
8889			return false;
8890		}
8891	
8892		if ( vis ) {
8893			// Insert column
8894			// Need to decide if we should use appendChild or insertBefore
8895			var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column+1);
8896	
8897			for ( i=0, ien=data.length ; i<ien ; i++ ) {
8898				if (data[i]) {
8899					tr = data[i].nTr;
8900					cells = data[i].anCells;
8901	
8902					if ( tr ) {
8903						// insertBefore can act like appendChild if 2nd arg is null
8904						tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8905					}
8906				}
8907			}
8908		}
8909		else {
8910			// Remove column
8911			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
8912		}
8913	
8914		// Common actions
8915		col.bVisible = vis;
8916	
8917		_colGroup(settings);
8918		
8919		return true;
8920	};
8921	
8922	
8923	_api_register( 'columns()', function ( selector, opts ) {
8924		// argument shifting
8925		if ( selector === undefined ) {
8926			selector = '';
8927		}
8928		else if ( $.isPlainObject( selector ) ) {
8929			opts = selector;
8930			selector = '';
8931		}
8932	
8933		opts = _selector_opts( opts );
8934	
8935		var inst = this.iterator( 'table', function ( settings ) {
8936			return __column_selector( settings, selector, opts );
8937		}, 1 );
8938	
8939		// Want argument shifting here and in _row_selector?
8940		inst.selector.cols = selector;
8941		inst.selector.opts = opts;
8942	
8943		return inst;
8944	} );
8945	
8946	_api_registerPlural( 'columns().header()', 'column().header()', function ( row ) {
8947		return this.iterator( 'column', function (settings, column) {
8948			return __column_header(settings, column, row);
8949		}, 1 );
8950	} );
8951	
8952	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( row ) {
8953		return this.iterator( 'column', function ( settings, column ) {
8954			var footer = settings.aoFooter;
8955	
8956			if (! footer.length) {
8957				return null;
8958			}
8959	
8960			return settings.aoFooter[row !== undefined ? row : 0][column].cell;
8961		}, 1 );
8962	} );
8963	
8964	_api_registerPlural( 'columns().data()', 'column().data()', function () {
8965		return this.iterator( 'column-rows', __columnData, 1 );
8966	} );
8967	
8968	_api_registerPlural( 'columns().render()', 'column().render()', function ( type ) {
8969		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8970			return __columnData( settings, column, i, j, rows, type );
8971		}, 1 );
8972	} );
8973	
8974	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8975		return this.iterator( 'column', function ( settings, column ) {
8976			return settings.aoColumns[column].mData;
8977		}, 1 );
8978	} );
8979	
8980	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8981		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8982			return _pluck_order( settings.aoData, rows,
8983				type === 'search' ? '_aFilterData' : '_aSortData', column
8984			);
8985		}, 1 );
8986	} );
8987	
8988	_api_registerPlural( 'columns().init()', 'column().init()', function () {
8989		return this.iterator( 'column', function ( settings, column ) {
8990			return settings.aoColumns[column];
8991		}, 1 );
8992	} );
8993	
8994	_api_registerPlural( 'columns().names()', 'column().name()', function () {
8995		return this.iterator( 'column', function ( settings, column ) {
8996			return settings.aoColumns[column].sName;
8997		}, 1 );
8998	} );
8999	
9000	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
9001		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
9002			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
9003		}, 1 );
9004	} );
9005	
9006	_api_registerPlural( 'columns().titles()', 'column().title()', function (title, row) {
9007		return this.iterator( 'column', function ( settings, column ) {
9008			// Argument shifting
9009			if (typeof title === 'number') {
9010				row = title;
9011				title = undefined;
9012			}
9013	
9014			var span = $('span.dt-column-title', this.column(column).header(row));
9015	
9016			if (title !== undefined) {
9017				span.html(title);
9018				return this;
9019			}
9020	
9021			return span.html();
9022		}, 1 );
9023	} );
9024	
9025	_api_registerPlural( 'columns().types()', 'column().type()', function () {
9026		return this.iterator( 'column', function ( settings, column ) {
9027			var type = settings.aoColumns[column].sType;
9028	
9029			// If the type was invalidated, then resolve it. This actually does
9030			// all columns at the moment. Would only happen once if getting all
9031			// column's data types.
9032			if (! type) {
9033				_fnColumnTypes(settings);
9034			}
9035	
9036			return type;
9037		}, 1 );
9038	} );
9039	
9040	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
9041		var that = this;
9042		var changed = [];
9043		var ret = this.iterator( 'column', function ( settings, column ) {
9044			if ( vis === undefined ) {
9045				return settings.aoColumns[ column ].bVisible;
9046			} // else
9047			
9048			if (__setColumnVis( settings, column, vis )) {
9049				changed.push(column);
9050			}
9051		} );
9052	
9053		// Group the column visibility changes
9054		if ( vis !== undefined ) {
9055			this.iterator( 'table', function ( settings ) {
9056				// Redraw the header after changes
9057				_fnDrawHead( settings, settings.aoHeader );
9058				_fnDrawHead( settings, settings.aoFooter );
9059		
9060				// Update colspan for no records display. Child rows and extensions will use their own
9061				// listeners to do this - only need to update the empty table item here
9062				if ( ! settings.aiDisplay.length ) {
9063					$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
9064				}
9065		
9066				_fnSaveState( settings );
9067	
9068				// Second loop once the first is done for events
9069				that.iterator( 'column', function ( settings, column ) {
9070					if (changed.includes(column)) {
9071						_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
9072					}
9073				} );
9074	
9075				if ( changed.length && (calc === undefined || calc) ) {
9076					that.columns.adjust();
9077				}
9078			});
9079		}
9080	
9081		return ret;
9082	} );
9083	
9084	_api_registerPlural( 'columns().widths()', 'column().width()', function () {
9085		// Injects a fake row into the table for just a moment so the widths can
9086		// be read, regardless of colspan in the header and rows being present in
9087		// the body
9088		var columns = this.columns(':visible').count();
9089		var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
9090	
9091		$(this.table().body()).append(row);
9092	
9093		var widths = row.children().map(function () {
9094			return $(this).outerWidth();
9095		});
9096	
9097		row.remove();
9098		
9099		return this.iterator( 'column', function ( settings, column ) {
9100			var visIdx = _fnColumnIndexToVisible( settings, column );
9101	
9102			return visIdx !== null ? widths[visIdx] : 0;
9103		}, 1);
9104	} );
9105	
9106	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
9107		return this.iterator( 'column', function ( settings, column ) {
9108			return type === 'visible' ?
9109				_fnColumnIndexToVisible( settings, column ) :
9110				column;
9111		}, 1 );
9112	} );
9113	
9114	_api_register( 'columns.adjust()', function () {
9115		return this.iterator( 'table', function ( settings ) {
9116			// Force a column sizing to happen with a manual call - otherwise it can skip
9117			// if the size hasn't changed
9118			settings.containerWidth = -1;
9119	
9120			_fnAdjustColumnSizing( settings );
9121		}, 1 );
9122	} );
9123	
9124	_api_register( 'column.index()', function ( type, idx ) {
9125		if ( this.context.length !== 0 ) {
9126			var ctx = this.context[0];
9127	
9128			if ( type === 'fromVisible' || type === 'toData' ) {
9129				return _fnVisibleToColumnIndex( ctx, idx );
9130			}
9131			else if ( type === 'fromData' || type === 'toVisible' ) {
9132				return _fnColumnIndexToVisible( ctx, idx );
9133			}
9134		}
9135	} );
9136	
9137	_api_register( 'column()', function ( selector, opts ) {
9138		return _selector_first( this.columns( selector, opts ) );
9139	} );
9140	
9141	var __cell_selector = function ( settings, selector, opts )
9142	{
9143		var data = settings.aoData;
9144		var rows = _selector_row_indexes( settings, opts );
9145		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
9146		var allCells = $(_flatten( [], cells ));
9147		var row;
9148		var columns = settings.aoColumns.length;
9149		var a, i, ien, j, o, host;
9150	
9151		var run = function ( s ) {
9152			var fnSelector = typeof s === 'function';
9153	
9154			if ( s === null || s === undefined || fnSelector ) {
9155				// All cells and function selectors
9156				a = [];
9157	
9158				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
9159					row = rows[i];
9160	
9161					for ( j=0 ; j<columns ; j++ ) {
9162						o = {
9163							row: row,
9164							column: j
9165						};
9166	
9167						if ( fnSelector ) {
9168							// Selector - function
9169							host = data[ row ];
9170	
9171							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
9172								a.push( o );
9173							}
9174						}
9175						else {
9176							// Selector - all
9177							a.push( o );
9178						}
9179					}
9180				}
9181	
9182				return a;
9183			}
9184			
9185			// Selector - index
9186			if ( $.isPlainObject( s ) ) {
9187				// Valid cell index and its in the array of selectable rows
9188				return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
9189					[s] :
9190					[];
9191			}
9192	
9193			// Selector - jQuery filtered cells
9194			var jqResult = allCells
9195				.filter( s )
9196				.map( function (i, el) {
9197					return { // use a new object, in case someone changes the values
9198						row:    el._DT_CellIndex.row,
9199						column: el._DT_CellIndex.column
9200					};
9201				} )
9202				.toArray();
9203	
9204			if ( jqResult.length || ! s.nodeName ) {
9205				return jqResult;
9206			}
9207	
9208			// Otherwise the selector is a node, and there is one last option - the
9209			// element might be a child of an element which has dt-row and dt-column
9210			// data attributes
9211			host = $(s).closest('*[data-dt-row]');
9212			return host.length ?
9213				[ {
9214					row: host.data('dt-row'),
9215					column: host.data('dt-column')
9216				} ] :
9217				[];
9218		};
9219	
9220		return _selector_run( 'cell', selector, run, settings, opts );
9221	};
9222	
9223	
9224	
9225	
9226	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
9227		// Argument shifting
9228		if ( $.isPlainObject( rowSelector ) ) {
9229			// Indexes
9230			if ( rowSelector.row === undefined ) {
9231				// Selector options in first parameter
9232				opts = rowSelector;
9233				rowSelector = null;
9234			}
9235			else {
9236				// Cell index objects in first parameter
9237				opts = columnSelector;
9238				columnSelector = null;
9239			}
9240		}
9241		if ( $.isPlainObject( columnSelector ) ) {
9242			opts = columnSelector;
9243			columnSelector = null;
9244		}
9245	
9246		// Cell selector
9247		if ( columnSelector === null || columnSelector === undefined ) {
9248			return this.iterator( 'table', function ( settings ) {
9249				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
9250			} );
9251		}
9252	
9253		// The default built in options need to apply to row and columns
9254		var internalOpts = opts ? {
9255			page: opts.page,
9256			order: opts.order,
9257			search: opts.search
9258		} : {};
9259	
9260		// Row + column selector
9261		var columns = this.columns( columnSelector, internalOpts );
9262		var rows = this.rows( rowSelector, internalOpts );
9263		var i, ien, j, jen;
9264	
9265		var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
9266			var a = [];
9267	
9268			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
9269				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
9270					a.push( {
9271						row:    rows[idx][i],
9272						column: columns[idx][j]
9273					} );
9274				}
9275			}
9276	
9277			return a;
9278		}, 1 );
9279	
9280		// There is currently only one extension which uses a cell selector extension
9281		// It is a _major_ performance drag to run this if it isn't needed, so this is
9282		// an extension specific check at the moment
9283		var cells = opts && opts.selected ?
9284			this.cells( cellsNoOpts, opts ) :
9285			cellsNoOpts;
9286	
9287		$.extend( cells.selector, {
9288			cols: columnSelector,
9289			rows: rowSelector,
9290			opts: opts
9291		} );
9292	
9293		return cells;
9294	} );
9295	
9296	
9297	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
9298		return this.iterator( 'cell', function ( settings, row, column ) {
9299			var data = settings.aoData[ row ];
9300	
9301			return data && data.anCells ?
9302				data.anCells[ column ] :
9303				undefined;
9304		}, 1 );
9305	} );
9306	
9307	
9308	_api_register( 'cells().data()', function () {
9309		return this.iterator( 'cell', function ( settings, row, column ) {
9310			return _fnGetCellData( settings, row, column );
9311		}, 1 );
9312	} );
9313	
9314	
9315	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
9316		type = type === 'search' ? '_aFilterData' : '_aSortData';
9317	
9318		return this.iterator( 'cell', function ( settings, row, column ) {
9319			return settings.aoData[ row ][ type ][ column ];
9320		}, 1 );
9321	} );
9322	
9323	
9324	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
9325		return this.iterator( 'cell', function ( settings, row, column ) {
9326			return _fnGetCellData( settings, row, column, type );
9327		}, 1 );
9328	} );
9329	
9330	
9331	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
9332		return this.iterator( 'cell', function ( settings, row, column ) {
9333			return {
9334				row: row,
9335				column: column,
9336				columnVisible: _fnColumnIndexToVisible( settings, column )
9337			};
9338		}, 1 );
9339	} );
9340	
9341	
9342	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
9343		return this.iterator( 'cell', function ( settings, row, column ) {
9344			_fnInvalidate( settings, row, src, column );
9345		} );
9346	} );
9347	
9348	
9349	
9350	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
9351		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
9352	} );
9353	
9354	
9355	_api_register( 'cell().data()', function ( data ) {
9356		var ctx = this.context;
9357		var cell = this[0];
9358	
9359		if ( data === undefined ) {
9360			// Get
9361			return ctx.length && cell.length ?
9362				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
9363				undefined;
9364		}
9365	
9366		// Set
9367		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
9368		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
9369	
9370		return this;
9371	} );
9372	
9373	
9374	
9375	/**
9376	 * Get current ordering (sorting) that has been applied to the table.
9377	 *
9378	 * @returns {array} 2D array containing the sorting information for the first
9379	 *   table in the current context. Each element in the parent array represents
9380	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
9381	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
9382	 *   the column index that the sorting condition applies to, the second is the
9383	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
9384	 *   index of the sorting order from the `column.sorting` initialisation array.
9385	 *//**
9386	 * Set the ordering for the table.
9387	 *
9388	 * @param {integer} order Column index to sort upon.
9389	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
9390	 * @returns {DataTables.Api} this
9391	 *//**
9392	 * Set the ordering for the table.
9393	 *
9394	 * @param {array} order 1D array of sorting information to be applied.
9395	 * @param {array} [...] Optional additional sorting conditions
9396	 * @returns {DataTables.Api} this
9397	 *//**
9398	 * Set the ordering for the table.
9399	 *
9400	 * @param {array} order 2D array of sorting information to be applied.
9401	 * @returns {DataTables.Api} this
9402	 */
9403	_api_register( 'order()', function ( order, dir ) {
9404		var ctx = this.context;
9405		var args = Array.prototype.slice.call( arguments );
9406	
9407		if ( order === undefined ) {
9408			// get
9409			return ctx.length !== 0 ?
9410				ctx[0].aaSorting :
9411				undefined;
9412		}
9413	
9414		// set
9415		if ( typeof order === 'number' ) {
9416			// Simple column / direction passed in
9417			order = [ [ order, dir ] ];
9418		}
9419		else if ( args.length > 1 ) {
9420			// Arguments passed in (list of 1D arrays)
9421			order = args;
9422		}
9423		// otherwise a 2D array was passed in
9424	
9425		return this.iterator( 'table', function ( settings ) {
9426			var resolved = [];
9427			_fnSortResolve(settings, resolved, order);
9428	
9429			settings.aaSorting = resolved;
9430		} );
9431	} );
9432	
9433	
9434	/**
9435	 * Attach a sort listener to an element for a given column
9436	 *
9437	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
9438	 *   listener to. This can take the form of a single DOM node, a jQuery
9439	 *   collection of nodes or a jQuery selector which will identify the node(s).
9440	 * @param {integer} column the column that a click on this node will sort on
9441	 * @param {function} [callback] callback function when sort is run
9442	 * @returns {DataTables.Api} this
9443	 */
9444	_api_register( 'order.listener()', function ( node, column, callback ) {
9445		return this.iterator( 'table', function ( settings ) {
9446			_fnSortAttachListener(settings, node, {}, column, callback);
9447		} );
9448	} );
9449	
9450	
9451	_api_register( 'order.fixed()', function ( set ) {
9452		if ( ! set ) {
9453			var ctx = this.context;
9454			var fixed = ctx.length ?
9455				ctx[0].aaSortingFixed :
9456				undefined;
9457	
9458			return Array.isArray( fixed ) ?
9459				{ pre: fixed } :
9460				fixed;
9461		}
9462	
9463		return this.iterator( 'table', function ( settings ) {
9464			settings.aaSortingFixed = $.extend( true, {}, set );
9465		} );
9466	} );
9467	
9468	
9469	// Order by the selected column(s)
9470	_api_register( [
9471		'columns().order()',
9472		'column().order()'
9473	], function ( dir ) {
9474		var that = this;
9475	
9476		if ( ! dir ) {
9477			return this.iterator( 'column', function ( settings, idx ) {
9478				var sort = _fnSortFlatten( settings );
9479	
9480				for ( var i=0, ien=sort.length ; i<ien ; i++ ) {
9481					if ( sort[i].col === idx ) {
9482						return sort[i].dir;
9483					}
9484				}
9485	
9486				return null;
9487			}, 1 );
9488		}
9489		else {
9490			return this.iterator( 'table', function ( settings, i ) {
9491				settings.aaSorting = that[i].map( function (col) {
9492					return [ col, dir ];
9493				} );
9494			} );
9495		}
9496	} );
9497	
9498	_api_registerPlural('columns().orderable()', 'column().orderable()', function ( directions ) {
9499		return this.iterator( 'column', function ( settings, idx ) {
9500			var col = settings.aoColumns[idx];
9501	
9502			return directions ?
9503				col.asSorting :
9504				col.bSortable;
9505		}, 1 );
9506	} );
9507	
9508	
9509	_api_register( 'processing()', function ( show ) {
9510		return this.iterator( 'table', function ( ctx ) {
9511			_fnProcessingDisplay( ctx, show );
9512		} );
9513	} );
9514	
9515	
9516	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9517		var ctx = this.context;
9518	
9519		if ( input === undefined ) {
9520			// get
9521			return ctx.length !== 0 ?
9522				ctx[0].oPreviousSearch.search :
9523				undefined;
9524		}
9525	
9526		// set
9527		return this.iterator( 'table', function ( settings ) {
9528			if ( ! settings.oFeatures.bFilter ) {
9529				return;
9530			}
9531	
9532			if (typeof regex === 'object') {
9533				// New style options to pass to the search builder
9534				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, regex, {
9535					search: input
9536				} ) );
9537			}
9538			else {
9539				// Compat for the old options
9540				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, {
9541					search: input,
9542					regex:  regex === null ? false : regex,
9543					smart:  smart === null ? true  : smart,
9544					caseInsensitive: caseInsen === null ? true : caseInsen
9545				} ) );
9546			}
9547		} );
9548	} );
9549	
9550	_api_register( 'search.fixed()', function ( name, search ) {
9551		var ret = this.iterator( true, 'table', function ( settings ) {
9552			var fixed = settings.searchFixed;
9553	
9554			if (! name) {
9555				return Object.keys(fixed);
9556			}
9557			else if (search === undefined) {
9558				return fixed[name];
9559			}
9560			else if (search === null) {
9561				delete fixed[name];
9562			}
9563			else {
9564				fixed[name] = search;
9565			}
9566	
9567			return this;
9568		} );
9569	
9570		return name !== undefined && search === undefined
9571			? ret[0]
9572			: ret;
9573	} );
9574	
9575	_api_registerPlural(
9576		'columns().search()',
9577		'column().search()',
9578		function ( input, regex, smart, caseInsen ) {
9579			return this.iterator( 'column', function ( settings, column ) {
9580				var preSearch = settings.aoPreSearchCols;
9581	
9582				if ( input === undefined ) {
9583					// get
9584					return preSearch[ column ].search;
9585				}
9586	
9587				// set
9588				if ( ! settings.oFeatures.bFilter ) {
9589					return;
9590				}
9591	
9592				if (typeof regex === 'object') {
9593					// New style options to pass to the search builder
9594					$.extend( preSearch[ column ], regex, {
9595						search: input
9596					} );
9597				}
9598				else {
9599					// Old style (with not all options available)
9600					$.extend( preSearch[ column ], {
9601						search: input,
9602						regex:  regex === null ? false : regex,
9603						smart:  smart === null ? true  : smart,
9604						caseInsensitive: caseInsen === null ? true : caseInsen
9605					} );
9606				}
9607	
9608				_fnFilterComplete( settings, settings.oPreviousSearch );
9609			} );
9610		}
9611	);
9612	
9613	_api_register([
9614			'columns().search.fixed()',
9615			'column().search.fixed()'
9616		],
9617		function ( name, search ) {
9618			var ret = this.iterator( true, 'column', function ( settings, colIdx ) {
9619				var fixed = settings.aoColumns[colIdx].searchFixed;
9620	
9621				if (! name) {
9622					return Object.keys(fixed);
9623				}
9624				else if (search === undefined) {
9625					return fixed[name] || null;
9626				}
9627				else if (search === null) {
9628					delete fixed[name];
9629				}
9630				else {
9631					fixed[name] = search;
9632				}
9633	
9634				return this;
9635			} );
9636	
9637			return name !== undefined && search === undefined
9638				? ret[0]
9639				: ret;
9640		}
9641	);
9642	/*
9643	 * State API methods
9644	 */
9645	
9646	_api_register( 'state()', function ( set, ignoreTime ) {
9647		// getter
9648		if ( ! set ) {
9649			return this.context.length ?
9650				this.context[0].oSavedState :
9651				null;
9652		}
9653	
9654		var setMutate = $.extend( true, {}, set );
9655	
9656		// setter
9657		return this.iterator( 'table', function ( settings ) {
9658			if ( ignoreTime !== false ) {
9659				setMutate.time = +new Date() + 100;
9660			}
9661	
9662			_fnImplementState( settings, setMutate, function(){} );
9663		} );
9664	} );
9665	
9666	
9667	_api_register( 'state.clear()', function () {
9668		return this.iterator( 'table', function ( settings ) {
9669			// Save an empty object
9670			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9671		} );
9672	} );
9673	
9674	
9675	_api_register( 'state.loaded()', function () {
9676		return this.context.length ?
9677			this.context[0].oLoadedState :
9678			null;
9679	} );
9680	
9681	
9682	_api_register( 'state.save()', function () {
9683		return this.iterator( 'table', function ( settings ) {
9684			_fnSaveState( settings );
9685		} );
9686	} );
9687	
9688	// Can be assigned in DateTable.use() - note luxon and moment vars are in helpers.js
9689	var __bootstrap;
9690	var __foundation;
9691	
9692	/**
9693	 * Set the libraries that DataTables uses, or the global objects.
9694	 * Note that the arguments can be either way around (legacy support)
9695	 * and the second is optional. See docs.
9696	 */
9697	DataTable.use = function (arg1, arg2) {
9698		// Reverse arguments for legacy support
9699		var module = typeof arg1 === 'string'
9700			? arg2
9701			: arg1;
9702		var type = typeof arg2 === 'string'
9703			? arg2
9704			: arg1;
9705	
9706		// Getter
9707		if (module === undefined && typeof type === 'string') {
9708			switch (type) {
9709				case 'lib':
9710				case 'jq':
9711					return $;
9712	
9713				case 'win':
9714					return window;
9715	
9716				case 'datetime':
9717					return DataTable.DateTime;
9718	
9719				case 'luxon':
9720					return __luxon;
9721	
9722				case 'moment':
9723					return __moment;
9724	
9725				case 'bootstrap':
9726					// Use local if set, otherwise try window, which could be undefined
9727					return __bootstrap || window.bootstrap;
9728	
9729				case 'foundation':
9730					// Ditto
9731					return __foundation || window.Foundation;
9732	
9733				default:
9734					return null;
9735			}
9736		}
9737	
9738		// Setter
9739		if (type === 'lib' || type === 'jq' || (module && module.fn && module.fn.jquery)) {
9740			$ = module;
9741		}
9742		else if (type === 'win' || (module && module.document)) {
9743			window = module;
9744			document = module.document;
9745		}
9746		else if (type === 'datetime' || (module && module.type === 'DateTime')) {
9747			DataTable.DateTime = module;
9748		}
9749		else if (type === 'luxon' || (module && module.FixedOffsetZone)) {
9750			__luxon = module;
9751		}
9752		else if (type === 'moment' || (module && module.isMoment)) {
9753			__moment = module;
9754		}
9755		else if (type === 'bootstrap' || (module && module.Modal && module.Modal.NAME === 'modal'))
9756		{
9757			// This is currently for BS5 only. BS3/4 attach to jQuery, so no need to use `.use()`
9758			__bootstrap = module;
9759		}
9760		else if (type === 'foundation' || (module && module.Reveal)) {
9761			__foundation = module;
9762		}
9763	}
9764	
9765	/**
9766	 * CommonJS factory function pass through. This will check if the arguments
9767	 * given are a window object or a jQuery object. If so they are set
9768	 * accordingly.
9769	 * @param {*} root Window
9770	 * @param {*} jq jQUery
9771	 * @returns {boolean} Indicator
9772	 */
9773	DataTable.factory = function (root, jq) {
9774		var is = false;
9775	
9776		// Test if the first parameter is a window object
9777		if (root && root.document) {
9778			window = root;
9779			document = root.document;
9780		}
9781	
9782		// Test if the second parameter is a jQuery object
9783		if (jq && jq.fn && jq.fn.jquery) {
9784			$ = jq;
9785			is = true;
9786		}
9787	
9788		return is;
9789	}
9790	
9791	/**
9792	 * Provide a common method for plug-ins to check the version of DataTables being
9793	 * used, in order to ensure compatibility.
9794	 *
9795	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
9796	 *    Note that the formats "X" and "X.Y" are also acceptable.
9797	 *  @param {string} [version2=current DataTables version] As above, but optional.
9798	 *   If not given the current DataTables version will be used.
9799	 *  @returns {boolean} true if this version of DataTables is greater or equal to
9800	 *    the required version, or false if this version of DataTales is not
9801	 *    suitable
9802	 *  @static
9803	 *  @dtopt API-Static
9804	 *
9805	 *  @example
9806	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9807	 */
9808	DataTable.versionCheck = function( version, version2 )
9809	{
9810		var aThis = version2 ?
9811			version2.split('.') :
9812			DataTable.version.split('.');
9813		var aThat = version.split('.');
9814		var iThis, iThat;
9815	
9816		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9817			iThis = parseInt( aThis[i], 10 ) || 0;
9818			iThat = parseInt( aThat[i], 10 ) || 0;
9819	
9820			// Parts are the same, keep comparing
9821			if (iThis === iThat) {
9822				continue;
9823			}
9824	
9825			// Parts are different, return immediately
9826			return iThis > iThat;
9827		}
9828	
9829		return true;
9830	};
9831	
9832	
9833	/**
9834	 * Check if a `<table>` node is a DataTable table already or not.
9835	 *
9836	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9837	 *      selector for the table to test. Note that if more than more than one
9838	 *      table is passed on, only the first will be checked
9839	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
9840	 *  @static
9841	 *  @dtopt API-Static
9842	 *
9843	 *  @example
9844	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9845	 *      $('#example').dataTable();
9846	 *    }
9847	 */
9848	DataTable.isDataTable = function ( table )
9849	{
9850		var t = $(table).get(0);
9851		var is = false;
9852	
9853		if ( table instanceof DataTable.Api ) {
9854			return true;
9855		}
9856	
9857		$.each( DataTable.settings, function (i, o) {
9858			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9859			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9860	
9861			if ( o.nTable === t || head === t || foot === t ) {
9862				is = true;
9863			}
9864		} );
9865	
9866		return is;
9867	};
9868	
9869	
9870	/**
9871	 * Get all DataTable tables that have been initialised - optionally you can
9872	 * select to get only currently visible tables.
9873	 *
9874	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9875	 *    or visible tables only.
9876	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9877	 *    DataTables
9878	 *  @static
9879	 *  @dtopt API-Static
9880	 *
9881	 *  @example
9882	 *    $.each( $.fn.dataTable.tables(true), function () {
9883	 *      $(table).DataTable().columns.adjust();
9884	 *    } );
9885	 */
9886	DataTable.tables = function ( visible )
9887	{
9888		var api = false;
9889	
9890		if ( $.isPlainObject( visible ) ) {
9891			api = visible.api;
9892			visible = visible.visible;
9893		}
9894	
9895		var a = DataTable.settings
9896			.filter( function (o) {
9897				return !visible || (visible && $(o.nTable).is(':visible')) 
9898					? true
9899					: false;
9900			} )
9901			.map( function (o) {
9902				return o.nTable;
9903			});
9904	
9905		return api ?
9906			new _Api( a ) :
9907			a;
9908	};
9909	
9910	
9911	/**
9912	 * Convert from camel case parameters to Hungarian notation. This is made public
9913	 * for the extensions to provide the same ability as DataTables core to accept
9914	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9915	 * parameters.
9916	 *
9917	 *  @param {object} src The model object which holds all parameters that can be
9918	 *    mapped.
9919	 *  @param {object} user The object to convert from camel case to Hungarian.
9920	 *  @param {boolean} force When set to `true`, properties which already have a
9921	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
9922	 *    won't be.
9923	 */
9924	DataTable.camelToHungarian = _fnCamelToHungarian;
9925	
9926	
9927	
9928	/**
9929	 *
9930	 */
9931	_api_register( '$()', function ( selector, opts ) {
9932		var
9933			rows   = this.rows( opts ).nodes(), // Get all rows
9934			jqRows = $(rows);
9935	
9936		return $( [].concat(
9937			jqRows.filter( selector ).toArray(),
9938			jqRows.find( selector ).toArray()
9939		) );
9940	} );
9941	
9942	
9943	// jQuery functions to operate on the tables
9944	$.each( [ 'on', 'one', 'off' ], function (i, key) {
9945		_api_register( key+'()', function ( /* event, handler */ ) {
9946			var args = Array.prototype.slice.call(arguments);
9947	
9948			// Add the `dt` namespace automatically if it isn't already present
9949			args[0] = args[0].split( /\s/ ).map( function ( e ) {
9950				return ! e.match(/\.dt\b/) ?
9951					e+'.dt' :
9952					e;
9953				} ).join( ' ' );
9954	
9955			var inst = $( this.tables().nodes() );
9956			inst[key].apply( inst, args );
9957			return this;
9958		} );
9959	} );
9960	
9961	
9962	_api_register( 'clear()', function () {
9963		return this.iterator( 'table', function ( settings ) {
9964			_fnClearTable( settings );
9965		} );
9966	} );
9967	
9968	
9969	_api_register( 'error()', function (msg) {
9970		return this.iterator( 'table', function ( settings ) {
9971			_fnLog( settings, 0, msg );
9972		} );
9973	} );
9974	
9975	
9976	_api_register( 'settings()', function () {
9977		return new _Api( this.context, this.context );
9978	} );
9979	
9980	
9981	_api_register( 'init()', function () {
9982		var ctx = this.context;
9983		return ctx.length ? ctx[0].oInit : null;
9984	} );
9985	
9986	
9987	_api_register( 'data()', function () {
9988		return this.iterator( 'table', function ( settings ) {
9989			return _pluck( settings.aoData, '_aData' );
9990		} ).flatten();
9991	} );
9992	
9993	
9994	_api_register( 'trigger()', function ( name, args, bubbles ) {
9995		return this.iterator( 'table', function ( settings ) {
9996			return _fnCallbackFire( settings, null, name, args, bubbles );
9997		} ).flatten();
9998	} );
9999	
10000	
10001	_api_register( 'ready()', function ( fn ) {
10002		var ctx = this.context;
10003	
10004		// Get status of first table
10005		if (! fn) {
10006			return ctx.length
10007				? (ctx[0]._bInitComplete || false)
10008				: null;
10009		}
10010	
10011		// Function to run either once the table becomes ready or
10012		// immediately if it is already ready.
10013		return this.tables().every(function () {
10014			var api = this;
10015	
10016			if (this.context[0]._bInitComplete) {
10017				fn.call(api);
10018			}
10019			else {
10020				this.on('init.dt.DT', function () {
10021					fn.call(api);
10022				});
10023			}
10024		} );
10025	} );
10026	
10027	
10028	_api_register( 'destroy()', function ( remove ) {
10029		remove = remove || false;
10030	
10031		return this.iterator( 'table', function ( settings ) {
10032			var classes   = settings.oClasses;
10033			var table     = settings.nTable;
10034			var tbody     = settings.nTBody;
10035			var thead     = settings.nTHead;
10036			var tfoot     = settings.nTFoot;
10037			var jqTable   = $(table);
10038			var jqTbody   = $(tbody);
10039			var jqWrapper = $(settings.nTableWrapper);
10040			var rows      = settings.aoData.map( function (r) { return r ? r.nTr : null; } );
10041			var orderClasses = classes.order;
10042	
10043			// Flag to note that the table is currently being destroyed - no action
10044			// should be taken
10045			settings.bDestroying = true;
10046	
10047			// Fire off the destroy callbacks for plug-ins etc
10048			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings], true );
10049	
10050			// If not being removed from the document, make all columns visible
10051			if ( ! remove ) {
10052				new _Api( settings ).columns().visible( true );
10053			}
10054	
10055			// Container width change listener
10056			if (settings.resizeObserver) {
10057				settings.resizeObserver.disconnect();
10058			}
10059	
10060			// Blitz all `DT` namespaced events (these are internal events, the
10061			// lowercase, `dt` events are user subscribed and they are responsible
10062			// for removing them
10063			jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
10064			$(window).off('.DT-'+settings.sInstance);
10065	
10066			// When scrolling we had to break the table up - restore it
10067			if ( table != thead.parentNode ) {
10068				jqTable.children('thead').detach();
10069				jqTable.append( thead );
10070			}
10071	
10072			if ( tfoot && table != tfoot.parentNode ) {
10073				jqTable.children('tfoot').detach();
10074				jqTable.append( tfoot );
10075			}
10076	
10077			// Clean up the header / footer
10078			cleanHeader(thead, 'header');
10079			cleanHeader(tfoot, 'footer');
10080			settings.colgroup.remove();
10081	
10082			settings.aaSorting = [];
10083			settings.aaSortingFixed = [];
10084			_fnSortingClasses( settings );
10085	
10086			$(jqTable).find('th, td').removeClass(
10087				$.map(DataTable.ext.type.className, function (v) {
10088					return v;
10089				}).join(' ')
10090			);
10091	
10092			$('th, td', thead)
10093				.removeClass(
10094					orderClasses.none + ' ' +
10095					orderClasses.canAsc + ' ' +
10096					orderClasses.canDesc + ' ' +
10097					orderClasses.isAsc + ' ' +
10098					orderClasses.isDesc
10099				)
10100				.css('width', '')
10101				.removeAttr('aria-sort');
10102	
10103			// Add the TR elements back into the table in their original order
10104			jqTbody.children().detach();
10105			jqTbody.append( rows );
10106	
10107			var orig = settings.nTableWrapper.parentNode;
10108			var insertBefore = settings.nTableWrapper.nextSibling;
10109	
10110			// Remove the DataTables generated nodes, events and classes
10111			var removedMethod = remove ? 'remove' : 'detach';
10112			jqTable[ removedMethod ]();
10113			jqWrapper[ removedMethod ]();
10114	
10115			// If we need to reattach the table to the document
10116			if ( ! remove && orig ) {
10117				// insertBefore acts like appendChild if !arg[1]
10118				orig.insertBefore( table, insertBefore );
10119	
10120				// Restore the width of the original table - was read from the style property,
10121				// so we can restore directly to that
10122				jqTable
10123					.css( 'width', settings.sDestroyWidth )
10124					.removeClass( classes.table );
10125			}
10126	
10127			/* Remove the settings object from the settings array */
10128			var idx = DataTable.settings.indexOf(settings);
10129			if ( idx !== -1 ) {
10130				DataTable.settings.splice( idx, 1 );
10131			}
10132		} );
10133	} );
10134	
10135	
10136	// Add the `every()` method for rows, columns and cells in a compact form
10137	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
10138		_api_register( type+'s().every()', function ( fn ) {
10139			var opts = this.selector.opts;
10140			var api = this;
10141			var inst;
10142			var counter = 0;
10143	
10144			return this.iterator( 'every', function ( settings, selectedIdx, tableIdx ) {
10145				inst = api[ type ](selectedIdx, opts);
10146	
10147				if (type === 'cell') {
10148					fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
10149				}
10150				else {
10151					fn.call(inst, selectedIdx, tableIdx, counter);
10152				}
10153	
10154				counter++;
10155			} );
10156		} );
10157	} );
10158	
10159	
10160	// i18n method for extensions to be able to use the language object from the
10161	// DataTable
10162	_api_register( 'i18n()', function ( token, def, plural ) {
10163		var ctx = this.context[0];
10164		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
10165	
10166		if ( resolved === undefined ) {
10167			resolved = def;
10168		}
10169	
10170		if ( $.isPlainObject( resolved ) ) {
10171			resolved = plural !== undefined && resolved[ plural ] !== undefined ?
10172				resolved[ plural ] :
10173				resolved._;
10174		}
10175	
10176		return typeof resolved === 'string'
10177			? resolved.replace( '%d', plural ) // nb: plural might be undefined,
10178			: resolved;
10179	} );
10180	
10181	// Needed for header and footer, so pulled into its own function
10182	function cleanHeader(node, className) {
10183		$(node).find('span.dt-column-order').remove();
10184		$(node).find('span.dt-column-title').each(function () {
10185			var title = $(this).html();
10186			$(this).parent().parent().append(title);
10187			$(this).remove();
10188		});
10189		$(node).find('div.dt-column-' + className).remove();
10190	
10191		$('th, td', node).removeAttr('data-dt-column');
10192	}
10193	
10194	/**
10195	 * Version string for plug-ins to check compatibility. Allowed format is
10196	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
10197	 * only for non-release builds. See https://semver.org/ for more information.
10198	 *  @member
10199	 *  @type string
10200	 *  @default Version number
10201	 */
10202	DataTable.version = "2.3.1";
10203	
10204	/**
10205	 * Private data store, containing all of the settings objects that are
10206	 * created for the tables on a given page.
10207	 *
10208	 * Note that the `DataTable.settings` object is aliased to
10209	 * `jQuery.fn.dataTableExt` through which it may be accessed and
10210	 * manipulated, or `jQuery.fn.dataTable.settings`.
10211	 *  @member
10212	 *  @type array
10213	 *  @default []
10214	 *  @private
10215	 */
10216	DataTable.settings = [];
10217	
10218	/**
10219	 * Object models container, for the various models that DataTables has
10220	 * available to it. These models define the objects that are used to hold
10221	 * the active state and configuration of the table.
10222	 *  @namespace
10223	 */
10224	DataTable.models = {};
10225	
10226	
10227	
10228	/**
10229	 * Template object for the way in which DataTables holds information about
10230	 * search information for the global filter and individual column filters.
10231	 *  @namespace
10232	 */
10233	DataTable.models.oSearch = {
10234		/**
10235		 * Flag to indicate if the filtering should be case insensitive or not
10236		 */
10237		"caseInsensitive": true,
10238	
10239		/**
10240		 * Applied search term
10241		 */
10242		"search": "",
10243	
10244		/**
10245		 * Flag to indicate if the search term should be interpreted as a
10246		 * regular expression (true) or not (false) and therefore and special
10247		 * regex characters escaped.
10248		 */
10249		"regex": false,
10250	
10251		/**
10252		 * Flag to indicate if DataTables is to use its smart filtering or not.
10253		 */
10254		"smart": true,
10255	
10256		/**
10257		 * Flag to indicate if DataTables should only trigger a search when
10258		 * the return key is pressed.
10259		 */
10260		"return": false
10261	};
10262	
10263	
10264	
10265	
10266	/**
10267	 * Template object for the way in which DataTables holds information about
10268	 * each individual row. This is the object format used for the settings
10269	 * aoData array.
10270	 *  @namespace
10271	 */
10272	DataTable.models.oRow = {
10273		/**
10274		 * TR element for the row
10275		 */
10276		"nTr": null,
10277	
10278		/**
10279		 * Array of TD elements for each row. This is null until the row has been
10280		 * created.
10281		 */
10282		"anCells": null,
10283	
10284		/**
10285		 * Data object from the original data source for the row. This is either
10286		 * an array if using the traditional form of DataTables, or an object if
10287		 * using mData options. The exact type will depend on the passed in
10288		 * data from the data source, or will be an array if using DOM a data
10289		 * source.
10290		 */
10291		"_aData": [],
10292	
10293		/**
10294		 * Sorting data cache - this array is ostensibly the same length as the
10295		 * number of columns (although each index is generated only as it is
10296		 * needed), and holds the data that is used for sorting each column in the
10297		 * row. We do this cache generation at the start of the sort in order that
10298		 * the formatting of the sort data need be done only once for each cell
10299		 * per sort. This array should not be read from or written to by anything
10300		 * other than the master sorting methods.
10301		 */
10302		"_aSortData": null,
10303	
10304		/**
10305		 * Per cell filtering data cache. As per the sort data cache, used to
10306		 * increase the performance of the filtering in DataTables
10307		 */
10308		"_aFilterData": null,
10309	
10310		/**
10311		 * Filtering data cache. This is the same as the cell filtering cache, but
10312		 * in this case a string rather than an array. This is easily computed with
10313		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
10314		 * needed on every search (memory traded for performance)
10315		 */
10316		"_sFilterRow": null,
10317	
10318		/**
10319		 * Denote if the original data source was from the DOM, or the data source
10320		 * object. This is used for invalidating data, so DataTables can
10321		 * automatically read data from the original source, unless uninstructed
10322		 * otherwise.
10323		 */
10324		"src": null,
10325	
10326		/**
10327		 * Index in the aoData array. This saves an indexOf lookup when we have the
10328		 * object, but want to know the index
10329		 */
10330		"idx": -1,
10331	
10332		/**
10333		 * Cached display value
10334		 */
10335		displayData: null
10336	};
10337	
10338	
10339	/**
10340	 * Template object for the column information object in DataTables. This object
10341	 * is held in the settings aoColumns array and contains all the information that
10342	 * DataTables needs about each individual column.
10343	 *
10344	 * Note that this object is related to {@link DataTable.defaults.column}
10345	 * but this one is the internal data store for DataTables's cache of columns.
10346	 * It should NOT be manipulated outside of DataTables. Any configuration should
10347	 * be done through the initialisation options.
10348	 *  @namespace
10349	 */
10350	DataTable.models.oColumn = {
10351		/**
10352		 * Column index.
10353		 */
10354		"idx": null,
10355	
10356		/**
10357		 * A list of the columns that sorting should occur on when this column
10358		 * is sorted. That this property is an array allows multi-column s
10358orting
10359		 * to be defined for a column (for example first name / last name columns
10360		 * would benefit from this). The values are integers pointing to the
10361		 * columns to be sorted on (typically it will be a single integer pointing
10362		 * at itself, but that doesn't need to be the case).
10363		 */
10364		"aDataSort": null,
10365	
10366		/**
10367		 * Define the sorting directions that are applied to the column, in sequence
10368		 * as the column is repeatedly sorted upon - i.e. the first value is used
10369		 * as the sorting direction when the column if first sorted (clicked on).
10370		 * Sort it again (click again) and it will move on to the next index.
10371		 * Repeat until loop.
10372		 */
10373		"asSorting": null,
10374	
10375		/**
10376		 * Flag to indicate if the column is searchable, and thus should be included
10377		 * in the filtering or not.
10378		 */
10379		"bSearchable": null,
10380	
10381		/**
10382		 * Flag to indicate if the column is sortable or not.
10383		 */
10384		"bSortable": null,
10385	
10386		/**
10387		 * Flag to indicate if the column is currently visible in the table or not
10388		 */
10389		"bVisible": null,
10390	
10391		/**
10392		 * Store for manual type assignment using the `column.type` option. This
10393		 * is held in store so we can manipulate the column's `sType` property.
10394		 */
10395		"_sManualType": null,
10396	
10397		/**
10398		 * Flag to indicate if HTML5 data attributes should be used as the data
10399		 * source for filtering or sorting. True is either are.
10400		 */
10401		"_bAttrSrc": false,
10402	
10403		/**
10404		 * Developer definable function that is called whenever a cell is created (Ajax source,
10405		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
10406		 * allowing you to modify the DOM element (add background colour for example) when the
10407		 * element is available.
10408		 */
10409		"fnCreatedCell": null,
10410	
10411		/**
10412		 * Function to get data from a cell in a column. You should <b>never</b>
10413		 * access data directly through _aData internally in DataTables - always use
10414		 * the method attached to this property. It allows mData to function as
10415		 * required. This function is automatically assigned by the column
10416		 * initialisation method
10417		 */
10418		"fnGetData": null,
10419	
10420		/**
10421		 * Function to set data for a cell in the column. You should <b>never</b>
10422		 * set the data directly to _aData internally in DataTables - always use
10423		 * this method. It allows mData to function as required. This function
10424		 * is automatically assigned by the column initialisation method
10425		 */
10426		"fnSetData": null,
10427	
10428		/**
10429		 * Property to read the value for the cells in the column from the data
10430		 * source array / object. If null, then the default content is used, if a
10431		 * function is given then the return from the function is used.
10432		 */
10433		"mData": null,
10434	
10435		/**
10436		 * Partner property to mData which is used (only when defined) to get
10437		 * the data - i.e. it is basically the same as mData, but without the
10438		 * 'set' option, and also the data fed to it is the result from mData.
10439		 * This is the rendering method to match the data method of mData.
10440		 */
10441		"mRender": null,
10442	
10443		/**
10444		 * The class to apply to all TD elements in the table's TBODY for the column
10445		 */
10446		"sClass": null,
10447	
10448		/**
10449		 * When DataTables calculates the column widths to assign to each column,
10450		 * it finds the longest string in each column and then constructs a
10451		 * temporary table and reads the widths from that. The problem with this
10452		 * is that "mmm" is much wider then "iiii", but the latter is a longer
10453		 * string - thus the calculation can go wrong (doing it properly and putting
10454		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
10455		 * a "work around" we provide this option. It will append its value to the
10456		 * text that is found to be the longest string for the column - i.e. padding.
10457		 */
10458		"sContentPadding": null,
10459	
10460		/**
10461		 * Allows a default value to be given for a column's data, and will be used
10462		 * whenever a null data source is encountered (this can be because mData
10463		 * is set to null, or because the data source itself is null).
10464		 */
10465		"sDefaultContent": null,
10466	
10467		/**
10468		 * Name for the column, allowing reference to the column by name as well as
10469		 * by index (needs a lookup to work by name).
10470		 */
10471		"sName": null,
10472	
10473		/**
10474		 * Custom sorting data type - defines which of the available plug-ins in
10475		 * afnSortData the custom sorting will use - if any is defined.
10476		 */
10477		"sSortDataType": 'std',
10478	
10479		/**
10480		 * Class to be applied to the header element when sorting on this column
10481		 */
10482		"sSortingClass": null,
10483	
10484		/**
10485		 * Title of the column - what is seen in the TH element (nTh).
10486		 */
10487		"sTitle": null,
10488	
10489		/**
10490		 * Column sorting and filtering type
10491		 */
10492		"sType": null,
10493	
10494		/**
10495		 * Width of the column
10496		 */
10497		"sWidth": null,
10498	
10499		/**
10500		 * Width of the column when it was first "encountered"
10501		 */
10502		"sWidthOrig": null,
10503	
10504		/** Cached string which is the longest in the column */
10505		maxLenString: null,
10506	
10507		/**
10508		 * Store for named searches
10509		 */
10510		searchFixed: null
10511	};
10512	
10513	
10514	/*
10515	 * Developer note: The properties of the object below are given in Hungarian
10516	 * notation, that was used as the interface for DataTables prior to v1.10, however
10517	 * from v1.10 onwards the primary interface is camel case. In order to avoid
10518	 * breaking backwards compatibility utterly with this change, the Hungarian
10519	 * version is still, internally the primary interface, but is is not documented
10520	 * - hence the @name tags in each doc comment. This allows a Javascript function
10521	 * to create a map from Hungarian notation to camel case (going the other direction
10522	 * would require each property to be listed, which would add around 3K to the size
10523	 * of DataTables, while this method is about a 0.5K hit).
10524	 *
10525	 * Ultimately this does pave the way for Hungarian notation to be dropped
10526	 * completely, but that is a massive amount of work and will break current
10527	 * installs (therefore is on-hold until v2).
10528	 */
10529	
10530	/**
10531	 * Initialisation options that can be given to DataTables at initialisation
10532	 * time.
10533	 *  @namespace
10534	 */
10535	DataTable.defaults = {
10536		/**
10537		 * An array of data to use for the table, passed in at initialisation which
10538		 * will be used in preference to any data which is already in the DOM. This is
10539		 * particularly useful for constructing tables purely in Javascript, for
10540		 * example with a custom Ajax call.
10541		 */
10542		"aaData": null,
10543	
10544	
10545		/**
10546		 * If ordering is enabled, then DataTables will perform a first pass sort on
10547		 * initialisation. You can define which column(s) the sort is performed
10548		 * upon, and the sorting direction, with this variable. The `sorting` array
10549		 * should contain an array for each column to be sorted initially containing
10550		 * the column's index and a direction string ('asc' or 'desc').
10551		 */
10552		"aaSorting": [[0,'asc']],
10553	
10554	
10555		/**
10556		 * This parameter is basically identical to the `sorting` parameter, but
10557		 * cannot be overridden by user interaction with the table. What this means
10558		 * is that you could have a column (visible or hidden) which the sorting
10559		 * will always be forced on first - any sorting after that (from the user)
10560		 * will then be performed as required. This can be useful for grouping rows
10561		 * together.
10562		 */
10563		"aaSortingFixed": [],
10564	
10565	
10566		/**
10567		 * DataTables can be instructed to load data to display in the table from a
10568		 * Ajax source. This option defines how that Ajax call is made and where to.
10569		 *
10570		 * The `ajax` property has three different modes of operation, depending on
10571		 * how it is defined. These are:
10572		 *
10573		 * * `string` - Set the URL from where the data should be loaded from.
10574		 * * `object` - Define properties for `jQuery.ajax`.
10575		 * * `function` - Custom data get function
10576		 *
10577		 * `string`
10578		 * --------
10579		 *
10580		 * As a string, the `ajax` property simply defines the URL from which
10581		 * DataTables will load data.
10582		 *
10583		 * `object`
10584		 * --------
10585		 *
10586		 * As an object, the parameters in the object are passed to
10587		 * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
10588		 * of the Ajax request. DataTables has a number of default parameters which
10589		 * you can override using this option. Please refer to the jQuery
10590		 * documentation for a full description of the options available, although
10591		 * the following parameters provide additional options in DataTables or
10592		 * require special consideration:
10593		 *
10594		 * * `data` - As with jQuery, `data` can be provided as an object, but it
10595		 *   can also be used as a function to manipulate the data DataTables sends
10596		 *   to the server. The function takes a single parameter, an object of
10597		 *   parameters with the values that DataTables has readied for sending. An
10598		 *   object may be returned which will be merged into the DataTables
10599		 *   defaults, or you can add the items to the object that was passed in and
10600		 *   not return anything from the function. This supersedes `fnServerParams`
10601		 *   from DataTables 1.9-.
10602		 *
10603		 * * `dataSrc` - By default DataTables will look for the property `data` (or
10604		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
10605		 *   from an Ajax source or for server-side processing - this parameter
10606		 *   allows that property to be changed. You can use Javascript dotted
10607		 *   object notation to get a data source for multiple levels of nesting, or
10608		 *   it my be used as a function. As a function it takes a single parameter,
10609		 *   the JSON returned from the server, which can be manipulated as
10610		 *   required, with the returned value being that used by DataTables as the
10611		 *   data source for the table.
10612		 *
10613		 * * `success` - Should not be overridden it is used internally in
10614		 *   DataTables. To manipulate / transform the data returned by the server
10615		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10616		 *
10617		 * `function`
10618		 * ----------
10619		 *
10620		 * As a function, making the Ajax call is left up to yourself allowing
10621		 * complete control of the Ajax request. Indeed, if desired, a method other
10622		 * than Ajax could be used to obtain the required data, such as Web storage
10623		 * or an AIR database.
10624		 *
10625		 * The function is given four parameters and no return is required. The
10626		 * parameters are:
10627		 *
10628		 * 1. _object_ - Data to send to the server
10629		 * 2. _function_ - Callback function that must be executed when the required
10630		 *    data has been obtained. That data should be passed into the callback
10631		 *    as the only parameter
10632		 * 3. _object_ - DataTables settings object for the table
10633		 */
10634		"ajax": null,
10635	
10636	
10637		/**
10638		 * This parameter allows you to readily specify the entries in the length drop
10639		 * down menu that DataTables shows when pagination is enabled. It can be
10640		 * either a 1D array of options which will be used for both the displayed
10641		 * option and the value, or a 2D array which will use the array in the first
10642		 * position as the value, and the array in the second position as the
10643		 * displayed options (useful for language strings such as 'All').
10644		 *
10645		 * Note that the `pageLength` property will be automatically set to the
10646		 * first value given in this array, unless `pageLength` is also provided.
10647		 */
10648		"aLengthMenu": [ 10, 25, 50, 100 ],
10649	
10650	
10651		/**
10652		 * The `columns` option in the initialisation parameter allows you to define
10653		 * details about the way individual columns behave. For a full list of
10654		 * column options that can be set, please see
10655		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10656		 * define your columns, you must have an entry in the array for every single
10657		 * column that you have in your table (these can be null if you don't which
10658		 * to specify any options).
10659		 */
10660		"aoColumns": null,
10661	
10662		/**
10663		 * Very similar to `columns`, `columnDefs` allows you to target a specific
10664		 * column, multiple columns, or all columns, using the `targets` property of
10665		 * each object in the array. This allows great flexibility when creating
10666		 * tables, as the `columnDefs` arrays can be of any length, targeting the
10667		 * columns you specifically want. `columnDefs` may use any of the column
10668		 * options available: {@link DataTable.defaults.column}, but it _must_
10669		 * have `targets` defined in each object in the array. Values in the `targets`
10670		 * array may be:
10671		 *   <ul>
10672		 *     <li>a string - class name will be matched on the TH for the column</li>
10673		 *     <li>0 or a positive integer - column index counting from the left</li>
10674		 *     <li>a negative integer - column index counting from the right</li>
10675		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10676		 *   </ul>
10677		 */
10678		"aoColumnDefs": null,
10679	
10680	
10681		/**
10682		 * Basically the same as `search`, this parameter defines the individual column
10683		 * filtering state at initialisation time. The array must be of the same size
10684		 * as the number of columns, and each element be an object with the parameters
10685		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10686		 * accepted and the default will be used.
10687		 */
10688		"aoSearchCols": [],
10689	
10690	
10691		/**
10692		 * Enable or disable automatic column width calculation. This can be disabled
10693		 * as an optimisation (it takes some time to calculate the widths) if the
10694		 * tables widths are passed in using `columns`.
10695		 */
10696		"bAutoWidth": true,
10697	
10698	
10699		/**
10700		 * Deferred rendering can provide DataTables with a huge speed boost when you
10701		 * are using an Ajax or JS data source for the table. This option, when set to
10702		 * true, will cause DataTables to defer the creation of the table elements for
10703		 * each row until they are needed for a draw - saving a significant amount of
10704		 * time.
10705		 */
10706		"bDeferRender": true,
10707	
10708	
10709		/**
10710		 * Replace a DataTable which matches the given selector and replace it with
10711		 * one which has the properties of the new initialisation object passed. If no
10712		 * table matches the selector, then the new DataTable will be constructed as
10713		 * per normal.
10714		 */
10715		"bDestroy": false,
10716	
10717	
10718		/**
10719		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10720		 * that it allows the end user to input multiple words (space separated) and
10721		 * will match a row containing those words, even if not in the order that was
10722		 * specified (this allow matching across multiple columns). Note that if you
10723		 * wish to use filtering in DataTables this must remain 'true' - to remove the
10724		 * default filtering input box and retain filtering abilities, please use
10725		 * {@link DataTable.defaults.dom}.
10726		 */
10727		"bFilter": true,
10728	
10729		/**
10730		 * Used only for compatiblity with DT1
10731		 * @deprecated
10732		 */
10733		"bInfo": true,
10734	
10735		/**
10736		 * Used only for compatiblity with DT1
10737		 * @deprecated
10738		 */
10739		"bLengthChange": true,
10740	
10741		/**
10742		 * Enable or disable pagination.
10743		 */
10744		"bPaginate": true,
10745	
10746	
10747		/**
10748		 * Enable or disable the display of a 'processing' indicator when the table is
10749		 * being processed (e.g. a sort). This is particularly useful for tables with
10750		 * large amounts of data where it can take a noticeable amount of time to sort
10751		 * the entries.
10752		 */
10753		"bProcessing": false,
10754	
10755	
10756		/**
10757		 * Retrieve the DataTables object for the given selector. Note that if the
10758		 * table has already been initialised, this parameter will cause DataTables
10759		 * to simply return the object that has already been set up - it will not take
10760		 * account of any changes you might have made to the initialisation object
10761		 * passed to DataTables (setting this parameter to true is an acknowledgement
10762		 * that you understand this). `destroy` can be used to reinitialise a table if
10763		 * you need.
10764		 */
10765		"bRetrieve": false,
10766	
10767	
10768		/**
10769		 * When vertical (y) scrolling is enabled, DataTables will force the height of
10770		 * the table's viewport to the given height at all times (useful for layout).
10771		 * However, this can look odd when filtering data down to a small data set,
10772		 * and the footer is left "floating" further down. This parameter (when
10773		 * enabled) will cause DataTables to collapse the table's viewport down when
10774		 * the result set will fit within the given Y height.
10775		 */
10776		"bScrollCollapse": false,
10777	
10778	
10779		/**
10780		 * Configure DataTables to use server-side processing. Note that the
10781		 * `ajax` parameter must also be given in order to give DataTables a
10782		 * source to obtain the required data for each draw.
10783		 */
10784		"bServerSide": false,
10785	
10786	
10787		/**
10788		 * Enable or disable sorting of columns. Sorting of individual columns can be
10789		 * disabled by the `sortable` option for each column.
10790		 */
10791		"bSort": true,
10792	
10793	
10794		/**
10795		 * Enable or display DataTables' ability to sort multiple columns at the
10796		 * same time (activated by shift-click by the user).
10797		 */
10798		"bSortMulti": true,
10799	
10800	
10801		/**
10802		 * Allows control over whether DataTables should use the top (true) unique
10803		 * cell that is found for a single column, or the bottom (false - default).
10804		 * This is useful when using complex headers.
10805		 */
10806		"bSortCellsTop": null,
10807	
10808	
10809		/** Specify which row is the title row in the header. Replacement for bSortCellsTop */
10810		titleRow: null,
10811	
10812	
10813		/**
10814		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10815		 * `sorting\_3` to the columns which are currently being sorted on. This is
10816		 * presented as a feature switch as it can increase processing time (while
10817		 * classes are removed and added) so for large data sets you might want to
10818		 * turn this off.
10819		 */
10820		"bSortClasses": true,
10821	
10822	
10823		/**
10824		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10825		 * used to save table display information such as pagination information,
10826		 * display length, filtering and sorting. As such when the end user reloads
10827		 * the page the display display will match what thy had previously set up.
10828		 */
10829		"bStateSave": false,
10830	
10831	
10832		/**
10833		 * This function is called when a TR element is created (and all TD child
10834		 * elements have been inserted), or registered if using a DOM source, allowing
10835		 * manipulation of the TR element (adding classes etc).
10836		 */
10837		"fnCreatedRow": null,
10838	
10839	
10840		/**
10841		 * This function is called on every 'draw' event, and allows you to
10842		 * dynamically modify any aspect you want about the created DOM.
10843		 */
10844		"fnDrawCallback": null,
10845	
10846	
10847		/**
10848		 * Identical to fnHeaderCallback() but for the table footer this function
10849		 * allows you to modify the table footer on every 'draw' event.
10850		 */
10851		"fnFooterCallback": null,
10852	
10853	
10854		/**
10855		 * When rendering large numbers in the information element for the table
10856		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10857		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10858		 * rendered as "1,000,000") to help readability for the end user. This
10859		 * function will override the default method DataTables uses.
10860		 */
10861		"fnFormatNumber": function ( toFormat ) {
10862			return toFormat.toString().replace(
10863				/\B(?=(\d{3})+(?!\d))/g,
10864				this.oLanguage.sThousands
10865			);
10866		},
10867	
10868	
10869		/**
10870		 * This function is called on every 'draw' event, and allows you to
10871		 * dynamically modify the header row. This can be used to calculate and
10872		 * display useful information about the table.
10873		 */
10874		"fnHeaderCallback": null,
10875	
10876	
10877		/**
10878		 * The information element can be used to convey information about the current
10879		 * state of the table. Although the internationalisation options presented by
10880		 * DataTables are quite capable of dealing with most customisations, there may
10881		 * be times where you wish to customise the string further. This callback
10882		 * allows you to do exactly that.
10883		 */
10884		"fnInfoCallback": null,
10885	
10886	
10887		/**
10888		 * Called when the table has been initialised. Normally DataTables will
10889		 * initialise sequentially and there will be no need for this function,
10890		 * however, this does not hold true when using external language information
10891		 * since that is obtained using an async XHR call.
10892		 */
10893		"fnInitComplete": null,
10894	
10895	
10896		/**
10897		 * Called at the very start of each table draw and can be used to cancel the
10898		 * draw by returning false, any other return (including undefined) results in
10899		 * the full draw occurring).
10900		 */
10901		"fnPreDrawCallback": null,
10902	
10903	
10904		/**
10905		 * This function allows you to 'post process' each row after it have been
10906		 * generated for each table draw, but before it is rendered on screen. This
10907		 * function might be used for setting the row class name etc.
10908		 */
10909		"fnRowCallback": null,
10910	
10911	
10912		/**
10913		 * Load the table state. With this function you can define from where, and how, the
10914		 * state of a table is loaded. By default DataTables will load from `localStorage`
10915		 * but you might wish to use a server-side database or cookies.
10916		 */
10917		"fnStateLoadCallback": function ( settings ) {
10918			try {
10919				return JSON.parse(
10920					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10921						'DataTables_'+settings.sInstance+'_'+location.pathname
10922					)
10923				);
10924			} catch (e) {
10925				return {};
10926			}
10927		},
10928	
10929	
10930		/**
10931		 * Callback which allows modification of the saved state prior to loading that state.
10932		 * This callback is called when the table is loading state from the stored data, but
10933		 * prior to the settings object being modified by the saved state. Note that for
10934		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10935		 * a plug-in.
10936		 */
10937		"fnStateLoadParams": null,
10938	
10939	
10940		/**
10941		 * Callback that is called when the state has been loaded from the state saving method
10942		 * and the DataTables settings object has been modified as a result of the loaded state.
10943		 */
10944		"fnStateLoaded": null,
10945	
10946	
10947		/**
10948		 * Save the table state. This function allows you to define where and how the state
10949		 * information for the table is stored By default DataTables will use `localStorage`
10950		 * but you might wish to use a server-side database or cookies.
10951		 */
10952		"fnStateSaveCallback": function ( settings, data ) {
10953			try {
10954				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10955					'DataTables_'+settings.sInstance+'_'+location.pathname,
10956					JSON.stringify( data )
10957				);
10958			} catch (e) {
10959				// noop
10960			}
10961		},
10962	
10963	
10964		/**
10965		 * Callback which allows modification of the state to be saved. Called when the table
10966		 * has changed state a new state save is required. This method allows modification of
10967		 * the state saving object prior to actually doing the save, including addition or
10968		 * other state properties or modification. Note that for plug-in authors, you should
10969		 * use the `stateSaveParams` event to save parameters for a plug-in.
10970		 */
10971		"fnStateSaveParams": null,
10972	
10973	
10974		/**
10975		 * Duration for which the saved state information is considered valid. After this period
10976		 * has elapsed the state will be returned to the default.
10977		 * Value is given in seconds.
10978		 */
10979		"iStateDuration": 7200,
10980	
10981	
10982		/**
10983		 * Number of rows to display on a single page when using pagination. If
10984		 * feature enabled (`lengthChange`) then the end user will be able to override
10985		 * this to a custom setting using a pop-up menu.
10986		 */
10987		"iDisplayLength": 10,
10988	
10989	
10990		/**
10991		 * Define the starting point for data display when using DataTables with
10992		 * pagination. Note that this parameter is the number of records, rather than
10993		 * the page number, so if you have 10 records per page and want to start on
10994		 * the third page, it should be "20".
10995		 */
10996		"iDisplayStart": 0,
10997	
10998	
10999		/**
11000		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
11001		 * and filtering) by adding a `tabindex` attribute to the required elements. This
11002		 * allows you to tab through the controls and press the enter key to activate them.
11003		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
11004		 * You can overrule this using this parameter if you wish. Use a value of -1 to
11005		 * disable built-in keyboard navigation.
11006		 */
11007		"iTabIndex": 0,
11008	
11009	
11010		/**
11011		 * Classes that DataTables assigns to the various components and features
11012		 * that it adds to the HTML table. This allows classes to be configured
11013		 * during initialisation in addition to through the static
11014		 * {@link DataTable.ext.oStdClasses} object).
11015		 */
11016		"oClasses": {},
11017	
11018	
11019		/**
11020		 * All strings that DataTables uses in the user interface that it creates
11021		 * are defined in this object, allowing you to modified them individually or
11022		 * completely replace them all as required.
11023		 */
11024		"oLanguage": {
11025			/**
11026			 * Strings that are used for WAI-ARIA labels and controls only (these are not
11027			 * actually visible on the page, but will be read by screenreaders, and thus
11028			 * must be internationalised as well).
11029			 */
11030			"oAria": {
11031				/**
11032				 * ARIA label that is added to the table headers when the column may be sorted
11033				 */
11034				"orderable": ": Activate to sort",
11035	
11036				/**
11037				 * ARIA label that is added to the table headers when the column is currently being sorted
11038				 */
11039				"orderableReverse": ": Activate to invert sorting",
11040	
11041				/**
11042				 * ARIA label that is added to the table headers when the column is currently being 
11043				 * sorted and next step is to remove sorting
11044				 */
11045				"orderableRemove": ": Activate to remove sorting",
11046	
11047				paginate: {
11048					first: 'First',
11049					last: 'Last',
11050					next: 'Next',
11051					previous: 'Previous',
11052					number: ''
11053				}
11054			},
11055	
11056			/**
11057			 * Pagination string used by DataTables for the built-in pagination
11058			 * control types.
11059			 */
11060			"oPaginate": {
11061				/**
11062				 * Label and character for first page button («)
11063				 */
11064				"sFirst": "\u00AB",
11065	
11066				/**
11067				 * Last page button (»)
11068				 */
11069				"sLast": "\u00BB",
11070	
11071				/**
11072				 * Next page button (›)
11073				 */
11074				"sNext": "\u203A",
11075	
11076				/**
11077				 * Previous page button (‹)
11078				 */
11079				"sPrevious": "\u2039",
11080			},
11081	
11082			/**
11083			 * Plural object for the data type the table is showing
11084			 */
11085			entries: {
11086				_: "entries",
11087				1: "entry"
11088			},
11089	
11090			/**
11091			 * Page length options
11092			 */
11093			lengthLabels: {
11094				'-1': 'All'
11095			},
11096	
11097			/**
11098			 * This string is shown in preference to `zeroRecords` when the table is
11099			 * empty of data (regardless of filtering). Note that this is an optional
11100			 * parameter - if it is not given, the value of `zeroRecords` will be used
11101			 * instead (either the default or given value).
11102			 */
11103			"sEmptyTable": "No data available in table",
11104	
11105	
11106			/**
11107			 * This string gives information to the end user about the information
11108			 * that is current on display on the page. The following tokens can be
11109			 * used in the string and will be dynamically replaced as the table
11110			 * display updates. This tokens can be placed anywhere in the string, or
11111			 * removed as needed by the language requires:
11112			 *
11113			 * * `\_START\_` - Display index of the first record on the current page
11114			 * * `\_END\_` - Display index of the last record on the current page
11115			 * * `\_TOTAL\_` - Number of records in the table after filtering
11116			 * * `\_MAX\_` - Number of records in the table without filtering
11117			 * * `\_PAGE\_` - Current page number
11118			 * * `\_PAGES\_` - Total number of pages of data in the table
11119			 */
11120			"sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
11121	
11122	
11123			/**
11124			 * Display information string for when the table is empty. Typically the
11125			 * format of this string should match `info`.
11126			 */
11127			"sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
11128	
11129	
11130			/**
11131			 * When a user filters the information in a table, this string is appended
11132			 * to the information (`info`) to give an idea of how strong the filtering
11133			 * is. The variable _MAX_ is dynamically updated.
11134			 */
11135			"sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
11136	
11137	
11138			/**
11139			 * If can be useful to append extra information to the info string at times,
11140			 * and this variable does exactly that. This information will be appended to
11141			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11142			 * being used) at all times.
11143			 */
11144			"sInfoPostFix": "",
11145	
11146	
11147			/**
11148			 * This decimal place operator is a little different from the other
11149			 * language options since DataTables doesn't output floating point
11150			 * numbers, so it won't ever use this for display of a number. Rather,
11151			 * what this parameter does is modify the sort methods of the table so
11152			 * that numbers which are in a format which has a character other than
11153			 * a period (`.`) as a decimal place will be sorted numerically.
11154			 *
11155			 * Note that numbers with different decimal places cannot be shown in
11156			 * the same table and still be sortable, the table must be consistent.
11157			 * However, multiple different tables on the page can use different
11158			 * decimal place characters.
11159			 */
11160			"sDecimal": "",
11161	
11162	
11163			/**
11164			 * DataTables has a build in number formatter (`formatNumber`) which is
11165			 * used to format large numbers that are used in the table information.
11166			 * By default a comma is used, but this can be trivially changed to any
11167			 * character you wish with this parameter.
11168			 */
11169			"sThousands": ",",
11170	
11171	
11172			/**
11173			 * Detail the action that will be taken when the drop down menu for the
11174			 * pagination length option is changed. The '_MENU_' variable is replaced
11175			 * with a default select list of 10, 25, 50 and 100, and can be replaced
11176			 * with a custom select box if required.
11177			 */
11178			"sLengthMenu": "_MENU_ _ENTRIES_ per page",
11179	
11180	
11181			/**
11182			 * When using Ajax sourced data and during the first draw when DataTables is
11183			 * gathering the data, this message is shown in an empty row in the table to
11184			 * indicate to the end user the the data is being loaded. Note that this
11185			 * parameter is not used when loading data by server-side processing, just
11186			 * Ajax sourced data with client-side processing.
11187			 */
11188			"sLoadingRecords": "Loading...",
11189	
11190	
11191			/**
11192			 * Text which is displayed when the table is processing a user action
11193			 * (usually a sort command or similar).
11194			 */
11195			"sProcessing": "",
11196	
11197	
11198			/**
11199			 * Details the actions that will be taken when the user types into the
11200			 * filtering input text box. The variable "_INPUT_", if used in the string,
11201			 * is replaced with the HTML text box for the filtering input allowing
11202			 * control over where it appears in the string. If "_INPUT_" is not given
11203			 * then the input box is appended to the string automatically.
11204			 */
11205			"sSearch": "Search:",
11206	
11207	
11208			/**
11209			 * Assign a `placeholder` attribute to the search `input` element
11210			 *  @type string
11211			 *  @default 
11212			 *
11213			 *  @dtopt Language
11214			 *  @name DataTable.defaults.language.searchPlaceholder
11215			 */
11216			"sSearchPlaceholder": "",
11217	
11218	
11219			/**
11220			 * All of the language information can be stored in a file on the
11221			 * server-side, which DataTables will look up if this parameter is passed.
11222			 * It must store the URL of the language file, which is in a JSON format,
11223			 * and the object has the same properties as the oLanguage object in the
11224			 * initialiser object (i.e. the above parameters). Please refer to one of
11225			 * the example language files to see how this works in action.
11226			 */
11227			"sUrl": "",
11228	
11229	
11230			/**
11231			 * Text shown inside the table records when the is no information to be
11232			 * displayed after filtering. `emptyTable` is shown when there is simply no
11233			 * information in the table at all (regardless of filtering).
11234			 */
11235			"sZeroRecords": "No matching records found"
11236		},
11237	
11238	
11239		/** The initial data order is reversed when `desc` ordering */
11240		orderDescReverse: true,
11241	
11242	
11243		/**
11244		 * This parameter allows you to have define the global filtering state at
11245		 * initialisation time. As an object the `search` parameter must be
11246		 * defined, but all other parameters are optional. When `regex` is true,
11247		 * the search string will be treated as a regular expression, when false
11248		 * (default) it will be treated as a straight string. When `smart`
11249		 * DataTables will use it's smart filtering methods (to word match at
11250		 * any point in the data), when false this will not be done.
11251		 */
11252		"oSearch": $.extend( {}, DataTable.models.oSearch ),
11253	
11254	
11255		/**
11256		 * Table and control layout. This replaces the legacy `dom` option.
11257		 */
11258		layout: {
11259			topStart: 'pageLength',
11260			topEnd: 'search',
11261			bottomStart: 'info',
11262			bottomEnd: 'paging'
11263		},
11264	
11265	
11266		/**
11267		 * Legacy DOM layout option
11268		 */
11269		"sDom": null,
11270	
11271	
11272		/**
11273		 * Search delay option. This will throttle full table searches that use the
11274		 * DataTables provided search input element (it does not effect calls to
11275		 * `dt-api search()`, providing a delay before the search is made.
11276		 */
11277		"searchDelay": null,
11278	
11279	
11280		/**
11281		 * DataTables features six different built-in options for the buttons to
11282		 * display for pagination control:
11283		 *
11284		 * * `numbers` - Page number buttons only
11285		 * * `simple` - 'Previous' and 'Next' buttons only
11286		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11287		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11288		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11289		 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11290		 */
11291		"sPaginationType": "",
11292	
11293	
11294		/**
11295		 * Enable horizontal scrolling. When a table is too wide to fit into a
11296		 * certain layout, or you have a large number of columns in the table, you
11297		 * can enable x-scrolling to show the table in a viewport, which can be
11298		 * scrolled. This property can be `true` which will allow the table to
11299		 * scroll horizontally when needed, or any CSS unit, or a number (in which
11300		 * case it will be treated as a pixel measurement). Setting as simply `true`
11301		 * is recommended.
11302		 */
11303		"sScrollX": "",
11304	
11305	
11306		/**
11307		 * This property can be used to force a DataTable to use more width than it
11308		 * might otherwise do when x-scrolling is enabled. For example if you have a
11309		 * table which requires to be well spaced, this parameter is useful for
11310		 * "over-sizing" the table, and thus forcing scrolling. This property can by
11311		 * any CSS unit, or a number (in which case it will be treated as a pixel
11312		 * measurement).
11313		 */
11314		"sScrollXInner": "",
11315	
11316	
11317		/**
11318		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11319		 * to the given height, and enable scrolling for any data which overflows the
11320		 * current viewport. This can be used as an alternative to paging to display
11321		 * a lot of data in a small area (although paging and scrolling can both be
11322		 * enabled at the same time). This property can be any CSS unit, or a number
11323		 * (in which case it will be treated as a pixel measurement).
11324		 */
11325		"sScrollY": "",
11326	
11327	
11328		/**
11329		 * __Deprecated__ The functionality provided by this parameter has now been
11330		 * superseded by that provided through `ajax`, which should be used instead.
11331		 *
11332		 * Set the HTTP method that is used to make the Ajax call for server-side
11333		 * processing or Ajax sourced data.
11334		 */
11335		"sServerMethod": "GET",
11336	
11337	
11338		/**
11339		 * DataTables makes use of renderers when displaying HTML elements for
11340		 * a table. These renderers can be added or modified by plug-ins to
11341		 * generate suitable mark-up for a site. For example the Bootstrap
11342		 * integration plug-in for DataTables uses a paging button renderer to
11343		 * display pagination buttons in the mark-up required by Bootstrap.
11344		 *
11345		 * For further information about the renderers available see
11346		 * DataTable.ext.renderer
11347		 */
11348		"renderer": null,
11349	
11350	
11351		/**
11352		 * Set the data property name that DataTables should use to get a row's id
11353		 * to set as the `id` property in the node.
11354		 */
11355		"rowId": "DT_RowId",
11356	
11357	
11358		/**
11359		 * Caption value
11360		 */
11361		"caption": null,
11362	
11363	
11364		/**
11365		 * For server-side processing - use the data from the DOM for the first draw
11366		 */
11367		iDeferLoading: null,
11368	
11369		/** Event listeners */
11370		on: null
11371	};
11372	
11373	_fnHungarianMap( DataTable.defaults );
11374	
11375	
11376	
11377	/*
11378	 * Developer note - See note in model.defaults.js about the use of Hungarian
11379	 * notation and camel case.
11380	 */
11381	
11382	/**
11383	 * Column options that can be given to DataTables at initialisation time.
11384	 *  @namespace
11385	 */
11386	DataTable.defaults.column = {
11387		/**
11388		 * Define which column(s) an order will occur on for this column. This
11389		 * allows a column's ordering to take multiple columns into account when
11390		 * doing a sort or use the data from a different column. For example first
11391		 * name / last name columns make sense to do a multi-column sort over the
11392		 * two columns.
11393		 */
11394		"aDataSort": null,
11395		"iDataSort": -1,
11396	
11397		ariaTitle: '',
11398	
11399	
11400		/**
11401		 * You can control the default ordering direction, and even alter the
11402		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11403		 * using this parameter.
11404		 */
11405		"asSorting": [ 'asc', 'desc', '' ],
11406	
11407	
11408		/**
11409		 * Enable or disable filtering on the data in this column.
11410		 */
11411		"bSearchable": true,
11412	
11413	
11414		/**
11415		 * Enable or disable ordering on this column.
11416		 */
11417		"bSortable": true,
11418	
11419	
11420		/**
11421		 * Enable or disable the display of this column.
11422		 */
11423		"bVisible": true,
11424	
11425	
11426		/**
11427		 * Developer definable function that is called whenever a cell is created (Ajax source,
11428		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11429		 * allowing you to modify the DOM element (add background colour for example) when the
11430		 * element is available.
11431		 */
11432		"fnCreatedCell": null,
11433	
11434	
11435		/**
11436		 * This property can be used to read data from any data source property,
11437		 * including deeply nested objects / properties. `data` can be given in a
11438		 * number of different ways which effect its behaviour:
11439		 *
11440		 * * `integer` - treated as an array index for the data source. This is the
11441		 *   default that DataTables uses (incrementally increased for each column).
11442		 * * `string` - read an object property from the data source. There are
11443		 *   three 'special' options that can be used in the string to alter how
11444		 *   DataTables reads the data from the source object:
11445		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
11446		 *      Javascript to read from nested objects, so to can the options
11447		 *      specified in `data`. For example: `browser.version` or
11448		 *      `browser.name`. If your object parameter name contains a period, use
11449		 *      `\\` to escape it - i.e. `first\\.name`.
11450		 *    * `[]` - Array notation. DataTables can automatically combine data
11451		 *      from and array source, joining the data with the characters provided
11452		 *      between the two brackets. For example: `name[, ]` would provide a
11453		 *      comma-space separated list from the source array. If no characters
11454		 *      are provided between the brackets, the original array source is
11455		 *      returned.
11456		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
11457		 *      execute a function of the name given. For example: `browser()` for a
11458		 *      simple function on the data source, `browser.version()` for a
11459		 *      function in a nested property or even `browser().version` to get an
11460		 *      object property if the function called returns an object. Note that
11461		 *      function notation is recommended for use in `render` rather than
11462		 *      `data` as it is much simpler to use as a renderer.
11463		 * * `null` - use the original data source for the row rather than plucking
11464		 *   data directly from it. This action has effects on two other
11465		 *   initialisation options:
11466		 *    * `defaultContent` - When null is given as the `data` option and
11467		 *      `defaultContent` is specified for the column, the value defined by
11468		 *      `defaultContent` will be used for the cell.
11469		 *    * `render` - When null is used for the `data` option and the `render`
11470		 *      option is specified for the column, the whole data source for the
11471		 *      row is used for the renderer.
11472		 * * `function` - the function given will be executed whenever DataTables
11473		 *   needs to set or get the data for a cell in the column. The function
11474		 *   takes three parameters:
11475		 *    * Parameters:
11476		 *      * `{array|object}` The data source for the row
11477		 *      * `{string}` The type call data requested - this will be 'set' when
11478		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
11479		 *        when gathering data. Note that when `undefined` is given for the
11480		 *        type DataTables expects to get the raw data for the object back<
11481		 *      * `{*}` Data to set when the second parameter is 'set'.
11482		 *    * Return:
11483		 *      * The return value from the function is not required when '
11483set' is
11484		 *        the type of call, but otherwise the return is what will be used
11485		 *        for the data requested.
11486		 *
11487		 * Note that `data` is a getter and setter option. If you just require
11488		 * formatting of data for output, you will likely want to use `render` which
11489		 * is simply a getter and thus simpler to use.
11490		 *
11491		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
11492		 * name change reflects the flexibility of this property and is consistent
11493		 * with the naming of mRender. If 'mDataProp' is given, then it will still
11494		 * be used by DataTables, as it automatically maps the old name to the new
11495		 * if required.
11496		 */
11497		"mData": null,
11498	
11499	
11500		/**
11501		 * This property is the rendering partner to `data` and it is suggested that
11502		 * when you want to manipulate data for display (including filtering,
11503		 * sorting etc) without altering the underlying data for the table, use this
11504		 * property. `render` can be considered to be the the read only companion to
11505		 * `data` which is read / write (then as such more complex). Like `data`
11506		 * this option can be given in a number of different ways to effect its
11507		 * behaviour:
11508		 *
11509		 * * `integer` - treated as an array index for the data source. This is the
11510		 *   default that DataTables uses (incrementally increased for each column).
11511		 * * `string` - read an object property from the data source. There are
11512		 *   three 'special' options that can be used in the string to alter how
11513		 *   DataTables reads the data from the source object:
11514		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
11515		 *      Javascript to read from nested objects, so to can the options
11516		 *      specified in `data`. For example: `browser.version` or
11517		 *      `browser.name`. If your object parameter name contains a period, use
11518		 *      `\\` to escape it - i.e. `first\\.name`.
11519		 *    * `[]` - Array notation. DataTables can automatically combine data
11520		 *      from and array source, joining the data with the characters provided
11521		 *      between the two brackets. For example: `name[, ]` would provide a
11522		 *      comma-space separated list from the source array. If no characters
11523		 *      are provided between the brackets, the original array source is
11524		 *      returned.
11525		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
11526		 *      execute a function of the name given. For example: `browser()` for a
11527		 *      simple function on the data source, `browser.version()` for a
11528		 *      function in a nested property or even `browser().version` to get an
11529		 *      object property if the function called returns an object.
11530		 * * `object` - use different data for the different data types requested by
11531		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
11532		 *   of the object is the data type the property refers to and the value can
11533		 *   defined using an integer, string or function using the same rules as
11534		 *   `render` normally does. Note that an `_` option _must_ be specified.
11535		 *   This is the default value to use if you haven't specified a value for
11536		 *   the data type requested by DataTables.
11537		 * * `function` - the function given will be executed whenever DataTables
11538		 *   needs to set or get the data for a cell in the column. The function
11539		 *   takes three parameters:
11540		 *    * Parameters:
11541		 *      * {array|object} The data source for the row (based on `data`)
11542		 *      * {string} The type call data requested - this will be 'filter',
11543		 *        'display', 'type' or 'sort'.
11544		 *      * {array|object} The full data source for the row (not based on
11545		 *        `data`)
11546		 *    * Return:
11547		 *      * The return value from the function is what will be used for the
11548		 *        data requested.
11549		 */
11550		"mRender": null,
11551	
11552	
11553		/**
11554		 * Change the cell type created for the column - either TD cells or TH cells. This
11555		 * can be useful as TH cells have semantic meaning in the table body, allowing them
11556		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
11557		 */
11558		"sCellType": "td",
11559	
11560	
11561		/**
11562		 * Class to give to each cell in this column.
11563		 */
11564		"sClass": "",
11565	
11566		/**
11567		 * When DataTables calculates the column widths to assign to each column,
11568		 * it finds the longest string in each column and then constructs a
11569		 * temporary table and reads the widths from that. The problem with this
11570		 * is that "mmm" is much wider then "iiii", but the latter is a longer
11571		 * string - thus the calculation can go wrong (doing it properly and putting
11572		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
11573		 * a "work around" we provide this option. It will append its value to the
11574		 * text that is found to be the longest string for the column - i.e. padding.
11575		 * Generally you shouldn't need this!
11576		 */
11577		"sContentPadding": "",
11578	
11579	
11580		/**
11581		 * Allows a default value to be given for a column's data, and will be used
11582		 * whenever a null data source is encountered (this can be because `data`
11583		 * is set to null, or because the data source itself is null).
11584		 */
11585		"sDefaultContent": null,
11586	
11587	
11588		/**
11589		 * This parameter is only used in DataTables' server-side processing. It can
11590		 * be exceptionally useful to know what columns are being displayed on the
11591		 * client side, and to map these to database fields. When defined, the names
11592		 * also allow DataTables to reorder information from the server if it comes
11593		 * back in an unexpected order (i.e. if you switch your columns around on the
11594		 * client-side, your server-side code does not also need updating).
11595		 */
11596		"sName": "",
11597	
11598	
11599		/**
11600		 * Defines a data source type for the ordering which can be used to read
11601		 * real-time information from the table (updating the internally cached
11602		 * version) prior to ordering. This allows ordering to occur on user
11603		 * editable elements such as form inputs.
11604		 */
11605		"sSortDataType": "std",
11606	
11607	
11608		/**
11609		 * The title of this column.
11610		 */
11611		"sTitle": null,
11612	
11613	
11614		/**
11615		 * The type allows you to specify how the data for this column will be
11616		 * ordered. Four types (string, numeric, date and html (which will strip
11617		 * HTML tags before ordering)) are currently available. Note that only date
11618		 * formats understood by Javascript's Date() object will be accepted as type
11619		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
11620		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
11621		 * through plug-ins.
11622		 */
11623		"sType": null,
11624	
11625	
11626		/**
11627		 * Defining the width of the column, this parameter may take any CSS value
11628		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
11629		 * been given a specific width through this interface ensuring that the table
11630		 * remains readable.
11631		 */
11632		"sWidth": null
11633	};
11634	
11635	_fnHungarianMap( DataTable.defaults.column );
11636	
11637	
11638	
11639	/**
11640	 * DataTables settings object - this holds all the information needed for a
11641	 * given table, including configuration, data and current application of the
11642	 * table options. DataTables does not have a single instance for each DataTable
11643	 * with the settings attached to that instance, but rather instances of the
11644	 * DataTable "class" are created on-the-fly as needed (typically by a
11645	 * $().dataTable() call) and the settings object is then applied to that
11646	 * instance.
11647	 *
11648	 * Note that this object is related to {@link DataTable.defaults} but this
11649	 * one is the internal data store for DataTables's cache of columns. It should
11650	 * NOT be manipulated outside of DataTables. Any configuration should be done
11651	 * through the initialisation options.
11652	 */
11653	DataTable.models.oSettings = {
11654		/**
11655		 * Primary features of DataTables and their enablement state.
11656		 */
11657		"oFeatures": {
11658	
11659			/**
11660			 * Flag to say if DataTables should automatically try to calculate the
11661			 * optimum table and columns widths (true) or not (false).
11662			 * Note that this parameter will be set by the initialisation routine. To
11663			 * set a default use {@link DataTable.defaults}.
11664			 */
11665			"bAutoWidth": null,
11666	
11667			/**
11668			 * Delay the creation of TR and TD elements until they are actually
11669			 * needed by a driven page draw. This can give a significant speed
11670			 * increase for Ajax source and Javascript source data, but makes no
11671			 * difference at all for DOM and server-side processing tables.
11672			 * Note that this parameter will be set by the initialisation routine. To
11673			 * set a default use {@link DataTable.defaults}.
11674			 */
11675			"bDeferRender": null,
11676	
11677			/**
11678			 * Enable filtering on the table or not. Note that if this is disabled
11679			 * then there is no filtering at all on the table, including fnFilter.
11680			 * To just remove the filtering input use sDom and remove the 'f' option.
11681			 * Note that this parameter will be set by the initialisation routine. To
11682			 * set a default use {@link DataTable.defaults}.
11683			 */
11684			"bFilter": null,
11685	
11686			/**
11687			 * Used only for compatiblity with DT1
11688			 * @deprecated
11689			 */
11690			"bInfo": true,
11691	
11692			/**
11693			 * Used only for compatiblity with DT1
11694			 * @deprecated
11695			 */
11696			"bLengthChange": true,
11697	
11698			/**
11699			 * Pagination enabled or not. Note that if this is disabled then length
11700			 * changing must also be disabled.
11701			 * Note that this parameter will be set by the initialisation routine. To
11702			 * set a default use {@link DataTable.defaults}.
11703			 */
11704			"bPaginate": null,
11705	
11706			/**
11707			 * Processing indicator enable flag whenever DataTables is enacting a
11708			 * user request - typically an Ajax request for server-side processing.
11709			 * Note that this parameter will be set by the initialisation routine. To
11710			 * set a default use {@link DataTable.defaults}.
11711			 */
11712			"bProcessing": null,
11713	
11714			/**
11715			 * Server-side processing enabled flag - when enabled DataTables will
11716			 * get all data from the server for every draw - there is no filtering,
11717			 * sorting or paging done on the client-side.
11718			 * Note that this parameter will be set by the initialisation routine. To
11719			 * set a default use {@link DataTable.defaults}.
11720			 */
11721			"bServerSide": null,
11722	
11723			/**
11724			 * Sorting enablement flag.
11725			 * Note that this parameter will be set by the initialisation routine. To
11726			 * set a default use {@link DataTable.defaults}.
11727			 */
11728			"bSort": null,
11729	
11730			/**
11731			 * Multi-column sorting
11732			 * Note that this parameter will be set by the initialisation routine. To
11733			 * set a default use {@link DataTable.defaults}.
11734			 */
11735			"bSortMulti": null,
11736	
11737			/**
11738			 * Apply a class to the columns which are being sorted to provide a
11739			 * visual highlight or not. This can slow things down when enabled since
11740			 * there is a lot of DOM interaction.
11741			 * Note that this parameter will be set by the initialisation routine. To
11742			 * set a default use {@link DataTable.defaults}.
11743			 */
11744			"bSortClasses": null,
11745	
11746			/**
11747			 * State saving enablement flag.
11748			 * Note that this parameter will be set by the initialisation routine. To
11749			 * set a default use {@link DataTable.defaults}.
11750			 */
11751			"bStateSave": null
11752		},
11753	
11754	
11755		/**
11756		 * Scrolling settings for a table.
11757		 */
11758		"oScroll": {
11759			/**
11760			 * When the table is shorter in height than sScrollY, collapse the
11761			 * table container down to the height of the table (when true).
11762			 * Note that this parameter will be set by the initialisation routine. To
11763			 * set a default use {@link DataTable.defaults}.
11764			 */
11765			"bCollapse": null,
11766	
11767			/**
11768			 * Width of the scrollbar for the web-browser's platform. Calculated
11769			 * during table initialisation.
11770			 */
11771			"iBarWidth": 0,
11772	
11773			/**
11774			 * Viewport width for horizontal scrolling. Horizontal scrolling is
11775			 * disabled if an empty string.
11776			 * Note that this parameter will be set by the initialisation routine. To
11777			 * set a default use {@link DataTable.defaults}.
11778			 */
11779			"sX": null,
11780	
11781			/**
11782			 * Width to expand the table to when using x-scrolling. Typically you
11783			 * should not need to use this.
11784			 * Note that this parameter will be set by the initialisation routine. To
11785			 * set a default use {@link DataTable.defaults}.
11786			 *  @deprecated
11787			 */
11788			"sXInner": null,
11789	
11790			/**
11791			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
11792			 * if an empty string.
11793			 * Note that this parameter will be set by the initialisation routine. To
11794			 * set a default use {@link DataTable.defaults}.
11795			 */
11796			"sY": null
11797		},
11798	
11799		/**
11800		 * Language information for the table.
11801		 */
11802		"oLanguage": {
11803			/**
11804			 * Information callback function. See
11805			 * {@link DataTable.defaults.fnInfoCallback}
11806			 */
11807			"fnInfoCallback": null
11808		},
11809	
11810		/**
11811		 * Browser support parameters
11812		 */
11813		"oBrowser": {
11814			/**
11815			 * Determine if the vertical scrollbar is on the right or left of the
11816			 * scrolling container - needed for rtl language layout, although not
11817			 * all browsers move the scrollbar (Safari).
11818			 */
11819			"bScrollbarLeft": false,
11820	
11821			/**
11822			 * Browser scrollbar width
11823			 */
11824			"barWidth": 0
11825		},
11826	
11827	
11828		"ajax": null,
11829	
11830	
11831		/**
11832		 * Array referencing the nodes which are used for the features. The
11833		 * parameters of this object match what is allowed by sDom - i.e.
11834		 *   <ul>
11835		 *     <li>'l' - Length changing</li>
11836		 *     <li>'f' - Filtering input</li>
11837		 *     <li>'t' - The table!</li>
11838		 *     <li>'i' - Information</li>
11839		 *     <li>'p' - Pagination</li>
11840		 *     <li>'r' - pRocessing</li>
11841		 *   </ul>
11842		 */
11843		"aanFeatures": [],
11844	
11845		/**
11846		 * Store data information - see {@link DataTable.models.oRow} for detailed
11847		 * information.
11848		 */
11849		"aoData": [],
11850	
11851		/**
11852		 * Array of indexes which are in the current display (after filtering etc)
11853		 */
11854		"aiDisplay": [],
11855	
11856		/**
11857		 * Array of indexes for display - no filtering
11858		 */
11859		"aiDisplayMaster": [],
11860	
11861		/**
11862		 * Map of row ids to data indexes
11863		 */
11864		"aIds": {},
11865	
11866		/**
11867		 * Store information about each column that is in use
11868		 */
11869		"aoColumns": [],
11870	
11871		/**
11872		 * Store information about the table's header
11873		 */
11874		"aoHeader": [],
11875	
11876		/**
11877		 * Store information about the table's footer
11878		 */
11879		"aoFooter": [],
11880	
11881		/**
11882		 * Store the applied global search information in case we want to force a
11883		 * research or compare the old search to a new one.
11884		 * Note that this parameter will be set by the initialisation routine. To
11885		 * set a default use {@link DataTable.defaults}.
11886		 */
11887		"oPreviousSearch": {},
11888	
11889		/**
11890		 * Store for named searches
11891		 */
11892		searchFixed: {},
11893	
11894		/**
11895		 * Store the applied search for each column - see
11896		 * {@link DataTable.models.oSearch} for the format that is used for the
11897		 * filtering information for each column.
11898		 */
11899		"aoPreSearchCols": [],
11900	
11901		/**
11902		 * Sorting that is applied to the table. Note that the inner arrays are
11903		 * used in the following manner:
11904		 * <ul>
11905		 *   <li>Index 0 - column number</li>
11906		 *   <li>Index 1 - current sorting direction</li>
11907		 * </ul>
11908		 * Note that this parameter will be set by the initialisation routine. To
11909		 * set a default use {@link DataTable.defaults}.
11910		 */
11911		"aaSorting": null,
11912	
11913		/**
11914		 * Sorting that is always applied to the table (i.e. prefixed in front of
11915		 * aaSorting).
11916		 * Note that this parameter will be set by the initialisation routine. To
11917		 * set a default use {@link DataTable.defaults}.
11918		 */
11919		"aaSortingFixed": [],
11920	
11921		/**
11922		 * If restoring a table - we should restore its width
11923		 */
11924		"sDestroyWidth": 0,
11925	
11926		/**
11927		 * Callback functions array for every time a row is inserted (i.e. on a draw).
11928		 */
11929		"aoRowCallback": [],
11930	
11931		/**
11932		 * Callback functions for the header on each draw.
11933		 */
11934		"aoHeaderCallback": [],
11935	
11936		/**
11937		 * Callback function for the footer on each draw.
11938		 */
11939		"aoFooterCallback": [],
11940	
11941		/**
11942		 * Array of callback functions for draw callback functions
11943		 */
11944		"aoDrawCallback": [],
11945	
11946		/**
11947		 * Array of callback functions for row created function
11948		 */
11949		"aoRowCreatedCallback": [],
11950	
11951		/**
11952		 * Callback functions for just before the table is redrawn. A return of
11953		 * false will be used to cancel the draw.
11954		 */
11955		"aoPreDrawCallback": [],
11956	
11957		/**
11958		 * Callback functions for when the table has been initialised.
11959		 */
11960		"aoInitComplete": [],
11961	
11962	
11963		/**
11964		 * Callbacks for modifying the settings to be stored for state saving, prior to
11965		 * saving state.
11966		 */
11967		"aoStateSaveParams": [],
11968	
11969		/**
11970		 * Callbacks for modifying the settings that have been stored for state saving
11971		 * prior to using the stored values to restore the state.
11972		 */
11973		"aoStateLoadParams": [],
11974	
11975		/**
11976		 * Callbacks for operating on the settings object once the saved state has been
11977		 * loaded
11978		 */
11979		"aoStateLoaded": [],
11980	
11981		/**
11982		 * Cache the table ID for quick access
11983		 */
11984		"sTableId": "",
11985	
11986		/**
11987		 * The TABLE node for the main table
11988		 */
11989		"nTable": null,
11990	
11991		/**
11992		 * Permanent ref to the thead element
11993		 */
11994		"nTHead": null,
11995	
11996		/**
11997		 * Permanent ref to the tfoot element - if it exists
11998		 */
11999		"nTFoot": null,
12000	
12001		/**
12002		 * Permanent ref to the tbody element
12003		 */
12004		"nTBody": null,
12005	
12006		/**
12007		 * Cache the wrapper node (contains all DataTables controlled elements)
12008		 */
12009		"nTableWrapper": null,
12010	
12011		/**
12012		 * Indicate if all required information has been read in
12013		 */
12014		"bInitialised": false,
12015	
12016		/**
12017		 * Information about open rows. Each object in the array has the parameters
12018		 * 'nTr' and 'nParent'
12019		 */
12020		"aoOpenRows": [],
12021	
12022		/**
12023		 * Dictate the positioning of DataTables' control elements - see
12024		 * {@link DataTable.model.oInit.sDom}.
12025		 * Note that this parameter will be set by the initialisation routine. To
12026		 * set a default use {@link DataTable.defaults}.
12027		 */
12028		"sDom": null,
12029	
12030		/**
12031		 * Search delay (in mS)
12032		 */
12033		"searchDelay": null,
12034	
12035		/**
12036		 * Which type of pagination should be used.
12037		 * Note that this parameter will be set by the initialisation routine. To
12038		 * set a default use {@link DataTable.defaults}.
12039		 */
12040		"sPaginationType": "two_button",
12041	
12042		/**
12043		 * Number of paging controls on the page. Only used for backwards compatibility
12044		 */
12045		pagingControls: 0,
12046	
12047		/**
12048		 * The state duration (for `stateSave`) in seconds.
12049		 * Note that this parameter will be set by the initialisation routine. To
12050		 * set a default use {@link DataTable.defaults}.
12051		 */
12052		"iStateDuration": 0,
12053	
12054		/**
12055		 * Array of callback functions for state saving. Each array element is an
12056		 * object with the following parameters:
12057		 *   <ul>
12058		 *     <li>function:fn - function to call. Takes two parameters, oSettings
12059		 *       and the JSON string to save that has been thus far created. Returns
12060		 *       a JSON string to be inserted into a json object
12061		 *       (i.e. '"param": [ 0, 1, 2]')</li>
12062		 *     <li>string:sName - name of callback</li>
12063		 *   </ul>
12064		 */
12065		"aoStateSave": [],
12066	
12067		/**
12068		 * Array of callback functions for state loading. Each array element is an
12069		 * object with the following parameters:
12070		 *   <ul>
12071		 *     <li>function:fn - function to call. Takes two parameters, oSettings
12072		 *       and the object stored. May return false to cancel state loading</li>
12073		 *     <li>string:sName - name of callback</li>
12074		 *   </ul>
12075		 */
12076		"aoStateLoad": [],
12077	
12078		/**
12079		 * State that was saved. Useful for back reference
12080		 */
12081		"oSavedState": null,
12082	
12083		/**
12084		 * State that was loaded. Useful for back reference
12085		 */
12086		"oLoadedState": null,
12087	
12088		/**
12089		 * Note if draw should be blocked while getting data
12090		 */
12091		"bAjaxDataGet": true,
12092	
12093		/**
12094		 * The last jQuery XHR object that was used for server-side data gathering.
12095		 * This can be used for working with the XHR information in one of the
12096		 * callbacks
12097		 */
12098		"jqXHR": null,
12099	
12100		/**
12101		 * JSON returned from the server in the last Ajax request
12102		 */
12103		"json": undefined,
12104	
12105		/**
12106		 * Data submitted as part of the last Ajax request
12107		 */
12108		"oAjaxData": undefined,
12109	
12110		/**
12111		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
12112		 * required).
12113		 * Note that this parameter will be set by the initialisation routine. To
12114		 * set a default use {@link DataTable.defaults}.
12115		 */
12116		"sServerMethod": null,
12117	
12118		/**
12119		 * Format numbers for display.
12120		 * Note that this parameter will be set by the initialisation routine. To
12121		 * set a default use {@link DataTable.defaults}.
12122		 */
12123		"fnFormatNumber": null,
12124	
12125		/**
12126		 * List of options that can be used for the user selectable length menu.
12127		 * Note that this parameter will be set by the initialisation routine. To
12128		 * set a default use {@link DataTable.defaults}.
12129		 */
12130		"aLengthMenu": null,
12131	
12132		/**
12133		 * Counter for the draws that the table does. Also used as a tracker for
12134		 * server-side processing
12135		 */
12136		"iDraw": 0,
12137	
12138		/**
12139		 * Indicate if a redraw is being done - useful for Ajax
12140		 */
12141		"bDrawing": false,
12142	
12143		/**
12144		 * Draw index (iDraw) of the last error when parsing the returned data
12145		 */
12146		"iDrawError": -1,
12147	
12148		/**
12149		 * Paging display length
12150		 */
12151		"_iDisplayLength": 10,
12152	
12153		/**
12154		 * Paging start point - aiDisplay index
12155		 */
12156		"_iDisplayStart": 0,
12157	
12158		/**
12159		 * Server-side processing - number of records in the result set
12160		 * (i.e. before filtering), Use fnRecordsTotal rather than
12161		 * this property to get the value of the number of records, regardless of
12162		 * the server-side processing setting.
12163		 */
12164		"_iRecordsTotal": 0,
12165	
12166		/**
12167		 * Server-side processing - number of records in the current display set
12168		 * (i.e. after filtering). Use fnRecordsDisplay rather than
12169		 * this property to get the value of the number of records, regardless of
12170		 * the server-side processing setting.
12171		 */
12172		"_iRecordsDisplay": 0,
12173	
12174		/**
12175		 * The classes to use for the table
12176		 */
12177		"oClasses": {},
12178	
12179		/**
12180		 * Flag attached to the settings object so you can check in the draw
12181		 * callback if filtering has been done in the draw. Deprecated in favour of
12182		 * events.
12183		 *  @deprecated
12184		 */
12185		"bFiltered": false,
12186	
12187		/**
12188		 * Flag attached to the settings object so you can check in the draw
12189		 * callback if sorting has been done in the draw. Deprecated in favour of
12190		 * events.
12191		 *  @deprecated
12192		 */
12193		"bSorted": false,
12194	
12195		/**
12196		 * Indicate that if multiple rows are in the header and there is more than
12197		 * one unique cell per column. Replaced by titleRow
12198		 */
12199		"bSortCellsTop": null,
12200	
12201		/**
12202		 * Initialisation object that is used for the table
12203		 */
12204		"oInit": null,
12205	
12206		/**
12207		 * Destroy callback functions - for plug-ins to attach themselves to the
12208		 * destroy so they can clean up markup and events.
12209		 */
12210		"aoDestroyCallback": [],
12211	
12212	
12213		/**
12214		 * Get the number of records in the current record set, before filtering
12215		 */
12216		"fnRecordsTotal": function ()
12217		{
12218			return _fnDataSource( this ) == 'ssp' ?
12219				this._iRecordsTotal * 1 :
12220				this.aiDisplayMaster.length;
12221		},
12222	
12223		/**
12224		 * Get the number of records in the current record set, after filtering
12225		 */
12226		"fnRecordsDisplay": function ()
12227		{
12228			return _fnDataSource( this ) == 'ssp' ?
12229				this._iRecordsDisplay * 1 :
12230				this.aiDisplay.length;
12231		},
12232	
12233		/**
12234		 * Get the display end point - aiDisplay index
12235		 */
12236		"fnDisplayEnd": function ()
12237		{
12238			var
12239				len      = this._iDisplayLength,
12240				start    = this._iDisplayStart,
12241				calc     = start + len,
12242				records  = this.aiDisplay.length,
12243				features = this.oFeatures,
12244				paginate = features.bPaginate;
12245	
12246			if ( features.bServerSide ) {
12247				return paginate === false || len === -1 ?
12248					start + records :
12249					Math.min( start+len, this._iRecordsDisplay );
12250			}
12251			else {
12252				return ! paginate || calc>records || len===-1 ?
12253					records :
12254					calc;
12255			}
12256		},
12257	
12258		/**
12259		 * The DataTables object for this table
12260		 */
12261		"oInstance": null,
12262	
12263		/**
12264		 * Unique identifier for each instance of the DataTables object. If there
12265		 * is an ID on the table node, then it takes that value, otherwise an
12266		 * incrementing internal counter is used.
12267		 */
12268		"sInstance": null,
12269	
12270		/**
12271		 * tabindex attribute value that is added to DataTables control elements, allowing
12272		 * keyboard navigation of the table and its controls.
12273		 */
12274		"iTabIndex": 0,
12275	
12276		/**
12277		 * DIV container for the footer scrolling table if scrolling
12278		 */
12279		"nScrollHead": null,
12280	
12281		/**
12282		 * DIV container for the footer scrolling table if scrolling
12283		 */
12284		"nScrollFoot": null,
12285	
12286		/**
12287		 * Last applied sort
12288		 */
12289		"aLastSort": [],
12290	
12291		/**
12292		 * Stored plug-in instances
12293		 */
12294		"oPlugins": {},
12295	
12296		/**
12297		 * Function used to get a row's id from the row's data
12298		 */
12299		"rowIdFn": null,
12300	
12301		/**
12302		 * Data location where to store a row's id
12303		 */
12304		"rowId": null,
12305	
12306		caption: '',
12307	
12308		captionNode: null,
12309	
12310		colgroup: null,
12311	
12312		/** Delay loading of data */
12313		deferLoading: null,
12314	
12315		/** Allow auto type detection */
12316		typeDetect: true,
12317	
12318		/** ResizeObserver for the container div */
12319		resizeObserver: null,
12320	
12321		/** Keep a record of the last size of the container, so we can skip duplicates */
12322		containerWidth: -1,
12323	
12324		/** Reverse the initial order of the data set on desc ordering */
12325		orderDescReverse: null,
12326	
12327		/** Show / hide ordering indicators in headers */
12328		orderIndicators: true,
12329	
12330		/** Default ordering listener */
12331		orderHandler: true,
12332	
12333		/** Title row indicator */
12334		titleRow: null
12335	};
12336	
12337	/**
12338	 * Extension object for DataTables that is used to provide all extension
12339	 * options.
12340	 *
12341	 * Note that the `DataTable.ext` object is available through
12342	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
12343	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
12344	 *  @namespace
12345	 *  @extends DataTable.models.ext
12346	 */
12347	
12348	
12349	var extPagination = DataTable.ext.pager;
12350	
12351	// Paging buttons configuration
12352	$.extend( extPagination, {
12353		simple: function () {
12354			return [ 'previous', 'next' ];
12355		},
12356	
12357		full: function () {
12358			return [ 'first', 'previous', 'next', 'last' ];
12359		},
12360	
12361		numbers: function () {
12362			return [ 'numbers' ];
12363		},
12364	
12365		simple_numbers: function () {
12366			return [ 'previous', 'numbers', 'next' ];
12367		},
12368	
12369		full_numbers: function () {
12370			return [ 'first', 'previous', 'numbers', 'next', 'last' ];
12371		},
12372	
12373		first_last: function () {
12374			return ['first', 'last'];
12375		},
12376	
12377		first_last_numbers: function () {
12378			return ['first', 'numbers', 'last'];
12379		},
12380	
12381		// For testing and plug-ins to use
12382		_numbers: _pagingNumbers,
12383	
12384		// Number of number buttons - legacy, use `numbers` option for paging feature
12385		numbers_length: 7
12386	} );
12387	
12388	
12389	$.extend( true, DataTable.ext.renderer, {
12390		pagingButton: {
12391			_: function (settings, buttonType, content, active, disabled) {
12392				var classes = settings.oClasses.paging;
12393				var btnClasses = [classes.button];
12394				var btn;
12395	
12396				if (active) {
12397					btnClasses.push(classes.active);
12398				}
12399	
12400				if (disabled) {
12401					btnClasses.push(classes.disabled)
12402				}
12403	
12404				if (buttonType === 'ellipsis') {
12405					btn = $('<span class="ellipsis"></span>').html(content)[0];
12406				}
12407				else {
12408					btn = $('<button>', {
12409						class: btnClasses.join(' '),
12410						role: 'link',
12411						type: 'button'
12412					}).html(content);
12413				}
12414	
12415				return {
12416					display: btn,
12417					clicker: btn
12418				}
12419			}
12420		},
12421	
12422		pagingContainer: {
12423			_: function (settings, buttons) {
12424				// No wrapping element - just append directly to the host
12425				return buttons;
12426			}
12427		}
12428	} );
12429	
12430	// Common function to remove new lines, strip HTML and diacritic control
12431	var _filterString = function (stripHtml, normalize) {
12432		return function (str) {
12433			if (_empty(str) || typeof str !== 'string') {
12434				return str;
12435			}
12436	
12437			str = str.replace( _re_new_lines, " " );
12438	
12439			if (stripHtml) {
12440				str = _stripHtml(str);
12441			}
12442	
12443			if (normalize) {
12444				str = _normalize(str, false);
12445			}
12446	
12447			return str;
12448		};
12449	}
12450	
12451	/*
12452	 * Public helper functions. These aren't used internally by DataTables, or
12453	 * called by any of the options passed into DataTables, but they can be used
12454	 * externally by developers working with DataTables. They are helper functions
12455	 * to make working with DataTables a little bit easier.
12456	 */
12457	
12458	/**
12459	 * Common logic for moment, luxon or a date action.
12460	 *
12461	 * Happens after __mldObj, so don't need to call `resolveWindowsLibs` again
12462	 */
12463	function __mld( dtLib, momentFn, luxonFn, dateFn, arg1 ) {
12464		if (__moment) {
12465			return dtLib[momentFn]( arg1 );
12466		}
12467		else if (__luxon) {
12468			return dtLib[luxonFn]( arg1 );
12469		}
12470		
12471		return dateFn ? dtLib[dateFn]( arg1 ) : dtLib;
12472	}
12473	
12474	
12475	var __mlWarning = false;
12476	var __luxon; // Can be assigned in DateTable.use()
12477	var __moment; // Can be assigned in DateTable.use()
12478	
12479	/**
12480	 * 
12481	 */
12482	function resolveWindowLibs() {
12483		if (window.luxon && ! __luxon) {
12484			__luxon = window.luxon;
12485		}
12486		
12487		if (window.moment && ! __moment) {
12488			__moment = window.moment;
12489		}
12490	}
12491	
12492	function __mldObj (d, format, locale) {
12493		var dt;
12494	
12495		resolveWindowLibs();
12496	
12497		if (__moment) {
12498			dt = __moment.utc( d, format, locale, true );
12499	
12500			if (! dt.isValid()) {
12501				return null;
12502			}
12503		}
12504		else if (__luxon) {
12505			dt = format && typeof d === 'string'
12506				? __luxon.DateTime.fromFormat( d, format )
12507				: __luxon.DateTime.fromISO( d );
12508	
12509			if (! dt.isValid) {
12510				return null;
12511			}
12512	
12513			dt = dt.setLocale(locale);
12514		}
12515		else if (! format) {
12516			// No format given, must be ISO
12517			dt = new Date(d);
12518		}
12519		else {
12520			if (! __mlWarning) {
12521				alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
12522			}
12523	
12524			__mlWarning = true;
12525		}
12526	
12527		return dt;
12528	}
12529	
12530	// Wrapper for date, datetime and time which all operate the same way with the exception of
12531	// the output string for auto locale support
12532	function __mlHelper (localeString) {
12533		return function ( from, to, locale, def ) {
12534			// Luxon and Moment support
12535			// Argument shifting
12536			if ( arguments.length === 0 ) {
12537				locale = 'en';
12538				to = null; // means toLocaleString
12539				from = null; // means iso8601
12540			}
12541			else if ( arguments.length === 1 ) {
12542				locale = 'en';
12543				to = from;
12544				from = null;
12545			}
12546			else if ( arguments.length === 2 ) {
12547				locale = to;
12548				to = from;
12549				from = null;
12550			}
12551	
12552			var typeName = 'datetime' + (to ? '-' + to : '');
12553	
12554			// Add type detection and sorting specific to this date format - we need to be able to identify
12555			// date type columns as such, rather than as numbers in extensions. Hence the need for this.
12556			if (! DataTable.ext.type.order[typeName + '-pre']) {
12557				DataTable.type(typeName, {
12558					detect: function (d) {
12559						// The renderer will give the value to type detect as the type!
12560						return d === typeName ? typeName : false;
12561					},
12562					order: {
12563						pre: function (d) {
12564							// The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
12565							// `valueOf` which gives milliseconds epoch
12566							return d.valueOf();
12567						}
12568					},
12569					className: 'dt-right'
12570				});
12571			}
12572		
12573			return function ( d, type ) {
12574				// Allow for a default value
12575				if (d === null || d === undefined) {
12576					if (def === '--now') {
12577						// We treat everything as UTC further down, so no changes are
12578						// made, as such need to get the local date / time as if it were
12579						// UTC
12580						var local = new Date();
12581						d = new Date( Date.UTC(
12582							local.getFullYear(), local.getMonth(), local.getDate(),
12583							local.getHours(), local.getMinutes(), local.getSeconds()
12584						) );
12585					}
12586					else {
12587						d = '';
12588					}
12589				}
12590	
12591				if (type === 'type') {
12592					// Typing uses the type name for fast matching
12593					return typeName;
12594				}
12595	
12596				if (d === '') {
12597					return type !== 'sort'
12598						? ''
12599						: __mldObj('0000-01-01 00:00:00', null, locale);
12600				}
12601	
12602				// Shortcut. If `from` and `to` are the same, we are using the renderer to
12603				// format for ordering, not display - its already in the display format.
12604				if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) {
12605					return d;
12606				}
12607	
12608				var dt = __mldObj(d, from, locale);
12609	
12610				if (dt === null) {
12611					return d;
12612				}
12613	
12614				if (type === 'sort') {
12615					return dt;
12616				}
12617				
12618				var formatted = to === null
12619					? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
12620					: __mld(dt, 'format', 'toFormat', 'toISOString', to);
12621	
12622				// XSS protection
12623				return type === 'display' ?
12624					_escapeHtml( formatted ) :
12625					formatted;
12626			};
12627		}
12628	}
12629	
12630	// Based on locale, determine standard number formatting
12631	// Fallback for legacy browsers is US English
12632	var __thousands = ',';
12633	var __decimal = '.';
12634	
12635	if (window.Intl !== undefined) {
12636		try {
12637			var num = new Intl.NumberFormat().formatToParts(100000.1);
12638		
12639			for (var i=0 ; i<num.length ; i++) {
12640				if (num[i].type === 'group') {
12641					__thousands = num[i].value;
12642				}
12643				else if (num[i].type === 'decimal') {
12644					__decimal = num[i].value;
12645				}
12646			}
12647		}
12648		catch (e) {
12649			// noop
12650		}
12651	}
12652	
12653	// Formatted date time detection - use by declaring the formats you are going to use
12654	DataTable.datetime = function ( format, locale ) {
12655		var typeName = 'datetime-' + format;
12656	
12657		if (! locale) {
12658			locale = 'en';
12659		}
12660	
12661		if (! DataTable.ext.type.order[typeName]) {
12662			DataTable.type(typeName, {
12663				detect: function (d) {
12664					var dt = __mldObj(d, format, locale);
12665					return d === '' || dt ? typeName : false;
12666				},
12667				order: {
12668					pre: function (d) {
12669						return __mldObj(d, format, locale) || 0;
12670					}
12671				},
12672				className: 'dt-right'
12673			});
12674		}
12675	}
12676	
12677	/**
12678	 * Helpers for `columns.render`.
12679	 *
12680	 * The options defined here can be used with the `columns.render` initialisation
12681	 * option to provide a display renderer. The following functions are defined:
12682	 *
12683	 * * `moment` - Uses the MomentJS library to convert from a given format into another.
12684	 * This renderer has three overloads:
12685	 *   * 1 parameter:
12686	 *     * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
12687	 *   * 2 parameters:
12688	 *     * `string` - Format to convert from
12689	 *     * `string` - Format to convert to. Assumes `en` locale
12690	 *   * 3 parameters:
12691	 *     * `string` - Format to convert from
12692	 *     * `string` - Format to convert to
12693	 *     * `string` - Locale
12694	 * * `number` - Will format numeric data (defined by `columns.data`) for
12695	 *   display, retaining the original unformatted data for sorting and filtering.
12696	 *   It takes 5 parameters:
12697	 *   * `string` - Thousands grouping separator
12698	 *   * `string` - Decimal point indicator
12699	 *   * `integer` - Number of decimal points to show
12700	 *   * `string` (optional) - Prefix.
12701	 *   * `string` (optional) - Postfix (/suffix).
12702	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
12703	 *   parameters.
12704	 *
12705	 * @example
12706	 *   // Column definition using the number renderer
12707	 *   {
12708	 *     data: "salary",
12709	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
12710	 *   }
12711	 *
12712	 * @namespace
12713	 */
12714	DataTable.render = {
12715		date: __mlHelper('toLocaleDateString'),
12716		datetime: __mlHelper('toLocaleString'),
12717		time: __mlHelper('toLocaleTimeString'),
12718		number: function ( thousands, decimal, precision, prefix, postfix ) {
12719			// Auto locale detection
12720			if (thousands === null || thousands === undefined) {
12721				thousands = __thousands;
12722			}
12723	
12724			if (decimal === null || decimal === undefined) {
12725				decimal = __decimal;
12726			}
12727	
12728			return {
12729				display: function ( d ) {
12730					if ( typeof d !== 'number' && typeof d !== 'string' ) {
12731						return d;
12732					}
12733	
12734					if (d === '' || d === null) {
12735						return d;
12736					}
12737	
12738					var negative = d < 0 ? '-' : '';
12739					var flo = parseFloat( d );
12740					var abs = Math.abs(flo);
12741	
12742					// Scientific notation for large and small numbers
12743					if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0) ) {
12744						var exp = flo.toExponential(precision).split(/e\+?/);
12745						return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
12746					}
12747	
12748					// If NaN then there isn't much formatting that we can do - just
12749					// return immediately, escaping any HTML (this was supposed to
12750					// be a number after all)
12751					if ( isNaN( flo ) ) {
12752						return _escapeHtml( d );
12753					}
12754	
12755					flo = flo.toFixed( precision );
12756					d = Math.abs( flo );
12757	
12758					var intPart = parseInt( d, 10 );
12759					var floatPart = precision ?
12760						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
12761						'';
12762	
12763					// If zero, then can't have a negative prefix
12764					if (intPart === 0 && parseFloat(floatPart) === 0) {
12765						negative = '';
12766					}
12767	
12768					return negative + (prefix||'') +
12769						intPart.toString().replace(
12770							/\B(?=(\d{3})+(?!\d))/g, thousands
12771						) +
12772						floatPart +
12773						(postfix||'');
12774				}
12775			};
12776		},
12777	
12778		text: function () {
12779			return {
12780				display: _escapeHtml,
12781				filter: _escapeHtml
12782			};
12783		}
12784	};
12785	
12786	
12787	var _extTypes = DataTable.ext.type;
12788	
12789	// Get / set type
12790	DataTable.type = function (name, prop, val) {
12791		if (! prop) {
12792			return {
12793				className: _extTypes.className[name],
12794				detect: _extTypes.detect.find(function (fn) {
12795					return fn._name === name;
12796				}),
12797				order: {
12798					pre: _extTypes.order[name + '-pre'],
12799					asc: _extTypes.order[name + '-asc'],
12800					desc: _extTypes.order[name + '-desc']
12801				},
12802				render: _extTypes.render[name],
12803				search: _extTypes.search[name]
12804			};
12805		}
12806	
12807		var setProp = function(prop, propVal) {
12808			_extTypes[prop][name] = propVal;
12809		};
12810		var setDetect = function (detect) {
12811			// `detect` can be a function or an object - we set a name
12812			// property for either - that is used for the detection
12813			Object.defineProperty(detect, "_name", {value: name});
12814	
12815			var idx = _extTypes.detect.findIndex(function (item) {
12816				return item._name === name;
12817			});
12818	
12819			if (idx === -1) {
12820				_extTypes.detect.unshift(detect);
12821			}
12822			else {
12823				_extTypes.detect.splice(idx, 1, detect);
12824			}
12825		};
12826		var setOrder = function (obj) {
12827			_extTypes.order[name + '-pre'] = obj.pre; // can be undefined
12828			_extTypes.order[name + '-asc'] = obj.asc; // can be undefined
12829			_extTypes.order[name + '-desc'] = obj.desc; // can be undefined
12830		};
12831	
12832		// prop is optional
12833		if (val === undefined) {
12834			val = prop;
12835			prop = null;
12836		}
12837	
12838		if (prop === 'className') {
12839			setProp('className', val);
12840		}
12841		else if (prop === 'detect') {
12842			setDetect(val);
12843		}
12844		else if (prop === 'order') {
12845			setOrder(val);
12846		}
12847		else if (prop === 'render') {
12848			setProp('render', val);
12849		}
12850		else if (prop === 'search') {
12851			setProp('search', val);
12852		}
12853		else if (! prop) {
12854			if (val.className) {
12855				setProp('className', val.className);
12856			}
12857	
12858			if (val.detect !== undefined) {
12859				setDetect(val.detect);
12860			}
12861	
12862			if (val.order) {
12863				setOrder(val.order);
12864			}
12865	
12866			if (val.render !== undefined) {
12867				setProp('render', val.render);
12868			}
12869	
12870			if (val.search !== undefined) {
12871				setProp('search', val.search);
12872			}
12873		}
12874	}
12875	
12876	// Get a list of types
12877	DataTable.types = function () {
12878		return _extTypes.detect.map(function (fn) {
12879			return fn._name;
12880		});
12881	};
12882	
12883	var __diacriticSort = function (a, b) {
12884		a = a !== null && a !== undefined ? a.toString().toLowerCase() : '';
12885		b = b !== null && b !== undefined ? b.toString().toLowerCase() : '';
12886	
12887		// Checked for `navigator.languages` support in `oneOf` so this code can't execute in old
12888		// Safari and thus can disable this check
12889		// eslint-disable-next-line compat/compat
12890		return a.localeCompare(b, navigator.languages[0] || navigator.language, {
12891			numeric: true,
12892			ignorePunctuation: true,
12893		});
12894	}
12895	
12896	var __diacriticHtmlSort = function (a, b) {
12897		a = _stripHtml(a);
12898		b = _stripHtml(b);
12899	
12900		return __diacriticSort(a, b);
12901	}
12902	
12903	//
12904	// Built in data types
12905	//
12906	
12907	DataTable.type('string', {
12908		detect: function () {
12909			return 'string';
12910		},
12911		order: {
12912			pre: function ( a ) {
12913				// This is a little complex, but faster than always calling toString,
12914				// http://jsperf.com/tostring-v-check
12915				return _empty(a) && typeof a !== 'boolean' ?
12916					'' :
12917					typeof a === 'string' ?
12918						a.toLowerCase() :
12919						! a.toString ?
12920							'' :
12921							a.toString();
12922			}
12923		},
12924		search: _filterString(false, true)
12925	});
12926	
12927	DataTable.type('string-utf8', {
12928		detect: {
12929			allOf: function ( d ) {
12930				return true;
12931			},
12932			oneOf: function ( d ) {
12933				// At least one data point must contain a non-ASCII character
12934				// This line will also check if navigator.languages is supported or not. If not (Safari 10.0-)
12935				// this data type won't be supported.
12936				// eslint-disable-next-line compat/compat
12937				return ! _empty( d ) && navigator.languages && typeof d === 'string' && d.match(/[^\x00-\x7F]/);
12938			}
12939		},
12940		order: {
12941			asc: __diacriticSort,
12942			desc: function (a, b) {
12943				return __diacriticSort(a, b) * -1;
12944			}
12945		},
12946		search: _filterString(false, true)
12947	});
12948	
12949	
12950	DataTable.type('html', {
12951		detect: {
12952			allOf: function ( d ) {
12953				return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1);
12954			},
12955			oneOf: function ( d ) {
12956				// At least one data point must contain a `<`
12957				return ! _empty( d ) && typeof d === 'string' && d.indexOf('<') !== -1;
12958			}
12959		},
12960		order: {
12961			pre: function ( a ) {
12962				return _empty(a) ?
12963					'' :
12964					a.replace ?
12965						_stripHtml(a).trim().toLowerCase() :
12966						a+'';
12967			}
12968		},
12969		search: _filterString(true, true)
12970	});
12971	
12972	
12973	DataTable.type('html-utf8', {
12974		detect: {
12975			allOf: function ( d ) {
12976				return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1);
12977			},
12978			oneOf: function ( d ) {
12979				// At least one data point must contain a `<` and a non-ASCII character
12980				// eslint-disable-next-line compat/compat
12981				return navigator.languages &&
12982					! _empty( d ) &&
12983					typeof d === 'string' &&
12984					d.indexOf('<') !== -1 &&
12985					typeof d === 'string' && d.match(/[^\x00-\x7F]/);
12986			}
12987		},
12988		order: {
12989			asc: __diacriticHtmlSort,
12990			desc: function (a, b) {
12991				return __diacriticHtmlSort(a, b) * -1;
12992			}
12993		},
12994		search: _filterString(true, true)
12995	});
12996	
12997	
12998	DataTable.type('date', {
12999		className: 'dt-type-date',
13000		detect: {
13001			allOf: function ( d ) {
13002				// V8 tries _very_ hard to make a string passed into `Date.parse()`
13003				// valid, so we need to use a regex to restrict date formats. Use a
13004				// plug-in for anything other than ISO8601 style strings
13005				if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
13006					return null;
13007				}
13008				var parsed = Date.parse(d);
13009				return (parsed !== null && !isNaN(parsed)) || _empty(d);
13010			},
13011			oneOf: function ( d ) {
13012				// At least one entry must be a date or a string with a date
13013				return (d instanceof Date) || (typeof d === 'string' && _re_date.test(d));
13014			}
13015		},
13016		order: {
13017			pre: function ( d ) {
13018				var ts = Date.parse( d );
13019				return isNaN(ts) ? -Infinity : ts;
13020			}
13021		}
13022	});
13023	
13024	
13025	DataTable.type('html-num-fmt', {
13026		className: 'dt-type-numeric',
13027		detect: {
13028			allOf: function ( d, settings ) {
13029				var decimal = settings.oLanguage.sDecimal;
13030				return _htmlNumeric( d, decimal, true, false );
13031			},
13032			oneOf: function (d, settings) {
13033				// At least one data point must contain a numeric value
13034				var decimal = settings.oLanguage.sDecimal;
13035				return _htmlNumeric( d, decimal, true, false );
13036			}
13037		},
13038		order: {
13039			pre: function ( d, s ) {
13040				var dp = s.oLanguage.sDecimal;
13041				return __numericReplace( d, dp, _re_html, _re_formatted_numeric );
13042			}
13043		},
13044		search: _filterString(true, true)
13045	});
13046	
13047	
13048	DataTable.type('html-num', {
13049		className: 'dt-type-numeric',
13050		detect: {
13051			allOf: function ( d, settings ) {
13052				var decimal = settings.oLanguage.sDecimal;
13053				return _htmlNumeric( d, decimal, false, true );
13054			},
13055			oneOf: function (d, settings) {
13056				// At least one data point must contain a numeric value
13057				var decimal = settings.oLanguage.sDecimal;
13058				return _htmlNumeric( d, decimal, false, false );
13059			}
13060		},
13061		order: {
13062			pre: function ( d, s ) {
13063				var dp = s.oLanguage.sDecimal;
13064				return __numericReplace( d, dp, _re_html );
13065			}
13066		},
13067		search: _filterString(true, true)
13068	});
13069	
13070	
13071	DataTable.type('num-fmt', {
13072		className: 'dt-type-numeric',
13073		detect: {
13074			allOf: function ( d, settings ) {
13075				var decimal = settings.oLanguage.sDecimal;
13076				return _isNumber( d, decimal, true, true );
13077			},
13078			oneOf: function (d, settings) {
13079				// At least one data point must contain a numeric value
13080				var decimal = settings.oLanguage.sDecimal;
13081				return _isNumber( d, decimal, true, false );
13082			}
13083		},
13084		order: {
13085			pre: function ( d, s ) {
13086				var dp = s.oLanguage.sDecimal;
13087				return __numericReplace( d, dp, _re_formatted_numeric );
13088			}
13089		}
13090	});
13091	
13092	
13093	DataTable.type('num', {
13094		className: 'dt-type-numeric',
13095		detect: {
13096			allOf: function ( d, settings ) {
13097				var decimal = settings.oLanguage.sDecimal;
13098				return _isNumber( d, decimal, false, true );
13099			},
13100			oneOf: function (d, settings) {
13101				// At least one data point must contain a numeric value
13102				var decimal = settings.oLanguage.sDecimal;
13103				return _isNumber( d, decimal, false, false );
13104			}
13105		},
13106		order: {
13107			pre: function (d, s) {
13108				var dp = s.oLanguage.sDecimal;
13109				return __numericReplace( d, dp );
13110			}
13111		}
13112	});
13113	
13114	
13115	
13116	
13117	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
13118		if ( d !== 0 && (!d || d === '-') ) {
13119			return -Infinity;
13120		}
13121		
13122		var type = typeof d;
13123	
13124		if (type === 'number' || type === 'bigint') {
13125			return d;
13126		}
13127	
13128		// If a decimal place other than `.` is used, it needs to be given to the
13129		// function so we can detect it and replace with a `.` which is the only
13130		// decimal place Javascript recognises - it is not locale aware.
13131		if ( decimalPlace ) {
13132			d = _numToDecimal( d, decimalPlace );
13133		}
13134	
13135		if ( d.replace ) {
13136			if ( re1 ) {
13137				d = d.replace( re1, '' );
13138			}
13139	
13140			if ( re2 ) {
13141				d = d.replace( re2, '' );
13142			}
13143		}
13144	
13145		return d * 1;
13146	};
13147	
13148	
13149	$.extend( true, DataTable.ext.renderer, {
13150		footer: {
13151			_: function ( settings, cell, classes ) {
13152				cell.addClass(classes.tfoot.cell);
13153			}
13154		},
13155	
13156		header: {
13157			_: function ( settings, cell, classes ) {
13158				cell.addClass(classes.thead.cell);
13159	
13160				if (! settings.oFeatures.bSort) {
13161					cell.addClass(classes.order.none);
13162				}
13163	
13164				var titleRow = settings.titleRow;
13165				var headerRows = cell.closest('thead').find('tr');
13166				var rowIdx = cell.parent().index();
13167	
13168				// Conditions to not apply the ordering icons
13169				if (
13170					// Cells and rows which have the attribute to disable the icons
13171					cell.attr('data-dt-order') === 'disable' ||
13172					cell.parent().attr('data-dt-order') === 'disable' ||
13173	
13174					// titleRow support, for defining a specific row in the header
13175					(titleRow === true && rowIdx !== 0) ||
13176					(titleRow === false && rowIdx !== headerRows.length - 1) ||
13177					(typeof titleRow === 'number' && rowIdx !== titleRow)
13178				) {
13179					return;
13180				}
13181	
13182				// No additional mark-up required
13183				// Attach a sort listener to update on sort - note that using the
13184				// `DT` namespace will allow the event to be removed automatically
13185				// on destroy, while the `dt` namespaced event is the one we are
13186				// listening for
13187				$(settings.nTable).on( 'order.dt.DT column-visibility.dt.DT', function ( e, ctx, column ) {
13188					if ( settings !== ctx ) { // need to check this this is the host
13189						return;               // table, not a nested one
13190					}
13191	
13192					var sorting = ctx.sortDetails;
13193	
13194					if (! sorting) {
13195						return;
13196					}
13197	
13198					var orderedColumns = _pluck(sorting, 'col');
13199	
13200					// This handler is only needed on column visibility if the column is part of the
13201					// ordering. If it isn't, then we can bail out to save performance. It could be a
13202					// separate event handler, but this is a balance between code reuse / size and performance
13203					// console.log(e, e.name, column, orderedColumns, orderedColumns.includes(column))
13204					if (e.type === 'column-visibility' && ! orderedColumns.includes(column)) {
13205						return;
13206					}
13207	
13208					var i;
13209					var orderClasses = classes.order;
13210					var columns = ctx.api.columns( cell );
13211					var col = settings.aoColumns[columns.flatten()[0]];
13212					var orderable = columns.orderable().includes(true);
13213					var ariaType = '';
13214					var indexes = columns.indexes();
13215					var sortDirs = columns.orderable(true).flatten();
13216					var tabIndex = settings.iTabIndex;
13217					var canOrder = ctx.orderHandler && orderable;
13218	
13219					cell
13220						.removeClass(
13221							orderClasses.isAsc +' '+
13222							orderClasses.isDesc
13223						)
13224						.toggleClass( orderClasses.none, ! orderable )
13225						.toggleClass( orderClasses.canAsc, canOrder && sortDirs.includes('asc') )
13226						.toggleClass( orderClasses.canDesc, canOrder && sortDirs.includes('desc') );
13227	
13228					// Determine if all of the columns that this cell covers are included in the
13229					// current ordering
13230					var isOrdering = true;
13231					
13232					for (i=0; i<indexes.length; i++) {
13233						if (! orderedColumns.includes(indexes[i])) {
13234							isOrdering = false;
13235						}
13236					}
13237	
13238					if ( isOrdering ) {
13239						// Get the ordering direction for the columns under this cell
13240						// Note that it is possible for a cell to be asc and desc sorting
13241						// (column spanning cells)
13242						var orderDirs = columns.order();
13243	
13244						cell.addClass(
13245							orderDirs.includes('asc') ? orderClasses.isAsc : '' +
13246							orderDirs.includes('desc') ? orderClasses.isDesc : ''
13247						);
13248					}
13249	
13250					// Find the first visible column that has ordering applied to it - it get's
13251					// the aria information, as the ARIA spec says that only one column should
13252					// be marked with aria-sort
13253					var firstVis = -1; // column index
13254	
13255					for (i=0; i<orderedColumns.length; i++) {
13256						if (settings.aoColumns[orderedColumns[i]].bVisible) {
13257							firstVis = orderedColumns[i];
13258							break;
13259						}
13260					}
13261	
13262					if (indexes[0] == firstVis) {
13263						var firstSort = sorting[0];
13264						var sortOrder = col.asSorting;
13265	
13266						cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
13267	
13268						// Determine if the next click will remove sorting or change the sort
13269						ariaType = ! sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
13270					}
13271					else {
13272						cell.removeAttr('aria-sort');
13273					}
13274	
13275					// Make the headers tab-able for keyboard navigation
13276					if (orderable) {
13277						var orderSpan = cell.find('.dt-column-order');
13278						
13279						orderSpan
13280							.attr('role', 'button')
13281							.attr('aria-label', orderable
13282								? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
13283								: col.ariaTitle
13284							);
13285	
13286						if (tabIndex !== -1) {
13287							orderSpan.attr('tabindex', tabIndex);
13288						}
13289					}
13290				} );
13291			}
13292		},
13293	
13294		layout: {
13295			_: function ( settings, container, items ) {
13296				var classes = settings.oClasses.layout;
13297				var row = $('<div/>')
13298					.attr('id', items.id || null)
13299					.addClass(items.className || classes.row)
13300					.appendTo( container );
13301	
13302				DataTable.ext.renderer.layout._forLayoutRow(items, function (key, val) {
13303					if (key === 'id' || key === 'className') {
13304						return;
13305					}
13306	
13307					var klass = '';
13308	
13309					if (val.table) {
13310						row.addClass(classes.tableRow);
13311						klass += classes.tableCell + ' ';
13312					}
13313	
13314					if (key === 'start') {
13315						klass += classes.start;
13316					}
13317					else if (key === 'end') {
13318						klass += classes.end;
13319					}
13320					else {
13321						klass += classes.full;
13322					}
13323	
13324					$('<div/>')
13325						.attr({
13326							id: val.id || null,
13327							"class": val.className
13328								? val.className
13329								: classes.cell + ' ' + klass
13330						})
13331						.append( val.contents )
13332						.appendTo( row );
13333				});
13334			},
13335	
13336			// Shared for use by the styling frameworks
13337			_forLayoutRow: function (items, fn) {
13338				// As we are inserting dom elements, we need start / end in a
13339				// specific order, this function is used for sorting the layout
13340				// keys.
13341				var layoutEnum = function (x) {
13342					switch (x) {
13343						case '': return 0;
13344						case 'start': return 1;
13345						case 'end': return 2;
13346						default: return 3;
13347					}
13348				};
13349	
13350				Object
13351					.keys(items)
13352					.sort(function (a, b) {
13353						return layoutEnum(a) - layoutEnum(b);
13354					})
13355					.forEach(function (key) {
13356						fn(key, items[key]);
13357					});
13358			}
13359		}
13360	} );
13361	
13362	
13363	DataTable.feature = {};
13364	
13365	// Third parameter is internal only!
13366	DataTable.feature.register = function ( name, cb, legacy ) {
13367		DataTable.ext.features[ name ] = cb;
13368	
13369		if (legacy) {
13370			_ext.feature.push({
13371				cFeature: legacy,
13372				fnInit: cb
13373			});
13374		}
13375	};
13376	
13377	function _divProp(el, prop, val) {
13378		if (val) {
13379			el[prop] = val;
13380		}
13381	}
13382	
13383	DataTable.feature.register( 'div', function ( settings, opts ) {
13384		var n = $('<div>')[0];
13385	
13386		if (opts) {
13387			_divProp(n, 'className', opts.className);
13388			_divProp(n, 'id', opts.id);
13389			_divProp(n, 'innerHTML', opts.html);
13390			_divProp(n, 'textContent', opts.text);
13391		}
13392	
13393		return n;
13394	} );
13395	
13396	DataTable.feature.register( 'info', function ( settings, opts ) {
13397		// For compatibility with the legacy `info` top level option
13398		if (! settings.oFeatures.bInfo) {
13399			return null;
13400		}
13401	
13402		var
13403			lang  = settings.oLanguage,
13404			tid = settings.sTableId,
13405			n = $('<div/>', {
13406				'class': settings.oClasses.info.container,
13407			} );
13408	
13409		opts = $.extend({
13410			callback: lang.fnInfoCallback,
13411			empty: lang.sInfoEmpty,
13412			postfix: lang.sInfoPostFix,
13413			search: lang.sInfoFiltered,
13414			text: lang.sInfo,
13415		}, opts);
13416	
13417	
13418		// Update display on each draw
13419		settings.aoDrawCallback.push(function (s) {
13420			_fnUpdateInfo(s, opts, n);
13421		});
13422	
13423		// For the first info display in the table, we add a callback and aria information.
13424		if (! settings._infoEl) {
13425			n.attr({
13426				'aria-live': 'polite',
13427				id: tid+'_info',
13428				role: 'status'
13429			});
13430	
13431			// Table is described by our info div
13432			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
13433	
13434			settings._infoEl = n;
13435		}
13436	
13437		return n;
13438	}, 'i' );
13439	
13440	/**
13441	 * Update the information elements in the display
13442	 *  @param {object} settings dataTables settings object
13443	 *  @memberof DataTable#oApi
13444	 */
13445	function _fnUpdateInfo ( settings, opts, node )
13446	{
13447		var
13448			start = settings._iDisplayStart+1,
13449			end   = settings.fnDisplayEnd(),
13450			max   = settings.fnRecordsTotal(),
13451			total = settings.fnRecordsDisplay(),
13452			out   = total
13453				? opts.text
13454				: opts.empty;
13455	
13456		if ( total !== max ) {
13457			// Record set after filtering
13458			out += ' ' + opts.search;
13459		}
13460	
13461		// Convert the macros
13462		out += opts.postfix;
13463		out = _fnMacros( settings, out );
13464	
13465		if ( opts.callback ) {
13466			out = opts.callback.call( settings.oInstance,
13467				settings, start, end, max, total, out
13468			);
13469		}
13470	
13471		node.html( out );
13472	
13473		_fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
13474	}
13475	
13476	var __searchCounter = 0;
13477	
13478	// opts
13479	// - text
13480	// - placeholder
13481	DataTable.feature.register( 'search', function ( settings, opts ) {
13482		// Don't show the input if filtering isn't available on the table
13483		if (! settings.oFeatures.bFilter) {
13484			return null;
13485		}
13486	
13487		var classes = settings.oClasses.search;
13488		var tableId = settings.sTableId;
13489		var language = settings.oLanguage;
13490		var previousSearch = settings.oPreviousSearch;
13491		var input = '<input type="search" class="'+classes.input+'"/>';
13492	
13493		opts = $.extend({
13494			placeholder: language.sSearchPlaceholder,
13495			processing: false,
13496			text: language.sSearch
13497		}, opts);
13498	
13499		// The _INPUT_ is optional - is appended if not present
13500		if (opts.text.indexOf('_INPUT_') === -1) {
13501			opts.text += '_INPUT_';
13502		}
13503	
13504		opts.text = _fnMacros(settings, opts.text);
13505	
13506		// We can put the <input> outside of the label if it is at the start or end
13507		// which helps improve accessability (not all screen readers like implicit
13508		// for elements).
13509		var end = opts.text.match(/_INPUT_$/);
13510		var start = opts.text.match(/^_INPUT_/);
13511		var removed = opts.text.replace(/_INPUT_/, '');
13512		var str = '<label>' + opts.text + '</label>';
13513	
13514		if (start) {
13515			str = '_INPUT_<label>' + removed + '</label>';
13516		}
13517		else if (end) {
13518			str = '<label>' + removed + '</label>_INPUT_';
13519		}
13520	
13521		var filter = $('<div>')
13522			.addClass(classes.container)
13523			.append(str.replace(/_INPUT_/, input));
13524	
13525		// add for and id to label and input
13526		filter.find('label').attr('for', 'dt-search-' + __searchCounter);
13527		filter.find('input').attr('id', 'dt-search-' + __searchCounter);
13528		__searchCounter++;
13529	
13530		var searchFn = function(event) {
13531			var val = this.value;
13532	
13533			if(previousSearch.return && event.key !== "Enter") {
13534				return;
13535			}
13536	
13537			/* Now do the filter */
13538			if ( val != previousSearch.search ) {
13539				_fnProcessingRun(settings, opts.processing, function () {
13540					previousSearch.search = val;
13541			
13542					_fnFilterComplete( settings, previousSearch );
13543			
13544					// Need to redraw, without resorting
13545					settings._iDisplayStart = 0;
13546					_fnDraw( settings );
13547				});
13548			}
13549		};
13550	
13551		var searchDelay = settings.searchDelay !== null ?
13552			settings.searchDelay :
13553			0;
13554	
13555		var jqFilter = $('input', filter)
13556			.val( previousSearch.search )
13557			.attr( 'placeholder', opts.placeholder )
13558			.on(
13559				'keyup.DT search.DT input.DT paste.DT cut.DT',
13560				searchDelay ?
13561					DataTable.util.debounce( searchFn, searchDelay ) :
13562					searchFn
13563			)
13564			.on( 'mouseup.DT', function(e) {
13565				// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
13566				// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
13567				// checks the value to see if it has changed. In other browsers it won't have.
13568				setTimeout( function () {
13569					searchFn.call(jqFilter[0], e);
13570				}, 10);
13571			} )
13572			.on( 'keypress.DT', function(e) {
13573				/* Prevent form submission */
13574				if ( e.keyCode == 13 ) {
13575					return false;
13576				}
13577			} )
13578			.attr('aria-controls', tableId);
13579	
13580		// Update the input elements whenever the table is filtered
13581		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
13582			if ( settings === s && jqFilter[0] !== document.activeElement ) {
13583				jqFilter.val( typeof previousSearch.search !== 'function'
13584					? previousSearch.search
13585					: ''
13586				);
13587			}
13588		} );
13589	
13590		return filter;
13591	}, 'f' );
13592	
13593	// opts
13594	// - type - button configuration
13595	// - buttons - number of buttons to show - must be odd
13596	DataTable.feature.register( 'paging', function ( settings, opts ) {
13597		// Don't show the paging input if the table doesn't have paging enabled
13598		if (! settings.oFeatures.bPaginate) {
13599			return null;
13600		}
13601	
13602		opts = $.extend({
13603			buttons: DataTable.ext.pager.numbers_length,
13604			type: settings.sPaginationType,
13605			boundaryNumbers: true,
13606			firstLast: true,
13607			previousNext: true,
13608			numbers: true
13609		}, opts);
13610	
13611		var host = $('<div/>')
13612			.addClass(settings.oClasses.paging.container + (opts.type ? ' paging_' + opts.type : ''))
13613			.append(
13614				$('<nav>')
13615					.attr('aria-label', 'pagination')
13616					.addClass(settings.oClasses.paging.nav)
13617			);
13618		var draw = function () {
13619			_pagingDraw(settings, host.children(), opts);
13620		};
13621	
13622		settings.aoDrawCallback.push(draw);
13623	
13624		// Responsive redraw of paging control
13625		$(settings.nTable).on('column-sizing.dt.DT', draw);
13626	
13627		return host;
13628	}, 'p' );
13629	
13630	/**
13631	 * Dynamically create the button type array based on the configuration options.
13632	 * This will only happen if the paging type is not defined.
13633	 */
13634	function _pagingDynamic(opts) {
13635		var out = [];
13636	
13637		if (opts.numbers) {
13638			out.push('numbers');
13639		}
13640	
13641		if (opts.previousNext) {
13642			out.unshift('previous');
13643			out.push('next');
13644		}
13645	
13646		if (opts.firstLast) {
13647			out.unshift('first');
13648			out.push('last');
13649		}
13650	
13651		return out;
13652	}
13653	
13654	function _pagingDraw(settings, host, opts) {
13655		if (! settings._bInitComplete) {
13656			return;
13657		}
13658	
13659		var
13660			plugin = opts.type
13661				? DataTable.ext.pager[ opts.type ]
13662				: _pagingDynamic,
13663			aria = settings.oLanguage.oAria.paginate || {},
13664			start      = settings._iDisplayStart,
13665			len        = settings._iDisplayLength,
13666			visRecords = settings.fnRecordsDisplay(),
13667			all        = len === -1,
13668			page = all ? 0 : Math.ceil( start / len ),
13669			pages = all ? 1 : Math.ceil( visRecords / len ),
13670			buttons = [],
13671			buttonEls = [],
13672			buttonsNested = plugin(opts)
13673				.map(function (val) {
13674					return val === 'numbers'
13675						? _pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
13676						: val;
13677				});
13678	
13679		// .flat() would be better, but not supported in old Safari
13680		buttons = buttons.concat.apply(buttons, buttonsNested);
13681	
13682		for (var i=0 ; i<buttons.length ; i++) {
13683			var button = buttons[i];
13684	
13685			var btnInfo = _pagingButtonInfo(settings, button, page, pages);
13686			var btn = _fnRenderer( settings, 'pagingButton' )(
13687				settings,
13688				button,
13689				btnInfo.display,
13690				btnInfo.active,
13691				btnInfo.disabled
13692			);
13693	
13694			var ariaLabel = typeof button === 'string'
13695				? aria[ button ]
13696				: aria.number
13697					? aria.number + (button+1)
13698					: null;
13699	
13700			// Common attributes
13701			$(btn.clicker).attr({
13702				'aria-controls': settings.sTableId,
13703				'aria-disabled': btnInfo.disabled ? 'true' : null,
13704				'aria-current': btnInfo.active ? 'page' : null,
13705				'aria-label': ariaLabel,
13706				'data-dt-idx': button,
13707				'tabIndex': btnInfo.disabled
13708					? -1
13709					: settings.iTabIndex && btn.clicker[0].nodeName.toLowerCase() !== 'span'
13710						? settings.iTabIndex
13711						: null, // `0` doesn't need a tabIndex since it is the default
13712			});
13713	
13714			if (typeof button !== 'number') {
13715				$(btn.clicker).addClass(button);
13716			}
13717	
13718			_fnBindAction(
13719				btn.clicker, {action: button}, function(e) {
13720					e.preventDefault();
13721	
13722					_fnPageChange( settings, e.data.action, true );
13723				}
13724			);
13725	
13726			buttonEls.push(btn.display);
13727		}
13728	
13729		var wrapped = _fnRenderer(settings, 'pagingContainer')(
13730			settings, buttonEls
13731		);
13732	
13733		var activeEl = host.find(document.activeElement).data('dt-idx');
13734	
13735		host.empty().append(wrapped);
13736	
13737		if ( activeEl !== undefined ) {
13738			host.find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
13739		}
13740	
13741		// Responsive - check if the buttons are over two lines based on the
13742		// height of the buttons and the container.
13743		if (buttonEls.length) {
13744			var outerHeight = $(buttonEls[0]).outerHeight();
13745		
13746			if (
13747				opts.buttons > 1 && // prevent infinite
13748				outerHeight > 0 && // will be 0 if hidden
13749				$(host).height() >= (outerHeight * 2) - 10
13750			) {
13751				_pagingDraw(settings, host, $.extend({}, opts, { buttons: opts.buttons - 2 }));
13752			}
13753		}
13754	}
13755	
13756	/**
13757	 * Get properties for a button based on the current paging state of the table
13758	 *
13759	 * @param {*} settings DT settings object
13760	 * @param {*} button The button type in question
13761	 * @param {*} page Table's current page
13762	 * @param {*} pages Number of pages
13763	 * @returns Info object
13764	 */
13765	function _pagingButtonInfo(settings, button, page, pages) {
13766		var lang = settings.oLanguage.oPaginate;
13767		var o = {
13768			display: '',
13769			active: false,
13770			disabled: false
13771		};
13772	
13773		switch ( button ) {
13774			case 'ellipsis':
13775				o.display = '&#x2026;';
13776				break;
13777	
13778			case 'first':
13779				o.display = lang.sFirst;
13780	
13781				if (page === 0) {
13782					o.disabled = true;
13783				}
13784				break;
13785	
13786			case 'previous':
13787				o.display = lang.sPrevious;
13788	
13789				if ( page === 0 ) {
13790					o.disabled = true;
13791				}
13792				break;
13793	
13794			case 'next':
13795				o.display = lang.sNext;
13796	
13797				if ( pages === 0 || page === pages-1 ) {
13798					o.disabled = true;
13799				}
13800				break;
13801	
13802			case 'last':
13803				o.display = lang.sLast;
13804	
13805				if ( pages === 0 || page === pages-1 ) {
13806					o.disabled = true;
13807				}
13808				break;
13809	
13810			default:
13811				if ( typeof button === 'number' ) {
13812					o.display = settings.fnFormatNumber( button + 1 );
13813					
13814					if (page === button) {
13815						o.active = true;
13816					}
13817				}
13818				break;
13819		}
13820	
13821		return o;
13822	}
13823	
13824	/**
13825	 * Compute what number buttons to show in the paging control
13826	 *
13827	 * @param {*} page Current page
13828	 * @param {*} pages Total number of pages
13829	 * @param {*} buttons Target number of number buttons
13830	 * @param {boolean} addFirstLast Indicate if page 1 and end should be included
13831	 * @returns Buttons to show
13832	 */
13833	function _pagingNumbers ( page, pages, buttons, addFirstLast ) {
13834		var
13835			numbers = [],
13836			half = Math.floor(buttons / 2),
13837			before = addFirstLast ? 2 : 1,
13838			after = addFirstLast ? 1 : 0;
13839	
13840		if ( pages <= buttons ) {
13841			numbers = _range(0, pages);
13842		}
13843		else if (buttons === 1) {
13844			// Single button - current page only
13845			numbers = [page];
13846		}
13847		else if (buttons === 3) {
13848			// Special logic for just three buttons
13849			if (page <= 1) {
13850				numbers = [0, 1, 'ellipsis'];
13851			}
13852			else if (page >= pages - 2) {
13853				numbers = _range(pages-2, pages);
13854				numbers.unshift('ellipsis');
13855			}
13856			else {
13857				numbers = ['ellipsis', page, 'ellipsis'];
13858			}
13859		}
13860		else if ( page <= half ) {
13861			numbers = _range(0, buttons-before);
13862			numbers.push('ellipsis');
13863	
13864			if (addFirstLast) {
13865				numbers.push(pages-1);
13866			}
13867		}
13868		else if ( page >= pages - 1 - half ) {
13869			numbers = _range(pages-(buttons-before), pages);
13870			numbers.unshift('ellipsis');
13871	
13872			if (addFirstLast) {
13873				numbers.unshift(0);
13874			}
13875		}
13876		else {
13877			numbers = _range(page-half+before, page+half-after);
13878			numbers.push('ellipsis');
13879			numbers.unshift('ellipsis');
13880	
13881			if (addFirstLast) {
13882				numbers.push(pages-1);
13883				numbers.unshift(0);
13884			}
13885		}
13886	
13887		return numbers;
13888	}
13889	
13890	var __lengthCounter = 0;
13891	
13892	// opts
13893	// - menu
13894	// - text
13895	DataTable.feature.register( 'pageLength', function ( settings, opts ) {
13896		var features = settings.oFeatures;
13897	
13898		// For compatibility with the legacy `pageLength` top level option
13899		if (! features.bPaginate || ! features.bLengthChange) {
13900			return null;
13901		}
13902	
13903		opts = $.extend({
13904			menu: settings.aLengthMenu,
13905			text: settings.oLanguage.sLengthMenu
13906		}, opts);
13907	
13908		var
13909			classes  = settings.oClasses.length,
13910			tableId  = settings.sTableId,
13911			menu     = opts.menu,
13912			lengths  = [],
13913			language = [],
13914			i;
13915	
13916		// Options can be given in a number of ways
13917		if (Array.isArray( menu[0] )) {
13918			// Old 1.x style - 2D array
13919			lengths = menu[0];
13920			language = menu[1];
13921		}
13922		else {
13923			for ( i=0 ; i<menu.length ; i++ ) {
13924				// An object with different label and value
13925				if ($.isPlainObject(menu[i])) {
13926					lengths.push(menu[i].value);
13927					language.push(menu[i].label);
13928				}
13929				else {
13930					// Or just a number to display and use
13931					lengths.push(menu[i]);
13932					language.push(menu[i]);
13933				}
13934			}
13935		}
13936	
13937		// We can put the <select> outside of the label if it is at the start or
13938		// end which helps improve accessability (not all screen readers like
13939		// implicit for elements).
13940		var end = opts.text.match(/_MENU_$/);
13941		var start = opts.text.match(/^_MENU_/);
13942		var removed = opts.text.replace(/_MENU_/, '');
13943		var str = '<label>' + opts.text + '</label>';
13944	
13945		if (start) {
13946			str = '_MENU_<label>' + removed + '</label>';
13947		}
13948		else if (end) {
13949			str = '<label>' + removed + '</label>_MENU_';
13950		}
13951	
13952		// Wrapper element - use a span as a holder for where the select will go
13953		var tmpId = 'tmp-' + (+new Date())
13954		var div = $('<div/>')
13955			.addClass( classes.container )
13956			.append(
13957				str.replace( '_MENU_', '<span id="'+tmpId+'"></span>' )
13958			);
13959	
13960		// Save text node content for macro updating
13961		var textNodes = [];
13962		Array.prototype.slice.call(div.find('label')[0].childNodes).forEach(function (el) {
13963			if (el.nodeType === Node.TEXT_NODE) {
13964				textNodes.push({
13965					el: el,
13966					text: el.textContent
13967				});
13968			}
13969		});
13970	
13971		// Update the label text in case it has an entries value
13972		var updateEntries = function (len) {
13973			textNodes.forEach(function (node) {
13974				node.el.textContent = _fnMacros(settings, node.text, len);
13975			});
13976		}
13977	
13978		// Next, the select itself, along with the options
13979		var select = $('<select/>', {
13980			'aria-controls': tableId,
13981			'class':         classes.select
13982		} );
13983	
13984		for ( i=0 ; i<lengths.length ; i++ ) {
13985			// Attempt to look up the length from the i18n options
13986			var label = settings.api.i18n('lengthLabels.' + lengths[i], null);
13987	
13988			if (label === null) {
13989				// If not present, fallback to old style
13990				label = typeof language[i] === 'number' ?
13991					settings.fnFormatNumber( language[i] ) :
13992					language[i];
13993			}
13994	
13995			select[0][ i ] = new Option(label, lengths[i]);
13996		}
13997	
13998		// add for and id to label and input
13999		div.find('label').attr('for', 'dt-length-' + __lengthCounter);
14000		select.attr('id', 'dt-length-' + __lengthCounter);
14001		__lengthCounter++;
14002	
14003		// Swap in the select list
14004		div.find('#' + tmpId).replaceWith(select);
14005	
14006		// Can't use `select` variable as user might provide their own and the
14007		// reference is broken by the use of outerHTML
14008		$('select', div)
14009			.val( settings._iDisplayLength )
14010			.on( 'change.DT', function() {
14011				_fnLengthChange( settings, $(this).val() );
14012				_fnDraw( settings );
14013			} );
14014	
14015		// Update node value whenever anything changes the table's length
14016		$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
14017			if ( settings === s ) {
14018				$('select', div).val( len );
14019	
14020				// Resolve plurals in the text for the new length
14021				updateEntries(len);
14022			}
14023		} );
14024	
14025		updateEntries(settings._iDisplayLength);
14026	
14027		return div;
14028	}, 'l' );
14029	
14030	// jQuery access
14031	$.fn.dataTable = DataTable;
14032	
14033	// Provide access to the host jQuery object (circular reference)
14034	DataTable.$ = $;
14035	
14036	// Legacy aliases
14037	$.fn.dataTableSettings = DataTable.settings;
14038	$.fn.dataTableExt = DataTable.ext;
14039	
14040	// With a capital `D` we return a DataTables API instance rather than a
14041	// jQuery object
14042	$.fn.DataTable = function ( opts ) {
14043		return $(this).dataTable( opts ).api();
14044	};
14045	
14046	// All properties that are available to $.fn.dataTable should also be
14047	// available on $.fn.DataTable
14048	$.each( DataTable, function ( prop, val ) {
14049		$.fn.DataTable[ prop ] = val;
14050	} );
14051
14052	return DataTable;
14053}));

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.