PageSourceSearch

https://www.ciencia.gob.es/.resources/site-web/webresources/js/dat…dataTables~2026-09-16-05-38-56-972~cache.js

js ciencia.gob.es collected 2026-09-24 08:47:12 UTC 380,594 bytes, 13,171 lines download raw bytes

1/*! DataTables 2.0.8
2 * © SpryMedia Ltd - datatables.net/license
3 */
4
5/**
6 * @summary     DataTables
7 * @description Paginate, search and order HTML tables
8 * @version     2.0.8
9 * @author      SpryMedia Ltd
10 * @contact     www.datatables.net
11 * @copyright   SpryMedia Ltd.
12 *
13 * This source file is free software, available under the following license:
14 *   MIT license - https://datatables.net/license
15 *
16 * This source file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
19 *
20 * For details please refer to: https://www.datatables.net
21 */
22
23(function( factory ) {
24	"use strict";
25
26	if ( typeof define === 'function' && define.amd ) {
27		// AMD
28		define( ['jquery'], function ( $ ) {
29			return factory( $, window, document );
30		} );
31	}
32	else if ( typeof exports === 'object' ) {
33		// CommonJS
34		// jQuery's factory checks for a global window - if it isn't present then it
35		// returns a factory function that expects the window object
36		var jq = require('jquery');
37
38		if (typeof window === 'undefined') {
39			module.exports = function (root, $) {
40				if ( ! root ) {
41					// CommonJS environments without a window global must pass a
42					// root. This will give an error otherwise
43					root = window;
44				}
45
46				if ( ! $ ) {
47					$ = jq( root );
48				}
49
50				return factory( $, root, root.document );
51			};
52		}
53		else {
54			module.exports = factory( jq, window, window.document );
55		}
56	}
57	else {
58		// Browser
59		window.DataTable = factory( jQuery, window, document );
60	}
61}(function( $, window, document ) {
62	"use strict";
63
64	
65	var DataTable = function ( selector, options )
66	{
67		// Check if called with a window or jQuery object for DOM less applications
68		// This is for backwards compatibility
69		if (DataTable.factory(selector, options)) {
70			return DataTable;
71		}
72	
73		// When creating with `new`, create a new DataTable, returning the API instance
74		if (this instanceof DataTable) {
75			return $(selector).DataTable(options);
76		}
77		else {
78			// Argument switching
79			options = selector;
80		}
81	
82		var _that = this;
83		var emptyInit = options === undefined;
84		var len = this.length;
85	
86		if ( emptyInit ) {
87			options = {};
88		}
89	
90		// Method to get DT API instance from jQuery object
91		this.api = function ()
92		{
93			return new _Api( this );
94		};
95	
96		this.each(function() {
97			// For each initialisation we want to give it a clean initialisation
98			// object that can be bashed around
99			var o = {};
100			var oInit = len > 1 ? // optimisation for single table case
101				_fnExtend( o, options, true ) :
102				options;
103	
104			
105			var i=0, iLen;
106			var sId = this.getAttribute( 'id' );
107			var bInitHandedOff = false;
108			var defaults = DataTable.defaults;
109			var $this = $(this);
110			
111			
112			/* Sanity check */
113			if ( this.nodeName.toLowerCase() != 'table' )
114			{
115				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
116				return;
117			}
118			
119			$(this).trigger( 'options.dt', oInit );
120			
121			/* Backwards compatibility for the defaults */
122			_fnCompatOpts( defaults );
123			_fnCompatCols( defaults.column );
124			
125			/* Convert the camel-case defaults to Hungarian */
126			_fnCamelToHungarian( defaults, defaults, true );
127			_fnCamelToHungarian( defaults.column, defaults.column, true );
128			
129			/* Setting up the initialisation object */
130			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
131			
132			
133			
134			/* Check to see if we are re-initialising a table */
135			var allSettings = DataTable.settings;
136			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
137			{
138				var s = allSettings[i];
139			
140				/* Base check on table node */
141				if (
142					s.nTable == this ||
143					(s.nTHead && s.nTHead.parentNode == this) ||
144					(s.nTFoot && s.nTFoot.parentNode == this)
145				) {
146					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
147					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
148			
149					if ( emptyInit || bRetrieve )
150					{
151						return s.oInstance;
152					}
153					else if ( bDestroy )
154					{
155						new DataTable.Api(s).destroy();
156						break;
157					}
158					else
159					{
160						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
161						return;
162					}
163				}
164			
165				/* If the element we are initialising has the same ID as a table which was previously
166				 * initialised, but the table nodes don't match (from before) then we destroy the old
167				 * instance by simply deleting it. This is under the assumption that the table has been
168				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
169				 */
170				if ( s.sTableId == this.id )
171				{
172					allSettings.splice( i, 1 );
173					break;
174				}
175			}
176			
177			/* Ensure the table has an ID - required for accessibility */
178			if ( sId === null || sId === "" )
179			{
180				sId = "DataTables_Table_"+(DataTable.ext._unique++);
181				this.id = sId;
182			}
183			
184			/* Create the settings object for this table and set some of the default parameters */
185			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
186				"sDestroyWidth": $this[0].style.width,
187				"sInstance":     sId,
188				"sTableId":      sId,
189				colgroup: $('<colgroup>').prependTo(this),
190				fastData: function (row, column, type) {
191					return _fnGetCellData(oSettings, row, column, type);
192				}
193			} );
194			oSettings.nTable = this;
195			oSettings.oInit  = oInit;
196			
197			allSettings.push( oSettings );
198			
199			// Make a single API instance available for internal handling
200			oSettings.api = new _Api( oSettings );
201			
202			// Need to add the instance after the instance after the settings object has been added
203			// to the settings array, so we can self reference the table instance if more than one
204			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
205			
206			// Backwards compatibility, before we apply all the defaults
207			_fnCompatOpts( oInit );
208			
209			// If the length menu is given, but the init display length is not, use the length menu
210			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
211			{
212				oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
213					? oInit.aLengthMenu[0][0]
214					: $.isPlainObject( oInit.aLengthMenu[0] )
215						? oInit.aLengthMenu[0].value
216						: oInit.aLengthMenu[0];
217			}
218			
219			// Apply the defaults and init options to make a single init object will all
220			// options defined from defaults and instance options.
221			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
222			
223			
224			// Map the initialisation options onto the settings object
225			_fnMap( oSettings.oFeatures, oInit, [
226				"bPaginate",
227				"bLengthChange",
228				"bFilter",
229				"bSort",
230				"bSortMulti",
231				"bInfo",
232				"bProcessing",
233				"bAutoWidth",
234				"bSortClasses",
235				"bServerSide",
236				"bDeferRender"
237			] );
238			_fnMap( oSettings, oInit, [
239				"ajax",
240				"fnFormatNumber",
241				"sServerMethod",
242				"aaSorting",
243				"aaSortingFixed",
244				"aLengthMenu",
245				"sPaginationType",
246				"iStateDuration",
247				"bSortCellsTop",
248				"iTabIndex",
249				"sDom",
250				"fnStateLoadCallback",
251				"fnStateSaveCallback",
252				"renderer",
253				"searchDelay",
254				"rowId",
255				"caption",
256				"layout",
257				[ "iCookieDuration", "iStateDuration" ], // backwards compat
258				[ "oSearch", "oPreviousSearch" ],
259				[ "aoSearchCols", "aoPreSearchCols" ],
260				[ "iDisplayLength", "_iDisplayLength" ]
261			] );
262			_fnMap( oSettings.oScroll, oInit, [
263				[ "sScrollX", "sX" ],
264				[ "sScrollXInner", "sXInner" ],
265				[ "sScrollY", "sY" ],
266				[ "bScrollCollapse", "bCollapse" ]
267			] );
268			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
269			
270			/* Callback functions which are array driven */
271			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback );
272			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams );
273			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams );
274			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded );
275			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback );
276			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
277			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback );
278			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback );
279			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete );
280			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback );
281			
282			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
283			
284			/* Browser support detection */
285			_fnBrowserDetect( oSettings );
286			
287			var oClasses = oSettings.oClasses;
288			
289			$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
290			$this.addClass( oClasses.table );
291			
292			if (! oSettings.oFeatures.bPaginate) {
293				oInit.iDisplayStart = 0;
294			}
295			
296			if ( oSettings.iInitDisplayStart === undefined )
297			{
298				/* Display start point, taking into account the save saving */
299				oSettings.iInitDisplayStart = oInit.iDisplayStart;
300				oSettings._iDisplayStart = oInit.iDisplayStart;
301			}
302			
303			/* Language definitions */
304			var oLanguage = oSettings.oLanguage;
305			$.extend( true, oLanguage, oInit.oLanguage );
306			
307			if ( oLanguage.sUrl )
308			{
309				/* Get the language definitions from a file - because this Ajax call makes the language
310				 * get async to the remainder of this function we use bInitHandedOff to indicate that
311				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
312				 */
313				$.ajax( {
314					dataType: 'json',
315					url: oLanguage.sUrl,
316					success: function ( json ) {
317						_fnCamelToHungarian( defaults.oLanguage, json );
318						$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
319			
320						_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
321						_fnInitialise( oSettings );
322					},
323					error: function () {
324						// Error occurred loading language file
325						_fnLog( oSettings, 0, 'i18n file loading error', 21 );
326			
327						// continue on as best we can
328						_fnInitialise( oSettings );
329					}
330				} );
331				bInitHandedOff = true;
332			}
333			else {
334				_fnCallbackFire( oSettings, null, 'i18n', [oSettings]);
335			}
336			
337			/*
338			 * Columns
339			 * See if we should load columns automatically or use defined ones
340			 */
341			var columnsInit = [];
342			var thead = this.getElementsByTagName('thead');
343			var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
344			
345			// If we don't have a columns array, then generate one with nulls
346			if ( oInit.aoColumns ) {
347				columnsInit = oInit.aoColumns;
348			}
349			else if ( initHeaderLayout.length ) {
350				for ( i=0, iLen=initHeaderLayout[0].length ; i<iLen ; i++ ) {
351					columnsInit.push( null );
352				}
353			}
354			
355			// Add the columns
356			for ( i=0, iLen=columnsInit.length ; i<iLen ; i++ ) {
357				_fnAddColumn( oSettings );
358			}
359			
360			// Apply the column definitions
361			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
362				_fnColumnOptions( oSettings, iCol, oDef );
363			} );
364			
365			/* HTML5 attribute detection - build an mData object automatically if the
366			 * attributes are found
367			 */
368			var rowOne = $this.children('tbody').find('tr').eq(0);
369			
370			if ( rowOne.length ) {
371				var a = function ( cell, name ) {
372					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
373				};
374			
375				$( rowOne[0] ).children('th, td').each( function (i, cell) {
376					var col = oSettings.aoColumns[i];
377			
378					if (! col) {
379						_fnLog( oSettings, 0, 'Incorrect column count', 18 );
380					}
381			
382					if ( col.mData === i ) {
383						var sort = a( cell, 'sort' ) || a( cell, 'order' );
384						var filter = a( cell, 'filter' ) || a( cell, 'search' );
385			
386						if ( sort !== null || filter !== null ) {
387							col.mData = {
388								_:      i+'.display',
389								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
390								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
391								filter: filter !== null ? i+'.@data-'+filter : undefined
392							};
393							col._isArrayHost = true;
394			
395							_fnColumnOptions( oSettings, i );
396						}
397					}
398				} );
399			}
400			
401			var features = oSettings.oFeatures;
402			var loadedInit = function () {
403				/*
404				 * Sorting
405				 * @todo For modularisation (1.11) this needs to do into a sort start up handler
406				 */
407			
408				// If aaSorting is not defined, then we use the first indicator in asSorting
409				// in case that has been altered, so the default sort reflects that option
410				if ( oInit.aaSorting === undefined ) {
411					var sorting = oSettings.aaSorting;
412					for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
413						sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
414					}
415				}
416			
417				/* Do a first pass on the sorting classes (allows any size changes to be taken into
418				 * account, and also will apply sorting disabled classes if disabled
419				 */
420				_fnSortingClasses( oSettings );
421			
422				_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
423					if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
424						_fnSortingClasses( oSettings );
425					}
426				} );
427			
428			
429				/*
430				 * Final init
431				 * Cache the header, body and footer as required, creating them if needed
432				 */
433				var caption = $this.children('caption');
434			
435				if ( oSettings.caption ) {
436					if ( caption.length === 0 ) {
437						caption = $('<caption/>').appendTo( $this );
438					}
439			
440					caption.html( oSettings.caption );
441				}
442			
443				// Store the caption side, so we can remove the element from the document
444				// when creating the element
445				if (caption.length) {
446					caption[0]._captionSide = caption.css('caption-side');
447					oSettings.captionNode = caption[0];
448				}
449			
450				if ( thead.length === 0 ) {
451					thead = $('<thead/>').appendTo($this);
452				}
453				oSettings.nTHead = thead[0];
454				$('tr', thead).addClass(oClasses.thead.row);
455			
456				var tbody = $this.children('tbody');
457				if ( tbody.length === 0 ) {
458					tbody = $('<tbody/>').insertAfter(thead);
459				}
460				oSettings.nTBody = tbody[0];
461			
462				var tfoot = $this.children('tfoot');
463				if ( tfoot.length === 0 ) {
464					// If we are a scrolling table, and no footer has been given, then we need to create
465					// a tfoot element for the caption element to be appended to
466					tfoot = $('<tfoot/>').appendTo($this);
467				}
468				oSettings.nTFoot = tfoot[0];
469				$('tr', tfoot).addClass(oClasses.tfoot.row);
470			
471				// Check if there is data passing into the constructor
472				if ( oInit.aaData ) {
473					for ( i=0 ; i<oInit.aaData.length ; i++ ) {
474						_fnAddData( oSettings, oInit.aaData[ i ] );
475					}
476				}
477				else if ( _fnDataSource( oSettings ) == 'dom' ) {
478					// Grab the data from the page
479					_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
480				}
481			
482				/* Copy the data index array */
483				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
484			
485				/* Initialisation complete - table can be drawn */
486				oSettings.bInitialised = true;
487			
488				/* Check if we need to initialise the table (it might not have been handed off to the
489				 * language processor)
490				 */
491				if ( bInitHandedOff === false ) {
492					_fnInitialise( oSettings );
493				}
494			};
495			
496			/* Must be done after everything which can be overridden by the state saving! */
497			_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState );
498			
499			if ( oInit.bStateSave )
500			{
501				features.bStateSave = true;
502				_fnLoadState( oSettings, oInit, loadedInit );
503			}
504			else {
505				loadedInit();
506			}
507			
508		} );
509		_that = null;
510		return this;
511	};
512	
513	
514	
515	/**
516	 * DataTables extensions
517	 * 
518	 * This namespace acts as a collection area for plug-ins that can be used to
519	 * extend DataTables capabilities. Indeed many of the build in methods
520	 * use this method to provide their own capabilities (sorting methods for
521	 * example).
522	 *
523	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
524	 * reasons
525	 *
526	 *  @namespace
527	 */
528	DataTable.ext = _ext = {
529		/**
530		 * Buttons. For use with the Buttons extension for DataTables. This is
531		 * defined here so other extensions can define buttons regardless of load
532		 * order. It is _not_ used by DataTables core.
533		 *
534		 *  @type object
535		 *  @default {}
536		 */
537		buttons: {},
538	
539	
540		/**
541		 * Element class names
542		 *
543		 *  @type object
544		 *  @default {}
545		 */
546		classes: {},
547	
548	
549		/**
550		 * DataTables build type (expanded by the download builder)
551		 *
552		 *  @type string
553		 */
554		builder: "-source-",
555	
556	
557		/**
558		 * Error reporting.
559		 * 
560		 * How should DataTables report an error. Can take the value 'alert',
561		 * 'throw', 'none' or a function.
562		 *
563		 *  @type string|function
564		 *  @default alert
565		 */
566		errMode: "alert",
567	
568	
569		/**
570		 * Legacy so v1 plug-ins don't throw js errors on load
571		 */
572		feature: [],
573	
574		/**
575		 * Feature plug-ins.
576		 * 
577		 * This is an object of callbacks which provide the features for DataTables
578		 * to be initialised via the `layout` option.
579		 */
580		features: {},
581	
582	
583		/**
584		 * Row searching.
585		 * 
586		 * This method of searching is complimentary to the default type based
587		 * searching, and a lot more comprehensive as it allows you complete control
588		 * over the searching logic. Each element in this array is a function
589		 * (parameters described below) that is called for every row in the table,
590		 * and your logic decides if it should be included in the searching data set
591		 * or not.
592		 *
593		 * Searching functions have the following input parameters:
594		 *
595		 * 1. `{object}` DataTables settings object: see
596		 *    {@link DataTable.models.oSettings}
597		 * 2. `{array|object}` Data for the row to be processed (same as the
598		 *    original format that was passed in as the data source, or an array
599		 *    from a DOM data source
600		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
601		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
602		 *
603		 * And the following return is expected:
604		 *
605		 * * {boolean} Include the row in the searched result set (true) or not
606		 *   (false)
607		 *
608		 * Note that as with the main search ability in DataTables, technically this
609		 * is "filtering", since it is subtractive. However, for consistency in
610		 * naming we call it searching here.
611		 *
612		 *  @type array
613		 *  @default []
614		 *
615		 *  @example
616		 *    // The following example shows custom search being applied to the
617		 *    // fourth column (i.e. the data[3] index) based on two input values
618		 *    // from the end-user, matching the data in a certain range.
619		 *    $.fn.dataTable.ext.search.push(
620		 *      function( settings, data, dataIndex ) {
621		 *        var min = document.getElementById('min').value * 1;
622		 *        var max = document.getElementById('max').value * 1;
623		 *        var version = data[3] == "-" ? 0 : data[3]*1;
624		 *
625		 *        if ( min == "" && max == "" ) {
626		 *          return true;
627		 *        }
628		 *        else if ( min == "" && version < max ) {
629		 *          return true;
630		 *        }
631		 *        else if ( min < version && "" == max ) {
632		 *          return true;
633		 *        }
634		 *        else if ( min < version && version < max ) {
635		 *          return true;
636		 *        }
637		 *        return false;
638		 *      }
639		 *    );
640		 */
641		search: [],
642	
643	
644		/**
645		 * Selector extensions
646		 *
647		 * The `selector` option can be used to extend the options available for the
648		 * selector modifier options (`selector-modifier` object data type) that
649		 * each of the three built in selector types offer (row, column and cell +
650		 * their plural counterparts). For example the Select extension uses this
651		 * mechanism to provide an option to select only rows, columns and cells
652		 * that have been marked as selected by the end user (`{selected: true}`),
653		 * which can be used in conjunction with the existing built in selector
654		 * options.
655		 *
656		 * Each property is an array to which functions can be pushed. The functions
657		 * take three attributes:
658		 *
659		 * * Settings object for the host table
660		 * * Options object (`selector-modifier` object type)
661		 * * Array of selected item indexes
662		 *
663		 * The return is an array of the resulting item indexes after the custom
664		 * selector has been applied.
665		 *
666		 *  @type object
667		 */
668		selector: {
669			cell: [],
670			column: [],
671			row: []
672		},
673	
674	
675		/**
676		 * Legacy configuration options. Enable and disable legacy options that
677		 * are available in DataTables.
678		 *
679		 *  @type object
680		 */
681		legacy: {
682			/**
683			 * Enable / disable DataTables 1.9 compatible server-side processing
684			 * requests
685			 *
686			 *  @type boolean
687			 *  @default null
688			 */
689			ajax: null
690		},
691	
692	
693		/**
694		 * Pagination plug-in methods.
695		 * 
696		 * Each entry in this object is a function and defines which buttons should
697		 * be shown by the pagination rendering method that is used for the table:
698		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
699		 * buttons are displayed in the document, while the functions here tell it
700		 * what buttons to display. This is done by returning an array of button
701		 * descriptions (what each button will do).
702		 *
703		 * Pagination types (the four built in options and any additional plug-in
704		 * options defined here) can be used through the `paginationType`
705		 * initialisation parameter.
706		 *
707		 * The functions defined take two parameters:
708		 *
709		 * 1. `{int} page` The current page index
710		 * 2. `{int} pages` The number of pages in the table
711		 *
712		 * Each function is expected to return an array where each element of the
713		 * array can be one of:
714		 *
715		 * * `first` - Jump to first page when activated
716		 * * `last` - Jump to last page when activated
717		 * * `previous` - Show previous page when activated
718		 * * `next` - Show next page when activated
719		 * * `{int}` - Show page of the index given
720		 * * `{array}` - A nested array containing the above elements to add a
721		 *   containing 'DIV' element (might be useful for styling).
722		 *
723		 * Note that DataTables v1.9- used this object slightly differently whereby
724		 * an object with two functions would be defined for each plug-in. That
725		 * ability is still supported by DataTables 1.10+ to provide backwards
726		 * compatibility, but this option of use is now decremented and no longer
727		 * documented in DataTables 1.10+.
728		 *
729		 *  @type object
730		 *  @default {}
731		 *
732		 *  @example
733		 *    // Show previous, next and current page buttons only
734		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
735		 *      return [ 'previous', page, 'next' ];
736		 *    };
737		 */
738		pager: {},
739	
740	
741		renderer: {
742			pageButton: {},
743			header: {}
744		},
745	
746	
747		/**
748		 * Ordering plug-ins - custom data source
749		 * 
750		 * The extension options for ordering of data available here is complimentary
751		 * to the default type based ordering that DataTables typically uses. It
752		 * allows much greater control over the the data that is being used to
753		 * order a column, but is necessarily therefore more complex.
754		 * 
755		 * This type of ordering is useful if you want to do ordering based on data
756		 * live from the DOM (for example the contents of an 'input' element) rather
757		 * than just the static string that DataTables knows of.
758		 * 
759		 * The way these plug-ins work is that you create an array of the values you
760		 * wish to be ordering for the column in question and then return that
761		 * array. The data in the array much be in the index order of the rows in
762		 * the table (not the currently ordering order!). Which order data gathering
763		 * function is run here depends on the `dt-init columns.orderDataType`
764		 * parameter that is used for the column (if any).
765		 *
766		 * The functions defined take two parameters:
767		 *
768		 * 1. `{object}` DataTables settings object: see
769		 *    {@link DataTable.models.oSettings}
770		 * 2. `{int}` Target column index
771		 *
772		 * Each function is expected to return an array:
773		 *
774		 * * `{array}` Data for the column to be ordering upon
775		 *
776		 *  @type array
777		 *
778		 *  @example
779		 *    // Ordering using `input` node values
780		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
781		 *    {
782		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
783		 *        return $('input', td).val();
784		 *      } );
785		 *    }
786		 */
787		order: {},
788	
789	
790		/**
791		 * Type based plug-ins.
792		 *
793		 * Each column in DataTables has a type assigned to it, either by automatic
794		 * detection or by direct assignment using the `type` option for the column.
795		 * The type of a column will effect how it is ordering and search (plug-ins
796		 * can also make use of the column type if required).
797		 *
798		 * @namespace
799		 */
800		type: {
801			/**
802			 * Automatic column class assignment
803			 */
804			className: {},
805	
806			/**
807			 * Type detection functions.
808			 *
809			 * The functions defined in this object are used to automatically detect
810			 * a column's type, making initialisation of DataTables super easy, even
811			 * when complex data is in the table.
812			 *
813			 * The functions defined take two parameters:
814			 *
815		     *  1. `{*}` Data from the column cell to be analysed
816		     *  2. `{settings}` DataTables settings object. This can be used to
817		     *     perform context specific type detection - for example detection
818		     *     based on language settings such as using a comma for a decimal
819		     *     place. Generally speaking the options from the settings will not
820		     *     be required
821			 *
822			 * Each function is expected to return:
823			 *
824			 * * `{string|null}` Data type detected, or null if unknown (and thus
825			 *   pass it on to the other type detection functions.
826			 *
827			 *  @type array
828			 *
829			 *  @example
830			 *    // Currency type detection plug-in:
831			 *    $.fn.dataTable.ext.type.detect.push(
832			 *      function ( data, settings ) {
833			 *        // Check the numeric part
834			 *        if ( ! data.substring(1).match(/[0-9]/) ) {
835			 *          return null;
836			 *        }
837			 *
838			 *        // Check prefixed by currency
839			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
840			 *          return 'currency';
841			 *        }
842			 *        return null;
843			 *      }
844			 *    );
845			 */
846			detect: [],
847	
848			/**
849			 * Automatic renderer assignment
850			 */
851			render: {},
852	
853	
854			/**
855			 * Type based search formatting.
856			 *
857			 * The type based searching functions can be used to pre-format the
858			 * data to be search on. For example, it can be used to strip HTML
859			 * tags or to de-format telephone numbers for numeric only searching.
860			 *
861			 * Note that is a search is not defined for a column of a given type,
862			 * no search formatting will be performed.
863			 * 
864			 * Pre-processing of searching data plug-ins - When you assign the sType
865			 * for a column (or have it automatically detected for you by DataTables
866			 * or a type detection plug-in), you will typically be using this for
867			 * custom sorting, but it can also be used to provide custom searching
868			 * by allowing you to pre-processing the data and returning the data in
869			 * the format that should be searched upon. This is done by adding
870			 * functions this object with a parameter name which matches the sType
871			 * for that target column. This is the corollary of <i>afnSortData</i>
872			 * for searching data.
873			 *
874			 * The functions defined take a single parameter:
875			 *
876		     *  1. `{*}` Data from the column cell to be prepared for searching
877			 *
878			 * Each function is expected to return:
879			 *
880			 * * `{string|null}` Formatted string that will be used for the searching.
881			 *
882			 *  @type object
883			 *  @default {}
884			 *
885			 *  @example
886			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
887			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
888			 *    }
889			 */
890			search: {},
891	
892	
893			/**
894			 * Type based ordering.
895			 *
896			 * The column type tells DataTables what ordering to apply to the table
897			 * when a column is sorted upon. The order for each type that is defined,
898			 * is defined by the functions available in this object.
899			 *
900			 * Each ordering option can be described by three properties added to
901			 * this object:
902			 *
903			 * * `{type}-pre` - Pre-formatting function
904			 * * `{type}-asc` - Ascending order function
905			 * * `{type}-desc` - Descending order function
906			 *
907			 * All three can be used together, only `{type}-pre` or only
908			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
909			 * that only `{type}-pre` is used, as this provides the optimal
910			 * implementation in terms of speed, although the others are provided
911			 * for compatibility with existing Javascript sort functions.
912			 *
913			 * `{type}-pre`: Functions defined take a single parameter:
914			 *
915		     *  1. `{*}` Data from the column cell to be prepared for ordering
916			 *
917			 * And return:
918			 *
919			 * * `{*}` Data to be sorted upon
920			 *
921			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
922			 * functions, taking two parameters:
923			 *
924		     *  1. `{*}` Data to compare to the second parameter
925		     *  2. `{*}` Data to compare to the first parameter
926			 *
927			 * And returning:
928			 *
929			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
930			 *   than the second parameter, ===0 if the two parameters are equal and
931			 *   >0 if the first parameter should be sorted height than the second
932			 *   parameter.
933			 * 
934			 *  @type object
935			 *  @default {}
936			 *
937			 *  @example
938			 *    // Numeric ordering of formatted numbers with a pre-formatter
939			 *    $.extend( $.fn.dataTable.ext.type.order, {
940			 *      "string-pre": function(x) {
941			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
942			 *        return parseFloat( a );
943			 *      }
944			 *    } );
945			 *
946			 *  @example
947			 *    // Case-sensitive string ordering, with no pre-formatting method
948			 *    $.extend( $.fn.dataTable.ext.order, {
949			 *      "string-case-asc": function(x,y) {
950			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
951			 *      },
952			 *      "string-case-desc": function(x,y) {
953			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
954			 *      }
955			 *    } );
956			 */
957			order: {}
958		},
959	
960		/**
961		 * Unique DataTables instance counter
962		 *
963		 * @type int
964		 * @private
965		 */
966		_unique: 0,
967	
968	
969		//
970		// Depreciated
971		// The following properties are retained for backwards compatibility only.
972		// The should not be used in new projects and will be removed in a future
973		// version
974		//
975	
976		/**
977		 * Version check function.
978		 *  @type function
979		 *  @depreciated Since 1.10
980		 */
981		fnVersionCheck: DataTable.fnVersionCheck,
982	
983	
984		/**
985		 * Index for what 'this' index API functions should use
986		 *  @type int
987		 *  @deprecated Since v1.10
988		 */
989		iApiIndex: 0,
990	
991	
992		/**
993		 * Software version
994		 *  @type string
995		 *  @deprecated Since v1.10
996		 */
997		sVersion: DataTable.version
998	};
999	
1000	
1001	//
1002	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
1003	//
1004	$.extend( _ext, {
1005		afnFiltering: _ext.search,
1006		aTypes:       _ext.type.detect,
1007		ofnSearch:    _ext.type.search,
1008		oSort:        _ext.type.order,
1009		afnSortData:  _ext.order,
1010		aoFeatures:   _ext.feature,
1011		oStdClasses:  _ext.classes,
1012		oPagination:  _ext.pager
1013	} );
1014	
1015	
1016	$.extend( DataTable.ext.classes, {
1017		container: 'dt-container',
1018		empty: {
1019			row: 'dt-empty'
1020		},
1021		info: {
1022			container: 'dt-info'
1023		},
1024		length: {
1025			container: 'dt-length',
1026			select: 'dt-input'
1027		},
1028		order: {
1029			canAsc: 'dt-orderable-asc',
1030			canDesc: 'dt-orderable-desc',
1031			isAsc: 'dt-ordering-asc',
1032			isDesc: 'dt-ordering-desc',
1033			none: 'dt-orderable-none',
1034			position: 'sorting_'
1035		},
1036		processing: {
1037			container: 'dt-processing'
1038		},
1039		scrolling: {
1040			body: 'dt-scroll-body',
1041			container: 'dt-scroll',
1042			footer: {
1043				self: 'dt-scroll-foot',
1044				inner: 'dt-scroll-footInner'
1045			},
1046			header: {
1047				self: 'dt-scroll-head',
1048				inner: 'dt-scroll-headInner'
1049			}
1050		},
1051		search: {
1052			container: 'dt-search',
1053			input: 'dt-input'
1054		},
1055		table: 'dataTable',	
1056		tbody: {
1057			cell: '',
1058			row: ''
1059		},
1060		thead: {
1061			cell: '',
1062			row: ''
1063		},
1064		tfoot: {
1065			cell: '',
1066			row: ''
1067		},
1068		paging: {
1069			active: 'current',
1070			button: 'dt-paging-button',
1071			container: 'dt-paging',
1072			disabled: 'disabled'
1073		}
1074	} );
1075	
1076	
1077	/*
1078	 * It is useful to have variables which are scoped locally so only the
1079	 * DataTables functions can access them and they don't leak into global space.
1080	 * At the same time these functions are often useful over multiple files in the
1081	 * core and API, so we list, or at least document, all variables which are used
1082	 * by DataTables as private variables here. This also ensures that there is no
1083	 * clashing of variable names and that they can easily referenced for reuse.
1084	 */
1085	
1086	
1087	// Defined else where
1088	//  _selector_run
1089	//  _selector_opts
1090	//  _selector_row_indexes
1091	
1092	var _ext; // DataTable.ext
1093	var _Api; // DataTable.Api
1094	var _api_register; // DataTable.Api.register
1095	var _api_registerPlural; // DataTable.Api.registerPlural
1096	
1097	var _re_dic = {};
1098	var _re_new_lines = /[\r\n\u2028]/g;
1099	var _re_html = /<([^>]*>)/g;
1100	var _max_str_len = Math.pow(2, 28);
1101	
1102	// This is not strict ISO8601 - Date.parse() is quite lax, although
1103	// implementations differ between browsers.
1104	var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
1105	
1106	// Escape regular expression special characters
1107	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1108	
1109	// https://en.wikipedia.org/wiki/Foreign_exchange_market
1110	// - \u20BD - Russian ruble.
1111	// - \u20a9 - South Korean Won
1112	// - \u20BA - Turkish Lira
1113	// - \u20B9 - Indian Rupee
1114	// - R - Brazil (R$) and South Africa
1115	// - fr - Swiss Franc
1116	// - kr - Swedish krona, Norwegian krone and Danish krone
1117	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1118	// - Ƀ - Bitcoin
1119	// - Ξ - Ethereum
1120	//   standards as thousands separators.
1121	var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1122	
1123	
1124	var _empty = function ( d ) {
1125		return !d || d === true || d === '-' ? true : false;
1126	};
1127	
1128	
1129	var _intVal = function ( s ) {
1130		var integer = parseInt( s, 10 );
1131		return !isNaN(integer) && isFinite(s) ? integer : null;
1132	};
1133	
1134	// Convert from a formatted number with characters other than `.` as the
1135	// decimal place, to a Javascript number
1136	var _numToDecimal = function ( num, decimalPoint ) {
1137		// Cache created regular expressions for speed as this function is called often
1138		if ( ! _re_dic[ decimalPoint ] ) {
1139			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1140		}
1141		return typeof num === 'string' && decimalPoint !== '.' ?
1142			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1143			num;
1144	};
1145	
1146	
1147	var _isNumber = function ( d, decimalPoint, formatted ) {
1148		var type = typeof d;
1149		var strType = type === 'string';
1150	
1151		if ( type === 'number' || type === 'bigint') {
1152			return true;
1153		}
1154	
1155		// If empty return immediately so there must be a number if it is a
1156		// formatted string (this stops the string "k", or "kr", etc being detected
1157		// as a formatted number for currency
1158		if ( _empty( d ) ) {
1159			return true;
1160		}
1161	
1162		if ( decimalPoint && strType ) {
1163			d = _numToDecimal( d, decimalPoint );
1164		}
1165	
1166		if ( formatted && strType ) {
1167			d = d.replace( _re_formatted_numeric, '' );
1168		}
1169	
1170		return !isNaN( parseFloat(d) ) && isFinite( d );
1171	};
1172	
1173	
1174	// A string without HTML in it can be considered to be HTML still
1175	var _isHtml = function ( d ) {
1176		return _empty( d ) || typeof d === 'string';
1177	};
1178	
1179	// Is a string a number surrounded by HTML?
1180	var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1181		if ( _empty( d ) ) {
1182			return true;
1183		}
1184	
1185		// input and select strings mean that this isn't just a number
1186		if (typeof d === 'string' && d.match(/<(input|select)/i)) {
1187			return null;
1188		}
1189	
1190		var html = _isHtml( d );
1191		return ! html ?
1192			null :
1193			_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1194				true :
1195				null;
1196	};
1197	
1198	
1199	var _pluck = function ( a, prop, prop2 ) {
1200		var out = [];
1201		var i=0, ien=a.length;
1202	
1203		// Could have the test in the loop for slightly smaller code, but speed
1204		// is essential here
1205		if ( prop2 !== undefined ) {
1206			for ( ; i<ien ; i++ ) {
1207				if ( a[i] && a[i][ prop ] ) {
1208					out.push( a[i][ prop ][ prop2 ] );
1209				}
1210			}
1211		}
1212		else {
1213			for ( ; i<ien ; i++ ) {
1214				if ( a[i] ) {
1215					out.push( a[i][ prop ] );
1216				}
1217			}
1218		}
1219	
1220		return out;
1221	};
1222	
1223	
1224	// Basically the same as _pluck, but rather than looping over `a` we use `order`
1225	// as the indexes to pick from `a`
1226	var _pluck_order = function ( a, order, prop, prop2 )
1227	{
1228		var out = [];
1229		var i=0, ien=order.length;
1230	
1231		// Could have the test in the loop for slightly smaller code, but speed
1232		// is essential here
1233		if ( prop2 !== undefined ) {
1234			for ( ; i<ien ; i++ ) {
1235				if ( a[ order[i] ][ prop ] ) {
1236					out.push( a[ order[i] ][ prop ][ prop2 ] );
1237				}
1238			}
1239		}
1240		else {
1241			for ( ; i<ien ; i++ ) {
1242				if ( a[ order[i] ] ) {
1243					out.push( a[ order[i] ][ prop ] );
1244				}
1245			}
1246		}
1247	
1248		return out;
1249	};
1250	
1251	
1252	var _range = function ( len, start )
1253	{
1254		var out = [];
1255		var end;
1256	
1257		if ( start === undefined ) {
1258			start = 0;
1259			end = len;
1260		}
1261		else {
1262			end = start;
1263			start = len;
1264		}
1265	
1266		for ( var i=start ; i<end ; i++ ) {
1267			out.push( i );
1268		}
1269	
1270		return out;
1271	};
1272	
1273	
1274	var _removeEmpty = function ( a )
1275	{
1276		var out = [];
1277	
1278		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1279			if ( a[i] ) { // careful - will remove all falsy values!
1280				out.push( a[i] );
1281			}
1282		}
1283	
1284		return out;
1285	};
1286	
1287	// Replaceable function in api.util
1288	var _stripHtml = function (input) {
1289		// Irrelevant check to workaround CodeQL's false positive on the regex
1290		if (input.length > _max_str_len) {
1291			throw new Error('Exceeded max str len');
1292		}
1293	
1294		var previous;
1295	
1296		input = input.replace(_re_html, ''); // Complete tags
1297	
1298		// Safety for incomplete script tag - use do / while to ensure that
1299		// we get all instances
1300		do {
1301			previous = input;
1302			input = input.replace(/<script/i, '');
1303		} while (input !== previous);
1304	
1305		return previous;
1306	};
1307	
1308	// Replaceable function in api.util
1309	var _escapeHtml = function ( d ) {
1310		if (Array.isArray(d)) {
1311			d = d.join(',');
1312		}
1313	
1314		return typeof d === 'string' ?
1315			d
1316				.replace(/&/g, '&amp;')
1317				.replace(/</g, '&lt;')
1318				.replace(/>/g, '&gt;')
1319				.replace(/"/g, '&quot;') :
1320			d;
1321	};
1322	
1323	// Remove diacritics from a string by decomposing it and then removing
1324	// non-ascii characters
1325	var _normalize = function (str, both) {
1326		if (typeof str !== 'string') {
1327			return str;
1328		}
1329	
1330		// It is faster to just run `normalize` than it is to check if
1331		// we need to with a regex!
1332		var res = str.normalize("NFD");
1333	
1334		// Equally, here we check if a regex is needed or not
1335		return res.length !== str.length
1336			? (both === true ? str + ' ' : '' ) + res.replace(/[\u0300-\u036f]/g, "")
1337			: res;
1338	}
1339	
1340	/**
1341	 * Determine if all values in the array are unique. This means we can short
1342	 * cut the _unique method at the cost of a single loop. A sorted array is used
1343	 * to easily check the values.
1344	 *
1345	 * @param  {array} src Source array
1346	 * @return {boolean} true if all unique, false otherwise
1347	 * @ignore
1348	 */
1349	var _areAllUnique = function ( src ) {
1350		if ( src.length < 2 ) {
1351			return true;
1352		}
1353	
1354		var sorted = src.slice().sort();
1355		var last = sorted[0];
1356	
1357		for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1358			if ( sorted[i] === last ) {
1359				return false;
1360			}
1361	
1362			last = sorted[i];
1363		}
1364	
1365		return true;
1366	};
1367	
1368	
1369	/**
1370	 * Find the unique elements in a source array.
1371	 *
1372	 * @param  {array} src Source array
1373	 * @return {array} Array of unique items
1374	 * @ignore
1375	 */
1376	var _unique = function ( src )
1377	{
1378		if (Array.from && Set) {
1379			return Array.from(new Set(src));
1380		}
1381	
1382		if ( _areAllUnique( src ) ) {
1383			return src.slice();
1384		}
1385	
1386		// A faster unique method is to use object keys to identify used values,
1387		// but this doesn't work with arrays or objects, which we must also
1388		// consider. See jsperf.app/compare-array-unique-versions/4 for more
1389		// information.
1390		var
1391			out = [],
1392			val,
1393			i, ien=src.length,
1394			j, k=0;
1395	
1396		again: for ( i=0 ; i<ien ; i++ ) {
1397			val = src[i];
1398	
1399			for ( j=0 ; j<k ; j++ ) {
1400				if ( out[j] === val ) {
1401					continue again;
1402				}
1403			}
1404	
1405			out.push( val );
1406			k++;
1407		}
1408	
1409		return out;
1410	};
1411	
1412	// Surprisingly this is faster than [].concat.apply
1413	// https://jsperf.com/flatten-an-array-loop-vs-reduce/2
1414	var _flatten = function (out, val) {
1415		if (Array.isArray(val)) {
1416			for (var i=0 ; i<val.length ; i++) {
1417				_flatten(out, val[i]);
1418			}
1419		}
1420		else {
1421			out.push(val);
1422		}
1423	
1424		return out;
1425	}
1426	
1427	// Similar to jQuery's addClass, but use classList.add
1428	function _addClass(el, name) {
1429		if (name) {
1430			name.split(' ').forEach(function (n) {
1431				if (n) {
1432					// `add` does deduplication, so no need to check `contains`
1433					el.classList.add(n);
1434				}
1435			});
1436		}
1437	}
1438	
1439	/**
1440	 * DataTables utility methods
1441	 * 
1442	 * This namespace provides helper methods that DataTables uses internally to
1443	 * create a DataTable, but which are not exclusively used only for DataTables.
1444	 * These methods can be used by extension authors to save the duplication of
1445	 * code.
1446	 *
1447	 *  @namespace
1448	 */
1449	DataTable.util = {
1450		/**
1451		 * Return a string with diacritic characters decomposed
1452		 * @param {*} mixed Function or string to normalize
1453		 * @param {*} both Return original string and the normalized string
1454		 * @returns String or undefined
1455		 */
1456		diacritics: function (mixed, both) {
1457			var type = typeof mixed;
1458	
1459			if (type !== 'function') {
1460				return _normalize(mixed, both);
1461			}
1462			_normalize = mixed;
1463		},
1464	
1465		/**
1466		 * Debounce a function
1467		 *
1468		 * @param {function} fn Function to be called
1469		 * @param {integer} freq Call frequency in mS
1470		 * @return {function} Wrapped function
1471		 */
1472		debounce: function ( fn, timeout ) {
1473			var timer;
1474	
1475			return function () {
1476				var that = this;
1477				var args = arguments;
1478	
1479				clearTimeout(timer);
1480	
1481				timer = setTimeout( function () {
1482					fn.apply(that, args);
1483				}, timeout || 250 );
1484			};
1485		},
1486	
1487		/**
1488		 * Throttle the calls to a function. Arguments and context are maintained
1489		 * for the throttled function.
1490		 *
1491		 * @param {function} fn Function to be called
1492		 * @param {integer} freq Call frequency in mS
1493		 * @return {function} Wrapped function
1494		 */
1495		throttle: function ( fn, freq ) {
1496			var
1497				frequency = freq !== undefined ? freq : 200,
1498				last,
1499				timer;
1500	
1501			return function () {
1502				var
1503					that = this,
1504					now  = +new Date(),
1505					args = arguments;
1506	
1507				if ( last && now < last + frequency ) {
1508					clearTimeout( timer );
1509	
1510					timer = setTimeout( function () {
1511						last = undefined;
1512						fn.apply( that, args );
1513					}, frequency );
1514				}
1515				else {
1516					last = now;
1517					fn.apply( that, args );
1518				}
1519			};
1520		},
1521	
1522		/**
1523		 * Escape a string such that it can be used in a regular expression
1524		 *
1525		 *  @param {string} val string to escape
1526		 *  @returns {string} escaped string
1527		 */
1528		escapeRegex: function ( val ) {
1529			return val.replace( _re_escape_regex, '\\$1' );
1530		},
1531	
1532		/**
1533		 * Create a function that will write to a nested object or array
1534		 * @param {*} source JSON notation string
1535		 * @returns Write function
1536		 */
1537		set: function ( source ) {
1538			if ( $.isPlainObject( source ) ) {
1539				/* Unlike get, only the underscore (global) option is used for for
1540				 * setting data since we don't know the type here. This is why an object
1541				 * option is not documented for `mData` (which is read/write), but it is
1542				 * for `mRender` which is read only.
1543				 */
1544				return DataTable.util.set( source._ );
1545			}
1546			else if ( source === null ) {
1547				// Nothing to do when the data source is null
1548				return function () {};
1549			}
1550			else if ( typeof source === 'function' ) {
1551				return function (data, val, meta) {
1552					source( data, 'set', val, meta );
1553				};
1554			}
1555			else if (
1556				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1557				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1558			) {
1559				// Like the get, we need to get data from a nested object
1560				var setData = function (data, val, src) {
1561					var a = _fnSplitObjNotation( src ), b;
1562					var aLast = a[a.length-1];
1563					var arrayNotation, funcNotation, o, innerSrc;
1564		
1565					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {
1566						// Protect against prototype pollution
1567						if (a[i] === '__proto__' || a[i] === 'constructor') {
1568							throw new Error('Cannot set prototype values');
1569						}
1570		
1571						// Check if we are dealing with an array notation request
1572						arrayNotation = a[i].match(__reArray);
1573						funcNotation = a[i].match(__reFn);
1574		
1575						if ( arrayNotation ) {
1576							a[i] = a[i].replace(__reArray, '');
1577							data[ a[i] ] = [];
1578		
1579							// Get the remainder of the nested object to set so we can recurse
1580							b = a.slice();
1581							b.splice( 0, i+1 );
1582							innerSrc = b.join('.');
1583		
1584							// Traverse each entry in the array setting the properties requested
1585							if ( Array.isArray( val ) ) {
1586								for ( var j=0, jLen=val.length ; j<jLen ; j++ ) {
1587									o = {};
1588									setData( o, val[j], innerSrc );
1589									data[ a[i] ].push( o );
1590								}
1591							}
1592							else {
1593								// We've been asked to save data to an array, but it
1594								// isn't array data to be saved. Best that can be done
1595								// is to just save the value.
1596								data[ a[i] ] = val;
1597							}
1598		
1599							// The inner call to setData has already traversed through the remainder
1600							// of the source and has set the data, thus we can exit here
1601							return;
1602						}
1603						else if ( funcNotation ) {
1604							// Function call
1605							a[i] = a[i].replace(__reFn, '');
1606							data = data[ a[i] ]( val );
1607						}
1608		
1609						// If the nested object doesn't currently exist - since we are
1610						// trying to set the value - create it
1611						if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {
1612							data[ a[i] ] = {};
1613						}
1614						data = data[ a[i] ];
1615					}
1616		
1617					// Last item in the input - i.e, the actual set
1618					if ( aLast.match(__reFn ) ) {
1619						// Function call
1620						data = data[ aLast.replace(__reFn, '') ]( val );
1621					}
1622					else {
1623						// If array notation is used, we just want to strip it and use the property name
1624						// and assign the value. If it isn't used, then we get the result we want anyway
1625						data[ aLast.replace(__reArray, '') ] = val;
1626					}
1627				};
1628		
1629				return function (data, val) { // meta is also passed in, but not used
1630					return setData( data, val, source );
1631				};
1632			}
1633			else {
1634				// Array or flat object mapping
1635				return function (data, val) { // meta is also passed in, but not used
1636					data[source] = val;
1637				};
1638			}
1639		},
1640	
1641		/**
1642		 * Create a function that will read nested objects from arrays, based on JSON notation
1643		 * @param {*} source JSON notation string
1644		 * @returns Value read
1645		 */
1646		get: function ( source ) {
1647			if ( $.isPlainObject( source ) ) {
1648				// Build an object of get functions, and wrap them in a single call
1649				var o = {};
1650				$.each( source, function (key, val) {
1651					if ( val ) {
1652						o[key] = DataTable.util.get( val );
1653					}
1654				} );
1655		
1656				return function (data, type, row, meta) {
1657					var t = o[type] || o._;
1658					return t !== undefined ?
1659						t(data, type, row, meta) :
1660						data;
1661				};
1662			}
1663			else if ( source === null ) {
1664				// Give an empty string for rendering / sorting etc
1665				return function (data) { // type, row and meta also passed, but not used
1666					return data;
1667				};
1668			}
1669			else if ( typeof source === 'function' ) {
1670				return function (data, type, row, meta) {
1671					return source( data, type, row, meta );
1672				};
1673			}
1674			else if (
1675				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1676				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1677			) {
1678				/* If there is a . in the source string then the data source is in a
1679				 * nested object so we loop over the data for each level to get the next
1680				 * level down. On each loop we test for undefined, and if found immediately
1681				 * return. This allows entire objects to be missing and sDefaultContent to
1682				 * be used if defined, rather than throwing an error
1683				 */
1684				var fetchData = function (data, type, src) {
1685					var arrayNotation, funcNotation, out, innerSrc;
1686		
1687					if ( src !== "" ) {
1688						var a = _fnSplitObjNotation( src );
1689		
1690						for ( var i=0, iLen=a.length ; i<iLen ; i++ ) {
1691							// Check if we are dealing with special notation
1692							arrayNotation = a[i].match(__reArray);
1693							funcNotation = a[i].match(__reFn);
1694		
1695							if ( arrayNotation ) {
1696								// Array notation
1697								a[i] = a[i].replace(__reArray, '');
1698		
1699								// Condition allows simply [] to be passed in
1700								if ( a[i] !== "" ) {
1701									data = data[ a[i] ];
1702								}
1703								out = [];
1704		
1705								// Get the remainder of the nested object to get
1706								a.splice( 0, i+1 );
1707								innerSrc = a.join('.');
1708		
1709								// Traverse each entry in the array getting the properties requested
1710								if ( Array.isArray( data ) ) {
1711									for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1712										out.push( fetchData( data[j], type, innerSrc ) );
1713									}
1714								}
1715		
1716								// If a string is given in between the array notation indicators, that
1717								// is used to join the strings together, otherwise an array is returned
1718								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1719								data = (join==="") ? out : out.join(join);
1720		
1721								// The inner call to fetchData has already traversed through the remainder
1722								// of the source requested, so we exit from the loop
1723								break;
1724							}
1725							else if ( funcNotation ) {
1726								// Function call
1727								a[i] = a[i].replace(__reFn, '');
1728								data = data[ a[i] ]();
1729								continue;
1730							}
1731		
1732							if (data === null || data[ a[i] ] === null) {
1733								return null;
1734							}
1735							else if ( data === undefined || data[ a[i] ] === undefined ) {
1736								return undefined;
1737							}
1738	
1739							data = data[ a[i] ];
1740						}
1741					}
1742		
1743					return data;
1744				};
1745		
1746				return function (data, type) { // row and meta also passed, but not used
1747					return fetchData( data, type, source );
1748				};
1749			}
1750			else {
1751				// Array or flat object mapping
1752				return function (data) { // row and meta also passed, but not used
1753					return data[source];
1754				};
1755			}
1756		},
1757	
1758		stripHtml: function (mixed) {
1759			var type = typeof mixed;
1760	
1761			if (type === 'function') {
1762				_stripHtml = mixed;
1763				return;
1764			}
1765			else if (type === 'string') {
1766				return _stripHtml(mixed);
1767			}
1768			return mixed;
1769		},
1770	
1771		escapeHtml: function (mixed) {
1772			var type = typeof mixed;
1773	
1774			if (type === 'function') {
1775				_escapeHtml = mixed;
1776				return;
1777			}
1778			else if (type === 'string' || Array.isArray(mixed)) {
1779				return _escapeHtml(mixed);
1780			}
1781			return mixed;
1782		},
1783	
1784		unique: _unique
1785	};
1786	
1787	
1788	
1789	/**
1790	 * Create a mapping object that allows camel case parameters to be looked up
1791	 * for their Hungarian counterparts. The mapping is stored in a private
1792	 * parameter called `_hungarianMap` which can be accessed on the source object.
1793	 *  @param {object} o
1794	 *  @memberof DataTable#oApi
1795	 */
1796	function _fnHungarianMap ( o )
1797	{
1798		var
1799			hungarian = 'a aa ai ao as b fn i m o s ',
1800			match,
1801			newKey,
1802			map = {};
1803	
1804		$.each( o, function (key) {
1805			match = key.match(/^([^A-Z]+?)([A-Z])/);
1806	
1807			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1808			{
1809				newKey = key.replace( match[0], match[2].toLowerCase() );
1810				map[ newKey ] = key;
1811	
1812				if ( match[1] === 'o' )
1813				{
1814					_fnHungarianMap( o[key] );
1815				}
1816			}
1817		} );
1818	
1819		o._hungarianMap = map;
1820	}
1821	
1822	
1823	/**
1824	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1825	 * created by _fnHungarianMap.
1826	 *  @param {object} src The model object which holds all parameters that can be
1827	 *    mapped.
1828	 *  @param {object} user The object to convert from camel case to Hungarian.
1829	 *  @param {boolean} force When set to `true`, properties which already have a
1830	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
1831	 *    won't be.
1832	 *  @memberof DataTable#oApi
1833	 */
1834	function _fnCamelToHungarian ( src, user, force )
1835	{
1836		if ( ! src._hungarianMap ) {
1837			_fnHungarianMap( src );
1838		}
1839	
1840		var hungarianKey;
1841	
1842		$.each( user, function (key) {
1843			hungarianKey = src._hungarianMap[ key ];
1844	
1845			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1846			{
1847				// For objects, we need to buzz down into the object to copy parameters
1848				if ( hungarianKey.charAt(0) === 'o' )
1849				{
1850					// Copy the camelCase options over to the hungarian
1851					if ( ! user[ hungarianKey ] ) {
1852						user[ hungarianKey ] = {};
1853					}
1854					$.extend( true, user[hungarianKey], user[key] );
1855	
1856					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1857				}
1858				else {
1859					user[hungarianKey] = user[ key ];
1860				}
1861			}
1862		} );
1863	}
1864	
1865	/**
1866	 * Map one parameter onto another
1867	 *  @param {object} o Object to map
1868	 *  @param {*} knew The new parameter name
1869	 *  @param {*} old The old parameter name
1870	 */
1871	var _fnCompatMap = function ( o, knew, old ) {
1872		if ( o[ knew ] !== undefined ) {
1873			o[ old ] = o[ knew ];
1874		}
1875	};
1876	
1877	
1878	/**
1879	 * Provide backwards compatibility for the main DT options. Note that the new
1880	 * options are mapped onto the old parameters, so this is an external interface
1881	 * change only.
1882	 *  @param {object} init Object to map
1883	 */
1884	function _fnCompatOpts ( init )
1885	{
1886		_fnCompatMap( init, 'ordering',      'bSort' );
1887		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
1888		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
1889		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1890		_fnCompatMap( init, 'order',         'aaSorting' );
1891		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
1892		_fnCompatMap( init, 'paging',        'bPaginate' );
1893		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
1894		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
1895		_fnCompatMap( init, 'searching',     'bFilter' );
1896	
1897		// Boolean initialisation of x-scrolling
1898		if ( typeof init.sScrollX === 'boolean' ) {
1899			init.sScrollX = init.sScrollX ? '100%' : '';
1900		}
1901		if ( typeof init.scrollX === 'boolean' ) {
1902			init.scrollX = init.scrollX ? '100%' : '';
1903		}
1904	
1905		// Column search objects are in an array, so it needs to be converted
1906		// element by element
1907		var searchCols = init.aoSearchCols;
1908	
1909		if ( searchCols ) {
1910			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1911				if ( searchCols[i] ) {
1912					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1913				}
1914			}
1915		}
1916	
1917		// Enable search delay if server-side processing is enabled
1918		if (init.serverSide && ! init.searchDelay) {
1919			init.searchDelay = 400;
1920		}
1921	}
1922	
1923	
1924	/**
1925	 * Provide backwards compatibility for column options. Note that the new options
1926	 * are mapped onto the old parameters, so this is an external interface change
1927	 * only.
1928	 *  @param {object} init Object to map
1929	 */
1930	function _fnCompatCols ( init )
1931	{
1932		_fnCompatMap( init, 'orderable',     'bSortable' );
1933		_fnCompatMap( init, 'orderData',     'aDataSort' );
1934		_fnCompatMap( init, 'orderSequence', 'asSorting' );
1935		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
1936	
1937		// orderData can be given as an integer
1938		var dataSort = init.aDataSort;
1939		if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {
1940			init.aDataSort = [ dataSort ];
1941		}
1942	}
1943	
1944	
1945	/**
1946	 * Browser feature detection for capabilities, quirks
1947	 *  @param {object} settings dataTables settings object
1948	 *  @memberof DataTable#oApi
1949	 */
1950	function _fnBrowserDetect( settings )
1951	{
1952		// We don't need to do this every time DataTables is constructed, the values
1953		// calculated are specific to the browser and OS configuration which we
1954		// don't expect to change between initialisations
1955		if ( ! DataTable.__browser ) {
1956			var browser = {};
1957			DataTable.__browser = browser;
1958	
1959			// Scrolling feature / quirks detection
1960			var n = $('<div/>')
1961				.css( {
1962					position: 'fixed',
1963					top: 0,
1964					left: -1 * window.pageXOffset, // allow for scrolling
1965					height: 1,
1966					width: 1,
1967					overflow: 'hidden'
1968				} )
1969				.append(
1970					$('<div/>')
1971						.css( {
1972							position: 'absolute',
1973							top: 1,
1974							left: 1,
1975							width: 100,
1976							overflow: 'scroll'
1977						} )
1978						.append(
1979							$('<div/>')
1980								.css( {
1981									width: '100%',
1982									height: 10
1983								} )
1984						)
1985				)
1986				.appendTo( 'body' );
1987	
1988			var outer = n.children();
1989			var inner = outer.children();
1990	
1991			// Get scrollbar width
1992			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1993	
1994			// In rtl text layout, some browsers (most, but not all) will place the
1995			// scrollbar on the left, rather than the right.
1996			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1997	
1998			n.remove();
1999		}
2000	
2001		$.extend( settings.oBrowser, DataTable.__browser );
2002		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
2003	}
2004	
2005	/**
2006	 * Add a column to the list used for the table with default values
2007	 *  @param {object} oSettings dataTables settings object
2008	 *  @memberof DataTable#oApi
2009	 */
2010	function _fnAddColumn( oSettings )
2011	{
2012		// Add column to aoColumns array
2013		var oDefaults = DataTable.defaults.column;
2014		var iCol = oSettings.aoColumns.length;
2015		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
2016			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
2017			"mData": oDefaults.mData ? oDefaults.mData : iCol,
2018			idx: iCol,
2019			searchFixed: {},
2020			colEl: $('<col>').attr('data-dt-column', iCol)
2021		} );
2022		oSettings.aoColumns.push( oCol );
2023	
2024		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
2025		// passed into extend can be undefined. This allows the user to give a default
2026		// with only some of the parameters defined, and also not give a default
2027		var searchCols = oSettings.aoPreSearchCols;
2028		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
2029	}
2030	
2031	
2032	/**
2033	 * Apply options for a column
2034	 *  @param {object} oSettings dataTables settings object
2035	 *  @param {int} iCol column index to consider
2036	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
2037	 *  @memberof DataTable#oApi
2038	 */
2039	function _fnColumnOptions( oSettings, iCol, oOptions )
2040	{
2041		var oCol = oSettings.aoColumns[ iCol ];
2042	
2043		/* User specified column options */
2044		if ( oOptions !== undefined && oOptions !== null )
2045		{
2046			// Backwards compatibility
2047			_fnCompatCols( oOptions );
2048	
2049			// Map camel case parameters to their Hungarian counterparts
2050			_fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
2051	
2052			/* Backwards compatibility for mDataProp */
2053			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2054			{
2055				oOptions.mData = oOptions.mDataProp;
2056			}
2057	
2058			if ( oOptions.sType )
2059			{
2060				oCol._sManualType = oOptions.sType;
2061			}
2062		
2063			// `class` is a reserved word in Javascript, so we need to provide
2064			// the ability to use a valid name for the camel case input
2065			if ( oOptions.className && ! oOptions.sClass )
2066			{
2067				oOptions.sClass = oOptions.className;
2068			}
2069	
2070			var origClass = oCol.sClass;
2071	
2072			$.extend( oCol, oOptions );
2073			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2074	
2075			// Merge class from previously defined classes with this one, rather than just
2076			// overwriting it in the extend above
2077			if (origClass !== oCol.sClass) {
2078				oCol.sClass = origClass + ' ' + oCol.sClass;
2079			}
2080	
2081			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
2082			 * priority if defined
2083			 */
2084			if ( oOptions.iDataSort !== undefined )
2085			{
2086				oCol.aDataSort = [ oOptions.iDataSort ];
2087			}
2088			_fnMap( oCol, oOptions, "aDataSort" );
2089		}
2090	
2091		/* Cache the data get and set functions for speed */
2092		var mDataSrc = oCol.mData;
2093		var mData = _fnGetObjectDataFn( mDataSrc );
2094	
2095		// The `render` option can be given as an array to access the helper rendering methods.
2096		// The first element is the rendering method to use, the rest are the parameters to pass
2097		if ( oCol.mRender && Array.isArray( oCol.mRender ) ) {
2098			var copy = oCol.mRender.slice();
2099			var name = copy.shift();
2100	
2101			oCol.mRender = DataTable.render[name].apply(window, copy);
2102		}
2103	
2104		oCol._render = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2105	
2106		var attrTest = function( src ) {
2107			return typeof src === 'string' && src.indexOf('@') !== -1;
2108		};
2109		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2110			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2111		);
2112		oCol._setter = null;
2113	
2114		oCol.fnGetData = function (rowData, type, meta) {
2115			var innerData = mData( rowData, type, undefined, meta );
2116	
2117			return oCol._render && type ?
2118				oCol._render( innerData, type, rowData, meta ) :
2119				innerData;
2120		};
2121		oCol.fnSetData = function ( rowData, val, meta ) {
2122			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2123		};
2124	
2125		// Indicate if DataTables should read DOM data as an object or array
2126		// Used in _fnGetRowElements
2127		if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) {
2128			oSettings._rowReadObject = true;
2129		}
2130	
2131		/* Feature sorting overrides column specific when off */
2132		if ( !oSettings.oFeatures.bSort )
2133		{
2134			oCol.bSortable = false;
2135		}
2136	}
2137	
2138	
2139	/**
2140	 * Adjust the table column widths for new data. Note: you would probably want to
2141	 * do a redraw after calling this function!
2142	 *  @param {object} settings dataTables settings object
2143	 *  @memberof DataTable#oApi
2144	 */
2145	function _fnAdjustColumnSizing ( settings )
2146	{
2147		_fnCalculateColumnWidths( settings );
2148		_fnColumnSizes( settings );
2149	
2150		var scroll = settings.oScroll;
2151		if ( scroll.sY !== '' || scroll.sX !== '') {
2152			_fnScrollDraw( settings );
2153		}
2154	
2155		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
2156	}
2157	
2158	/**
2159	 * Apply column sizes
2160	 *
2161	 * @param {*} settings DataTables settings object
2162	 */
2163	function _fnColumnSizes ( settings )
2164	{
2165		var cols = settings.aoColumns;
2166	
2167		for (var i=0 ; i<cols.length ; i++) {
2168			var width = _fnColumnsSumWidth(settings, [i], false, false);
2169	
2170			cols[i].colEl.css('width', width);
2171		}
2172	}
2173	
2174	
2175	/**
2176	 * Convert the index of a visible column to the index in the data array (take account
2177	 * of hidden columns)
2178	 *  @param {object} oSettings dataTables settings object
2179	 *  @param {int} iMatch Visible column index to lookup
2180	 *  @returns {int} i the data index
2181	 *  @memberof DataTable#oApi
2182	 */
2183	function _fnVisibleToColumnIndex( oSettings, iMatch )
2184	{
2185		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2186	
2187		return typeof aiVis[iMatch] === 'number' ?
2188			aiVis[iMatch] :
2189			null;
2190	}
2191	
2192	
2193	/**
2194	 * Convert the index of an index in the data array and convert it to the visible
2195	 *   column index (take account of hidden columns)
2196	 *  @param {int} iMatch Column index to lookup
2197	 *  @param {object} oSettings dataTables settings object
2198	 *  @returns {int} i the data index
2199	 *  @memberof DataTable#oApi
2200	 */
2201	function _fnColumnIndexToVisible( oSettings, iMatch )
2202	{
2203		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2204		var iPos = aiVis.indexOf(iMatch);
2205	
2206		return iPos !== -1 ? iPos : null;
2207	}
2208	
2209	
2210	/**
2211	 * Get the number of visible columns
2212	 *  @param {object} oSettings dataTables settings object
2213	 *  @returns {int} i the number of visible columns
2214	 *  @memberof DataTable#oApi
2215	 */
2216	function _fnVisbleColumns( settings )
2217	{
2218		var layout = settings.aoHeader;
2219		var columns = settings.aoColumns;
2220		var vis = 0;
2221	
2222		if ( layout.length ) {
2223			for ( var i=0, ien=layout[0].length ; i<ien ; i++ ) {
2224				if ( columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none' ) {
2225					vis++;
2226				}
2227			}
2228		}
2229	
2230		return vis;
2231	}
2232	
2233	
2234	/**
2235	 * Get an array of column indexes that match a given property
2236	 *  @param {object} oSettings dataTables settings object
2237	 *  @param {string} sParam Parameter in aoColumns to look for - typically
2238	 *    bVisible or bSearchable
2239	 *  @returns {array} Array of indexes with matched properties
2240	 *  @memberof DataTable#oApi
2241	 */
2242	function _fnGetColumns( oSettings, sParam )
2243	{
2244		var a = [];
2245	
2246		oSettings.aoColumns.map( function(val, i) {
2247			if ( val[sParam] ) {
2248				a.push( i );
2249			}
2250		} );
2251	
2252		return a;
2253	}
2254	
2255	
2256	/**
2257	 * Calculate the 'type' of a column
2258	 *  @param {object} settings dataTables settings object
2259	 *  @memberof DataTable#oApi
2260	 */
2261	function _fnColumnTypes ( settings )
2262	{
2263		var columns = settings.aoColumns;
2264		var data = settings.aoData;
2265		var types = DataTable.ext.type.detect;
2266		var i, ien, j, jen, k, ken;
2267		var col, detectedType, cache;
2268	
2269		// For each column, spin over the 
2270		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2271			col = columns[i];
2272			cache = [];
2273	
2274			if ( ! col.sType && col._sManualType ) {
2275				col.sType = col._sManualType;
2276			}
2277			else if ( ! col.sType ) {
2278				for ( j=0, jen=types.length ; j<jen ; j++ ) {
2279					for ( k=0, ken=data.length ; k<ken ; k++ ) {
2280	
2281						if (! data[k]) {
2282							continue;
2283						}
2284	
2285						// Use a cache array so we only need to get the type data
2286						// from the formatter once (when using multiple detectors)
2287						if ( cache[k] === undefined ) {
2288							cache[k] = _fnGetCellData( settings, k, i, 'type' );
2289						}
2290	
2291						detectedType = types[j]( cache[k], settings );
2292	
2293						// If null, then this type can't apply to this column, so
2294						// rather than testing all cells, break out. There is an
2295						// exception for the last type which is `html`. We need to
2296						// scan all rows since it is possible to mix string and HTML
2297						// types
2298						if ( ! detectedType && j !== types.length-2 ) {
2299							break;
2300						}
2301	
2302						// Only a single match is needed for html type since it is
2303						// bottom of the pile and very similar to string - but it
2304						// must not be empty
2305						if ( detectedType === 'html' && ! _empty(cache[k]) ) {
2306							break;
2307						}
2308					}
2309	
2310					// Type is valid for all data points in the column - use this
2311					// type
2312					if ( detectedType ) {
2313						col.sType = detectedType;
2314						break;
2315					}
2316				}
2317	
2318				// Fall back - if no type was detected, always use string
2319				if ( ! col.sType ) {
2320					col.sType = 'string';
2321				}
2322			}
2323	
2324			// Set class names for header / footer for auto type classes
2325			var autoClass = _ext.type.className[col.sType];
2326	
2327			if (autoClass) {
2328				_columnAutoClass(settings.aoHeader, i, autoClass);
2329				_columnAutoClass(settings.aoFooter, i, autoClass);
2330			}
2331	
2332			var renderer = _ext.type.render[col.sType];
2333	
2334			// This can only happen once! There is no way to remover
2335			// a renderer. After the first time the renderer has
2336			// already been set so createTr will run the renderer itself.
2337			if (renderer && ! col._render) {
2338				col._render = DataTable.util.get(renderer);
2339	
2340				_columnAutoRender(settings, i);
2341			}
2342		}
2343	}
2344	
2345	/**
2346	 * Apply an auto detected renderer to data which doesn't yet have
2347	 * a renderer
2348	 */
2349	function _columnAutoRender(settings, colIdx) {
2350		var data = settings.aoData;
2351	
2352		for (var i=0 ; i<data.length ; i++) {
2353			if (data[i].nTr) {
2354				// We have to update the display here since there is no
2355				// invalidation check for the data
2356				var display = _fnGetCellData( settings, i, colIdx, 'display' );
2357	
2358				data[i].displayData[colIdx] = display;
2359				_fnWriteCell(data[i].anCells[colIdx], display);
2360	
2361				// No need to update sort / filter data since it has
2362				// been invalidated and will be re-read with the
2363				// renderer now applied
2364			}
2365		}
2366	}
2367	
2368	/**
2369	 * Apply a class name to a column's header cells
2370	 */
2371	function _columnAutoClass(container, colIdx, className) {
2372		container.forEach(function (row) {
2373			if (row[colIdx] && row[colIdx].unique) {
2374				_addClass(row[colIdx].cell, className);
2375			}
2376		});
2377	}
2378	
2379	/**
2380	 * Take the column definitions and static columns arrays and calculate how
2381	 * they relate to column indexes. The callback function will then apply the
2382	 * definition found for a column to a suitable configuration object.
2383	 *  @param {object} oSettings dataTables settings object
2384	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
2385	 *  @param {array} aoCols The aoColumns array that defines columns individually
2386	 *  @param {array} headerLayout Layout for header as it was loaded
2387	 *  @param {function} fn Callback function - takes two parameters, the calculated
2388	 *    column index and the definition for that column.
2389	 *  @memberof DataTable#oApi
2390	 */
2391	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, headerLayout, fn )
2392	{
2393		var i, iLen, j, jLen, k, kLen, def;
2394		var columns = oSettings.aoColumns;
2395	
2396		if ( aoCols ) {
2397			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2398				if (aoCols[i] && aoCols[i].name) {
2399					columns[i].sName = aoCols[i].name;
2400				}
2401			}
2402		}
2403	
2404		// Column definitions with aTargets
2405		if ( aoColDefs )
2406		{
2407			/* Loop over the definitions array - loop in reverse so first instance has priority */
2408			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2409			{
2410				def = aoColDefs[i];
2411	
2412				/* Each definition can target multiple columns, as it is an array */
2413				var aTargets = def.target !== undefined
2414					? def.target
2415					: def.targets !== undefined
2416						? def.targets
2417						: def.aTargets;
2418	
2419				if ( ! Array.isArray( aTargets ) )
2420				{
2421					aTargets = [ aTargets ];
2422				}
2423	
2424				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2425				{
2426					var target = aTargets[j];
2427	
2428					if ( typeof target === 'number' && target >= 0 )
2429					{
2430						/* Add columns that we don't yet know about */
2431						while( columns.length <= target )
2432						{
2433							_fnAddColumn( oSettings );
2434						}
2435	
2436						/* Integer, basic index */
2437						fn( target, def );
2438					}
2439					else if ( typeof target === 'number' && target < 0 )
2440					{
2441						/* Negative integer, right to left column counting */
2442						fn( columns.length+target, def );
2443					}
2444					else if ( typeof target === 'string' )
2445					{
2446						for ( k=0, kLen=columns.length ; k<kLen ; k++ ) {
2447							if (target === '_all') {
2448								// Apply to all columns
2449								fn( k, def );
2450							}
2451							else if (target.indexOf(':name') !== -1) {
2452								// Column selector
2453								if (columns[k].sName === target.replace(':name', '')) {
2454									fn( k, def );
2455								}
2456							}
2457							else {
2458								// Cell selector
2459								headerLayout.forEach(function (row) {
2460									if (row[k]) {
2461										var cell = $(row[k].cell);
2462	
2463										// Legacy support. Note that it means that we don't support
2464										// an element name selector only, since they are treated as
2465										// class names for 1.x compat.
2466										if (target.match(/^[a-z][\w-]*$/i)) {
2467											target = '.' + target;
2468										}
2469	
2470										if (cell.is( target )) {
2471											fn( k, def );
2472										}
2473									}
2474								});
2475							}
2476						}
2477					}
2478				}
2479			}
2480		}
2481	
2482		// Statically defined columns array
2483		if ( aoCols ) {
2484			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2485				fn( i, aoCols[i] );
2486			}
2487		}
2488	}
2489	
2490	
2491	/**
2492	 * Get the width for a given set of columns
2493	 *
2494	 * @param {*} settings DataTables settings object
2495	 * @param {*} targets Columns - comma separated string or array of numbers
2496	 * @param {*} original Use the original width (true) or calculated (false)
2497	 * @param {*} incVisible Include visible columns (true) or not (false)
2498	 * @returns Combined CSS value
2499	 */
2500	function _fnColumnsSumWidth( settings, targets, original, incVisible ) {
2501		if ( ! Array.isArray( targets ) ) {
2502			targets = _fnColumnsFromHeader( targets );
2503		}
2504	
2505		var sum = 0;
2506		var unit;
2507		var columns = settings.aoColumns;
2508		
2509		for ( var i=0, ien=targets.length ; i<ien ; i++ ) {
2510			var column = columns[ targets[i] ];
2511			var definedWidth = original ?
2512				column.sWidthOrig :
2513				column.sWidth;
2514	
2515			if ( ! incVisible && column.bVisible === false ) {
2516				continue;
2517			}
2518	
2519			if ( definedWidth === null || definedWidth === undefined ) {
2520				return null; // can't determine a defined width - browser defined
2521			}
2522			else if ( typeof definedWidth === 'number' ) {
2523				unit = 'px';
2524				sum += definedWidth;
2525			}
2526			else {
2527				var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
2528	
2529				if ( matched ) {
2530					sum += matched[1] * 1;
2531					unit = matched.length === 3 ?
2532						matched[2] :
2533						'px';
2534				}
2535			}
2536		}
2537	
2538		return sum + unit;
2539	}
2540	
2541	function _fnColumnsFromHeader( cell )
2542	{
2543		var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
2544	
2545		if ( ! attr ) {
2546			return [];
2547		}
2548	
2549		return attr.split(',').map( function (val) {
2550			return val * 1;
2551		} );
2552	}
2553	/**
2554	 * Add a data array to the table, creating DOM node etc. This is the parallel to
2555	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2556	 * DOM source.
2557	 *  @param {object} settings dataTables settings object
2558	 *  @param {array} data data array to be added
2559	 *  @param {node} [tr] TR element to add to the table - optional. If not given,
2560	 *    DataTables will create a row automatically
2561	 *  @param {array} [tds] Array of TD|TH elements for the row - must be given
2562	 *    if nTr is.
2563	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2564	 *  @memberof DataTable#oApi
2565	 */
2566	function _fnAddData ( settings, dataIn, tr, tds )
2567	{
2568		/* Create the object for storing information about this new row */
2569		var rowIdx = settings.aoData.length;
2570		var rowModel = $.extend( true, {}, DataTable.models.oRow, {
2571			src: tr ? 'dom' : 'data',
2572			idx: rowIdx
2573		} );
2574	
2575		rowModel._aData = dataIn;
2576		settings.aoData.push( rowModel );
2577	
2578		var columns = settings.aoColumns;
2579	
2580		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2581		{
2582			// Invalidate the column types as the new data needs to be revalidated
2583			columns[i].sType = null;
2584		}
2585	
2586		/* Add to the display array */
2587		settings.aiDisplayMaster.push( rowIdx );
2588	
2589		var id = settings.rowIdFn( dataIn );
2590		if ( id !== undefined ) {
2591			settings.aIds[ id ] = rowModel;
2592		}
2593	
2594		/* Create the DOM information, or register it if already present */
2595		if ( tr || ! settings.oFeatures.bDeferRender )
2596		{
2597			_fnCreateTr( settings, rowIdx, tr, tds );
2598		}
2599	
2600		return rowIdx;
2601	}
2602	
2603	
2604	/**
2605	 * Add one or more TR elements to the table. Generally we'd expect to
2606	 * use this for reading data from a DOM sourced table, but it could be
2607	 * used for an TR element. Note that if a TR is given, it is used (i.e.
2608	 * it is not cloned).
2609	 *  @param {object} settings dataTables settings object
2610	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
2611	 *  @returns {array} Array of indexes for the added rows
2612	 *  @memberof DataTable#oApi
2613	 */
2614	function _fnAddTr( settings, trs )
2615	{
2616		var row;
2617	
2618		// Allow an individual node to be passed in
2619		if ( ! (trs instanceof $) ) {
2620			trs = $(trs);
2621		}
2622	
2623		return trs.map( function (i, el) {
2624			row = _fnGetRowElements( settings, el );
2625			return _fnAddData( settings, row.data, el, row.cells );
2626		} );
2627	}
2628	
2629	
2630	/**
2631	 * Get the data for a given cell from the internal cache, taking into account data mapping
2632	 *  @param {object} settings dataTables settings object
2633	 *  @param {int} rowIdx aoData row id
2634	 *  @param {int} colIdx Column index
2635	 *  @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
2636	 *  @returns {*} Cell data
2637	 *  @memberof DataTable#oApi
2638	 */
2639	function _fnGetCellData( settings, rowIdx, colIdx, type )
2640	{
2641		if (type === 'search') {
2642			type = 'filter';
2643		}
2644		else if (type === 'order') {
2645			type = 'sort';
2646		}
2647	
2648		var row = settings.aoData[rowIdx];
2649	
2650		if (! row) {
2651			return undefined;
2652		}
2653	
2654		var draw           = settings.iDraw;
2655		var col            = settings.aoColumns[colIdx];
2656		var rowData        = row._aData;
2657		var defaultContent = col.sDefaultContent;
2658		var cellData       = col.fnGetData( rowData, type, {
2659			settings: settings,
2660			row:      rowIdx,
2661			col:      colIdx
2662		} );
2663	
2664		// Allow for a node being returned for non-display types
2665		if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
2666			cellData = cellData.innerHTML;
2667		}
2668	
2669		if ( cellData === undefined ) {
2670			if ( settings.iDrawError != draw && defaultContent === null ) {
2671				_fnLog( settings, 0, "Requested unknown parameter "+
2672					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2673					" for row "+rowIdx+", column "+colIdx, 4 );
2674				settings.iDrawError = draw;
2675			}
2676			return defaultContent;
2677		}
2678	
2679		// When the data source is null and a specific data type is requested (i.e.
2680		// not the original data), we can use default column data
2681		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2682			cellData = defaultContent;
2683		}
2684		else if ( typeof cellData === 'function' ) {
2685			// If the data source is a function, then we run it and use the return,
2686			// executing in the scope of the data object (for instances)
2687			return cellData.call( rowData );
2688		}
2689	
2690		if ( cellData === null && type === 'display' ) {
2691			return '';
2692		}
2693	
2694		if ( type === 'filter' ) {
2695			var fomatters = DataTable.ext.type.search;
2696	
2697			if ( fomatters[ col.sType ] ) {
2698				cellData = fomatters[ col.sType ]( cellData );
2699			}
2700		}
2701	
2702		return cellData;
2703	}
2704	
2705	
2706	/**
2707	 * Set the value for a specific cell, into the internal data cache
2708	 *  @param {object} settings dataTables settings object
2709	 *  @param {int} rowIdx aoData row id
2710	 *  @param {int} colIdx Column index
2711	 *  @param {*} val Value to set
2712	 *  @memberof DataTable#oApi
2713	 */
2714	function _fnSetCellData( settings, rowIdx, colIdx, val )
2715	{
2716		var col     = settings.aoColumns[colIdx];
2717		var rowData = settings.aoData[rowIdx]._aData;
2718	
2719		col.fnSetData( rowData, val, {
2720			settings: settings,
2721			row:      rowIdx,
2722			col:      colIdx
2723		}  );
2724	}
2725	
2726	/**
2727	 * Write a value to a cell
2728	 * @param {*} td Cell
2729	 * @param {*} val Value
2730	 */
2731	function _fnWriteCell(td, val)
2732	{
2733		if (val && typeof val === 'object' && val.nodeName) {
2734			$(td)
2735				.empty()
2736				.append(val);
2737		}
2738		else {
2739			td.innerHTML = val;
2740		}
2741	}
2742	
2743	
2744	// Private variable that is used to match action syntax in the data property object
2745	var __reArray = /\[.*?\]$/;
2746	var __reFn = /\(\)$/;
2747	
2748	/**
2749	 * Split string on periods, taking into account escaped periods
2750	 * @param  {string} str String to split
2751	 * @return {array} Split string
2752	 */
2753	function _fnSplitObjNotation( str )
2754	{
2755		var parts = str.match(/(\\.|[^.])+/g) || [''];
2756	
2757		return parts.map( function ( s ) {
2758			return s.replace(/\\\./g, '.');
2759		} );
2760	}
2761	
2762	
2763	/**
2764	 * Return a function that can be used to get data from a source object, taking
2765	 * into account the ability to use nested objects as a source
2766	 *  @param {string|int|function} mSource The data source for the object
2767	 *  @returns {function} Data get function
2768	 *  @memberof DataTable#oApi
2769	 */
2770	var _fnGetObjectDataFn = DataTable.util.get;
2771	
2772	
2773	/**
2774	 * Return a function that can be used to set data from a source object, taking
2775	 * into account the ability to use nested objects as a source
2776	 *  @param {string|int|function} mSource The data source for the object
2777	 *  @returns {function} Data set function
2778	 *  @memberof DataTable#oApi
2779	 */
2780	var _fnSetObjectDataFn = DataTable.util.set;
2781	
2782	
2783	/**
2784	 * Return an array with the full table data
2785	 *  @param {object} oSettings dataTables settings object
2786	 *  @returns array {array} aData Master data array
2787	 *  @memberof DataTable#oApi
2788	 */
2789	function _fnGetDataMaster ( settings )
2790	{
2791		return _pluck( settings.aoData, '_aData' );
2792	}
2793	
2794	
2795	/**
2796	 * Nuke the table
2797	 *  @param {object} oSettings dataTables settings object
2798	 *  @memberof DataTable#oApi
2799	 */
2800	function _fnClearTable( settings )
2801	{
2802		settings.aoData.length = 0;
2803		settings.aiDisplayMaster.length = 0;
2804		settings.aiDisplay.length = 0;
2805		settings.aIds = {};
2806	}
2807	
2808	
2809	/**
2810	 * Mark cached data as invalid such that a re-read of the data will occur when
2811	 * the cached data is next requested. Also update from the data source object.
2812	 *
2813	 * @param {object} settings DataTables settings object
2814	 * @param {int}    rowIdx   Row index to invalidate
2815	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
2816	 *     or 'data'
2817	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
2818	 *     row will be invalidated
2819	 * @memberof DataTable#oApi
2820	 *
2821	 * @todo For the modularisation of v1.11 this will need to become a callback, so
2822	 *   the sort and filter methods can subscribe to it. That will required
2823	 *   initialisation options for sorting, which is why it is not already baked in
2824	 */
2825	function _fnInvalidate( settings, rowIdx, src, colIdx )
2826	{
2827		var row = settings.aoData[ rowIdx ];
2828		var i, ien;
2829	
2830		// Remove the cached data for the row
2831		row._aSortData = null;
2832		row._aFilterData = null;
2833		row.displayData = null;
2834	
2835		// Are we reading last data from DOM or the data object?
2836		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2837			// Read the data from the DOM
2838			row._aData = _fnGetRowElements(
2839					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2840				)
2841				.data;
2842		}
2843		else {
2844			// Reading from data object, update the DOM
2845			var cells = row.anCells;
2846			var display = _fnGetRowDisplay(settings, rowIdx);
2847	
2848			if ( cells ) {
2849				if ( colIdx !== undefined ) {
2850					_fnWriteCell(cells[colIdx], display[colIdx]);
2851				}
2852				else {
2853					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2854						_fnWriteCell(cells[i], display[i]);
2855					}
2856				}
2857			}
2858		}
2859	
2860		// Column specific invalidation
2861		var cols = settings.aoColumns;
2862		if ( colIdx !== undefined ) {
2863			// Type - the data might have changed
2864			cols[ colIdx ].sType = null;
2865	
2866			// Max length string. Its a fairly cheep recalculation, so not worth
2867			// something more complicated
2868			cols[ colIdx ].maxLenString = null;
2869		}
2870		else {
2871			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2872				cols[i].sType = null;
2873				cols[i].maxLenString = null;
2874			}
2875	
2876			// Update DataTables special `DT_*` attributes for the row
2877			_fnRowAttributes( settings, row );
2878		}
2879	}
2880	
2881	
2882	/**
2883	 * Build a data source object from an HTML row, reading the contents of the
2884	 * cells that are in the row.
2885	 *
2886	 * @param {object} settings DataTables settings object
2887	 * @param {node|object} TR element from which to read data or existing row
2888	 *   object from which to re-read the data from the cells
2889	 * @param {int} [colIdx] Optional column index
2890	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2891	 *   parameter should also be given and will be used to write the data into.
2892	 *   Only the column in question will be written
2893	 * @returns {object} Object with two parameters: `data` the data read, in
2894	 *   document order, and `cells` and array of nodes (they can be useful to the
2895	 *   caller, so rather than needing a second traversal to get them, just return
2896	 *   them from here).
2897	 * @memberof DataTable#oApi
2898	 */
2899	function _fnGetRowElements( settings, row, colIdx, d )
2900	{
2901		var
2902			tds = [],
2903			td = row.firstChild,
2904			name, col, i=0, contents,
2905			columns = settings.aoColumns,
2906			objectRead = settings._rowReadObject;
2907	
2908		// Allow the data object to be passed in, or construct
2909		d = d !== undefined ?
2910			d :
2911			objectRead ?
2912				{} :
2913				[];
2914	
2915		var attr = function ( str, td  ) {
2916			if ( typeof str === 'string' ) {
2917				var idx = str.indexOf('@');
2918	
2919				if ( idx !== -1 ) {
2920					var attr = str.substring( idx+1 );
2921					var setter = _fnSetObjectDataFn( str );
2922					setter( d, td.getAttribute( attr ) );
2923				}
2924			}
2925		};
2926	
2927		// Read data from a cell and store into the data object
2928		var cellProcess = function ( cell ) {
2929			if ( colIdx === undefined || colIdx === i ) {
2930				col = columns[i];
2931				contents = (cell.innerHTML).trim();
2932	
2933				if ( col && col._bAttrSrc ) {
2934					var setter = _fnSetObjectDataFn( col.mData._ );
2935					setter( d, contents );
2936	
2937					attr( col.mData.sort, cell );
2938					attr( col.mData.type, cell );
2939					attr( col.mData.filter, cell );
2940				}
2941				else {
2942					// Depending on the `data` option for the columns the data can
2943					// be read to either an object or an array.
2944					if ( objectRead ) {
2945						if ( ! col._setter ) {
2946							// Cache the setter function
2947							col._setter = _fnSetObjectDataFn( col.mData );
2948						}
2949						col._setter( d, contents );
2950					}
2951					else {
2952						d[i] = contents;
2953					}
2954				}
2955			}
2956	
2957			i++;
2958		};
2959	
2960		if ( td ) {
2961			// `tr` element was passed in
2962			while ( td ) {
2963				name = td.nodeName.toUpperCase();
2964	
2965				if ( name == "TD" || name == "TH" ) {
2966					cellProcess( td );
2967					tds.push( td );
2968				}
2969	
2970				td = td.nextSibling;
2971			}
2972		}
2973		else {
2974			// Existing row object passed in
2975			tds = row.anCells;
2976	
2977			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
2978				cellProcess( tds[j] );
2979			}
2980		}
2981	
2982		// Read the ID from the DOM if present
2983		var rowNode = row.firstChild ? row : row.nTr;
2984	
2985		if ( rowNode ) {
2986			var id = rowNode.getAttribute( 'id' );
2987	
2988			if ( id ) {
2989				_fnSetObjectDataFn( settings.rowId )( d, id );
2990			}
2991		}
2992	
2993		return {
2994			data: d,
2995			cells: tds
2996		};
2997	}
2998	
2999	/**
3000	 * Render and cache a row's display data for the columns, if required
3001	 * @returns 
3002	 */
3003	function _fnGetRowDisplay (settings, rowIdx) {
3004		let rowModal = settings.aoData[rowIdx];
3005		let columns = settings.aoColumns;
3006	
3007		if (! rowModal.displayData) {
3008			// Need to render and cache
3009			rowModal.displayData = [];
3010		
3011			for ( var colIdx=0, len=columns.length ; colIdx<len ; colIdx++ ) {
3012				rowModal.displayData.push(
3013					_fnGetCellData( settings, rowIdx, colIdx, 'display' )
3014				);
3015			}
3016		}
3017	
3018		return rowModal.displayData;
3019	}
3020	
3021	/**
3022	 * Create a new TR element (and it's TD children) for a row
3023	 *  @param {object} oSettings dataTables settings object
3024	 *  @param {int} iRow Row to consider
3025	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3026	 *    DataTables will create a row automatically
3027	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
3028	 *    if nTr is.
3029	 *  @memberof DataTable#oApi
3030	 */
3031	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3032	{
3033		var
3034			row = oSettings.aoData[iRow],
3035			rowData = row._aData,
3036			cells = [],
3037			nTr, nTd, oCol,
3038			i, iLen, create,
3039			trClass = oSettings.oClasses.tbody.row;
3040	
3041		if ( row.nTr === null )
3042		{
3043			nTr = nTrIn || document.createElement('tr');
3044	
3045			row.nTr = nTr;
3046			row.anCells = cells;
3047	
3048			_addClass(nTr, trClass);
3049	
3050			/* Use a private property on the node to allow reserve mapping from the node
3051			 * to the aoData array for fast look up
3052			 */
3053			nTr._DT_RowIndex = iRow;
3054	
3055			/* Special parameters can be given by the data source to be used on the row */
3056			_fnRowAttributes( oSettings, row );
3057	
3058			/* Process each column */
3059			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3060			{
3061				oCol = oSettings.aoColumns[i];
3062				create = nTrIn && anTds[i] ? false : true;
3063	
3064				nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
3065	
3066				if (! nTd) {
3067					_fnLog( oSettings, 0, 'Incorrect column count', 18 );
3068				}
3069	
3070				nTd._DT_CellIndex = {
3071					row: iRow,
3072					column: i
3073				};
3074				
3075				cells.push( nTd );
3076				
3077				var display = _fnGetRowDisplay(oSettings, iRow);
3078	
3079				// Need to create the HTML if new, or if a rendering function is defined
3080				if (
3081					create ||
3082					(
3083						(oCol.mRender || oCol.mData !== i) &&
3084						(!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3085					)
3086				) {
3087					_fnWriteCell(nTd, display[i]);
3088				}
3089	
3090				// Visibility - add or remove as required
3091				if ( oCol.bVisible && create )
3092				{
3093					nTr.appendChild( nTd );
3094				}
3095				else if ( ! oCol.bVisible && ! create )
3096				{
3097					nTd.parentNode.removeChild( nTd );
3098				}
3099	
3100				if ( oCol.fnCreatedCell )
3101				{
3102					oCol.fnCreatedCell.call( oSettings.oInstance,
3103						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3104					);
3105				}
3106			}
3107	
3108			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells] );
3109		}
3110		else {
3111			_addClass(row.nTr, trClass);
3112		}
3113	}
3114	
3115	
3116	/**
3117	 * Add attributes to a row based on the special `DT_*` parameters in a data
3118	 * source object.
3119	 *  @param {object} settings DataTables settings object
3120	 *  @param {object} DataTables row object for the row to be modified
3121	 *  @memberof DataTable#oApi
3122	 */
3123	function _fnRowAttributes( settings, row )
3124	{
3125		var tr = row.nTr;
3126		var data = row._aData;
3127	
3128		if ( tr ) {
3129			var id = settings.rowIdFn( data );
3130	
3131			if ( id ) {
3132				tr.id = id;
3133			}
3134	
3135			if ( data.DT_RowClass ) {
3136				// Remove any classes added by DT_RowClass before
3137				var a = data.DT_RowClass.split(' ');
3138				row.__rowc = row.__rowc ?
3139					_unique( row.__rowc.concat( a ) ) :
3140					a;
3141	
3142				$(tr)
3143					.removeClass( row.__rowc.join(' ') )
3144					.addClass( data.DT_RowClass );
3145			}
3146	
3147			if ( data.DT_RowAttr ) {
3148				$(tr).attr( data.DT_RowAttr );
3149			}
3150	
3151			if ( data.DT_RowData ) {
3152				$(tr).data( data.DT_RowData );
3153			}
3154		}
3155	}
3156	
3157	
3158	/**
3159	 * Create the HTML header for the table
3160	 *  @param {object} oSettings dataTables settings object
3161	 *  @memberof DataTable#oApi
3162	 */
3163	function _fnBuildHead( settings, side )
3164	{
3165		var classes = settings.oClasses;
3166		var columns = settings.aoColumns;
3167		var i, ien, row;
3168		var target = side === 'header'
3169			? settings.nTHead
3170			: settings.nTFoot;
3171		var titleProp = side === 'header' ? 'sTitle' : side;
3172	
3173		// Footer might be defined
3174		if (! target) {
3175			return;
3176		}
3177	
3178		// If no cells yet and we have content for them, then create
3179		if (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) {
3180			row = $('tr', target);
3181	
3182			// Add a row if needed
3183			if (! row.length) {
3184				row = $('<tr/>').appendTo(target)
3185			}
3186	
3187			// Add the number of cells needed to make up to the number of columns
3188			if (row.length === 1) {
3189				var cells = $('td, th', row);
3190	
3191				for ( i=cells.length, ien=columns.length ; i<ien ; i++ ) {
3192					$('<th/>')
3193						.html( columns[i][titleProp] || '' )
3194						.appendTo( row );
3195				}
3196			}
3197		}
3198	
3199		var detected = _fnDetectHeader( settings, target, true );
3200	
3201		if (side === 'header') {
3202			settings.aoHeader = detected;
3203		}
3204		else {
3205			settings.aoFooter = detected;
3206		}
3207	
3208		// ARIA role for the rows
3209		$(target).children('tr').attr('role', 'row');
3210	
3211		// Every cell needs to be passed through the renderer
3212		$(target).children('tr').children('th, td')
3213			.each( function () {
3214				_fnRenderer( settings, side )(
3215					settings, $(this), classes
3216				);
3217			} );
3218	}
3219	
3220	/**
3221	 * Build a layout structure for a header or footer
3222	 *
3223	 * @param {*} settings DataTables settings
3224	 * @param {*} source Source layout array
3225	 * @param {*} incColumns What columns should be included
3226	 * @returns Layout array
3227	 */
3228	function _fnHeaderLayout( settings, source, incColumns )
3229	{
3230		var row, column, cell;
3231		var local = [];
3232		var structure = [];
3233		var columns = settings.aoColumns;
3234		var columnCount = columns.length;
3235		var rowspan, colspan;
3236	
3237		if ( ! source ) {
3238			return;
3239		}
3240	
3241		// Default is to work on only visible columns
3242		if ( ! incColumns ) {
3243			incColumns = _range(columnCount)
3244				.filter(function (idx) {
3245					return columns[idx].bVisible;
3246				});
3247		}
3248	
3249		// Make a copy of the master layout array, but with only the columns we want
3250		for ( row=0 ; row<source.length ; row++ ) {
3251			// Remove any columns we haven't selected
3252			local[row] = source[row].slice().filter(function (cell, i) {
3253				return incColumns.includes(i);
3254			});
3255	
3256			// Prep the structure array - it needs an element for each row
3257			structure.push( [] );
3258		}
3259	
3260		for ( row=0 ; row<local.length ; row++ ) {
3261			for ( column=0 ; column<local[row].length ; column++ ) {
3262				rowspan = 1;
3263				colspan = 1;
3264	
3265				// Check to see if there is already a cell (row/colspan) covering our target
3266				// insert point. If there is, then there is nothing to do.
3267				if ( structure[row][column] === undefined ) {
3268					cell = local[row][column].cell;
3269	
3270					// Expand for rowspan
3271					while (
3272						local[row+rowspan] !== undefined &&
3273						local[row][column].cell == local[row+rowspan][column].cell
3274					) {
3275						structure[row+rowspan][column] = null;
3276						rowspan++;
3277					}
3278	
3279					// And for colspan
3280					while (
3281						local[row][column+colspan] !== undefined &&
3282						local[row][column].cell == local[row][column+colspan].cell
3283					) {
3284						// Which also needs to go over rows
3285						for ( var k=0 ; k<rowspan ; k++ ) {
3286							structure[row+k][column+colspan] = null;
3287						}
3288	
3289						colspan++;
3290					}
3291	
3292					var titleSpan = $('span.dt-column-title', cell);
3293	
3294					structure[row][column] = {
3295						cell: cell,
3296						colspan: colspan,
3297						rowspan: rowspan,
3298						title: titleSpan.length
3299							? titleSpan.html()
3300							: $(cell).html()
3301					};
3302				}
3303			}
3304		}
3305	
3306		return structure;
3307	}
3308	
3309	
3310	/**
3311	 * Draw the header (or footer) element based on the column visibility states.
3312	 *
3313	 *  @param object oSettings dataTables settings object
3314	 *  @param array aoSource Layout array from _fnDetectHeader
3315	 *  @memberof DataTable#oApi
3316	 */
3317	function _fnDrawHead( settings, source )
3318	{
3319		var layout = _fnHeaderLayout(settings, source);
3320		var tr, n;
3321	
3322		for ( var row=0 ; row<source.length ; row++ ) {
3323			tr = source[row].row;
3324	
3325			// All cells are going to be replaced, so empty out the row
3326			// Can't use $().empty() as that kills event handlers
3327			if (tr) {
3328				while( (n = tr.firstChild) ) {
3329					tr.removeChild( n );
3330				}
3331			}
3332	
3333			for ( var column=0 ; column<layout[row].length ; column++ ) {
3334				var point = layout[row][column];
3335	
3336				if (point) {
3337					$(point.cell)
3338						.appendTo(tr)
3339						.attr('rowspan', point.rowspan)
3340						.attr('colspan', point.colspan);
3341				}
3342			}
3343		}
3344	}
3345	
3346	
3347	/**
3348	 * Insert the required TR nodes into the table for display
3349	 *  @param {object} oSettings dataTables settings object
3350	 *  @param ajaxComplete true after ajax call to complete rendering
3351	 *  @memberof DataTable#oApi
3352	 */
3353	function _fnDraw( oSettings, ajaxComplete )
3354	{
3355		// Allow for state saving and a custom start position
3356		_fnStart( oSettings );
3357	
3358		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3359		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3360		if ( aPreDraw.indexOf(false) !== -1 )
3361		{
3362			_fnProcessingDisplay( oSettings, false );
3363			return;
3364		}
3365	
3366		var anRows = [];
3367		var iRowCount = 0;
3368		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3369		var aiDisplay = oSettings.aiDisplay;
3370		var iDisplayStart = oSettings._iDisplayStart;
3371		var iDisplayEnd = oSettings.fnDisplayEnd();
3372		var columns = oSettings.aoColumns;
3373		var body = $(oSettings.nTBody);
3374	
3375		oSettings.bDrawing = true;
3376	
3377		/* Server-side processing draw intercept */
3378		if ( !bServerSide )
3379		{
3380			oSettings.iDraw++;
3381		}
3382		else if ( !oSettings.bDestroying && !ajaxComplete)
3383		{
3384			// Show loading message for server-side processing
3385			if (oSettings.iDraw === 0) {
3386				body.empty().append(_emptyRow(oSettings));
3387			}
3388	
3389			_fnAjaxUpdate( oSettings );
3390			return;
3391		}
3392	
3393		if ( aiDisplay.length !== 0 )
3394		{
3395			var iStart = bServerSide ? 0 : iDisplayStart;
3396			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3397	
3398			for ( var j=iStart ; j<iEnd ; j++ )
3399			{
3400				var iDataIndex = aiDisplay[j];
3401				var aoData = oSettings.aoData[ iDataIndex ];
3402				if ( aoData.nTr === null )
3403				{
3404					_fnCreateTr( oSettings, iDataIndex );
3405				}
3406	
3407				var nRow = aoData.nTr;
3408	
3409				// Add various classes as needed
3410				for (var i=0 ; i<columns.length ; i++) {
3411					var col = columns[i];
3412					var td = aoData.anCells[i];
3413	
3414					_addClass(td, _ext.type.className[col.sType]); // auto class
3415					_addClass(td, col.sClass); // column class
3416					_addClass(td, oSettings.oClasses.tbody.cell); // all cells
3417				}
3418	
3419				// Row callback functions - might want to manipulate the row
3420				// iRowCount and j are not currently documented. Are they at all
3421				// useful?
3422				_fnCallbackFire( oSettings, 'aoRowCallback', null,
3423					[nRow, aoData._aData, iRowCount, j, iDataIndex] );
3424	
3425				anRows.push( nRow );
3426				iRowCount++;
3427			}
3428		}
3429		else
3430		{
3431			anRows[ 0 ] = _emptyRow(oSettings);
3432		}
3433	
3434		/* Header and footer callbacks */
3435		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3436			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3437	
3438		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3439			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3440	
3441		// replaceChildren is faster, but only became widespread in 2020,
3442		// so a fall back in jQuery is provided for older browsers.
3443		if (body[0].replaceChildren) {
3444			body[0].replaceChildren.apply(body[0], anRows);
3445		}
3446		else {
3447			body.children().detach();
3448			body.append( $(anRows) );
3449		}
3450	
3451		// Empty table needs a specific class
3452		$(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
3453	
3454		/* Call all required callback functions for the end of a draw */
3455		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings], true );
3456	
3457		/* Draw is complete, sorting and filtering must be as well */
3458		oSettings.bSorted = false;
3459		oSettings.bFiltered = false;
3460		oSettings.bDrawing = false;
3461	}
3462	
3463	
3464	/**
3465	 * Redraw the table - taking account of the various features which are enabled
3466	 *  @param {object} oSettings dataTables settings object
3467	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
3468	 *    the paging is reset to the first page
3469	 *  @memberof DataTable#oApi
3470	 */
3471	function _fnReDraw( settings, holdPosition, recompute )
3472	{
3473		var
3474			features = settings.oFeatures,
3475			sort     = features.bSort,
3476			filter   = features.bFilter;
3477	
3478		if (recompute === undefined || recompute === true) {
3479			if ( sort ) {
3480				_fnSort( settings );
3481			}
3482	
3483			if ( filter ) {
3484				_fnFilterComplete( settings, settings.oPreviousSearch );
3485			}
3486			else {
3487				// No filtering, so we want to just use the display master
3488				settings.aiDisplay = settings.aiDisplayMaster.slice();
3489			}
3490		}
3491	
3492		if ( holdPosition !== true ) {
3493			settings._iDisplayStart = 0;
3494		}
3495	
3496		// Let any modules know about the draw hold position state (used by
3497		// scrolling internally)
3498		settings._drawHold = holdPosition;
3499	
3500		_fnDraw( settings );
3501	
3502		settings._drawHold = false;
3503	}
3504	
3505	
3506	/*
3507	 * Table is empty - create a row with an empty message in it
3508	 */
3509	function _emptyRow ( settings ) {
3510		var oLang = settings.oLanguage;
3511		var zero = oLang.sZeroRecords;
3512		var dataSrc = _fnDataSource( settings );
3513	
3514		if (
3515			(settings.iDraw < 1 && dataSrc === 'ssp') ||
3516			(settings.iDraw <= 1 && dataSrc === 'ajax')
3517		) {
3518			zero = oLang.sLoadingRecords;
3519		}
3520		else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
3521		{
3522			zero = oLang.sEmptyTable;
3523		}
3524	
3525		return $( '<tr/>' )
3526			.append( $('<td />', {
3527				'colSpan': _fnVisbleColumns( settings ),
3528				'class':   settings.oClasses.empty.row
3529			} ).html( zero ) )[0];
3530	}
3531	
3532	
3533	/**
3534	 * Convert a `layout` object given by a user to the object structure needed
3535	 * for the renderer. This is done twice, once for above and once for below
3536	 * the table. Ordering must also be considered.
3537	 *
3538	 * @param {*} settings DataTables settings object
3539	 * @param {*} layout Layout object to convert
3540	 * @param {string} side `top` or `bottom`
3541	 * @returns Converted array structure - one item for each row.
3542	 */
3543	function _layoutArray ( settings, layout, side )
3544	{
3545		var groups = {};
3546	
3547		// Combine into like groups (e.g. `top`, `top2`, etc)
3548		$.each( layout, function ( pos, val ) {
3549			if (val === null) {
3550				return;
3551			}
3552	
3553			var splitPos = pos.replace(/([A-Z])/g, ' $1').split(' ');
3554	
3555			if ( ! groups[ splitPos[0] ] ) {
3556				groups[ splitPos[0] ] = {};
3557			}
3558	
3559			var align = splitPos.length === 1 ?
3560				'full' :
3561				splitPos[1].toLowerCase();
3562			var group = groups[ splitPos[0] ];
3563			var groupRun = function (contents, innerVal) {
3564				// If it is an object, then there can be multiple features contained in it
3565				if ( $.isPlainObject( innerVal ) ) {
3566					Object.keys(innerVal).map(function (key) {
3567						contents.push( {
3568							feature: key,
3569							opts: innerVal[key]
3570						});
3571					});
3572				}
3573				else {
3574					contents.push(innerVal);
3575				}
3576			}
3577	
3578			// Transform to an object with a contents property
3579			if (! group[align] || ! group[align].contents) {
3580				group[align] = { contents: [] };
3581			}
3582	
3583			// Allow for an array or just a single object
3584			if ( Array.isArray(val)) {
3585				for (var i=0 ; i<val.length ; i++) {
3586					groupRun(group[align].contents, val[i]);
3587				}
3588			}
3589			else {
3590				groupRun(group[ align ].contents, val);
3591			}
3592	
3593			// And make contents an array
3594			if ( ! Array.isArray( group[ align ].contents ) ) {
3595				group[ align ].contents = [ group[ align ].contents ];
3596			}
3597		} );
3598	
3599		var filtered = Object.keys(groups)
3600			.map( function ( pos ) {
3601				// Filter to only the side we need
3602				if ( pos.indexOf(side) !== 0 ) {
3603					return null;
3604				}
3605	
3606				return {
3607					name: pos,
3608					val: groups[pos]
3609				};
3610			} )
3611			.filter( function (item) {
3612				return item !== null;
3613			});
3614	
3615		// Order by item identifier
3616		filtered.sort( function ( a, b ) {
3617			var order1 = a.name.replace(/[^0-9]/g, '') * 1;
3618			var order2 = b.name.replace(/[^0-9]/g, '') * 1;
3619	
3620			return order2 - order1;
3621		} );
3622		
3623		if ( side === 'bottom' ) {
3624			filtered.reverse();
3625		}
3626	
3627		// Split into rows
3628		var rows = [];
3629		for ( var i=0, ien=filtered.length ; i<ien ; i++ ) {
3630			if (  filtered[i].val.full ) {
3631				rows.push( { full: filtered[i].val.full } );
3632				_layoutResolve( settings, rows[ rows.length - 1 ] );
3633	
3634				delete filtered[i].val.full;
3635			}
3636	
3637			if ( Object.keys(filtered[i].val).length ) {
3638				rows.push( filtered[i].val );
3639				_layoutResolve( settings, rows[ rows.length - 1 ] );
3640			}
3641		}
3642	
3643		return rows;
3644	}
3645	
3646	
3647	/**
3648	 * Convert the contents of a row's layout object to nodes that can be inserted
3649	 * into the document by a renderer. Execute functions, look up plug-ins, etc.
3650	 *
3651	 * @param {*} settings DataTables settings object
3652	 * @param {*} row Layout object for this row
3653	 */
3654	function _layoutResolve( settings, row ) {
3655		var getFeature = function (feature, opts) {
3656			if ( ! _ext.features[ feature ] ) {
3657				_fnLog( settings, 0, 'Unknown feature: '+ feature );
3658			}
3659	
3660			return _ext.features[ feature ].apply( this, [settings, opts] );
3661		};
3662	
3663		var resolve = function ( item ) {
3664			var line = row[ item ].contents;
3665	
3666			for ( var i=0, ien=line.length ; i<ien ; i++ ) {
3667				if ( ! line[i] ) {
3668					continue;
3669				}
3670				else if ( typeof line[i] === 'string' ) {
3671					line[i] = getFeature( line[i], null );
3672				}
3673				else if ( $.isPlainObject(line[i]) ) {
3674					// If it's an object, it just has feature and opts properties from
3675					// the transform in _layoutArray
3676					line[i] = getFeature(line[i].feature, line[i].opts);
3677				}
3678				else if ( typeof line[i].node === 'function' ) {
3679					line[i] = line[i].node( settings );
3680				}
3681				else if ( typeof line[i] === 'function' ) {
3682					var inst = line[i]( settings );
3683	
3684					line[i] = typeof inst.node === 'function' ?
3685						inst.node() :
3686						inst;
3687				}
3688			}
3689		};
3690	
3691		$.each( row, function ( key ) {
3692			resolve( key );
3693		} );
3694	}
3695	
3696	
3697	/**
3698	 * Add the options to the page HTML for the table
3699	 *  @param {object} settings DataTables settings object
3700	 *  @memberof DataTable#oApi
3701	 */
3702	function _fnAddOptionsHtml ( settings )
3703	{
3704		var classes = settings.oClasses;
3705		var table = $(settings.nTable);
3706	
3707		// Wrapper div around everything DataTables controls
3708		var insert = $('<div/>')
3709			.attr({
3710				id:      settings.sTableId+'_wrapper',
3711				'class': classes.container
3712			})
3713			.insertBefore(table);
3714	
3715		settings.nTableWrapper = insert[0];
3716	
3717		if (settings.sDom) {
3718			// Legacy
3719			_fnLayoutDom(settings, settings.sDom, insert);
3720		}
3721		else {
3722			var top = _layoutArray( settings, settings.layout, 'top' );
3723			var bottom = _layoutArray( settings, settings.layout, 'bottom' );
3724			var renderer = _fnRenderer( settings, 'layout' );
3725		
3726			// Everything above - the renderer will actually insert the contents into the document
3727			top.forEach(function (item) {
3728				renderer( settings, insert, item );
3729			});
3730	
3731			// The table - always the center of attention
3732			renderer( settings, insert, {
3733				full: {
3734					table: true,
3735					contents: [ _fnFeatureHtmlTable(settings) ]
3736				}
3737			} );
3738	
3739			// Everything below
3740			bottom.forEach(function (item) {
3741				renderer( settings, insert, item );
3742			});
3743		}
3744	
3745		// Processing floats on top, so it isn't an inserted feature
3746		_processingHtml( settings );
3747	}
3748	
3749	/**
3750	 * Draw the table with the legacy DOM property
3751	 * @param {*} settings DT settings object
3752	 * @param {*} dom DOM string
3753	 * @param {*} insert Insert point
3754	 */
3755	function _fnLayoutDom( settings, dom, insert )
3756	{
3757		var parts = dom.match(/(".*?")|('.*?')|./g);
3758		var featureNode, option, newNode, next, attr;
3759	
3760		for ( var i=0 ; i<parts.length ; i++ ) {
3761			featureNode = null;
3762			option = parts[i];
3763	
3764			if ( option == '<' ) {
3765				// New container div
3766				newNode = $('<div/>');
3767	
3768				// Check to see if we should append an id and/or a class name to the container
3769				next = parts[i+1];
3770	
3771				if ( next[0] == "'" || next[0] == '"' ) {
3772					attr = next.replace(/['"]/g, '');
3773	
3774					var id = '', className;
3775	
3776					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3777					 * breaks the string into parts and applies them as needed
3778					 */
3779					if ( attr.indexOf('.') != -1 ) {
3780						var split = attr.split('.');
3781	
3782						id = split[0];
3783						className = split[1];
3784					}
3785					else if ( attr[0] == "#" ) {
3786						id = attr;
3787					}
3788					else {
3789						className = attr;
3790					}
3791	
3792					newNode
3793						.attr('id', id.substring(1))
3794						.addClass(className);
3795	
3796					i++; // Move along the position array
3797				}
3798	
3799				insert.append( newNode );
3800				insert = newNode;
3801			}
3802			else if ( option == '>' ) {
3803				// End container div
3804				insert = insert.parent();
3805			}
3806			else if ( option == 't' ) {
3807				// Table
3808				featureNode = _fnFeatureHtmlTable( settings );
3809			}
3810			else
3811			{
3812				DataTable.ext.feature.forEach(function(feature) {
3813					if ( option == feature.cFeature ) {
3814						featureNode = feature.fnInit( settings );
3815					}
3816				});
3817			}
3818	
3819			// Add to the display
3820			if ( featureNode ) {
3821				insert.append( featureNode );
3822			}
3823		}
3824	}
3825	
3826	
3827	/**
3828	 * Use the DOM source to create up an array of header cells. The idea here is to
3829	 * create a layout grid (array) of rows x columns, which contains a reference
3830	 * to the cell that that point in the grid (regardless of col/rowspan), such that
3831	 * any column / row could be removed and the new grid constructed
3832	 *  @param {node} thead The header/footer element for the table
3833	 *  @returns {array} Calculated layout array
3834	 *  @memberof DataTable#oApi
3835	 */
3836	function _fnDetectHeader ( settings, thead, write )
3837	{
3838		var columns = settings.aoColumns;
3839		var rows = $(thead).children('tr');
3840		var row, cell;
3841		var i, k, l, iLen, shifted, column, colspan, rowspan;
3842		var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3843		var layout = [];
3844		var unique;
3845		var shift = function ( a, i, j ) {
3846			var k = a[i];
3847			while ( k[j] ) {
3848				j++;
3849			}
3850			return j;
3851		};
3852	
3853		// We know how many rows there are in the layout - so prep it
3854		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3855			layout.push( [] );
3856		}
3857	
3858		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3859			row = rows[i];
3860			column = 0;
3861	
3862			// For every cell in the row..
3863			cell = row.firstChild;
3864			while ( cell ) {
3865				if (
3866					cell.nodeName.toUpperCase() == 'TD' ||
3867					cell.nodeName.toUpperCase() == 'TH'
3868				) {
3869					var cols = [];
3870	
3871					// Get the col and rowspan attributes from the DOM and sanitise them
3872					colspan = cell.getAttribute('colspan') * 1;
3873					rowspan = cell.getAttribute('rowspan') * 1;
3874					colspan = (!colspan || colspan===0 || colspan===1) ? 1 : colspan;
3875					rowspan = (!rowspan || rowspan===0 || rowspan===1) ? 1 : rows
3875pan;
3876	
3877					// There might be colspan cells already in this row, so shift our target
3878					// accordingly
3879					shifted = shift( layout, i, column );
3880	
3881					// Cache calculation for unique columns
3882					unique = colspan === 1 ?
3883						true :
3884						false;
3885					
3886					// Perform header setup
3887					if ( write ) {
3888						if (unique) {
3889							// Allow column options to be set from HTML attributes
3890							_fnColumnOptions( settings, shifted, $(cell).data() );
3891							
3892							// Get the width for the column. This can be defined from the
3893							// width attribute, style attribute or `columns.width` option
3894							var columnDef = columns[shifted];
3895							var width = cell.getAttribute('width') || null;
3896							var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
3897							if ( t ) {
3898								width = t[1];
3899							}
3900	
3901							columnDef.sWidthOrig = columnDef.sWidth || width;
3902	
3903							if (isHeader) {
3904								// Column title handling - can be user set, or read from the DOM
3905								// This happens before the render, so the original is still in place
3906								if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
3907									cell.innerHTML = columnDef.sTitle;
3908								}
3909	
3910								if (! columnDef.sTitle && unique) {
3911									columnDef.sTitle = _stripHtml(cell.innerHTML);
3912									columnDef.autoTitle = true;
3913								}
3914							}
3915							else {
3916								// Footer specific operations
3917								if (columnDef.footer) {
3918									cell.innerHTML = columnDef.footer;
3919								}
3920							}
3921	
3922							// Fall back to the aria-label attribute on the table header if no ariaTitle is
3923							// provided.
3924							if (! columnDef.ariaTitle) {
3925								columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
3926							}
3927	
3928							// Column specific class names
3929							if ( columnDef.className ) {
3930								$(cell).addClass( columnDef.className );
3931							}
3932						}
3933	
3934						// Wrap the column title so we can write to it in future
3935						if ( $('span.dt-column-title', cell).length === 0) {
3936							$('<span>')
3937								.addClass('dt-column-title')
3938								.append(cell.childNodes)
3939								.appendTo(cell);
3940						}
3941	
3942						if ( isHeader && $('span.dt-column-order', cell).length === 0) {
3943							$('<span>')
3944								.addClass('dt-column-order')
3945								.appendTo(cell);
3946						}
3947					}
3948	
3949					// If there is col / rowspan, copy the information into the layout grid
3950					for ( l=0 ; l<colspan ; l++ ) {
3951						for ( k=0 ; k<rowspan ; k++ ) {
3952							layout[i+k][shifted+l] = {
3953								cell: cell,
3954								unique: unique
3955							};
3956	
3957							layout[i+k].row = row;
3958						}
3959	
3960						cols.push( shifted+l );
3961					}
3962	
3963					// Assign an attribute so spanning cells can still be identified
3964					// as belonging to a column
3965					cell.setAttribute('data-dt-column', _unique(cols).join(','));
3966				}
3967	
3968				cell = cell.nextSibling;
3969			}
3970		}
3971	
3972		return layout;
3973	}
3974	
3975	/**
3976	 * Set the start position for draw
3977	 *  @param {object} oSettings dataTables settings object
3978	 */
3979	function _fnStart( oSettings )
3980	{
3981		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3982		var iInitDisplayStart = oSettings.iInitDisplayStart;
3983	
3984		// Check and see if we have an initial draw position from state saving
3985		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3986		{
3987			oSettings._iDisplayStart = bServerSide ?
3988				iInitDisplayStart :
3989				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3990					0 :
3991					iInitDisplayStart;
3992	
3993			oSettings.iInitDisplayStart = -1;
3994		}
3995	}
3996	
3997	/**
3998	 * Create an Ajax call based on the table's settings, taking into account that
3999	 * parameters can have multiple forms, and backwards compatibility.
4000	 *
4001	 * @param {object} oSettings dataTables settings object
4002	 * @param {array} data Data to send to the server, required by
4003	 *     DataTables - may be augmented by developer callbacks
4004	 * @param {function} fn Callback function to run when data is obtained
4005	 */
4006	function _fnBuildAjax( oSettings, data, fn )
4007	{
4008		var ajaxData;
4009		var ajax = oSettings.ajax;
4010		var instance = oSettings.oInstance;
4011		var callback = function ( json ) {
4012			var status = oSettings.jqXHR
4013				? oSettings.jqXHR.status
4014				: null;
4015	
4016			if ( json === null || (typeof status === 'number' && status == 204 ) ) {
4017				json = {};
4018				_fnAjaxDataSrc( oSettings, json, [] );
4019			}
4020	
4021			var error = json.error || json.sError;
4022			if ( error ) {
4023				_fnLog( oSettings, 0, error );
4024			}
4025	
4026			oSettings.json = json;
4027	
4028			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
4029			fn( json );
4030		};
4031	
4032		if ( $.isPlainObject( ajax ) && ajax.data )
4033		{
4034			ajaxData = ajax.data;
4035	
4036			var newData = typeof ajaxData === 'function' ?
4037				ajaxData( data, oSettings ) :  // fn can manipulate data or return
4038				ajaxData;                      // an object object or array to merge
4039	
4040			// If the function returned something, use that alone
4041			data = typeof ajaxData === 'function' && newData ?
4042				newData :
4043				$.extend( true, data, newData );
4044	
4045			// Remove the data property as we've resolved it already and don't want
4046			// jQuery to do it again (it is restored at the end of the function)
4047			delete ajax.data;
4048		}
4049	
4050		var baseAjax = {
4051			"url": typeof ajax === 'string' ?
4052				ajax :
4053				'',
4054			"data": data,
4055			"success": callback,
4056			"dataType": "json",
4057			"cache": false,
4058			"type": oSettings.sServerMethod,
4059			"error": function (xhr, error) {
4060				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
4061	
4062				if ( ret.indexOf(true) === -1 ) {
4063					if ( error == "parsererror" ) {
4064						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
4065					}
4066					else if ( xhr.readyState === 4 ) {
4067						_fnLog( oSettings, 0, 'Ajax error', 7 );
4068					}
4069				}
4070	
4071				_fnProcessingDisplay( oSettings, false );
4072			}
4073		};
4074	
4075		// If `ajax` option is an object, extend and override our default base
4076		if ( $.isPlainObject( ajax ) ) {
4077			$.extend( baseAjax, ajax )
4078		}
4079	
4080		// Store the data submitted for the API
4081		oSettings.oAjaxData = data;
4082	
4083		// Allow plug-ins and external processes to modify the data
4084		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4085	
4086		if ( typeof ajax === 'function' )
4087		{
4088			// Is a function - let the caller define what needs to be done
4089			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
4090		}
4091		else if (ajax.url === '') {
4092			// No url, so don't load any data. Just apply an empty data array
4093			// to the object for the callback.
4094			var empty = {};
4095	
4096			DataTable.util.set(ajax.dataSrc)(empty, []);
4097			callback(empty);
4098		}
4099		else {
4100			// Object to extend the base settings
4101			oSettings.jqXHR = $.ajax( baseAjax );
4102	
4103			// Restore for next time around
4104			if ( ajaxData ) {
4105				ajax.data = ajaxData;
4106			}
4107		}
4108	}
4109	
4110	
4111	/**
4112	 * Update the table using an Ajax call
4113	 *  @param {object} settings dataTables settings object
4114	 *  @returns {boolean} Block the table drawing or not
4115	 *  @memberof DataTable#oApi
4116	 */
4117	function _fnAjaxUpdate( settings )
4118	{
4119		settings.iDraw++;
4120		_fnProcessingDisplay( settings, true );
4121	
4122		_fnBuildAjax(
4123			settings,
4124			_fnAjaxParameters( settings ),
4125			function(json) {
4126				_fnAjaxUpdateDraw( settings, json );
4127			}
4128		);
4129	}
4130	
4131	
4132	/**
4133	 * Build up the parameters in an object needed for a server-side processing
4134	 * request.
4135	 *  @param {object} oSettings dataTables settings object
4136	 *  @returns {bool} block the table drawing or not
4137	 *  @memberof DataTable#oApi
4138	 */
4139	function _fnAjaxParameters( settings )
4140	{
4141		var
4142			columns = settings.aoColumns,
4143			features = settings.oFeatures,
4144			preSearch = settings.oPreviousSearch,
4145			preColSearch = settings.aoPreSearchCols,
4146			colData = function ( idx, prop ) {
4147				return typeof columns[idx][prop] === 'function' ?
4148					'function' :
4149					columns[idx][prop];
4150			};
4151	
4152		return {
4153			draw: settings.iDraw,
4154			columns: columns.map( function ( column, i ) {
4155				return {
4156					data: colData(i, 'mData'),
4157					name: column.sName,
4158					searchable: column.bSearchable,
4159					orderable: column.bSortable,
4160					search: {
4161						value: preColSearch[i].search,
4162						regex: preColSearch[i].regex,
4163						fixed: Object.keys(column.searchFixed).map( function(name) {
4164							return {
4165								name: name,
4166								term: column.searchFixed[name].toString()
4167							}
4168						})
4169					}
4170				};
4171			} ),
4172			order: _fnSortFlatten( settings ).map( function ( val ) {
4173				return {
4174					column: val.col,
4175					dir: val.dir,
4176					name: colData(val.col, 'sName')
4177				};
4178			} ),
4179			start: settings._iDisplayStart,
4180			length: features.bPaginate ?
4181				settings._iDisplayLength :
4182				-1,
4183			search: {
4184				value: preSearch.search,
4185				regex: preSearch.regex,
4186				fixed: Object.keys(settings.searchFixed).map( function(name) {
4187					return {
4188						name: name,
4189						term: settings.searchFixed[name].toString()
4190					}
4191				})
4192			}
4193		};
4194	}
4195	
4196	
4197	/**
4198	 * Data the data from the server (nuking the old) and redraw the table
4199	 *  @param {object} oSettings dataTables settings object
4200	 *  @param {object} json json data return from the server.
4201	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
4202	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4203	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4204	 *  @param {array} json.aaData The data to display on this page
4205	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4206	 *  @memberof DataTable#oApi
4207	 */
4208	function _fnAjaxUpdateDraw ( settings, json )
4209	{
4210		var data = _fnAjaxDataSrc(settings, json);
4211		var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
4212		var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
4213		var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
4214	
4215		if ( draw !== undefined ) {
4216			// Protect against out of sequence returns
4217			if ( draw*1 < settings.iDraw ) {
4218				return;
4219			}
4220			settings.iDraw = draw * 1;
4221		}
4222	
4223		// No data in returned object, so rather than an array, we show an empty table
4224		if ( ! data ) {
4225			data = [];
4226		}
4227	
4228		_fnClearTable( settings );
4229		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
4230		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4231	
4232		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4233			_fnAddData( settings, data[i] );
4234		}
4235		settings.aiDisplay = settings.aiDisplayMaster.slice();
4236	
4237		_fnDraw( settings, true );
4238		_fnInitComplete( settings );
4239		_fnProcessingDisplay( settings, false );
4240	}
4241	
4242	
4243	/**
4244	 * Get the data from the JSON data source to use for drawing a table. Using
4245	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4246	 * source object, or from a processing function.
4247	 *  @param {object} settings dataTables settings object
4248	 *  @param  {object} json Data source object / array from the server
4249	 *  @return {array} Array of data to use
4250	 */
4251	function _fnAjaxDataSrc ( settings, json, write )
4252	{
4253		var dataProp = 'data';
4254	
4255		if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
4256			// Could in inside a `dataSrc` object, or not!
4257			var dataSrc = settings.ajax.dataSrc;
4258	
4259			// string, function and object are valid types
4260			if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
4261				dataProp = dataSrc;
4262			}
4263			else if (dataSrc.data !== undefined) {
4264				dataProp = dataSrc.data;
4265			}
4266		}
4267	
4268		if ( ! write ) {
4269			if ( dataProp === 'data' ) {
4270				// If the default, then we still want to support the old style, and safely ignore
4271				// it if possible
4272				return json.aaData || json[dataProp];
4273			}
4274	
4275			return dataProp !== "" ?
4276				_fnGetObjectDataFn( dataProp )( json ) :
4277				json;
4278		}
4279		
4280		// set
4281		_fnSetObjectDataFn( dataProp )( json, write );
4282	}
4283	
4284	/**
4285	 * Very similar to _fnAjaxDataSrc, but for the other SSP properties
4286	 * @param {*} settings DataTables settings object
4287	 * @param {*} param Target parameter
4288	 * @param {*} json JSON data
4289	 * @returns Resolved value
4290	 */
4291	function _fnAjaxDataSrcParam (settings, param, json) {
4292		var dataSrc = $.isPlainObject( settings.ajax )
4293			? settings.ajax.dataSrc
4294			: null;
4295	
4296		if (dataSrc && dataSrc[param]) {
4297			// Get from custom location
4298			return _fnGetObjectDataFn( dataSrc[param] )( json );
4299		}
4300	
4301		// else - Default behaviour
4302		var old = '';
4303	
4304		// Legacy support
4305		if (param === 'draw') {
4306			old = 'sEcho';
4307		}
4308		else if (param === 'recordsTotal') {
4309			old = 'iTotalRecords';
4310		}
4311		else if (param === 'recordsFiltered') {
4312			old = 'iTotalDisplayRecords';
4313		}
4314	
4315		return json[old] !== undefined
4316			? json[old]
4317			: json[param];
4318	}
4319	
4320	
4321	/**
4322	 * Filter the table using both the global filter and column based filtering
4323	 *  @param {object} settings dataTables settings object
4324	 *  @param {object} input search information
4325	 *  @memberof DataTable#oApi
4326	 */
4327	function _fnFilterComplete ( settings, input )
4328	{
4329		var columnsSearch = settings.aoPreSearchCols;
4330	
4331		// Resolve any column types that are unknown due to addition or invalidation
4332		// @todo As per sort - can this be moved into an event handler?
4333		_fnColumnTypes( settings );
4334	
4335		// In server-side processing all filtering is done by the server, so no point hanging around here
4336		if ( _fnDataSource( settings ) != 'ssp' )
4337		{
4338			// Check if any of the rows were invalidated
4339			_fnFilterData( settings );
4340	
4341			// Start from the full data set
4342			settings.aiDisplay = settings.aiDisplayMaster.slice();
4343	
4344			// Global filter first
4345			_fnFilter( settings.aiDisplay, settings, input.search, input );
4346	
4347			$.each(settings.searchFixed, function (name, term) {
4348				_fnFilter(settings.aiDisplay, settings, term, {});
4349			});
4350	
4351			// Then individual column filters
4352			for ( var i=0 ; i<columnsSearch.length ; i++ )
4353			{
4354				var col = columnsSearch[i];
4355	
4356				_fnFilter(
4357					settings.aiDisplay,
4358					settings,
4359					col.search,
4360					col,
4361					i
4362				);
4363	
4364				$.each(settings.aoColumns[i].searchFixed, function (name, term) {
4365					_fnFilter(settings.aiDisplay, settings, term, {}, i);
4366				});
4367			}
4368	
4369			// And finally global filtering
4370			_fnFilterCustom( settings );
4371		}
4372	
4373		// Tell the draw function we have been filtering
4374		settings.bFiltered = true;
4375	
4376		_fnCallbackFire( settings, null, 'search', [settings] );
4377	}
4378	
4379	
4380	/**
4381	 * Apply custom filtering functions
4382	 * 
4383	 * This is legacy now that we have named functions, but it is widely used
4384	 * from 1.x, so it is not yet deprecated.
4385	 *  @param {object} oSettings dataTables settings object
4386	 *  @memberof DataTable#oApi
4387	 */
4388	function _fnFilterCustom( settings )
4389	{
4390		var filters = DataTable.ext.search;
4391		var displayRows = settings.aiDisplay;
4392		var row, rowIdx;
4393	
4394		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4395			var rows = [];
4396	
4397			// Loop over each row and see if it should be included
4398			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4399				rowIdx = displayRows[ j ];
4400				row = settings.aoData[ rowIdx ];
4401	
4402				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4403					rows.push( rowIdx );
4404				}
4405			}
4406	
4407			// So the array reference doesn't break set the results into the
4408			// existing array
4409			displayRows.length = 0;
4410			displayRows.push.apply(displayRows, rows);
4411		}
4412	}
4413	
4414	
4415	/**
4416	 * Filter the data table based on user input and draw the table
4417	 */
4418	function _fnFilter( searchRows, settings, input, options, column )
4419	{
4420		if ( input === '' ) {
4421			return;
4422		}
4423	
4424		var i = 0;
4425		var matched = [];
4426	
4427		// Search term can be a function, regex or string - if a string we apply our
4428		// smart filtering regex (assuming the options require that)
4429		var searchFunc = typeof input === 'function' ? input : null;
4430		var rpSearch = input instanceof RegExp
4431			? input
4432			: searchFunc
4433				? null
4434				: _fnFilterCreateSearch( input, options );
4435	
4436		// Then for each row, does the test pass. If not, lop the row from the array
4437		for (i=0 ; i<searchRows.length ; i++) {
4438			var row = settings.aoData[ searchRows[i] ];
4439			var data = column === undefined
4440				? row._sFilterRow
4441				: row._aFilterData[ column ];
4442	
4443			if ( (searchFunc && searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && rpSearch.test(data)) ) {
4444				matched.push(searchRows[i]);
4445			}
4446		}
4447	
4448		// Mutate the searchRows array
4449		searchRows.length = matched.length;
4450	
4451		for (i=0 ; i<matched.length ; i++) {
4452			searchRows[i] = matched[i];
4453		}
4454	}
4455	
4456	
4457	/**
4458	 * Build a regular expression object suitable for searching a table
4459	 *  @param {string} sSearch string to search for
4460	 *  @param {bool} bRegex treat as a regular expression or not
4461	 *  @param {bool} bSmart perform smart filtering or not
4462	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4463	 *  @returns {RegExp} constructed object
4464	 *  @memberof DataTable#oApi
4465	 */
4466	function _fnFilterCreateSearch( search, inOpts )
4467	{
4468		var not = [];
4469		var options = $.extend({}, {
4470			boundary: false,
4471			caseInsensitive: true,
4472			exact: false,
4473			regex: false,
4474			smart: true
4475		}, inOpts);
4476	
4477		if (typeof search !== 'string') {
4478			search = search.toString();
4479		}
4480	
4481		// Remove diacritics if normalize is set up to do so
4482		search = _normalize(search);
4483	
4484		if (options.exact) {
4485			return new RegExp(
4486				'^'+_fnEscapeRegex(search)+'$',
4487				options.caseInsensitive ? 'i' : ''
4488			);
4489		}
4490	
4491		search = options.regex ?
4492			search :
4493			_fnEscapeRegex( search );
4494		
4495		if ( options.smart ) {
4496			/* For smart filtering we want to allow the search to work regardless of
4497			 * word order. We also want double quoted text to be preserved, so word
4498			 * order is important - a la google. And a negative look around for
4499			 * finding rows which don't contain a given string.
4500			 * 
4501			 * So this is the sort of thing we want to generate:
4502			 * 
4503			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4504			 */
4505			var parts = search.match( /!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''];
4506			var a = parts.map( function ( word ) {
4507				var negative = false;
4508				var m;
4509	
4510				// Determine if it is a "does not include"
4511				if ( word.charAt(0) === '!' ) {
4512					negative = true;
4513					word = word.substring(1);
4514				}
4515	
4516				// Strip the quotes from around matched phrases
4517				if ( word.charAt(0) === '"' ) {
4518					m = word.match( /^"(.*)"$/ );
4519					word = m ? m[1] : word;
4520				}
4521				else if ( word.charAt(0) === '\u201C' ) {
4522					// Smart quote match (iPhone users)
4523					m = word.match( /^\u201C(.*)\u201D$/ );
4524					word = m ? m[1] : word;
4525				}
4526	
4527				// For our "not" case, we need to modify the string that is
4528				// allowed to match at the end of the expression.
4529				if (negative) {
4530					if (word.length > 1) {
4531						not.push('(?!'+word+')');
4532					}
4533	
4534					word = '';
4535				}
4536	
4537				return word.replace(/"/g, '');
4538			} );
4539	
4540			var match = not.length
4541				? not.join('')
4542				: '';
4543	
4544			var boundary = options.boundary
4545				? '\\b'
4546				: '';
4547	
4548			search = '^(?=.*?'+boundary+a.join( ')(?=.*?'+boundary )+')('+match+'.)*$';
4549		}
4550	
4551		return new RegExp( search, options.caseInsensitive ? 'i' : '' );
4552	}
4553	
4554	
4555	/**
4556	 * Escape a string such that it can be used in a regular expression
4557	 *  @param {string} sVal string to escape
4558	 *  @returns {string} escaped string
4559	 *  @memberof DataTable#oApi
4560	 */
4561	var _fnEscapeRegex = DataTable.util.escapeRegex;
4562	
4563	var __filter_div = $('<div>')[0];
4564	var __filter_div_textContent = __filter_div.textContent !== undefined;
4565	
4566	// Update the filtering data for each row if needed (by invalidation or first run)
4567	function _fnFilterData ( settings )
4568	{
4569		var columns = settings.aoColumns;
4570		var data = settings.aoData;
4571		var column;
4572		var j, jen, filterData, cellData, row;
4573		var wasInvalidated = false;
4574	
4575		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
4576			if (! data[rowIdx]) {
4577				continue;
4578			}
4579	
4580			row = data[rowIdx];
4581	
4582			if ( ! row._aFilterData ) {
4583				filterData = [];
4584	
4585				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4586					column = columns[j];
4587	
4588					if ( column.bSearchable ) {
4589						cellData = _fnGetCellData( settings, rowIdx, j, 'filter' );
4590	
4591						// Search in DataTables is string based
4592						if ( cellData === null ) {
4593							cellData = '';
4594						}
4595	
4596						if ( typeof cellData !== 'string' && cellData.toString ) {
4597							cellData = cellData.toString();
4598						}
4599					}
4600					else {
4601						cellData = '';
4602					}
4603	
4604					// If it looks like there is an HTML entity in the string,
4605					// attempt to decode it so sorting works as expected. Note that
4606					// we could use a single line of jQuery to do this, but the DOM
4607					// method used here is much faster https://jsperf.com/html-decode
4608					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4609						__filter_div.innerHTML = cellData;
4610						cellData = __filter_div_textContent ?
4611							__filter_div.textContent :
4612							__filter_div.innerText;
4613					}
4614	
4615					if ( cellData.replace ) {
4616						cellData = cellData.replace(/[\r\n\u2028]/g, '');
4617					}
4618	
4619					filterData.push( cellData );
4620				}
4621	
4622				row._aFilterData = filterData;
4623				row._sFilterRow = filterData.join('  ');
4624				wasInvalidated = true;
4625			}
4626		}
4627	
4628		return wasInvalidated;
4629	}
4630	
4631	
4632	/**
4633	 * Draw the table for the first time, adding all required features
4634	 *  @param {object} settings dataTables settings object
4635	 *  @memberof DataTable#oApi
4636	 */
4637	function _fnInitialise ( settings )
4638	{
4639		var i, iAjaxStart=settings.iInitDisplayStart;
4640	
4641		/* Ensure that the table data is fully initialised */
4642		if ( ! settings.bInitialised ) {
4643			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4644			return;
4645		}
4646	
4647		/* Build and draw the header / footer for the table */
4648		_fnBuildHead( settings, 'header' );
4649		_fnBuildHead( settings, 'footer' );
4650		_fnDrawHead( settings, settings.aoHeader );
4651		_fnDrawHead( settings, settings.aoFooter );
4652	
4653		// Enable features
4654		_fnAddOptionsHtml( settings );
4655		_fnSortInit( settings );
4656	
4657		_colGroup( settings );
4658	
4659		/* Okay to show that something is going on now */
4660		_fnProcessingDisplay( settings, true );
4661	
4662		_fnCallbackFire( settings, null, 'preInit', [settings], true );
4663	
4664		// If there is default sorting required - let's do it. The sort function
4665		// will do the drawing for us. Otherwise we draw the table regardless of the
4666		// Ajax source - this allows the table to look initialised for Ajax sourcing
4667		// data (show 'loading' message possibly)
4668		_fnReDraw( settings );
4669	
4670		var dataSrc = _fnDataSource( settings );
4671	
4672		// Server-side processing init complete is done by _fnAjaxUpdateDraw
4673		if ( dataSrc != 'ssp' ) {
4674			// if there is an ajax source load the data
4675			if ( dataSrc == 'ajax' ) {
4676				_fnBuildAjax( settings, {}, function(json) {
4677					var aData = _fnAjaxDataSrc( settings, json );
4678	
4679					// Got the data - add it to the table
4680					for ( i=0 ; i<aData.length ; i++ ) {
4681						_fnAddData( settings, aData[i] );
4682					}
4683	
4684					// Reset the init display for cookie saving. We've already done
4685					// a filter, and therefore cleared it before. So we need to make
4686					// it appear 'fresh'
4687					settings.iInitDisplayStart = iAjaxStart;
4688	
4689					_fnReDraw( settings );
4690					_fnProcessingDisplay( settings, false );
4691					_fnInitComplete( settings );
4692				}, settings );
4693			}
4694			else {
4695				_fnInitComplete( settings );
4696				_fnProcessingDisplay( settings, false );
4697			}
4698		}
4699	}
4700	
4701	
4702	/**
4703	 * Draw the table for the first time, adding all required features
4704	 *  @param {object} settings dataTables settings object
4705	 *  @memberof DataTable#oApi
4706	 */
4707	function _fnInitComplete ( settings )
4708	{
4709		if (settings._bInitComplete) {
4710			return;
4711		}
4712	
4713		var args = [settings, settings.json];
4714	
4715		settings._bInitComplete = true;
4716	
4717		// Table is fully set up and we have data, so calculate the
4718		// column widths
4719		_fnAdjustColumnSizing( settings );
4720	
4721		_fnCallbackFire( settings, null, 'plugin-init', args, true );
4722		_fnCallbackFire( settings, 'aoInitComplete', 'init', args, true );
4723	}
4724	
4725	function _fnLengthChange ( settings, val )
4726	{
4727		var len = parseInt( val, 10 );
4728		settings._iDisplayLength = len;
4729	
4730		_fnLengthOverflow( settings );
4731	
4732		// Fire length change event
4733		_fnCallbackFire( settings, null, 'length', [settings, len] );
4734	}
4735	
4736	/**
4737	 * Alter the display settings to change the page
4738	 *  @param {object} settings DataTables settings object
4739	 *  @param {string|int} action Paging action to take: "first", "previous",
4740	 *    "next" or "last" or page number to jump to (integer)
4741	 *  @param [bool] redraw Automatically draw the update or not
4742	 *  @returns {bool} true page has changed, false - no change
4743	 *  @memberof DataTable#oApi
4744	 */
4745	function _fnPageChange ( settings, action, redraw )
4746	{
4747		var
4748			start     = settings._iDisplayStart,
4749			len       = settings._iDisplayLength,
4750			records   = settings.fnRecordsDisplay();
4751	
4752		if ( records === 0 || len === -1 )
4753		{
4754			start = 0;
4755		}
4756		else if ( typeof action === "number" )
4757		{
4758			start = action * len;
4759	
4760			if ( start > records )
4761			{
4762				start = 0;
4763			}
4764		}
4765		else if ( action == "first" )
4766		{
4767			start = 0;
4768		}
4769		else if ( action == "previous" )
4770		{
4771			start = len >= 0 ?
4772				start - len :
4773				0;
4774	
4775			if ( start < 0 )
4776			{
4777				start = 0;
4778			}
4779		}
4780		else if ( action == "next" )
4781		{
4782			if ( start + len < records )
4783			{
4784				start += len;
4785			}
4786		}
4787		else if ( action == "last" )
4788		{
4789			start = Math.floor( (records-1) / len) * len;
4790		}
4791		else if ( action === 'ellipsis' )
4792		{
4793			return;
4794		}
4795		else
4796		{
4797			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4798		}
4799	
4800		var changed = settings._iDisplayStart !== start;
4801		settings._iDisplayStart = start;
4802	
4803		_fnCallbackFire( settings, null, changed ? 'page' : 'page-nc', [settings] );
4804	
4805		if ( changed && redraw ) {
4806			_fnDraw( settings );
4807		}
4808	
4809		return changed;
4810	}
4811	
4812	
4813	/**
4814	 * Generate the node required for the processing node
4815	 *  @param {object} settings DataTables settings object
4816	 */
4817	function _processingHtml ( settings )
4818	{
4819		var table = settings.nTable;
4820		var scrolling = settings.oScroll.sX !== '' || settings.oScroll.sY !== '';
4821	
4822		if ( settings.oFeatures.bProcessing ) {
4823			var n = $('<div/>', {
4824					'id': settings.sTableId + '_processing',
4825					'class': settings.oClasses.processing.container,
4826					'role': 'status'
4827				} )
4828				.html( settings.oLanguage.sProcessing )
4829				.append('<div><div></div><div></div><div></div><div></div></div>');
4830	
4831			// Different positioning depending on if scrolling is enabled or not
4832			if (scrolling) {
4833				n.prependTo( $('div.dt-scroll', settings.nTableWrapper) );
4834			}
4835			else {
4836				n.insertBefore( table );
4837			}
4838	
4839			$(table).on( 'processing.dt.DT', function (e, s, show) {
4840				n.css( 'display', show ? 'block' : 'none' );
4841			} );
4842		}
4843	}
4844	
4845	
4846	/**
4847	 * Display or hide the processing indicator
4848	 *  @param {object} settings DataTables settings object
4849	 *  @param {bool} show Show the processing indicator (true) or not (false)
4850	 */
4851	function _fnProcessingDisplay ( settings, show )
4852	{
4853		_fnCallbackFire( settings, null, 'processing', [settings, show] );
4854	}
4855	/**
4856	 * Add any control elements for the table - specifically scrolling
4857	 *  @param {object} settings dataTables settings object
4858	 *  @returns {node} Node to add to the DOM
4859	 *  @memberof DataTable#oApi
4860	 */
4861	function _fnFeatureHtmlTable ( settings )
4862	{
4863		var table = $(settings.nTable);
4864	
4865		// Scrolling from here on in
4866		var scroll = settings.oScroll;
4867	
4868		if ( scroll.sX === '' && scroll.sY === '' ) {
4869			return settings.nTable;
4870		}
4871	
4872		var scrollX = scroll.sX;
4873		var scrollY = scroll.sY;
4874		var classes = settings.oClasses.scrolling;
4875		var caption = settings.captionNode;
4876		var captionSide = caption ? caption._captionSide : null;
4877		var headerClone = $( table[0].cloneNode(false) );
4878		var footerClone = $( table[0].cloneNode(false) );
4879		var footer = table.children('tfoot');
4880		var _div = '<div/>';
4881		var size = function ( s ) {
4882			return !s ? null : _fnStringToCss( s );
4883		};
4884	
4885		if ( ! footer.length ) {
4886			footer = null;
4887		}
4888	
4889		/*
4890		 * The HTML structure that we want to generate in this function is:
4891		 *  div - scroller
4892		 *    div - scroll head
4893		 *      div - scroll head inner
4894		 *        table - scroll head table
4895		 *          thead - thead
4896		 *    div - scroll body
4897		 *      table - table (master table)
4898		 *        thead - thead clone for sizing
4899		 *        tbody - tbody
4900		 *    div - scroll foot
4901		 *      div - scroll foot inner
4902		 *        table - scroll foot table
4903		 *          tfoot - tfoot
4904		 */
4905		var scroller = $( _div, { 'class': classes.container } )
4906			.append(
4907				$(_div, { 'class': classes.header.self } )
4908					.css( {
4909						overflow: 'hidden',
4910						position: 'relative',
4911						border: 0,
4912						width: scrollX ? size(scrollX) : '100%'
4913					} )
4914					.append(
4915						$(_div, { 'class': classes.header.inner } )
4916							.css( {
4917								'box-sizing': 'content-box',
4918								width: scroll.sXInner || '100%'
4919							} )
4920							.append(
4921								headerClone
4922									.removeAttr('id')
4923									.css( 'margin-left', 0 )
4924									.append( captionSide === 'top' ? caption : null )
4925									.append(
4926										table.children('thead')
4927									)
4928							)
4929					)
4930			)
4931			.append(
4932				$(_div, { 'class': classes.body } )
4933					.css( {
4934						position: 'relative',
4935						overflow: 'auto',
4936						width: size( scrollX )
4937					} )
4938					.append( table )
4939			);
4940	
4941		if ( footer ) {
4942			scroller.append(
4943				$(_div, { 'class': classes.footer.self } )
4944					.css( {
4945						overflow: 'hidden',
4946						border: 0,
4947						width: scrollX ? size(scrollX) : '100%'
4948					} )
4949					.append(
4950						$(_div, { 'class': classes.footer.inner } )
4951							.append(
4952								footerClone
4953									.removeAttr('id')
4954									.css( 'margin-left', 0 )
4955									.append( captionSide === 'bottom' ? caption : null )
4956									.append(
4957										table.children('tfoot')
4958									)
4959							)
4960					)
4961			);
4962		}
4963	
4964		var children = scroller.children();
4965		var scrollHead = children[0];
4966		var scrollBody = children[1];
4967		var scrollFoot = footer ? children[2] : null;
4968	
4969		// When the body is scrolled, then we also want to scroll the headers
4970		$(scrollBody).on( 'scroll.DT', function () {
4971			var scrollLeft = this.scrollLeft;
4972	
4973			scrollHead.scrollLeft = scrollLeft;
4974	
4975			if ( footer ) {
4976				scrollFoot.scrollLeft = scrollLeft;
4977			}
4978		} );
4979	
4980		// When focus is put on the header cells, we might need to scroll the body
4981		$('th, td', scrollHead).on('focus', function () {
4982			var scrollLeft = scrollHead.scrollLeft;
4983	
4984			scrollBody.scrollLeft = scrollLeft;
4985	
4986			if ( footer ) {
4987				scrollBody.scrollLeft = scrollLeft;
4988			}
4989		});
4990	
4991		$(scrollBody).css('max-height', scrollY);
4992		if (! scroll.bCollapse) {
4993			$(scrollBody).css('height', scrollY);
4994		}
4995	
4996		settings.nScrollHead = scrollHead;
4997		settings.nScrollBody = scrollBody;
4998		settings.nScrollFoot = scrollFoot;
4999	
5000		// On redraw - align columns
5001		settings.aoDrawCallback.push(_fnScrollDraw);
5002	
5003		return scroller[0];
5004	}
5005	
5006	
5007	
5008	/**
5009	 * Update the header, footer and body tables for resizing - i.e. column
5010	 * alignment.
5011	 *
5012	 * Welcome to the most horrible function DataTables. The process that this
5013	 * function follows is basically:
5014	 *   1. Re-create the table inside the scrolling div
5015	 *   2. Correct colgroup > col values if needed
5016	 *   3. Copy colgroup > col over to header and footer
5017	 *   4. Clean up
5018	 *
5019	 *  @param {object} settings dataTables settings object
5020	 *  @memberof DataTable#oApi
5021	 */
5022	function _fnScrollDraw ( settings )
5023	{
5024		// Given that this is such a monster function, a lot of variables are use
5025		// to try and keep the minimised size as small as possible
5026		var
5027			scroll         = settings.oScroll,
5028			barWidth       = scroll.iBarWidth,
5029			divHeader      = $(settings.nScrollHead),
5030			divHeaderInner = divHeader.children('div'),
5031			divHeaderTable = divHeaderInner.children('table'),
5032			divBodyEl      = settings.nScrollBody,
5033			divBody        = $(divBodyEl),
5034			divFooter      = $(settings.nScrollFoot),
5035			divFooterInner = divFooter.children('div'),
5036			divFooterTable = divFooterInner.children('table'),
5037			header         = $(settings.nTHead),
5038			table          = $(settings.nTable),
5039			footer         = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
5040			browser        = settings.oBrowser,
5041			headerCopy, footerCopy;
5042	
5043		// If the scrollbar visibility has changed from the last draw, we need to
5044		// adjust the column sizes as the table width will have changed to account
5045		// for the scrollbar
5046		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5047		
5048		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5049			settings.scrollBarVis = scrollBarVis;
5050			_fnAdjustColumnSizing( settings );
5051			return; // adjust column sizing will call this function again
5052		}
5053		else {
5054			settings.scrollBarVis = scrollBarVis;
5055		}
5056	
5057		// 1. Re-create the table inside the scrolling div
5058		// Remove the old minimised thead and tfoot elements in the inner table
5059		table.children('thead, tfoot').remove();
5060	
5061		// Clone the current header and footer elements and then place it into the inner table
5062		headerCopy = header.clone().prependTo( table );
5063		headerCopy.find('th, td').removeAttr('tabindex');
5064		headerCopy.find('[id]').removeAttr('id');
5065	
5066		if ( footer ) {
5067			footerCopy = footer.clone().prependTo( table );
5068			footerCopy.find('[id]').removeAttr('id');
5069		}
5070	
5071		// 2. Correct colgroup > col values if needed
5072		// It is possible that the cell sizes are smaller than the content, so we need to
5073		// correct colgroup>col for such cases. This can happen if the auto width detection
5074		// uses a cell which has a longer string, but isn't the widest! For example 
5075		// "Chief Executive Officer (CEO)" is the longest string in the demo, but
5076		// "Systems Administrator" is actually the widest string since it doesn't collapse.
5077		// Note the use of translating into a column index to get the `col` element. This
5078		// is because of Responsive which might remove `col` elements, knocking the alignment
5079		// of the indexes out.
5080		if (settings.aiDisplay.length) {
5081			// Get the column sizes from the first row in the table
5082			var colSizes = table.children('tbody').eq(0).children('tr').eq(0).children('th, td').map(function (vis) {
5083				return {
5084					idx: _fnVisibleToColumnIndex(settings, vis),
5085					width: $(this).outerWidth()
5086				}
5087			});
5088	
5089			// Check against what the colgroup > col is set to and correct if needed
5090			for (var i=0 ; i<colSizes.length ; i++) {
5091				var colEl = settings.aoColumns[ colSizes[i].idx ].colEl[0];
5092				var colWidth = colEl.style.width.replace('px', '');
5093	
5094				if (colWidth !== colSizes[i].width) {
5095					colEl.style.width = colSizes[i].width + 'px';
5096				}
5097			}
5098		}
5099	
5100		// 3. Copy the colgroup over to the header and footer
5101		divHeaderTable
5102			.find('colgroup')
5103			.remove();
5104	
5105		divHeaderTable.append(settings.colgroup.clone());
5106	
5107		if ( footer ) {
5108			divFooterTable
5109				.find('colgroup')
5110				.remove();
5111	
5112			divFooterTable.append(settings.colgroup.clone());
5113		}
5114	
5115		// "Hide" the header and footer that we used for the sizing. We need to keep
5116		// the content of the cell so that the width applied to the header and body
5117		// both match, but we want to hide it completely.
5118		$('th, td', headerCopy).each(function () {
5119			$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5120		});
5121	
5122		if ( footer ) {
5123			$('th, td', footerCopy).each(function () {
5124				$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5125			});
5126		}
5127	
5128		// 4. Clean up
5129		// Figure out if there are scrollbar present - if so then we need a the header and footer to
5130		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5131		var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5132		var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5133	
5134		// Set the width's of the header and footer tables
5135		var outerWidth = table.outerWidth();
5136	
5137		divHeaderTable.css('width', _fnStringToCss( outerWidth ));
5138		divHeaderInner
5139			.css('width', _fnStringToCss( outerWidth ))
5140			.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5141	
5142		if ( footer ) {
5143			divFooterTable.css('width', _fnStringToCss( outerWidth ));
5144			divFooterInner
5145				.css('width', _fnStringToCss( outerWidth ))
5146				.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5147		}
5148	
5149		// Correct DOM ordering for colgroup - comes before the thead
5150		table.children('colgroup').prependTo(table);
5151	
5152		// Adjust the position of the header in case we loose the y-scrollbar
5153		divBody.trigger('scroll');
5154	
5155		// If sorting or filtering has occurred, jump the scrolling back to the top
5156		// only if we aren't holding the position
5157		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5158			divBodyEl.scrollTop = 0;
5159		}
5160	}
5161	
5162	/**
5163	 * Calculate the width of columns for the table
5164	 *  @param {object} settings dataTables settings object
5165	 *  @memberof DataTable#oApi
5166	 */
5167	function _fnCalculateColumnWidths ( settings )
5168	{
5169		// Not interested in doing column width calculation if auto-width is disabled
5170		if (! settings.oFeatures.bAutoWidth) {
5171			return;
5172		}
5173	
5174		var
5175			table = settings.nTable,
5176			columns = settings.aoColumns,
5177			scroll = settings.oScroll,
5178			scrollY = scroll.sY,
5179			scrollX = scroll.sX,
5180			scrollXInner = scroll.sXInner,
5181			visibleColumns = _fnGetColumns( settings, 'bVisible' ),
5182			tableWidthAttr = table.getAttribute('width'), // from DOM element
5183			tableContainer = table.parentNode,
5184			i, column, columnIdx;
5185	
5186		var styleWidth = table.style.width;
5187		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5188			tableWidthAttr = styleWidth;
5189		}
5190	
5191		// Let plug-ins know that we are doing a recalc, in case they have changed any of the
5192		// visible columns their own way (e.g. Responsive uses display:none).
5193		_fnCallbackFire(
5194			settings,
5195			null,
5196			'column-calc',
5197			{visible: visibleColumns},
5198			false
5199		);
5200	
5201		// Construct a single row, worst case, table with the widest
5202		// node in the data, assign any user defined widths, then insert it into
5203		// the DOM and allow the browser to do all the hard work of calculating
5204		// table widths
5205		var tmpTable = $(table.cloneNode())
5206			.css( 'visibility', 'hidden' )
5207			.removeAttr( 'id' );
5208	
5209		// Clean up the table body
5210		tmpTable.append('<tbody>')
5211		var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5212	
5213		// Clone the table header and footer - we can't use the header / footer
5214		// from the cloned table, since if scrolling is active, the table's
5215		// real header and footer are contained in different table tags
5216		tmpTable
5217			.append( $(settings.nTHead).clone() )
5218			.append( $(settings.nTFoot).clone() );
5219	
5220		// Remove any assigned widths from the footer (from scrolling)
5221		tmpTable.find('tfoot th, tfoot td').css('width', '');
5222	
5223		// Apply custom sizing to the cloned header
5224		tmpTable.find('thead th, thead td').each( function () {
5225			// Get the `width` from the header layout
5226			var width = _fnColumnsSumWidth( settings, this, true, false );
5227	
5228			if ( width ) {
5229				this.style.width = width;
5230	
5231				// For scrollX we need to force the column width otherwise the
5232				// browser will collapse it. If this width is smaller than the
5233				// width the column requires, then it will have no effect
5234				if ( scrollX ) {
5235					$( this ).append( $('<div/>').css( {
5236						width: width,
5237						margin: 0,
5238						padding: 0,
5239						border: 0,
5240						height: 1
5241					} ) );
5242				}
5243			}
5244			else {
5245				this.style.width = '';
5246			}
5247		} );
5248	
5249		// Find the widest piece of data for each column and put it into the table
5250		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5251			columnIdx = visibleColumns[i];
5252			column = columns[ columnIdx ];
5253	
5254			var longest = _fnGetMaxLenString(settings, columnIdx);
5255			var autoClass = _ext.type.className[column.sType];
5256			var text = longest + column.sContentPadding;
5257			var insert = longest.indexOf('<') === -1
5258				? document.createTextNode(text)
5259				: text
5260			
5261			$('<td/>')
5262				.addClass(autoClass)
5263				.addClass(column.sClass)
5264				.append(insert)
5265				.appendTo(tr);
5266		}
5267	
5268		// Tidy the temporary table - remove name attributes so there aren't
5269		// duplicated in the dom (radio elements for example)
5270		$('[name]', tmpTable).removeAttr('name');
5271	
5272		// Table has been built, attach to the document so we can work with it.
5273		// A holding element is used, positioned at the top of the container
5274		// with minimal height, so it has no effect on if the container scrolls
5275		// or not. Otherwise it might trigger scrolling when it actually isn't
5276		// needed
5277		var holder = $('<div/>').css( scrollX || scrollY ?
5278				{
5279					position: 'absolute',
5280					top: 0,
5281					left: 0,
5282					height: 1,
5283					right: 0,
5284					overflow: 'hidden'
5285				} :
5286				{}
5287			)
5288			.append( tmpTable )
5289			.appendTo( tableContainer );
5290	
5291		// When scrolling (X or Y) we want to set the width of the table as 
5292		// appropriate. However, when not scrolling leave the table width as it
5293		// is. This results in slightly different, but I think correct behaviour
5294		if ( scrollX && scrollXInner ) {
5295			tmpTable.width( scrollXInner );
5296		}
5297		else if ( scrollX ) {
5298			tmpTable.css( 'width', 'auto' );
5299			tmpTable.removeAttr('width');
5300	
5301			// If there is no width attribute or style, then allow the table to
5302			// collapse
5303			if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5304				tmpTable.width( tableContainer.clientWidth );
5305			}
5306		}
5307		else if ( scrollY ) {
5308			tmpTable.width( tableContainer.clientWidth );
5309		}
5310		else if ( tableWidthAttr ) {
5311			tmpTable.width( tableWidthAttr );
5312		}
5313	
5314		// Get the width of each column in the constructed table
5315		var total = 0;
5316		var bodyCells = tmpTable.find('tbody tr').eq(0).children();
5317	
5318		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5319			// Use getBounding for sub-pixel accuracy, which we then want to round up!
5320			var bounding = bodyCells[i].getBoundingClientRect().width;
5321	
5322			// Total is tracked to remove any sub-pixel errors as the outerWidth
5323			// of the table might not equal the total given here
5324			total += bounding;
5325	
5326			// Width for each column to use
5327			columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding );
5328		}
5329	
5330		table.style.width = _fnStringToCss( total );
5331	
5332		// Finished with the table - ditch it
5333		holder.remove();
5334	
5335		// If there is a width attr, we want to attach an event listener which
5336		// allows the table sizing to automatically adjust when the window is
5337		// resized. Use the width attr rather than CSS, since we can't know if the
5338		// CSS is a relative value or absolute - DOM read is always px.
5339		if ( tableWidthAttr ) {
5340			table.style.width = _fnStringToCss( tableWidthAttr );
5341		}
5342	
5343		if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
5344			var bindResize = function () {
5345				$(window).on('resize.DT-'+settings.sInstance, DataTable.util.throttle( function () {
5346					if (! settings.bDestroying) {
5347						_fnAdjustColumnSizing( settings );
5348					}
5349				} ) );
5350			};
5351	
5352			bindResize();
5353	
5354			settings._reszEvt = true;
5355		}
5356	}
5357	
5358	
5359	/**
5360	 * Get the maximum strlen for each data column
5361	 *  @param {object} settings dataTables settings object
5362	 *  @param {int} colIdx column of interest
5363	 *  @returns {string} string of the max length
5364	 *  @memberof DataTable#oApi
5365	 */
5366	function _fnGetMaxLenString( settings, colIdx )
5367	{
5368		var column = settings.aoColumns[colIdx];
5369	
5370		if (! column.maxLenString) {
5371			var s, max='', maxLen = -1;
5372		
5373			for ( var i=0, ien=settings.aiDisplayMaster.length ; i<ien ; i++ ) {
5374				var rowIdx = settings.aiDisplayMaster[i];
5375				var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
5376	
5377				var cellString = data && typeof data === 'object' && data.nodeType
5378					? data.innerHTML
5379					: data+'';
5380	
5381				// Remove id / name attributes from elements so they
5382				// don't interfere with existing elements
5383				cellString = cellString
5384					.replace(/id=".*?"/g, '')
5385					.replace(/name=".*?"/g, '');
5386	
5387				s = _stripHtml(cellString)
5388					.replace( /&nbsp;/g, ' ' );
5389		
5390				if ( s.length > maxLen ) {
5391					// We want the HTML in the string, but the length that
5392					// is important is the stripped string
5393					max = cellString;
5394					maxLen = s.length;
5395				}
5396			}
5397	
5398			column.maxLenString = max;
5399		}
5400	
5401		return column.maxLenString;
5402	}
5403	
5404	
5405	/**
5406	 * Append a CSS unit (only if required) to a string
5407	 *  @param {string} value to css-ify
5408	 *  @returns {string} value with css unit
5409	 *  @memberof DataTable#oApi
5410	 */
5411	function _fnStringToCss( s )
5412	{
5413		if ( s === null ) {
5414			return '0px';
5415		}
5416	
5417		if ( typeof s == 'number' ) {
5418			return s < 0 ?
5419				'0px' :
5420				s+'px';
5421		}
5422	
5423		// Check it has a unit character already
5424		return s.match(/\d$/) ?
5425			s+'px' :
5426			s;
5427	}
5428	
5429	/**
5430	 * Re-insert the `col` elements for current visibility
5431	 *
5432	 * @param {*} settings DT settings
5433	 */
5434	function _colGroup( settings ) {
5435		var cols = settings.aoColumns;
5436	
5437		settings.colgroup.empty();
5438	
5439		for (i=0 ; i<cols.length ; i++) {
5440			if (cols[i].bVisible) {
5441				settings.colgroup.append(cols[i].colEl);
5442			}
5443		}
5444	}
5445	
5446	
5447	function _fnSortInit( settings ) {
5448		var target = settings.nTHead;
5449		var headerRows = target.querySelectorAll('tr');
5450		var legacyTop = settings.bSortCellsTop;
5451		var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5452		
5453		// Legacy support for `orderCellsTop`
5454		if (legacyTop === true) {
5455			target = headerRows[0];
5456		}
5457		else if (legacyTop === false) {
5458			target = headerRows[ headerRows.length - 1 ];
5459		}
5460	
5461		_fnSortAttachListener(
5462			settings,
5463			target,
5464			target === settings.nTHead
5465				? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5466				: 'th'+notSelector+', td'+notSelector
5467		);
5468	
5469		// Need to resolve the user input array into our internal structure
5470		var order = [];
5471		_fnSortResolve( settings, order, settings.aaSorting );
5472	
5473		settings.aaSorting = order;
5474	}
5475	
5476	
5477	function _fnSortAttachListener(settings, node, selector, column, callback) {
5478		_fnBindAction( node, selector, function (e) {
5479			var run = false;
5480			var columns = column === undefined
5481				? _fnColumnsFromHeader( e.target )
5482				: [column];
5483	
5484			if ( columns.length ) {
5485				for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
5486					var ret = _fnSortAdd( settings, columns[i], i, e.shiftKey );
5487	
5488					if (ret !== false) {
5489						run = true;
5490					}					
5491	
5492					// If the first entry is no sort, then subsequent
5493					// sort columns are ignored
5494					if (settings.aaSorting.length === 1 && settings.aaSorting[0][1] === '') {
5495						break;
5496					}
5497				}
5498	
5499				if (run) {
5500					_fnProcessingDisplay( settings, true );
5501	
5502					// Allow the processing display to show
5503					setTimeout( function () {
5504						_fnSort( settings );
5505						_fnSortDisplay( settings, settings.aiDisplay );
5506	
5507						// Sort processing done - redraw has its own processing display
5508						_fnProcessingDisplay( settings, false );
5509	
5510						_fnReDraw( settings, false, false );
5511	
5512						if (callback) {
5513							callback();
5514						}
5515					}, 0);
5516				}
5517			}
5518		} );
5519	}
5520	
5521	/**
5522	 * Sort the display array to match the master's order
5523	 * @param {*} settings
5524	 */
5525	function _fnSortDisplay(settings, display) {
5526		if (display.length < 2) {
5527			return;
5528		}
5529	
5530		var master = settings.aiDisplayMaster;
5531		var masterMap = {};
5532		var map = {};
5533		var i;
5534	
5535		// Rather than needing an `indexOf` on master array, we can create a map
5536		for (i=0 ; i<master.length ; i++) {
5537			masterMap[master[i]] = i;
5538		}
5539	
5540		// And then cache what would be the indexOf fom the display
5541		for (i=0 ; i<display.length ; i++) {
5542			map[display[i]] = masterMap[display[i]];
5543		}
5544	
5545		display.sort(function(a, b){
5546			// Short version of this function is simply `master.indexOf(a) - master.indexOf(b);`
5547			return map[a] - map[b];
5548		});
5549	}
5550	
5551	
5552	function _fnSortResolve (settings, nestedSort, sort) {
5553		var push = function ( a ) {
5554			if ($.isPlainObject(a)) {
5555				if (a.idx !== undefined) {
5556					// Index based ordering
5557					nestedSort.push([a.idx, a.dir]);
5558				}
5559				else if (a.name) {
5560					// Name based ordering
5561					var cols = _pluck( settings.aoColumns, 'sName');
5562					var idx = cols.indexOf(a.name);
5563	
5564					if (idx !== -1) {
5565						nestedSort.push([idx, a.dir]);
5566					}
5567				}
5568			}
5569			else {
5570				// Plain column index and direction pair
5571				nestedSort.push(a);
5572			}
5573		};
5574	
5575		if ( $.isPlainObject(sort) ) {
5576			// Object
5577			push(sort);
5578		}
5579		else if ( sort.length && typeof sort[0] === 'number' ) {
5580			// 1D array
5581			push(sort);
5582		}
5583		else if ( sort.length ) {
5584			// 2D array
5585			for (var z=0; z<sort.length; z++) {
5586				push(sort[z]); // Object or array
5587			}
5588		}
5589	}
5590	
5591	
5592	function _fnSortFlatten ( settings )
5593	{
5594		var
5595			i, k, kLen,
5596			aSort = [],
5597			extSort = DataTable.ext.type.order,
5598			aoColumns = settings.aoColumns,
5599			aDataSort, iCol, sType, srcCol,
5600			fixed = settings.aaSortingFixed,
5601			fixedObj = $.isPlainObject( fixed ),
5602			nestedSort = [];
5603		
5604		if ( ! settings.oFeatures.bSort ) {
5605			return aSort;
5606		}
5607	
5608		// Build the sort array, with pre-fix and post-fix options if they have been
5609		// specified
5610		if ( Array.isArray( fixed ) ) {
5611			_fnSortResolve( settings, nestedSort, fixed );
5612		}
5613	
5614		if ( fixedObj && fixed.pre ) {
5615			_fnSortResolve( settings, nestedSort, fixed.pre );
5616		}
5617	
5618		_fnSortResolve( settings, nestedSort, settings.aaSorting );
5619	
5620		if (fixedObj && fixed.post ) {
5621			_fnSortResolve( settings, nestedSort, fixed.post );
5622		}
5623	
5624		for ( i=0 ; i<nestedSort.length ; i++ )
5625		{
5626			srcCol = nestedSort[i][0];
5627	
5628			if ( aoColumns[ srcCol ] ) {
5629				aDataSort = aoColumns[ srcCol ].aDataSort;
5630	
5631				for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5632				{
5633					iCol = aDataSort[k];
5634					sType = aoColumns[ iCol ].sType || 'string';
5635	
5636					if ( nestedSort[i]._idx === undefined ) {
5637						nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
5638					}
5639	
5640					if ( nestedSort[i][1] ) {
5641						aSort.push( {
5642							src:       srcCol,
5643							col:       iCol,
5644							dir:       nestedSort[i][1],
5645							index:     nestedSort[i]._idx,
5646							type:      sType,
5647							formatter: extSort[ sType+"-pre" ],
5648							sorter:    extSort[ sType+"-"+nestedSort[i][1] ]
5649						} );
5650					}
5651				}
5652			}
5653		}
5654	
5655		return aSort;
5656	}
5657	
5658	/**
5659	 * Change the order of the table
5660	 *  @param {object} oSettings dataTables settings object
5661	 *  @memberof DataTable#oApi
5662	 */
5663	function _fnSort ( oSettings, col, dir )
5664	{
5665		var
5666			i, ien, iLen,
5667			aiOrig = [],
5668			extSort = DataTable.ext.type.order,
5669			aoData = oSettings.aoData,
5670			sortCol,
5671			displayMaster = oSettings.aiDisplayMaster,
5672			aSort;
5673	
5674		// Resolve any column types that are unknown due to addition or invalidation
5675		// @todo Can this be moved into a 'data-ready' handler which is called when
5676		//   data is going to be used in the table?
5677		_fnColumnTypes( oSettings );
5678	
5679		// Allow a specific column to be sorted, which will _not_ alter the display
5680		// master
5681		if (col !== undefined) {
5682			var srcCol = oSettings.aoColumns[col];
5683			aSort = [{
5684				src:       col,
5685				col:       col,
5686				dir:       dir,
5687				index:     0,
5688				type:      srcCol.sType,
5689				formatter: extSort[ srcCol.sType+"-pre" ],
5690				sorter:    extSort[ srcCol.sType+"-"+dir ]
5691			}];
5692			displayMaster = displayMaster.slice();
5693		}
5694		else {
5695			aSort = _fnSortFlatten( oSettings );
5696		}
5697	
5698		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5699			sortCol = aSort[i];
5700	
5701			// Load the data needed for the sort, for each cell
5702			_fnSortData( oSettings, sortCol.col );
5703		}
5704	
5705		/* No sorting required if server-side or no sorting array */
5706		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5707		{
5708			// Reset the initial positions on each pass so we get a stable sort
5709			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5710				aiOrig[ i ] = i;
5711			}
5712	
5713			// If the first sort is desc, then reverse the array to preserve original
5714			// order, just in reverse
5715			if (aSort.length && aSort[0].dir === 'desc') {
5716				aiOrig.reverse();
5717			}
5718	
5719			/* Do the sort - here we want multi-column sorting based on a given data source (column)
5720			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5721			 * follow on it's own, but this is what we want (example two column sorting):
5722			 *  fnLocalSorting = function(a,b){
5723			 *    var test;
5724			 *    test = oSort['string-asc']('data11', 'data12');
5725			 *      if (test !== 0)
5726			 *        return test;
5727			 *    test = oSort['numeric-desc']('data21', 'data22');
5728			 *    if (test !== 0)
5729			 *      return test;
5730			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5731			 *  }
5732			 * Basically we have a test for each sorting column, if the data in that column is equal,
5733			 * test the next column. If all columns match, then we use a numeric sort on the row
5734			 * positions in the original data array to provide a stable sort.
5735			 */
5736			displayMaster.sort( function ( a, b ) {
5737				var
5738					x, y, k, test, sort,
5739					len=aSort.length,
5740					dataA = aoData[a]._aSortData,
5741					dataB = aoData[b]._aSortData;
5742	
5743				for ( k=0 ; k<len ; k++ ) {
5744					sort = aSort[k];
5745	
5746					// Data, which may have already been through a `-pre` function
5747					x = dataA[ sort.col ];
5748					y = dataB[ sort.col ];
5749	
5750					if (sort.sorter) {
5751						// If there is a custom sorter (`-asc` or `-desc`) for this
5752						// data type, use it
5753						test = sort.sorter(x, y);
5754	
5755						if ( test !== 0 ) {
5756							return test;
5757						}
5758					}
5759					else {
5760						// Otherwise, use generic sorting
5761						test = x<y ? -1 : x>y ? 1 : 0;
5762	
5763						if ( test !== 0 ) {
5764							return sort.dir === 'asc' ? test : -test;
5765						}
5766					}
5767				}
5768	
5769				x = aiOrig[a];
5770				y = aiOrig[b];
5771	
5772				return x<y ? -1 : x>y ? 1 : 0;
5773			} );
5774		}
5775		else if ( aSort.length === 0 ) {
5776			// Apply index order
5777			displayMaster.sort(function (x, y) {
5778				return x<y ? -1 : x>y ? 1 : 0;
5779			});
5780		}
5781	
5782		if (col === undefined) {
5783			// Tell the draw function that we have sorted the data
5784			oSettings.bSorted = true;
5785	
5786			_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort] );
5787		}
5788	
5789		return displayMaster;
5790	}
5791	
5792	
5793	/**
5794	 * Function to run on user sort request
5795	 *  @param {object} settings dataTables settings object
5796	 *  @param {node} attachTo node to attach the handler to
5797	 *  @param {int} colIdx column sorting index
5798	 *  @param {int} addIndex Counter
5799	 *  @param {boolean} [shift=false] Shift click add
5800	 *  @param {function} [callback] callback function
5801	 *  @memberof DataTable#oApi
5802	 */
5803	function _fnSortAdd ( settings, colIdx, addIndex, shift )
5804	{
5805		var col = settings.aoColumns[ colIdx ];
5806		var sorting = settings.aaSorting;
5807		var asSorting = col.asSorting;
5808		var nextSortIdx;
5809		var next = function ( a, overflow ) {
5810			var idx = a._idx;
5811			if ( idx === undefined ) {
5812				idx = asSorting.indexOf(a[1]);
5813			}
5814	
5815			return idx+1 < asSorting.length ?
5816				idx+1 :
5817				overflow ?
5818					null :
5819					0;
5820		};
5821	
5822		if ( ! col.bSortable ) {
5823			return false;
5824		}
5825	
5826		// Convert to 2D array if needed
5827		if ( typeof sorting[0] === 'number' ) {
5828			sorting = settings.aaSorting = [ sorting ];
5829		}
5830	
5831		// If appending the sort then we are multi-column sorting
5832		if ( (shift || addIndex) && settings.oFeatures.bSortMulti ) {
5833			// Are we already doing some kind of sort on this column?
5834			var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
5835	
5836			if ( sortIdx !== -1 ) {
5837				// Yes, modify the sort
5838				nextSortIdx = next( sorting[sortIdx], true );
5839	
5840				if ( nextSortIdx === null && sorting.length === 1 ) {
5841					nextSortIdx = 0; // can't remove sorting completely
5842				}
5843	
5844				if ( nextSortIdx === null ) {
5845					sorting.splice( sortIdx, 1 );
5846				}
5847				else {
5848					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
5849					sorting[sortIdx]._idx = nextSortIdx;
5850				}
5851			}
5852			else if (shift) {
5853				// No sort on this column yet, being added by shift click
5854				// add it as itself
5855				sorting.push( [ colIdx, asSorting[0], 0 ] );
5856				sorting[sorting.length-1]._idx = 0;
5857			}
5858			else {
5859				// No sort on this column yet, being added from a colspan
5860				// so add with same direction as first column
5861				sorting.push( [ colIdx, sorting[0][1], 0 ] );
5862				sorting[sorting.length-1]._idx = 0;
5863			}
5864		}
5865		else if ( sorting.length && sorting[0][0] == colIdx ) {
5866			// Single column - already sorting on this column, modify the sort
5867			nextSortIdx = next( sorting[0] );
5868	
5869			sorting.length = 1;
5870			sorting[0][1] = asSorting[ nextSortIdx ];
5871			sorting[0]._idx = nextSortIdx;
5872		}
5873		else {
5874			// Single column - sort only on this column
5875			sorting.length = 0;
5876			sorting.push( [ colIdx, asSorting[0] ] );
5877			sorting[0]._idx = 0;
5878		}
5879	}
5880	
5881	
5882	/**
5883	 * Set the sorting classes on table's body, Note: it is safe to call this function
5884	 * when bSort and bSortClasses are false
5885	 *  @param {object} oSettings dataTables settings object
5886	 *  @memberof DataTable#oApi
5887	 */
5888	function _fnSortingClasses( settings )
5889	{
5890		var oldSort = settings.aLastSort;
5891		var sortClass = settings.oClasses.order.position;
5892		var sort = _fnSortFlatten( settings );
5893		var features = settings.oFeatures;
5894		var i, ien, colIdx;
5895	
5896		if ( features.bSort && features.bSortClasses ) {
5897			// Remove old sorting classes
5898			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
5899				colIdx = oldSort[i].src;
5900	
5901				// Remove column sorting
5902				$( _pluck( settings.aoData, 'anCells', colIdx ) )
5903					.removeClass( sortClass + (i<2 ? i+1 : 3) );
5904			}
5905	
5906			// Add new column sorting
5907			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
5908				colIdx = sort[i].src;
5909	
5910				$( _pluck( settings.aoData, 'anCells', colIdx ) )
5911					.addClass( sortClass + (i<2 ? i+1 : 3) );
5912			}
5913		}
5914	
5915		settings.aLastSort = sort;
5916	}
5917	
5918	
5919	// Get the data to sort a column, be it from cache, fresh (populating the
5920	// cache), or from a sort formatter
5921	function _fnSortData( settings, colIdx )
5922	{
5923		// Custom sorting function - provided by the sort data type
5924		var column = settings.aoColumns[ colIdx ];
5925		var customSort = DataTable.ext.order[ column.sSortDataType ];
5926		var customData;
5927	
5928		if ( customSort ) {
5929			customData = customSort.call( settings.oInstance, settings, colIdx,
5930				_fnColumnIndexToVisible( settings, colIdx )
5931			);
5932		}
5933	
5934		// Use / populate cache
5935		var row, cellData;
5936		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
5937		var data = settings.aoData;
5938	
5939		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
5940			// Sparse array
5941			if (! data[rowIdx]) {
5942				continue;
5943			}
5944	
5945			row = data[rowIdx];
5946	
5947			if ( ! row._aSortData ) {
5948				row._aSortData = [];
5949			}
5950	
5951			if ( ! row._aSortData[colIdx] || customSort ) {
5952				cellData = customSort ?
5953					customData[rowIdx] : // If there was a custom sort function, use data from there
5954					_fnGetCellData( settings, rowIdx, colIdx, 'sort' );
5955	
5956				row._aSortData[ colIdx ] = formatter ?
5957					formatter( cellData, settings ) :
5958					cellData;
5959			}
5960		}
5961	}
5962	
5963	
5964	/**
5965	 * State information for a table
5966	 *
5967	 * @param {*} settings
5968	 * @returns State object
5969	 */
5970	function _fnSaveState ( settings )
5971	{
5972		if (settings._bLoadingState) {
5973			return;
5974		}
5975	
5976		/* Store the interesting variables */
5977		var state = {
5978			time:    +new Date(),
5979			start:   settings._iDisplayStart,
5980			length:  settings._iDisplayLength,
5981			order:   $.extend( true, [], settings.aaSorting ),
5982			search:  $.extend({}, settings.oPreviousSearch),
5983			columns: settings.aoColumns.map( function ( col, i ) {
5984				return {
5985					visible: col.bVisible,
5986					search: $.extend({}, settings.aoPreSearchCols[i])
5987				};
5988			} )
5989		};
5990	
5991		settings.oSavedState = state;
5992		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
5993		
5994		if ( settings.oFeatures.bStateSave && !settings.bDestroying )
5995		{
5996			settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
5997		}	
5998	}
5999	
6000	
6001	/**
6002	 * Attempt to load a saved table state
6003	 *  @param {object} oSettings dataTables settings object
6004	 *  @param {object} oInit DataTables init object so we can override settings
6005	 *  @param {function} callback Callback to execute when the state has been loaded
6006	 *  @memberof DataTable#oApi
6007	 */
6008	function _fnLoadState ( settings, init, callback )
6009	{
6010		if ( ! settings.oFeatures.bStateSave ) {
6011			callback();
6012			return;
6013		}
6014	
6015		var loaded = function(state) {
6016			_fnImplementState(settings, state, callback);
6017		}
6018	
6019		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6020	
6021		if ( state !== undefined ) {
6022			_fnImplementState( settings, state, callback );
6023		}
6024		// otherwise, wait for the loaded callback to be executed
6025	
6026		return true;
6027	}
6028	
6029	function _fnImplementState ( settings, s, callback) {
6030		var i, ien;
6031		var columns = settings.aoColumns;
6032		settings._bLoadingState = true;
6033	
6034		// When StateRestore was introduced the state could now be implemented at any time
6035		// Not just initialisation. To do this an api instance is required in some places
6036		var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
6037	
6038		if ( ! s || ! s.time ) {
6039			settings._bLoadingState = false;
6040			callback();
6041			return;
6042		}
6043	
6044		// Reject old data
6045		var duration = settings.iStateDuration;
6046		if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6047			settings._bLoadingState = false;
6048			callback();
6049			return;
6050		}
6051	
6052		// Allow custom and plug-in manipulation functions to alter the saved data set and
6053		// cancelling of loading by returning false
6054		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6055		if ( abStateLoad.indexOf(false) !== -1 ) {
6056			settings._bLoadingState = false;
6057			callback();
6058			return;
6059		}
6060	
6061		// Number of columns have changed - all bets are off, no restore of settings
6062		if ( s.columns && columns.length !== s.columns.length ) {
6063			settings._bLoadingState = false;
6064			callback();
6065			return;
6066		}
6067	
6068		// Store the saved state so it might be accessed at any time
6069		settings.oLoadedState = $.extend( true, {}, s );
6070	
6071		// This is needed for ColReorder, which has to happen first to allow all
6072		// the stored indexes to be usable. It is not publicly documented.
6073		_fnCallbackFire( settings, null, 'stateLoadInit', [settings, s], true );
6074	
6075		// Page Length
6076		if ( s.length !== undefined ) {
6077			// If already initialised just set the value directly so that the select element is also updated
6078			if (api) {
6079				api.page.len(s.length)
6080			}
6081			else {
6082				settings._iDisplayLength   = s.length;
6083			}
6084		}
6085	
6086		// Restore key features - todo - for 1.11 this needs to be done by
6087		// subscribed events
6088		if ( s.start !== undefined ) {
6089			if(api === null) {
6090				settings._iDisplayStart    = s.start;
6091				settings.iInitDisplayStart = s.start;
6092			}
6093			else {
6094				_fnPageChange(settings, s.start/settings._iDisplayLength);
6095			}
6096		}
6097	
6098		// Order
6099		if ( s.order !== undefined ) {
6100			settings.aaSorting = [];
6101			$.each( s.order, function ( i, col ) {
6102				settings.aaSorting.push( col[0] >= columns.length ?
6103					[ 0, col[1] ] :
6104					col
6105				);
6106			} );
6107		}
6108	
6109		// Search
6110		if ( s.search !== undefined ) {
6111			$.extend( settings.oPreviousSearch, s.search );
6112		}
6113	
6114		// Columns
6115		if ( s.columns ) {
6116			for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6117				var col = s.columns[i];
6118	
6119				// Visibility
6120				if ( col.visible !== undefined ) {
6121					// If the api is defined, the table has been initialised so we need to use it rather than internal settings
6122					if (api) {
6123						// Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6124						api.column(i).visible(col.visible, false);
6125					}
6126					else {
6127						columns[i].bVisible = col.visible;
6128					}
6129				}
6130	
6131				// Search
6132				if ( col.search !== undefined ) {
6133					$.extend( settings.aoPreSearchCols[i], col.search );
6134				}
6135			}
6136			
6137			// If the api is defined then we need to adjust the columns once the visibility has been changed
6138			if (api) {
6139				api.columns.adjust();
6140			}
6141		}
6142	
6143		settings._bLoadingState = false;
6144		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6145		callback();
6146	}
6147	
6148	/**
6149	 * Log an error message
6150	 *  @param {object} settings dataTables settings object
6151	 *  @param {int} level log error messages, or display them to the user
6152	 *  @param {string} msg error message
6153	 *  @param {int} tn Technical note id to get more information about the error.
6154	 *  @memberof DataTable#oApi
6155	 */
6156	function _fnLog( settings, level, msg, tn )
6157	{
6158		msg = 'DataTables warning: '+
6159			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6160	
6161		if ( tn ) {
6162			msg += '. For more information about this error, please see '+
6163			'https://datatables.net/tn/'+tn;
6164		}
6165	
6166		if ( ! level  ) {
6167			// Backwards compatibility pre 1.10
6168			var ext = DataTable.ext;
6169			var type = ext.sErrMode || ext.errMode;
6170	
6171			if ( settings ) {
6172				_fnCallbackFire( settings, null, 'dt-error', [ settings, tn, msg ], true );
6173			}
6174	
6175			if ( type == 'alert' ) {
6176				alert( msg );
6177			}
6178			else if ( type == 'throw' ) {
6179				throw new Error(msg);
6180			}
6181			else if ( typeof type == 'function' ) {
6182				type( settings, tn, msg );
6183			}
6184		}
6185		else if ( window.console && console.log ) {
6186			console.log( msg );
6187		}
6188	}
6189	
6190	
6191	/**
6192	 * See if a property is defined on one object, if so assign it to the other object
6193	 *  @param {object} ret target object
6194	 *  @param {object} src source object
6195	 *  @param {string} name property
6196	 *  @param {string} [mappedName] name to map too - optional, name used if not given
6197	 *  @memberof DataTable#oApi
6198	 */
6199	function _fnMap( ret, src, name, mappedName )
6200	{
6201		if ( Array.isArray( name ) ) {
6202			$.each( name, function (i, val) {
6203				if ( Array.isArray( val ) ) {
6204					_fnMap( ret, src, val[0], val[1] );
6205				}
6206				else {
6207					_fnMap( ret, src, val );
6208				}
6209			} );
6210	
6211			return;
6212		}
6213	
6214		if ( mappedName === undefined ) {
6215			mappedName = name;
6216		}
6217	
6218		if ( src[name] !== undefined ) {
6219			ret[mappedName] = src[name];
6220		}
6221	}
6222	
6223	
6224	/**
6225	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6226	 * shallow copy arrays. The reason we need to do this, is that we don't want to
6227	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6228	 * able to override them, but we do want to deep copy arrays.
6229	 *  @param {object} out Object to extend
6230	 *  @param {object} extender Object from which the properties will be applied to
6231	 *      out
6232	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6233	 *      independent copy with the exception of the `data` or `aaData` parameters
6234	 *      if they are present. This is so you can pass in a collection to
6235	 *      DataTables and have that used as your data source without breaking the
6236	 *      references
6237	 *  @returns {object} out Reference, just for convenience - out === the return.
6238	 *  @memberof DataTable#oApi
6239	 *  @todo This doesn't take account of arrays inside the deep copied objects.
6240	 */
6241	function _fnExtend( out, extender, breakRefs )
6242	{
6243		var val;
6244	
6245		for ( var prop in extender ) {
6246			if ( Object.prototype.hasOwnProperty.call(extender, prop) ) {
6247				val = extender[prop];
6248	
6249				if ( $.isPlainObject( val ) ) {
6250					if ( ! $.isPlainObject( out[prop] ) ) {
6251						out[prop] = {};
6252					}
6253					$.extend( true, out[prop], val );
6254				}
6255				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {
6256					out[prop] = val.slice();
6257				}
6258				else {
6259					out[prop] = val;
6260				}
6261			}
6262		}
6263	
6264		return out;
6265	}
6266	
6267	
6268	/**
6269	 * Bind an event handers to allow a click or return key to activate the callback.
6270	 * This is good for accessibility since a return on the keyboard will have the
6271	 * same effect as a click, if the element has focus.
6272	 *  @param {element} n Element to bind the action to
6273	 *  @param {object|string} selector Selector (for delegated events) or data object
6274	 *   to pass to the triggered function
6275	 *  @param {function} fn Callback function for when the event is triggered
6276	 *  @memberof DataTable#oApi
6277	 */
6278	function _fnBindAction( n, selector, fn )
6279	{
6280		$(n)
6281			.on( 'click.DT', selector, function (e) {
6282				fn(e);
6283			} )
6284			.on( 'keypress.DT', selector, function (e){
6285				if ( e.which === 13 ) {
6286					e.preventDefault();
6287					fn(e);
6288				}
6289			} )
6290			.on( 'selectstart.DT', selector, function () {
6291				// Don't want a double click resulting in text selection
6292				return false;
6293			} );
6294	}
6295	
6296	
6297	/**
6298	 * Register a callback function. Easily allows a callback function to be added to
6299	 * an array store of callback functions that can then all be called together.
6300	 *  @param {object} settings dataTables settings object
6301	 *  @param {string} store Name of the array storage for the callbacks in oSettings
6302	 *  @param {function} fn Function to be called back
6303	 *  @memberof DataTable#oApi
6304	 */
6305	function _fnCallbackReg( settings, store, fn )
6306	{
6307		if ( fn ) {
6308			settings[store].push(fn);
6309		}
6310	}
6311	
6312	
6313	/**
6314	 * Fire callback functions and trigger events. Note that the loop over the
6315	 * callback array store is done backwards! Further note that you do not want to
6316	 * fire off triggers in time sensitive applications (for example cell creation)
6317	 * as its slow.
6318	 *  @param {object} settings dataTables settings object
6319	 *  @param {string} callbackArr Name of the array storage for the callbacks in
6320	 *      oSettings
6321	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
6322	 *      null no trigger is fired
6323	 *  @param {array} args Array of arguments to pass to the callback function /
6324	 *      trigger
6325	 *  @param {boolean} [bubbles] True if the event should bubble
6326	 *  @memberof DataTable#oApi
6327	 */
6328	function _fnCallbackFire( settings, callbackArr, eventName, args, bubbles )
6329	{
6330		var ret = [];
6331	
6332		if ( callbackArr ) {
6333			ret = settings[callbackArr].slice().reverse().map( function (val) {
6334				return val.apply( settings.oInstance, args );
6335			} );
6336		}
6337	
6338		if ( eventName !== null) {
6339			var e = $.Event( eventName+'.dt' );
6340			var table = $(settings.nTable);
6341			
6342			// Expose the DataTables API on the event object for easy access
6343			e.dt = settings.api;
6344	
6345			table[bubbles ?  'trigger' : 'triggerHandler']( e, args );
6346	
6347			// If not yet attached to the document, trigger the event
6348			// on the body directly to sort of simulate the bubble
6349			if (bubbles && table.parents('body').length === 0) {
6350				$('body').trigger( e, args );
6351			}
6352	
6353			ret.push( e.result );
6354		}
6355	
6356		return ret;
6357	}
6358	
6359	
6360	function _fnLengthOverflow ( settings )
6361	{
6362		var
6363			start = settings._iDisplayStart,
6364			end = settings.fnDisplayEnd(),
6365			len = settings._iDisplayLength;
6366	
6367		/* If we have space to show extra rows (backing up from the end point - then do so */
6368		if ( start >= end )
6369		{
6370			start = end - len;
6371		}
6372	
6373		// Keep the start record on the current page
6374		start -= (start % len);
6375	
6376		if ( len === -1 || start < 0 )
6377		{
6378			start = 0;
6379		}
6380	
6381		settings._iDisplayStart = start;
6382	}
6383	
6384	
6385	function _fnRenderer( settings, type )
6386	{
6387		var renderer = settings.renderer;
6388		var host = DataTable.ext.renderer[type];
6389	
6390		if ( $.isPlainObject( renderer ) && renderer[type] ) {
6391			// Specific renderer for this type. If available use it, otherwise use
6392			// the default.
6393			return host[renderer[type]] || host._;
6394		}
6395		else if ( typeof renderer === 'string' ) {
6396			// Common renderer - if there is one available for this type use it,
6397			// otherwise use the default
6398			return host[renderer] || host._;
6399		}
6400	
6401		// Use the default
6402		return host._;
6403	}
6404	
6405	
6406	/**
6407	 * Detect the data source being used for the table. Used to simplify the code
6408	 * a little (ajax) and to make it compress a little smaller.
6409	 *
6410	 *  @param {object} settings dataTables settings object
6411	 *  @returns {string} Data source
6412	 *  @memberof DataTable#oApi
6413	 */
6414	function _fnDataSource ( settings )
6415	{
6416		if ( settings.oFeatures.bServerSide ) {
6417			return 'ssp';
6418		}
6419		else if ( settings.ajax ) {
6420			return 'ajax';
6421		}
6422		return 'dom';
6423	}
6424	
6425	/**
6426	 * Common replacement for language strings
6427	 *
6428	 * @param {*} settings DT settings object
6429	 * @param {*} str String with values to replace
6430	 * @param {*} entries Plural number for _ENTRIES_ - can be undefined
6431	 * @returns String
6432	 */
6433	function _fnMacros ( settings, str, entries )
6434	{
6435		// When infinite scrolling, we are always starting at 1. _iDisplayStart is
6436		// used only internally
6437		var
6438			formatter  = settings.fnFormatNumber,
6439			start      = settings._iDisplayStart+1,
6440			len        = settings._iDisplayLength,
6441			vis        = settings.fnRecordsDisplay(),
6442			max        = settings.fnRecordsTotal(),
6443			all        = len === -1;
6444	
6445		return str.
6446			replace(/_START_/g, formatter.call( settings, start ) ).
6447			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
6448			replace(/_MAX_/g,   formatter.call( settings, max ) ).
6449			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
6450			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
6451			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ).
6452			replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries) ).
6453			replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max) ).
6454			replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
6455	}
6456	
6457	
6458	
6459	/**
6460	 * Computed structure of the DataTables API, defined by the options passed to
6461	 * `DataTable.Api.register()` when building the API.
6462	 *
6463	 * The structure is built in order to speed creation and extension of the Api
6464	 * objects since the extensions are effectively pre-parsed.
6465	 *
6466	 * The array is an array of objects with the following structure, where this
6467	 * base array represents the Api prototype base:
6468	 *
6469	 *     [
6470	 *       {
6471	 *         name:      'data'                -- string   - Property name
6472	 *         val:       function () {},       -- function - Api method (or undefined if just an object
6473	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6474	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6475	 *       },
6476	 *       {
6477	 *         name:     'row'
6478	 *         val:       {},
6479	 *         methodExt: [ ... ],
6480	 *         propExt:   [
6481	 *           {
6482	 *             name:      'data'
6483	 *             val:       function () {},
6484	 *             methodExt: [ ... ],
6485	 *             propExt:   [ ... ]
6486	 *           },
6487	 *           ...
6488	 *         ]
6489	 *       }
6490	 *     ]
6491	 *
6492	 * @type {Array}
6493	 * @ignore
6494	 */
6495	var __apiStruct = [];
6496	
6497	
6498	/**
6499	 * `Array.prototype` reference.
6500	 *
6501	 * @type object
6502	 * @ignore
6503	 */
6504	var __arrayProto = Array.prototype;
6505	
6506	
6507	/**
6508	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6509	 * take several different forms for ease of use.
6510	 *
6511	 * Each of the input parameter types will be converted to a DataTables settings
6512	 * object where possible.
6513	 *
6514	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6515	 *   of:
6516	 *
6517	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6518	 *     with be found and used.
6519	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6520	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6521	 *   * `object` - DataTables settings object
6522	 *   * `DataTables.Api` - API instance
6523	 * @return {array|null} Matching DataTables settings objects. `null` or
6524	 *   `undefined` is returned if no matching DataTable is found.
6525	 * @ignore
6526	 */
6527	var _toSettings = function ( mixed )
6528	{
6529		var idx, jq;
6530		var settings = DataTable.settings;
6531		var tables = _pluck(settings, 'nTable');
6532	
6533		if ( ! mixed ) {
6534			return [];
6535		}
6536		else if ( mixed.nTable && mixed.oFeatures ) {
6537			// DataTables settings object
6538			return [ mixed ];
6539		}
6540		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6541			// Table node
6542			idx = tables.indexOf(mixed);
6543			return idx !== -1 ? [ settings[idx] ] : null;
6544		}
6545		else if ( mixed && typeof mixed.settings === 'function' ) {
6546			return mixed.settings().toArray();
6547		}
6548		else if ( typeof mixed === 'string' ) {
6549			// jQuery selector
6550			jq = $(mixed).get();
6551		}
6552		else if ( mixed instanceof $ ) {
6553			// jQuery object (also DataTables instance)
6554			jq = mixed.get();
6555		}
6556	
6557		if ( jq ) {
6558			return settings.filter(function (v, idx) {
6559				return jq.includes(tables[idx]);
6560			});
6561		}
6562	};
6563	
6564	
6565	/**
6566	 * DataTables API class - used to control and interface with  one or more
6567	 * DataTables enhanced tables.
6568	 *
6569	 * The API class is heavily based on jQuery, presenting a chainable interface
6570	 * that you can use to interact with tables. Each instance of the API class has
6571	 * a "context" - i.e. the tables that it will operate on. This could be a single
6572	 * table, all tables on a page or a sub-set thereof.
6573	 *
6574	 * Additionally the API is designed to allow you to easily work with the data in
6575	 * the tables, retrieving and manipulating it as required. This is done by
6576	 * presenting the API class as an array like interface. The contents of the
6577	 * array depend upon the actions requested by each method (for example
6578	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6579	 * return an array of objects or arrays depending upon your table's
6580	 * configuration). The API object has a number of array like methods (`push`,
6581	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6582	 * `unique` etc) to assist your working with the data held in a table.
6583	 *
6584	 * Most methods (those which return an Api instance) are chainable, which means
6585	 * the return from a method call also has all of the methods available that the
6586	 * top level object had. For example, these two calls are equivalent:
6587	 *
6588	 *     // Not chained
6589	 *     api.row.add( {...} );
6590	 *     api.draw();
6591	 *
6592	 *     // Chained
6593	 *     api.row.add( {...} ).draw();
6594	 *
6595	 * @class DataTable.Api
6596	 * @param {array|object|string|jQuery} context DataTable identifier. This is
6597	 *   used to define which DataTables enhanced tables this API will operate on.
6598	 *   Can be one of:
6599	 *
6600	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6601	 *     with be found and used.
6602	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6603	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6604	 *   * `object` - DataTables settings object
6605	 * @param {array} [data] Data to initialise the Api instance with.
6606	 *
6607	 * @example
6608	 *   // Direct initialisation during DataTables construction
6609	 *   var api = $('#example').DataTable();
6610	 *
6611	 * @example
6612	 *   // Initialisation using a DataTables jQuery object
6613	 *   var api = $('#example').dataTable().api();
6614	 *
6615	 * @example
6616	 *   // Initialisation as a constructor
6617	 *   var api = new DataTable.Api( 'table.dataTable' );
6618	 */
6619	_Api = function ( context, data )
6620	{
6621		if ( ! (this instanceof _Api) ) {
6622			return new _Api( context, data );
6623		}
6624	
6625		var settings = [];
6626		var ctxSettings = function ( o ) {
6627			var a = _toSettings( o );
6628			if ( a ) {
6629				settings.push.apply( settings, a );
6630			}
6631		};
6632	
6633		if ( Array.isArray( context ) ) {
6634			for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6635				ctxSettings( context[i] );
6636			}
6637		}
6638		else {
6639			ctxSettings( context );
6640		}
6641	
6642		// Remove duplicates
6643		this.context = settings.length > 1
6644			? _unique( settings )
6645			: settings;
6646	
6647		// Initial data
6648		if ( data ) {
6649			this.push.apply(this, data);
6650		}
6651	
6652		// selector
6653		this.selector = {
6654			rows: null,
6655			cols: null,
6656			opts: null
6657		};
6658	
6659		_Api.extend( this, this, __apiStruct );
6660	};
6661	
6662	DataTable.Api = _Api;
6663	
6664	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6665	// isPlainObject.
6666	$.extend( _Api.prototype, {
6667		any: function ()
6668		{
6669			return this.count() !== 0;
6670		},
6671	
6672		context: [], // array of table settings objects
6673	
6674		count: function ()
6675		{
6676			return this.flatten().length;
6677		},
6678	
6679		each: function ( fn )
6680		{
6681			for ( var i=0, ien=this.length ; i<ien; i++ ) {
6682				fn.call( this, this[i], i, this );
6683			}
6684	
6685			return this;
6686		},
6687	
6688		eq: function ( idx )
6689		{
6690			var ctx = this.context;
6691	
6692			return ctx.length > idx ?
6693				new _Api( ctx[idx], this[idx] ) :
6694				null;
6695		},
6696	
6697		filter: function ( fn )
6698		{
6699			var a = __arrayProto.filter.call( this, fn, this );
6700	
6701			return new _Api( this.context, a );
6702		},
6703	
6704		flatten: function ()
6705		{
6706			var a = [];
6707	
6708			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6709		},
6710	
6711		get: function ( idx )
6712		{
6713			return this[ idx ];
6714		},
6715	
6716		join:    __arrayProto.join,
6717	
6718		includes: function ( find ) {
6719			return this.indexOf( find ) === -1 ? false : true;
6720		},
6721	
6722		indexOf: __arrayProto.indexOf,
6723	
6724		iterator: function ( flatten, type, fn, alwaysNew ) {
6725			var
6726				a = [], ret,
6727				i, ien, j, jen,
6728				context = this.context,
6729				rows, items, item,
6730				selector = this.selector;
6731	
6732			// Argument shifting
6733			if ( typeof flatten === 'string' ) {
6734				alwaysNew = fn;
6735				fn = type;
6736				type = flatten;
6737				flatten = false;
6738			}
6739	
6740			for ( i=0, ien=context.length ; i<ien ; i++ ) {
6741				var apiInst = new _Api( context[i] );
6742	
6743				if ( type === 'table' ) {
6744					ret = fn.call( apiInst, context[i], i );
6745	
6746					if ( ret !== undefined ) {
6747						a.push( ret );
6748					}
6749				}
6750				else if ( type === 'columns' || type === 'rows' ) {
6751					// this has same length as context - one entry for each table
6752					ret = fn.call( apiInst, context[i], this[i], i );
6753	
6754					if ( ret !== undefined ) {
6755						a.push( ret );
6756					}
6757				}
6758				else if ( type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6759					// columns and rows share the same structure.
6760					// 'this' is an array of column indexes for each context
6761					items = this[i];
6762	
6763					if ( type === 'column-rows' ) {
6764						rows = _selector_row_indexes( context[i], selector.opts );
6765					}
6766	
6767					for ( j=0, jen=items.length ; j<jen ; j++ ) {
6768						item = items[j];
6769	
6770						if ( type === 'cell' ) {
6771							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6772						}
6773						else {
6774							ret = fn.call( apiInst, context[i], item, i, j, rows );
6775						}
6776	
6777						if ( ret !== undefined ) {
6778							a.push( ret );
6779						}
6780					}
6781				}
6782			}
6783	
6784			if ( a.length || alwaysNew ) {
6785				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6786				var apiSelector = api.selector;
6787				apiSelector.rows = selector.rows;
6788				apiSelector.cols = selector.cols;
6789				apiSelector.opts = selector.opts;
6790				return api;
6791			}
6792			return this;
6793		},
6794	
6795		lastIndexOf: __arrayProto.lastIndexOf,
6796	
6797		length:  0,
6798	
6799		map: function ( fn )
6800		{
6801			var a = __arrayProto.map.call( this, fn, this );
6802	
6803			return new _Api( this.context, a );
6804		},
6805	
6806		pluck: function ( prop )
6807		{
6808			var fn = DataTable.util.get(prop);
6809	
6810			return this.map( function ( el ) {
6811				return fn(el);
6812			} );
6813		},
6814	
6815		pop:     __arrayProto.pop,
6816	
6817		push:    __arrayProto.push,
6818	
6819		reduce: __arrayProto.reduce,
6820	
6821		reduceRight: __arrayProto.reduceRight,
6822	
6823		reverse: __arrayProto.reverse,
6824	
6825		// Object with rows, columns and opts
6826		selector: null,
6827	
6828		shift:   __arrayProto.shift,
6829	
6830		slice: function () {
6831			return new _Api( this.context, this );
6832		},
6833	
6834		sort:    __arrayProto.sort,
6835	
6836		splice:  __arrayProto.splice,
6837	
6838		toArray: function ()
6839		{
6840			return __arrayProto.slice.call( this );
6841		},
6842	
6843		to$: function ()
6844		{
6845			return $( this );
6846		},
6847	
6848		toJQuery: function ()
6849		{
6850			return $( this );
6851		},
6852	
6853		unique: function ()
6854		{
6855			return new _Api( this.context, _unique(this.toArray()) );
6856		},
6857	
6858		unshift: __arrayProto.unshift
6859	} );
6860	
6861	
6862	function _api_scope( scope, fn, struc ) {
6863		return function () {
6864			var ret = fn.apply( scope || this, arguments );
6865	
6866			// Method extension
6867			_Api.extend( ret, ret, struc.methodExt );
6868			return ret;
6869		};
6870	}
6871	
6872	function _api_find( src, name ) {
6873		for ( var i=0, ien=src.length ; i<ien ; i++ ) {
6874			if ( src[i].name === name ) {
6875				return src[i];
6876			}
6877		}
6878		return null;
6879	}
6880	
6881	window.__apiStruct = __apiStruct;
6882	
6883	_Api.extend = function ( scope, obj, ext )
6884	{
6885		// Only extend API instances and static properties of the API
6886		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6887			return;
6888		}
6889	
6890		var
6891			i, ien,
6892			struct;
6893	
6894		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6895			struct = ext[i];
6896	
6897			if (struct.name === '__proto__') {
6898				continue;
6899			}
6900	
6901			// Value
6902			obj[ struct.name ] = struct.type === 'function' ?
6903				_api_scope( scope, struct.val, struct ) :
6904				struct.type === 'object' ?
6905					{} :
6906					struct.val;
6907	
6908			obj[ struct.name ].__dt_wrapper = true;
6909	
6910			// Property extension
6911			_Api.extend( scope, obj[ struct.name ], struct.propExt );
6912		}
6913	};
6914	
6915	//     [
6916	//       {
6917	//         name:      'data'                -- string   - Property name
6918	//         val:       function () {},       -- function - Api method (or undefined if just an object
6919	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6920	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6921	//       },
6922	//       {
6923	//         name:     'row'
6924	//         val:       {},
6925	//         methodExt: [ ... ],
6926	//         propExt:   [
6927	//           {
6928	//             name:      'data'
6929	//             val:       function () {},
6930	//             methodExt: [ ... ],
6931	//             propExt:   [ ... ]
6932	//           },
6933	//           ...
6934	//         ]
6935	//       }
6936	//     ]
6937	
6938	
6939	_Api.register = _api_register = function ( name, val )
6940	{
6941		if ( Array.isArray( name ) ) {
6942			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
6943				_Api.register( name[j], val );
6944			}
6945			return;
6946		}
6947	
6948		var
6949			i, ien,
6950			heir = name.split('.'),
6951			struct = __apiStruct,
6952			key, method;
6953	
6954		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
6955			method = heir[i].indexOf('()') !== -1;
6956			key = method ?
6957				heir[i].replace('()', '') :
6958				heir[i];
6959	
6960			var src = _api_find( struct, key );
6961			if ( ! src ) {
6962				src = {
6963					name:      key,
6964					val:       {},
6965					methodExt: [],
6966					propExt:   [],
6967					type:      'object'
6968				};
6969				struct.push( src );
6970			}
6971	
6972			if ( i === ien-1 ) {
6973				src.val = val;
6974				src.type = typeof val === 'function' ?
6975					'function' :
6976					$.isPlainObject( val ) ?
6977						'object' :
6978						'other';
6979			}
6980			else {
6981				struct = method ?
6982					src.methodExt :
6983					src.propExt;
6984			}
6985		}
6986	};
6987	
6988	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
6989		_Api.register( pluralName, val );
6990	
6991		_Api.register( singularName, function () {
6992			var ret = val.apply( this, arguments );
6993	
6994			if ( ret === this ) {
6995				// Returned item is the API instance that was passed in, return it
6996				return this;
6997			}
6998			else if ( ret instanceof _Api ) {
6999				// New API instance returned, want the value from the first item
7000				// in the returned array for the singular result.
7001				return ret.length ?
7002					Array.isArray( ret[0] ) ?
7003						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7004						ret[0] :
7005					undefined;
7006			}
7007	
7008			// Non-API return - just fire it back
7009			return ret;
7010		} );
7011	};
7012	
7013	
7014	/**
7015	 * Selector for HTML tables. Apply the given selector to the give array of
7016	 * DataTables settings objects.
7017	 *
7018	 * @param {string|integer} [selector] jQuery selector string or integer
7019	 * @param  {array} Array of DataTables settings objects to be filtered
7020	 * @return {array}
7021	 * @ignore
7022	 */
7023	var __table_selector = function ( selector, a )
7024	{
7025		if ( Array.isArray(selector) ) {
7026			var result = [];
7027	
7028			selector.forEach(function (sel) {
7029				var inner = __table_selector(sel, a);
7030	
7031				result.push.apply(result, inner);
7032			});
7033	
7034			return result.filter( function (item) {
7035				return item;
7036			});
7037		}
7038	
7039		// Integer is used to pick out a table by index
7040		if ( typeof selector === 'number' ) {
7041			return [ a[ selector ] ];
7042		}
7043	
7044		// Perform a jQuery selector on the table nodes
7045		var nodes = a.map( function (el) {
7046			return el.nTable;
7047		} );
7048	
7049		return $(nodes)
7050			.filter( selector )
7051			.map( function () {
7052				// Need to translate back from the table node to the settings
7053				var idx = nodes.indexOf(this);
7054				return a[ idx ];
7055			} )
7056			.toArray();
7057	};
7058	
7059	
7060	
7061	/**
7062	 * Context selector for the API's context (i.e. the tables the API instance
7063	 * refers to.
7064	 *
7065	 * @name    DataTable.Api#tables
7066	 * @param {string|integer} [selector] Selector to pick which tables the iterator
7067	 *   should operate on. If not given, all tables in the current context are
7068	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7069	 *   select multiple tables or as an integer to select a single table.
7070	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7071	 */
7072	_api_register( 'tables()', function ( selector ) {
7073		// A new instance is created if there was a selector specified
7074		return selector !== undefined && selector !== null ?
7075			new _Api( __table_selector( selector, this.context ) ) :
7076			this;
7077	} );
7078	
7079	
7080	_api_register( 'table()', function ( selector ) {
7081		var tables = this.tables( selector );
7082		var ctx = tables.context;
7083	
7084		// Truncate to the first matched table
7085		return ctx.length ?
7086			new _Api( ctx[0] ) :
7087			tables;
7088	} );
7089	
7090	// Common methods, combined to reduce size
7091	[
7092		['nodes', 'node', 'nTable'],
7093		['body', 'body', 'nTBody'],
7094		['header', 'header', 'nTHead'],
7095		['footer', 'footer', 'nTFoot'],
7096	].forEach(function (item) {
7097		_api_registerPlural(
7098			'tables().' + item[0] + '()',
7099			'table().' + item[1] + '()' ,
7100			function () {
7101				return this.iterator( 'table', function ( ctx ) {
7102					return ctx[item[2]];
7103				}, 1 );
7104			}
7105		);
7106	});
7107	
7108	// Structure methods
7109	[
7110		['header', 'aoHeader'],
7111		['footer', 'aoFooter'],
7112	].forEach(function (item) {
7113		_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
7114			var indexes = this.columns(selector).indexes().flatten();
7115			var ctx = this.context[0];
7116			
7117			return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7118		} );
7119	})
7120	
7121	
7122	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7123		return this.iterator( 'table', function ( ctx ) {
7124			return ctx.nTableWrapper;
7125		}, 1 );
7126	} );
7127	
7128	_api_register( 'tables().every()', function ( fn ) {
7129		var that = this;
7130	
7131		return this.iterator('table', function (s, i) {
7132			fn.call(that.table(i), i);
7133		});
7134	});
7135	
7136	_api_register( 'caption()', function ( value, side ) {
7137		var context = this.context;
7138	
7139		// Getter - return existing node's content
7140		if ( value === undefined ) {
7141			var caption = context[0].captionNode;
7142	
7143			return caption && context.length ?
7144				caption.innerHTML : 
7145				null;
7146		}
7147	
7148		return this.iterator( 'table', function ( ctx ) {
7149			var table = $(ctx.nTable);
7150			var caption = $(ctx.captionNode);
7151			var container = $(ctx.nTableWrapper);
7152	
7153			// Create the node if it doesn't exist yet
7154			if ( ! caption.length ) {
7155				caption = $('<caption/>').html( value );
7156				ctx.captionNode = caption[0];
7157	
7158				// If side isn't set, we need to insert into the document to let the
7159				// CSS decide so we can read it back, otherwise there is no way to
7160				// know if the CSS would put it top or bottom for scrolling
7161				if (! side) {
7162					table.prepend(caption);
7163	
7164					side = caption.css('caption-side');
7165				}
7166			}
7167	
7168			caption.html( value );
7169	
7170			if ( side ) {
7171				caption.css( 'caption-side', side );
7172				caption[0]._captionSide = side;
7173			}
7174	
7175			if (container.find('div.dataTables_scroll').length) {
7176				var selector = (side === 'top' ? 'Head' : 'Foot');
7177	
7178				container.find('div.dataTables_scroll'+ selector +' table').prepend(caption);
7179			}
7180			else {
7181				table.prepend(caption);
7182			}
7183		}, 1 );
7184	} );
7185	
7186	_api_register( 'caption.node()', function () {
7187		var ctx = this.context;
7188	
7189		return ctx.length ? ctx[0].captionNode : null;
7190	} );
7191	
7192	
7193	/**
7194	 * Redraw the tables in the current context.
7195	 */
7196	_api_register( 'draw()', function ( paging ) {
7197		return this.iterator( 'table', function ( settings ) {
7198			if ( paging === 'page' ) {
7199				_fnDraw( settings );
7200			}
7201			else {
7202				if ( typeof paging === 'string' ) {
7203					paging = paging === 'full-hold' ?
7204						false :
7205						true;
7206				}
7207	
7208				_fnReDraw( settings, paging===false );
7209			}
7210		} );
7211	} );
7212	
7213	
7214	
7215	/**
7216	 * Get the current page index.
7217	 *
7218	 * @return {integer} Current page index (zero based)
7219	 *//**
7220	 * Set the current page.
7221	 *
7222	 * Note that if you attempt to show a page which does not exist, DataTables will
7223	 * not throw an error, but rather reset the paging.
7224	 *
7225	 * @param {integer|string} action The paging action to take. This can be one of:
7226	 *  * `integer` - The page index to jump to
7227	 *  * `string` - An action to take:
7228	 *    * `first` - Jump to first page.
7229	 *    * `next` - Jump to the next page
7230	 *    * `previous` - Jump to previous page
7231	 *    * `last` - Jump to the last page.
7232	 * @returns {DataTables.Api} this
7233	 */
7234	_api_register( 'page()', function ( action ) {
7235		if ( action === undefined ) {
7236			return this.page.info().page; // not an expensive call
7237		}
7238	
7239		// else, have an action to take on all tables
7240		return this.iterator( 'table', function ( settings ) {
7241			_fnPageChange( settings, action );
7242		} );
7243	} );
7244	
7245	
7246	/**
7247	 * Paging information for the first table in the current context.
7248	 *
7249	 * If you require paging information for another table, use the `table()` method
7250	 * with a suitable selector.
7251	 *
7252	 * @return {object} Object with the following properties set:
7253	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7254	 *  * `pages` - Total number of pages
7255	 *  * `start` - Display index for the first record shown on the current page
7256	 *  * `end` - Display index for the last record shown on the current page
7257	 *  * `length` - Display length (number of records). Note that generally `start
7258	 *    + length = end`, but this is not always true, for example if there are
7259	 *    only 2 records to show on the final page, with a length of 10.
7260	 *  * `recordsTotal` - Full data set length
7261	 *  * `recordsDisplay` - Data set length once the current filtering criterion
7262	 *    are applied.
7263	 */
7264	_api_register( 'page.info()', function () {
7265		if ( this.context.length === 0 ) {
7266			return undefined;
7267		}
7268	
7269		var
7270			settings   = this.context[0],
7271			start      = settings._iDisplayStart,
7272			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7273			visRecords = settings.fnRecordsDisplay(),
7274			all        = len === -1;
7275	
7276		return {
7277			"page":           all ? 0 : Math.floor( start / len ),
7278			"pages":          all ? 1 : Math.ceil( visRecords / len ),
7279			"start":          start,
7280			"end":            settings.fnDisplayEnd(),
7281			"length":         len,
7282			"recordsTotal":   settings.fnRecordsTotal(),
7283			"recordsDisplay": visRecords,
7284			"serverSide":     _fnDataSource( settings ) === 'ssp'
7285		};
7286	} );
7287	
7288	
7289	/**
7290	 * Get the current page length.
7291	 *
7292	 * @return {integer} Current page length. Note `-1` indicates that all records
7293	 *   are to be shown.
7294	 *//**
7295	 * Set the current page length.
7296	 *
7297	 * @param {integer} Page length to set. Use `-1` to show all records.
7298	 * @returns {DataTables.Api} this
7299	 */
7300	_api_register( 'page.len()', function ( len ) {
7301		// Note that we can't call this function 'length()' because `length`
7302		// is a Javascript property of functions which defines how many arguments
7303		// the function expects.
7304		if ( len === undefined ) {
7305			return this.context.length !== 0 ?
7306				this.context[0]._iDisplayLength :
7307				undefined;
7308		}
7309	
7310		// else, set the page length
7311		return this.iterator( 'table', function ( settings ) {
7312			_fnLengthChange( settings, len );
7313		} );
7314	} );
7315	
7316	
7317	
7318	var __reload = function ( settings, holdPosition, callback ) {
7319		// Use the draw event to trigger a callback
7320		if ( callback ) {
7321			var api = new _Api( settings );
7322	
7323			api.one( 'draw', function () {
7324				callback( api.ajax.json() );
7325			} );
7326		}
7327	
7328		if ( _fnDataSource( settings ) == 'ssp' ) {
7329			_fnReDraw( settings, holdPosition );
7330		}
7331		else {
7332			_fnProcessingDisplay( settings, true );
7333	
7334			// Cancel an existing request
7335			var xhr = settings.jqXHR;
7336			if ( xhr && xhr.readyState !== 4 ) {
7337				xhr.abort();
7338			}
7339	
7340			// Trigger xhr
7341			_fnBuildAjax( settings, {}, function( json ) {
7342				_fnClearTable( settings );
7343	
7344				var data = _fnAjaxDataSrc( settings, json );
7345				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7346					_fnAddData( settings, data[i] );
7347				}
7348	
7349				_fnReDraw( settings, holdPosition );
7350				_fnInitComplete( settings );
7351				_fnProcessingDisplay( settings, false );
7352			} );
7353		}
7354	};
7355	
7356	
7357	/**
7358	 * Get the JSON response from the last Ajax request that DataTables made to the
7359	 * server. Note that this returns the JSON from the first table in the current
7360	 * context.
7361	 *
7362	 * @return {object} JSON received from the server.
7363	 */
7364	_api_register( 'ajax.json()', function () {
7365		var ctx = this.context;
7366	
7367		if ( ctx.length > 0 ) {
7368			return ctx[0].json;
7369		}
7370	
7371		// else return undefined;
7372	} );
7373	
7374	
7375	/**
7376	 * Get the data submitted in the last Ajax request
7377	 */
7378	_api_register( 'ajax.params()', function () {
7379		var ctx = this.context;
7380	
7381		if ( ctx.length > 0 ) {
7382			return ctx[0].oAjaxData;
7383		}
7384	
7385		// else return undefined;
7386	} );
7387	
7388	
7389	/**
7390	 * Reload tables from the Ajax data source. Note that this function will
7391	 * automatically re-draw the table when the remote data has been loaded.
7392	 *
7393	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7394	 *   position. A full re-sort and re-filter is performed when this method is
7395	 *   called, which is why the pagination reset is the default action.
7396	 * @returns {DataTables.Api} this
7397	 */
7398	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7399		return this.iterator( 'table', function (settings) {
7400			__reload( settings, resetPaging===false, callback );
7401		} );
7402	} );
7403	
7404	
7405	/**
7406	 * Get the current Ajax URL. Note that this returns the URL from the first
7407	 * table in the current context.
7408	 *
7409	 * @return {string} Current Ajax source URL
7410	 *//**
7411	 * Set the Ajax URL. Note that this will set the URL for all tables in the
7412	 * current context.
7413	 *
7414	 * @param {string} url URL to set.
7415	 * @returns {DataTables.Api} this
7416	 */
7417	_api_register( 'ajax.url()', function ( url ) {
7418		var ctx = this.context;
7419	
7420		if ( url === undefined ) {
7421			// get
7422			if ( ctx.length === 0 ) {
7423				return undefined;
7424			}
7425			ctx = ctx[0];
7426	
7427			return $.isPlainObject( ctx.ajax ) ?
7428				ctx.ajax.url :
7429				ctx.ajax;
7430		}
7431	
7432		// set
7433		return this.iterator( 'table', function ( settings ) {
7434			if ( $.isPlainObject( settings.ajax ) ) {
7435				settings.ajax.url = url;
7436			}
7437			else {
7438				settings.ajax = url;
7439			}
7440		} );
7441	} );
7442	
7443	
7444	/**
7445	 * Load data from the newly set Ajax URL. Note that this method is only
7446	 * available when `ajax.url()` is used to set a URL. Additionally, this method
7447	 * has the same effect as calling `ajax.reload()` but is provided for
7448	 * convenience when setting a new URL. Like `ajax.reload()` it will
7449	 * automatically redraw the table once the remote data has been loaded.
7450	 *
7451	 * @returns {DataTables.Api} this
7452	 */
7453	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7454		// Same as a reload, but makes sense to present it for easy access after a
7455		// url change
7456		return this.iterator( 'table', function ( ctx ) {
7457			__reload( ctx, resetPaging===false, callback );
7458		} );
7459	} );
7460	
7461	
7462	
7463	
7464	var _selector_run = function ( type, selector, selectFn, settings, opts )
7465	{
7466		var
7467			out = [], res,
7468			a, i, ien, j, jen,
7469			selectorType = typeof selector;
7470	
7471		// Can't just check for isArray here, as an API or jQuery instance might be
7472		// given with their array like look
7473		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7474			selector = [ selector ];
7475		}
7476	
7477		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7478			// Only split on simple strings - complex expressions will be jQuery selectors
7479			a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
7480				selector[i].split(',') :
7481				[ selector[i] ];
7482	
7483			for ( j=0, jen=a.length ; j<jen ; j++ ) {
7484				res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
7485	
7486				// Remove empty items
7487				res = res.filter( function (item) {
7488					return item !== null && item !== undefined;
7489				});
7490	
7491				if ( res && res.length ) {
7492					out = out.concat( res );
7493				}
7494			}
7495		}
7496	
7497		// selector extensions
7498		var ext = _ext.selector[ type ];
7499		if ( ext.length ) {
7500			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7501				out = ext[i]( settings, opts, out );
7502			}
7503		}
7504	
7505		return _unique( out );
7506	};
7507	
7508	
7509	var _selector_opts = function ( opts )
7510	{
7511		if ( ! opts ) {
7512			opts = {};
7513		}
7514	
7515		// Backwards compatibility for 1.9- which used the terminology filter rather
7516		// than search
7517		if ( opts.filter && opts.search === undefined ) {
7518			opts.search = opts.filter;
7519		}
7520	
7521		return $.extend( {
7522			search: 'none',
7523			order: 'current',
7524			page: 'all'
7525		}, opts );
7526	};
7527	
7528	
7529	// Reduce the API instance to the first item found
7530	var _selector_first = function ( old )
7531	{
7532		let inst = new _Api(old.context[0]);
7533	
7534		// Use a push rather than passing to the constructor, since it will
7535		// merge arrays down automatically, which isn't what is wanted here
7536		if (old.length) {
7537			inst.push( old[0] );
7538		}
7539	
7540		inst.selector = old.selector;
7541	
7542		// Limit to a single row / column / cell
7543		if (inst.length && inst[0].length > 1) {
7544			inst[0].splice(1);
7545		}
7546	
7547		return inst;
7548	};
7549	
7550	
7551	var _selector_row_indexes = function ( settings, opts )
7552	{
7553		var
7554			i, ien, tmp, a=[],
7555			displayFiltered = settings.aiDisplay,
7556			displayMaster = settings.aiDisplayMaster;
7557	
7558		var
7559			search = opts.search,  // none, applied, removed
7560			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7561			page   = opts.page;    // all, current
7562	
7563		if ( _fnDataSource( settings ) == 'ssp' ) {
7564			// In server-side processing mode, most options are irrelevant since
7565			// rows not shown don't exist and the index order is the applied order
7566			// Removed is a special case - for consistency just return an empty
7567			// array
7568			return search === 'removed' ?
7569				[] :
7570				_range( 0, displayMaster.length );
7571		}
7572	
7573		if ( page == 'current' ) {
7574			// Current page implies that order=current and filter=applied, since it is
7575			// fairly senseless otherwise, regardless of what order and search actually
7576			// are
7577			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7578				a.push( displayFiltered[i] );
7579			}
7580		}
7581		else if ( order == 'current' || order == 'applied' ) {
7582			if ( search == 'none') {
7583				a = displayMaster.slice();
7584			}
7585			else if ( search == 'applied' ) {
7586				a = displayFiltered.slice();
7587			}
7588			else if ( search == 'removed' ) {
7589				// O(n+m) solution by creating a hash map
7590				var displayFilteredMap = {};
7591	
7592				for ( i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7593					displayFilteredMap[displayFiltered[i]] = null;
7594				}
7595	
7596				displayMaster.forEach(function (item) {
7597					if (! Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
7598						a.push(item);
7599					}
7600				});
7601			}
7602		}
7603		else if ( order == 'index' || order == 'original' ) {
7604			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7605				if (! settings.aoData[i]) {
7606					continue;
7607				}
7608	
7609				if ( search == 'none' ) {
7610					a.push( i );
7611				}
7612				else { // applied | removed
7613					tmp = displayFiltered.indexOf(i);
7614	
7615					if ((tmp === -1 && search == 'removed') ||
7616						(tmp >= 0   && search == 'applied') )
7617					{
7618						a.push( i );
7619					}
7620				}
7621			}
7622		}
7623		else if ( typeof order === 'number' ) {
7624			// Order the rows by the given column
7625			var ordered = _fnSort(settings, order, 'asc');
7626	
7627			if (search === 'none') {
7628				a = ordered;
7629			}
7630			else { // applied | removed
7631				for (i=0; i<ordered.length; i++) {
7632					tmp = displayFiltered.indexOf(ordered[i]);
7633	
7634					if ((tmp === -1 && search == 'removed') ||
7635						(tmp >= 0   && search == 'applied') )
7636					{
7637						a.push( ordered[i] );
7638					}
7639				}
7640			}
7641		}
7642	
7643		return a;
7644	};
7645	
7646	
7647	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7648	 * Rows
7649	 *
7650	 * {}          - no selector - use all available rows
7651	 * {integer}   - row aoData index
7652	 * {node}      - TR node
7653	 * {string}    - jQuery selector to apply to the TR elements
7654	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
7655	 *
7656	 */
7657	var __row_selector = function ( settings, selector, opts )
7658	{
7659		var rows;
7660		var run = function ( sel ) {
7661			var selInt = _intVal( sel );
7662			var aoData = settings.aoData;
7663	
7664			// Short cut - selector is a number and no options provided (default is
7665			// all records, so no need to check if the index is in there, since it
7666			// must be - dev error if the index doesn't exist).
7667			if ( selInt !== null && ! opts ) {
7668				return [ selInt ];
7669			}
7670	
7671			if ( ! rows ) {
7672				rows = _selector_row_indexes( settings, opts );
7673			}
7674	
7675			if ( selInt !== null && rows.indexOf(selInt) !== -1 ) {
7676				// Selector - integer
7677				return [ selInt ];
7678			}
7679			else if ( sel === null || sel === undefined || sel === '' ) {
7680				// Selector - none
7681				return rows;
7682			}
7683	
7684			// Selector - function
7685			if ( typeof sel === 'function' ) {
7686				return rows.map( function (idx) {
7687					var row = aoData[ idx ];
7688					return sel( idx, row._aData, row.nTr ) ? idx : null;
7689				} );
7690			}
7691	
7692			// Selector - node
7693			if ( sel.nodeName ) {
7694				var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
7695				var cellIdx = sel._DT_CellIndex;
7696	
7697				if ( rowIdx !== undefined ) {
7698					// Make sure that the row is actually still present in the table
7699					return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7700						[ rowIdx ] :
7701						[];
7702				}
7703				else if ( cellIdx ) {
7704					return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
7705						[ cellIdx.row ] :
7706						[];
7707				}
7708				else {
7709					var host = $(sel).closest('*[data-dt-row]');
7710					return host.length ?
7711						[ host.data('dt-row') ] :
7712						[];
7713				}
7714			}
7715	
7716			// ID selector. Want to always be able to select rows by id, regardless
7717			// of if the tr element has been created or not, so can't rely upon
7718			// jQuery here - hence a custom implementation. This does not match
7719			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7720			// but to select it using a CSS selector engine (like Sizzle or
7721			// querySelect) it would need to need to be escaped for some characters.
7722			// DataTables simplifies this for row selectors since you can select
7723			// only a row. A # indicates an id any anything that follows is the id -
7724			// unescaped.
7725			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7726				// get row index from id
7727				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7728				if ( rowObj !== undefined ) {
7729					return [ rowObj.idx ];
7730				}
7731	
7732				// need to fall through to jQuery in case there is DOM id that
7733				// matches
7734			}
7735			
7736			// Get nodes in the order from the `rows` array with null values removed
7737			var nodes = _removeEmpty(
7738				_pluck_order( settings.aoData, rows, 'nTr' )
7739			);
7740	
7741			// Selector - jQuery selector string, array of nodes or jQuery object/
7742			// As jQuery's .filter() allows jQuery objects to be passed in filter,
7743			// it also allows arrays, so this will cope with all three options
7744			return $(nodes)
7745				.filter( sel )
7746				.map( function () {
7747					return this._DT_RowIndex;
7748				} )
7749				.toArray();
7750		};
7751	
7752		var matched = _selector_run( 'row', selector, run, settings, opts );
7753	
7754		if (opts.order === 'current' || opts.order === 'applied') {
7755			_fnSortDisplay(settings, matched);
7756		}
7757	
7758		return matched;
7759	};
7760	
7761	
7762	_api_register( 'rows()', function ( selector, opts ) {
7763		// argument shifting
7764		if ( selector === undefined ) {
7765			selector = '';
7766		}
7767		else if ( $.isPlainObject( selector ) ) {
7768			opts = selector;
7769			selector = '';
7770		}
7771	
7772		opts = _selector_opts( opts );
7773	
7774		var inst = this.iterator( 'table', function ( settings ) {
7775			return __row_selector( settings, selector, opts );
7776		}, 1 );
7777	
7778		// Want argument shifting here and in __row_selector?
7779		inst.selector.rows = selector;
7780		inst.selector.opts = opts;
7781	
7782		return inst;
7783	} );
7784	
7785	_api_register( 'rows().nodes()', function () {
7786		return this.iterator( 'row', function ( settings, row ) {
7787			return settings.aoData[ row ].nTr || undefined;
7788		}, 1 );
7789	} );
7790	
7791	_api_register( 'rows().data()', function () {
7792		return this.iterator( true, 'rows', function ( settings, rows ) {
7793			return _pluck_order( settings.aoData, rows, '_aData' );
7794		}, 1 );
7795	} );
7796	
7797	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7798		return this.iterator( 'row', function ( settings, row ) {
7799			var r = settings.aoData[ row ];
7800			return type === 'search' ? r._aFilterData : r._aSortData;
7801		}, 1 );
7802	} );
7803	
7804	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7805		return this.iterator( 'row', function ( settings, row ) {
7806			_fnInvalidate( settings, row, src );
7807		} );
7808	} );
7809	
7810	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7811		return this.iterator( 'row', function ( settings, row ) {
7812			return row;
7813		}, 1 );
7814	} );
7815	
7816	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7817		var a = [];
7818		var context = this.context;
7819	
7820		// `iterator` will drop undefined values, but in this case we want them
7821		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7822			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7823				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7824				a.push( (hash === true ? '#' : '' )+ id );
7825			}
7826		}
7827	
7828		return new _Api( context, a );
7829	} );
7830	
7831	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7832		this.iterator( 'row', function ( settings, row ) {
7833			var data = settings.aoData;
7834			var rowData = data[ row ];
7835	
7836			// Delete from the display arrays
7837			var idx = settings.aiDisplayMaster.indexOf(row);
7838			if (idx !== -1) {
7839				settings.aiDisplayMaster.splice(idx, 1);
7840			}
7841	
7842			// For server-side processing tables - subtract the deleted row from the count
7843			if ( settings._iRecordsDisplay > 0 ) {
7844				settings._iRecordsDisplay--;
7845			}
7846	
7847			// Check for an 'overflow' they case for displaying the table
7848			_fnLengthOverflow( settings );
7849	
7850			// Remove the row's ID reference if there is one
7851			var id = settings.rowIdFn( rowData._aData );
7852			if ( id !== undefined ) {
7853				delete settings.aIds[ id ];
7854			}
7855	
7856			data[row] = null;
7857		} );
7858	
7859		return this;
7860	} );
7861	
7862	
7863	_api_register( 'rows.add()', function ( rows ) {
7864		var newRows = this.iterator( 'table', function ( settings ) {
7865				var row, i, ien;
7866				var out = [];
7867	
7868				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7869					row = rows[i];
7870	
7871					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7872						out.push( _fnAddTr( settings, row )[0] );
7873					}
7874					else {
7875						out.push( _fnAddData( settings, row ) );
7876					}
7877				}
7878	
7879				return out;
7880			}, 1 );
7881	
7882		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
7883		var modRows = this.rows( -1 );
7884		modRows.pop();
7885		modRows.push.apply(modRows, newRows);
7886	
7887		return modRows;
7888	} );
7889	
7890	
7891	
7892	
7893	
7894	/**
7895	 *
7896	 */
7897	_api_register( 'row()', function ( selector, opts ) {
7898		return _selector_first( this.rows( selector, opts ) );
7899	} );
7900	
7901	
7902	_api_register( 'row().data()', function ( data ) {
7903		var ctx = this.context;
7904	
7905		if ( data === undefined ) {
7906			// Get
7907			return ctx.length && this.length && this[0].length ?
7908				ctx[0].aoData[ this[0] ]._aData :
7909				undefined;
7910		}
7911	
7912		// Set
7913		var row = ctx[0].aoData[ this[0] ];
7914		row._aData = data;
7915	
7916		// If the DOM has an id, and the data source is an array
7917		if ( Array.isArray( data ) && row.nTr && row.nTr.id ) {
7918			_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
7919		}
7920	
7921		// Automatically invalidate
7922		_fnInvalidate( ctx[0], this[0], 'data' );
7923	
7924		return this;
7925	} );
7926	
7927	
7928	_api_register( 'row().node()', function () {
7929		var ctx = this.context;
7930	
7931		if (ctx.length && this.length && this[0].length) {
7932			var row = ctx[0].aoData[ this[0] ];
7933	
7934			if (row && row.nTr) {
7935				return row.nTr;
7936			}
7937		}
7938	
7939		return null;
7940	} );
7941	
7942	
7943	_api_register( 'row.add()', function ( row ) {
7944		// Allow a jQuery object to be passed in - only a single row is added from
7945		// it though - the first element in the set
7946		if ( row instanceof $ && row.length ) {
7947			row = row[0];
7948		}
7949	
7950		var rows = this.iterator( 'table', function ( settings ) {
7951			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7952				return _fnAddTr( settings, row )[0];
7953			}
7954			return _fnAddData( settings, row );
7955		} );
7956	
7957		// Return an Api.rows() extended instance, with the newly added row selected
7958		return this.row( rows[0] );
7959	} );
7960	
7961	
7962	$(document).on('plugin-init.dt', function (e, context) {
7963		var api = new _Api( context );
7964	
7965		api.on( 'stateSaveParams.DT', function ( e, settings, d ) {
7966			// This could be more compact with the API, but it is a lot faster as a simple
7967			// internal loop
7968			var idFn = settings.rowIdFn;
7969			var rows = settings.aiDisplayMaster;
7970			var ids = [];
7971	
7972			for (var i=0 ; i<rows.length ; i++) {
7973				var rowIdx = rows[i];
7974				var data = settings.aoData[rowIdx];
7975	
7976				if (data._detailsShow) {
7977					ids.push( '#' + idFn(data._aData) );
7978				}
7979			}
7980	
7981			d.childRows = ids;
7982		});
7983	
7984		// For future state loads (e.g. with StateRestore)
7985		api.on( 'stateLoaded.DT', function (e, settings, state) {
7986			__details_state_load( api, state );
7987		});
7988	
7989		// And the initial load state
7990		__details_state_load( api, api.state.loaded() );
7991	});
7992	
7993	var __details_state_load = function (api, state)
7994	{
7995		if ( state && state.childRows ) {
7996			api
7997				.rows( state.childRows.map(function (id) {
7998					// Escape any `:` characters from the row id. Accounts for
7999					// already escaped characters.
8000					return id.replace(/([^:\\]*(?:\\.[^:\\]*)*):/g, "$1\\:");
8001				}) )
8002				.every( function () {
8003					_fnCallbackFire( api.settings()[0], null, 'requestChild', [ this ] )
8004				});
8005		}
8006	}
8007	
8008	var __details_add = function ( ctx, row, data, klass )
8009	{
8010		// Convert to array of TR elements
8011		var rows = [];
8012		var addRow = function ( r, k ) {
8013			// Recursion to allow for arrays of jQuery objects
8014			if ( Array.isArray( r ) || r instanceof $ ) {
8015				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8016					addRow( r[i], k );
8017				}
8018				return;
8019			}
8020	
8021			// If we get a TR element, then just add it directly - up to the dev
8022			// to add the correct number of columns etc
8023			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8024				r.setAttribute( 'data-dt-row', row.idx );
8025				rows.push( r );
8026			}
8027			else {
8028				// Otherwise create a row with a wrapper
8029				var created = $('<tr><td></td></tr>')
8030					.attr( 'data-dt-row', row.idx )
8031					.addClass( k );
8032				
8033				$('td', created)
8034					.addClass( k )
8035					.html( r )[0].colSpan = _fnVisbleColumns( ctx );
8036	
8037				rows.push( created[0] );
8038			}
8039		};
8040	
8041		addRow( data, klass );
8042	
8043		if ( row._details ) {
8044			row._details.detach();
8045		}
8046	
8047		row._details = $(rows);
8048	
8049		// If the children were already shown, that state should be retained
8050		if ( row._detailsShow ) {
8051			row._details.insertAfter( row.nTr );
8052		}
8053	};
8054	
8055	
8056	// Make state saving of child row details async to allow them to be batch processed
8057	var __details_state = DataTable.util.throttle(
8058		function (ctx) {
8059			_fnSaveState( ctx[0] )
8060		},
8061		500
8062	);
8063	
8064	
8065	var __details_remove = function ( api, idx )
8066	{
8067		var ctx = api.context;
8068	
8069		if ( ctx.length ) {
8070			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8071	
8072			if ( row && row._details ) {
8073				row._details.remove();
8074	
8075				row._detailsShow = undefined;
8076				row._details = undefined;
8077				$( row.nTr ).removeClass( 'dt-hasChild' );
8078				__details_state( ctx );
8079			}
8080		}
8081	};
8082	
8083	
8084	var __details_display = function ( api, show ) {
8085		var ctx = api.context;
8086	
8087		if ( ctx.length && api.length ) {
8088			var row = ctx[0].aoData[ api[0] ];
8089	
8090			if ( row._details ) {
8091				row._detailsShow = show;
8092	
8093				if ( show ) {
8094					row._details.insertAfter( row.nTr );
8095					$( row.nTr ).addClass( 'dt-hasChild' );
8096				}
8097				else {
8098					row._details.detach();
8099					$( row.nTr ).removeClass( 'dt-hasChild' );
8100				}
8101	
8102				_fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )
8103	
8104				__details_events( ctx[0] );
8105				__details_state( ctx );
8106			}
8107		}
8108	};
8109	
8110	
8111	var __details_events = function ( settings )
8112	{
8113		var api = new _Api( settings );
8114		var namespace = '.dt.DT_details';
8115		var drawEvent = 'draw'+namespace;
8116		var colvisEvent = 'column-sizing'+namespace;
8117		var destroyEvent = 'destroy'+namespace;
8118		var data = settings.aoData;
8119	
8120		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8121	
8122		if ( _pluck( data, '_details' ).length > 0 ) {
8123			// On each draw, insert the required elements into the document
8124			api.on( drawEvent, function ( e, ctx ) {
8125				if ( settings !== ctx ) {
8126					return;
8127				}
8128	
8129				api.rows( {page:'current'} ).eq(0).each( function (idx) {
8130					// Internal data grab
8131					var row = data[ idx ];
8132	
8133					if ( row._detailsShow ) {
8134						row._details.insertAfter( row.nTr );
8135					}
8136				} );
8137			} );
8138	
8139			// Column visibility change - update the colspan
8140			api.on( colvisEvent, function ( e, ctx ) {
8141				if ( settings !== ctx ) {
8142					return;
8143				}
8144	
8145				// Update the colspan for the details rows (note, only if it already has
8146				// a colspan)
8147				var row, visible = _fnVisbleColumns( ctx );
8148	
8149				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8150					row = data[i];
8151	
8152					if ( row && row._details ) {
8153						row._details.each(function () {
8154							var el = $(this).children('td');
8155	
8156							if (el.length == 1) {
8157								el.attr('colspan', visible);
8158							}
8159						});
8160					}
8161				}
8162			} );
8163	
8164			// Table destroyed - nuke any child rows
8165			api.on( destroyEvent, function ( e, ctx ) {
8166				if ( settings !== ctx ) {
8167					return;
8168				}
8169	
8170				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8171					if ( data[i] && data[i]._details ) {
8172						__details_remove( api, i );
8173					}
8174				}
8175			} );
8176		}
8177	};
8178	
8179	// Strings for the method names to help minification
8180	var _emp = '';
8181	var _child_obj = _emp+'row().child';
8182	var _child_mth = _child_obj+'()';
8183	
8184	// data can be:
8185	//  tr
8186	//  string
8187	//  jQuery or array of any of the above
8188	_api_register( _child_mth, function ( data, klass ) {
8189		var ctx = this.context;
8190	
8191		if ( data === undefined ) {
8192			// get
8193			return ctx.length && this.length && ctx[0].aoData[ this[0] ]
8194				? ctx[0].aoData[ this[0] ]._details
8195				: undefined;
8196		}
8197		else if ( data === true ) {
8198			// show
8199			this.child.show();
8200		}
8201		else if ( data === false ) {
8202			// remove
8203			__details_remove( this );
8204		}
8205		else if ( ctx.length && this.length ) {
8206			// set
8207			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8208		}
8209	
8210		return this;
8211	} );
8212	
8213	
8214	_api_register( [
8215		_child_obj+'.show()',
8216		_child_mth+'.show()' // only when `child()` was called with parameters (without
8217	], function () {         // it returns an object and this method is not executed)
8218		__details_display( this, true );
8219		return this;
8220	} );
8221	
8222	
8223	_api_register( [
8224		_child_obj+'.hide()',
8225		_child_mth+'.hide()' // only when `child()` was called with parameters (without
8226	], function () {         // it returns an object and this method is not executed)
8227		__details_display( this, false );
8228		return this;
8229	} );
8230	
8231	
8232	_api_register( [
8233		_child_obj+'.remove()',
8234		_child_mth+'.remove()' // only when `child()` was called with parameters (without
8235	], function () {           // it returns an object and this method is not executed)
8236		__details_remove( this );
8237		return this;
8238	} );
8239	
8240	
8241	_api_register( _child_obj+'.isShown()', function () {
8242		var ctx = this.context;
8243	
8244		if ( ctx.length && this.length && ctx[0].aoData[ this[0] ] ) {
8245			// _detailsShown as false or undefined will fall through to return false
8246			return ctx[0].aoData[ this[0] ]._detailsShow || false;
8247		}
8248		return false;
8249	} );
8250	
8251	
8252	
8253	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8254	 * Columns
8255	 *
8256	 * {integer}           - column index (>=0 count from left, <0 count from right)
8257	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8258	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8259	 * "{string}:name"     - column name
8260	 * "{string}"          - jQuery selector on column header nodes
8261	 *
8262	 */
8263	
8264	// can be an array of these items, comma separated list, or an array of comma
8265	// separated lists
8266	
8267	var __re_column_selector = /^([^:]+)?:(name|title|visIdx|visible)$/;
8268	
8269	
8270	// r1 and r2 are redundant - but it means that the parameters match for the
8271	// iterator callback in columns().data()
8272	var __columnData = function ( settings, column, r1, r2, rows, type ) {
8273		var a = [];
8274		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8275			a.push( _fnGetCellData( settings, rows[row], column, type ) );
8276		}
8277		return a;
8278	};
8279	
8280	
8281	var __column_header = function ( settings, column, row ) {
8282		var header = settings.aoHeader;
8283		var target = row !== undefined
8284			? row
8285			: settings.bSortCellsTop // legacy support
8286				? 0
8287				: header.length - 1;
8288	
8289		return header[target][column].cell;
8290	};
8291	
8292	var __column_selector = function ( settings, selector, opts )
8293	{
8294		var
8295			columns = settings.aoColumns,
8296			names = _pluck( columns, 'sName' ),
8297			titles = _pluck( columns, 'sTitle' ),
8298			cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
8299			nodes = _unique( _flatten([], cells) );
8300		
8301		var run = function ( s ) {
8302			var selInt = _intVal( s );
8303	
8304			// Selector - all
8305			if ( s === '' ) {
8306				return _range( columns.length );
8307			}
8308	
8309			// Selector - index
8310			if ( selInt !== null ) {
8311				return [ selInt >= 0 ?
8312					selInt : // Count from left
8313					columns.length + selInt // Count from right (+ because its a negative value)
8314				];
8315			}
8316	
8317			// Selector = function
8318			if ( typeof s === 'function' ) {
8319				var rows = _selector_row_indexes( settings, opts );
8320	
8321				return columns.map(function (col, idx) {
8322					return s(
8323							idx,
8324							__columnData( settings, idx, 0, 0, rows ),
8325							__column_header( settings, idx )
8326						) ? idx : null;
8327				});
8328			}
8329	
8330			// jQuery or string selector
8331			var match = typeof s === 'string' ?
8332				s.match( __re_column_selector ) :
8333				'';
8334	
8335			if ( match ) {
8336				switch( match[2] ) {
8337					case 'visIdx':
8338					case 'visible':
8339						if (match[1]) {
8340							var idx = parseInt( match[1], 10 );
8341							// Visible index given, convert to column index
8342							if ( idx < 0 ) {
8343								// Counting from the right
8344								var visColumns = columns.map( function (col,i) {
8345									return col.bVisible ? i : null;
8346								} );
8347								return [ visColumns[ visColumns.length + idx ] ];
8348							}
8349							// Counting from the left
8350							return [ _fnVisibleToColumnIndex( settings, idx ) ];
8351						}
8352						
8353						// `:visible` on its own
8354						return columns.map( function (col, i) {
8355							return col.bVisible ? i : null;
8356						} );
8357	
8358					case 'name':
8359						// match by name. `names` is column index complete and in order
8360						return names.map( function (name, i) {
8361							return name === match[1] ? i : null;
8362						} );
8363	
8364					case 'title':
8365						// match by column title
8366						return titles.map( function (title, i) {
8367							return title === match[1] ? i : null;
8368						} );
8369	
8370					default:
8371						return [];
8372				}
8373			}
8374	
8375			// Cell in the table body
8376			if ( s.nodeName && s._DT_CellIndex ) {
8377				return [ s._DT_CellIndex.column ];
8378			}
8379	
8380			// jQuery selector on the TH elements for the columns
8381			var jqResult = $( nodes )
8382				.filter( s )
8383				.map( function () {
8384					return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
8385				} )
8386				.toArray();
8387	
8388			if ( jqResult.length || ! s.nodeName ) {
8389				return jqResult;
8390			}
8391	
8392			// Otherwise a node which might have a `dt-column` data attribute, or be
8393			// a child or such an element
8394			var host = $(s).closest('*[data-dt-column]');
8395			return host.length ?
8396				[ host.data('dt-column') ] :
8397				[];
8398		};
8399	
8400		return _selector_run( 'column', selector, run, settings, opts );
8401	};
8402	
8403	
8404	var __setColumnVis = function ( settings, column, vis ) {
8405		var
8406			cols = settings.aoColumns,
8407			col  = cols[ column ],
8408			data = settings.aoData,
8409			cells, i, ien, tr;
8410	
8411		// Get
8412		if ( vis === undefined ) {
8413			return col.bVisible;
8414		}
8415	
8416		// Set
8417		// No change
8418		if ( col.bVisible === vis ) {
8419			return false;
8420		}
8421	
8422		if ( vis ) {
8423			// Insert column
8424			// Need to decide if we should use appendChild or insertBefore
8425			var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column+1);
8426	
8427			for ( i=0, ien=data.length ; i<ien ; i++ ) {
8428				if (data[i]) {
8429					tr = data[i].nTr;
8430					cells = data[i].anCells;
8431	
8432					if ( tr ) {
8433						// insertBefore can act like appendChild if 2nd arg is null
8434						tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8435					}
8436				}
8437			}
8438		}
8439		else {
8440			// Remove column
8441			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
8442		}
8443	
8444		// Common actions
8445		col.bVisible = vis;
8446	
8447		_colGroup(settings);
8448		
8449		return true;
8450	};
8451	
8452	
8453	_api_register( 'columns()', function ( selector, opts ) {
8454		// argument shifting
8455		if ( selector === undefined ) {
8456			selector = '';
8457		}
8458		else if ( $.isPlainObject( selector ) ) {
8459			opts = selector;
8460			selector = '';
8461		}
8462	
8463		opts = _selector_opts( opts );
8464	
8465		var inst = this.iterator( 'table', function ( settings ) {
8466			return __column_selector( settings, selector, opts );
8467		}, 1 );
8468	
8469		// Want argument shifting here and in _row_selector?
8470		inst.selector.cols = selector;
8471		inst.selector.opts = opts;
8472	
8473		return inst;
8474	} );
8475	
8476	_api_registerPlural( 'columns().header()', 'column().header()', function ( row ) {
8477		return this.iterator( 'column', function (settings, column) {
8478			return __column_header(settings, column, row);
8479		}, 1 );
8480	} );
8481	
8482	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( row ) {
8483		return this.iterator( 'column', function ( settings, column ) {
8484			var footer = settings.aoFooter;
8485	
8486			if (! footer.length) {
8487				return null;
8488			}
8489	
8490			return settings.aoFooter[row !== undefined ? row : 0][column].cell;
8491		}, 1 );
8492	} );
8493	
8494	_api_registerPlural( 'columns().data()', 'column().data()', function () {
8495		return this.iterator( 'column-rows', __columnData, 1 );
8496	} );
8497	
8498	_api_registerPlural( 'columns().render()', 'column().render()', function ( type ) {
8499		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8500			return __columnData( settings, column, i, j, rows, type );
8501		}, 1 );
8502	} );
8503	
8504	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8505		return this.iterator( 'column', function ( settings, column ) {
8506			return settings.aoColumns[column].mData;
8507		}, 1 );
8508	} );
8509	
8510	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8511		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8512			return _pluck_order( settings.aoData, rows,
8513				type === 'search' ? '_aFilterData' : '_aSortData', column
8514			);
8515		}, 1 );
8516	} );
8517	
8518	_api_registerPlural( 'columns().init()', 'column().init()', function () {
8519		return this.iterator( 'column', function ( settings, column ) {
8520			return settings.aoColumns[column];
8521		}, 1 );
8522	} );
8523	
8524	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8525		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8526			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8527		}, 1 );
8528	} );
8529	
8530	_api_registerPlural( 'columns().titles()', 'column().title()', function (title, row) {
8531		return this.iterator( 'column', function ( settings, column ) {
8532			// Argument shifting
8533			if (typeof title === 'number') {
8534				row = title;
8535				title = undefined;
8536			}
8537	
8538			var span = $('span.dt-column-title', this.column(column).header(row));
8539	
8540			if (title !== undefined) {
8541				span.html(title);
8542				return this;
8543			}
8544	
8545			return span.html();
8546		}, 1 );
8547	} );
8548	
8549	_api_registerPlural( 'columns().types()', 'column().type()', function () {
8550		return this.iterator( 'column', function ( settings, column ) {
8551			var type = settings.aoColumns[column].sType;
8552	
8553			// If the type was invalidated, then resolve it. This actually does
8554			// all columns at the moment. Would only happen once if getting all
8555			// column's data types.
8556			if (! type) {
8557				_fnColumnTypes(settings);
8558			}
8559	
8560			return type;
8561		}, 1 );
8562	} );
8563	
8564	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8565		var that = this;
8566		var changed = [];
8567		var ret = this.iterator( 'column', function ( settings, column ) {
8568			if ( vis === undefined ) {
8569				return settings.aoColumns[ column ].bVisible;
8570			} // else
8571			
8572			if (__setColumnVis( settings, column, vis )) {
8573				changed.push(column);
8574			}
8575		} );
8576	
8577		// Group the column visibility changes
8578		if ( vis !== undefined ) {
8579			this.iterator( 'table', function ( settings ) {
8580				// Redraw the header after changes
8581				_fnDrawHead( settings, settings.aoHeader );
8582				_fnDrawHead( settings, settings.aoFooter );
8583		
8584				// Update colspan for no records display. Child rows and extensions will use their own
8585				// listeners to do this - only need to update the empty table item here
8586				if ( ! settings.aiDisplay.length ) {
8587					$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8588				}
8589		
8590				_fnSaveState( settings );
8591	
8592				// Second loop once the first is done for events
8593				that.iterator( 'column', function ( settings, column ) {
8594					if (changed.includes(column)) {
8595						_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8596					}
8597				} );
8598	
8599				if ( changed.length && (calc === undefined || calc) ) {
8600					that.columns.adjust();
8601				}
8602			});
8603		}
8604	
8605		return ret;
8606	} );
8607	
8608	_api_registerPlural( 'columns().widths()', 'column().width()', function () {
8609		// Injects a fake row into the table for just a moment so the widths can
8610		// be read, regardless of colspan in the header and rows being present in
8611		// the body
8612		var columns = this.columns(':visible').count();
8613		var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
8614	
8615		$(this.table().body()).append(row);
8616	
8617		var widths = row.children().map(function () {
8618			return $(this).outerWidth();
8619		});
8620	
8621		row.remove();
8622		
8623		return this.iterator( 'column', function ( settings, column ) {
8624			var visIdx = _fnColumnIndexToVisible( settings, column );
8625	
8626			return visIdx !== null ? widths[visIdx] : 0;
8627		}, 1);
8628	} );
8629	
8630	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8631		return this.iterator( 'column', function ( settings, column ) {
8632			return type === 'visible' ?
8633				_fnColumnIndexToVisible( settings, column ) :
8634				column;
8635		}, 1 );
8636	} );
8637	
8638	_api_register( 'columns.adjust()', function () {
8639		return this.iterator( 'table', function ( settings ) {
8640			_fnAdjustColumnSizing( settings );
8641		}, 1 );
8642	} );
8643	
8644	_api_register( 'column.index()', function ( type, idx ) {
8645		if ( this.context.length !== 0 ) {
8646			var ctx = this.context[0];
8647	
8648			if ( type === 'fromVisible' || type === 'toData' ) {
8649				return _fnVisibleToColumnIndex( ctx, idx );
8650			}
8651			else if ( type === 'fromData' || type === 'toVisible' ) {
8652				return _fnColumnIndexToVisible( ctx, idx );
8653			}
8654		}
8655	} );
8656	
8657	_api_register( 'column()', function ( selector, opts ) {
8658		return _selector_first( this.columns( selector, opts ) );
8659	} );
8660	
8661	var __cell_selector = function ( settings, selector, opts )
8662	{
8663		var data = settings.aoData;
8664		var rows = _selector_row_indexes( settings, opts );
8665		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8666		var allCells = $(_flatten( [], cells ));
8667		var row;
8668		var columns = settings.aoColumns.length;
8669		var a, i, ien, j, o, host;
8670	
8671		var run = function ( s ) {
8672			var fnSelector = typeof s === 'function';
8673	
8674			if ( s === null || s === undefined || fnSelector ) {
8675				// All cells and function selectors
8676				a = [];
8677	
8678				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8679					row = rows[i];
8680	
8681					for ( j=0 ; j<columns ; j++ ) {
8682						o = {
8683							row: row,
8684							column: j
8685						};
8686	
8687						if ( fnSelector ) {
8688							// Selector - function
8689							host = data[ row ];
8690	
8691							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8692								a.push( o );
8693							}
8694						}
8695						else {
8696							// Selector - all
8697							a.push( o );
8698						}
8699					}
8700				}
8701	
8702				return a;
8703			}
8704			
8705			// Selector - index
8706			if ( $.isPlainObject( s ) ) {
8707				// Valid cell index and its in the array of selectable rows
8708				return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
8709					[s] :
8710					[];
8711			}
8712	
8713			// Selector - jQuery filtered cells
8714			var jqResult = allCells
8715				.filter( s )
8716				.map( function (i, el) {
8717					return { // use a new object, in case someone changes the values
8718						row:    el._DT_CellIndex.row,
8719						column: el._DT_CellIndex.column
8720					};
8721				} )
8722				.toArray();
8723	
8724			if ( jqResult.length || ! s.nodeName ) {
8725				return jqResult;
8726			}
8727	
8728			// Otherwise the selector is a node, and there is one last option - the
8729			// element might be a child of an element which has dt-row and dt-column
8730			// data attributes
8731			host = $(s).closest('*[data-dt-row]');
8732			return host.length ?
8733				[ {
8734					row: host.data('dt-row'),
8735					column: host.data('dt-column')
8736				} ] :
8737				[];
8738		};
8739	
8740		return _selector_run( 'cell', selector, run, settings, opts );
8741	};
8742	
8743	
8744	
8745	
8746	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8747		// Argument shifting
8748		if ( $.isPlainObject( rowSelector ) ) {
8749			// Indexes
8750			if ( rowSelector.row === undefined ) {
8751				// Selector options in first parameter
8752				opts = rowSelector;
8753				rowSelector = null;
8754			}
8755			else {
8756				// Cell index objects in first parameter
8757				opts = columnSelector;
8758				columnSelector = null;
8759			}
8760		}
8761		if ( $.isPlainObject( columnSelector ) ) {
8762			opts = columnSelector;
8763			columnSelector = null;
8764		}
8765	
8766		// Cell selector
8767		if ( columnSelector === null || columnSelector === undefined ) {
8768			return this.iterator( 'table', function ( settings ) {
8769				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8770			} );
8771		}
8772	
8773		// The default built in options need to apply to row and columns
8774		var internalOpts = opts ? {
8775			page: opts.page,
8776			order: opts.order,
8777			search: opts.search
8778		} : {};
8779	
8780		// Row + column selector
8781		var columns = this.columns( columnSelector, internalOpts );
8782		var rows = this.rows( rowSelector, internalOpts );
8783		var i, ien, j, jen;
8784	
8785		var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
8786			var a = [];
8787	
8788			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8789				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8790					a.push( {
8791						row:    rows[idx][i],
8792						column: columns[idx][j]
8793					} );
8794				}
8795			}
8796	
8797			return a;
8798		}, 1 );
8799	
8800		// There is currently only one extension which uses a cell selector extension
8801		// It is a _major_ performance drag to run this if it isn't needed, so this is
8802		// an extension specific check at the moment
8803		var cells = opts && opts.selected ?
8804			this.cells( cellsNoOpts, opts ) :
8805			cellsNoOpts;
8806	
8807		$.extend( cells.selector, {
8808			cols: columnSelector,
8809			rows: rowSelector,
8810			opts: opts
8811		} );
8812	
8813		return cells;
8814	} );
8815	
8816	
8817	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8818		return this.iterator( 'cell', function ( settings, row, column ) {
8819			var data = settings.aoData[ row ];
8820	
8821			return data && data.anCells ?
8822				data.anCells[ column ] :
8823				undefined;
8824		}, 1 );
8825	} );
8826	
8827	
8828	_api_register( 'cells().data()', function () {
8829		return this.iterator( 'cell', function ( settings, row, column ) {
8830			return _fnGetCellData( settings, row, column );
8831		}, 1 );
8832	} );
8833	
8834	
8835	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8836		type = type === 'search' ? '_aFilterData' : '_aSortData';
8837	
8838		return this.iterator( 'cell', function ( settings, row, column ) {
8839			return settings.aoData[ row ][ type ][ column ];
8840		}, 1 );
8841	} );
8842	
8843	
8844	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8845		return this.iterator( 'cell', function ( settings, row, column ) {
8846			return _fnGetCellData( settings, row, column, type );
8847		}, 1 );
8848	} );
8849	
8850	
8851	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8852		return this.iterator( 'cell', function ( settings, row, column ) {
8853			return {
8854				row: row,
8855				column: column,
8856				columnVisible: _fnColumnIndexToVisible( settings, column )
8857			};
8858		}, 1 );
8859	} );
8860	
8861	
8862	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8863		return this.iterator( 'cell', function ( settings, row, column ) {
8864			_fnInvalidate( settings, row, src, column );
8865		} );
8866	} );
8867	
8868	
8869	
8870	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8871		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8872	} );
8873	
8874	
8875	_api_register( 'cell().data()', function ( data ) {
8876		var ctx = this.context;
8877		var cell = this[0];
8878	
8879		if ( data === undefined ) {
8880			// Get
8881			return ctx.length && cell.length ?
8882				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8883				undefined;
8884		}
8885	
8886		// Set
8887		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8888		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8889	
8890		return this;
8891	} );
8892	
8893	
8894	
8895	/**
8896	 * Get current ordering (sorting) that has been applied to the table.
8897	 *
8898	 * @returns {array} 2D array containing the sorting information for the first
8899	 *   table in the current context. Each element in the parent array represents
8900	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
8901	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8902	 *   the column index that the sorting condition applies to, the second is the
8903	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
8904	 *   index of the sorting order from the `column.sorting` initialisation array.
8905	 *//**
8906	 * Set the ordering for the table.
8907	 *
8908	 * @param {integer} order Column index to sort upon.
8909	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8910	 * @returns {DataTables.Api} this
8911	 *//**
8912	 * Set the ordering for the table.
8913	 *
8914	 * @param {array} order 1D array of sorting information to be applied.
8915	 * @param {array} [...] Optional additional sorting conditions
8916	 * @returns {DataTables.Api} this
8917	 *//**
8918	 * Set the ordering for the table.
8919	 *
8920	 * @param {array} order 2D array of sorting information to be applied.
8921	 * @returns {DataTables.Api} this
8922	 */
8923	_api_register( 'order()', function ( order, dir ) {
8924		var ctx = this.context;
8925		var args = Array.prototype.slice.call( arguments );
8926	
8927		if ( order === undefined ) {
8928			// get
8929			return ctx.length !== 0 ?
8930				ctx[0].aaSorting :
8931				undefined;
8932		}
8933	
8934		// set
8935		if ( typeof order === 'number' ) {
8936			// Simple column / direction passed in
8937			order = [ [ order, dir ] ];
8938		}
8939		else if ( args.length > 1 ) {
8940			// Arguments passed in (list of 1D arrays)
8941			order = args;
8942		}
8943		// otherwise a 2D array was passed in
8944	
8945		return this.iterator( 'table', function ( settings ) {
8946			settings.aaSorting = Array.isArray(order) ? order.slice() : order;
8947		} );
8948	} );
8949	
8950	
8951	/**
8952	 * Attach a sort listener to an element for a given column
8953	 *
8954	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8955	 *   listener to. This can take the form of a single DOM node, a jQuery
8956	 *   collection of nodes or a jQuery selector which will identify the node(s).
8957	 * @param {integer} column the column that a click on this node will sort on
8958	 * @param {function} [callback] callback function when sort is run
8959	 * @returns {DataTables.Api} this
8960	 */
8961	_api_register( 'order.listener()', function ( node, column, callback ) {
8962		return this.iterator( 'table', function ( settings ) {
8963			_fnSortAttachListener(settings, node, {}, column, callback);
8964		} );
8965	} );
8966	
8967	
8968	_api_register( 'order.fixed()', function ( set ) {
8969		if ( ! set ) {
8970			var ctx = this.context;
8971			var fixed = ctx.length ?
8972				ctx[0].aaSortingFixed :
8973				undefined;
8974	
8975			return Array.isArray( fixed ) ?
8976				{ pre: fixed } :
8977				fixed;
8978		}
8979	
8980		return this.iterator( 'table', function ( settings ) {
8981			settings.aaSortingFixed = $.extend( true, {}, set );
8982		} );
8983	} );
8984	
8985	
8986	// Order by the selected column(s)
8987	_api_register( [
8988		'columns().order()',
8989		'column().order()'
8990	], function ( dir ) {
8991		var that = this;
8992	
8993		if ( ! dir ) {
8994			return this.iterator( 'column', function ( settings, idx ) {
8995				var sort = _fnSortFlatten( settings );
8996	
8997				for ( var i=0, ien=sort.length ; i<ien ; i++ ) {
8998					if ( sort[i].col === idx ) {
8999						return sort[i].dir;
9000					}
9001				}
9002	
9003				return null;
9004			}, 1 );
9005		}
9006		else {
9007			return this.iterator( 'table', function ( settings, i ) {
9008				settings.aaSorting = that[i].map( function (col) {
9009					return [ col, dir ];
9010				} );
9011			} );
9012		}
9013	} );
9014	
9015	_api_registerPlural('columns().orderable()', 'column().orderable()', function ( directions ) {
9016		return this.iterator( 'column', function ( settings, idx ) {
9017			var col = settings.aoColumns[idx];
9018	
9019			return directions ?
9020				col.asSorting :
9021				col.bSortable;
9022		}, 1 );
9023	} );
9024	
9025	
9026	_api_register( 'processing()', function ( show ) {
9027		return this.iterator( 'table', function ( ctx ) {
9028			_fnProcessingDisplay( ctx, show );
9029		} );
9030	} );
9031	
9032	
9033	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9034		var ctx = this.context;
9035	
9036		if ( input === undefined ) {
9037			// get
9038			return ctx.length !== 0 ?
9039				ctx[0].oPreviousSearch.search :
9040				undefined;
9041		}
9042	
9043		// set
9044		return this.iterator( 'table', function ( settings ) {
9045			if ( ! settings.oFeatures.bFilter ) {
9046				return;
9047			}
9048	
9049			if (typeof regex === 'object') {
9050				// New style options to pass to the search builder
9051				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, regex, {
9052					search: input
9053				} ) );
9054			}
9055			else {
9056				// Compat for the old options
9057				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, {
9058					search: input,
9059					regex:  regex === null ? false : regex,
9060					smart:  smart === null ? true  : smart,
9061					caseInsensitive: caseInsen === null ? true : caseInsen
9062				} ) );
9063			}
9064		} );
9065	} );
9066	
9067	_api_register( 'search.fixed()', function ( name, search ) {
9068		var ret = this.iterator( true, 'table', function ( settings ) {
9069			var fixed = settings.searchFixed;
9070	
9071			if (! name) {
9072				return Object.keys(fixed)
9073			}
9074			else if (search === undefined) {
9075				return fixed[name];
9076			}
9077			else if (search === null) {
9078				delete fixed[name];
9079			}
9080			else {
9081				fixed[name] = search;
9082			}
9083	
9084			return this;
9085		} );
9086	
9087		return name !== undefined && search === undefined
9088			? ret[0]
9089			: ret;
9090	} );
9091	
9092	_api_registerPlural(
9093		'columns().search()',
9094		'column().search()',
9095		function ( input, regex, smart, caseInsen ) {
9096			return this.iterator( 'column', function ( settings, column ) {
9097				var preSearch = settings.aoPreSearchCols;
9098	
9099				if ( input === undefined ) {
9100					// get
9101					return preSearch[ column ].search;
9102				}
9103	
9104				// set
9105				if ( ! settings.oFeatures.bFilter ) {
9106					return;
9107				}
9108	
9109				if (typeof regex === 'object') {
9110					// New style options to pass to the search builder
9111					$.extend( preSearch[ column ], regex, {
9112						search: input
9113					} );
9114				}
9115				else {
9116					// Old style (with not all options available)
9117					$.extend( preSearch[ column ], {
9118						search: input,
9119						regex:  regex === null ? false : regex,
9120						smart:  smart === null ? true  : smart,
9121						caseInsensitive: caseInsen === null ? true : caseInsen
9122					} );
9123				}
9124	
9125				_fnFilterComplete( settings, settings.oPreviousSearch );
9126			} );
9127		}
9128	);
9129	
9130	_api_register([
9131			'columns().search.fixed()',
9132			'column().search.fixed()'
9133		],
9134		function ( name, search ) {
9135			var ret = this.iterator( true, 'column', function ( settings, colIdx ) {
9136				var fixed = settings.aoColumns[colIdx].searchFixed;
9137	
9138				if (! name) {
9139					return Object.keys(fixed)
9140				}
9141				else if (search === undefined) {
9142					return fixed[name];
9143				}
9144				else if (search === null) {
9145					delete fixed[name];
9146				}
9147				else {
9148					fixed[name] = search;
9149				}
9150	
9151				return this;
9152			} );
9153	
9154			return name !== undefined && search === undefined
9155				? ret[0]
9156				: ret;
9157		}
9158	);
9159	/*
9160	 * State API methods
9161	 */
9162	
9163	_api_register( 'state()', function ( set, ignoreTime ) {
9164		// getter
9165		if ( ! set ) {
9166			return this.context.length ?
9167				this.context[0].oSavedState :
9168				null;
9169		}
9170	
9171		var setMutate = $.extend( true, {}, set );
9172	
9173		// setter
9174		return this.iterator( 'table', function ( settings ) {
9175			if ( ignoreTime !== false ) {
9176				setMutate.time = +new Date() + 100;
9177			}
9178	
9179			_fnImplementState( settings, setMutate, function(){} );
9180		} );
9181	} );
9182	
9183	
9184	_api_register( 'state.clear()', function () {
9185		return this.iterator( 'table', function ( settings ) {
9186			// Save an empty object
9187			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9188		} );
9189	} );
9190	
9191	
9192	_api_register( 'state.loaded()', function () {
9193		return this.context.length ?
9194			this.context[0].oLoadedState :
9195			null;
9196	} );
9197	
9198	
9199	_api_register( 'state.save()', function () {
9200		return this.iterator( 'table', function ( settings ) {
9201			_fnSaveState( settings );
9202		} );
9203	} );
9204	
9205	/**
9206	 * Set the jQuery or window object to be used by DataTables
9207	 *
9208	 * @param {*} module Library / container object
9209	 * @param {string} [type] Library or container type `lib`, `win` or `datetime`.
9210	 *   If not provided, automatic detection is attempted.
9211	 */
9212	DataTable.use = function (module, type) {
9213		if (type === 'lib' || module.fn) {
9214			$ = module;
9215		}
9216		else if (type == 'win' || module.document) {
9217			window = module;
9218			document = module.document;
9219		}
9220		else if (type === 'datetime' || module.type === 'DateTime') {
9221			DataTable.DateTime = module;
9222		}
9223	}
9224	
9225	/**
9226	 * CommonJS factory function pass through. This will check if the arguments
9227	 * given are a window object or a jQuery object. If so they are set
9228	 * accordingly.
9229	 * @param {*} root Window
9230	 * @param {*} jq jQUery
9231	 * @returns {boolean} Indicator
9232	 */
9233	DataTable.factory = function (root, jq) {
9234		var is = false;
9235	
9236		// Test if the first parameter is a window object
9237		if (root && root.document) {
9238			window = root;
9239			document = root.document;
9240		}
9241	
9242		// Test if the second parameter is a jQuery object
9243		if (jq && jq.fn && jq.fn.jquery) {
9244			$ = jq;
9245			is = true;
9246		}
9247	
9248		return is;
9249	}
9250	
9251	/**
9252	 * Provide a common method for plug-ins to check the version of DataTables being
9253	 * used, in order to ensure compatibility.
9254	 *
9255	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
9256	 *    Note that the formats "X" and "X.Y" are also acceptable.
9257	 *  @param {string} [version2=current DataTables version] As above, but optional.
9258	 *   If not given the current DataTables version will be used.
9259	 *  @returns {boolean} true if this version of DataTables is greater or equal to
9260	 *    the required version, or false if this version of DataTales is not
9261	 *    suitable
9262	 *  @static
9263	 *  @dtopt API-Static
9264	 *
9265	 *  @example
9266	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9267	 */
9268	DataTable.versionCheck = function( version, version2 )
9269	{
9270		var aThis = version2 ?
9271			version2.split('.') :
9272			DataTable.version.split('.');
9273		var aThat = version.split('.');
9274		var iThis, iThat;
9275	
9276		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9277			iThis = parseInt( aThis[i], 10 ) || 0;
9278			iThat = parseInt( aThat[i], 10 ) || 0;
9279	
9280			// Parts are the same, keep comparing
9281			if (iThis === iThat) {
9282				continue;
9283			}
9284	
9285			// Parts are different, return immediately
9286			return iThis > iThat;
9287		}
9288	
9289		return true;
9290	};
9291	
9292	
9293	/**
9294	 * Check if a `<table>` node is a DataTable table already or not.
9295	 *
9296	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9297	 *      selector for the table to test. Note that if more than more than one
9298	 *      table is passed on, only the first will be checked
9299	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
9300	 *  @static
9301	 *  @dtopt API-Static
9302	 *
9303	 *  @example
9304	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9305	 *      $('#example').dataTable();
9306	 *    }
9307	 */
9308	DataTable.isDataTable = function ( table )
9309	{
9310		var t = $(table).get(0);
9311		var is = false;
9312	
9313		if ( table instanceof DataTable.Api ) {
9314			return true;
9315		}
9316	
9317		$.each( DataTable.settings, function (i, o) {
9318			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9319			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9320	
9321			if ( o.nTable === t || head === t || foot === t ) {
9322				is = true;
9323			}
9324		} );
9325	
9326		return is;
9327	};
9328	
9329	
9330	/**
9331	 * Get all DataTable tables that have been initialised - optionally you can
9332	 * select to get only currently visible tables.
9333	 *
9334	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9335	 *    or visible tables only.
9336	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9337	 *    DataTables
9338	 *  @static
9339	 *  @dtopt API-Static
9340	 *
9341	 *  @example
9342	 *    $.each( $.fn.dataTable.tables(true), function () {
9343	 *      $(table).DataTable().columns.adjust();
9344	 *    } );
9345	 */
9346	DataTable.tables = function ( visible )
9347	{
9348		var api = false;
9349	
9350		if ( $.isPlainObject( visible ) ) {
9351			api = visible.api;
9352			visible = visible.visible;
9353		}
9354	
9355		var a = DataTable.settings
9356			.filter( function (o) {
9357				return !visible || (visible && $(o.nTable).is(':visible')) 
9358					? true
9359					: false;
9360			} )
9361			.map( function (o) {
9362				return o.nTable;
9363			});
9364	
9365		return api ?
9366			new _Api( a ) :
9367			a;
9368	};
9369	
9370	
9371	/**
9372	 * Convert from camel case parameters to Hungarian notation. This is made public
9373	 * for the extensions to provide the same ability as DataTables core to accept
9374	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9375	 * parameters.
9376	 *
9377	 *  @param {object} src The model object which holds all parameters that can be
9378	 *    mapped.
9379	 *  @param {object} user The object to convert from camel case to Hungarian.
9380	 *  @param {boolean} force When set to `true`, properties which already have a
9381	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
9382	 *    won't be.
9383	 */
9384	DataTable.camelToHungarian = _fnCamelToHungarian;
9385	
9386	
9387	
9388	/**
9389	 *
9390	 */
9391	_api_register( '$()', function ( selector, opts ) {
9392		var
9393			rows   = this.rows( opts ).nodes(), // Get all rows
9394			jqRows = $(rows);
9395	
9396		return $( [].concat(
9397			jqRows.filter( selector ).toArray(),
9398			jqRows.find( selector ).toArray()
9399		) );
9400	} );
9401	
9402	
9403	// jQuery functions to operate on the tables
9404	$.each( [ 'on', 'one', 'off' ], function (i, key) {
9405		_api_register( key+'()', function ( /* event, handler */ ) {
9406			var args = Array.prototype.slice.call(arguments);
9407	
9408			// Add the `dt` namespace automatically if it isn't already present
9409			args[0] = args[0].split( /\s/ ).map( function ( e ) {
9410				return ! e.match(/\.dt\b/) ?
9411					e+'.dt' :
9412					e;
9413				} ).join( ' ' );
9414	
9415			var inst = $( this.tables().nodes() );
9416			inst[key].apply( inst, args );
9417			return this;
9418		} );
9419	} );
9420	
9421	
9422	_api_register( 'clear()', function () {
9423		return this.iterator( 'table', function ( settings ) {
9424			_fnClearTable( settings );
9425		} );
9426	} );
9427	
9428	
9429	_api_register( 'error()', function (msg) {
9430		return this.iterator( 'table', function ( settings ) {
9431			_fnLog( settings, 0, msg );
9432		} );
9433	} );
9434	
9435	
9436	_api_register( 'settings()', function () {
9437		return new _Api( this.context, this.context );
9438	} );
9439	
9440	
9441	_api_register( 'init()', function () {
9442		var ctx = this.context;
9443		return ctx.length ? ctx[0].oInit : null;
9444	} );
9445	
9446	
9447	_api_register( 'data()', function () {
9448		return this.iterator( 'table', function ( settings ) {
9449			return _pluck( settings.aoData, '_aData' );
9450		} ).flatten();
9451	} );
9452	
9453	
9454	_api_register( 'trigger()', function ( name, args, bubbles ) {
9455		return this.iterator( 'table', function ( settings ) {
9456			return _fnCallbackFire( settings, null, name, args, bubbles );
9457		} ).flatten();
9458	} );
9459	
9460	
9461	_api_register( 'ready()', function ( fn ) {
9462		var ctx = this.context;
9463	
9464		// Get status of first table
9465		if (! fn) {
9466			return ctx.length
9467				? (ctx[0]._bInitComplete || false)
9468				: null;
9469		}
9470	
9471		// Function to run either once the table becomes ready or
9472		// immediately if it is already ready.
9473		return this.tables().every(function () {
9474			if (this.context[0]._bInitComplete) {
9475				fn.call(this);
9476			}
9477			else {
9478				this.on('init', function () {
9479					fn.call(this);
9480				});
9481			}
9482		} );
9483	} );
9484	
9485	
9486	_api_register( 'destroy()', function ( remove ) {
9487		remove = remove || false;
9488	
9489		return this.iterator( 'table', function ( settings ) {
9490			var classes   = settings.oClasses;
9491			var table     = settings.nTable;
9492			var tbody     = settings.nTBody;
9493			var thead     = settings.nTHead;
9494			var tfoot     = settings.nTFoot;
9495			var jqTable   = $(table);
9496			var jqTbody   = $(tbody);
9497			var jqWrapper = $(settings.nTableWrapper);
9498			var rows      = settings.aoData.map( function (r) { return r ? r.nTr : null; } );
9499			var orderClasses = classes.order;
9500	
9501			// Flag to note that the table is currently being destroyed - no action
9502			// should be taken
9503			settings.bDestroying = true;
9504	
9505			// Fire off the destroy callbacks for plug-ins etc
9506			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings], true );
9507	
9508			// If not being removed from the document, make all columns visible
9509			if ( ! remove ) {
9510				new _Api( settings ).columns().visible( true );
9511			}
9512	
9513			// Blitz all `DT` namespaced events (these are internal events, the
9514			// lowercase, `dt` events are user subscribed and they are responsible
9515			// for removing them
9516			jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9517			$(window).off('.DT-'+settings.sInstance);
9518	
9519			// When scrolling we had to break the table up - restore it
9520			if ( table != thead.parentNode ) {
9521				jqTable.children('thead').detach();
9522				jqTable.append( thead );
9523			}
9524	
9525			if ( tfoot && table != tfoot.parentNode ) {
9526				jqTable.children('tfoot').detach();
9527				jqTable.append( tfoot );
9528			}
9529	
9530			settings.colgroup.remove();
9531	
9532			settings.aaSorting = [];
9533			settings.aaSortingFixed = [];
9534			_fnSortingClasses( settings );
9535	
9536			$('th, td', thead)
9537				.removeClass(
9538					orderClasses.canAsc + ' ' +
9539					orderClasses.canDesc + ' ' +
9540					orderClasses.isAsc + ' ' +
9541					orderClasses.isDesc
9542				)
9543				.css('width', '');
9544	
9545			// Add the TR elements back into the table in their original order
9546			jqTbody.children().detach();
9547			jqTbody.append( rows );
9548	
9549			var orig = settings.nTableWrapper.parentNode;
9550			var insertBefore = settings.nTableWrapper.nextSibling;
9551	
9552			// Remove the DataTables generated nodes, events and classes
9553			var removedMethod = remove ? 'remove' : 'detach';
9554			jqTable[ removedMethod ]();
9555			jqWrapper[ removedMethod ]();
9556	
9557			// If we need to reattach the table to the document
9558			if ( ! remove && orig ) {
9559				// insertBefore acts like appendChild if !arg[1]
9560				orig.insertBefore( table, insertBefore );
9561	
9562				// Restore the width of the original table - was read from the style property,
9563				// so we can restore directly to that
9564				jqTable
9565					.css( 'width', settings.sDestroyWidth )
9566					.removeClass( classes.table );
9567			}
9568	
9569			/* Remove the settings object from the settings array */
9570			var idx = DataTable.settings.indexOf(settings);
9571			if ( idx !== -1 ) {
9572				DataTable.settings.splice( idx, 1 );
9573			}
9574		} );
9575	} );
9576	
9577	
9578	// Add the `every()` method for rows, columns and cells in a compact form
9579	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9580		_api_register( type+'s().every()', function ( fn ) {
9581			var opts = this.selector.opts;
9582			var api = this;
9583			var inst;
9584			var counter = 0;
9585	
9586			return this.iterator( 'every', function ( settings, selectedIdx, tableIdx ) {
9587				inst = api[ type ](selectedIdx, opts);
9588	
9589				if (type === 'cell') {
9590					fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
9591				}
9592				else {
9593					fn.call(inst, selectedIdx, tableIdx, counter);
9594				}
9595	
9596				counter++;
9597			} );
9598		} );
9599	} );
9600	
9601	
9602	// i18n method for extensions to be able to use the language object from the
9603	// DataTable
9604	_api_register( 'i18n()', function ( token, def, plural ) {
9605		var ctx = this.context[0];
9606		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9607	
9608		if ( resolved === undefined ) {
9609			resolved = def;
9610		}
9611	
9612		if ( $.isPlainObject( resolved ) ) {
9613			resolved = plural !== undefined && resolved[ plural ] !== undefined ?
9614				resolved[ plural ] :
9615				resolved._;
9616		}
9617	
9618		return typeof resolved === 'string'
9619			? resolved.replace( '%d', plural ) // nb: plural might be undefined,
9620			: resolved;
9621	} );
9622	
9623	/**
9624	 * Version string for plug-ins to check compatibility. Allowed format is
9625	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9626	 * only for non-release builds. See https://semver.org/ for more information.
9627	 *  @member
9628	 *  @type string
9629	 *  @default Version number
9630	 */
9631	DataTable.version = "2.0.8";
9632	
9633	/**
9634	 * Private data store, containing all of the settings objects that are
9635	 * created for the tables on a given page.
9636	 *
9637	 * Note that the `DataTable.settings` object is aliased to
9638	 * `jQuery.fn.dataTableExt` through which it may be accessed and
9639	 * manipulated, or `jQuery.fn.dataTable.settings`.
9640	 *  @member
9641	 *  @type array
9642	 *  @default []
9643	 *  @private
9644	 */
9645	DataTable.settings = [];
9646	
9647	/**
9648	 * Object models container, for the various models that DataTables has
9649	 * available to it. These models define the objects that are used to hold
9650	 * the active state and configuration of the table.
9651	 *  @namespace
9652	 */
9653	DataTable.models = {};
9654	
9655	
9656	
9657	/**
9658	 * Template object for the way in which DataTables holds information about
9659	 * search information for the global filter and individual column filters.
9660	 *  @namespace
9661	 */
9662	DataTable.models.oSearch = {
9663		/**
9664		 * Flag to indicate if the filtering should be case insensitive or not
9665		 */
9666		"caseInsensitive": true,
9667	
9668		/**
9669		 * Applied search term
9670		 */
9671		"search": "",
9672	
9673		/**
9674		 * Flag to indicate if the search term should be interpreted as a
9675		 * regular expression (true) or not (false) and therefore and special
9676		 * regex characters escaped.
9677		 */
9678		"regex": false,
9679	
9680		/**
9681		 * Flag to indicate if DataTables is to use its smart filtering or not.
9682		 */
9683		"smart": true,
9684	
9685		/**
9686		 * Flag to indicate if DataTables should only trigger a search when
9687		 * the return key is pressed.
9688		 */
9689		"return": false
9690	};
9691	
9692	
9693	
9694	
9695	/**
9696	 * Template object for the way in which DataTables holds information about
9697	 * each individual row. This is the object format used for the settings
9698	 * aoData array.
9699	 *  @namespace
9700	 */
9701	DataTable.models.oRow = {
9702		/**
9703		 * TR element for the row
9704		 */
9705		"nTr": null,
9706	
9707		/**
9708		 * Array of TD elements for each row. This is null until the row has been
9709		 * created.
9710		 */
9711		"anCells": null,
9712	
9713		/**
9714		 * Data object from the original data source for the row. This is either
9715		 * an array if using the traditional form of DataTables, or an object if
9716		 * using mData options. The exact type will depend on the passed in
9717		 * data from the data source, or will be an array if using DOM a data
9718		 * source.
9719		 */
9720		"_aData": [],
9721	
9722		/**
9723		 * Sorting data cache - this array is ostensibly the same length as the
9724		 * number of columns (although each index is generated only as it is
9725		 * needed), and holds the data that is used for sorting each column in the
9726		 * row. We do this cache generation at the start of the sort in order that
9727		 * the formatting of the sort data need be done only once for each cell
9728		 * per sort. This array should not be read from or written to by anything
9729		 * other than the master sorting methods.
9730		 */
9731		"_aSortData": null,
9732	
9733		/**
9734		 * Per cell filtering data cache. As per the sort data cache, used to
9735		 * increase the performance of the filtering in DataTables
9736		 */
9737		"_aFilterData": null,
9738	
9739		/**
9740		 * Filtering data cache. This is the same as the cell filtering cache, but
9741		 * in this case a string rather than an array. This is easily computed with
9742		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9743		 * needed on every search (memory traded for performance)
9744		 */
9745		"_sFilterRow": null,
9746	
9747		/**
9748		 * Denote if the original data source was from the DOM, or the data source
9749		 * object. This is used for invalidating data, so DataTables can
9750		 * automatically read data from the original source, unless uninstructed
9751		 * otherwise.
9752		 */
9753		"src": null,
9754	
9755		/**
9756		 * Index in the aoData array. This saves an indexOf lookup when we have the
9757		 * object, but want to know the index
9758		 */
9759		"idx": -1,
9760	
9761		/**
9762		 * Cached display value
9763		 */
9764		displayData: null
9765	};
9766	
9767	
9768	/**
9769	 * Template object for the column information object in DataTables. This object
9770	 * is held in the settings aoColumns array and contains all the information that
9771	 * DataTables needs about each individual column.
9772	 *
9773	 * Note that this object is related to {@link DataTable.defaults.column}
9774	 * but this one is the internal data store for DataTables's cache of columns.
9775	 * It should NOT be manipulated outside of DataTables. Any configuration should
9776	 * be done through the initialisation options.
9777	 *  @namespace
9778	 */
9779	DataTable.models.oColumn = {
9780		/**
9781		 * Column index.
9782		 */
9783		"idx": null,
9784	
9785		/**
9786		 * A list of the columns that sorting should occur on when this column
9787		 * is sorted. That this property is an array allows multi-column s
9787orting
9788		 * to be defined for a column (for example first name / last name columns
9789		 * would benefit from this). The values are integers pointing to the
9790		 * columns to be sorted on (typically it will be a single integer pointing
9791		 * at itself, but that doesn't need to be the case).
9792		 */
9793		"aDataSort": null,
9794	
9795		/**
9796		 * Define the sorting directions that are applied to the column, in sequence
9797		 * as the column is repeatedly sorted upon - i.e. the first value is used
9798		 * as the sorting direction when the column if first sorted (clicked on).
9799		 * Sort it again (click again) and it will move on to the next index.
9800		 * Repeat until loop.
9801		 */
9802		"asSorting": null,
9803	
9804		/**
9805		 * Flag to indicate if the column is searchable, and thus should be included
9806		 * in the filtering or not.
9807		 */
9808		"bSearchable": null,
9809	
9810		/**
9811		 * Flag to indicate if the column is sortable or not.
9812		 */
9813		"bSortable": null,
9814	
9815		/**
9816		 * Flag to indicate if the column is currently visible in the table or not
9817		 */
9818		"bVisible": null,
9819	
9820		/**
9821		 * Store for manual type assignment using the `column.type` option. This
9822		 * is held in store so we can manipulate the column's `sType` property.
9823		 */
9824		"_sManualType": null,
9825	
9826		/**
9827		 * Flag to indicate if HTML5 data attributes should be used as the data
9828		 * source for filtering or sorting. True is either are.
9829		 */
9830		"_bAttrSrc": false,
9831	
9832		/**
9833		 * Developer definable function that is called whenever a cell is created (Ajax source,
9834		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9835		 * allowing you to modify the DOM element (add background colour for example) when the
9836		 * element is available.
9837		 */
9838		"fnCreatedCell": null,
9839	
9840		/**
9841		 * Function to get data from a cell in a column. You should <b>never</b>
9842		 * access data directly through _aData internally in DataTables - always use
9843		 * the method attached to this property. It allows mData to function as
9844		 * required. This function is automatically assigned by the column
9845		 * initialisation method
9846		 */
9847		"fnGetData": null,
9848	
9849		/**
9850		 * Function to set data for a cell in the column. You should <b>never</b>
9851		 * set the data directly to _aData internally in DataTables - always use
9852		 * this method. It allows mData to function as required. This function
9853		 * is automatically assigned by the column initialisation method
9854		 */
9855		"fnSetData": null,
9856	
9857		/**
9858		 * Property to read the value for the cells in the column from the data
9859		 * source array / object. If null, then the default content is used, if a
9860		 * function is given then the return from the function is used.
9861		 */
9862		"mData": null,
9863	
9864		/**
9865		 * Partner property to mData which is used (only when defined) to get
9866		 * the data - i.e. it is basically the same as mData, but without the
9867		 * 'set' option, and also the data fed to it is the result from mData.
9868		 * This is the rendering method to match the data method of mData.
9869		 */
9870		"mRender": null,
9871	
9872		/**
9873		 * The class to apply to all TD elements in the table's TBODY for the column
9874		 */
9875		"sClass": null,
9876	
9877		/**
9878		 * When DataTables calculates the column widths to assign to each column,
9879		 * it finds the longest string in each column and then constructs a
9880		 * temporary table and reads the widths from that. The problem with this
9881		 * is that "mmm" is much wider then "iiii", but the latter is a longer
9882		 * string - thus the calculation can go wrong (doing it properly and putting
9883		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9884		 * a "work around" we provide this option. It will append its value to the
9885		 * text that is found to be the longest string for the column - i.e. padding.
9886		 */
9887		"sContentPadding": null,
9888	
9889		/**
9890		 * Allows a default value to be given for a column's data, and will be used
9891		 * whenever a null data source is encountered (this can be because mData
9892		 * is set to null, or because the data source itself is null).
9893		 */
9894		"sDefaultContent": null,
9895	
9896		/**
9897		 * Name for the column, allowing reference to the column by name as well as
9898		 * by index (needs a lookup to work by name).
9899		 */
9900		"sName": null,
9901	
9902		/**
9903		 * Custom sorting data type - defines which of the available plug-ins in
9904		 * afnSortData the custom sorting will use - if any is defined.
9905		 */
9906		"sSortDataType": 'std',
9907	
9908		/**
9909		 * Class to be applied to the header element when sorting on this column
9910		 */
9911		"sSortingClass": null,
9912	
9913		/**
9914		 * Title of the column - what is seen in the TH element (nTh).
9915		 */
9916		"sTitle": null,
9917	
9918		/**
9919		 * Column sorting and filtering type
9920		 */
9921		"sType": null,
9922	
9923		/**
9924		 * Width of the column
9925		 */
9926		"sWidth": null,
9927	
9928		/**
9929		 * Width of the column when it was first "encountered"
9930		 */
9931		"sWidthOrig": null,
9932	
9933		/** Cached string which is the longest in the column */
9934		maxLenString: null,
9935	
9936		/**
9937		 * Store for named searches
9938		 */
9939		searchFixed: null
9940	};
9941	
9942	
9943	/*
9944	 * Developer note: The properties of the object below are given in Hungarian
9945	 * notation, that was used as the interface for DataTables prior to v1.10, however
9946	 * from v1.10 onwards the primary interface is camel case. In order to avoid
9947	 * breaking backwards compatibility utterly with this change, the Hungarian
9948	 * version is still, internally the primary interface, but is is not documented
9949	 * - hence the @name tags in each doc comment. This allows a Javascript function
9950	 * to create a map from Hungarian notation to camel case (going the other direction
9951	 * would require each property to be listed, which would add around 3K to the size
9952	 * of DataTables, while this method is about a 0.5K hit).
9953	 *
9954	 * Ultimately this does pave the way for Hungarian notation to be dropped
9955	 * completely, but that is a massive amount of work and will break current
9956	 * installs (therefore is on-hold until v2).
9957	 */
9958	
9959	/**
9960	 * Initialisation options that can be given to DataTables at initialisation
9961	 * time.
9962	 *  @namespace
9963	 */
9964	DataTable.defaults = {
9965		/**
9966		 * An array of data to use for the table, passed in at initialisation which
9967		 * will be used in preference to any data which is already in the DOM. This is
9968		 * particularly useful for constructing tables purely in Javascript, for
9969		 * example with a custom Ajax call.
9970		 */
9971		"aaData": null,
9972	
9973	
9974		/**
9975		 * If ordering is enabled, then DataTables will perform a first pass sort on
9976		 * initialisation. You can define which column(s) the sort is performed
9977		 * upon, and the sorting direction, with this variable. The `sorting` array
9978		 * should contain an array for each column to be sorted initially containing
9979		 * the column's index and a direction string ('asc' or 'desc').
9980		 */
9981		"aaSorting": [[0,'asc']],
9982	
9983	
9984		/**
9985		 * This parameter is basically identical to the `sorting` parameter, but
9986		 * cannot be overridden by user interaction with the table. What this means
9987		 * is that you could have a column (visible or hidden) which the sorting
9988		 * will always be forced on first - any sorting after that (from the user)
9989		 * will then be performed as required. This can be useful for grouping rows
9990		 * together.
9991		 */
9992		"aaSortingFixed": [],
9993	
9994	
9995		/**
9996		 * DataTables can be instructed to load data to display in the table from a
9997		 * Ajax source. This option defines how that Ajax call is made and where to.
9998		 *
9999		 * The `ajax` property has three different modes of operation, depending on
10000		 * how it is defined. These are:
10001		 *
10002		 * * `string` - Set the URL from where the data should be loaded from.
10003		 * * `object` - Define properties for `jQuery.ajax`.
10004		 * * `function` - Custom data get function
10005		 *
10006		 * `string`
10007		 * --------
10008		 *
10009		 * As a string, the `ajax` property simply defines the URL from which
10010		 * DataTables will load data.
10011		 *
10012		 * `object`
10013		 * --------
10014		 *
10015		 * As an object, the parameters in the object are passed to
10016		 * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
10017		 * of the Ajax request. DataTables has a number of default parameters which
10018		 * you can override using this option. Please refer to the jQuery
10019		 * documentation for a full description of the options available, although
10020		 * the following parameters provide additional options in DataTables or
10021		 * require special consideration:
10022		 *
10023		 * * `data` - As with jQuery, `data` can be provided as an object, but it
10024		 *   can also be used as a function to manipulate the data DataTables sends
10025		 *   to the server. The function takes a single parameter, an object of
10026		 *   parameters with the values that DataTables has readied for sending. An
10027		 *   object may be returned which will be merged into the DataTables
10028		 *   defaults, or you can add the items to the object that was passed in and
10029		 *   not return anything from the function. This supersedes `fnServerParams`
10030		 *   from DataTables 1.9-.
10031		 *
10032		 * * `dataSrc` - By default DataTables will look for the property `data` (or
10033		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
10034		 *   from an Ajax source or for server-side processing - this parameter
10035		 *   allows that property to be changed. You can use Javascript dotted
10036		 *   object notation to get a data source for multiple levels of nesting, or
10037		 *   it my be used as a function. As a function it takes a single parameter,
10038		 *   the JSON returned from the server, which can be manipulated as
10039		 *   required, with the returned value being that used by DataTables as the
10040		 *   data source for the table.
10041		 *
10042		 * * `success` - Should not be overridden it is used internally in
10043		 *   DataTables. To manipulate / transform the data returned by the server
10044		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10045		 *
10046		 * `function`
10047		 * ----------
10048		 *
10049		 * As a function, making the Ajax call is left up to yourself allowing
10050		 * complete control of the Ajax request. Indeed, if desired, a method other
10051		 * than Ajax could be used to obtain the required data, such as Web storage
10052		 * or an AIR database.
10053		 *
10054		 * The function is given four parameters and no return is required. The
10055		 * parameters are:
10056		 *
10057		 * 1. _object_ - Data to send to the server
10058		 * 2. _function_ - Callback function that must be executed when the required
10059		 *    data has been obtained. That data should be passed into the callback
10060		 *    as the only parameter
10061		 * 3. _object_ - DataTables settings object for the table
10062		 */
10063		"ajax": null,
10064	
10065	
10066		/**
10067		 * This parameter allows you to readily specify the entries in the length drop
10068		 * down menu that DataTables shows when pagination is enabled. It can be
10069		 * either a 1D array of options which will be used for both the displayed
10070		 * option and the value, or a 2D array which will use the array in the first
10071		 * position as the value, and the array in the second position as the
10072		 * displayed options (useful for language strings such as 'All').
10073		 *
10074		 * Note that the `pageLength` property will be automatically set to the
10075		 * first value given in this array, unless `pageLength` is also provided.
10076		 */
10077		"aLengthMenu": [ 10, 25, 50, 100 ],
10078	
10079	
10080		/**
10081		 * The `columns` option in the initialisation parameter allows you to define
10082		 * details about the way individual columns behave. For a full list of
10083		 * column options that can be set, please see
10084		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10085		 * define your columns, you must have an entry in the array for every single
10086		 * column that you have in your table (these can be null if you don't which
10087		 * to specify any options).
10088		 */
10089		"aoColumns": null,
10090	
10091		/**
10092		 * Very similar to `columns`, `columnDefs` allows you to target a specific
10093		 * column, multiple columns, or all columns, using the `targets` property of
10094		 * each object in the array. This allows great flexibility when creating
10095		 * tables, as the `columnDefs` arrays can be of any length, targeting the
10096		 * columns you specifically want. `columnDefs` may use any of the column
10097		 * options available: {@link DataTable.defaults.column}, but it _must_
10098		 * have `targets` defined in each object in the array. Values in the `targets`
10099		 * array may be:
10100		 *   <ul>
10101		 *     <li>
10101a string - class name will be matched on the TH for the column</li>
10102		 *     <li>0 or a positive integer - column index counting from the left</li>
10103		 *     <li>a negative integer - column index counting from the right</li>
10104		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10105		 *   </ul>
10106		 */
10107		"aoColumnDefs": null,
10108	
10109	
10110		/**
10111		 * Basically the same as `search`, this parameter defines the individual column
10112		 * filtering state at initialisation time. The array must be of the same size
10113		 * as the number of columns, and each element be an object with the parameters
10114		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10115		 * accepted and the default will be used.
10116		 */
10117		"aoSearchCols": [],
10118	
10119	
10120		/**
10121		 * Enable or disable automatic column width calculation. This can be disabled
10122		 * as an optimisation (it takes some time to calculate the widths) if the
10123		 * tables widths are passed in using `columns`.
10124		 */
10125		"bAutoWidth": true,
10126	
10127	
10128		/**
10129		 * Deferred rendering can provide DataTables with a huge speed boost when you
10130		 * are using an Ajax or JS data source for the table. This option, when set to
10131		 * true, will cause DataTables to defer the creation of the table elements for
10132		 * each row until they are needed for a draw - saving a significant amount of
10133		 * time.
10134		 */
10135		"bDeferRender": true,
10136	
10137	
10138		/**
10139		 * Replace a DataTable which matches the given selector and replace it with
10140		 * one which has the properties of the new initialisation object passed. If no
10141		 * table matches the selector, then the new DataTable will be constructed as
10142		 * per normal.
10143		 */
10144		"bDestroy": false,
10145	
10146	
10147		/**
10148		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10149		 * that it allows the end user to input multiple words (space separated) and
10150		 * will match a row containing those words, even if not in the order that was
10151		 * specified (this allow matching across multiple columns). Note that if you
10152		 * wish to use filtering in DataTables this must remain 'true' - to remove the
10153		 * default filtering input box and retain filtering abilities, please use
10154		 * {@link DataTable.defaults.dom}.
10155		 */
10156		"bFilter": true,
10157	
10158		/**
10159		 * Used only for compatiblity with DT1
10160		 * @deprecated
10161		 */
10162		"bInfo": true,
10163	
10164		/**
10165		 * Used only for compatiblity with DT1
10166		 * @deprecated
10167		 */
10168		"bLengthChange": true,
10169	
10170		/**
10171		 * Enable or disable pagination.
10172		 */
10173		"bPaginate": true,
10174	
10175	
10176		/**
10177		 * Enable or disable the display of a 'processing' indicator when the table is
10178		 * being processed (e.g. a sort). This is particularly useful for tables with
10179		 * large amounts of data where it can take a noticeable amount of time to sort
10180		 * the entries.
10181		 */
10182		"bProcessing": false,
10183	
10184	
10185		/**
10186		 * Retrieve the DataTables object for the given selector. Note that if the
10187		 * table has already been initialised, this parameter will cause DataTables
10188		 * to simply return the object that has already been set up - it will not take
10189		 * account of any changes you might have made to the initialisation object
10190		 * passed to DataTables (setting this parameter to true is an acknowledgement
10191		 * that you understand this). `destroy` can be used to reinitialise a table if
10192		 * you need.
10193		 */
10194		"bRetrieve": false,
10195	
10196	
10197		/**
10198		 * When vertical (y) scrolling is enabled, DataTables will force the height of
10199		 * the table's viewport to the given height at all times (useful for layout).
10200		 * However, this can look odd when filtering data down to a small data set,
10201		 * and the footer is left "floating" further down. This parameter (when
10202		 * enabled) will cause DataTables to collapse the table's viewport down when
10203		 * the result set will fit within the given Y height.
10204		 */
10205		"bScrollCollapse": false,
10206	
10207	
10208		/**
10209		 * Configure DataTables to use server-side processing. Note that the
10210		 * `ajax` parameter must also be given in order to give DataTables a
10211		 * source to obtain the required data for each draw.
10212		 */
10213		"bServerSide": false,
10214	
10215	
10216		/**
10217		 * Enable or disable sorting of columns. Sorting of individual columns can be
10218		 * disabled by the `sortable` option for each column.
10219		 */
10220		"bSort": true,
10221	
10222	
10223		/**
10224		 * Enable or display DataTables' ability to sort multiple columns at the
10225		 * same time (activated by shift-click by the user).
10226		 */
10227		"bSortMulti": true,
10228	
10229	
10230		/**
10231		 * Allows control over whether DataTables should use the top (true) unique
10232		 * cell that is found for a single column, or the bottom (false - default).
10233		 * This is useful when using complex headers.
10234		 */
10235		"bSortCellsTop": null,
10236	
10237	
10238		/**
10239		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10240		 * `sorting\_3` to the columns which are currently being sorted on. This is
10241		 * presented as a feature switch as it can increase processing time (while
10242		 * classes are removed and added) so for large data sets you might want to
10243		 * turn this off.
10244		 */
10245		"bSortClasses": true,
10246	
10247	
10248		/**
10249		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10250		 * used to save table display information such as pagination information,
10251		 * display length, filtering and sorting. As such when the end user reloads
10252		 * the page the display display will match what thy had previously set up.
10253		 */
10254		"bStateSave": false,
10255	
10256	
10257		/**
10258		 * This function is called when a TR element is created (and all TD child
10259		 * elements have been inserted), or registered if using a DOM source, allowing
10260		 * manipulation of the TR element (adding classes etc).
10261		 */
10262		"fnCreatedRow": null,
10263	
10264	
10265		/**
10266		 * This function is called on every 'draw' event, and allows you to
10267		 * dynamically modify any aspect you want about the created DOM.
10268		 */
10269		"fnDrawCallback": null,
10270	
10271	
10272		/**
10273		 * Identical to fnHeaderCallback() but for the table footer this function
10274		 * allows you to modify the table footer on every 'draw' event.
10275		 */
10276		"fnFooterCallback": null,
10277	
10278	
10279		/**
10280		 * When rendering large numbers in the information element for the table
10281		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10282		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10283		 * rendered as "1,000,000") to help readability for the end user. This
10284		 * function will override the default method DataTables uses.
10285		 */
10286		"fnFormatNumber": function ( toFormat ) {
10287			return toFormat.toString().replace(
10288				/\B(?=(\d{3})+(?!\d))/g,
10289				this.oLanguage.sThousands
10290			);
10291		},
10292	
10293	
10294		/**
10295		 * This function is called on every 'draw' event, and allows you to
10296		 * dynamically modify the header row. This can be used to calculate and
10297		 * display useful information about the table.
10298		 */
10299		"fnHeaderCallback": null,
10300	
10301	
10302		/**
10303		 * The information element can be used to convey information about the current
10304		 * state of the table. Although the internationalisation options presented by
10305		 * DataTables are quite capable of dealing with most customisations, there may
10306		 * be times where you wish to customise the string further. This callback
10307		 * allows you to do exactly that.
10308		 */
10309		"fnInfoCallback": null,
10310	
10311	
10312		/**
10313		 * Called when the table has been initialised. Normally DataTables will
10314		 * initialise sequentially and there will be no need for this function,
10315		 * however, this does not hold true when using external language information
10316		 * since that is obtained using an async XHR call.
10317		 */
10318		"fnInitComplete": null,
10319	
10320	
10321		/**
10322		 * Called at the very start of each table draw and can be used to cancel the
10323		 * draw by returning false, any other return (including undefined) results in
10324		 * the full draw occurring).
10325		 */
10326		"fnPreDrawCallback": null,
10327	
10328	
10329		/**
10330		 * This function allows you to 'post process' each row after it have been
10331		 * generated for each table draw, but before it is rendered on screen. This
10332		 * function might be used for setting the row class name etc.
10333		 */
10334		"fnRowCallback": null,
10335	
10336	
10337		/**
10338		 * Load the table state. With this function you can define from where, and how, the
10339		 * state of a table is loaded. By default DataTables will load from `localStorage`
10340		 * but you might wish to use a server-side database or cookies.
10341		 */
10342		"fnStateLoadCallback": function ( settings ) {
10343			try {
10344				return JSON.parse(
10345					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10346						'DataTables_'+settings.sInstance+'_'+location.pathname
10347					)
10348				);
10349			} catch (e) {
10350				return {};
10351			}
10352		},
10353	
10354	
10355		/**
10356		 * Callback which allows modification of the saved state prior to loading that state.
10357		 * This callback is called when the table is loading state from the stored data, but
10358		 * prior to the settings object being modified by the saved state. Note that for
10359		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10360		 * a plug-in.
10361		 */
10362		"fnStateLoadParams": null,
10363	
10364	
10365		/**
10366		 * Callback that is called when the state has been loaded from the state saving method
10367		 * and the DataTables settings object has been modified as a result of the loaded state.
10368		 */
10369		"fnStateLoaded": null,
10370	
10371	
10372		/**
10373		 * Save the table state. This function allows you to define where and how the state
10374		 * information for the table is stored By default DataTables will use `localStorage`
10375		 * but you might wish to use a server-side database or cookies.
10376		 */
10377		"fnStateSaveCallback": function ( settings, data ) {
10378			try {
10379				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10380					'DataTables_'+settings.sInstance+'_'+location.pathname,
10381					JSON.stringify( data )
10382				);
10383			} catch (e) {
10384				// noop
10385			}
10386		},
10387	
10388	
10389		/**
10390		 * Callback which allows modification of the state to be saved. Called when the table
10391		 * has changed state a new state save is required. This method allows modification of
10392		 * the state saving object prior to actually doing the save, including addition or
10393		 * other state properties or modification. Note that for plug-in authors, you should
10394		 * use the `stateSaveParams` event to save parameters for a plug-in.
10395		 */
10396		"fnStateSaveParams": null,
10397	
10398	
10399		/**
10400		 * Duration for which the saved state information is considered valid. After this period
10401		 * has elapsed the state will be returned to the default.
10402		 * Value is given in seconds.
10403		 */
10404		"iStateDuration": 7200,
10405	
10406	
10407		/**
10408		 * Number of rows to display on a single page when using pagination. If
10409		 * feature enabled (`lengthChange`) then the end user will be able to override
10410		 * this to a custom setting using a pop-up menu.
10411		 */
10412		"iDisplayLength": 10,
10413	
10414	
10415		/**
10416		 * Define the starting point for data display when using DataTables with
10417		 * pagination. Note that this parameter is the number of records, rather than
10418		 * the page number, so if you have 10 records per page and want to start on
10419		 * the third page, it should be "20".
10420		 */
10421		"iDisplayStart": 0,
10422	
10423	
10424		/**
10425		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10426		 * and filtering) by adding a `tabindex` attribute to the required elements. This
10427		 * allows you to tab through the controls and press the enter key to activate them.
10428		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10429		 * You can overrule this using this parameter if you wish. Use a value of -1 to
10430		 * disable built-in keyboard navigation.
10431		 */
10432		"iTabIndex": 0,
10433	
10434	
10435		/**
10436		 * Classes that DataTables assigns to the various components and features
10437		 * that it adds to the HTML table. This allows classes to be configured
10438		 * during initialisation in addition to through the static
10439		 * {@link DataTable.ext.oStdClasses} object).
10440		 */
10441		"oClasses": {},
10442	
10443	
10444		/**
10445		 * All strings that DataTables uses in the user interface that it creates
10446		 * are defined in this object, allowing you to modified them individually or
10447		 * completely replace them all as required.
10448		 */
10449		"oLanguage": {
10450			/**
10451			 * Strings that are used for WAI-ARIA labels and controls only (these are not
10452			 * actually visible on the page, but will be read by screenreaders, and thus
10453			 * must be internationalised as well).
10454			 */
10455			"oAria": {
10456				/**
10457				 * ARIA label that is added to the table headers when the column may be sorted
10458				 */
10459				"orderable": ": Activate to sort",
10460	
10461				/**
10462				 * ARIA label that is added to the table headers when the column is currently being sorted
10463				 */
10464				"orderableReverse": ": Activate to invert sorting",
10465	
10466				/**
10467				 * ARIA label that is added to the table headers when the column is currently being 
10468				 * sorted and next step is to remove sorting
10469				 */
10470				"orderableRemove": ": Activate to remove sorting",
10471	
10472				paginate: {
10473					first: 'First',
10474					last: 'Last',
10475					next: 'Next',
10476					previous: 'Previous'
10477				}
10478			},
10479	
10480			/**
10481			 * Pagination string used by DataTables for the built-in pagination
10482			 * control types.
10483			 */
10484			"oPaginate": {
10485				/**
10486				 * Label and character for first page button («)
10487				 */
10488				"sFirst": "\u00AB",
10489	
10490				/**
10491				 * Last page button (»)
10492				 */
10493				"sLast": "\u00BB",
10494	
10495				/**
10496				 * Next page button (›)
10497				 */
10498				"sNext": "\u203A",
10499	
10500				/**
10501				 * Previous page button (‹)
10502				 */
10503				"sPrevious": "\u2039",
10504			},
10505	
10506			/**
10507			 * Plural object for the data type the table is showing
10508			 */
10509			entries: {
10510				_: "entries",
10511				1: "entry"
10512			},
10513	
10514			/**
10515			 * This string is shown in preference to `zeroRecords` when the table is
10516			 * empty of data (regardless of filtering). Note that this is an optional
10517			 * parameter - if it is not given, the value of `zeroRecords` will be used
10518			 * instead (either the default or given value).
10519			 */
10520			"sEmptyTable": "No data available in table",
10521	
10522	
10523			/**
10524			 * This string gives information to the end user about the information
10525			 * that is current on display on the page. The following tokens can be
10526			 * used in the string and will be dynamically replaced as the table
10527			 * display updates. This tokens can be placed anywhere in the string, or
10528			 * removed as needed by the language requires:
10529			 *
10530			 * * `\_START\_` - Display index of the first record on the current page
10531			 * * `\_END\_` - Display index of the last record on the current page
10532			 * * `\_TOTAL\_` - Number of records in the table after filtering
10533			 * * `\_MAX\_` - Number of records in the table without filtering
10534			 * * `\_PAGE\_` - Current page number
10535			 * * `\_PAGES\_` - Total number of pages of data in the table
10536			 */
10537			"sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
10538	
10539	
10540			/**
10541			 * Display information string for when the table is empty. Typically the
10542			 * format of this string should match `info`.
10543			 */
10544			"sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
10545	
10546	
10547			/**
10548			 * When a user filters the information in a table, this string is appended
10549			 * to the information (`info`) to give an idea of how strong the filtering
10550			 * is. The variable _MAX_ is dynamically updated.
10551			 */
10552			"sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
10553	
10554	
10555			/**
10556			 * If can be useful to append extra information to the info string at times,
10557			 * and this variable does exactly that. This information will be appended to
10558			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
10559			 * being used) at all times.
10560			 */
10561			"sInfoPostFix": "",
10562	
10563	
10564			/**
10565			 * This decimal place operator is a little different from the other
10566			 * language options since DataTables doesn't output floating point
10567			 * numbers, so it won't ever use this for display of a number. Rather,
10568			 * what this parameter does is modify the sort methods of the table so
10569			 * that numbers which are in a format which has a character other than
10570			 * a period (`.`) as a decimal place will be sorted numerically.
10571			 *
10572			 * Note that numbers with different decimal places cannot be shown in
10573			 * the same table and still be sortable, the table must be consistent.
10574			 * However, multiple different tables on the page can use different
10575			 * decimal place characters.
10576			 */
10577			"sDecimal": "",
10578	
10579	
10580			/**
10581			 * DataTables has a build in number formatter (`formatNumber`) which is
10582			 * used to format large numbers that are used in the table information.
10583			 * By default a comma is used, but this can be trivially changed to any
10584			 * character you wish with this parameter.
10585			 */
10586			"sThousands": ",",
10587	
10588	
10589			/**
10590			 * Detail the action that will be taken when the drop down menu for the
10591			 * pagination length option is changed. The '_MENU_' variable is replaced
10592			 * with a default select list of 10, 25, 50 and 100, and can be replaced
10593			 * with a custom select box if required.
10594			 */
10595			"sLengthMenu": "_MENU_ _ENTRIES_ per page",
10596	
10597	
10598			/**
10599			 * When using Ajax sourced data and during the first draw when DataTables is
10600			 * gathering the data, this message is shown in an empty row in the table to
10601			 * indicate to the end user the the data is being loaded. Note that this
10602			 * parameter is not used when loading data by server-side processing, just
10603			 * Ajax sourced data with client-side processing.
10604			 */
10605			"sLoadingRecords": "Loading...",
10606	
10607	
10608			/**
10609			 * Text which is displayed when the table is processing a user action
10610			 * (usually a sort command or similar).
10611			 */
10612			"sProcessing": "",
10613	
10614	
10615			/**
10616			 * Details the actions that will be taken when the user types into the
10617			 * filtering input text box. The variable "_INPUT_", if used in the string,
10618			 * is replaced with the HTML text box for the filtering input allowing
10619			 * control over where it appears in the string. If "_INPUT_" is not given
10620			 * then the input box is appended to the string automatically.
10621			 */
10622			"sSearch": "Search:",
10623	
10624	
10625			/**
10626			 * Assign a `placeholder` attribute to the search `input` element
10627			 *  @type string
10628			 *  @default 
10629			 *
10630			 *  @dtopt Language
10631			 *  @name DataTable.defaults.language.searchPlaceholder
10632			 */
10633			"sSearchPlaceholder": "",
10634	
10635	
10636			/**
10637			 * All of the language information can be stored in a file on the
10638			 * server-side, which DataTables will look up if this parameter is passed.
10639			 * It must store the URL of the language file, which is in a JSON format,
10640			 * and the object has the same properties as the oLanguage object in the
10641			 * initialiser object (i.e. the above parameters). Please refer to one of
10642			 * the example language files to see how this works in action.
10643			 */
10644			"sUrl": "",
10645	
10646	
10647			/**
10648			 * Text shown inside the table records when the is no information to be
10649			 * displayed after filtering. `emptyTable` is shown when there is simply no
10650			 * information in the table at all (regardless of filtering).
10651			 */
10652			"sZeroRecords": "No matching records found"
10653		},
10654	
10655	
10656		/**
10657		 * This parameter allows you to have define the global filtering state at
10658		 * initialisation time. As an object the `search` parameter must be
10659		 * defined, but all other parameters are optional. When `regex` is true,
10660		 * the search string will be treated as a regular expression, when false
10661		 * (default) it will be treated as a straight string. When `smart`
10662		 * DataTables will use it's smart filtering methods (to word match at
10663		 * any point in the data), when false this will not be done.
10664		 */
10665		"oSearch": $.extend( {}, DataTable.models.oSearch ),
10666	
10667	
10668		/**
10669		 * Table and control layout. This replaces the legacy `dom` option.
10670		 */
10671		layout: {
10672			topStart: 'pageLength',
10673			topEnd: 'search',
10674			bottomStart: 'info',
10675			bottomEnd: 'paging'
10676		},
10677	
10678	
10679		/**
10680		 * Legacy DOM layout option
10681		 */
10682		"sDom": null,
10683	
10684	
10685		/**
10686		 * Search delay option. This will throttle full table searches that use the
10687		 * DataTables provided search input element (it does not effect calls to
10688		 * `dt-api search()`, providing a delay before the search is made.
10689		 */
10690		"searchDelay": null,
10691	
10692	
10693		/**
10694		 * DataTables features six different built-in options for the buttons to
10695		 * display for pagination control:
10696		 *
10697		 * * `numbers` - Page number buttons only
10698		 * * `simple` - 'Previous' and 'Next' buttons only
10699		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
10700		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
10701		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
10702		 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
10703		 */
10704		"sPaginationType": "full_numbers",
10705	
10706	
10707		/**
10708		 * Enable horizontal scrolling. When a table is too wide to fit into a
10709		 * certain layout, or you have a large number of columns in the table, you
10710		 * can enable x-scrolling to show the table in a viewport, which can be
10711		 * scrolled. This property can be `true` which will allow the table to
10712		 * scroll horizontally when needed, or any CSS unit, or a number (in which
10713		 * case it will be treated as a pixel measurement). Setting as simply `true`
10714		 * is recommended.
10715		 */
10716		"sScrollX": "",
10717	
10718	
10719		/**
10720		 * This property can be used to force a DataTable to use more width than it
10721		 * might otherwise do when x-scrolling is enabled. For example if you have a
10722		 * table which requires to be well spaced, this parameter is useful for
10723		 * "over-sizing" the table, and thus forcing scrolling. This property can by
10724		 * any CSS unit, or a number (in which case it will be treated as a pixel
10725		 * measurement).
10726		 */
10727		"sScrollXInner": "",
10728	
10729	
10730		/**
10731		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
10732		 * to the given height, and enable scrolling for any data which overflows the
10733		 * current viewport. This can be used as an alternative to paging to display
10734		 * a lot of data in a small area (although paging and scrolling can both be
10735		 * enabled at the same time). This property can be any CSS unit, or a number
10736		 * (in which case it will be treated as a pixel measurement).
10737		 */
10738		"sScrollY": "",
10739	
10740	
10741		/**
10742		 * __Deprecated__ The functionality provided by this parameter has now been
10743		 * superseded by that provided through `ajax`, which should be used instead.
10744		 *
10745		 * Set the HTTP method that is used to make the Ajax call for server-side
10746		 * processing or Ajax sourced data.
10747		 */
10748		"sServerMethod": "GET",
10749	
10750	
10751		/**
10752		 * DataTables makes use of renderers when displaying HTML elements for
10753		 * a table. These renderers can be added or modified by plug-ins to
10754		 * generate suitable mark-up for a site. For example the Bootstrap
10755		 * integration plug-in for DataTables uses a paging button renderer to
10756		 * display pagination buttons in the mark-up required by Bootstrap.
10757		 *
10758		 * For further information about the renderers available see
10759		 * DataTable.ext.renderer
10760		 */
10761		"renderer": null,
10762	
10763	
10764		/**
10765		 * Set the data property name that DataTables should use to get a row's id
10766		 * to set as the `id` property in the node.
10767		 */
10768		"rowId": "DT_RowId",
10769	
10770	
10771		/**
10772		 * Caption value
10773		 */
10774		"caption": null
10775	};
10776	
10777	_fnHungarianMap( DataTable.defaults );
10778	
10779	
10780	
10781	/*
10782	 * Developer note - See note in model.defaults.js about the use of Hungarian
10783	 * notation and camel case.
10784	 */
10785	
10786	/**
10787	 * Column options that can be given to DataTables at initialisation time.
10788	 *  @namespace
10789	 */
10790	DataTable.defaults.column = {
10791		/**
10792		 * Define which column(s) an order will occur on for this column. This
10793		 * allows a column's ordering to take multiple columns into account when
10794		 * doing a sort or use the data from a different column. For example first
10795		 * name / last name columns make sense to do a multi-column sort over the
10796		 * two columns.
10797		 */
10798		"aDataSort": null,
10799		"iDataSort": -1,
10800	
10801		ariaTitle: '',
10802	
10803	
10804		/**
10805		 * You can control the default ordering direction, and even alter the
10806		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
10807		 * using this parameter.
10808		 */
10809		"asSorting": [ 'asc', 'desc', '' ],
10810	
10811	
10812		/**
10813		 * Enable or disable filtering on the data in this column.
10814		 */
10815		"bSearchable": true,
10816	
10817	
10818		/**
10819		 * Enable or disable ordering on this column.
10820		 */
10821		"bSortable": true,
10822	
10823	
10824		/**
10825		 * Enable or disable the display of this column.
10826		 */
10827		"bVisible": true,
10828	
10829	
10830		/**
10831		 * Developer definable function that is called whenever a cell is created (Ajax source,
10832		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
10833		 * allowing you to modify the DOM element (add background colour for example) when the
10834		 * element is available.
10835		 */
10836		"fnCreatedCell": null,
10837	
10838	
10839		/**
10840		 * This property can be used to read data from any data source property,
10841		 * including deeply nested objects / properties. `data` can be given in a
10842		 * number of different ways which effect its behaviour:
10843		 *
10844		 * * `integer` - treated as an array index for the data source. This is the
10845		 *   default that DataTables uses (incrementally increased for each column).
10846		 * * `string` - read an object property from the data source. There are
10847		 *   three 'special' options that can be used in the string to alter how
10848		 *   DataTables reads the data from the source object:
10849		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
10850		 *      Javascript to read from nested objects, so to can the options
10851		 *      specified in `data`. For example: `browser.version` or
10852		 *      `browser.name`. If your object parameter name contains a period, use
10853		 *      `\\` to escape it - i.e. `first\\.name`.
10854		 *    * `[]` - Array notation. DataTables can automatically combine data
10855		 *      from and array source, joining the data with the characters provided
10856		 *      between the two brackets. For example: `name[, ]` would provide a
10857		 *      comma-space separated list from the source array. If no characters
10858		 *      are provided between the brackets, the original array source is
10859		 *      returned.
10860		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
10861		 *      execute a function of the name given. For example: `browser()` for a
10862		 *      simple function on the data source, `browser.version()` for a
10863		 *      function in a nested property or even `browser().version` to get an
10864		 *      object property if the function called returns an object. Note that
10865		 *      function notation is recommended for use in `render` rather than
10866		 *      `data` as it is much simpler to use as a renderer.
10867		 * * `null` - use the original data source for the row rather than plucking
10868		 *   data directly from it. This action has effects on two other
10869		 *   initialisation options:
10870		 *    * `defaultContent` - When null is given as the `data` option and
10871		 *      `defaultContent` is specified for the column, the value defined by
10872		 *      `defaultContent` will be used for the cell.
10873		 *    * `render` - When null is used for the `data` option and the `render`
10874		 *      option is specified for the column, the whole data source for the
10875		 *      row is used for the renderer.
10876		 * * `function` - the function given will be executed whenever DataTables
10877		 *   needs to set or get the data for a cell in the column. The function
10878		 *   takes three parameters:
10879		 *    * Parameters:
10880		 *      * `{array|object}` The data source for the row
10881		 *      * `{string}` The type call data requested - this will be 'set' when
10882		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
10883		 *        when gathering data. Note that when `undefined` is given for the
10884		 *        type DataTables expects to get the raw data for the object back<
10885		 *      * `{*}` Data to set when the second parameter is 'set'.
10886		 *    * Return:
10887		 *      * The return value from the function is not required when '
10887set' is
10888		 *        the type of call, but otherwise the return is what will be used
10889		 *        for the data requested.
10890		 *
10891		 * Note that `data` is a getter and setter option. If you just require
10892		 * formatting of data for output, you will likely want to use `render` which
10893		 * is simply a getter and thus simpler to use.
10894		 *
10895		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
10896		 * name change reflects the flexibility of this property and is consistent
10897		 * with the naming of mRender. If 'mDataProp' is given, then it will still
10898		 * be used by DataTables, as it automatically maps the old name to the new
10899		 * if required.
10900		 */
10901		"mData": null,
10902	
10903	
10904		/**
10905		 * This property is the rendering partner to `data` and it is suggested that
10906		 * when you want to manipulate data for display (including filtering,
10907		 * sorting etc) without altering the underlying data for the table, use this
10908		 * property. `render` can be considered to be the the read only companion to
10909		 * `data` which is read / write (then as such more complex). Like `data`
10910		 * this option can be given in a number of different ways to effect its
10911		 * behaviour:
10912		 *
10913		 * * `integer` - treated as an array index for the data source. This is the
10914		 *   default that DataTables uses (incrementally increased for each column).
10915		 * * `string` - read an object property from the data source. There are
10916		 *   three 'special' options that can be used in the string to alter how
10917		 *   DataTables reads the data from the source object:
10918		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
10919		 *      Javascript to read from nested objects, so to can the options
10920		 *      specified in `data`. For example: `browser.version` or
10921		 *      `browser.name`. If your object parameter name contains a period, use
10922		 *      `\\` to escape it - i.e. `first\\.name`.
10923		 *    * `[]` - Array notation. DataTables can automatically combine data
10924		 *      from and array source, joining the data with the characters provided
10925		 *      between the two brackets. For example: `name[, ]` would provide a
10926		 *      comma-space separated list from the source array. If no characters
10927		 *      are provided between the brackets, the original array source is
10928		 *      returned.
10929		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
10930		 *      execute a function of the name given. For example: `browser()` for a
10931		 *      simple function on the data source, `browser.version()` for a
10932		 *      function in a nested property or even `browser().version` to get an
10933		 *      object property if the function called returns an object.
10934		 * * `object` - use different data for the different data types requested by
10935		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
10936		 *   of the object is the data type the property refers to and the value can
10937		 *   defined using an integer, string or function using the same rules as
10938		 *   `render` normally does. Note that an `_` option _must_ be specified.
10939		 *   This is the default value to use if you haven't specified a value for
10940		 *   the data type requested by DataTables.
10941		 * * `function` - the function given will be executed whenever DataTables
10942		 *   needs to set or get the data for a cell in the column. The function
10943		 *   takes three parameters:
10944		 *    * Parameters:
10945		 *      * {array|object} The data source for the row (based on `data`)
10946		 *      * {string} The type call data requested - this will be 'filter',
10947		 *        'display', 'type' or 'sort'.
10948		 *      * {array|object} The full data source for the row (not based on
10949		 *        `data`)
10950		 *    * Return:
10951		 *      * The return value from the function is what will be used for the
10952		 *        data requested.
10953		 */
10954		"mRender": null,
10955	
10956	
10957		/**
10958		 * Change the cell type created for the column - either TD cells or TH cells. This
10959		 * can be useful as TH cells have semantic meaning in the table body, allowing them
10960		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
10961		 */
10962		"sCellType": "td",
10963	
10964	
10965		/**
10966		 * Class to give to each cell in this column.
10967		 */
10968		"sClass": "",
10969	
10970		/**
10971		 * When DataTables calculates the column widths to assign to each column,
10972		 * it finds the longest string in each column and then constructs a
10973		 * temporary table and reads the widths from that. The problem with this
10974		 * is that "mmm" is much wider then "iiii", but the latter is a longer
10975		 * string - thus the calculation can go wrong (doing it properly and putting
10976		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
10977		 * a "work around" we provide this option. It will append its value to the
10978		 * text that is found to be the longest string for the column - i.e. padding.
10979		 * Generally you shouldn't need this!
10980		 */
10981		"sContentPadding": "",
10982	
10983	
10984		/**
10985		 * Allows a default value to be given for a column's data, and will be used
10986		 * whenever a null data source is encountered (this can be because `data`
10987		 * is set to null, or because the data source itself is null).
10988		 */
10989		"sDefaultContent": null,
10990	
10991	
10992		/**
10993		 * This parameter is only used in DataTables' server-side processing. It can
10994		 * be exceptionally useful to know what columns are being displayed on the
10995		 * client side, and to map these to database fields. When defined, the names
10996		 * also allow DataTables to reorder information from the server if it comes
10997		 * back in an unexpected order (i.e. if you switch your columns around on the
10998		 * client-side, your server-side code does not also need updating).
10999		 */
11000		"sName": "",
11001	
11002	
11003		/**
11004		 * Defines a data source type for the ordering which can be used to read
11005		 * real-time information from the table (updating the internally cached
11006		 * version) prior to ordering. This allows ordering to occur on user
11007		 * editable elements such as form inputs.
11008		 */
11009		"sSortDataType": "std",
11010	
11011	
11012		/**
11013		 * The title of this column.
11014		 */
11015		"sTitle": null,
11016	
11017	
11018		/**
11019		 * The type allows you to specify how the data for this column will be
11020		 * ordered. Four types (string, numeric, date and html (which will strip
11021		 * HTML tags before ordering)) are currently available. Note that only date
11022		 * formats understood by Javascript's Date() object will be accepted as type
11023		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
11024		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
11025		 * through plug-ins.
11026		 */
11027		"sType": null,
11028	
11029	
11030		/**
11031		 * Defining the width of the column, this parameter may take any CSS value
11032		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
11033		 * been given a specific width through this interface ensuring that the table
11034		 * remains readable.
11035		 */
11036		"sWidth": null
11037	};
11038	
11039	_fnHungarianMap( DataTable.defaults.column );
11040	
11041	
11042	
11043	/**
11044	 * DataTables settings object - this holds all the information needed for a
11045	 * given table, including configuration, data and current application of the
11046	 * table options. DataTables does not have a single instance for each DataTable
11047	 * with the settings attached to that instance, but rather instances of the
11048	 * DataTable "class" are created on-the-fly as needed (typically by a
11049	 * $().dataTable() call) and the settings object is then applied to that
11050	 * instance.
11051	 *
11052	 * Note that this object is related to {@link DataTable.defaults} but this
11053	 * one is the internal data store for DataTables's cache of columns. It should
11054	 * NOT be manipulated outside of DataTables. Any configuration should be done
11055	 * through the initialisation options.
11056	 */
11057	DataTable.models.oSettings = {
11058		/**
11059		 * Primary features of DataTables and their enablement state.
11060		 */
11061		"oFeatures": {
11062	
11063			/**
11064			 * Flag to say if DataTables should automatically try to calculate the
11065			 * optimum table and columns widths (true) or not (false).
11066			 * Note that this parameter will be set by the initialisation routine. To
11067			 * set a default use {@link DataTable.defaults}.
11068			 */
11069			"bAutoWidth": null,
11070	
11071			/**
11072			 * Delay the creation of TR and TD elements until they are actually
11073			 * needed by a driven page draw. This can give a significant speed
11074			 * increase for Ajax source and Javascript source data, but makes no
11075			 * difference at all for DOM and server-side processing tables.
11076			 * Note that this parameter will be set by the initialisation routine. To
11077			 * set a default use {@link DataTable.defaults}.
11078			 */
11079			"bDeferRender": null,
11080	
11081			/**
11082			 * Enable filtering on the table or not. Note that if this is disabled
11083			 * then there is no filtering at all on the table, including fnFilter.
11084			 * To just remove the filtering input use sDom and remove the 'f' option.
11085			 * Note that this parameter will be set by the initialisation routine. To
11086			 * set a default use {@link DataTable.defaults}.
11087			 */
11088			"bFilter": null,
11089	
11090			/**
11091			 * Used only for compatiblity with DT1
11092			 * @deprecated
11093			 */
11094			"bInfo": true,
11095	
11096			/**
11097			 * Used only for compatiblity with DT1
11098			 * @deprecated
11099			 */
11100			"bLengthChange": true,
11101	
11102			/**
11103			 * Pagination enabled or not. Note that if this is disabled then length
11104			 * changing must also be disabled.
11105			 * Note that this parameter will be set by the initialisation routine. To
11106			 * set a default use {@link DataTable.defaults}.
11107			 */
11108			"bPaginate": null,
11109	
11110			/**
11111			 * Processing indicator enable flag whenever DataTables is enacting a
11112			 * user request - typically an Ajax request for server-side processing.
11113			 * Note that this parameter will be set by the initialisation routine. To
11114			 * set a default use {@link DataTable.defaults}.
11115			 */
11116			"bProcessing": null,
11117	
11118			/**
11119			 * Server-side processing enabled flag - when enabled DataTables will
11120			 * get all data from the server for every draw - there is no filtering,
11121			 * sorting or paging done on the client-side.
11122			 * Note that this parameter will be set by the initialisation routine. To
11123			 * set a default use {@link DataTable.defaults}.
11124			 */
11125			"bServerSide": null,
11126	
11127			/**
11128			 * Sorting enablement flag.
11129			 * Note that this parameter will be set by the initialisation routine. To
11130			 * set a default use {@link DataTable.defaults}.
11131			 */
11132			"bSort": null,
11133	
11134			/**
11135			 * Multi-column sorting
11136			 * Note that this parameter will be set by the initialisation routine. To
11137			 * set a default use {@link DataTable.defaults}.
11138			 */
11139			"bSortMulti": null,
11140	
11141			/**
11142			 * Apply a class to the columns which are being sorted to provide a
11143			 * visual highlight or not. This can slow things down when enabled since
11144			 * there is a lot of DOM interaction.
11145			 * Note that this parameter will be set by the initialisation routine. To
11146			 * set a default use {@link DataTable.defaults}.
11147			 */
11148			"bSortClasses": null,
11149	
11150			/**
11151			 * State saving enablement flag.
11152			 * Note that this parameter will be set by the initialisation routine. To
11153			 * set a default use {@link DataTable.defaults}.
11154			 */
11155			"bStateSave": null
11156		},
11157	
11158	
11159		/**
11160		 * Scrolling settings for a table.
11161		 */
11162		"oScroll": {
11163			/**
11164			 * When the table is shorter in height than sScrollY, collapse the
11165			 * table container down to the height of the table (when true).
11166			 * Note that this parameter will be set by the initialisation routine. To
11167			 * set a default use {@link DataTable.defaults}.
11168			 */
11169			"bCollapse": null,
11170	
11171			/**
11172			 * Width of the scrollbar for the web-browser's platform. Calculated
11173			 * during table initialisation.
11174			 */
11175			"iBarWidth": 0,
11176	
11177			/**
11178			 * Viewport width for horizontal scrolling. Horizontal scrolling is
11179			 * disabled if an empty string.
11180			 * Note that this parameter will be set by the initialisation routine. To
11181			 * set a default use {@link DataTable.defaults}.
11182			 */
11183			"sX": null,
11184	
11185			/**
11186			 * Width to expand the table to when using x-scrolling. Typically you
11187			 * should not need to use this.
11188			 * Note that this parameter will be set by the initialisation routine. To
11189			 * set a default use {@link DataTable.defaults}.
11190			 *  @deprecated
11191			 */
11192			"sXInner": null,
11193	
11194			/**
11195			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
11196			 * if an empty string.
11197			 * Note that this parameter will be set by the initialisation routine. To
11198			 * set a default use {@link DataTable.defaults}.
11199			 */
11200			"sY": null
11201		},
11202	
11203		/**
11204		 * Language information for the table.
11205		 */
11206		"oLanguage": {
11207			/**
11208			 * Information callback function. See
11209			 * {@link DataTable.defaults.fnInfoCallback}
11210			 */
11211			"fnInfoCallback": null
11212		},
11213	
11214		/**
11215		 * Browser support parameters
11216		 */
11217		"oBrowser": {
11218			/**
11219			 * Determine if the vertical scrollbar is on the right or left of the
11220			 * scrolling container - needed for rtl language layout, although not
11221			 * all browsers move the scrollbar (Safari).
11222			 */
11223			"bScrollbarLeft": false,
11224	
11225			/**
11226			 * Browser scrollbar width
11227			 */
11228			"barWidth": 0
11229		},
11230	
11231	
11232		"ajax": null,
11233	
11234	
11235		/**
11236		 * Array referencing the nodes which are used for the features. The
11237		 * parameters of this object match what is allowed by sDom - i.e.
11238		 *   <ul>
11239		 *     <li>'l' - Length changing</li>
11240		 *     <li>'f' - Filtering input</li>
11241		 *     <li>'t' - The table!</li>
11242		 *     <li>'i' - Information</li>
11243		 *     <li>'p' - Pagination</li>
11244		 *     <li>'r' - pRocessing</li>
11245		 *   </ul>
11246		 */
11247		"aanFeatures": [],
11248	
11249		/**
11250		 * Store data information - see {@link DataTable.models.oRow} for detailed
11251		 * information.
11252		 */
11253		"aoData": [],
11254	
11255		/**
11256		 * Array of indexes which are in the current display (after filtering etc)
11257		 */
11258		"aiDisplay": [],
11259	
11260		/**
11261		 * Array of indexes for display - no filtering
11262		 */
11263		"aiDisplayMaster": [],
11264	
11265		/**
11266		 * Map of row ids to data indexes
11267		 */
11268		"aIds": {},
11269	
11270		/**
11271		 * Store information about each column that is in use
11272		 */
11273		"aoColumns": [],
11274	
11275		/**
11276		 * Store information about the table's header
11277		 */
11278		"aoHeader": [],
11279	
11280		/**
11281		 * Store information about the table's footer
11282		 */
11283		"aoFooter": [],
11284	
11285		/**
11286		 * Store the applied global search information in case we want to force a
11287		 * research or compare the old search to a new one.
11288		 * Note that this parameter will be set by the initialisation routine. To
11289		 * set a default use {@link DataTable.defaults}.
11290		 */
11291		"oPreviousSearch": {},
11292	
11293		/**
11294		 * Store for named searches
11295		 */
11296		searchFixed: {},
11297	
11298		/**
11299		 * Store the applied search for each column - see
11300		 * {@link DataTable.models.oSearch} for the format that is used for the
11301		 * filtering information for each column.
11302		 */
11303		"aoPreSearchCols": [],
11304	
11305		/**
11306		 * Sorting that is applied to the table. Note that the inner arrays are
11307		 * used in the following manner:
11308		 * <ul>
11309		 *   <li>Index 0 - column number</li>
11310		 *   <li>Index 1 - current sorting direction</li>
11311		 * </ul>
11312		 * Note that this parameter will be set by the initialisation routine. To
11313		 * set a default use {@link DataTable.defaults}.
11314		 */
11315		"aaSorting": null,
11316	
11317		/**
11318		 * Sorting that is always applied to the table (i.e. prefixed in front of
11319		 * aaSorting).
11320		 * Note that this parameter will be set by the initialisation routine. To
11321		 * set a default use {@link DataTable.defaults}.
11322		 */
11323		"aaSortingFixed": [],
11324	
11325		/**
11326		 * If restoring a table - we should restore its width
11327		 */
11328		"sDestroyWidth": 0,
11329	
11330		/**
11331		 * Callback functions array for every time a row is inserted (i.e. on a draw).
11332		 */
11333		"aoRowCallback": [],
11334	
11335		/**
11336		 * Callback functions for the header on each draw.
11337		 */
11338		"aoHeaderCallback": [],
11339	
11340		/**
11341		 * Callback function for the footer on each draw.
11342		 */
11343		"aoFooterCallback": [],
11344	
11345		/**
11346		 * Array of callback functions for draw callback functions
11347		 */
11348		"aoDrawCallback": [],
11349	
11350		/**
11351		 * Array of callback functions for row created function
11352		 */
11353		"aoRowCreatedCallback": [],
11354	
11355		/**
11356		 * Callback functions for just before the table is redrawn. A return of
11357		 * false will be used to cancel the draw.
11358		 */
11359		"aoPreDrawCallback": [],
11360	
11361		/**
11362		 * Callback functions for when the table has been initialised.
11363		 */
11364		"aoInitComplete": [],
11365	
11366	
11367		/**
11368		 * Callbacks for modifying the settings to be stored for state saving, prior to
11369		 * saving state.
11370		 */
11371		"aoStateSaveParams": [],
11372	
11373		/**
11374		 * Callbacks for modifying the settings that have been stored for state saving
11375		 * prior to using the stored values to restore the state.
11376		 */
11377		"aoStateLoadParams": [],
11378	
11379		/**
11380		 * Callbacks for operating on the settings object once the saved state has been
11381		 * loaded
11382		 */
11383		"aoStateLoaded": [],
11384	
11385		/**
11386		 * Cache the table ID for quick access
11387		 */
11388		"sTableId": "",
11389	
11390		/**
11391		 * The TABLE node for the main table
11392		 */
11393		"nTable": null,
11394	
11395		/**
11396		 * Permanent ref to the thead element
11397		 */
11398		"nTHead": null,
11399	
11400		/**
11401		 * Permanent ref to the tfoot element - if it exists
11402		 */
11403		"nTFoot": null,
11404	
11405		/**
11406		 * Permanent ref to the tbody element
11407		 */
11408		"nTBody": null,
11409	
11410		/**
11411		 * Cache the wrapper node (contains all DataTables controlled elements)
11412		 */
11413		"nTableWrapper": null,
11414	
11415		/**
11416		 * Indicate if all required information has been read in
11417		 */
11418		"bInitialised": false,
11419	
11420		/**
11421		 * Information about open rows. Each object in the array has the parameters
11422		 * 'nTr' and 'nParent'
11423		 */
11424		"aoOpenRows": [],
11425	
11426		/**
11427		 * Dictate the positioning of DataTables' control elements - see
11428		 * {@link DataTable.model.oInit.sDom}.
11429		 * Note that this parameter will be set by the initialisation routine. To
11430		 * set a default use {@link DataTable.defaults}.
11431		 */
11432		"sDom": null,
11433	
11434		/**
11435		 * Search delay (in mS)
11436		 */
11437		"searchDelay": null,
11438	
11439		/**
11440		 * Which type of pagination should be used.
11441		 * Note that this parameter will be set by the initialisation routine. To
11442		 * set a default use {@link DataTable.defaults}.
11443		 */
11444		"sPaginationType": "two_button",
11445	
11446		/**
11447		 * Number of paging controls on the page. Only used for backwards compatibility
11448		 */
11449		pagingControls: 0,
11450	
11451		/**
11452		 * The state duration (for `stateSave`) in seconds.
11453		 * Note that this parameter will be set by the initialisation routine. To
11454		 * set a default use {@link DataTable.defaults}.
11455		 */
11456		"iStateDuration": 0,
11457	
11458		/**
11459		 * Array of callback functions for state saving. Each array element is an
11460		 * object with the following parameters:
11461		 *   <ul>
11462		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11463		 *       and the JSON string to save that has been thus far created. Returns
11464		 *       a JSON string to be inserted into a json object
11465		 *       (i.e. '"param": [ 0, 1, 2]')</li>
11466		 *     <li>string:sName - name of callback</li>
11467		 *   </ul>
11468		 */
11469		"aoStateSave": [],
11470	
11471		/**
11472		 * Array of callback functions for state loading. Each array element is an
11473		 * object with the following parameters:
11474		 *   <ul>
11475		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11476		 *       and the object stored. May return false to cancel state loading</li>
11477		 *     <li>string:sName - name of callback</li>
11478		 *   </ul>
11479		 */
11480		"aoStateLoad": [],
11481	
11482		/**
11483		 * State that was saved. Useful for back reference
11484		 */
11485		"oSavedState": null,
11486	
11487		/**
11488		 * State that was loaded. Useful for back reference
11489		 */
11490		"oLoadedState": null,
11491	
11492		/**
11493		 * Note if draw should be blocked while getting data
11494		 */
11495		"bAjaxDataGet": true,
11496	
11497		/**
11498		 * The last jQuery XHR object that was used for server-side data gathering.
11499		 * This can be used for working with the XHR information in one of the
11500		 * callbacks
11501		 */
11502		"jqXHR": null,
11503	
11504		/**
11505		 * JSON returned from the server in the last Ajax request
11506		 */
11507		"json": undefined,
11508	
11509		/**
11510		 * Data submitted as part of the last Ajax request
11511		 */
11512		"oAjaxData": undefined,
11513	
11514		/**
11515		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
11516		 * required).
11517		 * Note that this parameter will be set by the initialisation routine. To
11518		 * set a default use {@link DataTable.defaults}.
11519		 */
11520		"sServerMethod": null,
11521	
11522		/**
11523		 * Format numbers for display.
11524		 * Note that this parameter will be set by the initialisation routine. To
11525		 * set a default use {@link DataTable.defaults}.
11526		 */
11527		"fnFormatNumber": null,
11528	
11529		/**
11530		 * List of options that can be used for the user selectable length menu.
11531		 * Note that this parameter will be set by the initialisation routine. To
11532		 * set a default use {@link DataTable.defaults}.
11533		 */
11534		"aLengthMenu": null,
11535	
11536		/**
11537		 * Counter for the draws that the table does. Also used as a tracker for
11538		 * server-side processing
11539		 */
11540		"iDraw": 0,
11541	
11542		/**
11543		 * Indicate if a redraw is being done - useful for Ajax
11544		 */
11545		"bDrawing": false,
11546	
11547		/**
11548		 * Draw index (iDraw) of the last error when parsing the returned data
11549		 */
11550		"iDrawError": -1,
11551	
11552		/**
11553		 * Paging display length
11554		 */
11555		"_iDisplayLength": 10,
11556	
11557		/**
11558		 * Paging start point - aiDisplay index
11559		 */
11560		"_iDisplayStart": 0,
11561	
11562		/**
11563		 * Server-side processing - number of records in the result set
11564		 * (i.e. before filtering), Use fnRecordsTotal rather than
11565		 * this property to get the value of the number of records, regardless of
11566		 * the server-side processing setting.
11567		 */
11568		"_iRecordsTotal": 0,
11569	
11570		/**
11571		 * Server-side processing - number of records in the current display set
11572		 * (i.e. after filtering). Use fnRecordsDisplay rather than
11573		 * this property to get the value of the number of records, regardless of
11574		 * the server-side processing setting.
11575		 */
11576		"_iRecordsDisplay": 0,
11577	
11578		/**
11579		 * The classes to use for the table
11580		 */
11581		"oClasses": {},
11582	
11583		/**
11584		 * Flag attached to the settings object so you can check in the draw
11585		 * callback if filtering has been done in the draw. Deprecated in favour of
11586		 * events.
11587		 *  @deprecated
11588		 */
11589		"bFiltered": false,
11590	
11591		/**
11592		 * Flag attached to the settings object so you can check in the draw
11593		 * callback if sorting has been done in the draw. Deprecated in favour of
11594		 * events.
11595		 *  @deprecated
11596		 */
11597		"bSorted": false,
11598	
11599		/**
11600		 * Indicate that if multiple rows are in the header and there is more than
11601		 * one unique cell per column, if the top one (true) or bottom one (false)
11602		 * should be used for sorting / title by DataTables.
11603		 * Note that this parameter will be set by the initialisation routine. To
11604		 * set a default use {@link DataTable.defaults}.
11605		 */
11606		"bSortCellsTop": null,
11607	
11608		/**
11609		 * Initialisation object that is used for the table
11610		 */
11611		"oInit": null,
11612	
11613		/**
11614		 * Destroy callback functions - for plug-ins to attach themselves to the
11615		 * destroy so they can clean up markup and events.
11616		 */
11617		"aoDestroyCallback": [],
11618	
11619	
11620		/**
11621		 * Get the number of records in the current record set, before filtering
11622		 */
11623		"fnRecordsTotal": function ()
11624		{
11625			return _fnDataSource( this ) == 'ssp' ?
11626				this._iRecordsTotal * 1 :
11627				this.aiDisplayMaster.length;
11628		},
11629	
11630		/**
11631		 * Get the number of records in the current record set, after filtering
11632		 */
11633		"fnRecordsDisplay": function ()
11634		{
11635			return _fnDataSource( this ) == 'ssp' ?
11636				this._iRecordsDisplay * 1 :
11637				this.aiDisplay.length;
11638		},
11639	
11640		/**
11641		 * Get the display end point - aiDisplay index
11642		 */
11643		"fnDisplayEnd": function ()
11644		{
11645			var
11646				len      = this._iDisplayLength,
11647				start    = this._iDisplayStart,
11648				calc     = start + len,
11649				records  = this.aiDisplay.length,
11650				features = this.oFeatures,
11651				paginate = features.bPaginate;
11652	
11653			if ( features.bServerSide ) {
11654				return paginate === false || len === -1 ?
11655					start + records :
11656					Math.min( start+len, this._iRecordsDisplay );
11657			}
11658			else {
11659				return ! paginate || calc>records || len===-1 ?
11660					records :
11661					calc;
11662			}
11663		},
11664	
11665		/**
11666		 * The DataTables object for this table
11667		 */
11668		"oInstance": null,
11669	
11670		/**
11671		 * Unique identifier for each instance of the DataTables object. If there
11672		 * is an ID on the table node, then it takes that value, otherwise an
11673		 * incrementing internal counter is used.
11674		 */
11675		"sInstance": null,
11676	
11677		/**
11678		 * tabindex attribute value that is added to DataTables control elements, allowing
11679		 * keyboard navigation of the table and its controls.
11680		 */
11681		"iTabIndex": 0,
11682	
11683		/**
11684		 * DIV container for the footer scrolling table if scrolling
11685		 */
11686		"nScrollHead": null,
11687	
11688		/**
11689		 * DIV container for the footer scrolling table if scrolling
11690		 */
11691		"nScrollFoot": null,
11692	
11693		/**
11694		 * Last applied sort
11695		 */
11696		"aLastSort": [],
11697	
11698		/**
11699		 * Stored plug-in instances
11700		 */
11701		"oPlugins": {},
11702	
11703		/**
11704		 * Function used to get a row's id from the row's data
11705		 */
11706		"rowIdFn": null,
11707	
11708		/**
11709		 * Data location where to store a row's id
11710		 */
11711		"rowId": null,
11712	
11713		caption: '',
11714	
11715		captionNode: null,
11716	
11717		colgroup: null
11718	};
11719	
11720	/**
11721	 * Extension object for DataTables that is used to provide all extension
11722	 * options.
11723	 *
11724	 * Note that the `DataTable.ext` object is available through
11725	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
11726	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
11727	 *  @namespace
11728	 *  @extends DataTable.models.ext
11729	 */
11730	
11731	
11732	var extPagination = DataTable.ext.pager;
11733	
11734	// Paging buttons configuration
11735	$.extend( extPagination, {
11736		simple: function () {
11737			return [ 'previous', 'next' ];
11738		},
11739	
11740		full: function () {
11741			return [  'first', 'previous', 'next', 'last' ];
11742		},
11743	
11744		numbers: function () {
11745			return [ 'numbers' ];
11746		},
11747	
11748		simple_numbers: function () {
11749			return [ 'previous', 'numbers', 'next' ];
11750		},
11751	
11752		full_numbers: function () {
11753			return [ 'first', 'previous', 'numbers', 'next', 'last' ];
11754		},
11755		
11756		first_last: function () {
11757			return ['first', 'last'];
11758		},
11759		
11760		first_last_numbers: function () {
11761			return ['first', 'numbers', 'last'];
11762		},
11763	
11764		// For testing and plug-ins to use
11765		_numbers: _pagingNumbers,
11766	
11767		// Number of number buttons - legacy, use `numbers` option for paging feature
11768		numbers_length: 7
11769	} );
11770	
11771	
11772	$.extend( true, DataTable.ext.renderer, {
11773		pagingButton: {
11774			_: function (settings, buttonType, content, active, disabled) {
11775				var classes = settings.oClasses.paging;
11776				var btnClasses = [classes.button];
11777				var btn;
11778	
11779				if (active) {
11780					btnClasses.push(classes.active);
11781				}
11782	
11783				if (disabled) {
11784					btnClasses.push(classes.disabled)
11785				}
11786	
11787				if (buttonType === 'ellipsis') {
11788					btn = $('<span class="ellipsis"></span>').html(content)[0];
11789				}
11790				else {
11791					btn = $('<button>', {
11792						class: btnClasses.join(' '),
11793						role: 'link',
11794						type: 'button'
11795					}).html(content);
11796				}
11797	
11798				return {
11799					display: btn,
11800					clicker: btn
11801				}
11802			}
11803		},
11804	
11805		pagingContainer: {
11806			_: function (settings, buttons) {
11807				// No wrapping element - just append directly to the host
11808				return buttons;
11809			}
11810		}
11811	} );
11812	
11813	// Common function to remove new lines, strip HTML and diacritic control
11814	var _filterString = function (stripHtml, normalize) {
11815		return function (str) {
11816			if (_empty(str) || typeof str !== 'string') {
11817				return str;
11818			}
11819	
11820			str = str.replace( _re_new_lines, " " );
11821	
11822			if (stripHtml) {
11823				str = _stripHtml(str);
11824			}
11825	
11826			if (normalize) {
11827				str = _normalize(str, false);
11828			}
11829	
11830			return str;
11831		};
11832	}
11833	
11834	/*
11835	 * Public helper functions. These aren't used internally by DataTables, or
11836	 * called by any of the options passed into DataTables, but they can be used
11837	 * externally by developers working with DataTables. They are helper functions
11838	 * to make working with DataTables a little bit easier.
11839	 */
11840	
11841	function __mldFnName(name) {
11842		return name.replace(/[\W]/g, '_')
11843	}
11844	
11845	// Common logic for moment, luxon or a date action
11846	function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) {
11847		if (window.moment) {
11848			return dt[momentFn]( arg1 );
11849		}
11850		else if (window.luxon) {
11851			return dt[luxonFn]( arg1 );
11852		}
11853		
11854		return dateFn ? dt[dateFn]( arg1 ) : dt;
11855	}
11856	
11857	
11858	var __mlWarning = false;
11859	function __mldObj (d, format, locale) {
11860		var dt;
11861	
11862		if (window.moment) {
11863			dt = window.moment.utc( d, format, locale, true );
11864	
11865			if (! dt.isValid()) {
11866				return null;
11867			}
11868		}
11869		else if (window.luxon) {
11870			dt = format && typeof d === 'string'
11871				? window.luxon.DateTime.fromFormat( d, format )
11872				: window.luxon.DateTime.fromISO( d );
11873	
11874			if (! dt.isValid) {
11875				return null;
11876			}
11877	
11878			dt.setLocale(locale);
11879		}
11880		else if (! format) {
11881			// No format given, must be ISO
11882			dt = new Date(d);
11883		}
11884		else {
11885			if (! __mlWarning) {
11886				alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
11887			}
11888	
11889			__mlWarning = true;
11890		}
11891	
11892		return dt;
11893	}
11894	
11895	// Wrapper for date, datetime and time which all operate the same way with the exception of
11896	// the output string for auto locale support
11897	function __mlHelper (localeString) {
11898		return function ( from, to, locale, def ) {
11899			// Luxon and Moment support
11900			// Argument shifting
11901			if ( arguments.length === 0 ) {
11902				locale = 'en';
11903				to = null;
11903 // means toLocaleString
11904				from = null; // means iso8601
11905			}
11906			else if ( arguments.length === 1 ) {
11907				locale = 'en';
11908				to = from;
11909				from = null;
11910			}
11911			else if ( arguments.length === 2 ) {
11912				locale = to;
11913				to = from;
11914				from = null;
11915			}
11916	
11917			var typeName = 'datetime' + (to ? '-' + __mldFnName(to) : '');
11918	
11919			// Add type detection and sorting specific to this date format - we need to be able to identify
11920			// date type columns as such, rather than as numbers in extensions. Hence the need for this.
11921			if (! DataTable.ext.type.order[typeName]) {
11922				DataTable.type(typeName, {
11923					detect: function (d) {
11924						// The renderer will give the value to type detect as the type!
11925						return d === typeName ? typeName : false;
11926					},
11927					order: {
11928						pre: function (d) {
11929							// The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
11930							// `valueOf` which gives milliseconds epoch
11931							return d.valueOf();
11932						}
11933					},
11934					className: 'dt-right'
11935				});
11936			}
11937		
11938			return function ( d, type ) {
11939				// Allow for a default value
11940				if (d === null || d === undefined) {
11941					if (def === '--now') {
11942						// We treat everything as UTC further down, so no changes are
11943						// made, as such need to get the local date / time as if it were
11944						// UTC
11945						var local = new Date();
11946						d = new Date( Date.UTC(
11947							local.getFullYear(), local.getMonth(), local.getDate(),
11948							local.getHours(), local.getMinutes(), local.getSeconds()
11949						) );
11950					}
11951					else {
11952						d = '';
11953					}
11954				}
11955	
11956				if (type === 'type') {
11957					// Typing uses the type name for fast matching
11958					return typeName;
11959				}
11960	
11961				if (d === '') {
11962					return type !== 'sort'
11963						? ''
11964						: __mldObj('0000-01-01 00:00:00', null, locale);
11965				}
11966	
11967				// Shortcut. If `from` and `to` are the same, we are using the renderer to
11968				// format for ordering, not display - its already in the display format.
11969				if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) {
11970					return d;
11971				}
11972	
11973				var dt = __mldObj(d, from, locale);
11974	
11975				if (dt === null) {
11976					return d;
11977				}
11978	
11979				if (type === 'sort') {
11980					return dt;
11981				}
11982				
11983				var formatted = to === null
11984					? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
11985					: __mld(dt, 'format', 'toFormat', 'toISOString', to);
11986	
11987				// XSS protection
11988				return type === 'display' ?
11989					_escapeHtml( formatted ) :
11990					formatted;
11991			};
11992		}
11993	}
11994	
11995	// Based on locale, determine standard number formatting
11996	// Fallback for legacy browsers is US English
11997	var __thousands = ',';
11998	var __decimal = '.';
11999	
12000	if (window.Intl !== undefined) {
12001		try {
12002			var num = new Intl.NumberFormat().formatToParts(100000.1);
12003		
12004			for (var i=0 ; i<num.length ; i++) {
12005				if (num[i].type === 'group') {
12006					__thousands = num[i].value;
12007				}
12008				else if (num[i].type === 'decimal') {
12009					__decimal = num[i].value;
12010				}
12011			}
12012		}
12013		catch (e) {
12014			// noop
12015		}
12016	}
12017	
12018	// Formatted date time detection - use by declaring the formats you are going to use
12019	DataTable.datetime = function ( format, locale ) {
12020		var typeName = 'datetime-detect-' + __mldFnName(format);
12021	
12022		if (! locale) {
12023			locale = 'en';
12024		}
12025	
12026		if (! DataTable.ext.type.order[typeName]) {
12027			DataTable.type(typeName, {
12028				detect: function (d) {
12029					var dt = __mldObj(d, format, locale);
12030					return d === '' || dt ? typeName : false;
12031				},
12032				order: {
12033					pre: function (d) {
12034						return __mldObj(d, format, locale) || 0;
12035					}
12036				},
12037				className: 'dt-right'
12038			});
12039		}
12040	}
12041	
12042	/**
12043	 * Helpers for `columns.render`.
12044	 *
12045	 * The options defined here can be used with the `columns.render` initialisation
12046	 * option to provide a display renderer. The following functions are defined:
12047	 *
12048	 * * `moment` - Uses the MomentJS library to convert from a given format into another.
12049	 * This renderer has three overloads:
12050	 *   * 1 parameter:
12051	 *     * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
12052	 *   * 2 parameters:
12053	 *     * `string` - Format to convert from
12054	 *     * `string` - Format to convert to. Assumes `en` locale
12055	 *   * 3 parameters:
12056	 *     * `string` - Format to convert from
12057	 *     * `string` - Format to convert to
12058	 *     * `string` - Locale
12059	 * * `number` - Will format numeric data (defined by `columns.data`) for
12060	 *   display, retaining the original unformatted data for sorting and filtering.
12061	 *   It takes 5 parameters:
12062	 *   * `string` - Thousands grouping separator
12063	 *   * `string` - Decimal point indicator
12064	 *   * `integer` - Number of decimal points to show
12065	 *   * `string` (optional) - Prefix.
12066	 *   * `string` (optional) - Postfix (/suffix).
12067	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
12068	 *   parameters.
12069	 *
12070	 * @example
12071	 *   // Column definition using the number renderer
12072	 *   {
12073	 *     data: "salary",
12074	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
12075	 *   }
12076	 *
12077	 * @namespace
12078	 */
12079	DataTable.render = {
12080		date: __mlHelper('toLocaleDateString'),
12081		datetime: __mlHelper('toLocaleString'),
12082		time: __mlHelper('toLocaleTimeString'),
12083		number: function ( thousands, decimal, precision, prefix, postfix ) {
12084			// Auto locale detection
12085			if (thousands === null || thousands === undefined) {
12086				thousands = __thousands;
12087			}
12088	
12089			if (decimal === null || decimal === undefined) {
12090				decimal = __decimal;
12091			}
12092	
12093			return {
12094				display: function ( d ) {
12095					if ( typeof d !== 'number' && typeof d !== 'string' ) {
12096						return d;
12097					}
12098	
12099					if (d === '' || d === null) {
12100						return d;
12101					}
12102	
12103					var negative = d < 0 ? '-' : '';
12104					var flo = parseFloat( d );
12105					var abs = Math.abs(flo);
12106	
12107					// Scientific notation for large and small numbers
12108					if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0) ) {
12109						var exp = flo.toExponential(precision).split(/e\+?/);
12110						return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
12111					}
12112	
12113					// If NaN then there isn't much formatting that we can do - just
12114					// return immediately, escaping any HTML (this was supposed to
12115					// be a number after all)
12116					if ( isNaN( flo ) ) {
12117						return _escapeHtml( d );
12118					}
12119	
12120					flo = flo.toFixed( precision );
12121					d = Math.abs( flo );
12122	
12123					var intPart = parseInt( d, 10 );
12124					var floatPart = precision ?
12125						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
12126						'';
12127	
12128					// If zero, then can't have a negative prefix
12129					if (intPart === 0 && parseFloat(floatPart) === 0) {
12130						negative = '';
12131					}
12132	
12133					return negative + (prefix||'') +
12134						intPart.toString().replace(
12135							/\B(?=(\d{3})+(?!\d))/g, thousands
12136						) +
12137						floatPart +
12138						(postfix||'');
12139				}
12140			};
12141		},
12142	
12143		text: function () {
12144			return {
12145				display: _escapeHtml,
12146				filter: _escapeHtml
12147			};
12148		}
12149	};
12150	
12151	
12152	var _extTypes = DataTable.ext.type;
12153	
12154	// Get / set type
12155	DataTable.type = function (name, prop, val) {
12156		if (! prop) {
12157			return {
12158				className: _extTypes.className[name],
12159				detect: _extTypes.detect.find(function (fn) {
12160					return fn.name === name;
12161				}),
12162				order: {
12163					pre: _extTypes.order[name + '-pre'],
12164					asc: _extTypes.order[name + '-asc'],
12165					desc: _extTypes.order[name + '-desc']
12166				},
12167				render: _extTypes.render[name],
12168				search: _extTypes.search[name]
12169			};
12170		}
12171	
12172		var setProp = function(prop, propVal) {
12173			_extTypes[prop][name] = propVal;
12174		};
12175		var setDetect = function (fn) {
12176			// Wrap to allow the function to return `true` rather than
12177			// specifying the type name.
12178			var cb = function (d, s) {
12179				var ret = fn(d, s);
12180	
12181				return ret === true
12182					? name
12183					: ret;
12184			};
12185			Object.defineProperty(cb, "name", {value: name});
12186	
12187			var idx = _extTypes.detect.findIndex(function (fn) {
12188				return fn.name === name;
12189			});
12190	
12191			if (idx === -1) {
12192				_extTypes.detect.unshift(cb);
12193			}
12194			else {
12195				_extTypes.detect.splice(idx, 1, cb);
12196			}
12197		};
12198		var setOrder = function (obj) {
12199			_extTypes.order[name + '-pre'] = obj.pre; // can be undefined
12200			_extTypes.order[name + '-asc'] = obj.asc; // can be undefined
12201			_extTypes.order[name + '-desc'] = obj.desc; // can be undefined
12202		};
12203	
12204		// prop is optional
12205		if (val === undefined) {
12206			val = prop;
12207			prop = null;
12208		}
12209	
12210		if (prop === 'className') {
12211			setProp('className', val);
12212		}
12213		else if (prop === 'detect') {
12214			setDetect(val);
12215		}
12216		else if (prop === 'order') {
12217			setOrder(val);
12218		}
12219		else if (prop === 'render') {
12220			setProp('render', val);
12221		}
12222		else if (prop === 'search') {
12223			setProp('search', val);
12224		}
12225		else if (! prop) {
12226			if (val.className) {
12227				setProp('className', val.className);
12228			}
12229	
12230			if (val.detect !== undefined) {
12231				setDetect(val.detect);
12232			}
12233	
12234			if (val.order) {
12235				setOrder(val.order);
12236			}
12237	
12238			if (val.render !== undefined) {
12239				setProp('render', val.render);
12240			}
12241	
12242			if (val.search !== undefined) {
12243				setProp('search', val.search);
12244			}
12245		}
12246	}
12247	
12248	// Get a list of types
12249	DataTable.types = function () {
12250		return _extTypes.detect.map(function (fn) {
12251			return fn.name;
12252		});
12253	};
12254	
12255	//
12256	// Built in data types
12257	//
12258	
12259	DataTable.type('string', {
12260		detect: function () {
12261			return 'string';
12262		},
12263		order: {
12264			pre: function ( a ) {
12265				// This is a little complex, but faster than always calling toString,
12266				// http://jsperf.com/tostring-v-check
12267				return _empty(a) ?
12268					'' :
12269					typeof a === 'string' ?
12270						a.toLowerCase() :
12271						! a.toString ?
12272							'' :
12273							a.toString();
12274			}
12275		},
12276		search: _filterString(false, true)
12277	});
12278	
12279	
12280	DataTable.type('html', {
12281		detect: function ( d ) {
12282			return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
12283				'html' : null;
12284		},
12285		order: {
12286			pre: function ( a ) {
12287				return _empty(a) ?
12288					'' :
12289					a.replace ?
12290						_stripHtml(a).trim().toLowerCase() :
12291						a+'';
12292			}
12293		},
12294		search: _filterString(true, true)
12295	});
12296	
12297	
12298	DataTable.type('date', {
12299		className: 'dt-type-date',
12300		detect: function ( d )
12301		{
12302			// V8 tries _very_ hard to make a string passed into `Date.parse()`
12303			// valid, so we need to use a regex to restrict date formats. Use a
12304			// plug-in for anything other than ISO8601 style strings
12305			if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
12306				return null;
12307			}
12308			var parsed = Date.parse(d);
12309			return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
12310		},
12311		order: {
12312			pre: function ( d ) {
12313				var ts = Date.parse( d );
12314				return isNaN(ts) ? -Infinity : ts;
12315			}
12316		}
12317	});
12318	
12319	
12320	DataTable.type('html-num-fmt', {
12321		className: 'dt-type-numeric',
12322		detect: function ( d, settings )
12323		{
12324			var decimal = settings.oLanguage.sDecimal;
12325			return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt' : null;
12326		},
12327		order: {
12328			pre: function ( d, s ) {
12329				var dp = s.oLanguage.sDecimal;
12330				return __numericReplace( d, dp, _re_html, _re_formatted_numeric );
12331			}
12332		},
12333		search: _filterString(true, true)
12334	});
12335	
12336	
12337	DataTable.type('html-num', {
12338		className: 'dt-type-numeric',
12339		detect: function ( d, settings )
12340		{
12341			var decimal = settings.oLanguage.sDecimal;
12342			return _htmlNumeric( d, decimal ) ? 'html-num' : null;
12343		},
12344		order: {
12345			pre: function ( d, s ) {
12346				var dp = s.oLanguage.sDecimal;
12347				return __numericReplace( d, dp, _re_html );
12348			}
12349		},
12350		search: _filterString(true, true)
12351	});
12352	
12353	
12354	DataTable.type('num-fmt', {
12355		className: 'dt-type-numeric',
12356		detect: function ( d, settings )
12357		{
12358			var decimal = settings.oLanguage.sDecimal;
12359			return _isNumber( d, decimal, true ) ? 'num-fmt' : null;
12360		},
12361		order: {
12362			pre: function ( d, s ) {
12363				var dp = s.oLanguage.sDecimal;
12364				return __numericReplace( d, dp, _re_formatted_numeric );
12365			}
12366		}
12367	});
12368	
12369	
12370	DataTable.type('num', {
12371		className: 'dt-type-numeric',
12372		detect: function ( d, settings )
12373		{
12374			var decimal = settings.oLanguage.sDecimal;
12375			return _isNumber( d, decimal ) ? 'num' : null;
12376		},
12377		order: {
12378			pre: function (d, s) {
12379				var dp = s.oLanguage.sDecimal;
12380				return __numericReplace( d, dp );
12381			}
12382		}
12383	});
12384	
12385	
12386	
12387	
12388	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
12389		if ( d !== 0 && (!d || d === '-') ) {
12390			return -Infinity;
12391		}
12392		
12393		var type = typeof d;
12394	
12395		if (type === 'number' || type === 'bigint') {
12396			return d;
12397		}
12398	
12399		// If a decimal place other than `.` is used, it needs to be given to the
12400		// function so we can detect it and replace with a `.` which is the only
12401		// decimal place Javascript recognises - it is not locale aware.
12402		if ( decimalPlace ) {
12403			d = _numToDecimal( d, decimalPlace );
12404		}
12405	
12406		if ( d.replace ) {
12407			if ( re1 ) {
12408				d = d.replace( re1, '' );
12409			}
12410	
12411			if ( re2 ) {
12412				d = d.replace( re2, '' );
12413			}
12414		}
12415	
12416		return d * 1;
12417	};
12418	
12419	
12420	$.extend( true, DataTable.ext.renderer, {
12421		footer: {
12422			_: function ( settings, cell, classes ) {
12423				cell.addClass(classes.tfoot.cell);
12424			}
12425		},
12426	
12427		header: {
12428			_: function ( settings, cell, classes ) {
12429				cell.addClass(classes.thead.cell);
12430	
12431				if (! settings.oFeatures.bSort) {
12432					cell.addClass(classes.order.none);
12433				}
12434	
12435				var legacyTop = settings.bSortCellsTop;
12436				var headerRows = cell.closest('thead').find('tr');
12437				var rowIdx = cell.parent().index();
12438	
12439				// Conditions to not apply the ordering icons
12440				if (
12441					// Cells and rows which have the attribute to disable the icons
12442					cell.attr('data-dt-order') === 'disable' ||
12443					cell.parent().attr('data-dt-order') === 'disable' ||
12444	
12445					// Legacy support for `orderCellsTop`. If it is set, then cells
12446					// which are not in the top or bottom row of the header (depending
12447					// on the value) do not get the sorting classes applied to them
12448					(legacyTop === true && rowIdx !== 0) ||
12449					(legacyTop === false && rowIdx !== headerRows.length - 1)
12450				) {
12451					return;
12452				}
12453	
12454				// No additional mark-up required
12455				// Attach a sort listener to update on sort - note that using the
12456				// `DT` namespace will allow the event to be removed automatically
12457				// on destroy, while the `dt` namespaced event is the one we are
12458				// listening for
12459				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting ) {
12460					if ( settings !== ctx ) { // need to check this this is the host
12461						return;               // table, not a nested one
12462					}
12463	
12464					var orderClasses = classes.order;
12465					var columns = ctx.api.columns( cell );
12466					var col = settings.aoColumns[columns.flatten()[0]];
12467					var orderable = columns.orderable().includes(true);
12468					var ariaType = '';
12469					var indexes = columns.indexes();
12470					var sortDirs = columns.orderable(true).flatten();
12471					var orderedColumns = ',' + sorting.map( function (val) {
12472						return val.col;
12473					} ).join(',') + ',';
12474	
12475					cell
12476						.removeClass(
12477							orderClasses.isAsc +' '+
12478							orderClasses.isDesc
12479						)
12480						.toggleClass( orderClasses.none, ! orderable )
12481						.toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
12482						.toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
12483					
12484					var sortIdx = orderedColumns.indexOf( ',' + indexes.toArray().join(',') + ',' );
12485	
12486					if ( sortIdx !== -1 ) {
12487						// Get the ordering direction for the columns under this cell
12488						// Note that it is possible for a cell to be asc and desc sorting
12489						// (column spanning cells)
12490						var orderDirs = columns.order();
12491	
12492						cell.addClass(
12493							orderDirs.includes('asc') ? orderClasses.isAsc : '' +
12494							orderDirs.includes('desc') ? orderClasses.isDesc : ''
12495						);
12496					}
12497	
12498					// The ARIA spec says that only one column should be marked with aria-sort
12499					if ( sortIdx === 0 ) {
12500						var firstSort = sorting[0];
12501						var sortOrder = col.asSorting;
12502	
12503						cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
12504	
12505						// Determine if the next click will remove sorting or change the sort
12506						ariaType = ! sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
12507					}
12508					else {
12509						cell.removeAttr('aria-sort');
12510					}
12511	
12512					cell.attr('aria-label', orderable
12513						? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
12514						: col.ariaTitle
12515					);
12516	
12517					if (orderable) {
12518						cell.find('.dt-column-title').attr('role', 'button');
12519						cell.attr('tabindex', 0)
12520					}
12521				} );
12522			}
12523		},
12524	
12525		layout: {
12526			_: function ( settings, container, items ) {
12527				var row = $('<div/>')
12528					.addClass('dt-layout-row')
12529					.appendTo( container );
12530	
12531				$.each( items, function (key, val) {
12532					var klass = ! val.table ?
12533						'dt-'+key+' ' :
12534						'';
12535	
12536					if (val.table) {
12537						row.addClass('dt-layout-table');
12538					}
12539	
12540					$('<div/>')
12541						.attr({
12542							id: val.id || null,
12543							"class": 'dt-layout-cell '+klass+(val.className || '')
12544						})
12545						.append( val.contents )
12546						.appendTo( row );
12547				} );
12548			}
12549		}
12550	} );
12551	
12552	
12553	DataTable.feature = {};
12554	
12555	// Third parameter is internal only!
12556	DataTable.feature.register = function ( name, cb, legacy ) {
12557		DataTable.ext.features[ name ] = cb;
12558	
12559		if (legacy) {
12560			_ext.feature.push({
12561				cFeature: legacy,
12562				fnInit: cb
12563			});
12564		}
12565	};
12566	
12567	DataTable.feature.register( 'info', function ( settings, opts ) {
12568		// For compatibility with the legacy `info` top level option
12569		if (! settings.oFeatures.bInfo) {
12570			return null;
12571		}
12572	
12573		var
12574			lang  = settings.oLanguage,
12575			tid = settings.sTableId,
12576			n = $('<div/>', {
12577				'class': settings.oClasses.info.container,
12578			} );
12579	
12580		opts = $.extend({
12581			callback: lang.fnInfoCallback,
12582			empty: lang.sInfoEmpty,
12583			postfix: lang.sInfoPostFix,
12584			search: lang.sInfoFiltered,
12585			text: lang.sInfo,
12586		}, opts);
12587	
12588	
12589		// Update display on each draw
12590		settings.aoDrawCallback.push(function (s) {
12591			_fnUpdateInfo(s, opts, n);
12592		});
12593	
12594		// For the first info display in the table, we add a callback and aria information.
12595		if (! settings._infoEl) {
12596			n.attr({
12597				'aria-live': 'polite',
12598				id: tid+'_info',
12599				role: 'status'
12600			});
12601	
12602			// Table is described by our info div
12603			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
12604	
12605			settings._infoEl = n;
12606		}
12607	
12608		return n;
12609	}, 'i' );
12610	
12611	/**
12612	 * Update the information elements in the display
12613	 *  @param {object} settings dataTables settings object
12614	 *  @memberof DataTable#oApi
12615	 */
12616	function _fnUpdateInfo ( settings, opts, node )
12617	{
12618		var
12619			start = settings._iDisplayStart+1,
12620			end   = settings.fnDisplayEnd(),
12621			max   = settings.fnRecordsTotal(),
12622			total = settings.fnRecordsDisplay(),
12623			out   = total
12624				? opts.text
12625				: opts.empty;
12626	
12627		if ( total !== max ) {
12628			// Record set after filtering
12629			out += ' ' + opts.search;
12630		}
12631	
12632		// Convert the macros
12633		out += opts.postfix;
12634		out = _fnMacros( settings, out );
12635	
12636		if ( opts.callback ) {
12637			out = opts.callback.call( settings.oInstance,
12638				settings, start, end, max, total, out
12639			);
12640		}
12641	
12642		node.html( out );
12643	
12644		_fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
12645	}
12646	
12647	var __searchCounter = 0;
12648	
12649	// opts
12650	// - text
12651	// - placeholder
12652	DataTable.feature.register( 'search', function ( settings, opts ) {
12653		// Don't show the input if filtering isn't available on the table
12654		if (! settings.oFeatures.bFilter) {
12655			return null;
12656		}
12657	
12658		var classes = settings.oClasses.search;
12659		var tableId = settings.sTableId;
12660		var language = settings.oLanguage;
12661		var previousSearch = settings.oPreviousSearch;
12662		var input = '<input type="search" class="'+classes.input+'"/>';
12663	
12664		opts = $.extend({
12665			placeholder: language.sSearchPlaceholder,
12666			text: language.sSearch
12667		}, opts);
12668	
12669		// The _INPUT_ is optional - is appended if not present
12670		if (opts.text.indexOf('_INPUT_') === -1) {
12671			opts.text += '_INPUT_';
12672		}
12673	
12674		opts.text = _fnMacros(settings, opts.text);
12675	
12676		// We can put the <input> outside of the label if it is at the start or end
12677		// which helps improve accessability (not all screen readers like implicit
12678		// for elements).
12679		var end = opts.text.match(/_INPUT_$/);
12680		var start = opts.text.match(/^_INPUT_/);
12681		var removed = opts.text.replace(/_INPUT_/, '');
12682		var str = '<label>' + opts.text + '</label>';
12683	
12684		if (start) {
12685			str = '_INPUT_<label>' + removed + '</label>';
12686		}
12687		else if (end) {
12688			str = '<label>' + removed + '</label>_INPUT_';
12689		}
12690	
12691		var filter = $('<div>')
12692			.addClass(classes.container)
12693			.append(str.replace(/_INPUT_/, input));
12694	
12695		// add for and id to label and input
12696		filter.find('label').attr('for', 'dt-search-' + __searchCounter);
12697		filter.find('input').attr('id', 'dt-search-' + __searchCounter);
12698		__searchCounter++;
12699	
12700		var searchFn = function(event) {
12701			var val = this.value;
12702	
12703			if(previousSearch.return && event.key !== "Enter") {
12704				return;
12705			}
12706	
12707			/* Now do the filter */
12708			if ( val != previousSearch.search ) {
12709				previousSearch.search = val;
12710	
12711				_fnFilterComplete( settings, previousSearch );
12712	
12713				// Need to redraw, without resorting
12714				settings._iDisplayStart = 0;
12715				_fnDraw( settings );
12716			}
12717		};
12718	
12719		var searchDelay = settings.searchDelay !== null ?
12720			settings.searchDelay :
12721			0;
12722	
12723		var jqFilter = $('input', filter)
12724			.val( previousSearch.search )
12725			.attr( 'placeholder', opts.placeholder )
12726			.on(
12727				'keyup.DT search.DT input.DT paste.DT cut.DT',
12728				searchDelay ?
12729					DataTable.util.debounce( searchFn, searchDelay ) :
12730					searchFn
12731			)
12732			.on( 'mouseup.DT', function(e) {
12733				// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
12734				// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
12735				// checks the value to see if it has changed. In other browsers it won't have.
12736				setTimeout( function () {
12737					searchFn.call(jqFilter[0], e);
12738				}, 10);
12739			} )
12740			.on( 'keypress.DT', function(e) {
12741				/* Prevent form submission */
12742				if ( e.keyCode == 13 ) {
12743					return false;
12744				}
12745			} )
12746			.attr('aria-controls', tableId);
12747	
12748		// Update the input elements whenever the table is filtered
12749		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
12750			if ( settings === s && jqFilter[0] !== document.activeElement ) {
12751				jqFilter.val( typeof previousSearch.search !== 'function'
12752					? previousSearch.search
12753					: ''
12754				);
12755			}
12756		} );
12757	
12758		return filter;
12759	}, 'f' );
12760	
12761	// opts
12762	// - type - button configuration
12763	// - buttons - number of buttons to show - must be odd
12764	DataTable.feature.register( 'paging', function ( settings, opts ) {
12765		// Don't show the paging input if the table doesn't have paging enabled
12766		if (! settings.oFeatures.bPaginate) {
12767			return null;
12768		}
12769	
12770		opts = $.extend({
12771			buttons: DataTable.ext.pager.numbers_length,
12772			type: settings.sPaginationType,
12773			boundaryNumbers: true
12774		}, opts);
12775	
12776		// To be removed in 2.1
12777		if (opts.numbers) {
12778			opts.buttons = opts.numbers;
12779		}
12780	
12781		var host = $('<div/>').addClass( settings.oClasses.paging.container + ' paging_' + opts.type );
12782		var draw = function () {
12783			_pagingDraw(settings, host, opts);
12784		};
12785	
12786		settings.aoDrawCallback.push(draw);
12787	
12788		// Responsive redraw of paging control
12789		$(settings.nTable).on('column-sizing.dt.DT', draw);
12790	
12791		return host;
12792	}, 'p' );
12793	
12794	function _pagingDraw(settings, host, opts) {
12795		if (! settings._bInitComplete) {
12796			return;
12797		}
12798	
12799		var
12800			plugin = DataTable.ext.pager[ opts.type ],
12801			aria = settings.oLanguage.oAria.paginate || {},
12802			start      = settings._iDisplayStart,
12803			len        = settings._iDisplayLength,
12804			visRecords = settings.fnRecordsDisplay(),
12805			all        = len === -1,
12806			page = all ? 0 : Math.ceil( start / len ),
12807			pages = all ? 1 : Math.ceil( visRecords / len ),
12808			buttons = plugin()
12809				.map(function (val) {
12810					return val === 'numbers'
12811						? _pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
12812						: val;
12813				})
12814				.flat();
12815	
12816		var buttonEls = [];
12817	
12818		for (var i=0 ; i<buttons.length ; i++) {
12819			var button = buttons[i];
12820	
12821			var btnInfo = _pagingButtonInfo(settings, button, page, pages);
12822			var btn = _fnRenderer( settings, 'pagingButton' )(
12823				settings,
12824				button,
12825				btnInfo.display,
12826				btnInfo.active,
12827				btnInfo.disabled
12828			);
12829	
12830			// Common attributes
12831			$(btn.clicker).attr({
12832				'aria-controls': settings.sTableId,
12833				'aria-disabled': btnInfo.disabled ? 'true' : null,
12834				'aria-current': btnInfo.active ? 'page' : null,
12835				'aria-label': aria[ button ],
12836				'data-dt-idx': button,
12837				'tabIndex': btnInfo.disabled ? -1 : settings.iTabIndex,
12838			});
12839	
12840			if (typeof button !== 'number') {
12841				$(btn.clicker).addClass(button);
12842			}
12843	
12844			_fnBindAction(
12845				btn.clicker, {action: button}, function(e) {
12846					e.preventDefault();
12847	
12848					_fnPageChange( settings, e.data.action, true );
12849				}
12850			);
12851	
12852			buttonEls.push(btn.display);
12853		}
12854	
12855		var wrapped = _fnRenderer(settings, 'pagingContainer')(
12856			settings, buttonEls
12857		);
12858	
12859		var activeEl = host.find(document.activeElement).data('dt-idx');
12860	
12861		host.empty().append(wrapped);
12862	
12863		if ( activeEl !== undefined ) {
12864			host.find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
12865		}
12866	
12867		// Responsive - check if the buttons are over two lines based on the
12868		// height of the buttons and the container.
12869		if (
12870			buttonEls.length && // any buttons
12871			opts.numbers > 1 && // prevent infinite
12872			$(host).height() >= ($(buttonEls[0]).outerHeight() * 2) - 10
12873		) {
12874			_pagingDraw(settings, host, $.extend({}, opts, { numbers: opts.numbers - 2 }));
12875		}
12876	}
12877	
12878	/**
12879	 * Get properties for a button based on the current paging state of the table
12880	 *
12881	 * @param {*} settings DT settings object
12882	 * @param {*} button The button type in question
12883	 * @param {*} page Table's current page
12884	 * @param {*} pages Number of pages
12885	 * @returns Info object
12886	 */
12887	function _pagingButtonInfo(settings, button, page, pages) {
12888		var lang = settings.oLanguage.oPaginate;
12889		var o = {
12890			display: '',
12891			active: false,
12892			disabled: false
12893		};
12894	
12895		switch ( button ) {
12896			case 'ellipsis':
12897				o.display = '&#x2026;';
12898				o.disabled = true;
12899				break;
12900	
12901			case 'first':
12902				o.display = lang.sFirst;
12903	
12904				if (page === 0) {
12905					o.disabled = true;
12906				}
12907				break;
12908	
12909			case 'previous':
12910				o.display = lang.sPrevious;
12911	
12912				if ( page === 0 ) {
12913					o.disabled = true;
12914				}
12915				break;
12916	
12917			case 'next':
12918				o.display = lang.sNext;
12919	
12920				if ( pages === 0 || page === pages-1 ) {
12921					o.disabled = true;
12922				}
12923				break;
12924	
12925			case 'last':
12926				o.display = lang.sLast;
12927	
12928				if ( pages === 0 || page === pages-1 ) {
12929					o.disabled = true;
12930				}
12931				break;
12932	
12933			default:
12934				if ( typeof button === 'number' ) {
12935					o.display = settings.fnFormatNumber( button + 1 );
12936					
12937					if (page === button) {
12938						o.active = true;
12939					}
12940				}
12941				break;
12942		}
12943	
12944		return o;
12945	}
12946	
12947	/**
12948	 * Compute what number buttons to show in the paging control
12949	 *
12950	 * @param {*} page Current page
12951	 * @param {*} pages Total number of pages
12952	 * @param {*} buttons Target number of number buttons
12953	 * @param {boolean} addFirstLast Indicate if page 1 and end should be included
12954	 * @returns Buttons to show
12955	 */
12956	function _pagingNumbers ( page, pages, buttons, addFirstLast ) {
12957		var
12958			numbers = [],
12959			half = Math.floor(buttons / 2),
12960			before = addFirstLast ? 2 : 1,
12961			after = addFirstLast ? 1 : 0;
12962	
12963		if ( pages <= buttons ) {
12964			numbers = _range(0, pages);
12965		}
12966		else if (buttons === 1) {
12967			// Single button - current page only
12968			numbers = [page];
12969		}
12970		else if (buttons === 3) {
12971			// Special logic for just three buttons
12972			if (page <= 1) {
12973				numbers = [0, 1, 'ellipsis'];
12974			}
12975			else if (page >= pages - 2) {
12976				numbers = _range(pages-2, pages);
12977				numbers.unshift('ellipsis');
12978			}
12979			else {
12980				numbers = ['ellipsis', page, 'ellipsis'];
12981			}
12982		}
12983		else if ( page <= half ) {
12984			numbers = _range(0, buttons-before);
12985			numbers.push('ellipsis');
12986	
12987			if (addFirstLast) {
12988				numbers.push(pages-1);
12989			}
12990		}
12991		else if ( page >= pages - 1 - half ) {
12992			numbers = _range(pages-(buttons-before), pages);
12993			numbers.unshift('ellipsis');
12994	
12995			if (addFirstLast) {
12996				numbers.unshift(0);
12997			}
12998		}
12999		else {
13000			numbers = _range(page-half+before, page+half-after);
13001			numbers.push('ellipsis');
13002			numbers.unshift('ellipsis');
13003	
13004			if (addFirstLast) {
13005				numbers.push(pages-1);
13006				numbers.unshift(0);
13007			}
13008		}
13009	
13010		return numbers;
13011	}
13012	
13013	var __lengthCounter = 0;
13014	
13015	// opts
13016	// - menu
13017	// - text
13018	DataTable.feature.register( 'pageLength', function ( settings, opts ) {
13019		var features = settings.oFeatures;
13020	
13021		// For compatibility with the legacy `pageLength` top level option
13022		if (! features.bPaginate || ! features.bLengthChange) {
13023			return null;
13024		}
13025	
13026		opts = $.extend({
13027			menu: settings.aLengthMenu,
13028			text: settings.oLanguage.sLengthMenu
13029		}, opts);
13030	
13031		var
13032			classes  = settings.oClasses.length,
13033			tableId  = settings.sTableId,
13034			menu     = opts.menu,
13035			lengths  = [],
13036			language = [],
13037			i;
13038	
13039		// Options can be given in a number of ways
13040		if (Array.isArray( menu[0] )) {
13041			// Old 1.x style - 2D array
13042			lengths = menu[0];
13043			language = menu[1];
13044		}
13045		else {
13046			for ( i=0 ; i<menu.length ; i++ ) {
13047				// An object with different label and value
13048				if ($.isPlainObject(menu[i])) {
13049					lengths.push(menu[i].value);
13050					language.push(menu[i].label);
13051				}
13052				else {
13053					// Or just a number to display and use
13054					lengths.push(menu[i]);
13055					language.push(menu[i]);
13056				}
13057			}
13058		}
13059	
13060		// We can put the <select> outside of the label if it is at the start or
13061		// end which helps improve accessability (not all screen readers like
13062		// implicit for elements).
13063		var end = opts.text.match(/_MENU_$/);
13064		var start = opts.text.match(/^_MENU_/);
13065		var removed = opts.text.replace(/_MENU_/, '');
13066		var str = '<label>' + opts.text + '</label>';
13067	
13068		if (start) {
13069			str = '_MENU_<label>' + removed + '</label>';
13070		}
13071		else if (end) {
13072			str = '<label>' + removed + '</label>_MENU_';
13073		}
13074	
13075		// Wrapper element - use a span as a holder for where the select will go
13076		var div = $('<div/>')
13077			.addClass( classes.container )
13078			.append(
13079				str.replace( '_MENU_', '<span></span>' )
13080			);
13081	
13082		// Save text node content for macro updating
13083		var textNodes = [];
13084		div.find('label')[0].childNodes.forEach(function (el) {
13085			if (el.nodeType === Node.TEXT_NODE) {
13086				textNodes.push({
13087					el: el,
13088					text: el.textContent
13089				});
13090			}
13091		})
13092	
13093		// Update the label text in case it has an entries value
13094		var updateEntries = function (len) {
13095			textNodes.forEach(function (node) {
13096				node.el.textContent = _fnMacros(settings, node.text, len);
13097			});
13098		}
13099	
13100		// Next, the select itself, along with the options
13101		var select = $('<select/>', {
13102			'name':          tableId+'_length',
13103			'aria-controls': tableId,
13104			'class':         classes.select
13105		} );
13106	
13107		for ( i=0 ; i<lengths.length ; i++ ) {
13108			select[0][ i ] = new Option(
13109				typeof language[i] === 'number' ?
13110					settings.fnFormatNumber( language[i] ) :
13111					language[i],
13112				lengths[i]
13113			);
13114		}
13115	
13116		// add for and id to label and input
13117		div.find('label').attr('for', 'dt-length-' + __lengthCounter);
13118		select.attr('id', 'dt-length-' + __lengthCounter);
13119		__lengthCounter++;
13120	
13121		// Swap in the select list
13122		div.find('span').replaceWith(select);
13123	
13124		// Can't use `select` variable as user might provide their own and the
13125		// reference is broken by the use of outerHTML
13126		$('select', div)
13127			.val( settings._iDisplayLength )
13128			.on( 'change.DT', function() {
13129				_fnLengthChange( settings, $(this).val() );
13130				_fnDraw( settings );
13131			} );
13132	
13133		// Update node value whenever anything changes the table's length
13134		$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
13135			if ( settings === s ) {
13136				$('select', div).val( len );
13137	
13138				// Resolve plurals in the text for the new length
13139				updateEntries(len);
13140			}
13141		} );
13142	
13143		updateEntries(settings._iDisplayLength);
13144	
13145		return div;
13146	}, 'l' );
13147	
13148	// jQuery access
13149	$.fn.dataTable = DataTable;
13150	
13151	// Provide access to the host jQuery object (circular reference)
13152	DataTable.$ = $;
13153	
13154	// Legacy aliases
13155	$.fn.dataTableSettings = DataTable.settings;
13156	$.fn.dataTableExt = DataTable.ext;
13157	
13158	// With a capital `D` we return a DataTables API instance rather than a
13159	// jQuery object
13160	$.fn.DataTable = function ( opts ) {
13161		return $(this).dataTable( opts ).api();
13162	};
13163	
13164	// All properties that are available to $.fn.dataTable should also be
13165	// available on $.fn.DataTable
13166	$.each( DataTable, function ( prop, val ) {
13167		$.fn.DataTable[ prop ] = val;
13168	} );
13169
13170	return DataTable;
13171}));

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.