PageSourceSearch

https://www.ciencia.gob.es/.resources/site-web/webresources/js/datatables~2026-09-16-05-38-56-636~cache.js

js ciencia.gob.es collected 2026-09-24 08:47:11 UTC 382,128 bytes, 13,242 lines download raw bytes

1/*
2 * This combined file was created by the DataTables downloader builder:
3 *   https://datatables.net/download
4 *
5 * To rebuild or modify this file with the latest versions of the included
6 * software please visit:
7 *   https://datatables.net/download/#dt/dt-2.0.8
8 *
9 * Included libraries:
10 *   DataTables 2.0.8
11 */
12
13/*! DataTables 2.0.8
14 * © SpryMedia Ltd - datatables.net/license
15 */
16
17/**
18 * @summary     DataTables
19 * @description Paginate, search and order HTML tables
20 * @version     2.0.8
21 * @author      SpryMedia Ltd
22 * @contact     www.datatables.net
23 * @copyright   SpryMedia Ltd.
24 *
25 * This source file is free software, available under the following license:
26 *   MIT license - https://datatables.net/license
27 *
28 * This source file is distributed in the hope that it will be useful, but
29 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
30 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
31 *
32 * For details please refer to: https://www.datatables.net
33 */
34
35(function( factory ) {
36	"use strict";
37
38	if ( typeof define === 'function' && define.amd ) {
39		// AMD
40		define( ['jquery'], function ( $ ) {
41			return factory( $, window, document );
42		} );
43	}
44	else if ( typeof exports === 'object' ) {
45		// CommonJS
46		// jQuery's factory checks for a global window - if it isn't present then it
47		// returns a factory function that expects the window object
48		var jq = require('jquery');
49
50		if (typeof window === 'undefined') {
51			module.exports = function (root, $) {
52				if ( ! root ) {
53					// CommonJS environments without a window global must pass a
54					// root. This will give an error otherwise
55					root = window;
56				}
57
58				if ( ! $ ) {
59					$ = jq( root );
60				}
61
62				return factory( $, root, root.document );
63			};
64		}
65		else {
66			module.exports = factory( jq, window, window.document );
67		}
68	}
69	else {
70		// Browser
71		window.DataTable = factory( jQuery, window, document );
72	}
73}(function( $, window, document ) {
74	"use strict";
75
76	
77	var DataTable = function ( selector, options )
78	{
79		// Check if called with a window or jQuery object for DOM less applications
80		// This is for backwards compatibility
81		if (DataTable.factory(selector, options)) {
82			return DataTable;
83		}
84	
85		// When creating with `new`, create a new DataTable, returning the API instance
86		if (this instanceof DataTable) {
87			return $(selector).DataTable(options);
88		}
89		else {
90			// Argument switching
91			options = selector;
92		}
93	
94		var _that = this;
95		var emptyInit = options === undefined;
96		var len = this.length;
97	
98		if ( emptyInit ) {
99			options = {};
100		}
101	
102		// Method to get DT API instance from jQuery object
103		this.api = function ()
104		{
105			return new _Api( this );
106		};
107	
108		this.each(function() {
109			// For each initialisation we want to give it a clean initialisation
110			// object that can be bashed around
111			var o = {};
112			var oInit = len > 1 ? // optimisation for single table case
113				_fnExtend( o, options, true ) :
114				options;
115	
116			
117			var i=0, iLen;
118			var sId = this.getAttribute( 'id' );
119			var bInitHandedOff = false;
120			var defaults = DataTable.defaults;
121			var $this = $(this);
122			
123			
124			/* Sanity check */
125			if ( this.nodeName.toLowerCase() != 'table' )
126			{
127				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
128				return;
129			}
130			
131			$(this).trigger( 'options.dt', oInit );
132			
133			/* Backwards compatibility for the defaults */
134			_fnCompatOpts( defaults );
135			_fnCompatCols( defaults.column );
136			
137			/* Convert the camel-case defaults to Hungarian */
138			_fnCamelToHungarian( defaults, defaults, true );
139			_fnCamelToHungarian( defaults.column, defaults.column, true );
140			
141			/* Setting up the initialisation object */
142			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
143			
144			
145			
146			/* Check to see if we are re-initialising a table */
147			var allSettings = DataTable.settings;
148			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
149			{
150				var s = allSettings[i];
151			
152				/* Base check on table node */
153				if (
154					s.nTable == this ||
155					(s.nTHead && s.nTHead.parentNode == this) ||
156					(s.nTFoot && s.nTFoot.parentNode == this)
157				) {
158					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
159					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
160			
161					if ( emptyInit || bRetrieve )
162					{
163						return s.oInstance;
164					}
165					else if ( bDestroy )
166					{
167						new DataTable.Api(s).destroy();
168						break;
169					}
170					else
171					{
172						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
173						return;
174					}
175				}
176			
177				/* If the element we are initialising has the same ID as a table which was previously
178				 * initialised, but the table nodes don't match (from before) then we destroy the old
179				 * instance by simply deleting it. This is under the assumption that the table has been
180				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
181				 */
182				if ( s.sTableId == this.id )
183				{
184					allSettings.splice( i, 1 );
185					break;
186				}
187			}
188			
189			/* Ensure the table has an ID - required for accessibility */
190			if ( sId === null || sId === "" )
191			{
192				sId = "DataTables_Table_"+(DataTable.ext._unique++);
193				this.id = sId;
194			}
195			
196			/* Create the settings object for this table and set some of the default parameters */
197			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
198				"sDestroyWidth": $this[0].style.width,
199				"sInstance":     sId,
200				"sTableId":      sId,
201				colgroup: $('<colgroup>').prependTo(this),
202				fastData: function (row, column, type) {
203					return _fnGetCellData(oSettings, row, column, type);
204				}
205			} );
206			oSettings.nTable = this;
207			oSettings.oInit  = oInit;
208			
209			allSettings.push( oSettings );
210			
211			// Make a single API instance available for internal handling
212			oSettings.api = new _Api( oSettings );
213			
214			// Need to add the instance after the instance after the settings object has been added
215			// to the settings array, so we can self reference the table instance if more than one
216			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
217			
218			// Backwards compatibility, before we apply all the defaults
219			_fnCompatOpts( oInit );
220			
221			// If the length menu is given, but the init display length is not, use the length menu
222			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
223			{
224				oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
225					? oInit.aLengthMenu[0][0]
226					: $.isPlainObject( oInit.aLengthMenu[0] )
227						? oInit.aLengthMenu[0].value
228						: oInit.aLengthMenu[0];
229			}
230			
231			// Apply the defaults and init options to make a single init object will all
232			// options defined from defaults and instance options.
233			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
234			
235			
236			// Map the initialisation options onto the settings object
237			_fnMap( oSettings.oFeatures, oInit, [
238				"bPaginate",
239				"bLengthChange",
240				"bFilter",
241				"bSort",
242				"bSortMulti",
243				"bInfo",
244				"bProcessing",
245				"bAutoWidth",
246				"bSortClasses",
247				"bServerSide",
248				"bDeferRender"
249			] );
250			_fnMap( oSettings, oInit, [
251				"ajax",
252				"fnFormatNumber",
253				"sServerMethod",
254				"aaSorting",
255				"aaSortingFixed",
256				"aLengthMenu",
257				"sPaginationType",
258				"iStateDuration",
259				"bSortCellsTop",
260				"iTabIndex",
261				"sDom",
262				"fnStateLoadCallback",
263				"fnStateSaveCallback",
264				"renderer",
265				"searchDelay",
266				"rowId",
267				"caption",
268				"layout",
269				[ "iCookieDuration", "iStateDuration" ], // backwards compat
270				[ "oSearch", "oPreviousSearch" ],
271				[ "aoSearchCols", "aoPreSearchCols" ],
272				[ "iDisplayLength", "_iDisplayLength" ]
273			] );
274			_fnMap( oSettings.oScroll, oInit, [
275				[ "sScrollX", "sX" ],
276				[ "sScrollXInner", "sXInner" ],
277				[ "sScrollY", "sY" ],
278				[ "bScrollCollapse", "bCollapse" ]
279			] );
280			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
281			
282			/* Callback functions which are array driven */
283			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback );
284			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams );
285			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams );
286			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded );
287			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback );
288			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
289			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback );
290			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback );
291			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete );
292			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback );
293			
294			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
295			
296			/* Browser support detection */
297			_fnBrowserDetect( oSettings );
298			
299			var oClasses = oSettings.oClasses;
300			
301			$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
302			$this.addClass( oClasses.table );
303			
304			if (! oSettings.oFeatures.bPaginate) {
305				oInit.iDisplayStart = 0;
306			}
307			
308			if ( oSettings.iInitDisplayStart === undefined )
309			{
310				/* Display start point, taking into account the save saving */
311				oSettings.iInitDisplayStart = oInit.iDisplayStart;
312				oSettings._iDisplayStart = oInit.iDisplayStart;
313			}
314			
315			/* Language definitions */
316			var oLanguage = oSettings.oLanguage;
317			$.extend( true, oLanguage, oInit.oLanguage );
318			
319			if ( oLanguage.sUrl )
320			{
321				/* Get the language definitions from a file - because this Ajax call makes the language
322				 * get async to the remainder of this function we use bInitHandedOff to indicate that
323				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
324				 */
325				$.ajax( {
326					dataType: 'json',
327					url: oLanguage.sUrl,
328					success: function ( json ) {
329						_fnCamelToHungarian( defaults.oLanguage, json );
330						$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
331			
332						_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
333						_fnInitialise( oSettings );
334					},
335					error: function () {
336						// Error occurred loading language file
337						_fnLog( oSettings, 0, 'i18n file loading error', 21 );
338			
339						// continue on as best we can
340						_fnInitialise( oSettings );
341					}
342				} );
343				bInitHandedOff = true;
344			}
345			else {
346				_fnCallbackFire( oSettings, null, 'i18n', [oSettings]);
347			}
348			
349			/*
350			 * Columns
351			 * See if we should load columns automatically or use defined ones
352			 */
353			var columnsInit = [];
354			var thead = this.getElementsByTagName('thead');
355			var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
356			
357			// If we don't have a columns array, then generate one with nulls
358			if ( oInit.aoColumns ) {
359				columnsInit = oInit.aoColumns;
360			}
361			else if ( initHeaderLayout.length ) {
362				for ( i=0, iLen=initHeaderLayout[0].length ; i<iLen ; i++ ) {
363					columnsInit.push( null );
364				}
365			}
366			
367			// Add the columns
368			for ( i=0, iLen=columnsInit.length ; i<iLen ; i++ ) {
369				_fnAddColumn( oSettings );
370			}
371			
372			// Apply the column definitions
373			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
374				_fnColumnOptions( oSettings, iCol, oDef );
375			} );
376			
377			/* HTML5 attribute detection - build an mData object automatically if the
378			 * attributes are found
379			 */
380			var rowOne = $this.children('tbody').find('tr').eq(0);
381			
382			if ( rowOne.length ) {
383				var a = function ( cell, name ) {
384					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
385				};
386			
387				$( rowOne[0] ).children('th, td').each( function (i, cell) {
388					var col = oSettings.aoColumns[i];
389			
390					if (! col) {
391						_fnLog( oSettings, 0, 'Incorrect column count', 18 );
392					}
393			
394					if ( col.mData === i ) {
395						var sort = a( cell, 'sort' ) || a( cell, 'order' );
396						var filter = a( cell, 'filter' ) || a( cell, 'search' );
397			
398						if ( sort !== null || filter !== null ) {
399							col.mData = {
400								_:      i+'.display',
401								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
402								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
403								filter: filter !== null ? i+'.@data-'+filter : undefined
404							};
405							col._isArrayHost = true;
406			
407							_fnColumnOptions( oSettings, i );
408						}
409					}
410				} );
411			}
412			
413			var features = oSettings.oFeatures;
414			var loadedInit = function () {
415				/*
416				 * Sorting
417				 * @todo For modularisation (1.11) this needs to do into a sort start up handler
418				 */
419			
420				// If aaSorting is not defined, then we use the first indicator in asSorting
421				// in case that has been altered, so the default sort reflects that option
422				if ( oInit.aaSorting === undefined ) {
423					var sorting = oSettings.aaSorting;
424					for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
425						sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
426					}
427				}
428			
429				/* Do a first pass on the sorting classes (allows any size changes to be taken into
430				 * account, and also will apply sorting disabled classes if disabled
431				 */
432				_fnSortingClasses( oSettings );
433			
434				_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
435					if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
436						_fnSortingClasses( oSettings );
437					}
438				} );
439			
440			
441				/*
442				 * Final init
443				 * Cache the header, body and footer as required, creating them if needed
444				 */
445				var caption = $this.children('caption');
446			
447				if ( oSettings.caption ) {
448					if ( caption.length === 0 ) {
449						caption = $('<caption/>').appendTo( $this );
450					}
451			
452					caption.html( oSettings.caption );
453				}
454			
455				// Store the caption side, so we can remove the element from the document
456				// when creating the element
457				if (caption.length) {
458					caption[0]._captionSide = caption.css('caption-side');
459					oSettings.captionNode = caption[0];
460				}
461			
462				if ( thead.length === 0 ) {
463					thead = $('<thead/>').appendTo($this);
464				}
465				oSettings.nTHead = thead[0];
466				$('tr', thead).addClass(oClasses.thead.row);
467			
468				var tbody = $this.children('tbody');
469				if ( tbody.length === 0 ) {
470					tbody = $('<tbody/>').insertAfter(thead);
471				}
472				oSettings.nTBody = tbody[0];
473			
474				var tfoot = $this.children('tfoot');
475				if ( tfoot.length === 0 ) {
476					// If we are a scrolling table, and no footer has been given, then we need to create
477					// a tfoot element for the caption element to be appended to
478					tfoot = $('<tfoot/>').appendTo($this);
479				}
480				oSettings.nTFoot = tfoot[0];
481				$('tr', tfoot).addClass(oClasses.tfoot.row);
482			
483				// Check if there is data passing into the constructor
484				if ( oInit.aaData ) {
485					for ( i=0 ; i<oInit.aaData.length ; i++ ) {
486						_fnAddData( oSettings, oInit.aaData[ i ] );
487					}
488				}
489				else if ( _fnDataSource( oSettings ) == 'dom' ) {
490					// Grab the data from the page
491					_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
492				}
493			
494				/* Copy the data index array */
495				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
496			
497				/* Initialisation complete - table can be drawn */
498				oSettings.bInitialised = true;
499			
500				/* Check if we need to initialise the table (it might not have been handed off to the
501				 * language processor)
502				 */
503				if ( bInitHandedOff === false ) {
504					_fnInitialise( oSettings );
505				}
506			};
507			
508			/* Must be done after everything which can be overridden by the state saving! */
509			_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState );
510			
511			if ( oInit.bStateSave )
512			{
513				features.bStateSave = true;
514				_fnLoadState( oSettings, oInit, loadedInit );
515			}
516			else {
517				loadedInit();
518			}
519			
520		} );
521		_that = null;
522		return this;
523	};
524	
525	
526	
527	/**
528	 * DataTables extensions
529	 * 
530	 * This namespace acts as a collection area for plug-ins that can be used to
531	 * extend DataTables capabilities. Indeed many of the build in methods
532	 * use this method to provide their own capabilities (sorting methods for
533	 * example).
534	 *
535	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
536	 * reasons
537	 *
538	 *  @namespace
539	 */
540	DataTable.ext = _ext = {
541		/**
542		 * Buttons. For use with the Buttons extension for DataTables. This is
543		 * defined here so other extensions can define buttons regardless of load
544		 * order. It is _not_ used by DataTables core.
545		 *
546		 *  @type object
547		 *  @default {}
548		 */
549		buttons: {},
550	
551	
552		/**
553		 * Element class names
554		 *
555		 *  @type object
556		 *  @default {}
557		 */
558		classes: {},
559	
560	
561		/**
562		 * DataTables build type (expanded by the download builder)
563		 *
564		 *  @type string
565		 */
566		builder: "dt/dt-2.0.8",
567	
568	
569		/**
570		 * Error reporting.
571		 * 
572		 * How should DataTables report an error. Can take the value 'alert',
573		 * 'throw', 'none' or a function.
574		 *
575		 *  @type string|function
576		 *  @default alert
577		 */
578		errMode: "alert",
579	
580	
581		/**
582		 * Legacy so v1 plug-ins don't throw js errors on load
583		 */
584		feature: [],
585	
586		/**
587		 * Feature plug-ins.
588		 * 
589		 * This is an object of callbacks which provide the features for DataTables
590		 * to be initialised via the `layout` option.
591		 */
592		features: {},
593	
594	
595		/**
596		 * Row searching.
597		 * 
598		 * This method of searching is complimentary to the default type based
599		 * searching, and a lot more comprehensive as it allows you complete control
600		 * over the searching logic. Each element in this array is a function
601		 * (parameters described below) that is called for every row in the table,
602		 * and your logic decides if it should be included in the searching data set
603		 * or not.
604		 *
605		 * Searching functions have the following input parameters:
606		 *
607		 * 1. `{object}` DataTables settings object: see
608		 *    {@link DataTable.models.oSettings}
609		 * 2. `{array|object}` Data for the row to be processed (same as the
610		 *    original format that was passed in as the data source, or an array
611		 *    from a DOM data source
612		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
613		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
614		 *
615		 * And the following return is expected:
616		 *
617		 * * {boolean} Include the row in the searched result set (true) or not
618		 *   (false)
619		 *
620		 * Note that as with the main search ability in DataTables, technically this
621		 * is "filtering", since it is subtractive. However, for consistency in
622		 * naming we call it searching here.
623		 *
624		 *  @type array
625		 *  @default []
626		 *
627		 *  @example
628		 *    // The following example shows custom search being applied to the
629		 *    // fourth column (i.e. the data[3] index) based on two input values
630		 *    // from the end-user, matching the data in a certain range.
631		 *    $.fn.dataTable.ext.search.push(
632		 *      function( settings, data, dataIndex ) {
633		 *        var min = document.getElementById('min').value * 1;
634		 *        var max = document.getElementById('max').value * 1;
635		 *        var version = data[3] == "-" ? 0 : data[3]*1;
636		 *
637		 *        if ( min == "" && max == "" ) {
638		 *          return true;
639		 *        }
640		 *        else if ( min == "" && version < max ) {
641		 *          return true;
642		 *        }
643		 *        else if ( min < version && "" == max ) {
644		 *          return true;
645		 *        }
646		 *        else if ( min < version && version < max ) {
647		 *          return true;
648		 *        }
649		 *        return false;
650		 *      }
651		 *    );
652		 */
653		search: [],
654	
655	
656		/**
657		 * Selector extensions
658		 *
659		 * The `selector` option can be used to extend the options available for the
660		 * selector modifier options (`selector-modifier` object data type) that
661		 * each of the three built in selector types offer (row, column and cell +
662		 * their plural counterparts). For example the Select extension uses this
663		 * mechanism to provide an option to select only rows, columns and cells
664		 * that have been marked as selected by the end user (`{selected: true}`),
665		 * which can be used in conjunction with the existing built in selector
666		 * options.
667		 *
668		 * Each property is an array to which functions can be pushed. The functions
669		 * take three attributes:
670		 *
671		 * * Settings object for the host table
672		 * * Options object (`selector-modifier` object type)
673		 * * Array of selected item indexes
674		 *
675		 * The return is an array of the resulting item indexes after the custom
676		 * selector has been applied.
677		 *
678		 *  @type object
679		 */
680		selector: {
681			cell: [],
682			column: [],
683			row: []
684		},
685	
686	
687		/**
688		 * Legacy configuration options. Enable and disable legacy options that
689		 * are available in DataTables.
690		 *
691		 *  @type object
692		 */
693		legacy: {
694			/**
695			 * Enable / disable DataTables 1.9 compatible server-side processing
696			 * requests
697			 *
698			 *  @type boolean
699			 *  @default null
700			 */
701			ajax: null
702		},
703	
704	
705		/**
706		 * Pagination plug-in methods.
707		 * 
708		 * Each entry in this object is a function and defines which buttons should
709		 * be shown by the pagination rendering method that is used for the table:
710		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
711		 * buttons are displayed in the document, while the functions here tell it
712		 * what buttons to display. This is done by returning an array of button
713		 * descriptions (what each button will do).
714		 *
715		 * Pagination types (the four built in options and any additional plug-in
716		 * options defined here) can be used through the `paginationType`
717		 * initialisation parameter.
718		 *
719		 * The functions defined take two parameters:
720		 *
721		 * 1. `{int} page` The current page index
722		 * 2. `{int} pages` The number of pages in the table
723		 *
724		 * Each function is expected to return an array where each element of the
725		 * array can be one of:
726		 *
727		 * * `first` - Jump to first page when activated
728		 * * `last` - Jump to last page when activated
729		 * * `previous` - Show previous page when activated
730		 * * `next` - Show next page when activated
731		 * * `{int}` - Show page of the index given
732		 * * `{array}` - A nested array containing the above elements to add a
733		 *   containing 'DIV' element (might be useful for styling).
734		 *
735		 * Note that DataTables v1.9- used this object slightly differently whereby
736		 * an object with two functions would be defined for each plug-in. That
737		 * ability is still supported by DataTables 1.10+ to provide backwards
738		 * compatibility, but this option of use is now decremented and no longer
739		 * documented in DataTables 1.10+.
740		 *
741		 *  @type object
742		 *  @default {}
743		 *
744		 *  @example
745		 *    // Show previous, next and current page buttons only
746		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
747		 *      return [ 'previous', page, 'next' ];
748		 *    };
749		 */
750		pager: {},
751	
752	
753		renderer: {
754			pageButton: {},
755			header: {}
756		},
757	
758	
759		/**
760		 * Ordering plug-ins - custom data source
761		 * 
762		 * The extension options for ordering of data available here is complimentary
763		 * to the default type based ordering that DataTables typically uses. It
764		 * allows much greater control over the the data that is being used to
765		 * order a column, but is necessarily therefore more complex.
766		 * 
767		 * This type of ordering is useful if you want to do ordering based on data
768		 * live from the DOM (for example the contents of an 'input' element) rather
769		 * than just the static string that DataTables knows of.
770		 * 
771		 * The way these plug-ins work is that you create an array of the values you
772		 * wish to be ordering for the column in question and then return that
773		 * array. The data in the array much be in the index order of the rows in
774		 * the table (not the currently ordering order!). Which order data gathering
775		 * function is run here depends on the `dt-init columns.orderDataType`
776		 * parameter that is used for the column (if any).
777		 *
778		 * The functions defined take two parameters:
779		 *
780		 * 1. `{object}` DataTables settings object: see
781		 *    {@link DataTable.models.oSettings}
782		 * 2. `{int}` Target column index
783		 *
784		 * Each function is expected to return an array:
785		 *
786		 * * `{array}` Data for the column to be ordering upon
787		 *
788		 *  @type array
789		 *
790		 *  @example
791		 *    // Ordering using `input` node values
792		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
793		 *    {
794		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
795		 *        return $('input', td).val();
796		 *      } );
797		 *    }
798		 */
799		order: {},
800	
801	
802		/**
803		 * Type based plug-ins.
804		 *
805		 * Each column in DataTables has a type assigned to it, either by automatic
806		 * detection or by direct assignment using the `type` option for the column.
807		 * The type of a column will effect how it is ordering and search (plug-ins
808		 * can also make use of the column type if required).
809		 *
810		 * @namespace
811		 */
812		type: {
813			/**
814			 * Automatic column class assignment
815			 */
816			className: {},
817	
818			/**
819			 * Type detection functions.
820			 *
821			 * The functions defined in this object are used to automatically detect
822			 * a column's type, making initialisation of DataTables super easy, even
823			 * when complex data is in the table.
824			 *
825			 * The functions defined take two parameters:
826			 *
827		     *  1. `{*}` Data from the column cell to be analysed
828		     *  2. `{settings}` DataTables settings object. This can be used to
829		     *     perform context specific type detection - for example detection
830		     *     based on language settings such as using a comma for a decimal
831		     *     place. Generally speaking the options from the settings will not
832		     *     be required
833			 *
834			 * Each function is expected to return:
835			 *
836			 * * `{string|null}` Data type detected, or null if unknown (and thus
837			 *   pass it on to the other type detection functions.
838			 *
839			 *  @type array
840			 *
841			 *  @example
842			 *    // Currency type detection plug-in:
843			 *    $.fn.dataTable.ext.type.detect.push(
844			 *      function ( data, settings ) {
845			 *        // Check the numeric part
846			 *        if ( ! data.substring(1).match(/[0-9]/) ) {
847			 *          return null;
848			 *        }
849			 *
850			 *        // Check prefixed by currency
851			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
852			 *          return 'currency';
853			 *        }
854			 *        return null;
855			 *      }
856			 *    );
857			 */
858			detect: [],
859	
860			/**
861			 * Automatic renderer assignment
862			 */
863			render: {},
864	
865	
866			/**
867			 * Type based search formatting.
868			 *
869			 * The type based searching functions can be used to pre-format the
870			 * data to be search on. For example, it can be used to strip HTML
871			 * tags or to de-format telephone numbers for numeric only searching.
872			 *
873			 * Note that is a search is not defined for a column of a given type,
874			 * no search formatting will be performed.
875			 * 
876			 * Pre-processing of searching data plug-ins - When you assign the sType
877			 * for a column (or have it automatically detected for you by DataTables
878			 * or a type detection plug-in), you will typically be using this for
879			 * custom sorting, but it can also be used to provide custom searching
880			 * by allowing you to pre-processing the data and returning the data in
881			 * the format that should be searched upon. This is done by adding
882			 * functions this object with a parameter name which matches the sType
883			 * for that target column. This is the corollary of <i>afnSortData</i>
884			 * for searching data.
885			 *
886			 * The functions defined take a single parameter:
887			 *
888		     *  1. `{*}` Data from the column cell to be prepared for searching
889			 *
890			 * Each function is expected to return:
891			 *
892			 * * `{string|null}` Formatted string that will be used for the searching.
893			 *
894			 *  @type object
895			 *  @default {}
896			 *
897			 *  @example
898			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
899			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
900			 *    }
901			 */
902			search: {},
903	
904	
905			/**
906			 * Type based ordering.
907			 *
908			 * The column type tells DataTables what ordering to apply to the table
909			 * when a column is sorted upon. The order for each type that is defined,
910			 * is defined by the functions available in this object.
911			 *
912			 * Each ordering option can be described by three properties added to
913			 * this object:
914			 *
915			 * * `{type}-pre` - Pre-formatting function
916			 * * `{type}-asc` - Ascending order function
917			 * * `{type}-desc` - Descending order function
918			 *
919			 * All three can be used together, only `{type}-pre` or only
920			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
921			 * that only `{type}-pre` is used, as this provides the optimal
922			 * implementation in terms of speed, although the others are provided
923			 * for compatibility with existing Javascript sort functions.
924			 *
925			 * `{type}-pre`: Functions defined take a single parameter:
926			 *
927		     *  1. `{*}` Data from the column cell to be prepared for ordering
928			 *
929			 * And return:
930			 *
931			 * * `{*}` Data to be sorted upon
932			 *
933			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
934			 * functions, taking two parameters:
935			 *
936		     *  1. `{*}` Data to compare to the second parameter
937		     *  2. `{*}` Data to compare to the first parameter
938			 *
939			 * And returning:
940			 *
941			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
942			 *   than the second parameter, ===0 if the two parameters are equal and
943			 *   >0 if the first parameter should be sorted height than the second
944			 *   parameter.
945			 * 
946			 *  @type object
947			 *  @default {}
948			 *
949			 *  @example
950			 *    // Numeric ordering of formatted numbers with a pre-formatter
951			 *    $.extend( $.fn.dataTable.ext.type.order, {
952			 *      "string-pre": function(x) {
953			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
954			 *        return parseFloat( a );
955			 *      }
956			 *    } );
957			 *
958			 *  @example
959			 *    // Case-sensitive string ordering, with no pre-formatting method
960			 *    $.extend( $.fn.dataTable.ext.order, {
961			 *      "string-case-asc": function(x,y) {
962			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
963			 *      },
964			 *      "string-case-desc": function(x,y) {
965			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
966			 *      }
967			 *    } );
968			 */
969			order: {}
970		},
971	
972		/**
973		 * Unique DataTables instance counter
974		 *
975		 * @type int
976		 * @private
977		 */
978		_unique: 0,
979	
980	
981		//
982		// Depreciated
983		// The following properties are retained for backwards compatibility only.
984		// The should not be used in new projects and will be removed in a future
985		// version
986		//
987	
988		/**
989		 * Version check function.
990		 *  @type function
991		 *  @depreciated Since 1.10
992		 */
993		fnVersionCheck: DataTable.fnVersionCheck,
994	
995	
996		/**
997		 * Index for what 'this' index API functions should use
998		 *  @type int
999		 *  @deprecated Since v1.10
1000		 */
1001		iApiIndex: 0,
1002	
1003	
1004		/**
1005		 * Software version
1006		 *  @type string
1007		 *  @deprecated Since v1.10
1008		 */
1009		sVersion: DataTable.version
1010	};
1011	
1012	
1013	//
1014	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
1015	//
1016	$.extend( _ext, {
1017		afnFiltering: _ext.search,
1018		aTypes:       _ext.type.detect,
1019		ofnSearch:    _ext.type.search,
1020		oSort:        _ext.type.order,
1021		afnSortData:  _ext.order,
1022		aoFeatures:   _ext.feature,
1023		oStdClasses:  _ext.classes,
1024		oPagination:  _ext.pager
1025	} );
1026	
1027	
1028	$.extend( DataTable.ext.classes, {
1029		container: 'dt-container',
1030		empty: {
1031			row: 'dt-empty'
1032		},
1033		info: {
1034			container: 'dt-info'
1035		},
1036		length: {
1037			container: 'dt-length',
1038			select: 'dt-input'
1039		},
1040		order: {
1041			canAsc: 'dt-orderable-asc',
1042			canDesc: 'dt-orderable-desc',
1043			isAsc: 'dt-ordering-asc',
1044			isDesc: 'dt-ordering-desc',
1045			none: 'dt-orderable-none',
1046			position: 'sorting_'
1047		},
1048		processing: {
1049			container: 'dt-processing'
1050		},
1051		scrolling: {
1052			body: 'dt-scroll-body',
1053			container: 'dt-scroll',
1054			footer: {
1055				self: 'dt-scroll-foot',
1056				inner: 'dt-scroll-footInner'
1057			},
1058			header: {
1059				self: 'dt-scroll-head',
1060				inner: 'dt-scroll-headInner'
1061			}
1062		},
1063		search: {
1064			container: 'dt-search',
1065			input: 'dt-input'
1066		},
1067		table: 'dataTable',	
1068		tbody: {
1069			cell: '',
1070			row: ''
1071		},
1072		thead: {
1073			cell: '',
1074			row: ''
1075		},
1076		tfoot: {
1077			cell: '',
1078			row: ''
1079		},
1080		paging: {
1081			active: 'current',
1082			button: 'dt-paging-button',
1083			container: 'dt-paging',
1084			disabled: 'disabled'
1085		}
1086	} );
1087	
1088	
1089	/*
1090	 * It is useful to have variables which are scoped locally so only the
1091	 * DataTables functions can access them and they don't leak into global space.
1092	 * At the same time these functions are often useful over multiple files in the
1093	 * core and API, so we list, or at least document, all variables which are used
1094	 * by DataTables as private variables here. This also ensures that there is no
1095	 * clashing of variable names and that they can easily referenced for reuse.
1096	 */
1097	
1098	
1099	// Defined else where
1100	//  _selector_run
1101	//  _selector_opts
1102	//  _selector_row_indexes
1103	
1104	var _ext; // DataTable.ext
1105	var _Api; // DataTable.Api
1106	var _api_register; // DataTable.Api.register
1107	var _api_registerPlural; // DataTable.Api.registerPlural
1108	
1109	var _re_dic = {};
1110	var _re_new_lines = /[\r\n\u2028]/g;
1111	var _re_html = /<([^>]*>)/g;
1112	var _max_str_len = Math.pow(2, 28);
1113	
1114	// This is not strict ISO8601 - Date.parse() is quite lax, although
1115	// implementations differ between browsers.
1116	var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
1117	
1118	// Escape regular expression special characters
1119	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1120	
1121	// https://en.wikipedia.org/wiki/Foreign_exchange_market
1122	// - \u20BD - Russian ruble.
1123	// - \u20a9 - South Korean Won
1124	// - \u20BA - Turkish Lira
1125	// - \u20B9 - Indian Rupee
1126	// - R - Brazil (R$) and South Africa
1127	// - fr - Swiss Franc
1128	// - kr - Swedish krona, Norwegian krone and Danish krone
1129	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1130	// - Ƀ - Bitcoin
1131	// - Ξ - Ethereum
1132	//   standards as thousands separators.
1133	var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1134	
1135	
1136	var _empty = function ( d ) {
1137		return !d || d === true || d === '-' ? true : false;
1138	};
1139	
1140	
1141	var _intVal = function ( s ) {
1142		var integer = parseInt( s, 10 );
1143		return !isNaN(integer) && isFinite(s) ? integer : null;
1144	};
1145	
1146	// Convert from a formatted number with characters other than `.` as the
1147	// decimal place, to a Javascript number
1148	var _numToDecimal = function ( num, decimalPoint ) {
1149		// Cache created regular expressions for speed as this function is called often
1150		if ( ! _re_dic[ decimalPoint ] ) {
1151			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1152		}
1153		return typeof num === 'string' && decimalPoint !== '.' ?
1154			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1155			num;
1156	};
1157	
1158	
1159	var _isNumber = function ( d, decimalPoint, formatted ) {
1160		var type = typeof d;
1161		var strType = type === 'string';
1162	
1163		if ( type === 'number' || type === 'bigint') {
1164			return true;
1165		}
1166	
1167		// If empty return immediately so there must be a number if it is a
1168		// formatted string (this stops the string "k", or "kr", etc being detected
1169		// as a formatted number for currency
1170		if ( _empty( d ) ) {
1171			return true;
1172		}
1173	
1174		if ( decimalPoint && strType ) {
1175			d = _numToDecimal( d, decimalPoint );
1176		}
1177	
1178		if ( formatted && strType ) {
1179			d = d.replace( _re_formatted_numeric, '' );
1180		}
1181	
1182		return !isNaN( parseFloat(d) ) && isFinite( d );
1183	};
1184	
1185	
1186	// A string without HTML in it can be considered to be HTML still
1187	var _isHtml = function ( d ) {
1188		return _empty( d ) || typeof d === 'string';
1189	};
1190	
1191	// Is a string a number surrounded by HTML?
1192	var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1193		if ( _empty( d ) ) {
1194			return true;
1195		}
1196	
1197		// input and select strings mean that this isn't just a number
1198		if (typeof d === 'string' && d.match(/<(input|select)/i)) {
1199			return null;
1200		}
1201	
1202		var html = _isHtml( d );
1203		return ! html ?
1204			null :
1205			_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1206				true :
1207				null;
1208	};
1209	
1210	
1211	var _pluck = function ( a, prop, prop2 ) {
1212		var out = [];
1213		var i=0, ien=a.length;
1214	
1215		// Could have the test in the loop for slightly smaller code, but speed
1216		// is essential here
1217		if ( prop2 !== undefined ) {
1218			for ( ; i<ien ; i++ ) {
1219				if ( a[i] && a[i][ prop ] ) {
1220					out.push( a[i][ prop ][ prop2 ] );
1221				}
1222			}
1223		}
1224		else {
1225			for ( ; i<ien ; i++ ) {
1226				if ( a[i] ) {
1227					out.push( a[i][ prop ] );
1228				}
1229			}
1230		}
1231	
1232		return out;
1233	};
1234	
1235	
1236	// Basically the same as _pluck, but rather than looping over `a` we use `order`
1237	// as the indexes to pick from `a`
1238	var _pluck_order = function ( a, order, prop, prop2 )
1239	{
1240		var out = [];
1241		var i=0, ien=order.length;
1242	
1243		// Could have the test in the loop for slightly smaller code, but speed
1244		// is essential here
1245		if ( prop2 !== undefined ) {
1246			for ( ; i<ien ; i++ ) {
1247				if ( a[ order[i] ][ prop ] ) {
1248					out.push( a[ order[i] ][ prop ][ prop2 ] );
1249				}
1250			}
1251		}
1252		else {
1253			for ( ; i<ien ; i++ ) {
1254				if ( a[ order[i] ] ) {
1255					out.push( a[ order[i] ][ prop ] );
1256				}
1257			}
1258		}
1259	
1260		return out;
1261	};
1262	
1263	
1264	var _range = function ( len, start )
1265	{
1266		var out = [];
1267		var end;
1268	
1269		if ( start === undefined ) {
1270			start = 0;
1271			end = len;
1272		}
1273		else {
1274			end = start;
1275			start = len;
1276		}
1277	
1278		for ( var i=start ; i<end ; i++ ) {
1279			out.push( i );
1280		}
1281	
1282		return out;
1283	};
1284	
1285	
1286	var _removeEmpty = function ( a )
1287	{
1288		var out = [];
1289	
1290		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1291			if ( a[i] ) { // careful - will remove all falsy values!
1292				out.push( a[i] );
1293			}
1294		}
1295	
1296		return out;
1297	};
1298	
1299	// Replaceable function in api.util
1300	var _stripHtml = function (input) {
1301		// Irrelevant check to workaround CodeQL's false positive on the regex
1302		if (input.length > _max_str_len) {
1303			throw new Error('Exceeded max str len');
1304		}
1305	
1306		var previous;
1307	
1308		input = input.replace(_re_html, ''); // Complete tags
1309	
1310		// Safety for incomplete script tag - use do / while to ensure that
1311		// we get all instances
1312		do {
1313			previous = input;
1314			input = input.replace(/<script/i, '');
1315		} while (input !== previous);
1316	
1317		return previous;
1318	};
1319	
1320	// Replaceable function in api.util
1321	var _escapeHtml = function ( d ) {
1322		if (Array.isArray(d)) {
1323			d = d.join(',');
1324		}
1325	
1326		return typeof d === 'string' ?
1327			d
1328				.replace(/&/g, '&amp;')
1329				.replace(/</g, '&lt;')
1330				.replace(/>/g, '&gt;')
1331				.replace(/"/g, '&quot;') :
1332			d;
1333	};
1334	
1335	// Remove diacritics from a string by decomposing it and then removing
1336	// non-ascii characters
1337	var _normalize = function (str, both) {
1338		if (typeof str !== 'string') {
1339			return str;
1340		}
1341	
1342		// It is faster to just run `normalize` than it is to check if
1343		// we need to with a regex!
1344		var res = str.normalize("NFD");
1345	
1346		// Equally, here we check if a regex is needed or not
1347		return res.length !== str.length
1348			? (both === true ? str + ' ' : '' ) + res.replace(/[\u0300-\u036f]/g, "")
1349			: res;
1350	}
1351	
1352	/**
1353	 * Determine if all values in the array are unique. This means we can short
1354	 * cut the _unique method at the cost of a single loop. A sorted array is used
1355	 * to easily check the values.
1356	 *
1357	 * @param  {array} src Source array
1358	 * @return {boolean} true if all unique, false otherwise
1359	 * @ignore
1360	 */
1361	var _areAllUnique = function ( src ) {
1362		if ( src.length < 2 ) {
1363			return true;
1364		}
1365	
1366		var sorted = src.slice().sort();
1367		var last = sorted[0];
1368	
1369		for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1370			if ( sorted[i] === last ) {
1371				return false;
1372			}
1373	
1374			last = sorted[i];
1375		}
1376	
1377		return true;
1378	};
1379	
1380	
1381	/**
1382	 * Find the unique elements in a source array.
1383	 *
1384	 * @param  {array} src Source array
1385	 * @return {array} Array of unique items
1386	 * @ignore
1387	 */
1388	var _unique = function ( src )
1389	{
1390		if (Array.from && Set) {
1391			return Array.from(new Set(src));
1392		}
1393	
1394		if ( _areAllUnique( src ) ) {
1395			return src.slice();
1396		}
1397	
1398		// A faster unique method is to use object keys to identify used values,
1399		// but this doesn't work with arrays or objects, which we must also
1400		// consider. See jsperf.app/compare-array-unique-versions/4 for more
1401		// information.
1402		var
1403			out = [],
1404			val,
1405			i, ien=src.length,
1406			j, k=0;
1407	
1408		again: for ( i=0 ; i<ien ; i++ ) {
1409			val = src[i];
1410	
1411			for ( j=0 ; j<k ; j++ ) {
1412				if ( out[j] === val ) {
1413					continue again;
1414				}
1415			}
1416	
1417			out.push( val );
1418			k++;
1419		}
1420	
1421		return out;
1422	};
1423	
1424	// Surprisingly this is faster than [].concat.apply
1425	// https://jsperf.com/flatten-an-array-loop-vs-reduce/2
1426	var _flatten = function (out, val) {
1427		if (Array.isArray(val)) {
1428			for (var i=0 ; i<val.length ; i++) {
1429				_flatten(out, val[i]);
1430			}
1431		}
1432		else {
1433			out.push(val);
1434		}
1435	
1436		return out;
1437	}
1438	
1439	// Similar to jQuery's addClass, but use classList.add
1440	function _addClass(el, name) {
1441		if (name) {
1442			name.split(' ').forEach(function (n) {
1443				if (n) {
1444					// `add` does deduplication, so no need to check `contains`
1445					el.classList.add(n);
1446				}
1447			});
1448		}
1449	}
1450	
1451	/**
1452	 * DataTables utility methods
1453	 * 
1454	 * This namespace provides helper methods that DataTables uses internally to
1455	 * create a DataTable, but which are not exclusively used only for DataTables.
1456	 * These methods can be used by extension authors to save the duplication of
1457	 * code.
1458	 *
1459	 *  @namespace
1460	 */
1461	DataTable.util = {
1462		/**
1463		 * Return a string with diacritic characters decomposed
1464		 * @param {*} mixed Function or string to normalize
1465		 * @param {*} both Return original string and the normalized string
1466		 * @returns String or undefined
1467		 */
1468		diacritics: function (mixed, both) {
1469			var type = typeof mixed;
1470	
1471			if (type !== 'function') {
1472				return _normalize(mixed, both);
1473			}
1474			_normalize = mixed;
1475		},
1476	
1477		/**
1478		 * Debounce a function
1479		 *
1480		 * @param {function} fn Function to be called
1481		 * @param {integer} freq Call frequency in mS
1482		 * @return {function} Wrapped function
1483		 */
1484		debounce: function ( fn, timeout ) {
1485			var timer;
1486	
1487			return function () {
1488				var that = this;
1489				var args = arguments;
1490	
1491				clearTimeout(timer);
1492	
1493				timer = setTimeout( function () {
1494					fn.apply(that, args);
1495				}, timeout || 250 );
1496			};
1497		},
1498	
1499		/**
1500		 * Throttle the calls to a function. Arguments and context are maintained
1501		 * for the throttled function.
1502		 *
1503		 * @param {function} fn Function to be called
1504		 * @param {integer} freq Call frequency in mS
1505		 * @return {function} Wrapped function
1506		 */
1507		throttle: function ( fn, freq ) {
1508			var
1509				frequency = freq !== undefined ? freq : 200,
1510				last,
1511				timer;
1512	
1513			return function () {
1514				var
1515					that = this,
1516					now  = +new Date(),
1517					args = arguments;
1518	
1519				if ( last && now < last + frequency ) {
1520					clearTimeout( timer );
1521	
1522					timer = setTimeout( function () {
1523						last = undefined;
1524						fn.apply( that, args );
1525					}, frequency );
1526				}
1527				else {
1528					last = now;
1529					fn.apply( that, args );
1530				}
1531			};
1532		},
1533	
1534		/**
1535		 * Escape a string such that it can be used in a regular expression
1536		 *
1537		 *  @param {string} val string to escape
1538		 *  @returns {string} escaped string
1539		 */
1540		escapeRegex: function ( val ) {
1541			return val.replace( _re_escape_regex, '\\$1' );
1542		},
1543	
1544		/**
1545		 * Create a function that will write to a nested object or array
1546		 * @param {*} source JSON notation string
1547		 * @returns Write function
1548		 */
1549		set: function ( source ) {
1550			if ( $.isPlainObject( source ) ) {
1551				/* Unlike get, only the underscore (global) option is used for for
1552				 * setting data since we don't know the type here. This is why an object
1553				 * option is not documented for `mData` (which is read/write), but it is
1554				 * for `mRender` which is read only.
1555				 */
1556				return DataTable.util.set( source._ );
1557			}
1558			else if ( source === null ) {
1559				// Nothing to do when the data source is null
1560				return function () {};
1561			}
1562			else if ( typeof source === 'function' ) {
1563				return function (data, val, meta) {
1564					source( data, 'set', val, meta );
1565				};
1566			}
1567			else if (
1568				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1569				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1570			) {
1571				// Like the get, we need to get data from a nested object
1572				var setData = function (data, val, src) {
1573					var a = _fnSplitObjNotation( src ), b;
1574					var aLast = a[a.length-1];
1575					var arrayNotation, funcNotation, o, innerSrc;
1576		
1577					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {
1578						// Protect against prototype pollution
1579						if (a[i] === '__proto__' || a[i] === 'constructor') {
1580							throw new Error('Cannot set prototype values');
1581						}
1582		
1583						// Check if we are dealing with an array notation request
1584						arrayNotation = a[i].match(__reArray);
1585						funcNotation = a[i].match(__reFn);
1586		
1587						if ( arrayNotation ) {
1588							a[i] = a[i].replace(__reArray, '');
1589							data[ a[i] ] = [];
1590		
1591							// Get the remainder of the nested object to set so we can recurse
1592							b = a.slice();
1593							b.splice( 0, i+1 );
1594							innerSrc = b.join('.');
1595		
1596							// Traverse each entry in the array setting the properties requested
1597							if ( Array.isArray( val ) ) {
1598								for ( var j=0, jLen=val.length ; j<jLen ; j++ ) {
1599									o = {};
1600									setData( o, val[j], innerSrc );
1601									data[ a[i] ].push( o );
1602								}
1603							}
1604							else {
1605								// We've been asked to save data to an array, but it
1606								// isn't array data to be saved. Best that can be done
1607								// is to just save the value.
1608								data[ a[i] ] = val;
1609							}
1610		
1611							// The inner call to setData has already traversed through the remainder
1612							// of the source and has set the data, thus we can exit here
1613							return;
1614						}
1615						else if ( funcNotation ) {
1616							// Function call
1617							a[i] = a[i].replace(__reFn, '');
1618							data = data[ a[i] ]( val );
1619						}
1620		
1621						// If the nested object doesn't currently exist - since we are
1622						// trying to set the value - create it
1623						if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {
1624							data[ a[i] ] = {};
1625						}
1626						data = data[ a[i] ];
1627					}
1628		
1629					// Last item in the input - i.e, the actual set
1630					if ( aLast.match(__reFn ) ) {
1631						// Function call
1632						data = data[ aLast.replace(__reFn, '') ]( val );
1633					}
1634					else {
1635						// If array notation is used, we just want to strip it and use the property name
1636						// and assign the value. If it isn't used, then we get the result we want anyway
1637						data[ aLast.replace(__reArray, '') ] = val;
1638					}
1639				};
1640		
1641				return function (data, val) { // meta is also passed in, but not used
1642					return setData( data, val, source );
1643				};
1644			}
1645			else {
1646				// Array or flat object mapping
1647				return function (data, val) { // meta is also passed in, but not used
1648					data[source] = val;
1649				};
1650			}
1651		},
1652	
1653		/**
1654		 * Create a function that will read nested objects from arrays, based on JSON notation
1655		 * @param {*} source JSON notation string
1656		 * @returns Value read
1657		 */
1658		get: function ( source ) {
1659			if ( $.isPlainObject( source ) ) {
1660				// Build an object of get functions, and wrap them in a single call
1661				var o = {};
1662				$.each( source, function (key, val) {
1663					if ( val ) {
1664						o[key] = DataTable.util.get( val );
1665					}
1666				} );
1667		
1668				return function (data, type, row, meta) {
1669					var t = o[type] || o._;
1670					return t !== undefined ?
1671						t(data, type, row, meta) :
1672						data;
1673				};
1674			}
1675			else if ( source === null ) {
1676				// Give an empty string for rendering / sorting etc
1677				return function (data) { // type, row and meta also passed, but not used
1678					return data;
1679				};
1680			}
1681			else if ( typeof source === 'function' ) {
1682				return function (data, type, row, meta) {
1683					return source( data, type, row, meta );
1684				};
1685			}
1686			else if (
1687				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1688				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1689			) {
1690				/* If there is a . in the source string then the data source is in a
1691				 * nested object so we loop over the data for each level to get the next
1692				 * level down. On each loop we test for undefined, and if found immediately
1693				 * return. This allows entire objects to be missing and sDefaultContent to
1694				 * be used if defined, rather than throwing an error
1695				 */
1696				var fetchData = function (data, type, src) {
1697					var arrayNotation, funcNotation, out, innerSrc;
1698		
1699					if ( src !== "" ) {
1700						var a = _fnSplitObjNotation( src );
1701		
1702						for ( var i=0, iLen=a.length ; i<iLen ; i++ ) {
1703							// Check if we are dealing with special notation
1704							arrayNotation = a[i].match(__reArray);
1705							funcNotation = a[i].match(__reFn);
1706		
1707							if ( arrayNotation ) {
1708								// Array notation
1709								a[i] = a[i].replace(__reArray, '');
1710		
1711								// Condition allows simply [] to be passed in
1712								if ( a[i] !== "" ) {
1713									data = data[ a[i] ];
1714								}
1715								out = [];
1716		
1717								// Get the remainder of the nested object to get
1718								a.splice( 0, i+1 );
1719								innerSrc = a.join('.');
1720		
1721								// Traverse each entry in the array getting the properties requested
1722								if ( Array.isArray( data ) ) {
1723									for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1724										out.push( fetchData( data[j], type, innerSrc ) );
1725									}
1726								}
1727		
1728								// If a string is given in between the array notation indicators, that
1729								// is used to join the strings together, otherwise an array is returned
1730								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1731								data = (join==="") ? out : out.join(join);
1732		
1733								// The inner call to fetchData has already traversed through the remainder
1734								// of the source requested, so we exit from the loop
1735								break;
1736							}
1737							else if ( funcNotation ) {
1738								// Function call
1739								a[i] = a[i].replace(__reFn, '');
1740								data = data[ a[i] ]();
1741								continue;
1742							}
1743		
1744							if (data === null || data[ a[i] ] === null) {
1745								return null;
1746							}
1747							else if ( data === undefined || data[ a[i] ] === undefined ) {
1748								return undefined;
1749							}
1750	
1751							data = data[ a[i] ];
1752						}
1753					}
1754		
1755					return data;
1756				};
1757		
1758				return function (data, type) { // row and meta also passed, but not used
1759					return fetchData( data, type, source );
1760				};
1761			}
1762			else {
1763				// Array or flat object mapping
1764				return function (data) { // row and meta also passed, but not used
1765					return data[source];
1766				};
1767			}
1768		},
1769	
1770		stripHtml: function (mixed) {
1771			var type = typeof mixed;
1772	
1773			if (type === 'function') {
1774				_stripHtml = mixed;
1775				return;
1776			}
1777			else if (type === 'string') {
1778				return _stripHtml(mixed);
1779			}
1780			return mixed;
1781		},
1782	
1783		escapeHtml: function (mixed) {
1784			var type = typeof mixed;
1785	
1786			if (type === 'function') {
1787				_escapeHtml = mixed;
1788				return;
1789			}
1790			else if (type === 'string' || Array.isArray(mixed)) {
1791				return _escapeHtml(mixed);
1792			}
1793			return mixed;
1794		},
1795	
1796		unique: _unique
1797	};
1798	
1799	
1800	
1801	/**
1802	 * Create a mapping object that allows camel case parameters to be looked up
1803	 * for their Hungarian counterparts. The mapping is stored in a private
1804	 * parameter called `_hungarianMap` which can be accessed on the source object.
1805	 *  @param {object} o
1806	 *  @memberof DataTable#oApi
1807	 */
1808	function _fnHungarianMap ( o )
1809	{
1810		var
1811			hungarian = 'a aa ai ao as b fn i m o s ',
1812			match,
1813			newKey,
1814			map = {};
1815	
1816		$.each( o, function (key) {
1817			match = key.match(/^([^A-Z]+?)([A-Z])/);
1818	
1819			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1820			{
1821				newKey = key.replace( match[0], match[2].toLowerCase() );
1822				map[ newKey ] = key;
1823	
1824				if ( match[1] === 'o' )
1825				{
1826					_fnHungarianMap( o[key] );
1827				}
1828			}
1829		} );
1830	
1831		o._hungarianMap = map;
1832	}
1833	
1834	
1835	/**
1836	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1837	 * created by _fnHungarianMap.
1838	 *  @param {object} src The model object which holds all parameters that can be
1839	 *    mapped.
1840	 *  @param {object} user The object to convert from camel case to Hungarian.
1841	 *  @param {boolean} force When set to `true`, properties which already have a
1842	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
1843	 *    won't be.
1844	 *  @memberof DataTable#oApi
1845	 */
1846	function _fnCamelToHungarian ( src, user, force )
1847	{
1848		if ( ! src._hungarianMap ) {
1849			_fnHungarianMap( src );
1850		}
1851	
1852		var hungarianKey;
1853	
1854		$.each( user, function (key) {
1855			hungarianKey = src._hungarianMap[ key ];
1856	
1857			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1858			{
1859				// For objects, we need to buzz down into the object to copy parameters
1860				if ( hungarianKey.charAt(0) === 'o' )
1861				{
1862					// Copy the camelCase options over to the hungarian
1863					if ( ! user[ hungarianKey ] ) {
1864						user[ hungarianKey ] = {};
1865					}
1866					$.extend( true, user[hungarianKey], user[key] );
1867	
1868					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1869				}
1870				else {
1871					user[hungarianKey] = user[ key ];
1872				}
1873			}
1874		} );
1875	}
1876	
1877	/**
1878	 * Map one parameter onto another
1879	 *  @param {object} o Object to map
1880	 *  @param {*} knew The new parameter name
1881	 *  @param {*} old The old parameter name
1882	 */
1883	var _fnCompatMap = function ( o, knew, old ) {
1884		if ( o[ knew ] !== undefined ) {
1885			o[ old ] = o[ knew ];
1886		}
1887	};
1888	
1889	
1890	/**
1891	 * Provide backwards compatibility for the main DT options. Note that the new
1892	 * options are mapped onto the old parameters, so this is an external interface
1893	 * change only.
1894	 *  @param {object} init Object to map
1895	 */
1896	function _fnCompatOpts ( init )
1897	{
1898		_fnCompatMap( init, 'ordering',      'bSort' );
1899		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
1900		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
1901		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1902		_fnCompatMap( init, 'order',         'aaSorting' );
1903		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
1904		_fnCompatMap( init, 'paging',        'bPaginate' );
1905		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
1906		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
1907		_fnCompatMap( init, 'searching',     'bFilter' );
1908	
1909		// Boolean initialisation of x-scrolling
1910		if ( typeof init.sScrollX === 'boolean' ) {
1911			init.sScrollX = init.sScrollX ? '100%' : '';
1912		}
1913		if ( typeof init.scrollX === 'boolean' ) {
1914			init.scrollX = init.scrollX ? '100%' : '';
1915		}
1916	
1917		// Column search objects are in an array, so it needs to be converted
1918		// element by element
1919		var searchCols = init.aoSearchCols;
1920	
1921		if ( searchCols ) {
1922			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1923				if ( searchCols[i] ) {
1924					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1925				}
1926			}
1927		}
1928	
1929		// Enable search delay if server-side processing is enabled
1930		if (init.serverSide && ! init.searchDelay) {
1931			init.searchDelay = 400;
1932		}
1933	}
1934	
1935	
1936	/**
1937	 * Provide backwards compatibility for column options. Note that the new options
1938	 * are mapped onto the old parameters, so this is an external interface change
1939	 * only.
1940	 *  @param {object} init Object to map
1941	 */
1942	function _fnCompatCols ( init )
1943	{
1944		_fnCompatMap( init, 'orderable',     'bSortable' );
1945		_fnCompatMap( init, 'orderData',     'aDataSort' );
1946		_fnCompatMap( init, 'orderSequence', 'asSorting' );
1947		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
1948	
1949		// orderData can be given as an integer
1950		var dataSort = init.aDataSort;
1951		if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {
1952			init.aDataSort = [ dataSort ];
1953		}
1954	}
1955	
1956	
1957	/**
1958	 * Browser feature detection for capabilities, quirks
1959	 *  @param {object} settings dataTables settings object
1960	 *  @memberof DataTable#oApi
1961	 */
1962	function _fnBrowserDetect( settings )
1963	{
1964		// We don't need to do this every time DataTables is constructed, the values
1965		// calculated are specific to the browser and OS configuration which we
1966		// don't expect to change between initialisations
1967		if ( ! DataTable.__browser ) {
1968			var browser = {};
1969			DataTable.__browser = browser;
1970	
1971			// Scrolling feature / quirks detection
1972			var n = $('<div/>')
1973				.css( {
1974					position: 'fixed',
1975					top: 0,
1976					left: -1 * window.pageXOffset, // allow for scrolling
1977					height: 1,
1978					width: 1,
1979					overflow: 'hidden'
1980				} )
1981				.append(
1982					$('<div/>')
1983						.css( {
1984							position: 'absolute',
1985							top: 1,
1986							left: 1,
1987							width: 100,
1988							overflow: 'scroll'
1989						} )
1990						.append(
1991							$('<div/>')
1992								.css( {
1993									width: '100%',
1994									height: 10
1995								} )
1996						)
1997				)
1998				.appendTo( 'body' );
1999	
2000			var outer = n.children();
2001			var inner = outer.children();
2002	
2003			// Get scrollbar width
2004			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
2005	
2006			// In rtl text layout, some browsers (most, but not all) will place the
2007			// scrollbar on the left, rather than the right.
2008			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
2009	
2010			n.remove();
2011		}
2012	
2013		$.extend( settings.oBrowser, DataTable.__browser );
2014		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
2015	}
2016	
2017	/**
2018	 * Add a column to the list used for the table with default values
2019	 *  @param {object} oSettings dataTables settings object
2020	 *  @memberof DataTable#oApi
2021	 */
2022	function _fnAddColumn( oSettings )
2023	{
2024		// Add column to aoColumns array
2025		var oDefaults = DataTable.defaults.column;
2026		var iCol = oSettings.aoColumns.length;
2027		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
2028			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
2029			"mData": oDefaults.mData ? oDefaults.mData : iCol,
2030			idx: iCol,
2031			searchFixed: {},
2032			colEl: $('<col>').attr('data-dt-column', iCol)
2033		} );
2034		oSettings.aoColumns.push( oCol );
2035	
2036		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
2037		// passed into extend can be undefined. This allows the user to give a default
2038		// with only some of the parameters defined, and also not give a default
2039		var searchCols = oSettings.aoPreSearchCols;
2040		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
2041	}
2042	
2043	
2044	/**
2045	 * Apply options for a column
2046	 *  @param {object} oSettings dataTables settings object
2047	 *  @param {int} iCol column index to consider
2048	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
2049	 *  @memberof DataTable#oApi
2050	 */
2051	function _fnColumnOptions( oSettings, iCol, oOptions )
2052	{
2053		var oCol = oSettings.aoColumns[ iCol ];
2054	
2055		/* User specified column options */
2056		if ( oOptions !== undefined && oOptions !== null )
2057		{
2058			// Backwards compatibility
2059			_fnCompatCols( oOptions );
2060	
2061			// Map camel case parameters to their Hungarian counterparts
2062			_fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
2063	
2064			/* Backwards compatibility for mDataProp */
2065			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2066			{
2067				oOptions.mData = oOptions.mDataProp;
2068			}
2069	
2070			if ( oOptions.sType )
2071			{
2072				oCol._sManualType = oOptions.sType;
2073			}
2074		
2075			// `class` is a reserved word in Javascript, so we need to provide
2076			// the ability to use a valid name for the camel case input
2077			if ( oOptions.className && ! oOptions.sClass )
2078			{
2079				oOptions.sClass = oOptions.className;
2080			}
2081	
2082			var origClass = oCol.sClass;
2083	
2084			$.extend( oCol, oOptions );
2085			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2086	
2087			// Merge class from previously defined classes with this one, rather than just
2088			// overwriting it in the extend above
2089			if (origClass !== oCol.sClass) {
2090				oCol.sClass = origClass + ' ' + oCol.sClass;
2091			}
2092	
2093			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
2094			 * priority if defined
2095			 */
2096			if ( oOptions.iDataSort !== undefined )
2097			{
2098				oCol.aDataSort = [ oOptions.iDataSort ];
2099			}
2100			_fnMap( oCol, oOptions, "aDataSort" );
2101		}
2102	
2103		/* Cache the data get and set functions for speed */
2104		var mDataSrc = oCol.mData;
2105		var mData = _fnGetObjectDataFn( mDataSrc );
2106	
2107		// The `render` option can be given as an array to access the helper rendering methods.
2108		// The first element is the rendering method to use, the rest are the parameters to pass
2109		if ( oCol.mRender && Array.isArray( oCol.mRender ) ) {
2110			var copy = oCol.mRender.slice();
2111			var name = copy.shift();
2112	
2113			oCol.mRender = DataTable.render[name].apply(window, copy);
2114		}
2115	
2116		oCol._render = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2117	
2118		var attrTest = function( src ) {
2119			return typeof src === 'string' && src.indexOf('@') !== -1;
2120		};
2121		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2122			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2123		);
2124		oCol._setter = null;
2125	
2126		oCol.fnGetData = function (rowData, type, meta) {
2127			var innerData = mData( rowData, type, undefined, meta );
2128	
2129			return oCol._render && type ?
2130				oCol._render( innerData, type, rowData, meta ) :
2131				innerData;
2132		};
2133		oCol.fnSetData = function ( rowData, val, meta ) {
2134			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2135		};
2136	
2137		// Indicate if DataTables should read DOM data as an object or array
2138		// Used in _fnGetRowElements
2139		if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) {
2140			oSettings._rowReadObject = true;
2141		}
2142	
2143		/* Feature sorting overrides column specific when off */
2144		if ( !oSettings.oFeatures.bSort )
2145		{
2146			oCol.bSortable = false;
2147		}
2148	}
2149	
2150	
2151	/**
2152	 * Adjust the table column widths for new data. Note: you would probably want to
2153	 * do a redraw after calling this function!
2154	 *  @param {object} settings dataTables settings object
2155	 *  @memberof DataTable#oApi
2156	 */
2157	function _fnAdjustColumnSizing ( settings )
2158	{
2159		_fnCalculateColumnWidths( settings );
2160		_fnColumnSizes( settings );
2161	
2162		var scroll = settings.oScroll;
2163		if ( scroll.sY !== '' || scroll.sX !== '') {
2164			_fnScrollDraw( settings );
2165		}
2166	
2167		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
2168	}
2169	
2170	/**
2171	 * Apply column sizes
2172	 *
2173	 * @param {*} settings DataTables settings object
2174	 */
2175	function _fnColumnSizes ( settings )
2176	{
2177		var cols = settings.aoColumns;
2178	
2179		for (var i=0 ; i<cols.length ; i++) {
2180			var width = _fnColumnsSumWidth(settings, [i], false, false);
2181	
2182			cols[i].colEl.css('width', width);
2183		}
2184	}
2185	
2186	
2187	/**
2188	 * Convert the index of a visible column to the index in the data array (take account
2189	 * of hidden columns)
2190	 *  @param {object} oSettings dataTables settings object
2191	 *  @param {int} iMatch Visible column index to lookup
2192	 *  @returns {int} i the data index
2193	 *  @memberof DataTable#oApi
2194	 */
2195	function _fnVisibleToColumnIndex( oSettings, iMatch )
2196	{
2197		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2198	
2199		return typeof aiVis[iMatch] === 'number' ?
2200			aiVis[iMatch] :
2201			null;
2202	}
2203	
2204	
2205	/**
2206	 * Convert the index of an index in the data array and convert it to the visible
2207	 *   column index (take account of hidden columns)
2208	 *  @param {int} iMatch Column index to lookup
2209	 *  @param {object} oSettings dataTables settings object
2210	 *  @returns {int} i the data index
2211	 *  @memberof DataTable#oApi
2212	 */
2213	function _fnColumnIndexToVisible( oSettings, iMatch )
2214	{
2215		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2216		var iPos = aiVis.indexOf(iMatch);
2217	
2218		return iPos !== -1 ? iPos : null;
2219	}
2220	
2221	
2222	/**
2223	 * Get the number of visible columns
2224	 *  @param {object} oSettings dataTables settings object
2225	 *  @returns {int} i the number of visible columns
2226	 *  @memberof DataTable#oApi
2227	 */
2228	function _fnVisbleColumns( settings )
2229	{
2230		var layout = settings.aoHeader;
2231		var columns = settings.aoColumns;
2232		var vis = 0;
2233	
2234		if ( layout.length ) {
2235			for ( var i=0, ien=layout[0].length ; i<ien ; i++ ) {
2236				if ( columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none' ) {
2237					vis++;
2238				}
2239			}
2240		}
2241	
2242		return vis;
2243	}
2244	
2245	
2246	/**
2247	 * Get an array of column indexes that match a given property
2248	 *  @param {object} oSettings dataTables settings object
2249	 *  @param {string} sParam Parameter in aoColumns to look for - typically
2250	 *    bVisible or bSearchable
2251	 *  @returns {array} Array of indexes with matched properties
2252	 *  @memberof DataTable#oApi
2253	 */
2254	function _fnGetColumns( oSettings, sParam )
2255	{
2256		var a = [];
2257	
2258		oSettings.aoColumns.map( function(val, i) {
2259			if ( val[sParam] ) {
2260				a.push( i );
2261			}
2262		} );
2263	
2264		return a;
2265	}
2266	
2267	
2268	/**
2269	 * Calculate the 'type' of a column
2270	 *  @param {object} settings dataTables settings object
2271	 *  @memberof DataTable#oApi
2272	 */
2273	function _fnColumnTypes ( settings )
2274	{
2275		var columns = settings.aoColumns;
2276		var data = settings.aoData;
2277		var types = DataTable.ext.type.detect;
2278		var i, ien, j, jen, k, ken;
2279		var col, detectedType, cache;
2280	
2281		// For each column, spin over the 
2282		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2283			col = columns[i];
2284			cache = [];
2285	
2286			if ( ! col.sType && col._sManualType ) {
2287				col.sType = col._sManualType;
2288			}
2289			else if ( ! col.sType ) {
2290				for ( j=0, jen=types.length ; j<jen ; j++ ) {
2291					for ( k=0, ken=data.length ; k<ken ; k++ ) {
2292	
2293						if (! data[k]) {
2294							continue;
2295						}
2296	
2297						// Use a cache array so we only need to get the type data
2298						// from the formatter once (when using multiple detectors)
2299						if ( cache[k] === undefined ) {
2300							cache[k] = _fnGetCellData( settings, k, i, 'type' );
2301						}
2302	
2303						detectedType = types[j]( cache[k], settings );
2304	
2305						// If null, then this type can't apply to this column, so
2306						// rather than testing all cells, break out. There is an
2307						// exception for the last type which is `html`. We need to
2308						// scan all rows since it is possible to mix string and HTML
2309						// types
2310						if ( ! detectedType && j !== types.length-2 ) {
2311							break;
2312						}
2313	
2314						// Only a single match is needed for html type since it is
2315						// bottom of the pile and very similar to string - but it
2316						// must not be empty
2317						if ( detectedType === 'html' && ! _empty(cache[k]) ) {
2318							break;
2319						}
2320					}
2321	
2322					// Type is valid for all data points in the column - use this
2323					// type
2324					if ( detectedType ) {
2325						col.sType = detectedType;
2326						break;
2327					}
2328				}
2329	
2330				// Fall back - if no type was detected, always use string
2331				if ( ! col.sType ) {
2332					col.sType = 'string';
2333				}
2334			}
2335	
2336			// Set class names for header / footer for auto type classes
2337			var autoClass = _ext.type.className[col.sType];
2338	
2339			if (autoClass) {
2340				_columnAutoClass(settings.aoHeader, i, autoClass);
2341				_columnAutoClass(settings.aoFooter, i, autoClass);
2342			}
2343	
2344			var renderer = _ext.type.render[col.sType];
2345	
2346			// This can only happen once! There is no way to remover
2347			// a renderer. After the first time the renderer has
2348			// already been set so createTr will run the renderer itself.
2349			if (renderer && ! col._render) {
2350				col._render = DataTable.util.get(renderer);
2351	
2352				_columnAutoRender(settings, i);
2353			}
2354		}
2355	}
2356	
2357	/**
2358	 * Apply an auto detected renderer to data which doesn't yet have
2359	 * a renderer
2360	 */
2361	function _columnAutoRender(settings, colIdx) {
2362		var data = settings.aoData;
2363	
2364		for (var i=0 ; i<data.length ; i++) {
2365			if (data[i].nTr) {
2366				// We have to update the display here since there is no
2367				// invalidation check for the data
2368				var display = _fnGetCellData( settings, i, colIdx, 'display' );
2369	
2370				data[i].displayData[colIdx] = display;
2371				_fnWriteCell(data[i].anCells[colIdx], display);
2372	
2373				// No need to update sort / filter data since it has
2374				// been invalidated and will be re-read with the
2375				// renderer now applied
2376			}
2377		}
2378	}
2379	
2380	/**
2381	 * Apply a class name to a column's header cells
2382	 */
2383	function _columnAutoClass(container, colIdx, className) {
2384		container.forEach(function (row) {
2385			if (row[colIdx] && row[colIdx].unique) {
2386				_addClass(row[colIdx].cell, className);
2387			}
2388		});
2389	}
2390	
2391	/**
2392	 * Take the column definitions and static columns arrays and calculate how
2393	 * they relate to column indexes. The callback function will then apply the
2394	 * definition found for a column to a suitable configuration object.
2395	 *  @param {object} oSettings dataTables settings object
2396	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
2397	 *  @param {array} aoCols The aoColumns array that defines columns individually
2398	 *  @param {array} headerLayout Layout for header as it was loaded
2399	 *  @param {function} fn Callback function - takes two parameters, the calculated
2400	 *    column index and the definition for that column.
2401	 *  @memberof DataTable#oApi
2402	 */
2403	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, headerLayout, fn )
2404	{
2405		var i, iLen, j, jLen, k, kLen, def;
2406		var columns = oSettings.aoColumns;
2407	
2408		if ( aoCols ) {
2409			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2410				if (aoCols[i] && aoCols[i].name) {
2411					columns[i].sName = aoCols[i].name;
2412				}
2413			}
2414		}
2415	
2416		// Column definitions with aTargets
2417		if ( aoColDefs )
2418		{
2419			/* Loop over the definitions array - loop in reverse so first instance has priority */
2420			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2421			{
2422				def = aoColDefs[i];
2423	
2424				/* Each definition can target multiple columns, as it is an array */
2425				var aTargets = def.target !== undefined
2426					? def.target
2427					: def.targets !== undefined
2428						? def.targets
2429						: def.aTargets;
2430	
2431				if ( ! Array.isArray( aTargets ) )
2432				{
2433					aTargets = [ aTargets ];
2434				}
2435	
2436				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2437				{
2438					var target = aTargets[j];
2439	
2440					if ( typeof target === 'number' && target >= 0 )
2441					{
2442						/* Add columns that we don't yet know about */
2443						while( columns.length <= target )
2444						{
2445							_fnAddColumn( oSettings );
2446						}
2447	
2448						/* Integer, basic index */
2449						fn( target, def );
2450					}
2451					else if ( typeof target === 'number' && target < 0 )
2452					{
2453						/* Negative integer, right to left column counting */
2454						fn( columns.length+target, def );
2455					}
2456					else if ( typeof target === 'string' )
2457					{
2458						for ( k=0, kLen=columns.length ; k<kLen ; k++ ) {
2459							if (target === '_all') {
2460								// Apply to all columns
2461								fn( k, def );
2462							}
2463							else if (target.indexOf(':name') !== -1) {
2464								// Column selector
2465								if (columns[k].sName === target.replace(':name', '')) {
2466									fn( k, def );
2467								}
2468							}
2469							else {
2470								// Cell selector
2471								headerLayout.forEach(function (row) {
2472									if (row[k]) {
2473										var cell = $(row[k].cell);
2474	
2475										// Legacy support. Note that it means that we don't support
2476										// an element name selector only, since they are treated as
2477										// class names for 1.x compat.
2478										if (target.match(/^[a-z][\w-]*$/i)) {
2479											target = '.' + target;
2480										}
2481	
2482										if (cell.is( target )) {
2483											fn( k, def );
2484										}
2485									}
2486								});
2487							}
2488						}
2489					}
2490				}
2491			}
2492		}
2493	
2494		// Statically defined columns array
2495		if ( aoCols ) {
2496			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2497				fn( i, aoCols[i] );
2498			}
2499		}
2500	}
2501	
2502	
2503	/**
2504	 * Get the width for a given set of columns
2505	 *
2506	 * @param {*} settings DataTables settings object
2507	 * @param {*} targets Columns - comma separated string or array of numbers
2508	 * @param {*} original Use the original width (true) or calculated (false)
2509	 * @param {*} incVisible Include visible columns (true) or not (false)
2510	 * @returns Combined CSS value
2511	 */
2512	function _fnColumnsSumWidth( settings, targets, original, incVisible ) {
2513		if ( ! Array.isArray( targets ) ) {
2514			targets = _fnColumnsFromHeader( targets );
2515		}
2516	
2517		var sum = 0;
2518		var unit;
2519		var columns = settings.aoColumns;
2520		
2521		for ( var i=0, ien=targets.length ; i<ien ; i++ ) {
2522			var column = columns[ targets[i] ];
2523			var definedWidth = original ?
2524				column.sWidthOrig :
2525				column.sWidth;
2526	
2527			if ( ! incVisible && column.bVisible === false ) {
2528				continue;
2529			}
2530	
2531			if ( definedWidth === null || definedWidth === undefined ) {
2532				return null; // can't determine a defined width - browser defined
2533			}
2534			else if ( typeof definedWidth === 'number' ) {
2535				unit = 'px';
2536				sum += definedWidth;
2537			}
2538			else {
2539				var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
2540	
2541				if ( matched ) {
2542					sum += matched[1] * 1;
2543					unit = matched.length === 3 ?
2544						matched[2] :
2545						'px';
2546				}
2547			}
2548		}
2549	
2550		return sum + unit;
2551	}
2552	
2553	function _fnColumnsFromHeader( cell )
2554	{
2555		var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
2556	
2557		if ( ! attr ) {
2558			return [];
2559		}
2560	
2561		return attr.split(',').map( function (val) {
2562			return val * 1;
2563		} );
2564	}
2565	/**
2566	 * Add a data array to the table, creating DOM node etc. This is the parallel to
2567	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2568	 * DOM source.
2569	 *  @param {object} settings dataTables settings object
2570	 *  @param {array} data data array to be added
2571	 *  @param {node} [tr] TR element to add to the table - optional. If not given,
2572	 *    DataTables will create a row automatically
2573	 *  @param {array} [tds] Array of TD|TH elements for the row - must be given
2574	 *    if nTr is.
2575	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2576	 *  @memberof DataTable#oApi
2577	 */
2578	function _fnAddData ( settings, dataIn, tr, tds )
2579	{
2580		/* Create the object for storing information about this new row */
2581		var rowIdx = settings.aoData.length;
2582		var rowModel = $.extend( true, {}, DataTable.models.oRow, {
2583			src: tr ? 'dom' : 'data',
2584			idx: rowIdx
2585		} );
2586	
2587		rowModel._aData = dataIn;
2588		settings.aoData.push( rowModel );
2589	
2590		var columns = settings.aoColumns;
2591	
2592		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2593		{
2594			// Invalidate the column types as the new data needs to be revalidated
2595			columns[i].sType = null;
2596		}
2597	
2598		/* Add to the display array */
2599		settings.aiDisplayMaster.push( rowIdx );
2600	
2601		var id = settings.rowIdFn( dataIn );
2602		if ( id !== undefined ) {
2603			settings.aIds[ id ] = rowModel;
2604		}
2605	
2606		/* Create the DOM information, or register it if already present */
2607		if ( tr || ! settings.oFeatures.bDeferRender )
2608		{
2609			_fnCreateTr( settings, rowIdx, tr, tds );
2610		}
2611	
2612		return rowIdx;
2613	}
2614	
2615	
2616	/**
2617	 * Add one or more TR elements to the table. Generally we'd expect to
2618	 * use this for reading data from a DOM sourced table, but it could be
2619	 * used for an TR element. Note that if a TR is given, it is used (i.e.
2620	 * it is not cloned).
2621	 *  @param {object} settings dataTables settings object
2622	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
2623	 *  @returns {array} Array of indexes for the added rows
2624	 *  @memberof DataTable#oApi
2625	 */
2626	function _fnAddTr( settings, trs )
2627	{
2628		var row;
2629	
2630		// Allow an individual node to be passed in
2631		if ( ! (trs instanceof $) ) {
2632			trs = $(trs);
2633		}
2634	
2635		return trs.map( function (i, el) {
2636			row = _fnGetRowElements( settings, el );
2637			return _fnAddData( settings, row.data, el, row.cells );
2638		} );
2639	}
2640	
2641	
2642	/**
2643	 * Get the data for a given cell from the internal cache, taking into account data mapping
2644	 *  @param {object} settings dataTables settings object
2645	 *  @param {int} rowIdx aoData row id
2646	 *  @param {int} colIdx Column index
2647	 *  @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
2648	 *  @returns {*} Cell data
2649	 *  @memberof DataTable#oApi
2650	 */
2651	function _fnGetCellData( settings, rowIdx, colIdx, type )
2652	{
2653		if (type === 'search') {
2654			type = 'filter';
2655		}
2656		else if (type === 'order') {
2657			type = 'sort';
2658		}
2659	
2660		var row = settings.aoData[rowIdx];
2661	
2662		if (! row) {
2663			return undefined;
2664		}
2665	
2666		var draw           = settings.iDraw;
2667		var col            = settings.aoColumns[colIdx];
2668		var rowData        = row._aData;
2669		var defaultContent = col.sDefaultContent;
2670		var cellData       = col.fnGetData( rowData, type, {
2671			settings: settings,
2672			row:      rowIdx,
2673			col:      colIdx
2674		} );
2675	
2676		// Allow for a node being returned for non-display types
2677		if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
2678			cellData = cellData.innerHTML;
2679		}
2680	
2681		if ( cellData === undefined ) {
2682			if ( settings.iDrawError != draw && defaultContent === null ) {
2683				_fnLog( settings, 0, "Requested unknown parameter "+
2684					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2685					" for row "+rowIdx+", column "+colIdx, 4 );
2686				settings.iDrawError = draw;
2687			}
2688			return defaultContent;
2689		}
2690	
2691		// When the data source is null and a specific data type is requested (i.e.
2692		// not the original data), we can use default column data
2693		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2694			cellData = defaultContent;
2695		}
2696		else if ( typeof cellData === 'function' ) {
2697			// If the data source is a function, then we run it and use the return,
2698			// executing in the scope of the data object (for instances)
2699			return cellData.call( rowData );
2700		}
2701	
2702		if ( cellData === null && type === 'display' ) {
2703			return '';
2704		}
2705	
2706		if ( type === 'filter' ) {
2707			var fomatters = DataTable.ext.type.search;
2708	
2709			if ( fomatters[ col.sType ] ) {
2710				cellData = fomatters[ col.sType ]( cellData );
2711			}
2712		}
2713	
2714		return cellData;
2715	}
2716	
2717	
2718	/**
2719	 * Set the value for a specific cell, into the internal data cache
2720	 *  @param {object} settings dataTables settings object
2721	 *  @param {int} rowIdx aoData row id
2722	 *  @param {int} colIdx Column index
2723	 *  @param {*} val Value to set
2724	 *  @memberof DataTable#oApi
2725	 */
2726	function _fnSetCellData( settings, rowIdx, colIdx, val )
2727	{
2728		var col     = settings.aoColumns[colIdx];
2729		var rowData = settings.aoData[rowIdx]._aData;
2730	
2731		col.fnSetData( rowData, val, {
2732			settings: settings,
2733			row:      rowIdx,
2734			col:      colIdx
2735		}  );
2736	}
2737	
2738	/**
2739	 * Write a value to a cell
2740	 * @param {*} td Cell
2741	 * @param {*} val Value
2742	 */
2743	function _fnWriteCell(td, val)
2744	{
2745		if (val && typeof val === 'object' && val.nodeName) {
2746			$(td)
2747				.empty()
2748				.append(val);
2749		}
2750		else {
2751			td.innerHTML = val;
2752		}
2753	}
2754	
2755	
2756	// Private variable that is used to match action syntax in the data property object
2757	var __reArray = /\[.*?\]$/;
2758	var __reFn = /\(\)$/;
2759	
2760	/**
2761	 * Split string on periods, taking into account escaped periods
2762	 * @param  {string} str String to split
2763	 * @return {array} Split string
2764	 */
2765	function _fnSplitObjNotation( str )
2766	{
2767		var parts = str.match(/(\\.|[^.])+/g) || [''];
2768	
2769		return parts.map( function ( s ) {
2770			return s.replace(/\\\./g, '.');
2771		} );
2772	}
2773	
2774	
2775	/**
2776	 * Return a function that can be used to get data from a source object, taking
2777	 * into account the ability to use nested objects as a source
2778	 *  @param {string|int|function} mSource The data source for the object
2779	 *  @returns {function} Data get function
2780	 *  @memberof DataTable#oApi
2781	 */
2782	var _fnGetObjectDataFn = DataTable.util.get;
2783	
2784	
2785	/**
2786	 * Return a function that can be used to set data from a source object, taking
2787	 * into account the ability to use nested objects as a source
2788	 *  @param {string|int|function} mSource The data source for the object
2789	 *  @returns {function} Data set function
2790	 *  @memberof DataTable#oApi
2791	 */
2792	var _fnSetObjectDataFn = DataTable.util.set;
2793	
2794	
2795	/**
2796	 * Return an array with the full table data
2797	 *  @param {object} oSettings dataTables settings object
2798	 *  @returns array {array} aData Master data array
2799	 *  @memberof DataTable#oApi
2800	 */
2801	function _fnGetDataMaster ( settings )
2802	{
2803		return _pluck( settings.aoData, '_aData' );
2804	}
2805	
2806	
2807	/**
2808	 * Nuke the table
2809	 *  @param {object} oSettings dataTables settings object
2810	 *  @memberof DataTable#oApi
2811	 */
2812	function _fnClearTable( settings )
2813	{
2814		settings.aoData.length = 0;
2815		settings.aiDisplayMaster.length = 0;
2816		settings.aiDisplay.length = 0;
2817		settings.aIds = {};
2818	}
2819	
2820	
2821	/**
2822	 * Mark cached data as invalid such that a re-read of the data will occur when
2823	 * the cached data is next requested. Also update from the data source object.
2824	 *
2825	 * @param {object} settings DataTables settings object
2826	 * @param {int}    rowIdx   Row index to invalidate
2827	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
2828	 *     or 'data'
2829	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
2830	 *     row will be invalidated
2831	 * @memberof DataTable#oApi
2832	 *
2833	 * @todo For the modularisation of v1.11 this will need to become a callback, so
2834	 *   the sort and filter methods can subscribe to it. That will required
2835	 *   initialisation options for sorting, which is why it is not already baked in
2836	 */
2837	function _fnInvalidate( settings, rowIdx, src, colIdx )
2838	{
2839		var row = settings.aoData[ rowIdx ];
2840		var i, ien;
2841	
2842		// Remove the cached data for the row
2843		row._aSortData = null;
2844		row._aFilterData = null;
2845		row.displayData = null;
2846	
2847		// Are we reading last data from DOM or the data object?
2848		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2849			// Read the data from the DOM
2850			row._aData = _fnGetRowElements(
2851					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2852				)
2853				.data;
2854		}
2855		else {
2856			// Reading from data object, update the DOM
2857			var cells = row.anCells;
2858			var display = _fnGetRowDisplay(settings, rowIdx);
2859	
2860			if ( cells ) {
2861				if ( colIdx !== undefined ) {
2862					_fnWriteCell(cells[colIdx], display[colIdx]);
2863				}
2864				else {
2865					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2866						_fnWriteCell(cells[i], display[i]);
2867					}
2868				}
2869			}
2870		}
2871	
2872		// Column specific invalidation
2873		var cols = settings.aoColumns;
2874		if ( colIdx !== undefined ) {
2875			// Type - the data might have changed
2876			cols[ colIdx ].sType = null;
2877	
2878			// Max length string. Its a fairly cheep recalculation, so not worth
2879			// something more complicated
2880			cols[ colIdx ].maxLenString = null;
2881		}
2882		else {
2883			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2884				cols[i].sType = null;
2885				cols[i].maxLenString = null;
2886			}
2887	
2888			// Update DataTables special `DT_*` attributes for the row
2889			_fnRowAttributes( settings, row );
2890		}
2891	}
2892	
2893	
2894	/**
2895	 * Build a data source object from an HTML row, reading the contents of the
2896	 * cells that are in the row.
2897	 *
2898	 * @param {object} settings DataTables settings object
2899	 * @param {node|object} TR element from which to read data or existing row
2900	 *   object from which to re-read the data from the cells
2901	 * @param {int} [colIdx] Optional column index
2902	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2903	 *   parameter should also be given and will be used to write the data into.
2904	 *   Only the column in question will be written
2905	 * @returns {object} Object with two parameters: `data` the data read, in
2906	 *   document order, and `cells` and array of nodes (they can be useful to the
2907	 *   caller, so rather than needing a second traversal to get them, just return
2908	 *   them from here).
2909	 * @memberof DataTable#oApi
2910	 */
2911	function _fnGetRowElements( settings, row, colIdx, d )
2912	{
2913		var
2914			tds = [],
2915			td = row.firstChild,
2916			name, col, i=0, contents,
2917			columns = settings.aoColumns,
2918			objectRead = settings._rowReadObject;
2919	
2920		// Allow the data object to be passed in, or construct
2921		d = d !== undefined ?
2922			d :
2923			objectRead ?
2924				{} :
2925				[];
2926	
2927		var attr = function ( str, td  ) {
2928			if ( typeof str === 'string' ) {
2929				var idx = str.indexOf('@');
2930	
2931				if ( idx !== -1 ) {
2932					var attr = str.substring( idx+1 );
2933					var setter = _fnSetObjectDataFn( str );
2934					setter( d, td.getAttribute( attr ) );
2935				}
2936			}
2937		};
2938	
2939		// Read data from a cell and store into the data object
2940		var cellProcess = function ( cell ) {
2941			if ( colIdx === undefined || colIdx === i ) {
2942				col = columns[i];
2943				contents = (cell.innerHTML).trim();
2944	
2945				if ( col && col._bAttrSrc ) {
2946					var setter = _fnSetObjectDataFn( col.mData._ );
2947					setter( d, contents );
2948	
2949					attr( col.mData.sort, cell );
2950					attr( col.mData.type, cell );
2951					attr( col.mData.filter, cell );
2952				}
2953				else {
2954					// Depending on the `data` option for the columns the data can
2955					// be read to either an object or an array.
2956					if ( objectRead ) {
2957						if ( ! col._setter ) {
2958							// Cache the setter function
2959							col._setter = _fnSetObjectDataFn( col.mData );
2960						}
2961						col._setter( d, contents );
2962					}
2963					else {
2964						d[i] = contents;
2965					}
2966				}
2967			}
2968	
2969			i++;
2970		};
2971	
2972		if ( td ) {
2973			// `tr` element was passed in
2974			while ( td ) {
2975				name = td.nodeName.toUpperCase();
2976	
2977				if ( name == "TD" || name == "TH" ) {
2978					cellProcess( td );
2979					tds.push( td );
2980				}
2981	
2982				td = td.nextSibling;
2983			}
2984		}
2985		else {
2986			// Existing row object passed in
2987			tds = row.anCells;
2988	
2989			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
2990				cellProcess( tds[j] );
2991			}
2992		}
2993	
2994		// Read the ID from the DOM if present
2995		var rowNode = row.firstChild ? row : row.nTr;
2996	
2997		if ( rowNode ) {
2998			var id = rowNode.getAttribute( 'id' );
2999	
3000			if ( id ) {
3001				_fnSetObjectDataFn( settings.rowId )( d, id );
3002			}
3003		}
3004	
3005		return {
3006			data: d,
3007			cells: tds
3008		};
3009	}
3010	
3011	/**
3012	 * Render and cache a row's display data for the columns, if required
3013	 * @returns 
3014	 */
3015	function _fnGetRowDisplay (settings, rowIdx) {
3016		let rowModal = settings.aoData[rowIdx];
3017		let columns = settings.aoColumns;
3018	
3019		if (! rowModal.displayData) {
3020			// Need to render and cache
3021			rowModal.displayData = [];
3022		
3023			for ( var colIdx=0, len=columns.length ; colIdx<len ; colIdx++ ) {
3024				rowModal.displayData.push(
3025					_fnGetCellData( settings, rowIdx, colIdx, 'display' )
3026				);
3027			}
3028		}
3029	
3030		return rowModal.displayData;
3031	}
3032	
3033	/**
3034	 * Create a new TR element (and it's TD children) for a row
3035	 *  @param {object} oSettings dataTables settings object
3036	 *  @param {int} iRow Row to consider
3037	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3038	 *    DataTables will create a row automatically
3039	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
3040	 *    if nTr is.
3041	 *  @memberof DataTable#oApi
3042	 */
3043	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3044	{
3045		var
3046			row = oSettings.aoData[iRow],
3047			rowData = row._aData,
3048			cells = [],
3049			nTr, nTd, oCol,
3050			i, iLen, create,
3051			trClass = oSettings.oClasses.tbody.row;
3052	
3053		if ( row.nTr === null )
3054		{
3055			nTr = nTrIn || document.createElement('tr');
3056	
3057			row.nTr = nTr;
3058			row.anCells = cells;
3059	
3060			_addClass(nTr, trClass);
3061	
3062			/* Use a private property on the node to allow reserve mapping from the node
3063			 * to the aoData array for fast look up
3064			 */
3065			nTr._DT_RowIndex = iRow;
3066	
3067			/* Special parameters can be given by the data source to be used on the row */
3068			_fnRowAttributes( oSettings, row );
3069	
3070			/* Process each column */
3071			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3072			{
3073				oCol = oSettings.aoColumns[i];
3074				create = nTrIn && anTds[i] ? false : true;
3075	
3076				nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
3077	
3078				if (! nTd) {
3079					_fnLog( oSettings, 0, 'Incorrect column count', 18 );
3080				}
3081	
3082				nTd._DT_CellIndex = {
3083					row: iRow,
3084					column: i
3085				};
3086				
3087				cells.push( nTd );
3088				
3089				var display = _fnGetRowDisplay(oSettings, iRow);
3090	
3091				// Need to create the HTML if new, or if a rendering function is defined
3092				if (
3093					create ||
3094					(
3095						(oCol.mRender || oCol.mData !== i) &&
3096						(!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3097					)
3098				) {
3099					_fnWriteCell(nTd, display[i]);
3100				}
3101	
3102				// Visibility - add or remove as required
3103				if ( oCol.bVisible && create )
3104				{
3105					nTr.appendChild( nTd );
3106				}
3107				else if ( ! oCol.bVisible && ! create )
3108				{
3109					nTd.parentNode.removeChild( nTd );
3110				}
3111	
3112				if ( oCol.fnCreatedCell )
3113				{
3114					oCol.fnCreatedCell.call( oSettings.oInstance,
3115						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3116					);
3117				}
3118			}
3119	
3120			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells] );
3121		}
3122		else {
3123			_addClass(row.nTr, trClass);
3124		}
3125	}
3126	
3127	
3128	/**
3129	 * Add attributes to a row based on the special `DT_*` parameters in a data
3130	 * source object.
3131	 *  @param {object} settings DataTables settings object
3132	 *  @param {object} DataTables row object for the row to be modified
3133	 *  @memberof DataTable#oApi
3134	 */
3135	function _fnRowAttributes( settings, row )
3136	{
3137		var tr = row.nTr;
3138		var data = row._aData;
3139	
3140		if ( tr ) {
3141			var id = settings.rowIdFn( data );
3142	
3143			if ( id ) {
3144				tr.id = id;
3145			}
3146	
3147			if ( data.DT_RowClass ) {
3148				// Remove any classes added by DT_RowClass before
3149				var a = data.DT_RowClass.split(' ');
3150				row.__rowc = row.__rowc ?
3151					_unique( row.__rowc.concat( a ) ) :
3152					a;
3153	
3154				$(tr)
3155					.removeClass( row.__rowc.join(' ') )
3156					.addClass( data.DT_RowClass );
3157			}
3158	
3159			if ( data.DT_RowAttr ) {
3160				$(tr).attr( data.DT_RowAttr );
3161			}
3162	
3163			if ( data.DT_RowData ) {
3164				$(tr).data( data.DT_RowData );
3165			}
3166		}
3167	}
3168	
3169	
3170	/**
3171	 * Create the HTML header for the table
3172	 *  @param {object} oSettings dataTables settings object
3173	 *  @memberof DataTable#oApi
3174	 */
3175	function _fnBuildHead( settings, side )
3176	{
3177		var classes = settings.oClasses;
3178		var columns = settings.aoColumns;
3179		var i, ien, row;
3180		var target = side === 'header'
3181			? settings.nTHead
3182			: settings.nTFoot;
3183		var titleProp = side === 'header' ? 'sTitle' : side;
3184	
3185		// Footer might be defined
3186		if (! target) {
3187			return;
3188		}
3189	
3190		// If no cells yet and we have content for them, then create
3191		if (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) {
3192			row = $('tr', target);
3193	
3194			// Add a row if needed
3195			if (! row.length) {
3196				row = $('<tr/>').appendTo(target)
3197			}
3198	
3199			// Add the number of cells needed to make up to the number of columns
3200			if (row.length === 1) {
3201				var cells = $('td, th', row);
3202	
3203				for ( i=cells.length, ien=columns.length ; i<ien ; i++ ) {
3204					$('<th/>')
3205						.html( columns[i][titleProp] || '' )
3206						.appendTo( row );
3207				}
3208			}
3209		}
3210	
3211		var detected = _fnDetectHeader( settings, target, true );
3212	
3213		if (side === 'header') {
3214			settings.aoHeader = detected;
3215		}
3216		else {
3217			settings.aoFooter = detected;
3218		}
3219	
3220		// ARIA role for the rows
3221		$(target).children('tr').attr('role', 'row');
3222	
3223		// Every cell needs to be passed through the renderer
3224		$(target).children('tr').children('th, td')
3225			.each( function () {
3226				_fnRenderer( settings, side )(
3227					settings, $(this), classes
3228				);
3229			} );
3230	}
3231	
3232	/**
3233	 * Build a layout structure for a header or footer
3234	 *
3235	 * @param {*} settings DataTables settings
3236	 * @param {*} source Source layout array
3237	 * @param {*} incColumns What columns should be included
3238	 * @returns Layout array
3239	 */
3240	function _fnHeaderLayout( settings, source, incColumns )
3241	{
3242		var row, column, cell;
3243		var local = [];
3244		var structure = [];
3245		var columns = settings.aoColumns;
3246		var columnCount = columns.length;
3247		var rowspan, colspan;
3248	
3249		if ( ! source ) {
3250			return;
3251		}
3252	
3253		// Default is to work on only visible columns
3254		if ( ! incColumns ) {
3255			incColumns = _range(columnCount)
3256				.filter(function (idx) {
3257					return columns[idx].bVisible;
3258				});
3259		}
3260	
3261		// Make a copy of the master layout array, but with only the columns we want
3262		for ( row=0 ; row<source.length ; row++ ) {
3263			// Remove any columns we haven't selected
3264			local[row] = source[row].slice().filter(function (cell, i) {
3265				return incColumns.includes(i);
3266			});
3267	
3268			// Prep the structure array - it needs an element for each row
3269			structure.push( [] );
3270		}
3271	
3272		for ( row=0 ; row<local.length ; row++ ) {
3273			for ( column=0 ; column<local[row].length ; column++ ) {
3274				rowspan = 1;
3275				colspan = 1;
3276	
3277				// Check to see if there is already a cell (row/colspan) covering our target
3278				// insert point. If there is, then there is nothing to do.
3279				if ( structure[row][column] === undefined ) {
3280					cell = local[row][column].cell;
3281	
3282					// Expand for rowspan
3283					while (
3284						local[row+rowspan] !== undefined &&
3285						local[row][column].cell == local[row+rowspan][column].cell
3286					) {
3287						structure[row+rowspan][column] = null;
3288						rowspan++;
3289					}
3290	
3291					// And for colspan
3292					while (
3293						local[row][column+colspan] !== undefined &&
3294						local[row][column].cell == local[row][column+colspan].cell
3295					) {
3296						// Which also needs to go over rows
3297						for ( var k=0 ; k<rowspan ; k++ ) {
3298							structure[row+k][column+colspan] = null;
3299						}
3300	
3301						colspan++;
3302					}
3303	
3304					var titleSpan = $('span.dt-column-title', cell);
3305	
3306					structure[row][column] = {
3307						cell: cell,
3308						colspan: colspan,
3309						rowspan: rowspan,
3310						title: titleSpan.length
3311							? titleSpan.html()
3312							: $(cell).html()
3313					};
3314				}
3315			}
3316		}
3317	
3318		return structure;
3319	}
3320	
3321	
3322	/**
3323	 * Draw the header (or footer) element based on the column visibility states.
3324	 *
3325	 *  @param object oSettings dataTables settings object
3326	 *  @param array aoSource Layout array from _fnDetectHeader
3327	 *  @memberof DataTable#oApi
3328	 */
3329	function _fnDrawHead( settings, source )
3330	{
3331		var layout = _fnHeaderLayout(settings, source);
3332		var tr, n;
3333	
3334		for ( var row=0 ; row<source.length ; row++ ) {
3335			tr = source[row].row;
3336	
3337			// All cells are going to be replaced, so empty out the row
3338			// Can't use $().empty() as that kills event handlers
3339			if (tr) {
3340				while( (n = tr.firstChild) ) {
3341					tr.removeChild( n );
3342				}
3343			}
3344	
3345			for ( var column=0 ; column<layout[row].length ; column++ ) {
3346				var point = layout[row][column];
3347	
3348				if (point) {
3349					$(point.cell)
3350						.appendTo(tr)
3351						.attr('rowspan', point.rowspan)
3352						.attr('colspan', point.colspan);
3353				}
3354			}
3355		}
3356	}
3357	
3358	
3359	/**
3360	 * Insert the required TR nodes into the table for display
3361	 *  @param {object} oSettings dataTables settings object
3362	 *  @param ajaxComplete true after ajax call to complete rendering
3363	 *  @memberof DataTable#oApi
3364	 */
3365	function _fnDraw( oSettings, ajaxComplete )
3366	{
3367		// Allow for state saving and a custom start position
3368		_fnStart( oSettings );
3369	
3370		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3371		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3372		if ( aPreDraw.indexOf(false) !== -1 )
3373		{
3374			_fnProcessingDisplay( oSettings, false );
3375			return;
3376		}
3377	
3378		var anRows = [];
3379		var iRowCount = 0;
3380		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3381		var aiDisplay = oSettings.aiDisplay;
3382		var iDisplayStart = oSettings._iDisplayStart;
3383		var iDisplayEnd = oSettings.fnDisplayEnd();
3384		var columns = oSettings.aoColumns;
3385		var body = $(oSettings.nTBody);
3386	
3387		oSettings.bDrawing = true;
3388	
3389		/* Server-side processing draw intercept */
3390		if ( !bServerSide )
3391		{
3392			oSettings.iDraw++;
3393		}
3394		else if ( !oSettings.bDestroying && !ajaxComplete)
3395		{
3396			// Show loading message for server-side processing
3397			if (oSettings.iDraw === 0) {
3398				body.empty().append(_emptyRow(oSettings));
3399			}
3400	
3401			_fnAjaxUpdate( oSettings );
3402			return;
3403		}
3404	
3405		if ( aiDisplay.length !== 0 )
3406		{
3407			var iStart = bServerSide ? 0 : iDisplayStart;
3408			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3409	
3410			for ( var j=iStart ; j<iEnd ; j++ )
3411			{
3412				var iDataIndex = aiDisplay[j];
3413				var aoData = oSettings.aoData[ iDataIndex ];
3414				if ( aoData.nTr === null )
3415				{
3416					_fnCreateTr( oSettings, iDataIndex );
3417				}
3418	
3419				var nRow = aoData.nTr;
3420	
3421				// Add various classes as needed
3422				for (var i=0 ; i<columns.length ; i++) {
3423					var col = columns[i];
3424					var td = aoData.anCells[i];
3425	
3426					_addClass(td, _ext.type.className[col.sType]); // auto class
3427					_addClass(td, col.sClass); // column class
3428					_addClass(td, oSettings.oClasses.tbody.cell); // all cells
3429				}
3430	
3431				// Row callback functions - might want to manipulate the row
3432				// iRowCount and j are not currently documented. Are they at all
3433				// useful?
3434				_fnCallbackFire( oSettings, 'aoRowCallback', null,
3435					[nRow, aoData._aData, iRowCount, j, iDataIndex] );
3436	
3437				anRows.push( nRow );
3438				iRowCount++;
3439			}
3440		}
3441		else
3442		{
3443			anRows[ 0 ] = _emptyRow(oSettings);
3444		}
3445	
3446		/* Header and footer callbacks */
3447		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3448			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3449	
3450		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3451			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3452	
3453		// replaceChildren is faster, but only became widespread in 2020,
3454		// so a fall back in jQuery is provided for older browsers.
3455		if (body[0].replaceChildren) {
3456			body[0].replaceChildren.apply(body[0], anRows);
3457		}
3458		else {
3459			body.children().detach();
3460			body.append( $(anRows) );
3461		}
3462	
3463		// Empty table needs a specific class
3464		$(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
3465	
3466		/* Call all required callback functions for the end of a draw */
3467		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings], true );
3468	
3469		/* Draw is complete, sorting and filtering must be as well */
3470		oSettings.bSorted = false;
3471		oSettings.bFiltered = false;
3472		oSettings.bDrawing = false;
3473	}
3474	
3475	
3476	/**
3477	 * Redraw the table - taking account of the various features which are enabled
3478	 *  @param {object} oSettings dataTables settings object
3479	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
3480	 *    the paging is reset to the first page
3481	 *  @memberof DataTable#oApi
3482	 */
3483	function _fnReDraw( settings, holdPosition, recompute )
3484	{
3485		var
3486			features = settings.oFeatures,
3487			sort     = features.bSort,
3488			filter   = features.bFilter;
3489	
3490		if (recompute === undefined || recompute === true) {
3491			if ( sort ) {
3492				_fnSort( settings );
3493			}
3494	
3495			if ( filter ) {
3496				_fnFilterComplete( settings, settings.oPreviousSearch );
3497			}
3498			else {
3499				// No filtering, so we want to just use the display master
3500				settings.aiDisplay = settings.aiDisplayMaster.slice();
3501			}
3502		}
3503	
3504		if ( holdPosition !== true ) {
3505			settings._iDisplayStart = 0;
3506		}
3507	
3508		// Let any modules know about the draw hold position state (used by
3509		// scrolling internally)
3510		settings._drawHold = holdPosition;
3511	
3512		_fnDraw( settings );
3513	
3514		settings._drawHold = false;
3515	}
3516	
3517	
3518	/*
3519	 * Table is empty - create a row with an empty message in it
3520	 */
3521	function _emptyRow ( settings ) {
3522		var oLang = settings.oLanguage;
3523		var zero = oLang.sZeroRecords;
3524		var dataSrc = _fnDataSource( settings );
3525	
3526		if (
3527			(settings.iDraw < 1 && dataSrc === 'ssp') ||
3528			(settings.iDraw <= 1 && dataSrc === 'ajax')
3529		) {
3530			zero = oLang.sLoadingRecords;
3531		}
3532		else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
3533		{
3534			zero = oLang.sEmptyTable;
3535		}
3536	
3537		return $( '<tr/>' )
3538			.append( $('<td />', {
3539				'colSpan': _fnVisbleColumns( settings ),
3540				'class':   settings.oClasses.empty.row
3541			} ).html( zero ) )[0];
3542	}
3543	
3544	
3545	/**
3546	 * Convert a `layout` object given by a user to the object structure needed
3547	 * for the renderer. This is done twice, once for above and once for below
3548	 * the table. Ordering must also be considered.
3549	 *
3550	 * @param {*} settings DataTables settings object
3551	 * @param {*} layout Layout object to convert
3552	 * @param {string} side `top` or `bottom`
3553	 * @returns Converted array structure - one item for each row.
3554	 */
3555	function _layoutArray ( settings, layout, side )
3556	{
3557		var groups = {};
3558	
3559		// Combine into like groups (e.g. `top`, `top2`, etc)
3560		$.each( layout, function ( pos, val ) {
3561			if (val === null) {
3562				return;
3563			}
3564	
3565			var splitPos = pos.replace(/([A-Z])/g, ' $1').split(' ');
3566	
3567			if ( ! groups[ splitPos[0] ] ) {
3568				groups[ splitPos[0] ] = {};
3569			}
3570	
3571			var align = splitPos.length === 1 ?
3572				'full' :
3573				splitPos[1].toLowerCase();
3574			var group = groups[ splitPos[0] ];
3575			var groupRun = function (contents, innerVal) {
3576				// If it is an object, then there can be multiple features contained in it
3577				if ( $.isPlainObject( innerVal ) ) {
3578					Object.keys(innerVal).map(function (key) {
3579						contents.push( {
3580							feature: key,
3581							opts: innerVal[key]
3582						});
3583					});
3584				}
3585				else {
3586					contents.push(innerVal);
3587				}
3588			}
3589	
3590			// Transform to an object with a contents property
3591			if (! group[align] || ! group[align].contents) {
3592				group[align] = { contents: [] };
3593			}
3594	
3595			// Allow for an array or just a single object
3596			if ( Array.isArray(val)) {
3597				for (var i=0 ; i<val.length ; i++) {
3598					groupRun(group[align].contents, val[i]);
3599				}
3600			}
3601			else {
3602				groupRun(group[ align ].contents, val);
3603			}
3604	
3605			// And make contents an array
3606			if ( ! Array.isArray( group[ align ].contents ) ) {
3607				group[ align ].contents = [ group[ align ].contents ];
3608			}
3609		} );
3610	
3611		var filtered = Object.keys(groups)
3612			.map( function ( pos ) {
3613				// Filter to only the side we need
3614				if ( pos.indexOf(side) !== 0 ) {
3615					return null;
3616				}
3617	
3618				return {
3619					name: pos,
3620					val: groups[pos]
3621				};
3622			} )
3623			.filter( function (item) {
3624				return item !== null;
3625			});
3626	
3627		// Order by item identifier
3628		filtered.sort( function ( a, b ) {
3629			var order1 = a.name.replace(/[^0-9]/g, '') * 1;
3630			var order2 = b.name.replace(/[^0-9]/g, '') * 1;
3631	
3632			return order2 - order1;
3633		} );
3634		
3635		if ( side === 'bottom' ) {
3636			filtered.reverse();
3637		}
3638	
3639		// Split into rows
3640		var rows = [];
3641		for ( var i=0, ien=filtered.length ; i<ien ; i++ ) {
3642			if (  filtered[i].val.full ) {
3643				rows.push( { full: filtered[i].val.full } );
3644				_layoutResolve( settings, rows[ rows.length - 1 ] );
3645	
3646				delete filtered[i].val.full;
3647			}
3648	
3649			if ( Object.keys(filtered[i].val).length ) {
3650				rows.push( filtered[i].val );
3651				_layoutResolve( settings, rows[ rows.length - 1 ] );
3652			}
3653		}
3654	
3655		return rows;
3656	}
3657	
3658	
3659	/**
3660	 * Convert the contents of a row's layout object to nodes that can be inserted
3661	 * into the document by a renderer. Execute functions, look up plug-ins, etc.
3662	 *
3663	 * @param {*} settings DataTables settings object
3664	 * @param {*} row Layout object for this row
3665	 */
3666	function _layoutResolve( settings, row ) {
3667		var getFeature = function (feature, opts) {
3668			if ( ! _ext.features[ feature ] ) {
3669				_fnLog( settings, 0, 'Unknown feature: '+ feature );
3670			}
3671	
3672			return _ext.features[ feature ].apply( this, [settings, opts] );
3673		};
3674	
3675		var resolve = function ( item ) {
3676			var line = row[ item ].contents;
3677	
3678			for ( var i=0, ien=line.length ; i<ien ; i++ ) {
3679				if ( ! line[i] ) {
3680					continue;
3681				}
3682				else if ( typeof line[i] === 'string' ) {
3683					line[i] = getFeature( line[i], null );
3684				}
3685				else if ( $.isPlainObject(line[i]) ) {
3686					// If it's an object, it just has feature and opts properties from
3687					// the transform in _layoutArray
3688					line[i] = getFeature(line[i].feature, line[i].opts);
3689				}
3690				else if ( typeof line[i].node === 'function' ) {
3691					line[i] = line[i].node( settings );
3692				}
3693				else if ( typeof line[i] === 'function' ) {
3694					var inst = line[i]( settings );
3695	
3696					line[i] = typeof inst.node === 'function' ?
3697						inst.node() :
3698						inst;
3699				}
3700			}
3701		};
3702	
3703		$.each( row, function ( key ) {
3704			resolve( key );
3705		} );
3706	}
3707	
3708	
3709	/**
3710	 * Add the options to the page HTML for the table
3711	 *  @param {object} settings DataTables settings object
3712	 *  @memberof DataTable#oApi
3713	 */
3714	function _fnAddOptionsHtml ( settings )
3715	{
3716		var classes = settings.oClasses;
3717		var table = $(settings.nTable);
3718	
3719		// Wrapper div around everything DataTables controls
3720		var insert = $('<div/>')
3721			.attr({
3722				id:      settings.sTableId+'_wrapper',
3723				'class': classes.container
3724			})
3725			.insertBefore(table);
3726	
3727		settings.nTableWrapper = insert[0];
3728	
3729		if (settings.sDom) {
3730			// Legacy
3731			_fnLayoutDom(settings, settings.sDom, insert);
3732		}
3733		else {
3734			var top = _layoutArray( settings, settings.layout, 'top' );
3735			var bottom = _layoutArray( settings, settings.layout, 'bottom' );
3736			var renderer = _fnRenderer( settings, 'layout' );
3737		
3738			// Everything above - the renderer will actually insert the contents into the document
3739			top.forEach(function (item) {
3740				renderer( settings, insert, item );
3741			});
3742	
3743			// The table - always the center of attention
3744			renderer( settings, insert, {
3745				full: {
3746					table: true,
3747					contents: [ _fnFeatureHtmlTable(settings) ]
3748				}
3749			} );
3750	
3751			// Everything below
3752			bottom.forEach(function (item) {
3753				renderer( settings, insert, item );
3754			});
3755		}
3756	
3757		// Processing floats on top, so it isn't an inserted feature
3758		_processingHtml( settings );
3759	}
3760	
3761	/**
3762	 * Draw the table with the legacy DOM property
3763	 * @param {*} settings DT settings object
3764	 * @param {*} dom DOM string
3765	 * @param {*} insert Insert point
3766	 */
3767	function _fnLayoutDom( settings, dom, insert )
3768	{
3769		var parts = dom.match(/(".*?")|('.*?')|./g);
3770		var featureNode, option, newNode, next, attr;
3771	
3772		for ( var i=0 ; i<parts.length ; i++ ) {
3773			featureNode = null;
3774			option = parts[i];
3775	
3776			if ( option == '<' ) {
3777				// New container div
3778				newNode = $('<div/>');
3779	
3780				// Check to see if we should append an id and/or a class name to the container
3781				next = parts[i+1];
3782	
3783				if ( next[0] == "'" || next[0] == '"' ) {
3784					attr = next.replace(/['"]/g, '');
3785	
3786					var id = '', className;
3787	
3788					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3789					 * breaks the string into parts and applies them as needed
3790					 */
3791					if ( attr.indexOf('.') != -1 ) {
3792						var split = attr.split('.');
3793	
3794						id = split[0];
3795						className = split[1];
3796					}
3797					else if ( attr[0] == "#" ) {
3798						id = attr;
3799					}
3800					else {
3801						className = attr;
3802					}
3803	
3804					newNode
3805						.attr('id', id.substring(1))
3806						.addClass(className);
3807	
3808					i++; // Move along the position array
3809				}
3810	
3811				insert.append( newNode );
3812				insert = newNode;
3813			}
3814			else if ( option == '>' ) {
3815				// End container div
3816				insert = insert.parent();
3817			}
3818			else if ( option == 't' ) {
3819				// Table
3820				featureNode = _fnFeatureHtmlTable( settings );
3821			}
3822			else
3823			{
3824				DataTable.ext.feature.forEach(function(feature) {
3825					if ( option == feature.cFeature ) {
3826						featureNode = feature.fnInit( settings );
3827					}
3828				});
3829			}
3830	
3831			// Add to the display
3832			if ( featureNode ) {
3833				insert.append( featureNode );
3834			}
3835		}
3836	}
3837	
3838	
3839	/**
3840	 * Use the DOM source to create up an array of header cells. The idea here is to
3841	 * create a layout grid (array) of rows x columns, which contains a reference
3842	 * to the cell that that point in the grid (regardless of col/rowspan), such that
3843	 * any column / row could be removed and the new grid constructed
3844	 *  @param {node} thead The header/footer element for the table
3845	 *  @returns {array} Calculated layout array
3846	 *  @memberof DataTable#oApi
3847	 */
3848	function _fnDetectHeader ( settings, thead, write )
3849	{
3850		var columns = settings.aoColumns;
3851		var rows = $(thead).children('tr');
3852		var row, cell;
3853		var i, k, l, iLen, shifted, column, colspan, rowspan;
3854		var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3855		var layout = [];
3856		var unique;
3857		var shift = function ( a, i, j ) {
3858			var k = a[i];
3859			while ( k[j] ) {
3860				j++;
3861			}
3862			return j;
3863		};
3864	
3865		// We know how many rows there are in the layout - so prep it
3866		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3867			layout.push( [] );
3868		}
3869	
3870		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3871			row = rows[i];
3872			column = 0;
3873	
3874			// For every cell in the row..
3875			cell = row.firstChild;
3876			while ( cell ) {
3877				if (
3878					cell.nodeName.toUpperCase() == 'TD' ||
3879					cell.nodeName.toUpperCase() == 'TH'
3880				) {
3881					var cols = [];
3882	
3883					// Get the col and rowspan attributes from the DOM and sanitise them
3884					colspan = cell.getAttribute('colspan') * 1;
3885					rowspan = cell.getAttribute('rowspan') * 1;
3886					colspan = (!colspan || colspan===0 || colspan===1) ? 1 : colspan;
3887					rowspan = (!rowspan || rowspan===0 || rowspan===1) ? 1 : rows
3887pan;
3888	
3889					// There might be colspan cells already in this row, so shift our target
3890					// accordingly
3891					shifted = shift( layout, i, column );
3892	
3893					// Cache calculation for unique columns
3894					unique = colspan === 1 ?
3895						true :
3896						false;
3897					
3898					// Perform header setup
3899					if ( write ) {
3900						if (unique) {
3901							// Allow column options to be set from HTML attributes
3902							_fnColumnOptions( settings, shifted, $(cell).data() );
3903							
3904							// Get the width for the column. This can be defined from the
3905							// width attribute, style attribute or `columns.width` option
3906							var columnDef = columns[shifted];
3907							var width = cell.getAttribute('width') || null;
3908							var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
3909							if ( t ) {
3910								width = t[1];
3911							}
3912	
3913							columnDef.sWidthOrig = columnDef.sWidth || width;
3914	
3915							if (isHeader) {
3916								// Column title handling - can be user set, or read from the DOM
3917								// This happens before the render, so the original is still in place
3918								if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
3919									cell.innerHTML = columnDef.sTitle;
3920								}
3921	
3922								if (! columnDef.sTitle && unique) {
3923									columnDef.sTitle = _stripHtml(cell.innerHTML);
3924									columnDef.autoTitle = true;
3925								}
3926							}
3927							else {
3928								// Footer specific operations
3929								if (columnDef.footer) {
3930									cell.innerHTML = columnDef.footer;
3931								}
3932							}
3933	
3934							// Fall back to the aria-label attribute on the table header if no ariaTitle is
3935							// provided.
3936							if (! columnDef.ariaTitle) {
3937								columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
3938							}
3939	
3940							// Column specific class names
3941							if ( columnDef.className ) {
3942								$(cell).addClass( columnDef.className );
3943							}
3944						}
3945	
3946						// Wrap the column title so we can write to it in future
3947						if ( $('span.dt-column-title', cell).length === 0) {
3948							$('<span>')
3949								.addClass('dt-column-title')
3950								.append(cell.childNodes)
3951								.appendTo(cell);
3952						}
3953	
3954						if ( isHeader && $('span.dt-column-order', cell).length === 0) {
3955							$('<span>')
3956								.addClass('dt-column-order')
3957								.appendTo(cell);
3958						}
3959					}
3960	
3961					// If there is col / rowspan, copy the information into the layout grid
3962					for ( l=0 ; l<colspan ; l++ ) {
3963						for ( k=0 ; k<rowspan ; k++ ) {
3964							layout[i+k][shifted+l] = {
3965								cell: cell,
3966								unique: unique
3967							};
3968	
3969							layout[i+k].row = row;
3970						}
3971	
3972						cols.push( shifted+l );
3973					}
3974	
3975					// Assign an attribute so spanning cells can still be identified
3976					// as belonging to a column
3977					cell.setAttribute('data-dt-column', _unique(cols).join(','));
3978				}
3979	
3980				cell = cell.nextSibling;
3981			}
3982		}
3983	
3984		return layout;
3985	}
3986	
3987	/**
3988	 * Set the start position for draw
3989	 *  @param {object} oSettings dataTables settings object
3990	 */
3991	function _fnStart( oSettings )
3992	{
3993		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3994		var iInitDisplayStart = oSettings.iInitDisplayStart;
3995	
3996		// Check and see if we have an initial draw position from state saving
3997		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3998		{
3999			oSettings._iDisplayStart = bServerSide ?
4000				iInitDisplayStart :
4001				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
4002					0 :
4003					iInitDisplayStart;
4004	
4005			oSettings.iInitDisplayStart = -1;
4006		}
4007	}
4008	
4009	/**
4010	 * Create an Ajax call based on the table's settings, taking into account that
4011	 * parameters can have multiple forms, and backwards compatibility.
4012	 *
4013	 * @param {object} oSettings dataTables settings object
4014	 * @param {array} data Data to send to the server, required by
4015	 *     DataTables - may be augmented by developer callbacks
4016	 * @param {function} fn Callback function to run when data is obtained
4017	 */
4018	function _fnBuildAjax( oSettings, data, fn )
4019	{
4020		var ajaxData;
4021		var ajax = oSettings.ajax;
4022		var instance = oSettings.oInstance;
4023		var callback = function ( json ) {
4024			var status = oSettings.jqXHR
4025				? oSettings.jqXHR.status
4026				: null;
4027	
4028			if ( json === null || (typeof status === 'number' && status == 204 ) ) {
4029				json = {};
4030				_fnAjaxDataSrc( oSettings, json, [] );
4031			}
4032	
4033			var error = json.error || json.sError;
4034			if ( error ) {
4035				_fnLog( oSettings, 0, error );
4036			}
4037	
4038			oSettings.json = json;
4039	
4040			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
4041			fn( json );
4042		};
4043	
4044		if ( $.isPlainObject( ajax ) && ajax.data )
4045		{
4046			ajaxData = ajax.data;
4047	
4048			var newData = typeof ajaxData === 'function' ?
4049				ajaxData( data, oSettings ) :  // fn can manipulate data or return
4050				ajaxData;                      // an object object or array to merge
4051	
4052			// If the function returned something, use that alone
4053			data = typeof ajaxData === 'function' && newData ?
4054				newData :
4055				$.extend( true, data, newData );
4056	
4057			// Remove the data property as we've resolved it already and don't want
4058			// jQuery to do it again (it is restored at the end of the function)
4059			delete ajax.data;
4060		}
4061	
4062		var baseAjax = {
4063			"url": typeof ajax === 'string' ?
4064				ajax :
4065				'',
4066			"data": data,
4067			"success": callback,
4068			"dataType": "json",
4069			"cache": false,
4070			"type": oSettings.sServerMethod,
4071			"error": function (xhr, error) {
4072				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
4073	
4074				if ( ret.indexOf(true) === -1 ) {
4075					if ( error == "parsererror" ) {
4076						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
4077					}
4078					else if ( xhr.readyState === 4 ) {
4079						_fnLog( oSettings, 0, 'Ajax error', 7 );
4080					}
4081				}
4082	
4083				_fnProcessingDisplay( oSettings, false );
4084			}
4085		};
4086	
4087		// If `ajax` option is an object, extend and override our default base
4088		if ( $.isPlainObject( ajax ) ) {
4089			$.extend( baseAjax, ajax )
4090		}
4091	
4092		// Store the data submitted for the API
4093		oSettings.oAjaxData = data;
4094	
4095		// Allow plug-ins and external processes to modify the data
4096		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4097	
4098		if ( typeof ajax === 'function' )
4099		{
4100			// Is a function - let the caller define what needs to be done
4101			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
4102		}
4103		else if (ajax.url === '') {
4104			// No url, so don't load any data. Just apply an empty data array
4105			// to the object for the callback.
4106			var empty = {};
4107	
4108			DataTable.util.set(ajax.dataSrc)(empty, []);
4109			callback(empty);
4110		}
4111		else {
4112			// Object to extend the base settings
4113			oSettings.jqXHR = $.ajax( baseAjax );
4114	
4115			// Restore for next time around
4116			if ( ajaxData ) {
4117				ajax.data = ajaxData;
4118			}
4119		}
4120	}
4121	
4122	
4123	/**
4124	 * Update the table using an Ajax call
4125	 *  @param {object} settings dataTables settings object
4126	 *  @returns {boolean} Block the table drawing or not
4127	 *  @memberof DataTable#oApi
4128	 */
4129	function _fnAjaxUpdate( settings )
4130	{
4131		settings.iDraw++;
4132		_fnProcessingDisplay( settings, true );
4133	
4134		_fnBuildAjax(
4135			settings,
4136			_fnAjaxParameters( settings ),
4137			function(json) {
4138				_fnAjaxUpdateDraw( settings, json );
4139			}
4140		);
4141	}
4142	
4143	
4144	/**
4145	 * Build up the parameters in an object needed for a server-side processing
4146	 * request.
4147	 *  @param {object} oSettings dataTables settings object
4148	 *  @returns {bool} block the table drawing or not
4149	 *  @memberof DataTable#oApi
4150	 */
4151	function _fnAjaxParameters( settings )
4152	{
4153		var
4154			columns = settings.aoColumns,
4155			features = settings.oFeatures,
4156			preSearch = settings.oPreviousSearch,
4157			preColSearch = settings.aoPreSearchCols,
4158			colData = function ( idx, prop ) {
4159				return typeof columns[idx][prop] === 'function' ?
4160					'function' :
4161					columns[idx][prop];
4162			};
4163	
4164		return {
4165			draw: settings.iDraw,
4166			columns: columns.map( function ( column, i ) {
4167				return {
4168					data: colData(i, 'mData'),
4169					name: column.sName,
4170					searchable: column.bSearchable,
4171					orderable: column.bSortable,
4172					search: {
4173						value: preColSearch[i].search,
4174						regex: preColSearch[i].regex,
4175						fixed: Object.keys(column.searchFixed).map( function(name) {
4176							return {
4177								name: name,
4178								term: column.searchFixed[name].toString()
4179							}
4180						})
4181					}
4182				};
4183			} ),
4184			order: _fnSortFlatten( settings ).map( function ( val ) {
4185				return {
4186					column: val.col,
4187					dir: val.dir,
4188					name: colData(val.col, 'sName')
4189				};
4190			} ),
4191			start: settings._iDisplayStart,
4192			length: features.bPaginate ?
4193				settings._iDisplayLength :
4194				-1,
4195			search: {
4196				value: preSearch.search,
4197				regex: preSearch.regex,
4198				fixed: Object.keys(settings.searchFixed).map( function(name) {
4199					return {
4200						name: name,
4201						term: settings.searchFixed[name].toString()
4202					}
4203				})
4204			}
4205		};
4206	}
4207	
4208	
4209	/**
4210	 * Data the data from the server (nuking the old) and redraw the table
4211	 *  @param {object} oSettings dataTables settings object
4212	 *  @param {object} json json data return from the server.
4213	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
4214	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4215	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4216	 *  @param {array} json.aaData The data to display on this page
4217	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4218	 *  @memberof DataTable#oApi
4219	 */
4220	function _fnAjaxUpdateDraw ( settings, json )
4221	{
4222		var data = _fnAjaxDataSrc(settings, json);
4223		var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
4224		var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
4225		var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
4226	
4227		if ( draw !== undefined ) {
4228			// Protect against out of sequence returns
4229			if ( draw*1 < settings.iDraw ) {
4230				return;
4231			}
4232			settings.iDraw = draw * 1;
4233		}
4234	
4235		// No data in returned object, so rather than an array, we show an empty table
4236		if ( ! data ) {
4237			data = [];
4238		}
4239	
4240		_fnClearTable( settings );
4241		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
4242		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4243	
4244		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4245			_fnAddData( settings, data[i] );
4246		}
4247		settings.aiDisplay = settings.aiDisplayMaster.slice();
4248	
4249		_fnDraw( settings, true );
4250		_fnInitComplete( settings );
4251		_fnProcessingDisplay( settings, false );
4252	}
4253	
4254	
4255	/**
4256	 * Get the data from the JSON data source to use for drawing a table. Using
4257	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4258	 * source object, or from a processing function.
4259	 *  @param {object} settings dataTables settings object
4260	 *  @param  {object} json Data source object / array from the server
4261	 *  @return {array} Array of data to use
4262	 */
4263	function _fnAjaxDataSrc ( settings, json, write )
4264	{
4265		var dataProp = 'data';
4266	
4267		if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
4268			// Could in inside a `dataSrc` object, or not!
4269			var dataSrc = settings.ajax.dataSrc;
4270	
4271			// string, function and object are valid types
4272			if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
4273				dataProp = dataSrc;
4274			}
4275			else if (dataSrc.data !== undefined) {
4276				dataProp = dataSrc.data;
4277			}
4278		}
4279	
4280		if ( ! write ) {
4281			if ( dataProp === 'data' ) {
4282				// If the default, then we still want to support the old style, and safely ignore
4283				// it if possible
4284				return json.aaData || json[dataProp];
4285			}
4286	
4287			return dataProp !== "" ?
4288				_fnGetObjectDataFn( dataProp )( json ) :
4289				json;
4290		}
4291		
4292		// set
4293		_fnSetObjectDataFn( dataProp )( json, write );
4294	}
4295	
4296	/**
4297	 * Very similar to _fnAjaxDataSrc, but for the other SSP properties
4298	 * @param {*} settings DataTables settings object
4299	 * @param {*} param Target parameter
4300	 * @param {*} json JSON data
4301	 * @returns Resolved value
4302	 */
4303	function _fnAjaxDataSrcParam (settings, param, json) {
4304		var dataSrc = $.isPlainObject( settings.ajax )
4305			? settings.ajax.dataSrc
4306			: null;
4307	
4308		if (dataSrc && dataSrc[param]) {
4309			// Get from custom location
4310			return _fnGetObjectDataFn( dataSrc[param] )( json );
4311		}
4312	
4313		// else - Default behaviour
4314		var old = '';
4315	
4316		// Legacy support
4317		if (param === 'draw') {
4318			old = 'sEcho';
4319		}
4320		else if (param === 'recordsTotal') {
4321			old = 'iTotalRecords';
4322		}
4323		else if (param === 'recordsFiltered') {
4324			old = 'iTotalDisplayRecords';
4325		}
4326	
4327		return json[old] !== undefined
4328			? json[old]
4329			: json[param];
4330	}
4331	
4332	
4333	/**
4334	 * Filter the table using both the global filter and column based filtering
4335	 *  @param {object} settings dataTables settings object
4336	 *  @param {object} input search information
4337	 *  @memberof DataTable#oApi
4338	 */
4339	function _fnFilterComplete ( settings, input )
4340	{
4341		var columnsSearch = settings.aoPreSearchCols;
4342	
4343		// Resolve any column types that are unknown due to addition or invalidation
4344		// @todo As per sort - can this be moved into an event handler?
4345		_fnColumnTypes( settings );
4346	
4347		// In server-side processing all filtering is done by the server, so no point hanging around here
4348		if ( _fnDataSource( settings ) != 'ssp' )
4349		{
4350			// Check if any of the rows were invalidated
4351			_fnFilterData( settings );
4352	
4353			// Start from the full data set
4354			settings.aiDisplay = settings.aiDisplayMaster.slice();
4355	
4356			// Global filter first
4357			_fnFilter( settings.aiDisplay, settings, input.search, input );
4358	
4359			$.each(settings.searchFixed, function (name, term) {
4360				_fnFilter(settings.aiDisplay, settings, term, {});
4361			});
4362	
4363			// Then individual column filters
4364			for ( var i=0 ; i<columnsSearch.length ; i++ )
4365			{
4366				var col = columnsSearch[i];
4367	
4368				_fnFilter(
4369					settings.aiDisplay,
4370					settings,
4371					col.search,
4372					col,
4373					i
4374				);
4375	
4376				$.each(settings.aoColumns[i].searchFixed, function (name, term) {
4377					_fnFilter(settings.aiDisplay, settings, term, {}, i);
4378				});
4379			}
4380	
4381			// And finally global filtering
4382			_fnFilterCustom( settings );
4383		}
4384	
4385		// Tell the draw function we have been filtering
4386		settings.bFiltered = true;
4387	
4388		_fnCallbackFire( settings, null, 'search', [settings] );
4389	}
4390	
4391	
4392	/**
4393	 * Apply custom filtering functions
4394	 * 
4395	 * This is legacy now that we have named functions, but it is widely used
4396	 * from 1.x, so it is not yet deprecated.
4397	 *  @param {object} oSettings dataTables settings object
4398	 *  @memberof DataTable#oApi
4399	 */
4400	function _fnFilterCustom( settings )
4401	{
4402		var filters = DataTable.ext.search;
4403		var displayRows = settings.aiDisplay;
4404		var row, rowIdx;
4405	
4406		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4407			var rows = [];
4408	
4409			// Loop over each row and see if it should be included
4410			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4411				rowIdx = displayRows[ j ];
4412				row = settings.aoData[ rowIdx ];
4413	
4414				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4415					rows.push( rowIdx );
4416				}
4417			}
4418	
4419			// So the array reference doesn't break set the results into the
4420			// existing array
4421			displayRows.length = 0;
4422			displayRows.push.apply(displayRows, rows);
4423		}
4424	}
4425	
4426	
4427	/**
4428	 * Filter the data table based on user input and draw the table
4429	 */
4430	function _fnFilter( searchRows, settings, input, options, column )
4431	{
4432		if ( input === '' ) {
4433			return;
4434		}
4435	
4436		var i = 0;
4437		var matched = [];
4438	
4439		// Search term can be a function, regex or string - if a string we apply our
4440		// smart filtering regex (assuming the options require that)
4441		var searchFunc = typeof input === 'function' ? input : null;
4442		var rpSearch = input instanceof RegExp
4443			? input
4444			: searchFunc
4445				? null
4446				: _fnFilterCreateSearch( input, options );
4447	
4448		// Then for each row, does the test pass. If not, lop the row from the array
4449		for (i=0 ; i<searchRows.length ; i++) {
4450			var row = settings.aoData[ searchRows[i] ];
4451			var data = column === undefined
4452				? row._sFilterRow
4453				: row._aFilterData[ column ];
4454	
4455			if ( (searchFunc && searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && rpSearch.test(data)) ) {
4456				matched.push(searchRows[i]);
4457			}
4458		}
4459	
4460		// Mutate the searchRows array
4461		searchRows.length = matched.length;
4462	
4463		for (i=0 ; i<matched.length ; i++) {
4464			searchRows[i] = matched[i];
4465		}
4466	}
4467	
4468	
4469	/**
4470	 * Build a regular expression object suitable for searching a table
4471	 *  @param {string} sSearch string to search for
4472	 *  @param {bool} bRegex treat as a regular expression or not
4473	 *  @param {bool} bSmart perform smart filtering or not
4474	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4475	 *  @returns {RegExp} constructed object
4476	 *  @memberof DataTable#oApi
4477	 */
4478	function _fnFilterCreateSearch( search, inOpts )
4479	{
4480		var not = [];
4481		var options = $.extend({}, {
4482			boundary: false,
4483			caseInsensitive: true,
4484			exact: false,
4485			regex: false,
4486			smart: true
4487		}, inOpts);
4488	
4489		if (typeof search !== 'string') {
4490			search = search.toString();
4491		}
4492	
4493		// Remove diacritics if normalize is set up to do so
4494		search = _normalize(search);
4495	
4496		if (options.exact) {
4497			return new RegExp(
4498				'^'+_fnEscapeRegex(search)+'$',
4499				options.caseInsensitive ? 'i' : ''
4500			);
4501		}
4502	
4503		search = options.regex ?
4504			search :
4505			_fnEscapeRegex( search );
4506		
4507		if ( options.smart ) {
4508			/* For smart filtering we want to allow the search to work regardless of
4509			 * word order. We also want double quoted text to be preserved, so word
4510			 * order is important - a la google. And a negative look around for
4511			 * finding rows which don't contain a given string.
4512			 * 
4513			 * So this is the sort of thing we want to generate:
4514			 * 
4515			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4516			 */
4517			var parts = search.match( /!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''];
4518			var a = parts.map( function ( word ) {
4519				var negative = false;
4520				var m;
4521	
4522				// Determine if it is a "does not include"
4523				if ( word.charAt(0) === '!' ) {
4524					negative = true;
4525					word = word.substring(1);
4526				}
4527	
4528				// Strip the quotes from around matched phrases
4529				if ( word.charAt(0) === '"' ) {
4530					m = word.match( /^"(.*)"$/ );
4531					word = m ? m[1] : word;
4532				}
4533				else if ( word.charAt(0) === '\u201C' ) {
4534					// Smart quote match (iPhone users)
4535					m = word.match( /^\u201C(.*)\u201D$/ );
4536					word = m ? m[1] : word;
4537				}
4538	
4539				// For our "not" case, we need to modify the string that is
4540				// allowed to match at the end of the expression.
4541				if (negative) {
4542					if (word.length > 1) {
4543						not.push('(?!'+word+')');
4544					}
4545	
4546					word = '';
4547				}
4548	
4549				return word.replace(/"/g, '');
4550			} );
4551	
4552			var match = not.length
4553				? not.join('')
4554				: '';
4555	
4556			var boundary = options.boundary
4557				? '\\b'
4558				: '';
4559	
4560			search = '^(?=.*?'+boundary+a.join( ')(?=.*?'+boundary )+')('+match+'.)*$';
4561		}
4562	
4563		return new RegExp( search, options.caseInsensitive ? 'i' : '' );
4564	}
4565	
4566	
4567	/**
4568	 * Escape a string such that it can be used in a regular expression
4569	 *  @param {string} sVal string to escape
4570	 *  @returns {string} escaped string
4571	 *  @memberof DataTable#oApi
4572	 */
4573	var _fnEscapeRegex = DataTable.util.escapeRegex;
4574	
4575	var __filter_div = $('<div>')[0];
4576	var __filter_div_textContent = __filter_div.textContent !== undefined;
4577	
4578	// Update the filtering data for each row if needed (by invalidation or first run)
4579	function _fnFilterData ( settings )
4580	{
4581		var columns = settings.aoColumns;
4582		var data = settings.aoData;
4583		var column;
4584		var j, jen, filterData, cellData, row;
4585		var wasInvalidated = false;
4586	
4587		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
4588			if (! data[rowIdx]) {
4589				continue;
4590			}
4591	
4592			row = data[rowIdx];
4593	
4594			if ( ! row._aFilterData ) {
4595				filterData = [];
4596	
4597				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4598					column = columns[j];
4599	
4600					if ( column.bSearchable ) {
4601						cellData = _fnGetCellData( settings, rowIdx, j, 'filter' );
4602	
4603						// Search in DataTables is string based
4604						if ( cellData === null ) {
4605							cellData = '';
4606						}
4607	
4608						if ( typeof cellData !== 'string' && cellData.toString ) {
4609							cellData = cellData.toString();
4610						}
4611					}
4612					else {
4613						cellData = '';
4614					}
4615	
4616					// If it looks like there is an HTML entity in the string,
4617					// attempt to decode it so sorting works as expected. Note that
4618					// we could use a single line of jQuery to do this, but the DOM
4619					// method used here is much faster https://jsperf.com/html-decode
4620					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4621						__filter_div.innerHTML = cellData;
4622						cellData = __filter_div_textContent ?
4623							__filter_div.textContent :
4624							__filter_div.innerText;
4625					}
4626	
4627					if ( cellData.replace ) {
4628						cellData = cellData.replace(/[\r\n\u2028]/g, '');
4629					}
4630	
4631					filterData.push( cellData );
4632				}
4633	
4634				row._aFilterData = filterData;
4635				row._sFilterRow = filterData.join('  ');
4636				wasInvalidated = true;
4637			}
4638		}
4639	
4640		return wasInvalidated;
4641	}
4642	
4643	
4644	/**
4645	 * Draw the table for the first time, adding all required features
4646	 *  @param {object} settings dataTables settings object
4647	 *  @memberof DataTable#oApi
4648	 */
4649	function _fnInitialise ( settings )
4650	{
4651		var i, iAjaxStart=settings.iInitDisplayStart;
4652	
4653		/* Ensure that the table data is fully initialised */
4654		if ( ! settings.bInitialised ) {
4655			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4656			return;
4657		}
4658	
4659		/* Build and draw the header / footer for the table */
4660		_fnBuildHead( settings, 'header' );
4661		_fnBuildHead( settings, 'footer' );
4662		_fnDrawHead( settings, settings.aoHeader );
4663		_fnDrawHead( settings, settings.aoFooter );
4664	
4665		// Enable features
4666		_fnAddOptionsHtml( settings );
4667		_fnSortInit( settings );
4668	
4669		_colGroup( settings );
4670	
4671		/* Okay to show that something is going on now */
4672		_fnProcessingDisplay( settings, true );
4673	
4674		_fnCallbackFire( settings, null, 'preInit', [settings], true );
4675	
4676		// If there is default sorting required - let's do it. The sort function
4677		// will do the drawing for us. Otherwise we draw the table regardless of the
4678		// Ajax source - this allows the table to look initialised for Ajax sourcing
4679		// data (show 'loading' message possibly)
4680		_fnReDraw( settings );
4681	
4682		var dataSrc = _fnDataSource( settings );
4683	
4684		// Server-side processing init complete is done by _fnAjaxUpdateDraw
4685		if ( dataSrc != 'ssp' ) {
4686			// if there is an ajax source load the data
4687			if ( dataSrc == 'ajax' ) {
4688				_fnBuildAjax( settings, {}, function(json) {
4689					var aData = _fnAjaxDataSrc( settings, json );
4690	
4691					// Got the data - add it to the table
4692					for ( i=0 ; i<aData.length ; i++ ) {
4693						_fnAddData( settings, aData[i] );
4694					}
4695	
4696					// Reset the init display for cookie saving. We've already done
4697					// a filter, and therefore cleared it before. So we need to make
4698					// it appear 'fresh'
4699					settings.iInitDisplayStart = iAjaxStart;
4700	
4701					_fnReDraw( settings );
4702					_fnProcessingDisplay( settings, false );
4703					_fnInitComplete( settings );
4704				}, settings );
4705			}
4706			else {
4707				_fnInitComplete( settings );
4708				_fnProcessingDisplay( settings, false );
4709			}
4710		}
4711	}
4712	
4713	
4714	/**
4715	 * Draw the table for the first time, adding all required features
4716	 *  @param {object} settings dataTables settings object
4717	 *  @memberof DataTable#oApi
4718	 */
4719	function _fnInitComplete ( settings )
4720	{
4721		if (settings._bInitComplete) {
4722			return;
4723		}
4724	
4725		var args = [settings, settings.json];
4726	
4727		settings._bInitComplete = true;
4728	
4729		// Table is fully set up and we have data, so calculate the
4730		// column widths
4731		_fnAdjustColumnSizing( settings );
4732	
4733		_fnCallbackFire( settings, null, 'plugin-init', args, true );
4734		_fnCallbackFire( settings, 'aoInitComplete', 'init', args, true );
4735	}
4736	
4737	function _fnLengthChange ( settings, val )
4738	{
4739		var len = parseInt( val, 10 );
4740		settings._iDisplayLength = len;
4741	
4742		_fnLengthOverflow( settings );
4743	
4744		// Fire length change event
4745		_fnCallbackFire( settings, null, 'length', [settings, len] );
4746	}
4747	
4748	/**
4749	 * Alter the display settings to change the page
4750	 *  @param {object} settings DataTables settings object
4751	 *  @param {string|int} action Paging action to take: "first", "previous",
4752	 *    "next" or "last" or page number to jump to (integer)
4753	 *  @param [bool] redraw Automatically draw the update or not
4754	 *  @returns {bool} true page has changed, false - no change
4755	 *  @memberof DataTable#oApi
4756	 */
4757	function _fnPageChange ( settings, action, redraw )
4758	{
4759		var
4760			start     = settings._iDisplayStart,
4761			len       = settings._iDisplayLength,
4762			records   = settings.fnRecordsDisplay();
4763	
4764		if ( records === 0 || len === -1 )
4765		{
4766			start = 0;
4767		}
4768		else if ( typeof action === "number" )
4769		{
4770			start = action * len;
4771	
4772			if ( start > records )
4773			{
4774				start = 0;
4775			}
4776		}
4777		else if ( action == "first" )
4778		{
4779			start = 0;
4780		}
4781		else if ( action == "previous" )
4782		{
4783			start = len >= 0 ?
4784				start - len :
4785				0;
4786	
4787			if ( start < 0 )
4788			{
4789				start = 0;
4790			}
4791		}
4792		else if ( action == "next" )
4793		{
4794			if ( start + len < records )
4795			{
4796				start += len;
4797			}
4798		}
4799		else if ( action == "last" )
4800		{
4801			start = Math.floor( (records-1) / len) * len;
4802		}
4803		else if ( action === 'ellipsis' )
4804		{
4805			return;
4806		}
4807		else
4808		{
4809			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4810		}
4811	
4812		var changed = settings._iDisplayStart !== start;
4813		settings._iDisplayStart = start;
4814	
4815		_fnCallbackFire( settings, null, changed ? 'page' : 'page-nc', [settings] );
4816	
4817		if ( changed && redraw ) {
4818			_fnDraw( settings );
4819		}
4820	
4821		return changed;
4822	}
4823	
4824	
4825	/**
4826	 * Generate the node required for the processing node
4827	 *  @param {object} settings DataTables settings object
4828	 */
4829	function _processingHtml ( settings )
4830	{
4831		var table = settings.nTable;
4832		var scrolling = settings.oScroll.sX !== '' || settings.oScroll.sY !== '';
4833	
4834		if ( settings.oFeatures.bProcessing ) {
4835			var n = $('<div/>', {
4836					'id': settings.sTableId + '_processing',
4837					'class': settings.oClasses.processing.container,
4838					'role': 'status'
4839				} )
4840				.html( settings.oLanguage.sProcessing )
4841				.append('<div><div></div><div></div><div></div><div></div></div>');
4842	
4843			// Different positioning depending on if scrolling is enabled or not
4844			if (scrolling) {
4845				n.prependTo( $('div.dt-scroll', settings.nTableWrapper) );
4846			}
4847			else {
4848				n.insertBefore( table );
4849			}
4850	
4851			$(table).on( 'processing.dt.DT', function (e, s, show) {
4852				n.css( 'display', show ? 'block' : 'none' );
4853			} );
4854		}
4855	}
4856	
4857	
4858	/**
4859	 * Display or hide the processing indicator
4860	 *  @param {object} settings DataTables settings object
4861	 *  @param {bool} show Show the processing indicator (true) or not (false)
4862	 */
4863	function _fnProcessingDisplay ( settings, show )
4864	{
4865		_fnCallbackFire( settings, null, 'processing', [settings, show] );
4866	}
4867	/**
4868	 * Add any control elements for the table - specifically scrolling
4869	 *  @param {object} settings dataTables settings object
4870	 *  @returns {node} Node to add to the DOM
4871	 *  @memberof DataTable#oApi
4872	 */
4873	function _fnFeatureHtmlTable ( settings )
4874	{
4875		var table = $(settings.nTable);
4876	
4877		// Scrolling from here on in
4878		var scroll = settings.oScroll;
4879	
4880		if ( scroll.sX === '' && scroll.sY === '' ) {
4881			return settings.nTable;
4882		}
4883	
4884		var scrollX = scroll.sX;
4885		var scrollY = scroll.sY;
4886		var classes = settings.oClasses.scrolling;
4887		var caption = settings.captionNode;
4888		var captionSide = caption ? caption._captionSide : null;
4889		var headerClone = $( table[0].cloneNode(false) );
4890		var footerClone = $( table[0].cloneNode(false) );
4891		var footer = table.children('tfoot');
4892		var _div = '<div/>';
4893		var size = function ( s ) {
4894			return !s ? null : _fnStringToCss( s );
4895		};
4896	
4897		if ( ! footer.length ) {
4898			footer = null;
4899		}
4900	
4901		/*
4902		 * The HTML structure that we want to generate in this function is:
4903		 *  div - scroller
4904		 *    div - scroll head
4905		 *      div - scroll head inner
4906		 *        table - scroll head table
4907		 *          thead - thead
4908		 *    div - scroll body
4909		 *      table - table (master table)
4910		 *        thead - thead clone for sizing
4911		 *        tbody - tbody
4912		 *    div - scroll foot
4913		 *      div - scroll foot inner
4914		 *        table - scroll foot table
4915		 *          tfoot - tfoot
4916		 */
4917		var scroller = $( _div, { 'class': classes.container } )
4918			.append(
4919				$(_div, { 'class': classes.header.self } )
4920					.css( {
4921						overflow: 'hidden',
4922						position: 'relative',
4923						border: 0,
4924						width: scrollX ? size(scrollX) : '100%'
4925					} )
4926					.append(
4927						$(_div, { 'class': classes.header.inner } )
4928							.css( {
4929								'box-sizing': 'content-box',
4930								width: scroll.sXInner || '100%'
4931							} )
4932							.append(
4933								headerClone
4934									.removeAttr('id')
4935									.css( 'margin-left', 0 )
4936									.append( captionSide === 'top' ? caption : null )
4937									.append(
4938										table.children('thead')
4939									)
4940							)
4941					)
4942			)
4943			.append(
4944				$(_div, { 'class': classes.body } )
4945					.css( {
4946						position: 'relative',
4947						overflow: 'auto',
4948						width: size( scrollX )
4949					} )
4950					.append( table )
4951			);
4952	
4953		if ( footer ) {
4954			scroller.append(
4955				$(_div, { 'class': classes.footer.self } )
4956					.css( {
4957						overflow: 'hidden',
4958						border: 0,
4959						width: scrollX ? size(scrollX) : '100%'
4960					} )
4961					.append(
4962						$(_div, { 'class': classes.footer.inner } )
4963							.append(
4964								footerClone
4965									.removeAttr('id')
4966									.css( 'margin-left', 0 )
4967									.append( captionSide === 'bottom' ? caption : null )
4968									.append(
4969										table.children('tfoot')
4970									)
4971							)
4972					)
4973			);
4974		}
4975	
4976		var children = scroller.children();
4977		var scrollHead = children[0];
4978		var scrollBody = children[1];
4979		var scrollFoot = footer ? children[2] : null;
4980	
4981		// When the body is scrolled, then we also want to scroll the headers
4982		$(scrollBody).on( 'scroll.DT', function () {
4983			var scrollLeft = this.scrollLeft;
4984	
4985			scrollHead.scrollLeft = scrollLeft;
4986	
4987			if ( footer ) {
4988				scrollFoot.scrollLeft = scrollLeft;
4989			}
4990		} );
4991	
4992		// When focus is put on the header cells, we might need to scroll the body
4993		$('th, td', scrollHead).on('focus', function () {
4994			var scrollLeft = scrollHead.scrollLeft;
4995	
4996			scrollBody.scrollLeft = scrollLeft;
4997	
4998			if ( footer ) {
4999				scrollBody.scrollLeft = scrollLeft;
5000			}
5001		});
5002	
5003		$(scrollBody).css('max-height', scrollY);
5004		if (! scroll.bCollapse) {
5005			$(scrollBody).css('height', scrollY);
5006		}
5007	
5008		settings.nScrollHead = scrollHead;
5009		settings.nScrollBody = scrollBody;
5010		settings.nScrollFoot = scrollFoot;
5011	
5012		// On redraw - align columns
5013		settings.aoDrawCallback.push(_fnScrollDraw);
5014	
5015		return scroller[0];
5016	}
5017	
5018	
5019	
5020	/**
5021	 * Update the header, footer and body tables for resizing - i.e. column
5022	 * alignment.
5023	 *
5024	 * Welcome to the most horrible function DataTables. The process that this
5025	 * function follows is basically:
5026	 *   1. Re-create the table inside the scrolling div
5027	 *   2. Correct colgroup > col values if needed
5028	 *   3. Copy colgroup > col over to header and footer
5029	 *   4. Clean up
5030	 *
5031	 *  @param {object} settings dataTables settings object
5032	 *  @memberof DataTable#oApi
5033	 */
5034	function _fnScrollDraw ( settings )
5035	{
5036		// Given that this is such a monster function, a lot of variables are use
5037		// to try and keep the minimised size as small as possible
5038		var
5039			scroll         = settings.oScroll,
5040			barWidth       = scroll.iBarWidth,
5041			divHeader      = $(settings.nScrollHead),
5042			divHeaderInner = divHeader.children('div'),
5043			divHeaderTable = divHeaderInner.children('table'),
5044			divBodyEl      = settings.nScrollBody,
5045			divBody        = $(divBodyEl),
5046			divFooter      = $(settings.nScrollFoot),
5047			divFooterInner = divFooter.children('div'),
5048			divFooterTable = divFooterInner.children('table'),
5049			header         = $(settings.nTHead),
5050			table          = $(settings.nTable),
5051			footer         = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
5052			browser        = settings.oBrowser,
5053			headerCopy, footerCopy;
5054	
5055		// If the scrollbar visibility has changed from the last draw, we need to
5056		// adjust the column sizes as the table width will have changed to account
5057		// for the scrollbar
5058		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5059		
5060		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5061			settings.scrollBarVis = scrollBarVis;
5062			_fnAdjustColumnSizing( settings );
5063			return; // adjust column sizing will call this function again
5064		}
5065		else {
5066			settings.scrollBarVis = scrollBarVis;
5067		}
5068	
5069		// 1. Re-create the table inside the scrolling div
5070		// Remove the old minimised thead and tfoot elements in the inner table
5071		table.children('thead, tfoot').remove();
5072	
5073		// Clone the current header and footer elements and then place it into the inner table
5074		headerCopy = header.clone().prependTo( table );
5075		headerCopy.find('th, td').removeAttr('tabindex');
5076		headerCopy.find('[id]').removeAttr('id');
5077	
5078		if ( footer ) {
5079			footerCopy = footer.clone().prependTo( table );
5080			footerCopy.find('[id]').removeAttr('id');
5081		}
5082	
5083		// 2. Correct colgroup > col values if needed
5084		// It is possible that the cell sizes are smaller than the content, so we need to
5085		// correct colgroup>col for such cases. This can happen if the auto width detection
5086		// uses a cell which has a longer string, but isn't the widest! For example 
5087		// "Chief Executive Officer (CEO)" is the longest string in the demo, but
5088		// "Systems Administrator" is actually the widest string since it doesn't collapse.
5089		// Note the use of translating into a column index to get the `col` element. This
5090		// is because of Responsive which might remove `col` elements, knocking the alignment
5091		// of the indexes out.
5092		if (settings.aiDisplay.length) {
5093			// Get the column sizes from the first row in the table
5094			var colSizes = table.children('tbody').eq(0).children('tr').eq(0).children('th, td').map(function (vis) {
5095				return {
5096					idx: _fnVisibleToColumnIndex(settings, vis),
5097					width: $(this).outerWidth()
5098				}
5099			});
5100	
5101			// Check against what the colgroup > col is set to and correct if needed
5102			for (var i=0 ; i<colSizes.length ; i++) {
5103				var colEl = settings.aoColumns[ colSizes[i].idx ].colEl[0];
5104				var colWidth = colEl.style.width.replace('px', '');
5105	
5106				if (colWidth !== colSizes[i].width) {
5107					colEl.style.width = colSizes[i].width + 'px';
5108				}
5109			}
5110		}
5111	
5112		// 3. Copy the colgroup over to the header and footer
5113		divHeaderTable
5114			.find('colgroup')
5115			.remove();
5116	
5117		divHeaderTable.append(settings.colgroup.clone());
5118	
5119		if ( footer ) {
5120			divFooterTable
5121				.find('colgroup')
5122				.remove();
5123	
5124			divFooterTable.append(settings.colgroup.clone());
5125		}
5126	
5127		// "Hide" the header and footer that we used for the sizing. We need to keep
5128		// the content of the cell so that the width applied to the header and body
5129		// both match, but we want to hide it completely.
5130		$('th, td', headerCopy).each(function () {
5131			$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5132		});
5133	
5134		if ( footer ) {
5135			$('th, td', footerCopy).each(function () {
5136				$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5137			});
5138		}
5139	
5140		// 4. Clean up
5141		// Figure out if there are scrollbar present - if so then we need a the header and footer to
5142		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5143		var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5144		var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5145	
5146		// Set the width's of the header and footer tables
5147		var outerWidth = table.outerWidth();
5148	
5149		divHeaderTable.css('width', _fnStringToCss( outerWidth ));
5150		divHeaderInner
5151			.css('width', _fnStringToCss( outerWidth ))
5152			.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5153	
5154		if ( footer ) {
5155			divFooterTable.css('width', _fnStringToCss( outerWidth ));
5156			divFooterInner
5157				.css('width', _fnStringToCss( outerWidth ))
5158				.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5159		}
5160	
5161		// Correct DOM ordering for colgroup - comes before the thead
5162		table.children('colgroup').prependTo(table);
5163	
5164		// Adjust the position of the header in case we loose the y-scrollbar
5165		divBody.trigger('scroll');
5166	
5167		// If sorting or filtering has occurred, jump the scrolling back to the top
5168		// only if we aren't holding the position
5169		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5170			divBodyEl.scrollTop = 0;
5171		}
5172	}
5173	
5174	/**
5175	 * Calculate the width of columns for the table
5176	 *  @param {object} settings dataTables settings object
5177	 *  @memberof DataTable#oApi
5178	 */
5179	function _fnCalculateColumnWidths ( settings )
5180	{
5181		// Not interested in doing column width calculation if auto-width is disabled
5182		if (! settings.oFeatures.bAutoWidth) {
5183			return;
5184		}
5185	
5186		var
5187			table = settings.nTable,
5188			columns = settings.aoColumns,
5189			scroll = settings.oScroll,
5190			scrollY = scroll.sY,
5191			scrollX = scroll.sX,
5192			scrollXInner = scroll.sXInner,
5193			visibleColumns = _fnGetColumns( settings, 'bVisible' ),
5194			tableWidthAttr = table.getAttribute('width'), // from DOM element
5195			tableContainer = table.parentNode,
5196			i, column, columnIdx;
5197	
5198		var styleWidth = table.style.width;
5199		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5200			tableWidthAttr = styleWidth;
5201		}
5202	
5203		// Let plug-ins know that we are doing a recalc, in case they have changed any of the
5204		// visible columns their own way (e.g. Responsive uses display:none).
5205		_fnCallbackFire(
5206			settings,
5207			null,
5208			'column-calc',
5209			{visible: visibleColumns},
5210			false
5211		);
5212	
5213		// Construct a single row, worst case, table with the widest
5214		// node in the data, assign any user defined widths, then insert it into
5215		// the DOM and allow the browser to do all the hard work of calculating
5216		// table widths
5217		var tmpTable = $(table.cloneNode())
5218			.css( 'visibility', 'hidden' )
5219			.removeAttr( 'id' );
5220	
5221		// Clean up the table body
5222		tmpTable.append('<tbody>')
5223		var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5224	
5225		// Clone the table header and footer - we can't use the header / footer
5226		// from the cloned table, since if scrolling is active, the table's
5227		// real header and footer are contained in different table tags
5228		tmpTable
5229			.append( $(settings.nTHead).clone() )
5230			.append( $(settings.nTFoot).clone() );
5231	
5232		// Remove any assigned widths from the footer (from scrolling)
5233		tmpTable.find('tfoot th, tfoot td').css('width', '');
5234	
5235		// Apply custom sizing to the cloned header
5236		tmpTable.find('thead th, thead td').each( function () {
5237			// Get the `width` from the header layout
5238			var width = _fnColumnsSumWidth( settings, this, true, false );
5239	
5240			if ( width ) {
5241				this.style.width = width;
5242	
5243				// For scrollX we need to force the column width otherwise the
5244				// browser will collapse it. If this width is smaller than the
5245				// width the column requires, then it will have no effect
5246				if ( scrollX ) {
5247					$( this ).append( $('<div/>').css( {
5248						width: width,
5249						margin: 0,
5250						padding: 0,
5251						border: 0,
5252						height: 1
5253					} ) );
5254				}
5255			}
5256			else {
5257				this.style.width = '';
5258			}
5259		} );
5260	
5261		// Find the widest piece of data for each column and put it into the table
5262		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5263			columnIdx = visibleColumns[i];
5264			column = columns[ columnIdx ];
5265	
5266			var longest = _fnGetMaxLenString(settings, columnIdx);
5267			var autoClass = _ext.type.className[column.sType];
5268			var text = longest + column.sContentPadding;
5269			var insert = longest.indexOf('<') === -1
5270				? document.createTextNode(text)
5271				: text
5272			
5273			$('<td/>')
5274				.addClass(autoClass)
5275				.addClass(column.sClass)
5276				.append(insert)
5277				.appendTo(tr);
5278		}
5279	
5280		// Tidy the temporary table - remove name attributes so there aren't
5281		// duplicated in the dom (radio elements for example)
5282		$('[name]', tmpTable).removeAttr('name');
5283	
5284		// Table has been built, attach to the document so we can work with it.
5285		// A holding element is used, positioned at the top of the container
5286		// with minimal height, so it has no effect on if the container scrolls
5287		// or not. Otherwise it might trigger scrolling when it actually isn't
5288		// needed
5289		var holder = $('<div/>').css( scrollX || scrollY ?
5290				{
5291					position: 'absolute',
5292					top: 0,
5293					left: 0,
5294					height: 1,
5295					right: 0,
5296					overflow: 'hidden'
5297				} :
5298				{}
5299			)
5300			.append( tmpTable )
5301			.appendTo( tableContainer );
5302	
5303		// When scrolling (X or Y) we want to set the width of the table as 
5304		// appropriate. However, when not scrolling leave the table width as it
5305		// is. This results in slightly different, but I think correct behaviour
5306		if ( scrollX && scrollXInner ) {
5307			tmpTable.width( scrollXInner );
5308		}
5309		else if ( scrollX ) {
5310			tmpTable.css( 'width', 'auto' );
5311			tmpTable.removeAttr('width');
5312	
5313			// If there is no width attribute or style, then allow the table to
5314			// collapse
5315			if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5316				tmpTable.width( tableContainer.clientWidth );
5317			}
5318		}
5319		else if ( scrollY ) {
5320			tmpTable.width( tableContainer.clientWidth );
5321		}
5322		else if ( tableWidthAttr ) {
5323			tmpTable.width( tableWidthAttr );
5324		}
5325	
5326		// Get the width of each column in the constructed table
5327		var total = 0;
5328		var bodyCells = tmpTable.find('tbody tr').eq(0).children();
5329	
5330		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5331			// Use getBounding for sub-pixel accuracy, which we then want to round up!
5332			var bounding = bodyCells[i].getBoundingClientRect().width;
5333	
5334			// Total is tracked to remove any sub-pixel errors as the outerWidth
5335			// of the table might not equal the total given here
5336			total += bounding;
5337	
5338			// Width for each column to use
5339			columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding );
5340		}
5341	
5342		table.style.width = _fnStringToCss( total );
5343	
5344		// Finished with the table - ditch it
5345		holder.remove();
5346	
5347		// If there is a width attr, we want to attach an event listener which
5348		// allows the table sizing to automatically adjust when the window is
5349		// resized. Use the width attr rather than CSS, since we can't know if the
5350		// CSS is a relative value or absolute - DOM read is always px.
5351		if ( tableWidthAttr ) {
5352			table.style.width = _fnStringToCss( tableWidthAttr );
5353		}
5354	
5355		if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
5356			var bindResize = function () {
5357				$(window).on('resize.DT-'+settings.sInstance, DataTable.util.throttle( function () {
5358					if (! settings.bDestroying) {
5359						_fnAdjustColumnSizing( settings );
5360					}
5361				} ) );
5362			};
5363	
5364			bindResize();
5365	
5366			settings._reszEvt = true;
5367		}
5368	}
5369	
5370	
5371	/**
5372	 * Get the maximum strlen for each data column
5373	 *  @param {object} settings dataTables settings object
5374	 *  @param {int} colIdx column of interest
5375	 *  @returns {string} string of the max length
5376	 *  @memberof DataTable#oApi
5377	 */
5378	function _fnGetMaxLenString( settings, colIdx )
5379	{
5380		var column = settings.aoColumns[colIdx];
5381	
5382		if (! column.maxLenString) {
5383			var s, max='', maxLen = -1;
5384		
5385			for ( var i=0, ien=settings.aiDisplayMaster.length ; i<ien ; i++ ) {
5386				var rowIdx = settings.aiDisplayMaster[i];
5387				var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
5388	
5389				var cellString = data && typeof data === 'object' && data.nodeType
5390					? data.innerHTML
5391					: data+'';
5392	
5393				// Remove id / name attributes from elements so they
5394				// don't interfere with existing elements
5395				cellString = cellString
5396					.replace(/id=".*?"/g, '')
5397					.replace(/name=".*?"/g, '');
5398	
5399				s = _stripHtml(cellString)
5400					.replace( /&nbsp;/g, ' ' );
5401		
5402				if ( s.length > maxLen ) {
5403					// We want the HTML in the string, but the length that
5404					// is important is the stripped string
5405					max = cellString;
5406					maxLen = s.length;
5407				}
5408			}
5409	
5410			column.maxLenString = max;
5411		}
5412	
5413		return column.maxLenString;
5414	}
5415	
5416	
5417	/**
5418	 * Append a CSS unit (only if required) to a string
5419	 *  @param {string} value to css-ify
5420	 *  @returns {string} value with css unit
5421	 *  @memberof DataTable#oApi
5422	 */
5423	function _fnStringToCss( s )
5424	{
5425		if ( s === null ) {
5426			return '0px';
5427		}
5428	
5429		if ( typeof s == 'number' ) {
5430			return s < 0 ?
5431				'0px' :
5432				s+'px';
5433		}
5434	
5435		// Check it has a unit character already
5436		return s.match(/\d$/) ?
5437			s+'px' :
5438			s;
5439	}
5440	
5441	/**
5442	 * Re-insert the `col` elements for current visibility
5443	 *
5444	 * @param {*} settings DT settings
5445	 */
5446	function _colGroup( settings ) {
5447		var cols = settings.aoColumns;
5448	
5449		settings.colgroup.empty();
5450	
5451		for (i=0 ; i<cols.length ; i++) {
5452			if (cols[i].bVisible) {
5453				settings.colgroup.append(cols[i].colEl);
5454			}
5455		}
5456	}
5457	
5458	
5459	function _fnSortInit( settings ) {
5460		var target = settings.nTHead;
5461		var headerRows = target.querySelectorAll('tr');
5462		var legacyTop = settings.bSortCellsTop;
5463		var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5464		
5465		// Legacy support for `orderCellsTop`
5466		if (legacyTop === true) {
5467			target = headerRows[0];
5468		}
5469		else if (legacyTop === false) {
5470			target = headerRows[ headerRows.length - 1 ];
5471		}
5472	
5473		_fnSortAttachListener(
5474			settings,
5475			target,
5476			target === settings.nTHead
5477				? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5478				: 'th'+notSelector+', td'+notSelector
5479		);
5480	
5481		// Need to resolve the user input array into our internal structure
5482		var order = [];
5483		_fnSortResolve( settings, order, settings.aaSorting );
5484	
5485		settings.aaSorting = order;
5486	}
5487	
5488	
5489	function _fnSortAttachListener(settings, node, selector, column, callback) {
5490		_fnBindAction( node, selector, function (e) {
5491			var run = false;
5492			var columns = column === undefined
5493				? _fnColumnsFromHeader( e.target )
5494				: [column];
5495	
5496			if ( columns.length ) {
5497				for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
5498					var ret = _fnSortAdd( settings, columns[i], i, e.shiftKey );
5499	
5500					if (ret !== false) {
5501						run = true;
5502					}					
5503	
5504					// If the first entry is no sort, then subsequent
5505					// sort columns are ignored
5506					if (settings.aaSorting.length === 1 && settings.aaSorting[0][1] === '') {
5507						break;
5508					}
5509				}
5510	
5511				if (run) {
5512					_fnProcessingDisplay( settings, true );
5513	
5514					// Allow the processing display to show
5515					setTimeout( function () {
5516						_fnSort( settings );
5517						_fnSortDisplay( settings, settings.aiDisplay );
5518	
5519						// Sort processing done - redraw has its own processing display
5520						_fnProcessingDisplay( settings, false );
5521	
5522						_fnReDraw( settings, false, false );
5523	
5524						if (callback) {
5525							callback();
5526						}
5527					}, 0);
5528				}
5529			}
5530		} );
5531	}
5532	
5533	/**
5534	 * Sort the display array to match the master's order
5535	 * @param {*} settings
5536	 */
5537	function _fnSortDisplay(settings, display) {
5538		if (display.length < 2) {
5539			return;
5540		}
5541	
5542		var master = settings.aiDisplayMaster;
5543		var masterMap = {};
5544		var map = {};
5545		var i;
5546	
5547		// Rather than needing an `indexOf` on master array, we can create a map
5548		for (i=0 ; i<master.length ; i++) {
5549			masterMap[master[i]] = i;
5550		}
5551	
5552		// And then cache what would be the indexOf fom the display
5553		for (i=0 ; i<display.length ; i++) {
5554			map[display[i]] = masterMap[display[i]];
5555		}
5556	
5557		display.sort(function(a, b){
5558			// Short version of this function is simply `master.indexOf(a) - master.indexOf(b);`
5559			return map[a] - map[b];
5560		});
5561	}
5562	
5563	
5564	function _fnSortResolve (settings, nestedSort, sort) {
5565		var push = function ( a ) {
5566			if ($.isPlainObject(a)) {
5567				if (a.idx !== undefined) {
5568					// Index based ordering
5569					nestedSort.push([a.idx, a.dir]);
5570				}
5571				else if (a.name) {
5572					// Name based ordering
5573					var cols = _pluck( settings.aoColumns, 'sName');
5574					var idx = cols.indexOf(a.name);
5575	
5576					if (idx !== -1) {
5577						nestedSort.push([idx, a.dir]);
5578					}
5579				}
5580			}
5581			else {
5582				// Plain column index and direction pair
5583				nestedSort.push(a);
5584			}
5585		};
5586	
5587		if ( $.isPlainObject(sort) ) {
5588			// Object
5589			push(sort);
5590		}
5591		else if ( sort.length && typeof sort[0] === 'number' ) {
5592			// 1D array
5593			push(sort);
5594		}
5595		else if ( sort.length ) {
5596			// 2D array
5597			for (var z=0; z<sort.length; z++) {
5598				push(sort[z]); // Object or array
5599			}
5600		}
5601	}
5602	
5603	
5604	function _fnSortFlatten ( settings )
5605	{
5606		var
5607			i, k, kLen,
5608			aSort = [],
5609			extSort = DataTable.ext.type.order,
5610			aoColumns = settings.aoColumns,
5611			aDataSort, iCol, sType, srcCol,
5612			fixed = settings.aaSortingFixed,
5613			fixedObj = $.isPlainObject( fixed ),
5614			nestedSort = [];
5615		
5616		if ( ! settings.oFeatures.bSort ) {
5617			return aSort;
5618		}
5619	
5620		// Build the sort array, with pre-fix and post-fix options if they have been
5621		// specified
5622		if ( Array.isArray( fixed ) ) {
5623			_fnSortResolve( settings, nestedSort, fixed );
5624		}
5625	
5626		if ( fixedObj && fixed.pre ) {
5627			_fnSortResolve( settings, nestedSort, fixed.pre );
5628		}
5629	
5630		_fnSortResolve( settings, nestedSort, settings.aaSorting );
5631	
5632		if (fixedObj && fixed.post ) {
5633			_fnSortResolve( settings, nestedSort, fixed.post );
5634		}
5635	
5636		for ( i=0 ; i<nestedSort.length ; i++ )
5637		{
5638			srcCol = nestedSort[i][0];
5639	
5640			if ( aoColumns[ srcCol ] ) {
5641				aDataSort = aoColumns[ srcCol ].aDataSort;
5642	
5643				for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5644				{
5645					iCol = aDataSort[k];
5646					sType = aoColumns[ iCol ].sType || 'string';
5647	
5648					if ( nestedSort[i]._idx === undefined ) {
5649						nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
5650					}
5651	
5652					if ( nestedSort[i][1] ) {
5653						aSort.push( {
5654							src:       srcCol,
5655							col:       iCol,
5656							dir:       nestedSort[i][1],
5657							index:     nestedSort[i]._idx,
5658							type:      sType,
5659							formatter: extSort[ sType+"-pre" ],
5660							sorter:    extSort[ sType+"-"+nestedSort[i][1] ]
5661						} );
5662					}
5663				}
5664			}
5665		}
5666	
5667		return aSort;
5668	}
5669	
5670	/**
5671	 * Change the order of the table
5672	 *  @param {object} oSettings dataTables settings object
5673	 *  @memberof DataTable#oApi
5674	 */
5675	function _fnSort ( oSettings, col, dir )
5676	{
5677		var
5678			i, ien, iLen,
5679			aiOrig = [],
5680			extSort = DataTable.ext.type.order,
5681			aoData = oSettings.aoData,
5682			sortCol,
5683			displayMaster = oSettings.aiDisplayMaster,
5684			aSort;
5685	
5686		// Resolve any column types that are unknown due to addition or invalidation
5687		// @todo Can this be moved into a 'data-ready' handler which is called when
5688		//   data is going to be used in the table?
5689		_fnColumnTypes( oSettings );
5690	
5691		// Allow a specific column to be sorted, which will _not_ alter the display
5692		// master
5693		if (col !== undefined) {
5694			var srcCol = oSettings.aoColumns[col];
5695			aSort = [{
5696				src:       col,
5697				col:       col,
5698				dir:       dir,
5699				index:     0,
5700				type:      srcCol.sType,
5701				formatter: extSort[ srcCol.sType+"-pre" ],
5702				sorter:    extSort[ srcCol.sType+"-"+dir ]
5703			}];
5704			displayMaster = displayMaster.slice();
5705		}
5706		else {
5707			aSort = _fnSortFlatten( oSettings );
5708		}
5709	
5710		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5711			sortCol = aSort[i];
5712	
5713			// Load the data needed for the sort, for each cell
5714			_fnSortData( oSettings, sortCol.col );
5715		}
5716	
5717		/* No sorting required if server-side or no sorting array */
5718		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5719		{
5720			// Reset the initial positions on each pass so we get a stable sort
5721			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5722				aiOrig[ i ] = i;
5723			}
5724	
5725			// If the first sort is desc, then reverse the array to preserve original
5726			// order, just in reverse
5727			if (aSort.length && aSort[0].dir === 'desc') {
5728				aiOrig.reverse();
5729			}
5730	
5731			/* Do the sort - here we want multi-column sorting based on a given data source (column)
5732			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5733			 * follow on it's own, but this is what we want (example two column sorting):
5734			 *  fnLocalSorting = function(a,b){
5735			 *    var test;
5736			 *    test = oSort['string-asc']('data11', 'data12');
5737			 *      if (test !== 0)
5738			 *        return test;
5739			 *    test = oSort['numeric-desc']('data21', 'data22');
5740			 *    if (test !== 0)
5741			 *      return test;
5742			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5743			 *  }
5744			 * Basically we have a test for each sorting column, if the data in that column is equal,
5745			 * test the next column. If all columns match, then we use a numeric sort on the row
5746			 * positions in the original data array to provide a stable sort.
5747			 */
5748			displayMaster.sort( function ( a, b ) {
5749				var
5750					x, y, k, test, sort,
5751					len=aSort.length,
5752					dataA = aoData[a]._aSortData,
5753					dataB = aoData[b]._aSortData;
5754	
5755				for ( k=0 ; k<len ; k++ ) {
5756					sort = aSort[k];
5757	
5758					// Data, which may have already been through a `-pre` function
5759					x = dataA[ sort.col ];
5760					y = dataB[ sort.col ];
5761	
5762					if (sort.sorter) {
5763						// If there is a custom sorter (`-asc` or `-desc`) for this
5764						// data type, use it
5765						test = sort.sorter(x, y);
5766	
5767						if ( test !== 0 ) {
5768							return test;
5769						}
5770					}
5771					else {
5772						// Otherwise, use generic sorting
5773						test = x<y ? -1 : x>y ? 1 : 0;
5774	
5775						if ( test !== 0 ) {
5776							return sort.dir === 'asc' ? test : -test;
5777						}
5778					}
5779				}
5780	
5781				x = aiOrig[a];
5782				y = aiOrig[b];
5783	
5784				return x<y ? -1 : x>y ? 1 : 0;
5785			} );
5786		}
5787		else if ( aSort.length === 0 ) {
5788			// Apply index order
5789			displayMaster.sort(function (x, y) {
5790				return x<y ? -1 : x>y ? 1 : 0;
5791			});
5792		}
5793	
5794		if (col === undefined) {
5795			// Tell the draw function that we have sorted the data
5796			oSettings.bSorted = true;
5797	
5798			_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort] );
5799		}
5800	
5801		return displayMaster;
5802	}
5803	
5804	
5805	/**
5806	 * Function to run on user sort request
5807	 *  @param {object} settings dataTables settings object
5808	 *  @param {node} attachTo node to attach the handler to
5809	 *  @param {int} colIdx column sorting index
5810	 *  @param {int} addIndex Counter
5811	 *  @param {boolean} [shift=false] Shift click add
5812	 *  @param {function} [callback] callback function
5813	 *  @memberof DataTable#oApi
5814	 */
5815	function _fnSortAdd ( settings, colIdx, addIndex, shift )
5816	{
5817		var col = settings.aoColumns[ colIdx ];
5818		var sorting = settings.aaSorting;
5819		var asSorting = col.asSorting;
5820		var nextSortIdx;
5821		var next = function ( a, overflow ) {
5822			var idx = a._idx;
5823			if ( idx === undefined ) {
5824				idx = asSorting.indexOf(a[1]);
5825			}
5826	
5827			return idx+1 < asSorting.length ?
5828				idx+1 :
5829				overflow ?
5830					null :
5831					0;
5832		};
5833	
5834		if ( ! col.bSortable ) {
5835			return false;
5836		}
5837	
5838		// Convert to 2D array if needed
5839		if ( typeof sorting[0] === 'number' ) {
5840			sorting = settings.aaSorting = [ sorting ];
5841		}
5842	
5843		// If appending the sort then we are multi-column sorting
5844		if ( (shift || addIndex) && settings.oFeatures.bSortMulti ) {
5845			// Are we already doing some kind of sort on this column?
5846			var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
5847	
5848			if ( sortIdx !== -1 ) {
5849				// Yes, modify the sort
5850				nextSortIdx = next( sorting[sortIdx], true );
5851	
5852				if ( nextSortIdx === null && sorting.length === 1 ) {
5853					nextSortIdx = 0; // can't remove sorting completely
5854				}
5855	
5856				if ( nextSortIdx === null ) {
5857					sorting.splice( sortIdx, 1 );
5858				}
5859				else {
5860					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
5861					sorting[sortIdx]._idx = nextSortIdx;
5862				}
5863			}
5864			else if (shift) {
5865				// No sort on this column yet, being added by shift click
5866				// add it as itself
5867				sorting.push( [ colIdx, asSorting[0], 0 ] );
5868				sorting[sorting.length-1]._idx = 0;
5869			}
5870			else {
5871				// No sort on this column yet, being added from a colspan
5872				// so add with same direction as first column
5873				sorting.push( [ colIdx, sorting[0][1], 0 ] );
5874				sorting[sorting.length-1]._idx = 0;
5875			}
5876		}
5877		else if ( sorting.length && sorting[0][0] == colIdx ) {
5878			// Single column - already sorting on this column, modify the sort
5879			nextSortIdx = next( sorting[0] );
5880	
5881			sorting.length = 1;
5882			sorting[0][1] = asSorting[ nextSortIdx ];
5883			sorting[0]._idx = nextSortIdx;
5884		}
5885		else {
5886			// Single column - sort only on this column
5887			sorting.length = 0;
5888			sorting.push( [ colIdx, asSorting[0] ] );
5889			sorting[0]._idx = 0;
5890		}
5891	}
5892	
5893	
5894	/**
5895	 * Set the sorting classes on table's body, Note: it is safe to call this function
5896	 * when bSort and bSortClasses are false
5897	 *  @param {object} oSettings dataTables settings object
5898	 *  @memberof DataTable#oApi
5899	 */
5900	function _fnSortingClasses( settings )
5901	{
5902		var oldSort = settings.aLastSort;
5903		var sortClass = settings.oClasses.order.position;
5904		var sort = _fnSortFlatten( settings );
5905		var features = settings.oFeatures;
5906		var i, ien, colIdx;
5907	
5908		if ( features.bSort && features.bSortClasses ) {
5909			// Remove old sorting classes
5910			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
5911				colIdx = oldSort[i].src;
5912	
5913				// Remove column sorting
5914				$( _pluck( settings.aoData, 'anCells', colIdx ) )
5915					.removeClass( sortClass + (i<2 ? i+1 : 3) );
5916			}
5917	
5918			// Add new column sorting
5919			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
5920				colIdx = sort[i].src;
5921	
5922				$( _pluck( settings.aoData, 'anCells', colIdx ) )
5923					.addClass( sortClass + (i<2 ? i+1 : 3) );
5924			}
5925		}
5926	
5927		settings.aLastSort = sort;
5928	}
5929	
5930	
5931	// Get the data to sort a column, be it from cache, fresh (populating the
5932	// cache), or from a sort formatter
5933	function _fnSortData( settings, colIdx )
5934	{
5935		// Custom sorting function - provided by the sort data type
5936		var column = settings.aoColumns[ colIdx ];
5937		var customSort = DataTable.ext.order[ column.sSortDataType ];
5938		var customData;
5939	
5940		if ( customSort ) {
5941			customData = customSort.call( settings.oInstance, settings, colIdx,
5942				_fnColumnIndexToVisible( settings, colIdx )
5943			);
5944		}
5945	
5946		// Use / populate cache
5947		var row, cellData;
5948		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
5949		var data = settings.aoData;
5950	
5951		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
5952			// Sparse array
5953			if (! data[rowIdx]) {
5954				continue;
5955			}
5956	
5957			row = data[rowIdx];
5958	
5959			if ( ! row._aSortData ) {
5960				row._aSortData = [];
5961			}
5962	
5963			if ( ! row._aSortData[colIdx] || customSort ) {
5964				cellData = customSort ?
5965					customData[rowIdx] : // If there was a custom sort function, use data from there
5966					_fnGetCellData( settings, rowIdx, colIdx, 'sort' );
5967	
5968				row._aSortData[ colIdx ] = formatter ?
5969					formatter( cellData, settings ) :
5970					cellData;
5971			}
5972		}
5973	}
5974	
5975	
5976	/**
5977	 * State information for a table
5978	 *
5979	 * @param {*} settings
5980	 * @returns State object
5981	 */
5982	function _fnSaveState ( settings )
5983	{
5984		if (settings._bLoadingState) {
5985			return;
5986		}
5987	
5988		/* Store the interesting variables */
5989		var state = {
5990			time:    +new Date(),
5991			start:   settings._iDisplayStart,
5992			length:  settings._iDisplayLength,
5993			order:   $.extend( true, [], settings.aaSorting ),
5994			search:  $.extend({}, settings.oPreviousSearch),
5995			columns: settings.aoColumns.map( function ( col, i ) {
5996				return {
5997					visible: col.bVisible,
5998					search: $.extend({}, settings.aoPreSearchCols[i])
5999				};
6000			} )
6001		};
6002	
6003		settings.oSavedState = state;
6004		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6005		
6006		if ( settings.oFeatures.bStateSave && !settings.bDestroying )
6007		{
6008			settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6009		}	
6010	}
6011	
6012	
6013	/**
6014	 * Attempt to load a saved table state
6015	 *  @param {object} oSettings dataTables settings object
6016	 *  @param {object} oInit DataTables init object so we can override settings
6017	 *  @param {function} callback Callback to execute when the state has been loaded
6018	 *  @memberof DataTable#oApi
6019	 */
6020	function _fnLoadState ( settings, init, callback )
6021	{
6022		if ( ! settings.oFeatures.bStateSave ) {
6023			callback();
6024			return;
6025		}
6026	
6027		var loaded = function(state) {
6028			_fnImplementState(settings, state, callback);
6029		}
6030	
6031		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6032	
6033		if ( state !== undefined ) {
6034			_fnImplementState( settings, state, callback );
6035		}
6036		// otherwise, wait for the loaded callback to be executed
6037	
6038		return true;
6039	}
6040	
6041	function _fnImplementState ( settings, s, callback) {
6042		var i, ien;
6043		var columns = settings.aoColumns;
6044		settings._bLoadingState = true;
6045	
6046		// When StateRestore was introduced the state could now be implemented at any time
6047		// Not just initialisation. To do this an api instance is required in some places
6048		var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
6049	
6050		if ( ! s || ! s.time ) {
6051			settings._bLoadingState = false;
6052			callback();
6053			return;
6054		}
6055	
6056		// Reject old data
6057		var duration = settings.iStateDuration;
6058		if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6059			settings._bLoadingState = false;
6060			callback();
6061			return;
6062		}
6063	
6064		// Allow custom and plug-in manipulation functions to alter the saved data set and
6065		// cancelling of loading by returning false
6066		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6067		if ( abStateLoad.indexOf(false) !== -1 ) {
6068			settings._bLoadingState = false;
6069			callback();
6070			return;
6071		}
6072	
6073		// Number of columns have changed - all bets are off, no restore of settings
6074		if ( s.columns && columns.length !== s.columns.length ) {
6075			settings._bLoadingState = false;
6076			callback();
6077			return;
6078		}
6079	
6080		// Store the saved state so it might be accessed at any time
6081		settings.oLoadedState = $.extend( true, {}, s );
6082	
6083		// This is needed for ColReorder, which has to happen first to allow all
6084		// the stored indexes to be usable. It is not publicly documented.
6085		_fnCallbackFire( settings, null, 'stateLoadInit', [settings, s], true );
6086	
6087		// Page Length
6088		if ( s.length !== undefined ) {
6089			// If already initialised just set the value directly so that the select element is also updated
6090			if (api) {
6091				api.page.len(s.length)
6092			}
6093			else {
6094				settings._iDisplayLength   = s.length;
6095			}
6096		}
6097	
6098		// Restore key features - todo - for 1.11 this needs to be done by
6099		// subscribed events
6100		if ( s.start !== undefined ) {
6101			if(api === null) {
6102				settings._iDisplayStart    = s.start;
6103				settings.iInitDisplayStart = s.start;
6104			}
6105			else {
6106				_fnPageChange(settings, s.start/settings._iDisplayLength);
6107			}
6108		}
6109	
6110		// Order
6111		if ( s.order !== undefined ) {
6112			settings.aaSorting = [];
6113			$.each( s.order, function ( i, col ) {
6114				settings.aaSorting.push( col[0] >= columns.length ?
6115					[ 0, col[1] ] :
6116					col
6117				);
6118			} );
6119		}
6120	
6121		// Search
6122		if ( s.search !== undefined ) {
6123			$.extend( settings.oPreviousSearch, s.search );
6124		}
6125	
6126		// Columns
6127		if ( s.columns ) {
6128			for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6129				var col = s.columns[i];
6130	
6131				// Visibility
6132				if ( col.visible !== undefined ) {
6133					// If the api is defined, the table has been initialised so we need to use it rather than internal settings
6134					if (api) {
6135						// Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6136						api.column(i).visible(col.visible, false);
6137					}
6138					else {
6139						columns[i].bVisible = col.visible;
6140					}
6141				}
6142	
6143				// Search
6144				if ( col.search !== undefined ) {
6145					$.extend( settings.aoPreSearchCols[i], col.search );
6146				}
6147			}
6148			
6149			// If the api is defined then we need to adjust the columns once the visibility has been changed
6150			if (api) {
6151				api.columns.adjust();
6152			}
6153		}
6154	
6155		settings._bLoadingState = false;
6156		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6157		callback();
6158	}
6159	
6160	/**
6161	 * Log an error message
6162	 *  @param {object} settings dataTables settings object
6163	 *  @param {int} level log error messages, or display them to the user
6164	 *  @param {string} msg error message
6165	 *  @param {int} tn Technical note id to get more information about the error.
6166	 *  @memberof DataTable#oApi
6167	 */
6168	function _fnLog( settings, level, msg, tn )
6169	{
6170		msg = 'DataTables warning: '+
6171			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6172	
6173		if ( tn ) {
6174			msg += '. For more information about this error, please see '+
6175			'https://datatables.net/tn/'+tn;
6176		}
6177	
6178		if ( ! level  ) {
6179			// Backwards compatibility pre 1.10
6180			var ext = DataTable.ext;
6181			var type = ext.sErrMode || ext.errMode;
6182	
6183			if ( settings ) {
6184				_fnCallbackFire( settings, null, 'dt-error', [ settings, tn, msg ], true );
6185			}
6186	
6187			if ( type == 'alert' ) {
6188				alert( msg );
6189			}
6190			else if ( type == 'throw' ) {
6191				throw new Error(msg);
6192			}
6193			else if ( typeof type == 'function' ) {
6194				type( settings, tn, msg );
6195			}
6196		}
6197		else if ( window.console && console.log ) {
6198			console.log( msg );
6199		}
6200	}
6201	
6202	
6203	/**
6204	 * See if a property is defined on one object, if so assign it to the other object
6205	 *  @param {object} ret target object
6206	 *  @param {object} src source object
6207	 *  @param {string} name property
6208	 *  @param {string} [mappedName] name to map too - optional, name used if not given
6209	 *  @memberof DataTable#oApi
6210	 */
6211	function _fnMap( ret, src, name, mappedName )
6212	{
6213		if ( Array.isArray( name ) ) {
6214			$.each( name, function (i, val) {
6215				if ( Array.isArray( val ) ) {
6216					_fnMap( ret, src, val[0], val[1] );
6217				}
6218				else {
6219					_fnMap( ret, src, val );
6220				}
6221			} );
6222	
6223			return;
6224		}
6225	
6226		if ( mappedName === undefined ) {
6227			mappedName = name;
6228		}
6229	
6230		if ( src[name] !== undefined ) {
6231			ret[mappedName] = src[name];
6232		}
6233	}
6234	
6235	
6236	/**
6237	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6238	 * shallow copy arrays. The reason we need to do this, is that we don't want to
6239	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6240	 * able to override them, but we do want to deep copy arrays.
6241	 *  @param {object} out Object to extend
6242	 *  @param {object} extender Object from which the properties will be applied to
6243	 *      out
6244	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6245	 *      independent copy with the exception of the `data` or `aaData` parameters
6246	 *      if they are present. This is so you can pass in a collection to
6247	 *      DataTables and have that used as your data source without breaking the
6248	 *      references
6249	 *  @returns {object} out Reference, just for convenience - out === the return.
6250	 *  @memberof DataTable#oApi
6251	 *  @todo This doesn't take account of arrays inside the deep copied objects.
6252	 */
6253	function _fnExtend( out, extender, breakRefs )
6254	{
6255		var val;
6256	
6257		for ( var prop in extender ) {
6258			if ( Object.prototype.hasOwnProperty.call(extender, prop) ) {
6259				val = extender[prop];
6260	
6261				if ( $.isPlainObject( val ) ) {
6262					if ( ! $.isPlainObject( out[prop] ) ) {
6263						out[prop] = {};
6264					}
6265					$.extend( true, out[prop], val );
6266				}
6267				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {
6268					out[prop] = val.slice();
6269				}
6270				else {
6271					out[prop] = val;
6272				}
6273			}
6274		}
6275	
6276		return out;
6277	}
6278	
6279	
6280	/**
6281	 * Bind an event handers to allow a click or return key to activate the callback.
6282	 * This is good for accessibility since a return on the keyboard will have the
6283	 * same effect as a click, if the element has focus.
6284	 *  @param {element} n Element to bind the action to
6285	 *  @param {object|string} selector Selector (for delegated events) or data object
6286	 *   to pass to the triggered function
6287	 *  @param {function} fn Callback function for when the event is triggered
6288	 *  @memberof DataTable#oApi
6289	 */
6290	function _fnBindAction( n, selector, fn )
6291	{
6292		$(n)
6293			.on( 'click.DT', selector, function (e) {
6294				fn(e);
6295			} )
6296			.on( 'keypress.DT', selector, function (e){
6297				if ( e.which === 13 ) {
6298					e.preventDefault();
6299					fn(e);
6300				}
6301			} )
6302			.on( 'selectstart.DT', selector, function () {
6303				// Don't want a double click resulting in text selection
6304				return false;
6305			} );
6306	}
6307	
6308	
6309	/**
6310	 * Register a callback function. Easily allows a callback function to be added to
6311	 * an array store of callback functions that can then all be called together.
6312	 *  @param {object} settings dataTables settings object
6313	 *  @param {string} store Name of the array storage for the callbacks in oSettings
6314	 *  @param {function} fn Function to be called back
6315	 *  @memberof DataTable#oApi
6316	 */
6317	function _fnCallbackReg( settings, store, fn )
6318	{
6319		if ( fn ) {
6320			settings[store].push(fn);
6321		}
6322	}
6323	
6324	
6325	/**
6326	 * Fire callback functions and trigger events. Note that the loop over the
6327	 * callback array store is done backwards! Further note that you do not want to
6328	 * fire off triggers in time sensitive applications (for example cell creation)
6329	 * as its slow.
6330	 *  @param {object} settings dataTables settings object
6331	 *  @param {string} callbackArr Name of the array storage for the callbacks in
6332	 *      oSettings
6333	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
6334	 *      null no trigger is fired
6335	 *  @param {array} args Array of arguments to pass to the callback function /
6336	 *      trigger
6337	 *  @param {boolean} [bubbles] True if the event should bubble
6338	 *  @memberof DataTable#oApi
6339	 */
6340	function _fnCallbackFire( settings, callbackArr, eventName, args, bubbles )
6341	{
6342		var ret = [];
6343	
6344		if ( callbackArr ) {
6345			ret = settings[callbackArr].slice().reverse().map( function (val) {
6346				return val.apply( settings.oInstance, args );
6347			} );
6348		}
6349	
6350		if ( eventName !== null) {
6351			var e = $.Event( eventName+'.dt' );
6352			var table = $(settings.nTable);
6353			
6354			// Expose the DataTables API on the event object for easy access
6355			e.dt = settings.api;
6356	
6357			table[bubbles ?  'trigger' : 'triggerHandler']( e, args );
6358	
6359			// If not yet attached to the document, trigger the event
6360			// on the body directly to sort of simulate the bubble
6361			if (bubbles && table.parents('body').length === 0) {
6362				$('body').trigger( e, args );
6363			}
6364	
6365			ret.push( e.result );
6366		}
6367	
6368		return ret;
6369	}
6370	
6371	
6372	function _fnLengthOverflow ( settings )
6373	{
6374		var
6375			start = settings._iDisplayStart,
6376			end = settings.fnDisplayEnd(),
6377			len = settings._iDisplayLength;
6378	
6379		/* If we have space to show extra rows (backing up from the end point - then do so */
6380		if ( start >= end )
6381		{
6382			start = end - len;
6383		}
6384	
6385		// Keep the start record on the current page
6386		start -= (start % len);
6387	
6388		if ( len === -1 || start < 0 )
6389		{
6390			start = 0;
6391		}
6392	
6393		settings._iDisplayStart = start;
6394	}
6395	
6396	
6397	function _fnRenderer( settings, type )
6398	{
6399		var renderer = settings.renderer;
6400		var host = DataTable.ext.renderer[type];
6401	
6402		if ( $.isPlainObject( renderer ) && renderer[type] ) {
6403			// Specific renderer for this type. If available use it, otherwise use
6404			// the default.
6405			return host[renderer[type]] || host._;
6406		}
6407		else if ( typeof renderer === 'string' ) {
6408			// Common renderer - if there is one available for this type use it,
6409			// otherwise use the default
6410			return host[renderer] || host._;
6411		}
6412	
6413		// Use the default
6414		return host._;
6415	}
6416	
6417	
6418	/**
6419	 * Detect the data source being used for the table. Used to simplify the code
6420	 * a little (ajax) and to make it compress a little smaller.
6421	 *
6422	 *  @param {object} settings dataTables settings object
6423	 *  @returns {string} Data source
6424	 *  @memberof DataTable#oApi
6425	 */
6426	function _fnDataSource ( settings )
6427	{
6428		if ( settings.oFeatures.bServerSide ) {
6429			return 'ssp';
6430		}
6431		else if ( settings.ajax ) {
6432			return 'ajax';
6433		}
6434		return 'dom';
6435	}
6436	
6437	/**
6438	 * Common replacement for language strings
6439	 *
6440	 * @param {*} settings DT settings object
6441	 * @param {*} str String with values to replace
6442	 * @param {*} entries Plural number for _ENTRIES_ - can be undefined
6443	 * @returns String
6444	 */
6445	function _fnMacros ( settings, str, entries )
6446	{
6447		// When infinite scrolling, we are always starting at 1. _iDisplayStart is
6448		// used only internally
6449		var
6450			formatter  = settings.fnFormatNumber,
6451			start      = settings._iDisplayStart+1,
6452			len        = settings._iDisplayLength,
6453			vis        = settings.fnRecordsDisplay(),
6454			max        = settings.fnRecordsTotal(),
6455			all        = len === -1;
6456	
6457		return str.
6458			replace(/_START_/g, formatter.call( settings, start ) ).
6459			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
6460			replace(/_MAX_/g,   formatter.call( settings, max ) ).
6461			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
6462			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
6463			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ).
6464			replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries) ).
6465			replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max) ).
6466			replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
6467	}
6468	
6469	
6470	
6471	/**
6472	 * Computed structure of the DataTables API, defined by the options passed to
6473	 * `DataTable.Api.register()` when building the API.
6474	 *
6475	 * The structure is built in order to speed creation and extension of the Api
6476	 * objects since the extensions are effectively pre-parsed.
6477	 *
6478	 * The array is an array of objects with the following structure, where this
6479	 * base array represents the Api prototype base:
6480	 *
6481	 *     [
6482	 *       {
6483	 *         name:      'data'                -- string   - Property name
6484	 *         val:       function () {},       -- function - Api method (or undefined if just an object
6485	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6486	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6487	 *       },
6488	 *       {
6489	 *         name:     'row'
6490	 *         val:       {},
6491	 *         methodExt: [ ... ],
6492	 *         propExt:   [
6493	 *           {
6494	 *             name:      'data'
6495	 *             val:       function () {},
6496	 *             methodExt: [ ... ],
6497	 *             propExt:   [ ... ]
6498	 *           },
6499	 *           ...
6500	 *         ]
6501	 *       }
6502	 *     ]
6503	 *
6504	 * @type {Array}
6505	 * @ignore
6506	 */
6507	var __apiStruct = [];
6508	
6509	
6510	/**
6511	 * `Array.prototype` reference.
6512	 *
6513	 * @type object
6514	 * @ignore
6515	 */
6516	var __arrayProto = Array.prototype;
6517	
6518	
6519	/**
6520	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6521	 * take several different forms for ease of use.
6522	 *
6523	 * Each of the input parameter types will be converted to a DataTables settings
6524	 * object where possible.
6525	 *
6526	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6527	 *   of:
6528	 *
6529	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6530	 *     with be found and used.
6531	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6532	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6533	 *   * `object` - DataTables settings object
6534	 *   * `DataTables.Api` - API instance
6535	 * @return {array|null} Matching DataTables settings objects. `null` or
6536	 *   `undefined` is returned if no matching DataTable is found.
6537	 * @ignore
6538	 */
6539	var _toSettings = function ( mixed )
6540	{
6541		var idx, jq;
6542		var settings = DataTable.settings;
6543		var tables = _pluck(settings, 'nTable');
6544	
6545		if ( ! mixed ) {
6546			return [];
6547		}
6548		else if ( mixed.nTable && mixed.oFeatures ) {
6549			// DataTables settings object
6550			return [ mixed ];
6551		}
6552		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6553			// Table node
6554			idx = tables.indexOf(mixed);
6555			return idx !== -1 ? [ settings[idx] ] : null;
6556		}
6557		else if ( mixed && typeof mixed.settings === 'function' ) {
6558			return mixed.settings().toArray();
6559		}
6560		else if ( typeof mixed === 'string' ) {
6561			// jQuery selector
6562			jq = $(mixed).get();
6563		}
6564		else if ( mixed instanceof $ ) {
6565			// jQuery object (also DataTables instance)
6566			jq = mixed.get();
6567		}
6568	
6569		if ( jq ) {
6570			return settings.filter(function (v, idx) {
6571				return jq.includes(tables[idx]);
6572			});
6573		}
6574	};
6575	
6576	
6577	/**
6578	 * DataTables API class - used to control and interface with  one or more
6579	 * DataTables enhanced tables.
6580	 *
6581	 * The API class is heavily based on jQuery, presenting a chainable interface
6582	 * that you can use to interact with tables. Each instance of the API class has
6583	 * a "context" - i.e. the tables that it will operate on. This could be a single
6584	 * table, all tables on a page or a sub-set thereof.
6585	 *
6586	 * Additionally the API is designed to allow you to easily work with the data in
6587	 * the tables, retrieving and manipulating it as required. This is done by
6588	 * presenting the API class as an array like interface. The contents of the
6589	 * array depend upon the actions requested by each method (for example
6590	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6591	 * return an array of objects or arrays depending upon your table's
6592	 * configuration). The API object has a number of array like methods (`push`,
6593	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6594	 * `unique` etc) to assist your working with the data held in a table.
6595	 *
6596	 * Most methods (those which return an Api instance) are chainable, which means
6597	 * the return from a method call also has all of the methods available that the
6598	 * top level object had. For example, these two calls are equivalent:
6599	 *
6600	 *     // Not chained
6601	 *     api.row.add( {...} );
6602	 *     api.draw();
6603	 *
6604	 *     // Chained
6605	 *     api.row.add( {...} ).draw();
6606	 *
6607	 * @class DataTable.Api
6608	 * @param {array|object|string|jQuery} context DataTable identifier. This is
6609	 *   used to define which DataTables enhanced tables this API will operate on.
6610	 *   Can be one of:
6611	 *
6612	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6613	 *     with be found and used.
6614	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6615	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6616	 *   * `object` - DataTables settings object
6617	 * @param {array} [data] Data to initialise the Api instance with.
6618	 *
6619	 * @example
6620	 *   // Direct initialisation during DataTables construction
6621	 *   var api = $('#example').DataTable();
6622	 *
6623	 * @example
6624	 *   // Initialisation using a DataTables jQuery object
6625	 *   var api = $('#example').dataTable().api();
6626	 *
6627	 * @example
6628	 *   // Initialisation as a constructor
6629	 *   var api = new DataTable.Api( 'table.dataTable' );
6630	 */
6631	_Api = function ( context, data )
6632	{
6633		if ( ! (this instanceof _Api) ) {
6634			return new _Api( context, data );
6635		}
6636	
6637		var settings = [];
6638		var ctxSettings = function ( o ) {
6639			var a = _toSettings( o );
6640			if ( a ) {
6641				settings.push.apply( settings, a );
6642			}
6643		};
6644	
6645		if ( Array.isArray( context ) ) {
6646			for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6647				ctxSettings( context[i] );
6648			}
6649		}
6650		else {
6651			ctxSettings( context );
6652		}
6653	
6654		// Remove duplicates
6655		this.context = settings.length > 1
6656			? _unique( settings )
6657			: settings;
6658	
6659		// Initial data
6660		if ( data ) {
6661			this.push.apply(this, data);
6662		}
6663	
6664		// selector
6665		this.selector = {
6666			rows: null,
6667			cols: null,
6668			opts: null
6669		};
6670	
6671		_Api.extend( this, this, __apiStruct );
6672	};
6673	
6674	DataTable.Api = _Api;
6675	
6676	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6677	// isPlainObject.
6678	$.extend( _Api.prototype, {
6679		any: function ()
6680		{
6681			return this.count() !== 0;
6682		},
6683	
6684		context: [], // array of table settings objects
6685	
6686		count: function ()
6687		{
6688			return this.flatten().length;
6689		},
6690	
6691		each: function ( fn )
6692		{
6693			for ( var i=0, ien=this.length ; i<ien; i++ ) {
6694				fn.call( this, this[i], i, this );
6695			}
6696	
6697			return this;
6698		},
6699	
6700		eq: function ( idx )
6701		{
6702			var ctx = this.context;
6703	
6704			return ctx.length > idx ?
6705				new _Api( ctx[idx], this[idx] ) :
6706				null;
6707		},
6708	
6709		filter: function ( fn )
6710		{
6711			var a = __arrayProto.filter.call( this, fn, this );
6712	
6713			return new _Api( this.context, a );
6714		},
6715	
6716		flatten: function ()
6717		{
6718			var a = [];
6719	
6720			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6721		},
6722	
6723		get: function ( idx )
6724		{
6725			return this[ idx ];
6726		},
6727	
6728		join:    __arrayProto.join,
6729	
6730		includes: function ( find ) {
6731			return this.indexOf( find ) === -1 ? false : true;
6732		},
6733	
6734		indexOf: __arrayProto.indexOf,
6735	
6736		iterator: function ( flatten, type, fn, alwaysNew ) {
6737			var
6738				a = [], ret,
6739				i, ien, j, jen,
6740				context = this.context,
6741				rows, items, item,
6742				selector = this.selector;
6743	
6744			// Argument shifting
6745			if ( typeof flatten === 'string' ) {
6746				alwaysNew = fn;
6747				fn = type;
6748				type = flatten;
6749				flatten = false;
6750			}
6751	
6752			for ( i=0, ien=context.length ; i<ien ; i++ ) {
6753				var apiInst = new _Api( context[i] );
6754	
6755				if ( type === 'table' ) {
6756					ret = fn.call( apiInst, context[i], i );
6757	
6758					if ( ret !== undefined ) {
6759						a.push( ret );
6760					}
6761				}
6762				else if ( type === 'columns' || type === 'rows' ) {
6763					// this has same length as context - one entry for each table
6764					ret = fn.call( apiInst, context[i], this[i], i );
6765	
6766					if ( ret !== undefined ) {
6767						a.push( ret );
6768					}
6769				}
6770				else if ( type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6771					// columns and rows share the same structure.
6772					// 'this' is an array of column indexes for each context
6773					items = this[i];
6774	
6775					if ( type === 'column-rows' ) {
6776						rows = _selector_row_indexes( context[i], selector.opts );
6777					}
6778	
6779					for ( j=0, jen=items.length ; j<jen ; j++ ) {
6780						item = items[j];
6781	
6782						if ( type === 'cell' ) {
6783							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6784						}
6785						else {
6786							ret = fn.call( apiInst, context[i], item, i, j, rows );
6787						}
6788	
6789						if ( ret !== undefined ) {
6790							a.push( ret );
6791						}
6792					}
6793				}
6794			}
6795	
6796			if ( a.length || alwaysNew ) {
6797				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6798				var apiSelector = api.selector;
6799				apiSelector.rows = selector.rows;
6800				apiSelector.cols = selector.cols;
6801				apiSelector.opts = selector.opts;
6802				return api;
6803			}
6804			return this;
6805		},
6806	
6807		lastIndexOf: __arrayProto.lastIndexOf,
6808	
6809		length:  0,
6810	
6811		map: function ( fn )
6812		{
6813			var a = __arrayProto.map.call( this, fn, this );
6814	
6815			return new _Api( this.context, a );
6816		},
6817	
6818		pluck: function ( prop )
6819		{
6820			var fn = DataTable.util.get(prop);
6821	
6822			return this.map( function ( el ) {
6823				return fn(el);
6824			} );
6825		},
6826	
6827		pop:     __arrayProto.pop,
6828	
6829		push:    __arrayProto.push,
6830	
6831		reduce: __arrayProto.reduce,
6832	
6833		reduceRight: __arrayProto.reduceRight,
6834	
6835		reverse: __arrayProto.reverse,
6836	
6837		// Object with rows, columns and opts
6838		selector: null,
6839	
6840		shift:   __arrayProto.shift,
6841	
6842		slice: function () {
6843			return new _Api( this.context, this );
6844		},
6845	
6846		sort:    __arrayProto.sort,
6847	
6848		splice:  __arrayProto.splice,
6849	
6850		toArray: function ()
6851		{
6852			return __arrayProto.slice.call( this );
6853		},
6854	
6855		to$: function ()
6856		{
6857			return $( this );
6858		},
6859	
6860		toJQuery: function ()
6861		{
6862			return $( this );
6863		},
6864	
6865		unique: function ()
6866		{
6867			return new _Api( this.context, _unique(this.toArray()) );
6868		},
6869	
6870		unshift: __arrayProto.unshift
6871	} );
6872	
6873	
6874	function _api_scope( scope, fn, struc ) {
6875		return function () {
6876			var ret = fn.apply( scope || this, arguments );
6877	
6878			// Method extension
6879			_Api.extend( ret, ret, struc.methodExt );
6880			return ret;
6881		};
6882	}
6883	
6884	function _api_find( src, name ) {
6885		for ( var i=0, ien=src.length ; i<ien ; i++ ) {
6886			if ( src[i].name === name ) {
6887				return src[i];
6888			}
6889		}
6890		return null;
6891	}
6892	
6893	window.__apiStruct = __apiStruct;
6894	
6895	_Api.extend = function ( scope, obj, ext )
6896	{
6897		// Only extend API instances and static properties of the API
6898		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6899			return;
6900		}
6901	
6902		var
6903			i, ien,
6904			struct;
6905	
6906		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6907			struct = ext[i];
6908	
6909			if (struct.name === '__proto__') {
6910				continue;
6911			}
6912	
6913			// Value
6914			obj[ struct.name ] = struct.type === 'function' ?
6915				_api_scope( scope, struct.val, struct ) :
6916				struct.type === 'object' ?
6917					{} :
6918					struct.val;
6919	
6920			obj[ struct.name ].__dt_wrapper = true;
6921	
6922			// Property extension
6923			_Api.extend( scope, obj[ struct.name ], struct.propExt );
6924		}
6925	};
6926	
6927	//     [
6928	//       {
6929	//         name:      'data'                -- string   - Property name
6930	//         val:       function () {},       -- function - Api method (or undefined if just an object
6931	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6932	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6933	//       },
6934	//       {
6935	//         name:     'row'
6936	//         val:       {},
6937	//         methodExt: [ ... ],
6938	//         propExt:   [
6939	//           {
6940	//             name:      'data'
6941	//             val:       function () {},
6942	//             methodExt: [ ... ],
6943	//             propExt:   [ ... ]
6944	//           },
6945	//           ...
6946	//         ]
6947	//       }
6948	//     ]
6949	
6950	
6951	_Api.register = _api_register = function ( name, val )
6952	{
6953		if ( Array.isArray( name ) ) {
6954			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
6955				_Api.register( name[j], val );
6956			}
6957			return;
6958		}
6959	
6960		var
6961			i, ien,
6962			heir = name.split('.'),
6963			struct = __apiStruct,
6964			key, method;
6965	
6966		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
6967			method = heir[i].indexOf('()') !== -1;
6968			key = method ?
6969				heir[i].replace('()', '') :
6970				heir[i];
6971	
6972			var src = _api_find( struct, key );
6973			if ( ! src ) {
6974				src = {
6975					name:      key,
6976					val:       {},
6977					methodExt: [],
6978					propExt:   [],
6979					type:      'object'
6980				};
6981				struct.push( src );
6982			}
6983	
6984			if ( i === ien-1 ) {
6985				src.val = val;
6986				src.type = typeof val === 'function' ?
6987					'function' :
6988					$.isPlainObject( val ) ?
6989						'object' :
6990						'other';
6991			}
6992			else {
6993				struct = method ?
6994					src.methodExt :
6995					src.propExt;
6996			}
6997		}
6998	};
6999	
7000	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7001		_Api.register( pluralName, val );
7002	
7003		_Api.register( singularName, function () {
7004			var ret = val.apply( this, arguments );
7005	
7006			if ( ret === this ) {
7007				// Returned item is the API instance that was passed in, return it
7008				return this;
7009			}
7010			else if ( ret instanceof _Api ) {
7011				// New API instance returned, want the value from the first item
7012				// in the returned array for the singular result.
7013				return ret.length ?
7014					Array.isArray( ret[0] ) ?
7015						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7016						ret[0] :
7017					undefined;
7018			}
7019	
7020			// Non-API return - just fire it back
7021			return ret;
7022		} );
7023	};
7024	
7025	
7026	/**
7027	 * Selector for HTML tables. Apply the given selector to the give array of
7028	 * DataTables settings objects.
7029	 *
7030	 * @param {string|integer} [selector] jQuery selector string or integer
7031	 * @param  {array} Array of DataTables settings objects to be filtered
7032	 * @return {array}
7033	 * @ignore
7034	 */
7035	var __table_selector = function ( selector, a )
7036	{
7037		if ( Array.isArray(selector) ) {
7038			var result = [];
7039	
7040			selector.forEach(function (sel) {
7041				var inner = __table_selector(sel, a);
7042	
7043				result.push.apply(result, inner);
7044			});
7045	
7046			return result.filter( function (item) {
7047				return item;
7048			});
7049		}
7050	
7051		// Integer is used to pick out a table by index
7052		if ( typeof selector === 'number' ) {
7053			return [ a[ selector ] ];
7054		}
7055	
7056		// Perform a jQuery selector on the table nodes
7057		var nodes = a.map( function (el) {
7058			return el.nTable;
7059		} );
7060	
7061		return $(nodes)
7062			.filter( selector )
7063			.map( function () {
7064				// Need to translate back from the table node to the settings
7065				var idx = nodes.indexOf(this);
7066				return a[ idx ];
7067			} )
7068			.toArray();
7069	};
7070	
7071	
7072	
7073	/**
7074	 * Context selector for the API's context (i.e. the tables the API instance
7075	 * refers to.
7076	 *
7077	 * @name    DataTable.Api#tables
7078	 * @param {string|integer} [selector] Selector to pick which tables the iterator
7079	 *   should operate on. If not given, all tables in the current context are
7080	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7081	 *   select multiple tables or as an integer to select a single table.
7082	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7083	 */
7084	_api_register( 'tables()', function ( selector ) {
7085		// A new instance is created if there was a selector specified
7086		return selector !== undefined && selector !== null ?
7087			new _Api( __table_selector( selector, this.context ) ) :
7088			this;
7089	} );
7090	
7091	
7092	_api_register( 'table()', function ( selector ) {
7093		var tables = this.tables( selector );
7094		var ctx = tables.context;
7095	
7096		// Truncate to the first matched table
7097		return ctx.length ?
7098			new _Api( ctx[0] ) :
7099			tables;
7100	} );
7101	
7102	// Common methods, combined to reduce size
7103	[
7104		['nodes', 'node', 'nTable'],
7105		['body', 'body', 'nTBody'],
7106		['header', 'header', 'nTHead'],
7107		['footer', 'footer', 'nTFoot'],
7108	].forEach(function (item) {
7109		_api_registerPlural(
7110			'tables().' + item[0] + '()',
7111			'table().' + item[1] + '()' ,
7112			function () {
7113				return this.iterator( 'table', function ( ctx ) {
7114					return ctx[item[2]];
7115				}, 1 );
7116			}
7117		);
7118	});
7119	
7120	// Structure methods
7121	[
7122		['header', 'aoHeader'],
7123		['footer', 'aoFooter'],
7124	].forEach(function (item) {
7125		_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
7126			var indexes = this.columns(selector).indexes().flatten();
7127			var ctx = this.context[0];
7128			
7129			return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7130		} );
7131	})
7132	
7133	
7134	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7135		return this.iterator( 'table', function ( ctx ) {
7136			return ctx.nTableWrapper;
7137		}, 1 );
7138	} );
7139	
7140	_api_register( 'tables().every()', function ( fn ) {
7141		var that = this;
7142	
7143		return this.iterator('table', function (s, i) {
7144			fn.call(that.table(i), i);
7145		});
7146	});
7147	
7148	_api_register( 'caption()', function ( value, side ) {
7149		var context = this.context;
7150	
7151		// Getter - return existing node's content
7152		if ( value === undefined ) {
7153			var caption = context[0].captionNode;
7154	
7155			return caption && context.length ?
7156				caption.innerHTML : 
7157				null;
7158		}
7159	
7160		return this.iterator( 'table', function ( ctx ) {
7161			var table = $(ctx.nTable);
7162			var caption = $(ctx.captionNode);
7163			var container = $(ctx.nTableWrapper);
7164	
7165			// Create the node if it doesn't exist yet
7166			if ( ! caption.length ) {
7167				caption = $('<caption/>').html( value );
7168				ctx.captionNode = caption[0];
7169	
7170				// If side isn't set, we need to insert into the document to let the
7171				// CSS decide so we can read it back, otherwise there is no way to
7172				// know if the CSS would put it top or bottom for scrolling
7173				if (! side) {
7174					table.prepend(caption);
7175	
7176					side = caption.css('caption-side');
7177				}
7178			}
7179	
7180			caption.html( value );
7181	
7182			if ( side ) {
7183				caption.css( 'caption-side', side );
7184				caption[0]._captionSide = side;
7185			}
7186	
7187			if (container.find('div.dataTables_scroll').length) {
7188				var selector = (side === 'top' ? 'Head' : 'Foot');
7189	
7190				container.find('div.dataTables_scroll'+ selector +' table').prepend(caption);
7191			}
7192			else {
7193				table.prepend(caption);
7194			}
7195		}, 1 );
7196	} );
7197	
7198	_api_register( 'caption.node()', function () {
7199		var ctx = this.context;
7200	
7201		return ctx.length ? ctx[0].captionNode : null;
7202	} );
7203	
7204	
7205	/**
7206	 * Redraw the tables in the current context.
7207	 */
7208	_api_register( 'draw()', function ( paging ) {
7209		return this.iterator( 'table', function ( settings ) {
7210			if ( paging === 'page' ) {
7211				_fnDraw( settings );
7212			}
7213			else {
7214				if ( typeof paging === 'string' ) {
7215					paging = paging === 'full-hold' ?
7216						false :
7217						true;
7218				}
7219	
7220				_fnReDraw( settings, paging===false );
7221			}
7222		} );
7223	} );
7224	
7225	
7226	
7227	/**
7228	 * Get the current page index.
7229	 *
7230	 * @return {integer} Current page index (zero based)
7231	 *//**
7232	 * Set the current page.
7233	 *
7234	 * Note that if you attempt to show a page which does not exist, DataTables will
7235	 * not throw an error, but rather reset the paging.
7236	 *
7237	 * @param {integer|string} action The paging action to take. This can be one of:
7238	 *  * `integer` - The page index to jump to
7239	 *  * `string` - An action to take:
7240	 *    * `first` - Jump to first page.
7241	 *    * `next` - Jump to the next page
7242	 *    * `previous` - Jump to previous page
7243	 *    * `last` - Jump to the last page.
7244	 * @returns {DataTables.Api} this
7245	 */
7246	_api_register( 'page()', function ( action ) {
7247		if ( action === undefined ) {
7248			return this.page.info().page; // not an expensive call
7249		}
7250	
7251		// else, have an action to take on all tables
7252		return this.iterator( 'table', function ( settings ) {
7253			_fnPageChange( settings, action );
7254		} );
7255	} );
7256	
7257	
7258	/**
7259	 * Paging information for the first table in the current context.
7260	 *
7261	 * If you require paging information for another table, use the `table()` method
7262	 * with a suitable selector.
7263	 *
7264	 * @return {object} Object with the following properties set:
7265	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7266	 *  * `pages` - Total number of pages
7267	 *  * `start` - Display index for the first record shown on the current page
7268	 *  * `end` - Display index for the last record shown on the current page
7269	 *  * `length` - Display length (number of records). Note that generally `start
7270	 *    + length = end`, but this is not always true, for example if there are
7271	 *    only 2 records to show on the final page, with a length of 10.
7272	 *  * `recordsTotal` - Full data set length
7273	 *  * `recordsDisplay` - Data set length once the current filtering criterion
7274	 *    are applied.
7275	 */
7276	_api_register( 'page.info()', function () {
7277		if ( this.context.length === 0 ) {
7278			return undefined;
7279		}
7280	
7281		var
7282			settings   = this.context[0],
7283			start      = settings._iDisplayStart,
7284			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7285			visRecords = settings.fnRecordsDisplay(),
7286			all        = len === -1;
7287	
7288		return {
7289			"page":           all ? 0 : Math.floor( start / len ),
7290			"pages":          all ? 1 : Math.ceil( visRecords / len ),
7291			"start":          start,
7292			"end":            settings.fnDisplayEnd(),
7293			"length":         len,
7294			"recordsTotal":   settings.fnRecordsTotal(),
7295			"recordsDisplay": visRecords,
7296			"serverSide":     _fnDataSource( settings ) === 'ssp'
7297		};
7298	} );
7299	
7300	
7301	/**
7302	 * Get the current page length.
7303	 *
7304	 * @return {integer} Current page length. Note `-1` indicates that all records
7305	 *   are to be shown.
7306	 *//**
7307	 * Set the current page length.
7308	 *
7309	 * @param {integer} Page length to set. Use `-1` to show all records.
7310	 * @returns {DataTables.Api} this
7311	 */
7312	_api_register( 'page.len()', function ( len ) {
7313		// Note that we can't call this function 'length()' because `length`
7314		// is a Javascript property of functions which defines how many arguments
7315		// the function expects.
7316		if ( len === undefined ) {
7317			return this.context.length !== 0 ?
7318				this.context[0]._iDisplayLength :
7319				undefined;
7320		}
7321	
7322		// else, set the page length
7323		return this.iterator( 'table', function ( settings ) {
7324			_fnLengthChange( settings, len );
7325		} );
7326	} );
7327	
7328	
7329	
7330	var __reload = function ( settings, holdPosition, callback ) {
7331		// Use the draw event to trigger a callback
7332		if ( callback ) {
7333			var api = new _Api( settings );
7334	
7335			api.one( 'draw', function () {
7336				callback( api.ajax.json() );
7337			} );
7338		}
7339	
7340		if ( _fnDataSource( settings ) == 'ssp' ) {
7341			_fnReDraw( settings, holdPosition );
7342		}
7343		else {
7344			_fnProcessingDisplay( settings, true );
7345	
7346			// Cancel an existing request
7347			var xhr = settings.jqXHR;
7348			if ( xhr && xhr.readyState !== 4 ) {
7349				xhr.abort();
7350			}
7351	
7352			// Trigger xhr
7353			_fnBuildAjax( settings, {}, function( json ) {
7354				_fnClearTable( settings );
7355	
7356				var data = _fnAjaxDataSrc( settings, json );
7357				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7358					_fnAddData( settings, data[i] );
7359				}
7360	
7361				_fnReDraw( settings, holdPosition );
7362				_fnInitComplete( settings );
7363				_fnProcessingDisplay( settings, false );
7364			} );
7365		}
7366	};
7367	
7368	
7369	/**
7370	 * Get the JSON response from the last Ajax request that DataTables made to the
7371	 * server. Note that this returns the JSON from the first table in the current
7372	 * context.
7373	 *
7374	 * @return {object} JSON received from the server.
7375	 */
7376	_api_register( 'ajax.json()', function () {
7377		var ctx = this.context;
7378	
7379		if ( ctx.length > 0 ) {
7380			return ctx[0].json;
7381		}
7382	
7383		// else return undefined;
7384	} );
7385	
7386	
7387	/**
7388	 * Get the data submitted in the last Ajax request
7389	 */
7390	_api_register( 'ajax.params()', function () {
7391		var ctx = this.context;
7392	
7393		if ( ctx.length > 0 ) {
7394			return ctx[0].oAjaxData;
7395		}
7396	
7397		// else return undefined;
7398	} );
7399	
7400	
7401	/**
7402	 * Reload tables from the Ajax data source. Note that this function will
7403	 * automatically re-draw the table when the remote data has been loaded.
7404	 *
7405	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7406	 *   position. A full re-sort and re-filter is performed when this method is
7407	 *   called, which is why the pagination reset is the default action.
7408	 * @returns {DataTables.Api} this
7409	 */
7410	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7411		return this.iterator( 'table', function (settings) {
7412			__reload( settings, resetPaging===false, callback );
7413		} );
7414	} );
7415	
7416	
7417	/**
7418	 * Get the current Ajax URL. Note that this returns the URL from the first
7419	 * table in the current context.
7420	 *
7421	 * @return {string} Current Ajax source URL
7422	 *//**
7423	 * Set the Ajax URL. Note that this will set the URL for all tables in the
7424	 * current context.
7425	 *
7426	 * @param {string} url URL to set.
7427	 * @returns {DataTables.Api} this
7428	 */
7429	_api_register( 'ajax.url()', function ( url ) {
7430		var ctx = this.context;
7431	
7432		if ( url === undefined ) {
7433			// get
7434			if ( ctx.length === 0 ) {
7435				return undefined;
7436			}
7437			ctx = ctx[0];
7438	
7439			return $.isPlainObject( ctx.ajax ) ?
7440				ctx.ajax.url :
7441				ctx.ajax;
7442		}
7443	
7444		// set
7445		return this.iterator( 'table', function ( settings ) {
7446			if ( $.isPlainObject( settings.ajax ) ) {
7447				settings.ajax.url = url;
7448			}
7449			else {
7450				settings.ajax = url;
7451			}
7452		} );
7453	} );
7454	
7455	
7456	/**
7457	 * Load data from the newly set Ajax URL. Note that this method is only
7458	 * available when `ajax.url()` is used to set a URL. Additionally, this method
7459	 * has the same effect as calling `ajax.reload()` but is provided for
7460	 * convenience when setting a new URL. Like `ajax.reload()` it will
7461	 * automatically redraw the table once the remote data has been loaded.
7462	 *
7463	 * @returns {DataTables.Api} this
7464	 */
7465	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7466		// Same as a reload, but makes sense to present it for easy access after a
7467		// url change
7468		return this.iterator( 'table', function ( ctx ) {
7469			__reload( ctx, resetPaging===false, callback );
7470		} );
7471	} );
7472	
7473	
7474	
7475	
7476	var _selector_run = function ( type, selector, selectFn, settings, opts )
7477	{
7478		var
7479			out = [], res,
7480			a, i, ien, j, jen,
7481			selectorType = typeof selector;
7482	
7483		// Can't just check for isArray here, as an API or jQuery instance might be
7484		// given with their array like look
7485		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7486			selector = [ selector ];
7487		}
7488	
7489		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7490			// Only split on simple strings - complex expressions will be jQuery selectors
7491			a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
7492				selector[i].split(',') :
7493				[ selector[i] ];
7494	
7495			for ( j=0, jen=a.length ; j<jen ; j++ ) {
7496				res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
7497	
7498				// Remove empty items
7499				res = res.filter( function (item) {
7500					return item !== null && item !== undefined;
7501				});
7502	
7503				if ( res && res.length ) {
7504					out = out.concat( res );
7505				}
7506			}
7507		}
7508	
7509		// selector extensions
7510		var ext = _ext.selector[ type ];
7511		if ( ext.length ) {
7512			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7513				out = ext[i]( settings, opts, out );
7514			}
7515		}
7516	
7517		return _unique( out );
7518	};
7519	
7520	
7521	var _selector_opts = function ( opts )
7522	{
7523		if ( ! opts ) {
7524			opts = {};
7525		}
7526	
7527		// Backwards compatibility for 1.9- which used the terminology filter rather
7528		// than search
7529		if ( opts.filter && opts.search === undefined ) {
7530			opts.search = opts.filter;
7531		}
7532	
7533		return $.extend( {
7534			search: 'none',
7535			order: 'current',
7536			page: 'all'
7537		}, opts );
7538	};
7539	
7540	
7541	// Reduce the API instance to the first item found
7542	var _selector_first = function ( old )
7543	{
7544		let inst = new _Api(old.context[0]);
7545	
7546		// Use a push rather than passing to the constructor, since it will
7547		// merge arrays down automatically, which isn't what is wanted here
7548		if (old.length) {
7549			inst.push( old[0] );
7550		}
7551	
7552		inst.selector = old.selector;
7553	
7554		// Limit to a single row / column / cell
7555		if (inst.length && inst[0].length > 1) {
7556			inst[0].splice(1);
7557		}
7558	
7559		return inst;
7560	};
7561	
7562	
7563	var _selector_row_indexes = function ( settings, opts )
7564	{
7565		var
7566			i, ien, tmp, a=[],
7567			displayFiltered = settings.aiDisplay,
7568			displayMaster = settings.aiDisplayMaster;
7569	
7570		var
7571			search = opts.search,  // none, applied, removed
7572			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7573			page   = opts.page;    // all, current
7574	
7575		if ( _fnDataSource( settings ) == 'ssp' ) {
7576			// In server-side processing mode, most options are irrelevant since
7577			// rows not shown don't exist and the index order is the applied order
7578			// Removed is a special case - for consistency just return an empty
7579			// array
7580			return search === 'removed' ?
7581				[] :
7582				_range( 0, displayMaster.length );
7583		}
7584	
7585		if ( page == 'current' ) {
7586			// Current page implies that order=current and filter=applied, since it is
7587			// fairly senseless otherwise, regardless of what order and search actually
7588			// are
7589			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7590				a.push( displayFiltered[i] );
7591			}
7592		}
7593		else if ( order == 'current' || order == 'applied' ) {
7594			if ( search == 'none') {
7595				a = displayMaster.slice();
7596			}
7597			else if ( search == 'applied' ) {
7598				a = displayFiltered.slice();
7599			}
7600			else if ( search == 'removed' ) {
7601				// O(n+m) solution by creating a hash map
7602				var displayFilteredMap = {};
7603	
7604				for ( i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7605					displayFilteredMap[displayFiltered[i]] = null;
7606				}
7607	
7608				displayMaster.forEach(function (item) {
7609					if (! Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
7610						a.push(item);
7611					}
7612				});
7613			}
7614		}
7615		else if ( order == 'index' || order == 'original' ) {
7616			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7617				if (! settings.aoData[i]) {
7618					continue;
7619				}
7620	
7621				if ( search == 'none' ) {
7622					a.push( i );
7623				}
7624				else { // applied | removed
7625					tmp = displayFiltered.indexOf(i);
7626	
7627					if ((tmp === -1 && search == 'removed') ||
7628						(tmp >= 0   && search == 'applied') )
7629					{
7630						a.push( i );
7631					}
7632				}
7633			}
7634		}
7635		else if ( typeof order === 'number' ) {
7636			// Order the rows by the given column
7637			var ordered = _fnSort(settings, order, 'asc');
7638	
7639			if (search === 'none') {
7640				a = ordered;
7641			}
7642			else { // applied | removed
7643				for (i=0; i<ordered.length; i++) {
7644					tmp = displayFiltered.indexOf(ordered[i]);
7645	
7646					if ((tmp === -1 && search == 'removed') ||
7647						(tmp >= 0   && search == 'applied') )
7648					{
7649						a.push( ordered[i] );
7650					}
7651				}
7652			}
7653		}
7654	
7655		return a;
7656	};
7657	
7658	
7659	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7660	 * Rows
7661	 *
7662	 * {}          - no selector - use all available rows
7663	 * {integer}   - row aoData index
7664	 * {node}      - TR node
7665	 * {string}    - jQuery selector to apply to the TR elements
7666	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
7667	 *
7668	 */
7669	var __row_selector = function ( settings, selector, opts )
7670	{
7671		var rows;
7672		var run = function ( sel ) {
7673			var selInt = _intVal( sel );
7674			var aoData = settings.aoData;
7675	
7676			// Short cut - selector is a number and no options provided (default is
7677			// all records, so no need to check if the index is in there, since it
7678			// must be - dev error if the index doesn't exist).
7679			if ( selInt !== null && ! opts ) {
7680				return [ selInt ];
7681			}
7682	
7683			if ( ! rows ) {
7684				rows = _selector_row_indexes( settings, opts );
7685			}
7686	
7687			if ( selInt !== null && rows.indexOf(selInt) !== -1 ) {
7688				// Selector - integer
7689				return [ selInt ];
7690			}
7691			else if ( sel === null || sel === undefined || sel === '' ) {
7692				// Selector - none
7693				return rows;
7694			}
7695	
7696			// Selector - function
7697			if ( typeof sel === 'function' ) {
7698				return rows.map( function (idx) {
7699					var row = aoData[ idx ];
7700					return sel( idx, row._aData, row.nTr ) ? idx : null;
7701				} );
7702			}
7703	
7704			// Selector - node
7705			if ( sel.nodeName ) {
7706				var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
7707				var cellIdx = sel._DT_CellIndex;
7708	
7709				if ( rowIdx !== undefined ) {
7710					// Make sure that the row is actually still present in the table
7711					return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7712						[ rowIdx ] :
7713						[];
7714				}
7715				else if ( cellIdx ) {
7716					return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
7717						[ cellIdx.row ] :
7718						[];
7719				}
7720				else {
7721					var host = $(sel).closest('*[data-dt-row]');
7722					return host.length ?
7723						[ host.data('dt-row') ] :
7724						[];
7725				}
7726			}
7727	
7728			// ID selector. Want to always be able to select rows by id, regardless
7729			// of if the tr element has been created or not, so can't rely upon
7730			// jQuery here - hence a custom implementation. This does not match
7731			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7732			// but to select it using a CSS selector engine (like Sizzle or
7733			// querySelect) it would need to need to be escaped for some characters.
7734			// DataTables simplifies this for row selectors since you can select
7735			// only a row. A # indicates an id any anything that follows is the id -
7736			// unescaped.
7737			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7738				// get row index from id
7739				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7740				if ( rowObj !== undefined ) {
7741					return [ rowObj.idx ];
7742				}
7743	
7744				// need to fall through to jQuery in case there is DOM id that
7745				// matches
7746			}
7747			
7748			// Get nodes in the order from the `rows` array with null values removed
7749			var nodes = _removeEmpty(
7750				_pluck_order( settings.aoData, rows, 'nTr' )
7751			);
7752	
7753			// Selector - jQuery selector string, array of nodes or jQuery object/
7754			// As jQuery's .filter() allows jQuery objects to be passed in filter,
7755			// it also allows arrays, so this will cope with all three options
7756			return $(nodes)
7757				.filter( sel )
7758				.map( function () {
7759					return this._DT_RowIndex;
7760				} )
7761				.toArray();
7762		};
7763	
7764		var matched = _selector_run( 'row', selector, run, settings, opts );
7765	
7766		if (opts.order === 'current' || opts.order === 'applied') {
7767			_fnSortDisplay(settings, matched);
7768		}
7769	
7770		return matched;
7771	};
7772	
7773	
7774	_api_register( 'rows()', function ( selector, opts ) {
7775		// argument shifting
7776		if ( selector === undefined ) {
7777			selector = '';
7778		}
7779		else if ( $.isPlainObject( selector ) ) {
7780			opts = selector;
7781			selector = '';
7782		}
7783	
7784		opts = _selector_opts( opts );
7785	
7786		var inst = this.iterator( 'table', function ( settings ) {
7787			return __row_selector( settings, selector, opts );
7788		}, 1 );
7789	
7790		// Want argument shifting here and in __row_selector?
7791		inst.selector.rows = selector;
7792		inst.selector.opts = opts;
7793	
7794		return inst;
7795	} );
7796	
7797	_api_register( 'rows().nodes()', function () {
7798		return this.iterator( 'row', function ( settings, row ) {
7799			return settings.aoData[ row ].nTr || undefined;
7800		}, 1 );
7801	} );
7802	
7803	_api_register( 'rows().data()', function () {
7804		return this.iterator( true, 'rows', function ( settings, rows ) {
7805			return _pluck_order( settings.aoData, rows, '_aData' );
7806		}, 1 );
7807	} );
7808	
7809	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7810		return this.iterator( 'row', function ( settings, row ) {
7811			var r = settings.aoData[ row ];
7812			return type === 'search' ? r._aFilterData : r._aSortData;
7813		}, 1 );
7814	} );
7815	
7816	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7817		return this.iterator( 'row', function ( settings, row ) {
7818			_fnInvalidate( settings, row, src );
7819		} );
7820	} );
7821	
7822	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7823		return this.iterator( 'row', function ( settings, row ) {
7824			return row;
7825		}, 1 );
7826	} );
7827	
7828	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7829		var a = [];
7830		var context = this.context;
7831	
7832		// `iterator` will drop undefined values, but in this case we want them
7833		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7834			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7835				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7836				a.push( (hash === true ? '#' : '' )+ id );
7837			}
7838		}
7839	
7840		return new _Api( context, a );
7841	} );
7842	
7843	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7844		this.iterator( 'row', function ( settings, row ) {
7845			var data = settings.aoData;
7846			var rowData = data[ row ];
7847	
7848			// Delete from the display arrays
7849			var idx = settings.aiDisplayMaster.indexOf(row);
7850			if (idx !== -1) {
7851				settings.aiDisplayMaster.splice(idx, 1);
7852			}
7853	
7854			// For server-side processing tables - subtract the deleted row from the count
7855			if ( settings._iRecordsDisplay > 0 ) {
7856				settings._iRecordsDisplay--;
7857			}
7858	
7859			// Check for an 'overflow' they case for displaying the table
7860			_fnLengthOverflow( settings );
7861	
7862			// Remove the row's ID reference if there is one
7863			var id = settings.rowIdFn( rowData._aData );
7864			if ( id !== undefined ) {
7865				delete settings.aIds[ id ];
7866			}
7867	
7868			data[row] = null;
7869		} );
7870	
7871		return this;
7872	} );
7873	
7874	
7875	_api_register( 'rows.add()', function ( rows ) {
7876		var newRows = this.iterator( 'table', function ( settings ) {
7877				var row, i, ien;
7878				var out = [];
7879	
7880				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7881					row = rows[i];
7882	
7883					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7884						out.push( _fnAddTr( settings, row )[0] );
7885					}
7886					else {
7887						out.push( _fnAddData( settings, row ) );
7888					}
7889				}
7890	
7891				return out;
7892			}, 1 );
7893	
7894		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
7895		var modRows = this.rows( -1 );
7896		modRows.pop();
7897		modRows.push.apply(modRows, newRows);
7898	
7899		return modRows;
7900	} );
7901	
7902	
7903	
7904	
7905	
7906	/**
7907	 *
7908	 */
7909	_api_register( 'row()', function ( selector, opts ) {
7910		return _selector_first( this.rows( selector, opts ) );
7911	} );
7912	
7913	
7914	_api_register( 'row().data()', function ( data ) {
7915		var ctx = this.context;
7916	
7917		if ( data === undefined ) {
7918			// Get
7919			return ctx.length && this.length && this[0].length ?
7920				ctx[0].aoData[ this[0] ]._aData :
7921				undefined;
7922		}
7923	
7924		// Set
7925		var row = ctx[0].aoData[ this[0] ];
7926		row._aData = data;
7927	
7928		// If the DOM has an id, and the data source is an array
7929		if ( Array.isArray( data ) && row.nTr && row.nTr.id ) {
7930			_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
7931		}
7932	
7933		// Automatically invalidate
7934		_fnInvalidate( ctx[0], this[0], 'data' );
7935	
7936		return this;
7937	} );
7938	
7939	
7940	_api_register( 'row().node()', function () {
7941		var ctx = this.context;
7942	
7943		if (ctx.length && this.length && this[0].length) {
7944			var row = ctx[0].aoData[ this[0] ];
7945	
7946			if (row && row.nTr) {
7947				return row.nTr;
7948			}
7949		}
7950	
7951		return null;
7952	} );
7953	
7954	
7955	_api_register( 'row.add()', function ( row ) {
7956		// Allow a jQuery object to be passed in - only a single row is added from
7957		// it though - the first element in the set
7958		if ( row instanceof $ && row.length ) {
7959			row = row[0];
7960		}
7961	
7962		var rows = this.iterator( 'table', function ( settings ) {
7963			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7964				return _fnAddTr( settings, row )[0];
7965			}
7966			return _fnAddData( settings, row );
7967		} );
7968	
7969		// Return an Api.rows() extended instance, with the newly added row selected
7970		return this.row( rows[0] );
7971	} );
7972	
7973	
7974	$(document).on('plugin-init.dt', function (e, context) {
7975		var api = new _Api( context );
7976	
7977		api.on( 'stateSaveParams.DT', function ( e, settings, d ) {
7978			// This could be more compact with the API, but it is a lot faster as a simple
7979			// internal loop
7980			var idFn = settings.rowIdFn;
7981			var rows = settings.aiDisplayMaster;
7982			var ids = [];
7983	
7984			for (var i=0 ; i<rows.length ; i++) {
7985				var rowIdx = rows[i];
7986				var data = settings.aoData[rowIdx];
7987	
7988				if (data._detailsShow) {
7989					ids.push( '#' + idFn(data._aData) );
7990				}
7991			}
7992	
7993			d.childRows = ids;
7994		});
7995	
7996		// For future state loads (e.g. with StateRestore)
7997		api.on( 'stateLoaded.DT', function (e, settings, state) {
7998			__details_state_load( api, state );
7999		});
8000	
8001		// And the initial load state
8002		__details_state_load( api, api.state.loaded() );
8003	});
8004	
8005	var __details_state_load = function (api, state)
8006	{
8007		if ( state && state.childRows ) {
8008			api
8009				.rows( state.childRows.map(function (id) {
8010					// Escape any `:` characters from the row id. Accounts for
8011					// already escaped characters.
8012					return id.replace(/([^:\\]*(?:\\.[^:\\]*)*):/g, "$1\\:");
8013				}) )
8014				.every( function () {
8015					_fnCallbackFire( api.settings()[0], null, 'requestChild', [ this ] )
8016				});
8017		}
8018	}
8019	
8020	var __details_add = function ( ctx, row, data, klass )
8021	{
8022		// Convert to array of TR elements
8023		var rows = [];
8024		var addRow = function ( r, k ) {
8025			// Recursion to allow for arrays of jQuery objects
8026			if ( Array.isArray( r ) || r instanceof $ ) {
8027				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8028					addRow( r[i], k );
8029				}
8030				return;
8031			}
8032	
8033			// If we get a TR element, then just add it directly - up to the dev
8034			// to add the correct number of columns etc
8035			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8036				r.setAttribute( 'data-dt-row', row.idx );
8037				rows.push( r );
8038			}
8039			else {
8040				// Otherwise create a row with a wrapper
8041				var created = $('<tr><td></td></tr>')
8042					.attr( 'data-dt-row', row.idx )
8043					.addClass( k );
8044				
8045				$('td', created)
8046					.addClass( k )
8047					.html( r )[0].colSpan = _fnVisbleColumns( ctx );
8048	
8049				rows.push( created[0] );
8050			}
8051		};
8052	
8053		addRow( data, klass );
8054	
8055		if ( row._details ) {
8056			row._details.detach();
8057		}
8058	
8059		row._details = $(rows);
8060	
8061		// If the children were already shown, that state should be retained
8062		if ( row._detailsShow ) {
8063			row._details.insertAfter( row.nTr );
8064		}
8065	};
8066	
8067	
8068	// Make state saving of child row details async to allow them to be batch processed
8069	var __details_state = DataTable.util.throttle(
8070		function (ctx) {
8071			_fnSaveState( ctx[0] )
8072		},
8073		500
8074	);
8075	
8076	
8077	var __details_remove = function ( api, idx )
8078	{
8079		var ctx = api.context;
8080	
8081		if ( ctx.length ) {
8082			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8083	
8084			if ( row && row._details ) {
8085				row._details.remove();
8086	
8087				row._detailsShow = undefined;
8088				row._details = undefined;
8089				$( row.nTr ).removeClass( 'dt-hasChild' );
8090				__details_state( ctx );
8091			}
8092		}
8093	};
8094	
8095	
8096	var __details_display = function ( api, show ) {
8097		var ctx = api.context;
8098	
8099		if ( ctx.length && api.length ) {
8100			var row = ctx[0].aoData[ api[0] ];
8101	
8102			if ( row._details ) {
8103				row._detailsShow = show;
8104	
8105				if ( show ) {
8106					row._details.insertAfter( row.nTr );
8107					$( row.nTr ).addClass( 'dt-hasChild' );
8108				}
8109				else {
8110					row._details.detach();
8111					$( row.nTr ).removeClass( 'dt-hasChild' );
8112				}
8113	
8114				_fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )
8115	
8116				__details_events( ctx[0] );
8117				__details_state( ctx );
8118			}
8119		}
8120	};
8121	
8122	
8123	var __details_events = function ( settings )
8124	{
8125		var api = new _Api( settings );
8126		var namespace = '.dt.DT_details';
8127		var drawEvent = 'draw'+namespace;
8128		var colvisEvent = 'column-sizing'+namespace;
8129		var destroyEvent = 'destroy'+namespace;
8130		var data = settings.aoData;
8131	
8132		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8133	
8134		if ( _pluck( data, '_details' ).length > 0 ) {
8135			// On each draw, insert the required elements into the document
8136			api.on( drawEvent, function ( e, ctx ) {
8137				if ( settings !== ctx ) {
8138					return;
8139				}
8140	
8141				api.rows( {page:'current'} ).eq(0).each( function (idx) {
8142					// Internal data grab
8143					var row = data[ idx ];
8144	
8145					if ( row._detailsShow ) {
8146						row._details.insertAfter( row.nTr );
8147					}
8148				} );
8149			} );
8150	
8151			// Column visibility change - update the colspan
8152			api.on( colvisEvent, function ( e, ctx ) {
8153				if ( settings !== ctx ) {
8154					return;
8155				}
8156	
8157				// Update the colspan for the details rows (note, only if it already has
8158				// a colspan)
8159				var row, visible = _fnVisbleColumns( ctx );
8160	
8161				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8162					row = data[i];
8163	
8164					if ( row && row._details ) {
8165						row._details.each(function () {
8166							var el = $(this).children('td');
8167	
8168							if (el.length == 1) {
8169								el.attr('colspan', visible);
8170							}
8171						});
8172					}
8173				}
8174			} );
8175	
8176			// Table destroyed - nuke any child rows
8177			api.on( destroyEvent, function ( e, ctx ) {
8178				if ( settings !== ctx ) {
8179					return;
8180				}
8181	
8182				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8183					if ( data[i] && data[i]._details ) {
8184						__details_remove( api, i );
8185					}
8186				}
8187			} );
8188		}
8189	};
8190	
8191	// Strings for the method names to help minification
8192	var _emp = '';
8193	var _child_obj = _emp+'row().child';
8194	var _child_mth = _child_obj+'()';
8195	
8196	// data can be:
8197	//  tr
8198	//  string
8199	//  jQuery or array of any of the above
8200	_api_register( _child_mth, function ( data, klass ) {
8201		var ctx = this.context;
8202	
8203		if ( data === undefined ) {
8204			// get
8205			return ctx.length && this.length && ctx[0].aoData[ this[0] ]
8206				? ctx[0].aoData[ this[0] ]._details
8207				: undefined;
8208		}
8209		else if ( data === true ) {
8210			// show
8211			this.child.show();
8212		}
8213		else if ( data === false ) {
8214			// remove
8215			__details_remove( this );
8216		}
8217		else if ( ctx.length && this.length ) {
8218			// set
8219			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8220		}
8221	
8222		return this;
8223	} );
8224	
8225	
8226	_api_register( [
8227		_child_obj+'.show()',
8228		_child_mth+'.show()' // only when `child()` was called with parameters (without
8229	], function () {         // it returns an object and this method is not executed)
8230		__details_display( this, true );
8231		return this;
8232	} );
8233	
8234	
8235	_api_register( [
8236		_child_obj+'.hide()',
8237		_child_mth+'.hide()' // only when `child()` was called with parameters (without
8238	], function () {         // it returns an object and this method is not executed)
8239		__details_display( this, false );
8240		return this;
8241	} );
8242	
8243	
8244	_api_register( [
8245		_child_obj+'.remove()',
8246		_child_mth+'.remove()' // only when `child()` was called with parameters (without
8247	], function () {           // it returns an object and this method is not executed)
8248		__details_remove( this );
8249		return this;
8250	} );
8251	
8252	
8253	_api_register( _child_obj+'.isShown()', function () {
8254		var ctx = this.context;
8255	
8256		if ( ctx.length && this.length && ctx[0].aoData[ this[0] ] ) {
8257			// _detailsShown as false or undefined will fall through to return false
8258			return ctx[0].aoData[ this[0] ]._detailsShow || false;
8259		}
8260		return false;
8261	} );
8262	
8263	
8264	
8265	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8266	 * Columns
8267	 *
8268	 * {integer}           - column index (>=0 count from left, <0 count from right)
8269	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8270	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8271	 * "{string}:name"     - column name
8272	 * "{string}"          - jQuery selector on column header nodes
8273	 *
8274	 */
8275	
8276	// can be an array of these items, comma separated list, or an array of comma
8277	// separated lists
8278	
8279	var __re_column_selector = /^([^:]+)?:(name|title|visIdx|visible)$/;
8280	
8281	
8282	// r1 and r2 are redundant - but it means that the parameters match for the
8283	// iterator callback in columns().data()
8284	var __columnData = function ( settings, column, r1, r2, rows, type ) {
8285		var a = [];
8286		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8287			a.push( _fnGetCellData( settings, rows[row], column, type ) );
8288		}
8289		return a;
8290	};
8291	
8292	
8293	var __column_header = function ( settings, column, row ) {
8294		var header = settings.aoHeader;
8295		var target = row !== undefined
8296			? row
8297			: settings.bSortCellsTop // legacy support
8298				? 0
8299				: header.length - 1;
8300	
8301		return header[target][column].cell;
8302	};
8303	
8304	var __column_selector = function ( settings, selector, opts )
8305	{
8306		var
8307			columns = settings.aoColumns,
8308			names = _pluck( columns, 'sName' ),
8309			titles = _pluck( columns, 'sTitle' ),
8310			cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
8311			nodes = _unique( _flatten([], cells) );
8312		
8313		var run = function ( s ) {
8314			var selInt = _intVal( s );
8315	
8316			// Selector - all
8317			if ( s === '' ) {
8318				return _range( columns.length );
8319			}
8320	
8321			// Selector - index
8322			if ( selInt !== null ) {
8323				return [ selInt >= 0 ?
8324					selInt : // Count from left
8325					columns.length + selInt // Count from right (+ because its a negative value)
8326				];
8327			}
8328	
8329			// Selector = function
8330			if ( typeof s === 'function' ) {
8331				var rows = _selector_row_indexes( settings, opts );
8332	
8333				return columns.map(function (col, idx) {
8334					return s(
8335							idx,
8336							__columnData( settings, idx, 0, 0, rows ),
8337							__column_header( settings, idx )
8338						) ? idx : null;
8339				});
8340			}
8341	
8342			// jQuery or string selector
8343			var match = typeof s === 'string' ?
8344				s.match( __re_column_selector ) :
8345				'';
8346	
8347			if ( match ) {
8348				switch( match[2] ) {
8349					case 'visIdx':
8350					case 'visible':
8351						if (match[1]) {
8352							var idx = parseInt( match[1], 10 );
8353							// Visible index given, convert to column index
8354							if ( idx < 0 ) {
8355								// Counting from the right
8356								var visColumns = columns.map( function (col,i) {
8357									return col.bVisible ? i : null;
8358								} );
8359								return [ visColumns[ visColumns.length + idx ] ];
8360							}
8361							// Counting from the left
8362							return [ _fnVisibleToColumnIndex( settings, idx ) ];
8363						}
8364						
8365						// `:visible` on its own
8366						return columns.map( function (col, i) {
8367							return col.bVisible ? i : null;
8368						} );
8369	
8370					case 'name':
8371						// match by name. `names` is column index complete and in order
8372						return names.map( function (name, i) {
8373							return name === match[1] ? i : null;
8374						} );
8375	
8376					case 'title':
8377						// match by column title
8378						return titles.map( function (title, i) {
8379							return title === match[1] ? i : null;
8380						} );
8381	
8382					default:
8383						return [];
8384				}
8385			}
8386	
8387			// Cell in the table body
8388			if ( s.nodeName && s._DT_CellIndex ) {
8389				return [ s._DT_CellIndex.column ];
8390			}
8391	
8392			// jQuery selector on the TH elements for the columns
8393			var jqResult = $( nodes )
8394				.filter( s )
8395				.map( function () {
8396					return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
8397				} )
8398				.toArray();
8399	
8400			if ( jqResult.length || ! s.nodeName ) {
8401				return jqResult;
8402			}
8403	
8404			// Otherwise a node which might have a `dt-column` data attribute, or be
8405			// a child or such an element
8406			var host = $(s).closest('*[data-dt-column]');
8407			return host.length ?
8408				[ host.data('dt-column') ] :
8409				[];
8410		};
8411	
8412		return _selector_run( 'column', selector, run, settings, opts );
8413	};
8414	
8415	
8416	var __setColumnVis = function ( settings, column, vis ) {
8417		var
8418			cols = settings.aoColumns,
8419			col  = cols[ column ],
8420			data = settings.aoData,
8421			cells, i, ien, tr;
8422	
8423		// Get
8424		if ( vis === undefined ) {
8425			return col.bVisible;
8426		}
8427	
8428		// Set
8429		// No change
8430		if ( col.bVisible === vis ) {
8431			return false;
8432		}
8433	
8434		if ( vis ) {
8435			// Insert column
8436			// Need to decide if we should use appendChild or insertBefore
8437			var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column+1);
8438	
8439			for ( i=0, ien=data.length ; i<ien ; i++ ) {
8440				if (data[i]) {
8441					tr = data[i].nTr;
8442					cells = data[i].anCells;
8443	
8444					if ( tr ) {
8445						// insertBefore can act like appendChild if 2nd arg is null
8446						tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8447					}
8448				}
8449			}
8450		}
8451		else {
8452			// Remove column
8453			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
8454		}
8455	
8456		// Common actions
8457		col.bVisible = vis;
8458	
8459		_colGroup(settings);
8460		
8461		return true;
8462	};
8463	
8464	
8465	_api_register( 'columns()', function ( selector, opts ) {
8466		// argument shifting
8467		if ( selector === undefined ) {
8468			selector = '';
8469		}
8470		else if ( $.isPlainObject( selector ) ) {
8471			opts = selector;
8472			selector = '';
8473		}
8474	
8475		opts = _selector_opts( opts );
8476	
8477		var inst = this.iterator( 'table', function ( settings ) {
8478			return __column_selector( settings, selector, opts );
8479		}, 1 );
8480	
8481		// Want argument shifting here and in _row_selector?
8482		inst.selector.cols = selector;
8483		inst.selector.opts = opts;
8484	
8485		return inst;
8486	} );
8487	
8488	_api_registerPlural( 'columns().header()', 'column().header()', function ( row ) {
8489		return this.iterator( 'column', function (settings, column) {
8490			return __column_header(settings, column, row);
8491		}, 1 );
8492	} );
8493	
8494	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( row ) {
8495		return this.iterator( 'column', function ( settings, column ) {
8496			var footer = settings.aoFooter;
8497	
8498			if (! footer.length) {
8499				return null;
8500			}
8501	
8502			return settings.aoFooter[row !== undefined ? row : 0][column].cell;
8503		}, 1 );
8504	} );
8505	
8506	_api_registerPlural( 'columns().data()', 'column().data()', function () {
8507		return this.iterator( 'column-rows', __columnData, 1 );
8508	} );
8509	
8510	_api_registerPlural( 'columns().render()', 'column().render()', function ( type ) {
8511		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8512			return __columnData( settings, column, i, j, rows, type );
8513		}, 1 );
8514	} );
8515	
8516	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8517		return this.iterator( 'column', function ( settings, column ) {
8518			return settings.aoColumns[column].mData;
8519		}, 1 );
8520	} );
8521	
8522	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8523		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8524			return _pluck_order( settings.aoData, rows,
8525				type === 'search' ? '_aFilterData' : '_aSortData', column
8526			);
8527		}, 1 );
8528	} );
8529	
8530	_api_registerPlural( 'columns().init()', 'column().init()', function () {
8531		return this.iterator( 'column', function ( settings, column ) {
8532			return settings.aoColumns[column];
8533		}, 1 );
8534	} );
8535	
8536	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8537		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8538			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8539		}, 1 );
8540	} );
8541	
8542	_api_registerPlural( 'columns().titles()', 'column().title()', function (title, row) {
8543		return this.iterator( 'column', function ( settings, column ) {
8544			// Argument shifting
8545			if (typeof title === 'number') {
8546				row = title;
8547				title = undefined;
8548			}
8549	
8550			var span = $('span.dt-column-title', this.column(column).header(row));
8551	
8552			if (title !== undefined) {
8553				span.html(title);
8554				return this;
8555			}
8556	
8557			return span.html();
8558		}, 1 );
8559	} );
8560	
8561	_api_registerPlural( 'columns().types()', 'column().type()', function () {
8562		return this.iterator( 'column', function ( settings, column ) {
8563			var type = settings.aoColumns[column].sType;
8564	
8565			// If the type was invalidated, then resolve it. This actually does
8566			// all columns at the moment. Would only happen once if getting all
8567			// column's data types.
8568			if (! type) {
8569				_fnColumnTypes(settings);
8570			}
8571	
8572			return type;
8573		}, 1 );
8574	} );
8575	
8576	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8577		var that = this;
8578		var changed = [];
8579		var ret = this.iterator( 'column', function ( settings, column ) {
8580			if ( vis === undefined ) {
8581				return settings.aoColumns[ column ].bVisible;
8582			} // else
8583			
8584			if (__setColumnVis( settings, column, vis )) {
8585				changed.push(column);
8586			}
8587		} );
8588	
8589		// Group the column visibility changes
8590		if ( vis !== undefined ) {
8591			this.iterator( 'table', function ( settings ) {
8592				// Redraw the header after changes
8593				_fnDrawHead( settings, settings.aoHeader );
8594				_fnDrawHead( settings, settings.aoFooter );
8595		
8596				// Update colspan for no records display. Child rows and extensions will use their own
8597				// listeners to do this - only need to update the empty table item here
8598				if ( ! settings.aiDisplay.length ) {
8599					$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8600				}
8601		
8602				_fnSaveState( settings );
8603	
8604				// Second loop once the first is done for events
8605				that.iterator( 'column', function ( settings, column ) {
8606					if (changed.includes(column)) {
8607						_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8608					}
8609				} );
8610	
8611				if ( changed.length && (calc === undefined || calc) ) {
8612					that.columns.adjust();
8613				}
8614			});
8615		}
8616	
8617		return ret;
8618	} );
8619	
8620	_api_registerPlural( 'columns().widths()', 'column().width()', function () {
8621		// Injects a fake row into the table for just a moment so the widths can
8622		// be read, regardless of colspan in the header and rows being present in
8623		// the body
8624		var columns = this.columns(':visible').count();
8625		var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
8626	
8627		$(this.table().body()).append(row);
8628	
8629		var widths = row.children().map(function () {
8630			return $(this).outerWidth();
8631		});
8632	
8633		row.remove();
8634		
8635		return this.iterator( 'column', function ( settings, column ) {
8636			var visIdx = _fnColumnIndexToVisible( settings, column );
8637	
8638			return visIdx !== null ? widths[visIdx] : 0;
8639		}, 1);
8640	} );
8641	
8642	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8643		return this.iterator( 'column', function ( settings, column ) {
8644			return type === 'visible' ?
8645				_fnColumnIndexToVisible( settings, column ) :
8646				column;
8647		}, 1 );
8648	} );
8649	
8650	_api_register( 'columns.adjust()', function () {
8651		return this.iterator( 'table', function ( settings ) {
8652			_fnAdjustColumnSizing( settings );
8653		}, 1 );
8654	} );
8655	
8656	_api_register( 'column.index()', function ( type, idx ) {
8657		if ( this.context.length !== 0 ) {
8658			var ctx = this.context[0];
8659	
8660			if ( type === 'fromVisible' || type === 'toData' ) {
8661				return _fnVisibleToColumnIndex( ctx, idx );
8662			}
8663			else if ( type === 'fromData' || type === 'toVisible' ) {
8664				return _fnColumnIndexToVisible( ctx, idx );
8665			}
8666		}
8667	} );
8668	
8669	_api_register( 'column()', function ( selector, opts ) {
8670		return _selector_first( this.columns( selector, opts ) );
8671	} );
8672	
8673	var __cell_selector = function ( settings, selector, opts )
8674	{
8675		var data = settings.aoData;
8676		var rows = _selector_row_indexes( settings, opts );
8677		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8678		var allCells = $(_flatten( [], cells ));
8679		var row;
8680		var columns = settings.aoColumns.length;
8681		var a, i, ien, j, o, host;
8682	
8683		var run = function ( s ) {
8684			var fnSelector = typeof s === 'function';
8685	
8686			if ( s === null || s === undefined || fnSelector ) {
8687				// All cells and function selectors
8688				a = [];
8689	
8690				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8691					row = rows[i];
8692	
8693					for ( j=0 ; j<columns ; j++ ) {
8694						o = {
8695							row: row,
8696							column: j
8697						};
8698	
8699						if ( fnSelector ) {
8700							// Selector - function
8701							host = data[ row ];
8702	
8703							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8704								a.push( o );
8705							}
8706						}
8707						else {
8708							// Selector - all
8709							a.push( o );
8710						}
8711					}
8712				}
8713	
8714				return a;
8715			}
8716			
8717			// Selector - index
8718			if ( $.isPlainObject( s ) ) {
8719				// Valid cell index and its in the array of selectable rows
8720				return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
8721					[s] :
8722					[];
8723			}
8724	
8725			// Selector - jQuery filtered cells
8726			var jqResult = allCells
8727				.filter( s )
8728				.map( function (i, el) {
8729					return { // use a new object, in case someone changes the values
8730						row:    el._DT_CellIndex.row,
8731						column: el._DT_CellIndex.column
8732					};
8733				} )
8734				.toArray();
8735	
8736			if ( jqResult.length || ! s.nodeName ) {
8737				return jqResult;
8738			}
8739	
8740			// Otherwise the selector is a node, and there is one last option - the
8741			// element might be a child of an element which has dt-row and dt-column
8742			// data attributes
8743			host = $(s).closest('*[data-dt-row]');
8744			return host.length ?
8745				[ {
8746					row: host.data('dt-row'),
8747					column: host.data('dt-column')
8748				} ] :
8749				[];
8750		};
8751	
8752		return _selector_run( 'cell', selector, run, settings, opts );
8753	};
8754	
8755	
8756	
8757	
8758	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8759		// Argument shifting
8760		if ( $.isPlainObject( rowSelector ) ) {
8761			// Indexes
8762			if ( rowSelector.row === undefined ) {
8763				// Selector options in first parameter
8764				opts = rowSelector;
8765				rowSelector = null;
8766			}
8767			else {
8768				// Cell index objects in first parameter
8769				opts = columnSelector;
8770				columnSelector = null;
8771			}
8772		}
8773		if ( $.isPlainObject( columnSelector ) ) {
8774			opts = columnSelector;
8775			columnSelector = null;
8776		}
8777	
8778		// Cell selector
8779		if ( columnSelector === null || columnSelector === undefined ) {
8780			return this.iterator( 'table', function ( settings ) {
8781				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8782			} );
8783		}
8784	
8785		// The default built in options need to apply to row and columns
8786		var internalOpts = opts ? {
8787			page: opts.page,
8788			order: opts.order,
8789			search: opts.search
8790		} : {};
8791	
8792		// Row + column selector
8793		var columns = this.columns( columnSelector, internalOpts );
8794		var rows = this.rows( rowSelector, internalOpts );
8795		var i, ien, j, jen;
8796	
8797		var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
8798			var a = [];
8799	
8800			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8801				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8802					a.push( {
8803						row:    rows[idx][i],
8804						column: columns[idx][j]
8805					} );
8806				}
8807			}
8808	
8809			return a;
8810		}, 1 );
8811	
8812		// There is currently only one extension which uses a cell selector extension
8813		// It is a _major_ performance drag to run this if it isn't needed, so this is
8814		// an extension specific check at the moment
8815		var cells = opts && opts.selected ?
8816			this.cells( cellsNoOpts, opts ) :
8817			cellsNoOpts;
8818	
8819		$.extend( cells.selector, {
8820			cols: columnSelector,
8821			rows: rowSelector,
8822			opts: opts
8823		} );
8824	
8825		return cells;
8826	} );
8827	
8828	
8829	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8830		return this.iterator( 'cell', function ( settings, row, column ) {
8831			var data = settings.aoData[ row ];
8832	
8833			return data && data.anCells ?
8834				data.anCells[ column ] :
8835				undefined;
8836		}, 1 );
8837	} );
8838	
8839	
8840	_api_register( 'cells().data()', function () {
8841		return this.iterator( 'cell', function ( settings, row, column ) {
8842			return _fnGetCellData( settings, row, column );
8843		}, 1 );
8844	} );
8845	
8846	
8847	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8848		type = type === 'search' ? '_aFilterData' : '_aSortData';
8849	
8850		return this.iterator( 'cell', function ( settings, row, column ) {
8851			return settings.aoData[ row ][ type ][ column ];
8852		}, 1 );
8853	} );
8854	
8855	
8856	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8857		return this.iterator( 'cell', function ( settings, row, column ) {
8858			return _fnGetCellData( settings, row, column, type );
8859		}, 1 );
8860	} );
8861	
8862	
8863	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8864		return this.iterator( 'cell', function ( settings, row, column ) {
8865			return {
8866				row: row,
8867				column: column,
8868				columnVisible: _fnColumnIndexToVisible( settings, column )
8869			};
8870		}, 1 );
8871	} );
8872	
8873	
8874	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8875		return this.iterator( 'cell', function ( settings, row, column ) {
8876			_fnInvalidate( settings, row, src, column );
8877		} );
8878	} );
8879	
8880	
8881	
8882	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8883		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8884	} );
8885	
8886	
8887	_api_register( 'cell().data()', function ( data ) {
8888		var ctx = this.context;
8889		var cell = this[0];
8890	
8891		if ( data === undefined ) {
8892			// Get
8893			return ctx.length && cell.length ?
8894				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8895				undefined;
8896		}
8897	
8898		// Set
8899		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8900		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8901	
8902		return this;
8903	} );
8904	
8905	
8906	
8907	/**
8908	 * Get current ordering (sorting) that has been applied to the table.
8909	 *
8910	 * @returns {array} 2D array containing the sorting information for the first
8911	 *   table in the current context. Each element in the parent array represents
8912	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
8913	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8914	 *   the column index that the sorting condition applies to, the second is the
8915	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
8916	 *   index of the sorting order from the `column.sorting` initialisation array.
8917	 *//**
8918	 * Set the ordering for the table.
8919	 *
8920	 * @param {integer} order Column index to sort upon.
8921	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8922	 * @returns {DataTables.Api} this
8923	 *//**
8924	 * Set the ordering for the table.
8925	 *
8926	 * @param {array} order 1D array of sorting information to be applied.
8927	 * @param {array} [...] Optional additional sorting conditions
8928	 * @returns {DataTables.Api} this
8929	 *//**
8930	 * Set the ordering for the table.
8931	 *
8932	 * @param {array} order 2D array of sorting information to be applied.
8933	 * @returns {DataTables.Api} this
8934	 */
8935	_api_register( 'order()', function ( order, dir ) {
8936		var ctx = this.context;
8937		var args = Array.prototype.slice.call( arguments );
8938	
8939		if ( order === undefined ) {
8940			// get
8941			return ctx.length !== 0 ?
8942				ctx[0].aaSorting :
8943				undefined;
8944		}
8945	
8946		// set
8947		if ( typeof order === 'number' ) {
8948			// Simple column / direction passed in
8949			order = [ [ order, dir ] ];
8950		}
8951		else if ( args.length > 1 ) {
8952			// Arguments passed in (list of 1D arrays)
8953			order = args;
8954		}
8955		// otherwise a 2D array was passed in
8956	
8957		return this.iterator( 'table', function ( settings ) {
8958			settings.aaSorting = Array.isArray(order) ? order.slice() : order;
8959		} );
8960	} );
8961	
8962	
8963	/**
8964	 * Attach a sort listener to an element for a given column
8965	 *
8966	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8967	 *   listener to. This can take the form of a single DOM node, a jQuery
8968	 *   collection of nodes or a jQuery selector which will identify the node(s).
8969	 * @param {integer} column the column that a click on this node will sort on
8970	 * @param {function} [callback] callback function when sort is run
8971	 * @returns {DataTables.Api} this
8972	 */
8973	_api_register( 'order.listener()', function ( node, column, callback ) {
8974		return this.iterator( 'table', function ( settings ) {
8975			_fnSortAttachListener(settings, node, {}, column, callback);
8976		} );
8977	} );
8978	
8979	
8980	_api_register( 'order.fixed()', function ( set ) {
8981		if ( ! set ) {
8982			var ctx = this.context;
8983			var fixed = ctx.length ?
8984				ctx[0].aaSortingFixed :
8985				undefined;
8986	
8987			return Array.isArray( fixed ) ?
8988				{ pre: fixed } :
8989				fixed;
8990		}
8991	
8992		return this.iterator( 'table', function ( settings ) {
8993			settings.aaSortingFixed = $.extend( true, {}, set );
8994		} );
8995	} );
8996	
8997	
8998	// Order by the selected column(s)
8999	_api_register( [
9000		'columns().order()',
9001		'column().order()'
9002	], function ( dir ) {
9003		var that = this;
9004	
9005		if ( ! dir ) {
9006			return this.iterator( 'column', function ( settings, idx ) {
9007				var sort = _fnSortFlatten( settings );
9008	
9009				for ( var i=0, ien=sort.length ; i<ien ; i++ ) {
9010					if ( sort[i].col === idx ) {
9011						return sort[i].dir;
9012					}
9013				}
9014	
9015				return null;
9016			}, 1 );
9017		}
9018		else {
9019			return this.iterator( 'table', function ( settings, i ) {
9020				settings.aaSorting = that[i].map( function (col) {
9021					return [ col, dir ];
9022				} );
9023			} );
9024		}
9025	} );
9026	
9027	_api_registerPlural('columns().orderable()', 'column().orderable()', function ( directions ) {
9028		return this.iterator( 'column', function ( settings, idx ) {
9029			var col = settings.aoColumns[idx];
9030	
9031			return directions ?
9032				col.asSorting :
9033				col.bSortable;
9034		}, 1 );
9035	} );
9036	
9037	
9038	_api_register( 'processing()', function ( show ) {
9039		return this.iterator( 'table', function ( ctx ) {
9040			_fnProcessingDisplay( ctx, show );
9041		} );
9042	} );
9043	
9044	
9045	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9046		var ctx = this.context;
9047	
9048		if ( input === undefined ) {
9049			// get
9050			return ctx.length !== 0 ?
9051				ctx[0].oPreviousSearch.search :
9052				undefined;
9053		}
9054	
9055		// set
9056		return this.iterator( 'table', function ( settings ) {
9057			if ( ! settings.oFeatures.bFilter ) {
9058				return;
9059			}
9060	
9061			if (typeof regex === 'object') {
9062				// New style options to pass to the search builder
9063				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, regex, {
9064					search: input
9065				} ) );
9066			}
9067			else {
9068				// Compat for the old options
9069				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, {
9070					search: input,
9071					regex:  regex === null ? false : regex,
9072					smart:  smart === null ? true  : smart,
9073					caseInsensitive: caseInsen === null ? true : caseInsen
9074				} ) );
9075			}
9076		} );
9077	} );
9078	
9079	_api_register( 'search.fixed()', function ( name, search ) {
9080		var ret = this.iterator( true, 'table', function ( settings ) {
9081			var fixed = settings.searchFixed;
9082	
9083			if (! name) {
9084				return Object.keys(fixed)
9085			}
9086			else if (search === undefined) {
9087				return fixed[name];
9088			}
9089			else if (search === null) {
9090				delete fixed[name];
9091			}
9092			else {
9093				fixed[name] = search;
9094			}
9095	
9096			return this;
9097		} );
9098	
9099		return name !== undefined && search === undefined
9100			? ret[0]
9101			: ret;
9102	} );
9103	
9104	_api_registerPlural(
9105		'columns().search()',
9106		'column().search()',
9107		function ( input, regex, smart, caseInsen ) {
9108			return this.iterator( 'column', function ( settings, column ) {
9109				var preSearch = settings.aoPreSearchCols;
9110	
9111				if ( input === undefined ) {
9112					// get
9113					return preSearch[ column ].search;
9114				}
9115	
9116				// set
9117				if ( ! settings.oFeatures.bFilter ) {
9118					return;
9119				}
9120	
9121				if (typeof regex === 'object') {
9122					// New style options to pass to the search builder
9123					$.extend( preSearch[ column ], regex, {
9124						search: input
9125					} );
9126				}
9127				else {
9128					// Old style (with not all options available)
9129					$.extend( preSearch[ column ], {
9130						search: input,
9131						regex:  regex === null ? false : regex,
9132						smart:  smart === null ? true  : smart,
9133						caseInsensitive: caseInsen === null ? true : caseInsen
9134					} );
9135				}
9136	
9137				_fnFilterComplete( settings, settings.oPreviousSearch );
9138			} );
9139		}
9140	);
9141	
9142	_api_register([
9143			'columns().search.fixed()',
9144			'column().search.fixed()'
9145		],
9146		function ( name, search ) {
9147			var ret = this.iterator( true, 'column', function ( settings, colIdx ) {
9148				var fixed = settings.aoColumns[colIdx].searchFixed;
9149	
9150				if (! name) {
9151					return Object.keys(fixed)
9152				}
9153				else if (search === undefined) {
9154					return fixed[name];
9155				}
9156				else if (search === null) {
9157					delete fixed[name];
9158				}
9159				else {
9160					fixed[name] = search;
9161				}
9162	
9163				return this;
9164			} );
9165	
9166			return name !== undefined && search === undefined
9167				? ret[0]
9168				: ret;
9169		}
9170	);
9171	/*
9172	 * State API methods
9173	 */
9174	
9175	_api_register( 'state()', function ( set, ignoreTime ) {
9176		// getter
9177		if ( ! set ) {
9178			return this.context.length ?
9179				this.context[0].oSavedState :
9180				null;
9181		}
9182	
9183		var setMutate = $.extend( true, {}, set );
9184	
9185		// setter
9186		return this.iterator( 'table', function ( settings ) {
9187			if ( ignoreTime !== false ) {
9188				setMutate.time = +new Date() + 100;
9189			}
9190	
9191			_fnImplementState( settings, setMutate, function(){} );
9192		} );
9193	} );
9194	
9195	
9196	_api_register( 'state.clear()', function () {
9197		return this.iterator( 'table', function ( settings ) {
9198			// Save an empty object
9199			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9200		} );
9201	} );
9202	
9203	
9204	_api_register( 'state.loaded()', function () {
9205		return this.context.length ?
9206			this.context[0].oLoadedState :
9207			null;
9208	} );
9209	
9210	
9211	_api_register( 'state.save()', function () {
9212		return this.iterator( 'table', function ( settings ) {
9213			_fnSaveState( settings );
9214		} );
9215	} );
9216	
9217	/**
9218	 * Set the jQuery or window object to be used by DataTables
9219	 *
9220	 * @param {*} module Library / container object
9221	 * @param {string} [type] Library or container type `lib`, `win` or `datetime`.
9222	 *   If not provided, automatic detection is attempted.
9223	 */
9224	DataTable.use = function (module, type) {
9225		if (type === 'lib' || module.fn) {
9226			$ = module;
9227		}
9228		else if (type == 'win' || module.document) {
9229			window = module;
9230			document = module.document;
9231		}
9232		else if (type === 'datetime' || module.type === 'DateTime') {
9233			DataTable.DateTime = module;
9234		}
9235	}
9236	
9237	/**
9238	 * CommonJS factory function pass through. This will check if the arguments
9239	 * given are a window object or a jQuery object. If so they are set
9240	 * accordingly.
9241	 * @param {*} root Window
9242	 * @param {*} jq jQUery
9243	 * @returns {boolean} Indicator
9244	 */
9245	DataTable.factory = function (root, jq) {
9246		var is = false;
9247	
9248		// Test if the first parameter is a window object
9249		if (root && root.document) {
9250			window = root;
9251			document = root.document;
9252		}
9253	
9254		// Test if the second parameter is a jQuery object
9255		if (jq && jq.fn && jq.fn.jquery) {
9256			$ = jq;
9257			is = true;
9258		}
9259	
9260		return is;
9261	}
9262	
9263	/**
9264	 * Provide a common method for plug-ins to check the version of DataTables being
9265	 * used, in order to ensure compatibility.
9266	 *
9267	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
9268	 *    Note that the formats "X" and "X.Y" are also acceptable.
9269	 *  @param {string} [version2=current DataTables version] As above, but optional.
9270	 *   If not given the current DataTables version will be used.
9271	 *  @returns {boolean} true if this version of DataTables is greater or equal to
9272	 *    the required version, or false if this version of DataTales is not
9273	 *    suitable
9274	 *  @static
9275	 *  @dtopt API-Static
9276	 *
9277	 *  @example
9278	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9279	 */
9280	DataTable.versionCheck = function( version, version2 )
9281	{
9282		var aThis = version2 ?
9283			version2.split('.') :
9284			DataTable.version.split('.');
9285		var aThat = version.split('.');
9286		var iThis, iThat;
9287	
9288		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9289			iThis = parseInt( aThis[i], 10 ) || 0;
9290			iThat = parseInt( aThat[i], 10 ) || 0;
9291	
9292			// Parts are the same, keep comparing
9293			if (iThis === iThat) {
9294				continue;
9295			}
9296	
9297			// Parts are different, return immediately
9298			return iThis > iThat;
9299		}
9300	
9301		return true;
9302	};
9303	
9304	
9305	/**
9306	 * Check if a `<table>` node is a DataTable table already or not.
9307	 *
9308	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9309	 *      selector for the table to test. Note that if more than more than one
9310	 *      table is passed on, only the first will be checked
9311	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
9312	 *  @static
9313	 *  @dtopt API-Static
9314	 *
9315	 *  @example
9316	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9317	 *      $('#example').dataTable();
9318	 *    }
9319	 */
9320	DataTable.isDataTable = function ( table )
9321	{
9322		var t = $(table).get(0);
9323		var is = false;
9324	
9325		if ( table instanceof DataTable.Api ) {
9326			return true;
9327		}
9328	
9329		$.each( DataTable.settings, function (i, o) {
9330			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9331			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9332	
9333			if ( o.nTable === t || head === t || foot === t ) {
9334				is = true;
9335			}
9336		} );
9337	
9338		return is;
9339	};
9340	
9341	
9342	/**
9343	 * Get all DataTable tables that have been initialised - optionally you can
9344	 * select to get only currently visible tables.
9345	 *
9346	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9347	 *    or visible tables only.
9348	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9349	 *    DataTables
9350	 *  @static
9351	 *  @dtopt API-Static
9352	 *
9353	 *  @example
9354	 *    $.each( $.fn.dataTable.tables(true), function () {
9355	 *      $(table).DataTable().columns.adjust();
9356	 *    } );
9357	 */
9358	DataTable.tables = function ( visible )
9359	{
9360		var api = false;
9361	
9362		if ( $.isPlainObject( visible ) ) {
9363			api = visible.api;
9364			visible = visible.visible;
9365		}
9366	
9367		var a = DataTable.settings
9368			.filter( function (o) {
9369				return !visible || (visible && $(o.nTable).is(':visible')) 
9370					? true
9371					: false;
9372			} )
9373			.map( function (o) {
9374				return o.nTable;
9375			});
9376	
9377		return api ?
9378			new _Api( a ) :
9379			a;
9380	};
9381	
9382	
9383	/**
9384	 * Convert from camel case parameters to Hungarian notation. This is made public
9385	 * for the extensions to provide the same ability as DataTables core to accept
9386	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9387	 * parameters.
9388	 *
9389	 *  @param {object} src The model object which holds all parameters that can be
9390	 *    mapped.
9391	 *  @param {object} user The object to convert from camel case to Hungarian.
9392	 *  @param {boolean} force When set to `true`, properties which already have a
9393	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
9394	 *    won't be.
9395	 */
9396	DataTable.camelToHungarian = _fnCamelToHungarian;
9397	
9398	
9399	
9400	/**
9401	 *
9402	 */
9403	_api_register( '$()', function ( selector, opts ) {
9404		var
9405			rows   = this.rows( opts ).nodes(), // Get all rows
9406			jqRows = $(rows);
9407	
9408		return $( [].concat(
9409			jqRows.filter( selector ).toArray(),
9410			jqRows.find( selector ).toArray()
9411		) );
9412	} );
9413	
9414	
9415	// jQuery functions to operate on the tables
9416	$.each( [ 'on', 'one', 'off' ], function (i, key) {
9417		_api_register( key+'()', function ( /* event, handler */ ) {
9418			var args = Array.prototype.slice.call(arguments);
9419	
9420			// Add the `dt` namespace automatically if it isn't already present
9421			args[0] = args[0].split( /\s/ ).map( function ( e ) {
9422				return ! e.match(/\.dt\b/) ?
9423					e+'.dt' :
9424					e;
9425				} ).join( ' ' );
9426	
9427			var inst = $( this.tables().nodes() );
9428			inst[key].apply( inst, args );
9429			return this;
9430		} );
9431	} );
9432	
9433	
9434	_api_register( 'clear()', function () {
9435		return this.iterator( 'table', function ( settings ) {
9436			_fnClearTable( settings );
9437		} );
9438	} );
9439	
9440	
9441	_api_register( 'error()', function (msg) {
9442		return this.iterator( 'table', function ( settings ) {
9443			_fnLog( settings, 0, msg );
9444		} );
9445	} );
9446	
9447	
9448	_api_register( 'settings()', function () {
9449		return new _Api( this.context, this.context );
9450	} );
9451	
9452	
9453	_api_register( 'init()', function () {
9454		var ctx = this.context;
9455		return ctx.length ? ctx[0].oInit : null;
9456	} );
9457	
9458	
9459	_api_register( 'data()', function () {
9460		return this.iterator( 'table', function ( settings ) {
9461			return _pluck( settings.aoData, '_aData' );
9462		} ).flatten();
9463	} );
9464	
9465	
9466	_api_register( 'trigger()', function ( name, args, bubbles ) {
9467		return this.iterator( 'table', function ( settings ) {
9468			return _fnCallbackFire( settings, null, name, args, bubbles );
9469		} ).flatten();
9470	} );
9471	
9472	
9473	_api_register( 'ready()', function ( fn ) {
9474		var ctx = this.context;
9475	
9476		// Get status of first table
9477		if (! fn) {
9478			return ctx.length
9479				? (ctx[0]._bInitComplete || false)
9480				: null;
9481		}
9482	
9483		// Function to run either once the table becomes ready or
9484		// immediately if it is already ready.
9485		return this.tables().every(function () {
9486			if (this.context[0]._bInitComplete) {
9487				fn.call(this);
9488			}
9489			else {
9490				this.on('init', function () {
9491					fn.call(this);
9492				});
9493			}
9494		} );
9495	} );
9496	
9497	
9498	_api_register( 'destroy()', function ( remove ) {
9499		remove = remove || false;
9500	
9501		return this.iterator( 'table', function ( settings ) {
9502			var classes   = settings.oClasses;
9503			var table     = settings.nTable;
9504			var tbody     = settings.nTBody;
9505			var thead     = settings.nTHead;
9506			var tfoot     = settings.nTFoot;
9507			var jqTable   = $(table);
9508			var jqTbody   = $(tbody);
9509			var jqWrapper = $(settings.nTableWrapper);
9510			var rows      = settings.aoData.map( function (r) { return r ? r.nTr : null; } );
9511			var orderClasses = classes.order;
9512	
9513			// Flag to note that the table is currently being destroyed - no action
9514			// should be taken
9515			settings.bDestroying = true;
9516	
9517			// Fire off the destroy callbacks for plug-ins etc
9518			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings], true );
9519	
9520			// If not being removed from the document, make all columns visible
9521			if ( ! remove ) {
9522				new _Api( settings ).columns().visible( true );
9523			}
9524	
9525			// Blitz all `DT` namespaced events (these are internal events, the
9526			// lowercase, `dt` events are user subscribed and they are responsible
9527			// for removing them
9528			jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9529			$(window).off('.DT-'+settings.sInstance);
9530	
9531			// When scrolling we had to break the table up - restore it
9532			if ( table != thead.parentNode ) {
9533				jqTable.children('thead').detach();
9534				jqTable.append( thead );
9535			}
9536	
9537			if ( tfoot && table != tfoot.parentNode ) {
9538				jqTable.children('tfoot').detach();
9539				jqTable.append( tfoot );
9540			}
9541	
9542			settings.colgroup.remove();
9543	
9544			settings.aaSorting = [];
9545			settings.aaSortingFixed = [];
9546			_fnSortingClasses( settings );
9547	
9548			$('th, td', thead)
9549				.removeClass(
9550					orderClasses.canAsc + ' ' +
9551					orderClasses.canDesc + ' ' +
9552					orderClasses.isAsc + ' ' +
9553					orderClasses.isDesc
9554				)
9555				.css('width', '');
9556	
9557			// Add the TR elements back into the table in their original order
9558			jqTbody.children().detach();
9559			jqTbody.append( rows );
9560	
9561			var orig = settings.nTableWrapper.parentNode;
9562			var insertBefore = settings.nTableWrapper.nextSibling;
9563	
9564			// Remove the DataTables generated nodes, events and classes
9565			var removedMethod = remove ? 'remove' : 'detach';
9566			jqTable[ removedMethod ]();
9567			jqWrapper[ removedMethod ]();
9568	
9569			// If we need to reattach the table to the document
9570			if ( ! remove && orig ) {
9571				// insertBefore acts like appendChild if !arg[1]
9572				orig.insertBefore( table, insertBefore );
9573	
9574				// Restore the width of the original table - was read from the style property,
9575				// so we can restore directly to that
9576				jqTable
9577					.css( 'width', settings.sDestroyWidth )
9578					.removeClass( classes.table );
9579			}
9580	
9581			/* Remove the settings object from the settings array */
9582			var idx = DataTable.settings.indexOf(settings);
9583			if ( idx !== -1 ) {
9584				DataTable.settings.splice( idx, 1 );
9585			}
9586		} );
9587	} );
9588	
9589	
9590	// Add the `every()` method for rows, columns and cells in a compact form
9591	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9592		_api_register( type+'s().every()', function ( fn ) {
9593			var opts = this.selector.opts;
9594			var api = this;
9595			var inst;
9596			var counter = 0;
9597	
9598			return this.iterator( 'every', function ( settings, selectedIdx, tableIdx ) {
9599				inst = api[ type ](selectedIdx, opts);
9600	
9601				if (type === 'cell') {
9602					fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
9603				}
9604				else {
9605					fn.call(inst, selectedIdx, tableIdx, counter);
9606				}
9607	
9608				counter++;
9609			} );
9610		} );
9611	} );
9612	
9613	
9614	// i18n method for extensions to be able to use the language object from the
9615	// DataTable
9616	_api_register( 'i18n()', function ( token, def, plural ) {
9617		var ctx = this.context[0];
9618		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9619	
9620		if ( resolved === undefined ) {
9621			resolved = def;
9622		}
9623	
9624		if ( $.isPlainObject( resolved ) ) {
9625			resolved = plural !== undefined && resolved[ plural ] !== undefined ?
9626				resolved[ plural ] :
9627				resolved._;
9628		}
9629	
9630		return typeof resolved === 'string'
9631			? resolved.replace( '%d', plural ) // nb: plural might be undefined,
9632			: resolved;
9633	} );
9634	
9635	/**
9636	 * Version string for plug-ins to check compatibility. Allowed format is
9637	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9638	 * only for non-release builds. See https://semver.org/ for more information.
9639	 *  @member
9640	 *  @type string
9641	 *  @default Version number
9642	 */
9643	DataTable.version = "2.0.8";
9644	
9645	/**
9646	 * Private data store, containing all of the settings objects that are
9647	 * created for the tables on a given page.
9648	 *
9649	 * Note that the `DataTable.settings` object is aliased to
9650	 * `jQuery.fn.dataTableExt` through which it may be accessed and
9651	 * manipulated, or `jQuery.fn.dataTable.settings`.
9652	 *  @member
9653	 *  @type array
9654	 *  @default []
9655	 *  @private
9656	 */
9657	DataTable.settings = [];
9658	
9659	/**
9660	 * Object models container, for the various models that DataTables has
9661	 * available to it. These models define the objects that are used to hold
9662	 * the active state and configuration of the table.
9663	 *  @namespace
9664	 */
9665	DataTable.models = {};
9666	
9667	
9668	
9669	/**
9670	 * Template object for the way in which DataTables holds information about
9671	 * search information for the global filter and individual column filters.
9672	 *  @namespace
9673	 */
9674	DataTable.models.oSearch = {
9675		/**
9676		 * Flag to indicate if the filtering should be case insensitive or not
9677		 */
9678		"caseInsensitive": true,
9679	
9680		/**
9681		 * Applied search term
9682		 */
9683		"search": "",
9684	
9685		/**
9686		 * Flag to indicate if the search term should be interpreted as a
9687		 * regular expression (true) or not (false) and therefore and special
9688		 * regex characters escaped.
9689		 */
9690		"regex": false,
9691	
9692		/**
9693		 * Flag to indicate if DataTables is to use its smart filtering or not.
9694		 */
9695		"smart": true,
9696	
9697		/**
9698		 * Flag to indicate if DataTables should only trigger a search when
9699		 * the return key is pressed.
9700		 */
9701		"return": false
9702	};
9703	
9704	
9705	
9706	
9707	/**
9708	 * Template object for the way in which DataTables holds information about
9709	 * each individual row. This is the object format used for the settings
9710	 * aoData array.
9711	 *  @namespace
9712	 */
9713	DataTable.models.oRow = {
9714		/**
9715		 * TR element for the row
9716		 */
9717		"nTr": null,
9718	
9719		/**
9720		 * Array of TD elements for each row. This is null until the row has been
9721		 * created.
9722		 */
9723		"anCells": null,
9724	
9725		/**
9726		 * Data object from the original data source for the row. This is either
9727		 * an array if using the traditional form of DataTables, or an object if
9728		 * using mData options. The exact type will depend on the passed in
9729		 * data from the data source, or will be an array if using DOM a data
9730		 * source.
9731		 */
9732		"_aData": [],
9733	
9734		/**
9735		 * Sorting data cache - this array is ostensibly the same length as the
9736		 * number of columns (although each index is generated only as it is
9737		 * needed), and holds the data that is used for sorting each column in the
9738		 * row. We do this cache generation at the start of the sort in order that
9739		 * the formatting of the sort data need be done only once for each cell
9740		 * per sort. This array should not be read from or written to by anything
9741		 * other than the master sorting methods.
9742		 */
9743		"_aSortData": null,
9744	
9745		/**
9746		 * Per cell filtering data cache. As per the sort data cache, used to
9747		 * increase the performance of the filtering in DataTables
9748		 */
9749		"_aFilterData": null,
9750	
9751		/**
9752		 * Filtering data cache. This is the same as the cell filtering cache, but
9753		 * in this case a string rather than an array. This is easily computed with
9754		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9755		 * needed on every search (memory traded for performance)
9756		 */
9757		"_sFilterRow": null,
9758	
9759		/**
9760		 * Denote if the original data source was from the DOM, or the data source
9761		 * object. This is used for invalidating data, so DataTables can
9762		 * automatically read data from the original source, unless uninstructed
9763		 * otherwise.
9764		 */
9765		"src": null,
9766	
9767		/**
9768		 * Index in the aoData array. This saves an indexOf lookup when we have the
9769		 * object, but want to know the index
9770		 */
9771		"idx": -1,
9772	
9773		/**
9774		 * Cached display value
9775		 */
9776		displayData: null
9777	};
9778	
9779	
9780	/**
9781	 * Template object for the column information object in DataTables. This object
9782	 * is held in the settings aoColumns array and contains all the information that
9783	 * DataTables needs about each individual column.
9784	 *
9785	 * Note that this object is related to {@link DataTable.defaults.column}
9786	 * but this one is the internal data store for DataTables's cache of columns.
9787	 * It should NOT be manipulated outside of DataTables. Any configuration should
9788	 * be done through the initialisation options.
9789	 *  @namespace
9790	 */
9791	DataTable.models.oColumn = {
9792		/**
9793		 * Column index.
9794		 */
9795		"idx": null,
9796	
9797		/**
9798		 * A list of the columns that sorting should occur on when this column
9799		 * is sorted. That this property is an array allows multi-column s
9799orting
9800		 * to be defined for a column (for example first name / last name columns
9801		 * would benefit from this). The values are integers pointing to the
9802		 * columns to be sorted on (typically it will be a single integer pointing
9803		 * at itself, but that doesn't need to be the case).
9804		 */
9805		"aDataSort": null,
9806	
9807		/**
9808		 * Define the sorting directions that are applied to the column, in sequence
9809		 * as the column is repeatedly sorted upon - i.e. the first value is used
9810		 * as the sorting direction when the column if first sorted (clicked on).
9811		 * Sort it again (click again) and it will move on to the next index.
9812		 * Repeat until loop.
9813		 */
9814		"asSorting": null,
9815	
9816		/**
9817		 * Flag to indicate if the column is searchable, and thus should be included
9818		 * in the filtering or not.
9819		 */
9820		"bSearchable": null,
9821	
9822		/**
9823		 * Flag to indicate if the column is sortable or not.
9824		 */
9825		"bSortable": null,
9826	
9827		/**
9828		 * Flag to indicate if the column is currently visible in the table or not
9829		 */
9830		"bVisible": null,
9831	
9832		/**
9833		 * Store for manual type assignment using the `column.type` option. This
9834		 * is held in store so we can manipulate the column's `sType` property.
9835		 */
9836		"_sManualType": null,
9837	
9838		/**
9839		 * Flag to indicate if HTML5 data attributes should be used as the data
9840		 * source for filtering or sorting. True is either are.
9841		 */
9842		"_bAttrSrc": false,
9843	
9844		/**
9845		 * Developer definable function that is called whenever a cell is created (Ajax source,
9846		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9847		 * allowing you to modify the DOM element (add background colour for example) when the
9848		 * element is available.
9849		 */
9850		"fnCreatedCell": null,
9851	
9852		/**
9853		 * Function to get data from a cell in a column. You should <b>never</b>
9854		 * access data directly through _aData internally in DataTables - always use
9855		 * the method attached to this property. It allows mData to function as
9856		 * required. This function is automatically assigned by the column
9857		 * initialisation method
9858		 */
9859		"fnGetData": null,
9860	
9861		/**
9862		 * Function to set data for a cell in the column. You should <b>never</b>
9863		 * set the data directly to _aData internally in DataTables - always use
9864		 * this method. It allows mData to function as required. This function
9865		 * is automatically assigned by the column initialisation method
9866		 */
9867		"fnSetData": null,
9868	
9869		/**
9870		 * Property to read the value for the cells in the column from the data
9871		 * source array / object. If null, then the default content is used, if a
9872		 * function is given then the return from the function is used.
9873		 */
9874		"mData": null,
9875	
9876		/**
9877		 * Partner property to mData which is used (only when defined) to get
9878		 * the data - i.e. it is basically the same as mData, but without the
9879		 * 'set' option, and also the data fed to it is the result from mData.
9880		 * This is the rendering method to match the data method of mData.
9881		 */
9882		"mRender": null,
9883	
9884		/**
9885		 * The class to apply to all TD elements in the table's TBODY for the column
9886		 */
9887		"sClass": null,
9888	
9889		/**
9890		 * When DataTables calculates the column widths to assign to each column,
9891		 * it finds the longest string in each column and then constructs a
9892		 * temporary table and reads the widths from that. The problem with this
9893		 * is that "mmm" is much wider then "iiii", but the latter is a longer
9894		 * string - thus the calculation can go wrong (doing it properly and putting
9895		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9896		 * a "work around" we provide this option. It will append its value to the
9897		 * text that is found to be the longest string for the column - i.e. padding.
9898		 */
9899		"sContentPadding": null,
9900	
9901		/**
9902		 * Allows a default value to be given for a column's data, and will be used
9903		 * whenever a null data source is encountered (this can be because mData
9904		 * is set to null, or because the data source itself is null).
9905		 */
9906		"sDefaultContent": null,
9907	
9908		/**
9909		 * Name for the column, allowing reference to the column by name as well as
9910		 * by index (needs a lookup to work by name).
9911		 */
9912		"sName": null,
9913	
9914		/**
9915		 * Custom sorting data type - defines which of the available plug-ins in
9916		 * afnSortData the custom sorting will use - if any is defined.
9917		 */
9918		"sSortDataType": 'std',
9919	
9920		/**
9921		 * Class to be applied to the header element when sorting on this column
9922		 */
9923		"sSortingClass": null,
9924	
9925		/**
9926		 * Title of the column - what is seen in the TH element (nTh).
9927		 */
9928		"sTitle": null,
9929	
9930		/**
9931		 * Column sorting and filtering type
9932		 */
9933		"sType": null,
9934	
9935		/**
9936		 * Width of the column
9937		 */
9938		"sWidth": null,
9939	
9940		/**
9941		 * Width of the column when it was first "encountered"
9942		 */
9943		"sWidthOrig": null,
9944	
9945		/** Cached string which is the longest in the column */
9946		maxLenString: null,
9947	
9948		/**
9949		 * Store for named searches
9950		 */
9951		searchFixed: null
9952	};
9953	
9954	
9955	/*
9956	 * Developer note: The properties of the object below are given in Hungarian
9957	 * notation, that was used as the interface for DataTables prior to v1.10, however
9958	 * from v1.10 onwards the primary interface is camel case. In order to avoid
9959	 * breaking backwards compatibility utterly with this change, the Hungarian
9960	 * version is still, internally the primary interface, but is is not documented
9961	 * - hence the @name tags in each doc comment. This allows a Javascript function
9962	 * to create a map from Hungarian notation to camel case (going the other direction
9963	 * would require each property to be listed, which would add around 3K to the size
9964	 * of DataTables, while this method is about a 0.5K hit).
9965	 *
9966	 * Ultimately this does pave the way for Hungarian notation to be dropped
9967	 * completely, but that is a massive amount of work and will break current
9968	 * installs (therefore is on-hold until v2).
9969	 */
9970	
9971	/**
9972	 * Initialisation options that can be given to DataTables at initialisation
9973	 * time.
9974	 *  @namespace
9975	 */
9976	DataTable.defaults = {
9977		/**
9978		 * An array of data to use for the table, passed in at initialisation which
9979		 * will be used in preference to any data which is already in the DOM. This is
9980		 * particularly useful for constructing tables purely in Javascript, for
9981		 * example with a custom Ajax call.
9982		 */
9983		"aaData": null,
9984	
9985	
9986		/**
9987		 * If ordering is enabled, then DataTables will perform a first pass sort on
9988		 * initialisation. You can define which column(s) the sort is performed
9989		 * upon, and the sorting direction, with this variable. The `sorting` array
9990		 * should contain an array for each column to be sorted initially containing
9991		 * the column's index and a direction string ('asc' or 'desc').
9992		 */
9993		"aaSorting": [[0,'asc']],
9994	
9995	
9996		/**
9997		 * This parameter is basically identical to the `sorting` parameter, but
9998		 * cannot be overridden by user interaction with the table. What this means
9999		 * is that you could have a column (visible or hidden) which the sorting
10000		 * will always be forced on first - any sorting after that (from the user)
10001		 * will then be performed as required. This can be useful for grouping rows
10002		 * together.
10003		 */
10004		"aaSortingFixed": [],
10005	
10006	
10007		/**
10008		 * DataTables can be instructed to load data to display in the table from a
10009		 * Ajax source. This option defines how that Ajax call is made and where to.
10010		 *
10011		 * The `ajax` property has three different modes of operation, depending on
10012		 * how it is defined. These are:
10013		 *
10014		 * * `string` - Set the URL from where the data should be loaded from.
10015		 * * `object` - Define properties for `jQuery.ajax`.
10016		 * * `function` - Custom data get function
10017		 *
10018		 * `string`
10019		 * --------
10020		 *
10021		 * As a string, the `ajax` property simply defines the URL from which
10022		 * DataTables will load data.
10023		 *
10024		 * `object`
10025		 * --------
10026		 *
10027		 * As an object, the parameters in the object are passed to
10028		 * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
10029		 * of the Ajax request. DataTables has a number of default parameters which
10030		 * you can override using this option. Please refer to the jQuery
10031		 * documentation for a full description of the options available, although
10032		 * the following parameters provide additional options in DataTables or
10033		 * require special consideration:
10034		 *
10035		 * * `data` - As with jQuery, `data` can be provided as an object, but it
10036		 *   can also be used as a function to manipulate the data DataTables sends
10037		 *   to the server. The function takes a single parameter, an object of
10038		 *   parameters with the values that DataTables has readied for sending. An
10039		 *   object may be returned which will be merged into the DataTables
10040		 *   defaults, or you can add the items to the object that was passed in and
10041		 *   not return anything from the function. This supersedes `fnServerParams`
10042		 *   from DataTables 1.9-.
10043		 *
10044		 * * `dataSrc` - By default DataTables will look for the property `data` (or
10045		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
10046		 *   from an Ajax source or for server-side processing - this parameter
10047		 *   allows that property to be changed. You can use Javascript dotted
10048		 *   object notation to get a data source for multiple levels of nesting, or
10049		 *   it my be used as a function. As a function it takes a single parameter,
10050		 *   the JSON returned from the server, which can be manipulated as
10051		 *   required, with the returned value being that used by DataTables as the
10052		 *   data source for the table.
10053		 *
10054		 * * `success` - Should not be overridden it is used internally in
10055		 *   DataTables. To manipulate / transform the data returned by the server
10056		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10057		 *
10058		 * `function`
10059		 * ----------
10060		 *
10061		 * As a function, making the Ajax call is left up to yourself allowing
10062		 * complete control of the Ajax request. Indeed, if desired, a method other
10063		 * than Ajax could be used to obtain the required data, such as Web storage
10064		 * or an AIR database.
10065		 *
10066		 * The function is given four parameters and no return is required. The
10067		 * parameters are:
10068		 *
10069		 * 1. _object_ - Data to send to the server
10070		 * 2. _function_ - Callback function that must be executed when the required
10071		 *    data has been obtained. That data should be passed into the callback
10072		 *    as the only parameter
10073		 * 3. _object_ - DataTables settings object for the table
10074		 */
10075		"ajax": null,
10076	
10077	
10078		/**
10079		 * This parameter allows you to readily specify the entries in the length drop
10080		 * down menu that DataTables shows when pagination is enabled. It can be
10081		 * either a 1D array of options which will be used for both the displayed
10082		 * option and the value, or a 2D array which will use the array in the first
10083		 * position as the value, and the array in the second position as the
10084		 * displayed options (useful for language strings such as 'All').
10085		 *
10086		 * Note that the `pageLength` property will be automatically set to the
10087		 * first value given in this array, unless `pageLength` is also provided.
10088		 */
10089		"aLengthMenu": [ 10, 25, 50, 100 ],
10090	
10091	
10092		/**
10093		 * The `columns` option in the initialisation parameter allows you to define
10094		 * details about the way individual columns behave. For a full list of
10095		 * column options that can be set, please see
10096		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10097		 * define your columns, you must have an entry in the array for every single
10098		 * column that you have in your table (these can be null if you don't which
10099		 * to specify any options).
10100		 */
10101		"aoColumns": null,
10102	
10103		/**
10104		 * Very similar to `columns`, `columnDefs` allows you to target a specific
10105		 * column, multiple columns, or all columns, using the `targets` property of
10106		 * each object in the array. This allows great flexibility when creating
10107		 * tables, as the `columnDefs` arrays can be of any length, targeting the
10108		 * columns you specifically want. `columnDefs` may use any of the column
10109		 * options available: {@link DataTable.defaults.column}, but it _must_
10110		 * have `targets` defined in each object in the array. Values in the `targets`
10111		 * array may be:
10112		 *   <ul>
10113		 *     <li>
10113a string - class name will be matched on the TH for the column</li>
10114		 *     <li>0 or a positive integer - column index counting from the left</li>
10115		 *     <li>a negative integer - column index counting from the right</li>
10116		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10117		 *   </ul>
10118		 */
10119		"aoColumnDefs": null,
10120	
10121	
10122		/**
10123		 * Basically the same as `search`, this parameter defines the individual column
10124		 * filtering state at initialisation time. The array must be of the same size
10125		 * as the number of columns, and each element be an object with the parameters
10126		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10127		 * accepted and the default will be used.
10128		 */
10129		"aoSearchCols": [],
10130	
10131	
10132		/**
10133		 * Enable or disable automatic column width calculation. This can be disabled
10134		 * as an optimisation (it takes some time to calculate the widths) if the
10135		 * tables widths are passed in using `columns`.
10136		 */
10137		"bAutoWidth": true,
10138	
10139	
10140		/**
10141		 * Deferred rendering can provide DataTables with a huge speed boost when you
10142		 * are using an Ajax or JS data source for the table. This option, when set to
10143		 * true, will cause DataTables to defer the creation of the table elements for
10144		 * each row until they are needed for a draw - saving a significant amount of
10145		 * time.
10146		 */
10147		"bDeferRender": true,
10148	
10149	
10150		/**
10151		 * Replace a DataTable which matches the given selector and replace it with
10152		 * one which has the properties of the new initialisation object passed. If no
10153		 * table matches the selector, then the new DataTable will be constructed as
10154		 * per normal.
10155		 */
10156		"bDestroy": false,
10157	
10158	
10159		/**
10160		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10161		 * that it allows the end user to input multiple words (space separated) and
10162		 * will match a row containing those words, even if not in the order that was
10163		 * specified (this allow matching across multiple columns). Note that if you
10164		 * wish to use filtering in DataTables this must remain 'true' - to remove the
10165		 * default filtering input box and retain filtering abilities, please use
10166		 * {@link DataTable.defaults.dom}.
10167		 */
10168		"bFilter": true,
10169	
10170		/**
10171		 * Used only for compatiblity with DT1
10172		 * @deprecated
10173		 */
10174		"bInfo": true,
10175	
10176		/**
10177		 * Used only for compatiblity with DT1
10178		 * @deprecated
10179		 */
10180		"bLengthChange": true,
10181	
10182		/**
10183		 * Enable or disable pagination.
10184		 */
10185		"bPaginate": true,
10186	
10187	
10188		/**
10189		 * Enable or disable the display of a 'processing' indicator when the table is
10190		 * being processed (e.g. a sort). This is particularly useful for tables with
10191		 * large amounts of data where it can take a noticeable amount of time to sort
10192		 * the entries.
10193		 */
10194		"bProcessing": false,
10195	
10196	
10197		/**
10198		 * Retrieve the DataTables object for the given selector. Note that if the
10199		 * table has already been initialised, this parameter will cause DataTables
10200		 * to simply return the object that has already been set up - it will not take
10201		 * account of any changes you might have made to the initialisation object
10202		 * passed to DataTables (setting this parameter to true is an acknowledgement
10203		 * that you understand this). `destroy` can be used to reinitialise a table if
10204		 * you need.
10205		 */
10206		"bRetrieve": false,
10207	
10208	
10209		/**
10210		 * When vertical (y) scrolling is enabled, DataTables will force the height of
10211		 * the table's viewport to the given height at all times (useful for layout).
10212		 * However, this can look odd when filtering data down to a small data set,
10213		 * and the footer is left "floating" further down. This parameter (when
10214		 * enabled) will cause DataTables to collapse the table's viewport down when
10215		 * the result set will fit within the given Y height.
10216		 */
10217		"bScrollCollapse": false,
10218	
10219	
10220		/**
10221		 * Configure DataTables to use server-side processing. Note that the
10222		 * `ajax` parameter must also be given in order to give DataTables a
10223		 * source to obtain the required data for each draw.
10224		 */
10225		"bServerSide": false,
10226	
10227	
10228		/**
10229		 * Enable or disable sorting of columns. Sorting of individual columns can be
10230		 * disabled by the `sortable` option for each column.
10231		 */
10232		"bSort": true,
10233	
10234	
10235		/**
10236		 * Enable or display DataTables' ability to sort multiple columns at the
10237		 * same time (activated by shift-click by the user).
10238		 */
10239		"bSortMulti": true,
10240	
10241	
10242		/**
10243		 * Allows control over whether DataTables should use the top (true) unique
10244		 * cell that is found for a single column, or the bottom (false - default).
10245		 * This is useful when using complex headers.
10246		 */
10247		"bSortCellsTop": null,
10248	
10249	
10250		/**
10251		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10252		 * `sorting\_3` to the columns which are currently being sorted on. This is
10253		 * presented as a feature switch as it can increase processing time (while
10254		 * classes are removed and added) so for large data sets you might want to
10255		 * turn this off.
10256		 */
10257		"bSortClasses": true,
10258	
10259	
10260		/**
10261		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10262		 * used to save table display information such as pagination information,
10263		 * display length, filtering and sorting. As such when the end user reloads
10264		 * the page the display display will match what thy had previously set up.
10265		 */
10266		"bStateSave": false,
10267	
10268	
10269		/**
10270		 * This function is called when a TR element is created (and all TD child
10271		 * elements have been inserted), or registered if using a DOM source, allowing
10272		 * manipulation of the TR element (adding classes etc).
10273		 */
10274		"fnCreatedRow": null,
10275	
10276	
10277		/**
10278		 * This function is called on every 'draw' event, and allows you to
10279		 * dynamically modify any aspect you want about the created DOM.
10280		 */
10281		"fnDrawCallback": null,
10282	
10283	
10284		/**
10285		 * Identical to fnHeaderCallback() but for the table footer this function
10286		 * allows you to modify the table footer on every 'draw' event.
10287		 */
10288		"fnFooterCallback": null,
10289	
10290	
10291		/**
10292		 * When rendering large numbers in the information element for the table
10293		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10294		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10295		 * rendered as "1,000,000") to help readability for the end user. This
10296		 * function will override the default method DataTables uses.
10297		 */
10298		"fnFormatNumber": function ( toFormat ) {
10299			return toFormat.toString().replace(
10300				/\B(?=(\d{3})+(?!\d))/g,
10301				this.oLanguage.sThousands
10302			);
10303		},
10304	
10305	
10306		/**
10307		 * This function is called on every 'draw' event, and allows you to
10308		 * dynamically modify the header row. This can be used to calculate and
10309		 * display useful information about the table.
10310		 */
10311		"fnHeaderCallback": null,
10312	
10313	
10314		/**
10315		 * The information element can be used to convey information about the current
10316		 * state of the table. Although the internationalisation options presented by
10317		 * DataTables are quite capable of dealing with most customisations, there may
10318		 * be times where you wish to customise the string further. This callback
10319		 * allows you to do exactly that.
10320		 */
10321		"fnInfoCallback": null,
10322	
10323	
10324		/**
10325		 * Called when the table has been initialised. Normally DataTables will
10326		 * initialise sequentially and there will be no need for this function,
10327		 * however, this does not hold true when using external language information
10328		 * since that is obtained using an async XHR call.
10329		 */
10330		"fnInitComplete": null,
10331	
10332	
10333		/**
10334		 * Called at the very start of each table draw and can be used to cancel the
10335		 * draw by returning false, any other return (including undefined) results in
10336		 * the full draw occurring).
10337		 */
10338		"fnPreDrawCallback": null,
10339	
10340	
10341		/**
10342		 * This function allows you to 'post process' each row after it have been
10343		 * generated for each table draw, but before it is rendered on screen. This
10344		 * function might be used for setting the row class name etc.
10345		 */
10346		"fnRowCallback": null,
10347	
10348	
10349		/**
10350		 * Load the table state. With this function you can define from where, and how, the
10351		 * state of a table is loaded. By default DataTables will load from `localStorage`
10352		 * but you might wish to use a server-side database or cookies.
10353		 */
10354		"fnStateLoadCallback": function ( settings ) {
10355			try {
10356				return JSON.parse(
10357					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10358						'DataTables_'+settings.sInstance+'_'+location.pathname
10359					)
10360				);
10361			} catch (e) {
10362				return {};
10363			}
10364		},
10365	
10366	
10367		/**
10368		 * Callback which allows modification of the saved state prior to loading that state.
10369		 * This callback is called when the table is loading state from the stored data, but
10370		 * prior to the settings object being modified by the saved state. Note that for
10371		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10372		 * a plug-in.
10373		 */
10374		"fnStateLoadParams": null,
10375	
10376	
10377		/**
10378		 * Callback that is called when the state has been loaded from the state saving method
10379		 * and the DataTables settings object has been modified as a result of the loaded state.
10380		 */
10381		"fnStateLoaded": null,
10382	
10383	
10384		/**
10385		 * Save the table state. This function allows you to define where and how the state
10386		 * information for the table is stored By default DataTables will use `localStorage`
10387		 * but you might wish to use a server-side database or cookies.
10388		 */
10389		"fnStateSaveCallback": function ( settings, data ) {
10390			try {
10391				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10392					'DataTables_'+settings.sInstance+'_'+location.pathname,
10393					JSON.stringify( data )
10394				);
10395			} catch (e) {
10396				// noop
10397			}
10398		},
10399	
10400	
10401		/**
10402		 * Callback which allows modification of the state to be saved. Called when the table
10403		 * has changed state a new state save is required. This method allows modification of
10404		 * the state saving object prior to actually doing the save, including addition or
10405		 * other state properties or modification. Note that for plug-in authors, you should
10406		 * use the `stateSaveParams` event to save parameters for a plug-in.
10407		 */
10408		"fnStateSaveParams": null,
10409	
10410	
10411		/**
10412		 * Duration for which the saved state information is considered valid. After this period
10413		 * has elapsed the state will be returned to the default.
10414		 * Value is given in seconds.
10415		 */
10416		"iStateDuration": 7200,
10417	
10418	
10419		/**
10420		 * Number of rows to display on a single page when using pagination. If
10421		 * feature enabled (`lengthChange`) then the end user will be able to override
10422		 * this to a custom setting using a pop-up menu.
10423		 */
10424		"iDisplayLength": 10,
10425	
10426	
10427		/**
10428		 * Define the starting point for data display when using DataTables with
10429		 * pagination. Note that this parameter is the number of records, rather than
10430		 * the page number, so if you have 10 records per page and want to start on
10431		 * the third page, it should be "20".
10432		 */
10433		"iDisplayStart": 0,
10434	
10435	
10436		/**
10437		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10438		 * and filtering) by adding a `tabindex` attribute to the required elements. This
10439		 * allows you to tab through the controls and press the enter key to activate them.
10440		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10441		 * You can overrule this using this parameter if you wish. Use a value of -1 to
10442		 * disable built-in keyboard navigation.
10443		 */
10444		"iTabIndex": 0,
10445	
10446	
10447		/**
10448		 * Classes that DataTables assigns to the various components and features
10449		 * that it adds to the HTML table. This allows classes to be configured
10450		 * during initialisation in addition to through the static
10451		 * {@link DataTable.ext.oStdClasses} object).
10452		 */
10453		"oClasses": {},
10454	
10455	
10456		/**
10457		 * All strings that DataTables uses in the user interface that it creates
10458		 * are defined in this object, allowing you to modified them individually or
10459		 * completely replace them all as required.
10460		 */
10461		"oLanguage": {
10462			/**
10463			 * Strings that are used for WAI-ARIA labels and controls only (these are not
10464			 * actually visible on the page, but will be read by screenreaders, and thus
10465			 * must be internationalised as well).
10466			 */
10467			"oAria": {
10468				/**
10469				 * ARIA label that is added to the table headers when the column may be sorted
10470				 */
10471				"orderable": ": Activate to sort",
10472	
10473				/**
10474				 * ARIA label that is added to the table headers when the column is currently being sorted
10475				 */
10476				"orderableReverse": ": Activate to invert sorting",
10477	
10478				/**
10479				 * ARIA label that is added to the table headers when the column is currently being 
10480				 * sorted and next step is to remove sorting
10481				 */
10482				"orderableRemove": ": Activate to remove sorting",
10483	
10484				paginate: {
10485					first: 'First',
10486					last: 'Last',
10487					next: 'Next',
10488					previous: 'Previous'
10489				}
10490			},
10491	
10492			/**
10493			 * Pagination string used by DataTables for the built-in pagination
10494			 * control types.
10495			 */
10496			"oPaginate": {
10497				/**
10498				 * Label and character for first page button («)
10499				 */
10500				"sFirst": "\u00AB",
10501	
10502				/**
10503				 * Last page button (»)
10504				 */
10505				"sLast": "\u00BB",
10506	
10507				/**
10508				 * Next page button (›)
10509				 */
10510				"sNext": "\u203A",
10511	
10512				/**
10513				 * Previous page button (‹)
10514				 */
10515				"sPrevious": "\u2039",
10516			},
10517	
10518			/**
10519			 * Plural object for the data type the table is showing
10520			 */
10521			entries: {
10522				_: "entries",
10523				1: "entry"
10524			},
10525	
10526			/**
10527			 * This string is shown in preference to `zeroRecords` when the table is
10528			 * empty of data (regardless of filtering). Note that this is an optional
10529			 * parameter - if it is not given, the value of `zeroRecords` will be used
10530			 * instead (either the default or given value).
10531			 */
10532			"sEmptyTable": "No data available in table",
10533	
10534	
10535			/**
10536			 * This string gives information to the end user about the information
10537			 * that is current on display on the page. The following tokens can be
10538			 * used in the string and will be dynamically replaced as the table
10539			 * display updates. This tokens can be placed anywhere in the string, or
10540			 * removed as needed by the language requires:
10541			 *
10542			 * * `\_START\_` - Display index of the first record on the current page
10543			 * * `\_END\_` - Display index of the last record on the current page
10544			 * * `\_TOTAL\_` - Number of records in the table after filtering
10545			 * * `\_MAX\_` - Number of records in the table without filtering
10546			 * * `\_PAGE\_` - Current page number
10547			 * * `\_PAGES\_` - Total number of pages of data in the table
10548			 */
10549			"sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
10550	
10551	
10552			/**
10553			 * Display information string for when the table is empty. Typically the
10554			 * format of this string should match `info`.
10555			 */
10556			"sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
10557	
10558	
10559			/**
10560			 * When a user filters the information in a table, this string is appended
10561			 * to the information (`info`) to give an idea of how strong the filtering
10562			 * is. The variable _MAX_ is dynamically updated.
10563			 */
10564			"sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
10565	
10566	
10567			/**
10568			 * If can be useful to append extra information to the info string at times,
10569			 * and this variable does exactly that. This information will be appended to
10570			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
10571			 * being used) at all times.
10572			 */
10573			"sInfoPostFix": "",
10574	
10575	
10576			/**
10577			 * This decimal place operator is a little different from the other
10578			 * language options since DataTables doesn't output floating point
10579			 * numbers, so it won't ever use this for display of a number. Rather,
10580			 * what this parameter does is modify the sort methods of the table so
10581			 * that numbers which are in a format which has a character other than
10582			 * a period (`.`) as a decimal place will be sorted numerically.
10583			 *
10584			 * Note that numbers with different decimal places cannot be shown in
10585			 * the same table and still be sortable, the table must be consistent.
10586			 * However, multiple different tables on the page can use different
10587			 * decimal place characters.
10588			 */
10589			"sDecimal": "",
10590	
10591	
10592			/**
10593			 * DataTables has a build in number formatter (`formatNumber`) which is
10594			 * used to format large numbers that are used in the table information.
10595			 * By default a comma is used, but this can be trivially changed to any
10596			 * character you wish with this parameter.
10597			 */
10598			"sThousands": ",",
10599	
10600	
10601			/**
10602			 * Detail the action that will be taken when the drop down menu for the
10603			 * pagination length option is changed. The '_MENU_' variable is replaced
10604			 * with a default select list of 10, 25, 50 and 100, and can be replaced
10605			 * with a custom select box if required.
10606			 */
10607			"sLengthMenu": "_MENU_ _ENTRIES_ per page",
10608	
10609	
10610			/**
10611			 * When using Ajax sourced data and during the first draw when DataTables is
10612			 * gathering the data, this message is shown in an empty row in the table to
10613			 * indicate to the end user the the data is being loaded. Note that this
10614			 * parameter is not used when loading data by server-side processing, just
10615			 * Ajax sourced data with client-side processing.
10616			 */
10617			"sLoadingRecords": "Loading...",
10618	
10619	
10620			/**
10621			 * Text which is displayed when the table is processing a user action
10622			 * (usually a sort command or similar).
10623			 */
10624			"sProcessing": "",
10625	
10626	
10627			/**
10628			 * Details the actions that will be taken when the user types into the
10629			 * filtering input text box. The variable "_INPUT_", if used in the string,
10630			 * is replaced with the HTML text box for the filtering input allowing
10631			 * control over where it appears in the string. If "_INPUT_" is not given
10632			 * then the input box is appended to the string automatically.
10633			 */
10634			"sSearch": "Search:",
10635	
10636	
10637			/**
10638			 * Assign a `placeholder` attribute to the search `input` element
10639			 *  @type string
10640			 *  @default 
10641			 *
10642			 *  @dtopt Language
10643			 *  @name DataTable.defaults.language.searchPlaceholder
10644			 */
10645			"sSearchPlaceholder": "",
10646	
10647	
10648			/**
10649			 * All of the language information can be stored in a file on the
10650			 * server-side, which DataTables will look up if this parameter is passed.
10651			 * It must store the URL of the language file, which is in a JSON format,
10652			 * and the object has the same properties as the oLanguage object in the
10653			 * initialiser object (i.e. the above parameters). Please refer to one of
10654			 * the example language files to see how this works in action.
10655			 */
10656			"sUrl": "",
10657	
10658	
10659			/**
10660			 * Text shown inside the table records when the is no information to be
10661			 * displayed after filtering. `emptyTable` is shown when there is simply no
10662			 * information in the table at all (regardless of filtering).
10663			 */
10664			"sZeroRecords": "No matching records found"
10665		},
10666	
10667	
10668		/**
10669		 * This parameter allows you to have define the global filtering state at
10670		 * initialisation time. As an object the `search` parameter must be
10671		 * defined, but all other parameters are optional. When `regex` is true,
10672		 * the search string will be treated as a regular expression, when false
10673		 * (default) it will be treated as a straight string. When `smart`
10674		 * DataTables will use it's smart filtering methods (to word match at
10675		 * any point in the data), when false this will not be done.
10676		 */
10677		"oSearch": $.extend( {}, DataTable.models.oSearch ),
10678	
10679	
10680		/**
10681		 * Table and control layout. This replaces the legacy `dom` option.
10682		 */
10683		layout: {
10684			topStart: 'pageLength',
10685			topEnd: 'search',
10686			bottomStart: 'info',
10687			bottomEnd: 'paging'
10688		},
10689	
10690	
10691		/**
10692		 * Legacy DOM layout option
10693		 */
10694		"sDom": null,
10695	
10696	
10697		/**
10698		 * Search delay option. This will throttle full table searches that use the
10699		 * DataTables provided search input element (it does not effect calls to
10700		 * `dt-api search()`, providing a delay before the search is made.
10701		 */
10702		"searchDelay": null,
10703	
10704	
10705		/**
10706		 * DataTables features six different built-in options for the buttons to
10707		 * display for pagination control:
10708		 *
10709		 * * `numbers` - Page number buttons only
10710		 * * `simple` - 'Previous' and 'Next' buttons only
10711		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
10712		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
10713		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
10714		 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
10715		 */
10716		"sPaginationType": "full_numbers",
10717	
10718	
10719		/**
10720		 * Enable horizontal scrolling. When a table is too wide to fit into a
10721		 * certain layout, or you have a large number of columns in the table, you
10722		 * can enable x-scrolling to show the table in a viewport, which can be
10723		 * scrolled. This property can be `true` which will allow the table to
10724		 * scroll horizontally when needed, or any CSS unit, or a number (in which
10725		 * case it will be treated as a pixel measurement). Setting as simply `true`
10726		 * is recommended.
10727		 */
10728		"sScrollX": "",
10729	
10730	
10731		/**
10732		 * This property can be used to force a DataTable to use more width than it
10733		 * might otherwise do when x-scrolling is enabled. For example if you have a
10734		 * table which requires to be well spaced, this parameter is useful for
10735		 * "over-sizing" the table, and thus forcing scrolling. This property can by
10736		 * any CSS unit, or a number (in which case it will be treated as a pixel
10737		 * measurement).
10738		 */
10739		"sScrollXInner": "",
10740	
10741	
10742		/**
10743		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
10744		 * to the given height, and enable scrolling for any data which overflows the
10745		 * current viewport. This can be used as an alternative to paging to display
10746		 * a lot of data in a small area (although paging and scrolling can both be
10747		 * enabled at the same time). This property can be any CSS unit, or a number
10748		 * (in which case it will be treated as a pixel measurement).
10749		 */
10750		"sScrollY": "",
10751	
10752	
10753		/**
10754		 * __Deprecated__ The functionality provided by this parameter has now been
10755		 * superseded by that provided through `ajax`, which should be used instead.
10756		 *
10757		 * Set the HTTP method that is used to make the Ajax call for server-side
10758		 * processing or Ajax sourced data.
10759		 */
10760		"sServerMethod": "GET",
10761	
10762	
10763		/**
10764		 * DataTables makes use of renderers when displaying HTML elements for
10765		 * a table. These renderers can be added or modified by plug-ins to
10766		 * generate suitable mark-up for a site. For example the Bootstrap
10767		 * integration plug-in for DataTables uses a paging button renderer to
10768		 * display pagination buttons in the mark-up required by Bootstrap.
10769		 *
10770		 * For further information about the renderers available see
10771		 * DataTable.ext.renderer
10772		 */
10773		"renderer": null,
10774	
10775	
10776		/**
10777		 * Set the data property name that DataTables should use to get a row's id
10778		 * to set as the `id` property in the node.
10779		 */
10780		"rowId": "DT_RowId",
10781	
10782	
10783		/**
10784		 * Caption value
10785		 */
10786		"caption": null
10787	};
10788	
10789	_fnHungarianMap( DataTable.defaults );
10790	
10791	
10792	
10793	/*
10794	 * Developer note - See note in model.defaults.js about the use of Hungarian
10795	 * notation and camel case.
10796	 */
10797	
10798	/**
10799	 * Column options that can be given to DataTables at initialisation time.
10800	 *  @namespace
10801	 */
10802	DataTable.defaults.column = {
10803		/**
10804		 * Define which column(s) an order will occur on for this column. This
10805		 * allows a column's ordering to take multiple columns into account when
10806		 * doing a sort or use the data from a different column. For example first
10807		 * name / last name columns make sense to do a multi-column sort over the
10808		 * two columns.
10809		 */
10810		"aDataSort": null,
10811		"iDataSort": -1,
10812	
10813		ariaTitle: '',
10814	
10815	
10816		/**
10817		 * You can control the default ordering direction, and even alter the
10818		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
10819		 * using this parameter.
10820		 */
10821		"asSorting": [ 'asc', 'desc', '' ],
10822	
10823	
10824		/**
10825		 * Enable or disable filtering on the data in this column.
10826		 */
10827		"bSearchable": true,
10828	
10829	
10830		/**
10831		 * Enable or disable ordering on this column.
10832		 */
10833		"bSortable": true,
10834	
10835	
10836		/**
10837		 * Enable or disable the display of this column.
10838		 */
10839		"bVisible": true,
10840	
10841	
10842		/**
10843		 * Developer definable function that is called whenever a cell is created (Ajax source,
10844		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
10845		 * allowing you to modify the DOM element (add background colour for example) when the
10846		 * element is available.
10847		 */
10848		"fnCreatedCell": null,
10849	
10850	
10851		/**
10852		 * This property can be used to read data from any data source property,
10853		 * including deeply nested objects / properties. `data` can be given in a
10854		 * number of different ways which effect its behaviour:
10855		 *
10856		 * * `integer` - treated as an array index for the data source. This is the
10857		 *   default that DataTables uses (incrementally increased for each column).
10858		 * * `string` - read an object property from the data source. There are
10859		 *   three 'special' options that can be used in the string to alter how
10860		 *   DataTables reads the data from the source object:
10861		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
10862		 *      Javascript to read from nested objects, so to can the options
10863		 *      specified in `data`. For example: `browser.version` or
10864		 *      `browser.name`. If your object parameter name contains a period, use
10865		 *      `\\` to escape it - i.e. `first\\.name`.
10866		 *    * `[]` - Array notation. DataTables can automatically combine data
10867		 *      from and array source, joining the data with the characters provided
10868		 *      between the two brackets. For example: `name[, ]` would provide a
10869		 *      comma-space separated list from the source array. If no characters
10870		 *      are provided between the brackets, the original array source is
10871		 *      returned.
10872		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
10873		 *      execute a function of the name given. For example: `browser()` for a
10874		 *      simple function on the data source, `browser.version()` for a
10875		 *      function in a nested property or even `browser().version` to get an
10876		 *      object property if the function called returns an object. Note that
10877		 *      function notation is recommended for use in `render` rather than
10878		 *      `data` as it is much simpler to use as a renderer.
10879		 * * `null` - use the original data source for the row rather than plucking
10880		 *   data directly from it. This action has effects on two other
10881		 *   initialisation options:
10882		 *    * `defaultContent` - When null is given as the `data` option and
10883		 *      `defaultContent` is specified for the column, the value defined by
10884		 *      `defaultContent` will be used for the cell.
10885		 *    * `render` - When null is used for the `data` option and the `render`
10886		 *      option is specified for the column, the whole data source for the
10887		 *      row is used for the renderer.
10888		 * * `function` - the function given will be executed whenever DataTables
10889		 *   needs to set or get the data for a cell in the column. The function
10890		 *   takes three parameters:
10891		 *    * Parameters:
10892		 *      * `{array|object}` The data source for the row
10893		 *      * `{string}` The type call data requested - this will be 'set' when
10894		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
10895		 *        when gathering data. Note that when `undefined` is given for the
10896		 *        type DataTables expects to get the raw data for the object back<
10897		 *      * `{*}` Data to set when the second parameter is 'set'.
10898		 *    * Return:
10899		 *      * The return value from the function is not required when '
10899set' is
10900		 *        the type of call, but otherwise the return is what will be used
10901		 *        for the data requested.
10902		 *
10903		 * Note that `data` is a getter and setter option. If you just require
10904		 * formatting of data for output, you will likely want to use `render` which
10905		 * is simply a getter and thus simpler to use.
10906		 *
10907		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
10908		 * name change reflects the flexibility of this property and is consistent
10909		 * with the naming of mRender. If 'mDataProp' is given, then it will still
10910		 * be used by DataTables, as it automatically maps the old name to the new
10911		 * if required.
10912		 */
10913		"mData": null,
10914	
10915	
10916		/**
10917		 * This property is the rendering partner to `data` and it is suggested that
10918		 * when you want to manipulate data for display (including filtering,
10919		 * sorting etc) without altering the underlying data for the table, use this
10920		 * property. `render` can be considered to be the the read only companion to
10921		 * `data` which is read / write (then as such more complex). Like `data`
10922		 * this option can be given in a number of different ways to effect its
10923		 * behaviour:
10924		 *
10925		 * * `integer` - treated as an array index for the data source. This is the
10926		 *   default that DataTables uses (incrementally increased for each column).
10927		 * * `string` - read an object property from the data source. There are
10928		 *   three 'special' options that can be used in the string to alter how
10929		 *   DataTables reads the data from the source object:
10930		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
10931		 *      Javascript to read from nested objects, so to can the options
10932		 *      specified in `data`. For example: `browser.version` or
10933		 *      `browser.name`. If your object parameter name contains a period, use
10934		 *      `\\` to escape it - i.e. `first\\.name`.
10935		 *    * `[]` - Array notation. DataTables can automatically combine data
10936		 *      from and array source, joining the data with the characters provided
10937		 *      between the two brackets. For example: `name[, ]` would provide a
10938		 *      comma-space separated list from the source array. If no characters
10939		 *      are provided between the brackets, the original array source is
10940		 *      returned.
10941		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
10942		 *      execute a function of the name given. For example: `browser()` for a
10943		 *      simple function on the data source, `browser.version()` for a
10944		 *      function in a nested property or even `browser().version` to get an
10945		 *      object property if the function called returns an object.
10946		 * * `object` - use different data for the different data types requested by
10947		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
10948		 *   of the object is the data type the property refers to and the value can
10949		 *   defined using an integer, string or function using the same rules as
10950		 *   `render` normally does. Note that an `_` option _must_ be specified.
10951		 *   This is the default value to use if you haven't specified a value for
10952		 *   the data type requested by DataTables.
10953		 * * `function` - the function given will be executed whenever DataTables
10954		 *   needs to set or get the data for a cell in the column. The function
10955		 *   takes three parameters:
10956		 *    * Parameters:
10957		 *      * {array|object} The data source for the row (based on `data`)
10958		 *      * {string} The type call data requested - this will be 'filter',
10959		 *        'display', 'type' or 'sort'.
10960		 *      * {array|object} The full data source for the row (not based on
10961		 *        `data`)
10962		 *    * Return:
10963		 *      * The return value from the function is what will be used for the
10964		 *        data requested.
10965		 */
10966		"mRender": null,
10967	
10968	
10969		/**
10970		 * Change the cell type created for the column - either TD cells or TH cells. This
10971		 * can be useful as TH cells have semantic meaning in the table body, allowing them
10972		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
10973		 */
10974		"sCellType": "td",
10975	
10976	
10977		/**
10978		 * Class to give to each cell in this column.
10979		 */
10980		"sClass": "",
10981	
10982		/**
10983		 * When DataTables calculates the column widths to assign to each column,
10984		 * it finds the longest string in each column and then constructs a
10985		 * temporary table and reads the widths from that. The problem with this
10986		 * is that "mmm" is much wider then "iiii", but the latter is a longer
10987		 * string - thus the calculation can go wrong (doing it properly and putting
10988		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
10989		 * a "work around" we provide this option. It will append its value to the
10990		 * text that is found to be the longest string for the column - i.e. padding.
10991		 * Generally you shouldn't need this!
10992		 */
10993		"sContentPadding": "",
10994	
10995	
10996		/**
10997		 * Allows a default value to be given for a column's data, and will be used
10998		 * whenever a null data source is encountered (this can be because `data`
10999		 * is set to null, or because the data source itself is null).
11000		 */
11001		"sDefaultContent": null,
11002	
11003	
11004		/**
11005		 * This parameter is only used in DataTables' server-side processing. It can
11006		 * be exceptionally useful to know what columns are being displayed on the
11007		 * client side, and to map these to database fields. When defined, the names
11008		 * also allow DataTables to reorder information from the server if it comes
11009		 * back in an unexpected order (i.e. if you switch your columns around on the
11010		 * client-side, your server-side code does not also need updating).
11011		 */
11012		"sName": "",
11013	
11014	
11015		/**
11016		 * Defines a data source type for the ordering which can be used to read
11017		 * real-time information from the table (updating the internally cached
11018		 * version) prior to ordering. This allows ordering to occur on user
11019		 * editable elements such as form inputs.
11020		 */
11021		"sSortDataType": "std",
11022	
11023	
11024		/**
11025		 * The title of this column.
11026		 */
11027		"sTitle": null,
11028	
11029	
11030		/**
11031		 * The type allows you to specify how the data for this column will be
11032		 * ordered. Four types (string, numeric, date and html (which will strip
11033		 * HTML tags before ordering)) are currently available. Note that only date
11034		 * formats understood by Javascript's Date() object will be accepted as type
11035		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
11036		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
11037		 * through plug-ins.
11038		 */
11039		"sType": null,
11040	
11041	
11042		/**
11043		 * Defining the width of the column, this parameter may take any CSS value
11044		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
11045		 * been given a specific width through this interface ensuring that the table
11046		 * remains readable.
11047		 */
11048		"sWidth": null
11049	};
11050	
11051	_fnHungarianMap( DataTable.defaults.column );
11052	
11053	
11054	
11055	/**
11056	 * DataTables settings object - this holds all the information needed for a
11057	 * given table, including configuration, data and current application of the
11058	 * table options. DataTables does not have a single instance for each DataTable
11059	 * with the settings attached to that instance, but rather instances of the
11060	 * DataTable "class" are created on-the-fly as needed (typically by a
11061	 * $().dataTable() call) and the settings object is then applied to that
11062	 * instance.
11063	 *
11064	 * Note that this object is related to {@link DataTable.defaults} but this
11065	 * one is the internal data store for DataTables's cache of columns. It should
11066	 * NOT be manipulated outside of DataTables. Any configuration should be done
11067	 * through the initialisation options.
11068	 */
11069	DataTable.models.oSettings = {
11070		/**
11071		 * Primary features of DataTables and their enablement state.
11072		 */
11073		"oFeatures": {
11074	
11075			/**
11076			 * Flag to say if DataTables should automatically try to calculate the
11077			 * optimum table and columns widths (true) or not (false).
11078			 * Note that this parameter will be set by the initialisation routine. To
11079			 * set a default use {@link DataTable.defaults}.
11080			 */
11081			"bAutoWidth": null,
11082	
11083			/**
11084			 * Delay the creation of TR and TD elements until they are actually
11085			 * needed by a driven page draw. This can give a significant speed
11086			 * increase for Ajax source and Javascript source data, but makes no
11087			 * difference at all for DOM and server-side processing tables.
11088			 * Note that this parameter will be set by the initialisation routine. To
11089			 * set a default use {@link DataTable.defaults}.
11090			 */
11091			"bDeferRender": null,
11092	
11093			/**
11094			 * Enable filtering on the table or not. Note that if this is disabled
11095			 * then there is no filtering at all on the table, including fnFilter.
11096			 * To just remove the filtering input use sDom and remove the 'f' option.
11097			 * Note that this parameter will be set by the initialisation routine. To
11098			 * set a default use {@link DataTable.defaults}.
11099			 */
11100			"bFilter": null,
11101	
11102			/**
11103			 * Used only for compatiblity with DT1
11104			 * @deprecated
11105			 */
11106			"bInfo": true,
11107	
11108			/**
11109			 * Used only for compatiblity with DT1
11110			 * @deprecated
11111			 */
11112			"bLengthChange": true,
11113	
11114			/**
11115			 * Pagination enabled or not. Note that if this is disabled then length
11116			 * changing must also be disabled.
11117			 * Note that this parameter will be set by the initialisation routine. To
11118			 * set a default use {@link DataTable.defaults}.
11119			 */
11120			"bPaginate": null,
11121	
11122			/**
11123			 * Processing indicator enable flag whenever DataTables is enacting a
11124			 * user request - typically an Ajax request for server-side processing.
11125			 * Note that this parameter will be set by the initialisation routine. To
11126			 * set a default use {@link DataTable.defaults}.
11127			 */
11128			"bProcessing": null,
11129	
11130			/**
11131			 * Server-side processing enabled flag - when enabled DataTables will
11132			 * get all data from the server for every draw - there is no filtering,
11133			 * sorting or paging done on the client-side.
11134			 * Note that this parameter will be set by the initialisation routine. To
11135			 * set a default use {@link DataTable.defaults}.
11136			 */
11137			"bServerSide": null,
11138	
11139			/**
11140			 * Sorting enablement flag.
11141			 * Note that this parameter will be set by the initialisation routine. To
11142			 * set a default use {@link DataTable.defaults}.
11143			 */
11144			"bSort": null,
11145	
11146			/**
11147			 * Multi-column sorting
11148			 * Note that this parameter will be set by the initialisation routine. To
11149			 * set a default use {@link DataTable.defaults}.
11150			 */
11151			"bSortMulti": null,
11152	
11153			/**
11154			 * Apply a class to the columns which are being sorted to provide a
11155			 * visual highlight or not. This can slow things down when enabled since
11156			 * there is a lot of DOM interaction.
11157			 * Note that this parameter will be set by the initialisation routine. To
11158			 * set a default use {@link DataTable.defaults}.
11159			 */
11160			"bSortClasses": null,
11161	
11162			/**
11163			 * State saving enablement flag.
11164			 * Note that this parameter will be set by the initialisation routine. To
11165			 * set a default use {@link DataTable.defaults}.
11166			 */
11167			"bStateSave": null
11168		},
11169	
11170	
11171		/**
11172		 * Scrolling settings for a table.
11173		 */
11174		"oScroll": {
11175			/**
11176			 * When the table is shorter in height than sScrollY, collapse the
11177			 * table container down to the height of the table (when true).
11178			 * Note that this parameter will be set by the initialisation routine. To
11179			 * set a default use {@link DataTable.defaults}.
11180			 */
11181			"bCollapse": null,
11182	
11183			/**
11184			 * Width of the scrollbar for the web-browser's platform. Calculated
11185			 * during table initialisation.
11186			 */
11187			"iBarWidth": 0,
11188	
11189			/**
11190			 * Viewport width for horizontal scrolling. Horizontal scrolling is
11191			 * disabled if an empty string.
11192			 * Note that this parameter will be set by the initialisation routine. To
11193			 * set a default use {@link DataTable.defaults}.
11194			 */
11195			"sX": null,
11196	
11197			/**
11198			 * Width to expand the table to when using x-scrolling. Typically you
11199			 * should not need to use this.
11200			 * Note that this parameter will be set by the initialisation routine. To
11201			 * set a default use {@link DataTable.defaults}.
11202			 *  @deprecated
11203			 */
11204			"sXInner": null,
11205	
11206			/**
11207			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
11208			 * if an empty string.
11209			 * Note that this parameter will be set by the initialisation routine. To
11210			 * set a default use {@link DataTable.defaults}.
11211			 */
11212			"sY": null
11213		},
11214	
11215		/**
11216		 * Language information for the table.
11217		 */
11218		"oLanguage": {
11219			/**
11220			 * Information callback function. See
11221			 * {@link DataTable.defaults.fnInfoCallback}
11222			 */
11223			"fnInfoCallback": null
11224		},
11225	
11226		/**
11227		 * Browser support parameters
11228		 */
11229		"oBrowser": {
11230			/**
11231			 * Determine if the vertical scrollbar is on the right or left of the
11232			 * scrolling container - needed for rtl language layout, although not
11233			 * all browsers move the scrollbar (Safari).
11234			 */
11235			"bScrollbarLeft": false,
11236	
11237			/**
11238			 * Browser scrollbar width
11239			 */
11240			"barWidth": 0
11241		},
11242	
11243	
11244		"ajax": null,
11245	
11246	
11247		/**
11248		 * Array referencing the nodes which are used for the features. The
11249		 * parameters of this object match what is allowed by sDom - i.e.
11250		 *   <ul>
11251		 *     <li>'l' - Length changing</li>
11252		 *     <li>'f' - Filtering input</li>
11253		 *     <li>'t' - The table!</li>
11254		 *     <li>'i' - Information</li>
11255		 *     <li>'p' - Pagination</li>
11256		 *     <li>'r' - pRocessing</li>
11257		 *   </ul>
11258		 */
11259		"aanFeatures": [],
11260	
11261		/**
11262		 * Store data information - see {@link DataTable.models.oRow} for detailed
11263		 * information.
11264		 */
11265		"aoData": [],
11266	
11267		/**
11268		 * Array of indexes which are in the current display (after filtering etc)
11269		 */
11270		"aiDisplay": [],
11271	
11272		/**
11273		 * Array of indexes for display - no filtering
11274		 */
11275		"aiDisplayMaster": [],
11276	
11277		/**
11278		 * Map of row ids to data indexes
11279		 */
11280		"aIds": {},
11281	
11282		/**
11283		 * Store information about each column that is in use
11284		 */
11285		"aoColumns": [],
11286	
11287		/**
11288		 * Store information about the table's header
11289		 */
11290		"aoHeader": [],
11291	
11292		/**
11293		 * Store information about the table's footer
11294		 */
11295		"aoFooter": [],
11296	
11297		/**
11298		 * Store the applied global search information in case we want to force a
11299		 * research or compare the old search to a new one.
11300		 * Note that this parameter will be set by the initialisation routine. To
11301		 * set a default use {@link DataTable.defaults}.
11302		 */
11303		"oPreviousSearch": {},
11304	
11305		/**
11306		 * Store for named searches
11307		 */
11308		searchFixed: {},
11309	
11310		/**
11311		 * Store the applied search for each column - see
11312		 * {@link DataTable.models.oSearch} for the format that is used for the
11313		 * filtering information for each column.
11314		 */
11315		"aoPreSearchCols": [],
11316	
11317		/**
11318		 * Sorting that is applied to the table. Note that the inner arrays are
11319		 * used in the following manner:
11320		 * <ul>
11321		 *   <li>Index 0 - column number</li>
11322		 *   <li>Index 1 - current sorting direction</li>
11323		 * </ul>
11324		 * Note that this parameter will be set by the initialisation routine. To
11325		 * set a default use {@link DataTable.defaults}.
11326		 */
11327		"aaSorting": null,
11328	
11329		/**
11330		 * Sorting that is always applied to the table (i.e. prefixed in front of
11331		 * aaSorting).
11332		 * Note that this parameter will be set by the initialisation routine. To
11333		 * set a default use {@link DataTable.defaults}.
11334		 */
11335		"aaSortingFixed": [],
11336	
11337		/**
11338		 * If restoring a table - we should restore its width
11339		 */
11340		"sDestroyWidth": 0,
11341	
11342		/**
11343		 * Callback functions array for every time a row is inserted (i.e. on a draw).
11344		 */
11345		"aoRowCallback": [],
11346	
11347		/**
11348		 * Callback functions for the header on each draw.
11349		 */
11350		"aoHeaderCallback": [],
11351	
11352		/**
11353		 * Callback function for the footer on each draw.
11354		 */
11355		"aoFooterCallback": [],
11356	
11357		/**
11358		 * Array of callback functions for draw callback functions
11359		 */
11360		"aoDrawCallback": [],
11361	
11362		/**
11363		 * Array of callback functions for row created function
11364		 */
11365		"aoRowCreatedCallback": [],
11366	
11367		/**
11368		 * Callback functions for just before the table is redrawn. A return of
11369		 * false will be used to cancel the draw.
11370		 */
11371		"aoPreDrawCallback": [],
11372	
11373		/**
11374		 * Callback functions for when the table has been initialised.
11375		 */
11376		"aoInitComplete": [],
11377	
11378	
11379		/**
11380		 * Callbacks for modifying the settings to be stored for state saving, prior to
11381		 * saving state.
11382		 */
11383		"aoStateSaveParams": [],
11384	
11385		/**
11386		 * Callbacks for modifying the settings that have been stored for state saving
11387		 * prior to using the stored values to restore the state.
11388		 */
11389		"aoStateLoadParams": [],
11390	
11391		/**
11392		 * Callbacks for operating on the settings object once the saved state has been
11393		 * loaded
11394		 */
11395		"aoStateLoaded": [],
11396	
11397		/**
11398		 * Cache the table ID for quick access
11399		 */
11400		"sTableId": "",
11401	
11402		/**
11403		 * The TABLE node for the main table
11404		 */
11405		"nTable": null,
11406	
11407		/**
11408		 * Permanent ref to the thead element
11409		 */
11410		"nTHead": null,
11411	
11412		/**
11413		 * Permanent ref to the tfoot element - if it exists
11414		 */
11415		"nTFoot": null,
11416	
11417		/**
11418		 * Permanent ref to the tbody element
11419		 */
11420		"nTBody": null,
11421	
11422		/**
11423		 * Cache the wrapper node (contains all DataTables controlled elements)
11424		 */
11425		"nTableWrapper": null,
11426	
11427		/**
11428		 * Indicate if all required information has been read in
11429		 */
11430		"bInitialised": false,
11431	
11432		/**
11433		 * Information about open rows. Each object in the array has the parameters
11434		 * 'nTr' and 'nParent'
11435		 */
11436		"aoOpenRows": [],
11437	
11438		/**
11439		 * Dictate the positioning of DataTables' control elements - see
11440		 * {@link DataTable.model.oInit.sDom}.
11441		 * Note that this parameter will be set by the initialisation routine. To
11442		 * set a default use {@link DataTable.defaults}.
11443		 */
11444		"sDom": null,
11445	
11446		/**
11447		 * Search delay (in mS)
11448		 */
11449		"searchDelay": null,
11450	
11451		/**
11452		 * Which type of pagination should be used.
11453		 * Note that this parameter will be set by the initialisation routine. To
11454		 * set a default use {@link DataTable.defaults}.
11455		 */
11456		"sPaginationType": "two_button",
11457	
11458		/**
11459		 * Number of paging controls on the page. Only used for backwards compatibility
11460		 */
11461		pagingControls: 0,
11462	
11463		/**
11464		 * The state duration (for `stateSave`) in seconds.
11465		 * Note that this parameter will be set by the initialisation routine. To
11466		 * set a default use {@link DataTable.defaults}.
11467		 */
11468		"iStateDuration": 0,
11469	
11470		/**
11471		 * Array of callback functions for state saving. Each array element is an
11472		 * object with the following parameters:
11473		 *   <ul>
11474		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11475		 *       and the JSON string to save that has been thus far created. Returns
11476		 *       a JSON string to be inserted into a json object
11477		 *       (i.e. '"param": [ 0, 1, 2]')</li>
11478		 *     <li>string:sName - name of callback</li>
11479		 *   </ul>
11480		 */
11481		"aoStateSave": [],
11482	
11483		/**
11484		 * Array of callback functions for state loading. Each array element is an
11485		 * object with the following parameters:
11486		 *   <ul>
11487		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11488		 *       and the object stored. May return false to cancel state loading</li>
11489		 *     <li>string:sName - name of callback</li>
11490		 *   </ul>
11491		 */
11492		"aoStateLoad": [],
11493	
11494		/**
11495		 * State that was saved. Useful for back reference
11496		 */
11497		"oSavedState": null,
11498	
11499		/**
11500		 * State that was loaded. Useful for back reference
11501		 */
11502		"oLoadedState": null,
11503	
11504		/**
11505		 * Note if draw should be blocked while getting data
11506		 */
11507		"bAjaxDataGet": true,
11508	
11509		/**
11510		 * The last jQuery XHR object that was used for server-side data gathering.
11511		 * This can be used for working with the XHR information in one of the
11512		 * callbacks
11513		 */
11514		"jqXHR": null,
11515	
11516		/**
11517		 * JSON returned from the server in the last Ajax request
11518		 */
11519		"json": undefined,
11520	
11521		/**
11522		 * Data submitted as part of the last Ajax request
11523		 */
11524		"oAjaxData": undefined,
11525	
11526		/**
11527		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
11528		 * required).
11529		 * Note that this parameter will be set by the initialisation routine. To
11530		 * set a default use {@link DataTable.defaults}.
11531		 */
11532		"sServerMethod": null,
11533	
11534		/**
11535		 * Format numbers for display.
11536		 * Note that this parameter will be set by the initialisation routine. To
11537		 * set a default use {@link DataTable.defaults}.
11538		 */
11539		"fnFormatNumber": null,
11540	
11541		/**
11542		 * List of options that can be used for the user selectable length menu.
11543		 * Note that this parameter will be set by the initialisation routine. To
11544		 * set a default use {@link DataTable.defaults}.
11545		 */
11546		"aLengthMenu": null,
11547	
11548		/**
11549		 * Counter for the draws that the table does. Also used as a tracker for
11550		 * server-side processing
11551		 */
11552		"iDraw": 0,
11553	
11554		/**
11555		 * Indicate if a redraw is being done - useful for Ajax
11556		 */
11557		"bDrawing": false,
11558	
11559		/**
11560		 * Draw index (iDraw) of the last error when parsing the returned data
11561		 */
11562		"iDrawError": -1,
11563	
11564		/**
11565		 * Paging display length
11566		 */
11567		"_iDisplayLength": 10,
11568	
11569		/**
11570		 * Paging start point - aiDisplay index
11571		 */
11572		"_iDisplayStart": 0,
11573	
11574		/**
11575		 * Server-side processing - number of records in the result set
11576		 * (i.e. before filtering), Use fnRecordsTotal rather than
11577		 * this property to get the value of the number of records, regardless of
11578		 * the server-side processing setting.
11579		 */
11580		"_iRecordsTotal": 0,
11581	
11582		/**
11583		 * Server-side processing - number of records in the current display set
11584		 * (i.e. after filtering). Use fnRecordsDisplay rather than
11585		 * this property to get the value of the number of records, regardless of
11586		 * the server-side processing setting.
11587		 */
11588		"_iRecordsDisplay": 0,
11589	
11590		/**
11591		 * The classes to use for the table
11592		 */
11593		"oClasses": {},
11594	
11595		/**
11596		 * Flag attached to the settings object so you can check in the draw
11597		 * callback if filtering has been done in the draw. Deprecated in favour of
11598		 * events.
11599		 *  @deprecated
11600		 */
11601		"bFiltered": false,
11602	
11603		/**
11604		 * Flag attached to the settings object so you can check in the draw
11605		 * callback if sorting has been done in the draw. Deprecated in favour of
11606		 * events.
11607		 *  @deprecated
11608		 */
11609		"bSorted": false,
11610	
11611		/**
11612		 * Indicate that if multiple rows are in the header and there is more than
11613		 * one unique cell per column, if the top one (true) or bottom one (false)
11614		 * should be used for sorting / title by DataTables.
11615		 * Note that this parameter will be set by the initialisation routine. To
11616		 * set a default use {@link DataTable.defaults}.
11617		 */
11618		"bSortCellsTop": null,
11619	
11620		/**
11621		 * Initialisation object that is used for the table
11622		 */
11623		"oInit": null,
11624	
11625		/**
11626		 * Destroy callback functions - for plug-ins to attach themselves to the
11627		 * destroy so they can clean up markup and events.
11628		 */
11629		"aoDestroyCallback": [],
11630	
11631	
11632		/**
11633		 * Get the number of records in the current record set, before filtering
11634		 */
11635		"fnRecordsTotal": function ()
11636		{
11637			return _fnDataSource( this ) == 'ssp' ?
11638				this._iRecordsTotal * 1 :
11639				this.aiDisplayMaster.length;
11640		},
11641	
11642		/**
11643		 * Get the number of records in the current record set, after filtering
11644		 */
11645		"fnRecordsDisplay": function ()
11646		{
11647			return _fnDataSource( this ) == 'ssp' ?
11648				this._iRecordsDisplay * 1 :
11649				this.aiDisplay.length;
11650		},
11651	
11652		/**
11653		 * Get the display end point - aiDisplay index
11654		 */
11655		"fnDisplayEnd": function ()
11656		{
11657			var
11658				len      = this._iDisplayLength,
11659				start    = this._iDisplayStart,
11660				calc     = start + len,
11661				records  = this.aiDisplay.length,
11662				features = this.oFeatures,
11663				paginate = features.bPaginate;
11664	
11665			if ( features.bServerSide ) {
11666				return paginate === false || len === -1 ?
11667					start + records :
11668					Math.min( start+len, this._iRecordsDisplay );
11669			}
11670			else {
11671				return ! paginate || calc>records || len===-1 ?
11672					records :
11673					calc;
11674			}
11675		},
11676	
11677		/**
11678		 * The DataTables object for this table
11679		 */
11680		"oInstance": null,
11681	
11682		/**
11683		 * Unique identifier for each instance of the DataTables object. If there
11684		 * is an ID on the table node, then it takes that value, otherwise an
11685		 * incrementing internal counter is used.
11686		 */
11687		"sInstance": null,
11688	
11689		/**
11690		 * tabindex attribute value that is added to DataTables control elements, allowing
11691		 * keyboard navigation of the table and its controls.
11692		 */
11693		"iTabIndex": 0,
11694	
11695		/**
11696		 * DIV container for the footer scrolling table if scrolling
11697		 */
11698		"nScrollHead": null,
11699	
11700		/**
11701		 * DIV container for the footer scrolling table if scrolling
11702		 */
11703		"nScrollFoot": null,
11704	
11705		/**
11706		 * Last applied sort
11707		 */
11708		"aLastSort": [],
11709	
11710		/**
11711		 * Stored plug-in instances
11712		 */
11713		"oPlugins": {},
11714	
11715		/**
11716		 * Function used to get a row's id from the row's data
11717		 */
11718		"rowIdFn": null,
11719	
11720		/**
11721		 * Data location where to store a row's id
11722		 */
11723		"rowId": null,
11724	
11725		caption: '',
11726	
11727		captionNode: null,
11728	
11729		colgroup: null
11730	};
11731	
11732	/**
11733	 * Extension object for DataTables that is used to provide all extension
11734	 * options.
11735	 *
11736	 * Note that the `DataTable.ext` object is available through
11737	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
11738	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
11739	 *  @namespace
11740	 *  @extends DataTable.models.ext
11741	 */
11742	
11743	
11744	var extPagination = DataTable.ext.pager;
11745	
11746	// Paging buttons configuration
11747	$.extend( extPagination, {
11748		simple: function () {
11749			return [ 'previous', 'next' ];
11750		},
11751	
11752		full: function () {
11753			return [  'first', 'previous', 'next', 'last' ];
11754		},
11755	
11756		numbers: function () {
11757			return [ 'numbers' ];
11758		},
11759	
11760		simple_numbers: function () {
11761			return [ 'previous', 'numbers', 'next' ];
11762		},
11763	
11764		full_numbers: function () {
11765			return [ 'first', 'previous', 'numbers', 'next', 'last' ];
11766		},
11767		
11768		first_last: function () {
11769			return ['first', 'last'];
11770		},
11771		
11772		first_last_numbers: function () {
11773			return ['first', 'numbers', 'last'];
11774		},
11775	
11776		// For testing and plug-ins to use
11777		_numbers: _pagingNumbers,
11778	
11779		// Number of number buttons - legacy, use `numbers` option for paging feature
11780		numbers_length: 7
11781	} );
11782	
11783	
11784	$.extend( true, DataTable.ext.renderer, {
11785		pagingButton: {
11786			_: function (settings, buttonType, content, active, disabled) {
11787				var classes = settings.oClasses.paging;
11788				var btnClasses = [classes.button];
11789				var btn;
11790	
11791				if (active) {
11792					btnClasses.push(classes.active);
11793				}
11794	
11795				if (disabled) {
11796					btnClasses.push(classes.disabled)
11797				}
11798	
11799				if (buttonType === 'ellipsis') {
11800					btn = $('<span class="ellipsis"></span>').html(content)[0];
11801				}
11802				else {
11803					btn = $('<button>', {
11804						class: btnClasses.join(' '),
11805						role: 'link',
11806						type: 'button'
11807					}).html(content);
11808				}
11809	
11810				return {
11811					display: btn,
11812					clicker: btn
11813				}
11814			}
11815		},
11816	
11817		pagingContainer: {
11818			_: function (settings, buttons) {
11819				// No wrapping element - just append directly to the host
11820				return buttons;
11821			}
11822		}
11823	} );
11824	
11825	// Common function to remove new lines, strip HTML and diacritic control
11826	var _filterString = function (stripHtml, normalize) {
11827		return function (str) {
11828			if (_empty(str) || typeof str !== 'string') {
11829				return str;
11830			}
11831	
11832			str = str.replace( _re_new_lines, " " );
11833	
11834			if (stripHtml) {
11835				str = _stripHtml(str);
11836			}
11837	
11838			if (normalize) {
11839				str = _normalize(str, false);
11840			}
11841	
11842			return str;
11843		};
11844	}
11845	
11846	/*
11847	 * Public helper functions. These aren't used internally by DataTables, or
11848	 * called by any of the options passed into DataTables, but they can be used
11849	 * externally by developers working with DataTables. They are helper functions
11850	 * to make working with DataTables a little bit easier.
11851	 */
11852	
11853	function __mldFnName(name) {
11854		return name.replace(/[\W]/g, '_')
11855	}
11856	
11857	// Common logic for moment, luxon or a date action
11858	function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) {
11859		if (window.moment) {
11860			return dt[momentFn]( arg1 );
11861		}
11862		else if (window.luxon) {
11863			return dt[luxonFn]( arg1 );
11864		}
11865		
11866		return dateFn ? dt[dateFn]( arg1 ) : dt;
11867	}
11868	
11869	
11870	var __mlWarning = false;
11871	function __mldObj (d, format, locale) {
11872		var dt;
11873	
11874		if (window.moment) {
11875			dt = window.moment.utc( d, format, locale, true );
11876	
11877			if (! dt.isValid()) {
11878				return null;
11879			}
11880		}
11881		else if (window.luxon) {
11882			dt = format && typeof d === 'string'
11883				? window.luxon.DateTime.fromFormat( d, format )
11884				: window.luxon.DateTime.fromISO( d );
11885	
11886			if (! dt.isValid) {
11887				return null;
11888			}
11889	
11890			dt.setLocale(locale);
11891		}
11892		else if (! format) {
11893			// No format given, must be ISO
11894			dt = new Date(d);
11895		}
11896		else {
11897			if (! __mlWarning) {
11898				alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
11899			}
11900	
11901			__mlWarning = true;
11902		}
11903	
11904		return dt;
11905	}
11906	
11907	// Wrapper for date, datetime and time which all operate the same way with the exception of
11908	// the output string for auto locale support
11909	function __mlHelper (localeString) {
11910		return function ( from, to, locale, def ) {
11911			// Luxon and Moment support
11912			// Argument shifting
11913			if ( arguments.length === 0 ) {
11914				locale = 'en';
11915				to = null;
11915 // means toLocaleString
11916				from = null; // means iso8601
11917			}
11918			else if ( arguments.length === 1 ) {
11919				locale = 'en';
11920				to = from;
11921				from = null;
11922			}
11923			else if ( arguments.length === 2 ) {
11924				locale = to;
11925				to = from;
11926				from = null;
11927			}
11928	
11929			var typeName = 'datetime' + (to ? '-' + __mldFnName(to) : '');
11930	
11931			// Add type detection and sorting specific to this date format - we need to be able to identify
11932			// date type columns as such, rather than as numbers in extensions. Hence the need for this.
11933			if (! DataTable.ext.type.order[typeName]) {
11934				DataTable.type(typeName, {
11935					detect: function (d) {
11936						// The renderer will give the value to type detect as the type!
11937						return d === typeName ? typeName : false;
11938					},
11939					order: {
11940						pre: function (d) {
11941							// The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
11942							// `valueOf` which gives milliseconds epoch
11943							return d.valueOf();
11944						}
11945					},
11946					className: 'dt-right'
11947				});
11948			}
11949		
11950			return function ( d, type ) {
11951				// Allow for a default value
11952				if (d === null || d === undefined) {
11953					if (def === '--now') {
11954						// We treat everything as UTC further down, so no changes are
11955						// made, as such need to get the local date / time as if it were
11956						// UTC
11957						var local = new Date();
11958						d = new Date( Date.UTC(
11959							local.getFullYear(), local.getMonth(), local.getDate(),
11960							local.getHours(), local.getMinutes(), local.getSeconds()
11961						) );
11962					}
11963					else {
11964						d = '';
11965					}
11966				}
11967	
11968				if (type === 'type') {
11969					// Typing uses the type name for fast matching
11970					return typeName;
11971				}
11972	
11973				if (d === '') {
11974					return type !== 'sort'
11975						? ''
11976						: __mldObj('0000-01-01 00:00:00', null, locale);
11977				}
11978	
11979				// Shortcut. If `from` and `to` are the same, we are using the renderer to
11980				// format for ordering, not display - its already in the display format.
11981				if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) {
11982					return d;
11983				}
11984	
11985				var dt = __mldObj(d, from, locale);
11986	
11987				if (dt === null) {
11988					return d;
11989				}
11990	
11991				if (type === 'sort') {
11992					return dt;
11993				}
11994				
11995				var formatted = to === null
11996					? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
11997					: __mld(dt, 'format', 'toFormat', 'toISOString', to);
11998	
11999				// XSS protection
12000				return type === 'display' ?
12001					_escapeHtml( formatted ) :
12002					formatted;
12003			};
12004		}
12005	}
12006	
12007	// Based on locale, determine standard number formatting
12008	// Fallback for legacy browsers is US English
12009	var __thousands = ',';
12010	var __decimal = '.';
12011	
12012	if (window.Intl !== undefined) {
12013		try {
12014			var num = new Intl.NumberFormat().formatToParts(100000.1);
12015		
12016			for (var i=0 ; i<num.length ; i++) {
12017				if (num[i].type === 'group') {
12018					__thousands = num[i].value;
12019				}
12020				else if (num[i].type === 'decimal') {
12021					__decimal = num[i].value;
12022				}
12023			}
12024		}
12025		catch (e) {
12026			// noop
12027		}
12028	}
12029	
12030	// Formatted date time detection - use by declaring the formats you are going to use
12031	DataTable.datetime = function ( format, locale ) {
12032		var typeName = 'datetime-detect-' + __mldFnName(format);
12033	
12034		if (! locale) {
12035			locale = 'en';
12036		}
12037	
12038		if (! DataTable.ext.type.order[typeName]) {
12039			DataTable.type(typeName, {
12040				detect: function (d) {
12041					var dt = __mldObj(d, format, locale);
12042					return d === '' || dt ? typeName : false;
12043				},
12044				order: {
12045					pre: function (d) {
12046						return __mldObj(d, format, locale) || 0;
12047					}
12048				},
12049				className: 'dt-right'
12050			});
12051		}
12052	}
12053	
12054	/**
12055	 * Helpers for `columns.render`.
12056	 *
12057	 * The options defined here can be used with the `columns.render` initialisation
12058	 * option to provide a display renderer. The following functions are defined:
12059	 *
12060	 * * `moment` - Uses the MomentJS library to convert from a given format into another.
12061	 * This renderer has three overloads:
12062	 *   * 1 parameter:
12063	 *     * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
12064	 *   * 2 parameters:
12065	 *     * `string` - Format to convert from
12066	 *     * `string` - Format to convert to. Assumes `en` locale
12067	 *   * 3 parameters:
12068	 *     * `string` - Format to convert from
12069	 *     * `string` - Format to convert to
12070	 *     * `string` - Locale
12071	 * * `number` - Will format numeric data (defined by `columns.data`) for
12072	 *   display, retaining the original unformatted data for sorting and filtering.
12073	 *   It takes 5 parameters:
12074	 *   * `string` - Thousands grouping separator
12075	 *   * `string` - Decimal point indicator
12076	 *   * `integer` - Number of decimal points to show
12077	 *   * `string` (optional) - Prefix.
12078	 *   * `string` (optional) - Postfix (/suffix).
12079	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
12080	 *   parameters.
12081	 *
12082	 * @example
12083	 *   // Column definition using the number renderer
12084	 *   {
12085	 *     data: "salary",
12086	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
12087	 *   }
12088	 *
12089	 * @namespace
12090	 */
12091	DataTable.render = {
12092		date: __mlHelper('toLocaleDateString'),
12093		datetime: __mlHelper('toLocaleString'),
12094		time: __mlHelper('toLocaleTimeString'),
12095		number: function ( thousands, decimal, precision, prefix, postfix ) {
12096			// Auto locale detection
12097			if (thousands === null || thousands === undefined) {
12098				thousands = __thousands;
12099			}
12100	
12101			if (decimal === null || decimal === undefined) {
12102				decimal = __decimal;
12103			}
12104	
12105			return {
12106				display: function ( d ) {
12107					if ( typeof d !== 'number' && typeof d !== 'string' ) {
12108						return d;
12109					}
12110	
12111					if (d === '' || d === null) {
12112						return d;
12113					}
12114	
12115					var negative = d < 0 ? '-' : '';
12116					var flo = parseFloat( d );
12117					var abs = Math.abs(flo);
12118	
12119					// Scientific notation for large and small numbers
12120					if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0) ) {
12121						var exp = flo.toExponential(precision).split(/e\+?/);
12122						return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
12123					}
12124	
12125					// If NaN then there isn't much formatting that we can do - just
12126					// return immediately, escaping any HTML (this was supposed to
12127					// be a number after all)
12128					if ( isNaN( flo ) ) {
12129						return _escapeHtml( d );
12130					}
12131	
12132					flo = flo.toFixed( precision );
12133					d = Math.abs( flo );
12134	
12135					var intPart = parseInt( d, 10 );
12136					var floatPart = precision ?
12137						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
12138						'';
12139	
12140					// If zero, then can't have a negative prefix
12141					if (intPart === 0 && parseFloat(floatPart) === 0) {
12142						negative = '';
12143					}
12144	
12145					return negative + (prefix||'') +
12146						intPart.toString().replace(
12147							/\B(?=(\d{3})+(?!\d))/g, thousands
12148						) +
12149						floatPart +
12150						(postfix||'');
12151				}
12152			};
12153		},
12154	
12155		text: function () {
12156			return {
12157				display: _escapeHtml,
12158				filter: _escapeHtml
12159			};
12160		}
12161	};
12162	
12163	
12164	var _extTypes = DataTable.ext.type;
12165	
12166	// Get / set type
12167	DataTable.type = function (name, prop, val) {
12168		if (! prop) {
12169			return {
12170				className: _extTypes.className[name],
12171				detect: _extTypes.detect.find(function (fn) {
12172					return fn.name === name;
12173				}),
12174				order: {
12175					pre: _extTypes.order[name + '-pre'],
12176					asc: _extTypes.order[name + '-asc'],
12177					desc: _extTypes.order[name + '-desc']
12178				},
12179				render: _extTypes.render[name],
12180				search: _extTypes.search[name]
12181			};
12182		}
12183	
12184		var setProp = function(prop, propVal) {
12185			_extTypes[prop][name] = propVal;
12186		};
12187		var setDetect = function (fn) {
12188			// Wrap to allow the function to return `true` rather than
12189			// specifying the type name.
12190			var cb = function (d, s) {
12191				var ret = fn(d, s);
12192	
12193				return ret === true
12194					? name
12195					: ret;
12196			};
12197			Object.defineProperty(cb, "name", {value: name});
12198	
12199			var idx = _extTypes.detect.findIndex(function (fn) {
12200				return fn.name === name;
12201			});
12202	
12203			if (idx === -1) {
12204				_extTypes.detect.unshift(cb);
12205			}
12206			else {
12207				_extTypes.detect.splice(idx, 1, cb);
12208			}
12209		};
12210		var setOrder = function (obj) {
12211			_extTypes.order[name + '-pre'] = obj.pre; // can be undefined
12212			_extTypes.order[name + '-asc'] = obj.asc; // can be undefined
12213			_extTypes.order[name + '-desc'] = obj.desc; // can be undefined
12214		};
12215	
12216		// prop is optional
12217		if (val === undefined) {
12218			val = prop;
12219			prop = null;
12220		}
12221	
12222		if (prop === 'className') {
12223			setProp('className', val);
12224		}
12225		else if (prop === 'detect') {
12226			setDetect(val);
12227		}
12228		else if (prop === 'order') {
12229			setOrder(val);
12230		}
12231		else if (prop === 'render') {
12232			setProp('render', val);
12233		}
12234		else if (prop === 'search') {
12235			setProp('search', val);
12236		}
12237		else if (! prop) {
12238			if (val.className) {
12239				setProp('className', val.className);
12240			}
12241	
12242			if (val.detect !== undefined) {
12243				setDetect(val.detect);
12244			}
12245	
12246			if (val.order) {
12247				setOrder(val.order);
12248			}
12249	
12250			if (val.render !== undefined) {
12251				setProp('render', val.render);
12252			}
12253	
12254			if (val.search !== undefined) {
12255				setProp('search', val.search);
12256			}
12257		}
12258	}
12259	
12260	// Get a list of types
12261	DataTable.types = function () {
12262		return _extTypes.detect.map(function (fn) {
12263			return fn.name;
12264		});
12265	};
12266	
12267	//
12268	// Built in data types
12269	//
12270	
12271	DataTable.type('string', {
12272		detect: function () {
12273			return 'string';
12274		},
12275		order: {
12276			pre: function ( a ) {
12277				// This is a little complex, but faster than always calling toString,
12278				// http://jsperf.com/tostring-v-check
12279				return _empty(a) ?
12280					'' :
12281					typeof a === 'string' ?
12282						a.toLowerCase() :
12283						! a.toString ?
12284							'' :
12285							a.toString();
12286			}
12287		},
12288		search: _filterString(false, true)
12289	});
12290	
12291	
12292	DataTable.type('html', {
12293		detect: function ( d ) {
12294			return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
12295				'html' : null;
12296		},
12297		order: {
12298			pre: function ( a ) {
12299				return _empty(a) ?
12300					'' :
12301					a.replace ?
12302						_stripHtml(a).trim().toLowerCase() :
12303						a+'';
12304			}
12305		},
12306		search: _filterString(true, true)
12307	});
12308	
12309	
12310	DataTable.type('date', {
12311		className: 'dt-type-date',
12312		detect: function ( d )
12313		{
12314			// V8 tries _very_ hard to make a string passed into `Date.parse()`
12315			// valid, so we need to use a regex to restrict date formats. Use a
12316			// plug-in for anything other than ISO8601 style strings
12317			if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
12318				return null;
12319			}
12320			var parsed = Date.parse(d);
12321			return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
12322		},
12323		order: {
12324			pre: function ( d ) {
12325				var ts = Date.parse( d );
12326				return isNaN(ts) ? -Infinity : ts;
12327			}
12328		}
12329	});
12330	
12331	
12332	DataTable.type('html-num-fmt', {
12333		className: 'dt-type-numeric',
12334		detect: function ( d, settings )
12335		{
12336			var decimal = settings.oLanguage.sDecimal;
12337			return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt' : null;
12338		},
12339		order: {
12340			pre: function ( d, s ) {
12341				var dp = s.oLanguage.sDecimal;
12342				return __numericReplace( d, dp, _re_html, _re_formatted_numeric );
12343			}
12344		},
12345		search: _filterString(true, true)
12346	});
12347	
12348	
12349	DataTable.type('html-num', {
12350		className: 'dt-type-numeric',
12351		detect: function ( d, settings )
12352		{
12353			var decimal = settings.oLanguage.sDecimal;
12354			return _htmlNumeric( d, decimal ) ? 'html-num' : null;
12355		},
12356		order: {
12357			pre: function ( d, s ) {
12358				var dp = s.oLanguage.sDecimal;
12359				return __numericReplace( d, dp, _re_html );
12360			}
12361		},
12362		search: _filterString(true, true)
12363	});
12364	
12365	
12366	DataTable.type('num-fmt', {
12367		className: 'dt-type-numeric',
12368		detect: function ( d, settings )
12369		{
12370			var decimal = settings.oLanguage.sDecimal;
12371			return _isNumber( d, decimal, true ) ? 'num-fmt' : null;
12372		},
12373		order: {
12374			pre: function ( d, s ) {
12375				var dp = s.oLanguage.sDecimal;
12376				return __numericReplace( d, dp, _re_formatted_numeric );
12377			}
12378		}
12379	});
12380	
12381	
12382	DataTable.type('num', {
12383		className: 'dt-type-numeric',
12384		detect: function ( d, settings )
12385		{
12386			var decimal = settings.oLanguage.sDecimal;
12387			return _isNumber( d, decimal ) ? 'num' : null;
12388		},
12389		order: {
12390			pre: function (d, s) {
12391				var dp = s.oLanguage.sDecimal;
12392				return __numericReplace( d, dp );
12393			}
12394		}
12395	});
12396	
12397	
12398	
12399	
12400	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
12401		if ( d !== 0 && (!d || d === '-') ) {
12402			return -Infinity;
12403		}
12404		
12405		var type = typeof d;
12406	
12407		if (type === 'number' || type === 'bigint') {
12408			return d;
12409		}
12410	
12411		// If a decimal place other than `.` is used, it needs to be given to the
12412		// function so we can detect it and replace with a `.` which is the only
12413		// decimal place Javascript recognises - it is not locale aware.
12414		if ( decimalPlace ) {
12415			d = _numToDecimal( d, decimalPlace );
12416		}
12417	
12418		if ( d.replace ) {
12419			if ( re1 ) {
12420				d = d.replace( re1, '' );
12421			}
12422	
12423			if ( re2 ) {
12424				d = d.replace( re2, '' );
12425			}
12426		}
12427	
12428		return d * 1;
12429	};
12430	
12431	
12432	$.extend( true, DataTable.ext.renderer, {
12433		footer: {
12434			_: function ( settings, cell, classes ) {
12435				cell.addClass(classes.tfoot.cell);
12436			}
12437		},
12438	
12439		header: {
12440			_: function ( settings, cell, classes ) {
12441				cell.addClass(classes.thead.cell);
12442	
12443				if (! settings.oFeatures.bSort) {
12444					cell.addClass(classes.order.none);
12445				}
12446	
12447				var legacyTop = settings.bSortCellsTop;
12448				var headerRows = cell.closest('thead').find('tr');
12449				var rowIdx = cell.parent().index();
12450	
12451				// Conditions to not apply the ordering icons
12452				if (
12453					// Cells and rows which have the attribute to disable the icons
12454					cell.attr('data-dt-order') === 'disable' ||
12455					cell.parent().attr('data-dt-order') === 'disable' ||
12456	
12457					// Legacy support for `orderCellsTop`. If it is set, then cells
12458					// which are not in the top or bottom row of the header (depending
12459					// on the value) do not get the sorting classes applied to them
12460					(legacyTop === true && rowIdx !== 0) ||
12461					(legacyTop === false && rowIdx !== headerRows.length - 1)
12462				) {
12463					return;
12464				}
12465	
12466				// No additional mark-up required
12467				// Attach a sort listener to update on sort - note that using the
12468				// `DT` namespace will allow the event to be removed automatically
12469				// on destroy, while the `dt` namespaced event is the one we are
12470				// listening for
12471				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting ) {
12472					if ( settings !== ctx ) { // need to check this this is the host
12473						return;               // table, not a nested one
12474					}
12475	
12476					var orderClasses = classes.order;
12477					var columns = ctx.api.columns( cell );
12478					var col = settings.aoColumns[columns.flatten()[0]];
12479					var orderable = columns.orderable().includes(true);
12480					var ariaType = '';
12481					var indexes = columns.indexes();
12482					var sortDirs = columns.orderable(true).flatten();
12483					var orderedColumns = ',' + sorting.map( function (val) {
12484						return val.col;
12485					} ).join(',') + ',';
12486	
12487					cell
12488						.removeClass(
12489							orderClasses.isAsc +' '+
12490							orderClasses.isDesc
12491						)
12492						.toggleClass( orderClasses.none, ! orderable )
12493						.toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
12494						.toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
12495					
12496					var sortIdx = orderedColumns.indexOf( ',' + indexes.toArray().join(',') + ',' );
12497	
12498					if ( sortIdx !== -1 ) {
12499						// Get the ordering direction for the columns under this cell
12500						// Note that it is possible for a cell to be asc and desc sorting
12501						// (column spanning cells)
12502						var orderDirs = columns.order();
12503	
12504						cell.addClass(
12505							orderDirs.includes('asc') ? orderClasses.isAsc : '' +
12506							orderDirs.includes('desc') ? orderClasses.isDesc : ''
12507						);
12508					}
12509	
12510					// The ARIA spec says that only one column should be marked with aria-sort
12511					if ( sortIdx === 0 ) {
12512						var firstSort = sorting[0];
12513						var sortOrder = col.asSorting;
12514	
12515						cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
12516	
12517						// Determine if the next click will remove sorting or change the sort
12518						ariaType = ! sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
12519					}
12520					else {
12521						cell.removeAttr('aria-sort');
12522					}
12523	
12524					cell.attr('aria-label', orderable
12525						? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
12526						: col.ariaTitle
12527					);
12528	
12529					if (orderable) {
12530						cell.find('.dt-column-title').attr('role', 'button');
12531						cell.attr('tabindex', 0)
12532					}
12533				} );
12534			}
12535		},
12536	
12537		layout: {
12538			_: function ( settings, container, items ) {
12539				var row = $('<div/>')
12540					.addClass('dt-layout-row')
12541					.appendTo( container );
12542	
12543				$.each( items, function (key, val) {
12544					var klass = ! val.table ?
12545						'dt-'+key+' ' :
12546						'';
12547	
12548					if (val.table) {
12549						row.addClass('dt-layout-table');
12550					}
12551	
12552					$('<div/>')
12553						.attr({
12554							id: val.id || null,
12555							"class": 'dt-layout-cell '+klass+(val.className || '')
12556						})
12557						.append( val.contents )
12558						.appendTo( row );
12559				} );
12560			}
12561		}
12562	} );
12563	
12564	
12565	DataTable.feature = {};
12566	
12567	// Third parameter is internal only!
12568	DataTable.feature.register = function ( name, cb, legacy ) {
12569		DataTable.ext.features[ name ] = cb;
12570	
12571		if (legacy) {
12572			_ext.feature.push({
12573				cFeature: legacy,
12574				fnInit: cb
12575			});
12576		}
12577	};
12578	
12579	DataTable.feature.register( 'info', function ( settings, opts ) {
12580		// For compatibility with the legacy `info` top level option
12581		if (! settings.oFeatures.bInfo) {
12582			return null;
12583		}
12584	
12585		var
12586			lang  = settings.oLanguage,
12587			tid = settings.sTableId,
12588			n = $('<div/>', {
12589				'class': settings.oClasses.info.container,
12590			} );
12591	
12592		opts = $.extend({
12593			callback: lang.fnInfoCallback,
12594			empty: lang.sInfoEmpty,
12595			postfix: lang.sInfoPostFix,
12596			search: lang.sInfoFiltered,
12597			text: lang.sInfo,
12598		}, opts);
12599	
12600	
12601		// Update display on each draw
12602		settings.aoDrawCallback.push(function (s) {
12603			_fnUpdateInfo(s, opts, n);
12604		});
12605	
12606		// For the first info display in the table, we add a callback and aria information.
12607		if (! settings._infoEl) {
12608			n.attr({
12609				'aria-live': 'polite',
12610				id: tid+'_info',
12611				role: 'status'
12612			});
12613	
12614			// Table is described by our info div
12615			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
12616	
12617			settings._infoEl = n;
12618		}
12619	
12620		return n;
12621	}, 'i' );
12622	
12623	/**
12624	 * Update the information elements in the display
12625	 *  @param {object} settings dataTables settings object
12626	 *  @memberof DataTable#oApi
12627	 */
12628	function _fnUpdateInfo ( settings, opts, node )
12629	{
12630		var
12631			start = settings._iDisplayStart+1,
12632			end   = settings.fnDisplayEnd(),
12633			max   = settings.fnRecordsTotal(),
12634			total = settings.fnRecordsDisplay(),
12635			out   = total
12636				? opts.text
12637				: opts.empty;
12638	
12639		if ( total !== max ) {
12640			// Record set after filtering
12641			out += ' ' + opts.search;
12642		}
12643	
12644		// Convert the macros
12645		out += opts.postfix;
12646		out = _fnMacros( settings, out );
12647	
12648		if ( opts.callback ) {
12649			out = opts.callback.call( settings.oInstance,
12650				settings, start, end, max, total, out
12651			);
12652		}
12653	
12654		node.html( out );
12655	
12656		_fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
12657	}
12658	
12659	var __searchCounter = 0;
12660	
12661	// opts
12662	// - text
12663	// - placeholder
12664	DataTable.feature.register( 'search', function ( settings, opts ) {
12665		// Don't show the input if filtering isn't available on the table
12666		if (! settings.oFeatures.bFilter) {
12667			return null;
12668		}
12669	
12670		var classes = settings.oClasses.search;
12671		var tableId = settings.sTableId;
12672		var language = settings.oLanguage;
12673		var previousSearch = settings.oPreviousSearch;
12674		var input = '<input type="search" class="'+classes.input+'"/>';
12675	
12676		opts = $.extend({
12677			placeholder: language.sSearchPlaceholder,
12678			text: language.sSearch
12679		}, opts);
12680	
12681		// The _INPUT_ is optional - is appended if not present
12682		if (opts.text.indexOf('_INPUT_') === -1) {
12683			opts.text += '_INPUT_';
12684		}
12685	
12686		opts.text = _fnMacros(settings, opts.text);
12687	
12688		// We can put the <input> outside of the label if it is at the start or end
12689		// which helps improve accessability (not all screen readers like implicit
12690		// for elements).
12691		var end = opts.text.match(/_INPUT_$/);
12692		var start = opts.text.match(/^_INPUT_/);
12693		var removed = opts.text.replace(/_INPUT_/, '');
12694		var str = '<label>' + opts.text + '</label>';
12695	
12696		if (start) {
12697			str = '_INPUT_<label>' + removed + '</label>';
12698		}
12699		else if (end) {
12700			str = '<label>' + removed + '</label>_INPUT_';
12701		}
12702	
12703		var filter = $('<div>')
12704			.addClass(classes.container)
12705			.append(str.replace(/_INPUT_/, input));
12706	
12707		// add for and id to label and input
12708		filter.find('label').attr('for', 'dt-search-' + __searchCounter);
12709		filter.find('input').attr('id', 'dt-search-' + __searchCounter);
12710		__searchCounter++;
12711	
12712		var searchFn = function(event) {
12713			var val = this.value;
12714	
12715			if(previousSearch.return && event.key !== "Enter") {
12716				return;
12717			}
12718	
12719			/* Now do the filter */
12720			if ( val != previousSearch.search ) {
12721				previousSearch.search = val;
12722	
12723				_fnFilterComplete( settings, previousSearch );
12724	
12725				// Need to redraw, without resorting
12726				settings._iDisplayStart = 0;
12727				_fnDraw( settings );
12728			}
12729		};
12730	
12731		var searchDelay = settings.searchDelay !== null ?
12732			settings.searchDelay :
12733			0;
12734	
12735		var jqFilter = $('input', filter)
12736			.val( previousSearch.search )
12737			.attr( 'placeholder', opts.placeholder )
12738			.on(
12739				'keyup.DT search.DT input.DT paste.DT cut.DT',
12740				searchDelay ?
12741					DataTable.util.debounce( searchFn, searchDelay ) :
12742					searchFn
12743			)
12744			.on( 'mouseup.DT', function(e) {
12745				// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
12746				// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
12747				// checks the value to see if it has changed. In other browsers it won't have.
12748				setTimeout( function () {
12749					searchFn.call(jqFilter[0], e);
12750				}, 10);
12751			} )
12752			.on( 'keypress.DT', function(e) {
12753				/* Prevent form submission */
12754				if ( e.keyCode == 13 ) {
12755					return false;
12756				}
12757			} )
12758			.attr('aria-controls', tableId);
12759	
12760		// Update the input elements whenever the table is filtered
12761		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
12762			if ( settings === s && jqFilter[0] !== document.activeElement ) {
12763				jqFilter.val( typeof previousSearch.search !== 'function'
12764					? previousSearch.search
12765					: ''
12766				);
12767			}
12768		} );
12769	
12770		return filter;
12771	}, 'f' );
12772	
12773	// opts
12774	// - type - button configuration
12775	// - buttons - number of buttons to show - must be odd
12776	DataTable.feature.register( 'paging', function ( settings, opts ) {
12777		// Don't show the paging input if the table doesn't have paging enabled
12778		if (! settings.oFeatures.bPaginate) {
12779			return null;
12780		}
12781	
12782		opts = $.extend({
12783			buttons: DataTable.ext.pager.numbers_length,
12784			type: settings.sPaginationType,
12785			boundaryNumbers: true
12786		}, opts);
12787	
12788		// To be removed in 2.1
12789		if (opts.numbers) {
12790			opts.buttons = opts.numbers;
12791		}
12792	
12793		var host = $('<div/>').addClass( settings.oClasses.paging.container + ' paging_' + opts.type );
12794		var draw = function () {
12795			_pagingDraw(settings, host, opts);
12796		};
12797	
12798		settings.aoDrawCallback.push(draw);
12799	
12800		// Responsive redraw of paging control
12801		$(settings.nTable).on('column-sizing.dt.DT', draw);
12802	
12803		return host;
12804	}, 'p' );
12805	
12806	function _pagingDraw(settings, host, opts) {
12807		if (! settings._bInitComplete) {
12808			return;
12809		}
12810	
12811		var
12812			plugin = DataTable.ext.pager[ opts.type ],
12813			aria = settings.oLanguage.oAria.paginate || {},
12814			start      = settings._iDisplayStart,
12815			len        = settings._iDisplayLength,
12816			visRecords = settings.fnRecordsDisplay(),
12817			all        = len === -1,
12818			page = all ? 0 : Math.ceil( start / len ),
12819			pages = all ? 1 : Math.ceil( visRecords / len ),
12820			buttons = plugin()
12821				.map(function (val) {
12822					return val === 'numbers'
12823						? _pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
12824						: val;
12825				})
12826				.flat();
12827	
12828		var buttonEls = [];
12829	
12830		for (var i=0 ; i<buttons.length ; i++) {
12831			var button = buttons[i];
12832	
12833			var btnInfo = _pagingButtonInfo(settings, button, page, pages);
12834			var btn = _fnRenderer( settings, 'pagingButton' )(
12835				settings,
12836				button,
12837				btnInfo.display,
12838				btnInfo.active,
12839				btnInfo.disabled
12840			);
12841	
12842			// Common attributes
12843			$(btn.clicker).attr({
12844				'aria-controls': settings.sTableId,
12845				'aria-disabled': btnInfo.disabled ? 'true' : null,
12846				'aria-current': btnInfo.active ? 'page' : null,
12847				'aria-label': aria[ button ],
12848				'data-dt-idx': button,
12849				'tabIndex': btnInfo.disabled ? -1 : settings.iTabIndex,
12850			});
12851	
12852			if (typeof button !== 'number') {
12853				$(btn.clicker).addClass(button);
12854			}
12855	
12856			_fnBindAction(
12857				btn.clicker, {action: button}, function(e) {
12858					e.preventDefault();
12859	
12860					_fnPageChange( settings, e.data.action, true );
12861				}
12862			);
12863	
12864			buttonEls.push(btn.display);
12865		}
12866	
12867		var wrapped = _fnRenderer(settings, 'pagingContainer')(
12868			settings, buttonEls
12869		);
12870	
12871		var activeEl = host.find(document.activeElement).data('dt-idx');
12872	
12873		host.empty().append(wrapped);
12874	
12875		if ( activeEl !== undefined ) {
12876			host.find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
12877		}
12878	
12879		// Responsive - check if the buttons are over two lines based on the
12880		// height of the buttons and the container.
12881		if (
12882			buttonEls.length && // any buttons
12883			opts.numbers > 1 && // prevent infinite
12884			$(host).height() >= ($(buttonEls[0]).outerHeight() * 2) - 10
12885		) {
12886			_pagingDraw(settings, host, $.extend({}, opts, { numbers: opts.numbers - 2 }));
12887		}
12888	}
12889	
12890	/**
12891	 * Get properties for a button based on the current paging state of the table
12892	 *
12893	 * @param {*} settings DT settings object
12894	 * @param {*} button The button type in question
12895	 * @param {*} page Table's current page
12896	 * @param {*} pages Number of pages
12897	 * @returns Info object
12898	 */
12899	function _pagingButtonInfo(settings, button, page, pages) {
12900		var lang = settings.oLanguage.oPaginate;
12901		var o = {
12902			display: '',
12903			active: false,
12904			disabled: false
12905		};
12906	
12907		switch ( button ) {
12908			case 'ellipsis':
12909				o.display = '&#x2026;';
12910				o.disabled = true;
12911				break;
12912	
12913			case 'first':
12914				o.display = lang.sFirst;
12915	
12916				if (page === 0) {
12917					o.disabled = true;
12918				}
12919				break;
12920	
12921			case 'previous':
12922				o.display = lang.sPrevious;
12923	
12924				if ( page === 0 ) {
12925					o.disabled = true;
12926				}
12927				break;
12928	
12929			case 'next':
12930				o.display = lang.sNext;
12931	
12932				if ( pages === 0 || page === pages-1 ) {
12933					o.disabled = true;
12934				}
12935				break;
12936	
12937			case 'last':
12938				o.display = lang.sLast;
12939	
12940				if ( pages === 0 || page === pages-1 ) {
12941					o.disabled = true;
12942				}
12943				break;
12944	
12945			default:
12946				if ( typeof button === 'number' ) {
12947					o.display = settings.fnFormatNumber( button + 1 );
12948					
12949					if (page === button) {
12950						o.active = true;
12951					}
12952				}
12953				break;
12954		}
12955	
12956		return o;
12957	}
12958	
12959	/**
12960	 * Compute what number buttons to show in the paging control
12961	 *
12962	 * @param {*} page Current page
12963	 * @param {*} pages Total number of pages
12964	 * @param {*} buttons Target number of number buttons
12965	 * @param {boolean} addFirstLast Indicate if page 1 and end should be included
12966	 * @returns Buttons to show
12967	 */
12968	function _pagingNumbers ( page, pages, buttons, addFirstLast ) {
12969		var
12970			numbers = [],
12971			half = Math.floor(buttons / 2),
12972			before = addFirstLast ? 2 : 1,
12973			after = addFirstLast ? 1 : 0;
12974	
12975		if ( pages <= buttons ) {
12976			numbers = _range(0, pages);
12977		}
12978		else if (buttons === 1) {
12979			// Single button - current page only
12980			numbers = [page];
12981		}
12982		else if (buttons === 3) {
12983			// Special logic for just three buttons
12984			if (page <= 1) {
12985				numbers = [0, 1, 'ellipsis'];
12986			}
12987			else if (page >= pages - 2) {
12988				numbers = _range(pages-2, pages);
12989				numbers.unshift('ellipsis');
12990			}
12991			else {
12992				numbers = ['ellipsis', page, 'ellipsis'];
12993			}
12994		}
12995		else if ( page <= half ) {
12996			numbers = _range(0, buttons-before);
12997			numbers.push('ellipsis');
12998	
12999			if (addFirstLast) {
13000				numbers.push(pages-1);
13001			}
13002		}
13003		else if ( page >= pages - 1 - half ) {
13004			numbers = _range(pages-(buttons-before), pages);
13005			numbers.unshift('ellipsis');
13006	
13007			if (addFirstLast) {
13008				numbers.unshift(0);
13009			}
13010		}
13011		else {
13012			numbers = _range(page-half+before, page+half-after);
13013			numbers.push('ellipsis');
13014			numbers.unshift('ellipsis');
13015	
13016			if (addFirstLast) {
13017				numbers.push(pages-1);
13018				numbers.unshift(0);
13019			}
13020		}
13021	
13022		return numbers;
13023	}
13024	
13025	var __lengthCounter = 0;
13026	
13027	// opts
13028	// - menu
13029	// - text
13030	DataTable.feature.register( 'pageLength', function ( settings, opts ) {
13031		var features = settings.oFeatures;
13032	
13033		// For compatibility with the legacy `pageLength` top level option
13034		if (! features.bPaginate || ! features.bLengthChange) {
13035			return null;
13036		}
13037	
13038		opts = $.extend({
13039			menu: settings.aLengthMenu,
13040			text: settings.oLanguage.sLengthMenu
13041		}, opts);
13042	
13043		var
13044			classes  = settings.oClasses.length,
13045			tableId  = settings.sTableId,
13046			menu     = opts.menu,
13047			lengths  = [],
13048			language = [],
13049			i;
13050	
13051		// Options can be given in a number of ways
13052		if (Array.isArray( menu[0] )) {
13053			// Old 1.x style - 2D array
13054			lengths = menu[0];
13055			language = menu[1];
13056		}
13057		else {
13058			for ( i=0 ; i<menu.length ; i++ ) {
13059				// An object with different label and value
13060				if ($.isPlainObject(menu[i])) {
13061					lengths.push(menu[i].value);
13062					language.push(menu[i].label);
13063				}
13064				else {
13065					// Or just a number to display and use
13066					lengths.push(menu[i]);
13067					language.push(menu[i]);
13068				}
13069			}
13070		}
13071	
13072		// We can put the <select> outside of the label if it is at the start or
13073		// end which helps improve accessability (not all screen readers like
13074		// implicit for elements).
13075		var end = opts.text.match(/_MENU_$/);
13076		var start = opts.text.match(/^_MENU_/);
13077		var removed = opts.text.replace(/_MENU_/, '');
13078		var str = '<label>' + opts.text + '</label>';
13079	
13080		if (start) {
13081			str = '_MENU_<label>' + removed + '</label>';
13082		}
13083		else if (end) {
13084			str = '<label>' + removed + '</label>_MENU_';
13085		}
13086	
13087		// Wrapper element - use a span as a holder for where the select will go
13088		var div = $('<div/>')
13089			.addClass( classes.container )
13090			.append(
13091				str.replace( '_MENU_', '<span></span>' )
13092			);
13093	
13094		// Save text node content for macro updating
13095		var textNodes = [];
13096		div.find('label')[0].childNodes.forEach(function (el) {
13097			if (el.nodeType === Node.TEXT_NODE) {
13098				textNodes.push({
13099					el: el,
13100					text: el.textContent
13101				});
13102			}
13103		})
13104	
13105		// Update the label text in case it has an entries value
13106		var updateEntries = function (len) {
13107			textNodes.forEach(function (node) {
13108				node.el.textContent = _fnMacros(settings, node.text, len);
13109			});
13110		}
13111	
13112		// Next, the select itself, along with the options
13113		var select = $('<select/>', {
13114			'name':          tableId+'_length',
13115			'aria-controls': tableId,
13116			'class':         classes.select
13117		} );
13118	
13119		for ( i=0 ; i<lengths.length ; i++ ) {
13120			select[0][ i ] = new Option(
13121				typeof language[i] === 'number' ?
13122					settings.fnFormatNumber( language[i] ) :
13123					language[i],
13124				lengths[i]
13125			);
13126		}
13127	
13128		// add for and id to label and input
13129		div.find('label').attr('for', 'dt-length-' + __lengthCounter);
13130		select.attr('id', 'dt-length-' + __lengthCounter);
13131		__lengthCounter++;
13132	
13133		// Swap in the select list
13134		div.find('span').replaceWith(select);
13135	
13136		// Can't use `select` variable as user might provide their own and the
13137		// reference is broken by the use of outerHTML
13138		$('select', div)
13139			.val( settings._iDisplayLength )
13140			.on( 'change.DT', function() {
13141				_fnLengthChange( settings, $(this).val() );
13142				_fnDraw( settings );
13143			} );
13144	
13145		// Update node value whenever anything changes the table's length
13146		$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
13147			if ( settings === s ) {
13148				$('select', div).val( len );
13149	
13150				// Resolve plurals in the text for the new length
13151				updateEntries(len);
13152			}
13153		} );
13154	
13155		updateEntries(settings._iDisplayLength);
13156	
13157		return div;
13158	}, 'l' );
13159	
13160	// jQuery access
13161	$.fn.dataTable = DataTable;
13162	
13163	// Provide access to the host jQuery object (circular reference)
13164	DataTable.$ = $;
13165	
13166	// Legacy aliases
13167	$.fn.dataTableSettings = DataTable.settings;
13168	$.fn.dataTableExt = DataTable.ext;
13169	
13170	// With a capital `D` we return a DataTables API instance rather than a
13171	// jQuery object
13172	$.fn.DataTable = function ( opts ) {
13173		return $(this).dataTable( opts ).api();
13174	};
13175	
13176	// All properties that are available to $.fn.dataTable should also be
13177	// available on $.fn.DataTable
13178	$.each( DataTable, function ( prop, val ) {
13179		$.fn.DataTable[ prop ] = val;
13180	} );
13181
13182	return DataTable;
13183}));
13184
13185
13186/*! DataTables styling integration
13187 * © SpryMedia Ltd - datatables.net/license
13188 */
13189
13190(function( factory ){
13191	if ( typeof define === 'function' && define.amd ) {
13192		// AMD
13193		define( ['jquery', 'datatables.net'], function ( $ ) {
13194			return factory( $, window, document );
13195		} );
13196	}
13197	else if ( typeof exports === 'object' ) {
13198		// CommonJS
13199		var jq = require('jquery');
13200		var cjsRequires = function (root, $) {
13201			if ( ! $.fn.dataTable ) {
13202				require('datatables.net')(root, $);
13203			}
13204		};
13205
13206		if (typeof window === 'undefined') {
13207			module.exports = function (root, $) {
13208				if ( ! root ) {
13209					// CommonJS environments without a window global must pass a
13210					// root. This will give an error otherwise
13211					root = window;
13212				}
13213
13214				if ( ! $ ) {
13215					$ = jq( root );
13216				}
13217
13218				cjsRequires( root, $ );
13219				return factory( $, root, root.document );
13220			};
13221		}
13222		else {
13223			cjsRequires( window, jq );
13224			module.exports = factory( jq, window, window.document );
13225		}
13226	}
13227	else {
13228		// Browser
13229		factory( jQuery, window, document );
13230	}
13231}(function( $, window, document ) {
13232'use strict';
13233var DataTable = $.fn.dataTable;
13234
13235
13236
13237
13238
13239return DataTable;
13240}));
13241
13242

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.