PageSourceSearch

https://ecycleregistration.org/assets/vendor/datatables-extended/dataTables.js?v=20240427-1

js ecycleregistration.org collected 2026-09-29 14:06:12 UTC 379,398 bytes, 13,130 lines download raw bytes

vendor: 5,498 bytes, lines 1-190
1/*! DataTables 2.0.5
2 * © SpryMedia Ltd - datatables.net/license
3 */
4
5/**
6 * @summary     DataTables
7 * @description Paginate, search and order HTML tables
8 * @version     2.0.5
9 * @author      SpryMedia Ltd
10 * @contact     www.datatables.net
11 * @copyright   SpryMedia Ltd.
12 *
13 * This source file is free software, available under the following license:
14 *   MIT license - https://datatables.net/license
15 *
16 * This source file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
19 *
20 * For details please refer to: https://www.datatables.net
21 */
22
23(function( factory ) {
24	"use strict";
25
26	if ( typeof define === 'function' && define.amd ) {
27		// AMD
28		define( ['jquery'], function ( $ ) {
29			return factory( $, window, document );
30		} );
31	}
32	else if ( typeof exports === 'object' ) {
33		// CommonJS
34		// jQuery's factory checks for a global window - if it isn't present then it
35		// returns a factory function that expects the window object
36		var jq = require('jquery');
37
38		if (typeof window === 'undefined') {
39			module.exports = function (root, $) {
40				if ( ! root ) {
41					// CommonJS environments without a window global must pass a
42					// root. This will give an error otherwise
43					root = window;
44				}
45
46				if ( ! $ ) {
47					$ = jq( root );
48				}
49
50				return factory( $, root, root.document );
51			};
52		}
53		else {
54			module.exports = factory( jq, window, window.document );
55		}
56	}
57	else {
58		// Browser
59		window.DataTable = factory( jQuery, window, document );
60	}
61}(function( $, window, document ) {
62	"use strict";
63
64	
65	var DataTable = function ( selector, options )
66	{
67		// Check if called with a window or jQuery object for DOM less applications
68		// This is for backwards compatibility
69		if (DataTable.factory(selector, options)) {
70			return DataTable;
71		}
72	
73		// When creating with `new`, create a new DataTable, returning the API instance
74		if (this instanceof DataTable) {
75			return $(selector).DataTable(options);
76		}
77		else {
78			// Argument switching
79			options = selector;
80		}
81	
82		var _that = this;
83		var emptyInit = options === undefined;
84		var len = this.length;
85	
86		if ( emptyInit ) {
87			options = {};
88		}
89	
90		// Method to get DT API instance from jQuery object
91		this.api = function ()
92		{
93			return new _Api( this );
94		};
95	
96		this.each(function() {
97			// For each initialisation we want to give it a clean initialisation
98			// object that can be bashed around
99			var o = {};
100			var oInit = len > 1 ? // optimisation for single table case
101				_fnExtend( o, options, true ) :
102				options;
103	
104			
105			var i=0, iLen;
106			var sId = this.getAttribute( 'id' );
107			var bInitHandedOff = false;
108			var defaults = DataTable.defaults;
109			var $this = $(this);
110			
111			
112			/* Sanity check */
113			if ( this.nodeName.toLowerCase() != 'table' )
114			{
115				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
116				return;
117			}
118			
119			$(this).trigger( 'options.dt', oInit );
120			
121			/* Backwards compatibility for the defaults */
122			_fnCompatOpts( defaults );
123			_fnCompatCols( defaults.column );
124			
125			/* Convert the camel-case defaults to Hungarian */
126			_fnCamelToHungarian( defaults, defaults, true );
127			_fnCamelToHungarian( defaults.column, defaults.column, true );
128			
129			/* Setting up the initialisation object */
130			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
131			
132			
133			
134			/* Check to see if we are re-initialising a table */
135			var allSettings = DataTable.settings;
136			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
137			{
138				var s = allSettings[i];
139			
140				/* Base check on table node */
141				if (
142					s.nTable == this ||
143					(s.nTHead && s.nTHead.parentNode == this) ||
144					(s.nTFoot && s.nTFoot.parentNode == this)
145				) {
146					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
147					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
148			
149					if ( emptyInit || bRetrieve )
150					{
151						return s.oInstance;
152					}
153					else if ( bDestroy )
154					{
155						new DataTable.Api(s).destroy();
156						break;
157					}
158					else
159					{
160						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
161						return;
162					}
163				}
164			
165				/* If the element we are initialising has the same ID as a table which was previously
166				 * initialised, but the table nodes don't match (from before) then we destroy the old
167				 * instance by simply deleting it. This is under the assumption that the table has been
168				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
169				 */
170				if ( s.sTableId == this.id )
171				{
172					allSettings.splice( i, 1 );
173					break;
174				}
175			}
176			
177			/* Ensure the table has an ID - required for accessibility */
178			if ( sId === null || sId === "" )
179			{
180				sId = "DataTables_Table_"+(DataTable.ext._unique++);
181				this.id = sId;
182			}
183			
184			/* Create the settings object for this table and set some of the default parameters */
185			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
186				"sDestroyWidth": $this[0].style.width,
187				"sInstance":     sId,
188				"sTableId":      sId,
189				colgroup: $('<colgroup>').prependTo(this),
190				fastData: function (row, column, type) {
191					return _fnGetCellData(oSettings, row, column, type);
192				}
193			} );
194			oSettings.nTable = this;
195			oSettings.oInit  = oInit;
196			
197			allSettings.push( oSettings );
198			
199			// Make a single API instance available for internal handling
200			oSettings.api = new _Api( oSettings );
201			
202			// Need to add the instance after the instance after the settings object has been added
203			// to the settings array, so we can self reference the table instance if more than one
204			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
205			
206			// Backwards compatibility, before we apply all the defaults
207			_fnCompatOpts( oInit );
208			
209			// If the length menu is given, but the init display length is not, use the length menu
210			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
211			{
212				oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
213					? oInit.aLengthMenu[0][0]
214					: $.isPlainObject( oInit.aLengthMenu[0] )
215						? oInit.aLengthMenu[0].value
216						: oInit.aLengthMenu[0];
217			}
218			
219			// Apply the defaults and init options to make a single init object will all
220			// options defined from defaults and instance options.
221			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
222			
223			
224			// Map the initialisation options onto the settings object
225			_fnMap( oSettings.oFeatures, oInit, [
226				"bPaginate",
227				"bLengthChange",
228				"bFilter",
229				"bSort",
230				"bSortMulti",
231				"bInfo",
232				"bProcessing",
233				"bAutoWidth",
234				"bSortClasses",
235				"bServerSide",
236				"bDeferRender"
237			] );
238			_fnMap( oSettings, oInit, [
239				"ajax",
240				"fnFormatNumber",
241				"sServerMethod",
242				"aaSorting",
243				"aaSortingFixed",
244				"aLengthMenu",
245				"sPaginationType",
246				"iStateDuration",
247				"bSortCellsTop",
248				"iTabIndex",
249				"sDom",
250				"fnStateLoadCallback",
251				"fnStateSaveCallback",
252				"renderer",
253				"searchDelay",
254				"rowId",
255				"caption",
256				"layout",
257				[ "iCookieDuration", "iStateDuration" ], // backwards compat
258				[ "oSearch", "oPreviousSearch" ],
259				[ "aoSearchCols", "aoPreSearchCols" ],
260				[ "iDisplayLength", "_iDisplayLength" ]
261			] );
262			_fnMap( oSettings.oScroll, oInit, [
263				[ "sScrollX", "sX" ],
264				[ "sScrollXInner", "sXInner" ],
265				[ "sScrollY", "sY" ],
266				[ "bScrollCollapse", "bCollapse" ]
267			] );
268			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
269			
270			/* Callback functions which are array driven */
271			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback );
272			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams );
273			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams );
274			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded );
275			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback );
276			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
277			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback );
278			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback );
279			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete );
280			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback );
281			
282			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
283			
284			/* Browser support detection */
285			_fnBrowserDetect( oSettings );
286			
287			var oClasses = oSettings.oClasses;
288			
289			$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
290			$this.addClass( oClasses.table );
291			
292			if (! oSettings.oFeatures.bPaginate) {
293				oInit.iDisplayStart = 0;
294			}
295			
296			if ( oSettings.iInitDisplayStart === undefined )
297			{
298				/* Display start point, taking into account the save saving */
299				oSettings.iInitDisplayStart = oInit.iDisplayStart;
300				oSettings._iDisplayStart = oInit.iDisplayStart;
301			}
302			
303			/* Language definitions */
304			var oLanguage = oSettings.oLanguage;
305			$.extend( true, oLanguage, oInit.oLanguage );
306			
307			if ( oLanguage.sUrl )
308			{
309				/* Get the language definitions from a file - because this Ajax call makes the language
310				 * get async to the remainder of this function we use bInitHandedOff to indicate that
311				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
312				 */
313				$.ajax( {
314					dataType: 'json',
315					url: oLanguage.sUrl,
316					success: function ( json ) {
317						_fnCamelToHungarian( defaults.oLanguage, json );
318						$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
319			
320						_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
321						_fnInitialise( oSettings );
322					},
323					error: function () {
324						// Error occurred loading language file
325						_fnLog( oSettings, 0, 'i18n file loading error', 21 );
326			
327						// continue on as best we can
328						_fnInitialise( oSettings );
329					}
330				} );
331				bInitHandedOff = true;
332			}
333			else {
334				_fnCallbackFire( oSettings, null, 'i18n', [oSettings]);
335			}
336			
337			/*
338			 * Columns
339			 * See if we should load columns automatically or use defined ones
340			 */
341			var columnsInit = [];
342			var thead = this.getElementsByTagName('thead');
343			var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
344			
345			// If we don't have a columns array, then generate one with nulls
346			if ( oInit.aoColumns ) {
347				columnsInit = oInit.aoColumns;
348			}
349			else if ( initHeaderLayout.length ) {
350				for ( i=0, iLen=initHeaderLayout[0].length ; i<iLen ; i++ ) {
351					columnsInit.push( null );
352				}
353			}
354			
355			// Add the columns
356			for ( i=0, iLen=columnsInit.length ; i<iLen ; i++ ) {
357				_fnAddColumn( oSettings );
358			}
359			
360			// Apply the column definitions
361			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
362				_fnColumnOptions( oSettings, iCol, oDef );
363			} );
364			
365			/* HTML5 attribute detection - build an mData object automatically if the
366			 * attributes are found
367			 */
368			var rowOne = $this.children('tbody').find('tr').eq(0);
369			
370			if ( rowOne.length ) {
371				var a = function ( cell, name ) {
372					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
373				};
374			
375				$( rowOne[0] ).children('th, td').each( function (i, cell) {
376					var col = oSettings.aoColumns[i];
377			
378					if (! col) {
379						_fnLog( oSettings, 0, 'Incorrect column count', 18 );
380					}
381			
382					if ( col.mData === i ) {
383						var sort = a( cell, 'sort' ) || a( cell, 'order' );
384						var filter = a( cell, 'filter' ) || a( cell, 'search' );
385			
386						if ( sort !== null || filter !== null ) {
387							col.mData = {
388								_:      i+'.display',
389								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
390								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
391								filter: filter !== null ? i+'.@data-'+filter : undefined
392							};
393							col._isArrayHost = true;
394			
395							_fnColumnOptions( oSettings, i );
396						}
397					}
398				} );
399			}
400			
401			var features = oSettings.oFeatures;
402			var loadedInit = function () {
403				/*
404				 * Sorting
405				 * @todo For modularisation (1.11) this needs to do into a sort start up handler
406				 */
407			
408				// If aaSorting is not defined, then we use the first indicator in asSorting
409				// in case that has been altered, so the default sort reflects that option
410				if ( oInit.aaSorting === undefined ) {
411					var sorting = oSettings.aaSorting;
412					for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
413						sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
414					}
415				}
416			
417				/* Do a first pass on the sorting classes (allows any size changes to be taken into
418				 * account, and also will apply sorting disabled classes if disabled
419				 */
420				_fnSortingClasses( oSettings );
421			
422				_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
423					if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
424						_fnSortingClasses( oSettings );
425					}
426				} );
427			
428			
429				/*
430				 * Final init
431				 * Cache the header, body and footer as required, creating them if needed
432				 */
433				var caption = $this.children('caption');
434			
435				if ( oSettings.caption ) {
436					if ( caption.length === 0 ) {
437						caption = $('<caption/>').appendTo( $this );
438					}
439			
440					caption.html( oSettings.caption );
441				}
442			
443				// Store the caption side, so we can remove the element from the document
444				// when creating the element
445				if (caption.length) {
446					caption[0]._captionSide = caption.css('caption-side');
447					oSettings.captionNode = caption[0];
448				}
449			
450				if ( thead.length === 0 ) {
451					thead = $('<thead/>').appendTo($this);
452				}
453				oSettings.nTHead = thead[0];
454				$('tr', thead).addClass(oClasses.thead.row);
455			
456				var tbody = $this.children('tbody');
457				if ( tbody.length === 0 ) {
458					tbody = $('<tbody/>').insertAfter(thead);
459				}
460				oSettings.nTBody = tbody[0];
461			
462				var tfoot = $this.children('tfoot');
463				if ( tfoot.length === 0 ) {
464					// If we are a scrolling table, and no footer has been given, then we need to create
465					// a tfoot element for the caption element to be appended to
466					tfoot = $('<tfoot/>').appendTo($this);
467				}
468				oSettings.nTFoot = tfoot[0];
469				$('tr', tfoot).addClass(oClasses.tfoot.row);
470			
471				// Check if there is data passing into the constructor
472				if ( oInit.aaData ) {
473					for ( i=0 ; i<oInit.aaData.length ; i++ ) {
474						_fnAddData( oSettings, oInit.aaData[ i ] );
475					}
476				}
477				else if ( _fnDataSource( oSettings ) == 'dom' ) {
478					// Grab the data from the page
479					_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
480				}
481			
482				/* Copy the data index array */
483				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
484			
485				/* Initialisation complete - table can be drawn */
486				oSettings.bInitialised = true;
487			
488				/* Check if we need to initialise the table (it might not have been handed off to the
489				 * language processor)
490				 */
491				if ( bInitHandedOff === false ) {
492					_fnInitialise( oSettings );
493				}
494			};
495			
496			/* Must be done after everything which can be overridden by the state saving! */
497			_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState );
498			
499			if ( oInit.bStateSave )
500			{
501				features.bStateSave = true;
502				_fnLoadState( oSettings, oInit, loadedInit );
503			}
504			else {
505				loadedInit();
506			}
507			
508		} );
509		_that = null;
510		return this;
511	};
512	
513	
514	
515	/**
516	 * DataTables extensions
517	 * 
518	 * This namespace acts as a collection area for plug-ins that can be used to
519	 * extend DataTables capabilities. Indeed many of the build in methods
520	 * use this method to provide their own capabilities (sorting methods for
521	 * example).
522	 *
523	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
524	 * reasons
525	 *
526	 *  @namespace
527	 */
528	DataTable.ext = _ext = {
529		/**
530		 * Buttons. For use with the Buttons extension for DataTables. This is
531		 * defined here so other extensions can define buttons regardless of load
532		 * order. It is _not_ used by DataTables core.
533		 *
534		 *  @type object
535		 *  @default {}
536		 */
537		buttons: {},
538	
539	
540		/**
541		 * Element class names
542		 *
543		 *  @type object
544		 *  @default {}
545		 */
546		classes: {},
547	
548	
549		/**
550		 * DataTables build type (expanded by the download builder)
551		 *
552		 *  @type string
553		 */
554		builder: "-source-",
555	
556	
557		/**
558		 * Error reporting.
559		 * 
560		 * How should DataTables report an error. Can take the value 'alert',
561		 * 'throw', 'none' or a function.
562		 *
563		 *  @type string|function
564		 *  @default alert
565		 */
566		errMode: "alert",
567	
568	
569		/**
570		 * Legacy so v1 plug-ins don't throw js errors on load
571		 */
572		feature: [],
573	
574		/**
575		 * Feature plug-ins.
576		 * 
577		 * This is an object of callbacks which provide the features for DataTables
578		 * to be initialised via the `layout` option.
579		 */
580		features: {},
581	
582	
583		/**
584		 * Row searching.
585		 * 
586		 * This method of searching is complimentary to the default type based
587		 * searching, and a lot more comprehensive as it allows you complete control
588		 * over the searching logic. Each element in this array is a function
589		 * (parameters described below) that is called for every row in the table,
590		 * and your logic decides if it should be included in the searching data set
591		 * or not.
592		 *
593		 * Searching functions have the following input parameters:
594		 *
595		 * 1. `{object}` DataTables settings object: see
596		 *    {@link DataTable.models.oSettings}
597		 * 2. `{array|object}` Data for the row to be processed (same as the
598		 *    original format that was passed in as the data source, or an array
599		 *    from a DOM data source
600		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
601		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
602		 *
603		 * And the following return is expected:
604		 *
605		 * * {boolean} Include the row in the searched result set (true) or not
606		 *   (false)
607		 *
608		 * Note that as with the main search ability in DataTables, technically this
609		 * is "filtering", since it is subtractive. However, for consistency in
610		 * naming we call it searching here.
611		 *
612		 *  @type array
613		 *  @default []
614		 *
615		 *  @example
616		 *    // The following example shows custom search being applied to the
617		 *    // fourth column (i.e. the data[3] index) based on two input values
618		 *    // from the end-user, matching the data in a certain range.
619		 *    $.fn.dataTable.ext.search.push(
620		 *      function( settings, data, dataIndex ) {
621		 *        var min = document.getElementById('min').value * 1;
622		 *        var max = document.getElementById('max').value * 1;
623		 *        var version = data[3] == "-" ? 0 : data[3]*1;
624		 *
625		 *        if ( min == "" && max == "" ) {
626		 *          return true;
627		 *        }
628		 *        else if ( min == "" && version < max ) {
629		 *          return true;
630		 *        }
631		 *        else if ( min < version && "" == max ) {
632		 *          return true;
633		 *        }
634		 *        else if ( min < version && version < max ) {
635		 *          return true;
636		 *        }
637		 *        return false;
638		 *      }
639		 *    );
640		 */
641		search: [],
642	
643	
644		/**
645		 * Selector extensions
646		 *
647		 * The `selector` option can be used to extend the options available for the
648		 * selector modifier options (`selector-modifier` object data type) that
649		 * each of the three built in selector types offer (row, column and cell +
650		 * their plural counterparts). For example the Select extension uses this
651		 * mechanism to provide an option to select only rows, columns and cells
652		 * that have been marked as selected by the end user (`{selected: true}`),
653		 * which can be used in conjunction with the existing built in selector
654		 * options.
655		 *
656		 * Each property is an array to which functions can be pushed. The functions
657		 * take three attributes:
658		 *
659		 * * Settings object for the host table
660		 * * Options object (`selector-modifier` object type)
661		 * * Array of selected item indexes
662		 *
663		 * The return is an array of the resulting item indexes after the custom
664		 * selector has been applied.
665		 *
666		 *  @type object
667		 */
668		selector: {
669			cell: [],
670			column: [],
671			row: []
672		},
673	
674	
675		/**
676		 * Legacy configuration options. Enable and disable legacy options that
677		 * are available in DataTables.
678		 *
679		 *  @type object
680		 */
681		legacy: {
682			/**
683			 * Enable / disable DataTables 1.9 compatible server-side processing
684			 * requests
685			 *
686			 *  @type boolean
687			 *  @default null
688			 */
689			ajax: null
690		},
691	
692	
693		/**
694		 * Pagination plug-in methods.
695		 * 
696		 * Each entry in this object is a function and defines which buttons should
697		 * be shown by the pagination rendering method that is used for the table:
698		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
699		 * buttons are displayed in the document, while the functions here tell it
700		 * what buttons to display. This is done by returning an array of button
701		 * descriptions (what each button will do).
702		 *
703		 * Pagination types (the four built in options and any additional plug-in
704		 * options defined here) can be used through the `paginationType`
705		 * initialisation parameter.
706		 *
707		 * The functions defined take two parameters:
708		 *
709		 * 1. `{int} page` The current page index
710		 * 2. `{int} pages` The number of pages in the table
711		 *
712		 * Each function is expected to return an array where each element of the
713		 * array can be one of:
714		 *
715		 * * `first` - Jump to first page when activated
716		 * * `last` - Jump to last page when activated
717		 * * `previous` - Show previous page when activated
718		 * * `next` - Show next page when activated
719		 * * `{int}` - Show page of the index given
720		 * * `{array}` - A nested array containing the above elements to add a
721		 *   containing 'DIV' element (might be useful for styling).
722		 *
723		 * Note that DataTables v1.9- used this object slightly differently whereby
724		 * an object with two functions would be defined for each plug-in. That
725		 * ability is still supported by DataTables 1.10+ to provide backwards
726		 * compatibility, but this option of use is now decremented and no longer
727		 * documented in DataTables 1.10+.
728		 *
729		 *  @type object
730		 *  @default {}
731		 *
732		 *  @example
733		 *    // Show previous, next and current page buttons only
734		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
735		 *      return [ 'previous', page, 'next' ];
736		 *    };
737		 */
738		pager: {},
739	
740	
741		renderer: {
742			pageButton: {},
743			header: {}
744		},
745	
746	
747		/**
748		 * Ordering plug-ins - custom data source
749		 * 
750		 * The extension options for ordering of data available here is complimentary
751		 * to the default type based ordering that DataTables typically uses. It
752		 * allows much greater control over the the data that is being used to
753		 * order a column, but is necessarily therefore more complex.
754		 * 
755		 * This type of ordering is useful if you want to do ordering based on data
756		 * live from the DOM (for example the contents of an 'input' element) rather
757		 * than just the static string that DataTables knows of.
758		 * 
759		 * The way these plug-ins work is that you create an array of the values you
760		 * wish to be ordering for the column in question and then return that
761		 * array. The data in the array much be in the index order of the rows in
762		 * the table (not the currently ordering order!). Which order data gathering
763		 * function is run here depends on the `dt-init columns.orderDataType`
764		 * parameter that is used for the column (if any).
765		 *
766		 * The functions defined take two parameters:
767		 *
768		 * 1. `{object}` DataTables settings object: see
769		 *    {@link DataTable.models.oSettings}
770		 * 2. `{int}` Target column index
771		 *
772		 * Each function is expected to return an array:
773		 *
774		 * * `{array}` Data for the column to be ordering upon
775		 *
776		 *  @type array
777		 *
778		 *  @example
779		 *    // Ordering using `input` node values
780		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
781		 *    {
782		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
783		 *        return $('input', td).val();
784		 *      } );
785		 *    }
786		 */
787		order: {},
788	
789	
790		/**
791		 * Type based plug-ins.
792		 *
793		 * Each column in DataTables has a type assigned to it, either by automatic
794		 * detection or by direct assignment using the `type` option for the column.
795		 * The type of a column will effect how it is ordering and search (plug-ins
796		 * can also make use of the column type if required).
797		 *
798		 * @namespace
799		 */
800		type: {
801			/**
802			 * Automatic column class assignment
803			 */
804			className: {},
805	
806			/**
807			 * Type detection functions.
808			 *
809			 * The functions defined in this object are used to automatically detect
810			 * a column's type, making initialisation of DataTables super easy, even
811			 * when complex data is in the table.
812			 *
813			 * The functions defined take two parameters:
814			 *
815		     *  1. `{*}` Data from the column cell to be analysed
816		     *  2. `{settings}` DataTables settings object. This can be used to
817		     *     perform context specific type detection - for example detection
818		     *     based on language settings such as using a comma for a decimal
819		     *     place. Generally speaking the options from the settings will not
820		     *     be required
821			 *
822			 * Each function is expected to return:
823			 *
824			 * * `{string|null}` Data type detected, or null if unknown (and thus
825			 *   pass it on to the other type detection functions.
826			 *
827			 *  @type array
828			 *
829			 *  @example
830			 *    // Currency type detection plug-in:
831			 *    $.fn.dataTable.ext.type.detect.push(
832			 *      function ( data, settings ) {
833			 *        // Check the numeric part
834			 *        if ( ! data.substring(1).match(/[0-9]/) ) {
835			 *          return null;
836			 *        }
837			 *
838			 *        // Check prefixed by currency
839			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
840			 *          return 'currency';
841			 *        }
842			 *        return null;
843			 *      }
844			 *    );
845			 */
846			detect: [],
847	
848			/**
849			 * Automatic renderer assignment
850			 */
851			render: {},
852	
853	
854			/**
855			 * Type based search formatting.
856			 *
857			 * The type based searching functions can be used to pre-format the
858			 * data to be search on. For example, it can be used to strip HTML
859			 * tags or to de-format telephone numbers for numeric only searching.
860			 *
861			 * Note that is a search is not defined for a column of a given type,
862			 * no search formatting will be performed.
863			 * 
864			 * Pre-processing of searching data plug-ins - When you assign the sType
865			 * for a column (or have it automatically detected for you by DataTables
866			 * or a type detection plug-in), you will typically be using this for
867			 * custom sorting, but it can also be used to provide custom searching
868			 * by allowing you to pre-processing the data and returning the data in
869			 * the format that should be searched upon. This is done by adding
870			 * functions this object with a parameter name which matches the sType
871			 * for that target column. This is the corollary of <i>afnSortData</i>
872			 * for searching data.
873			 *
874			 * The functions defined take a single parameter:
875			 *
876		     *  1. `{*}` Data from the column cell to be prepared for searching
877			 *
878			 * Each function is expected to return:
879			 *
880			 * * `{string|null}` Formatted string that will be used for the searching.
881			 *
882			 *  @type object
883			 *  @default {}
884			 *
885			 *  @example
886			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
887			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
888			 *    }
889			 */
890			search: {},
891	
892	
893			/**
894			 * Type based ordering.
895			 *
896			 * The column type tells DataTables what ordering to apply to the table
897			 * when a column is sorted upon. The order for each type that is defined,
898			 * is defined by the functions available in this object.
899			 *
900			 * Each ordering option can be described by three properties added to
901			 * this object:
902			 *
903			 * * `{type}-pre` - Pre-formatting function
904			 * * `{type}-asc` - Ascending order function
905			 * * `{type}-desc` - Descending order function
906			 *
907			 * All three can be used together, only `{type}-pre` or only
908			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
909			 * that only `{type}-pre` is used, as this provides the optimal
910			 * implementation in terms of speed, although the others are provided
911			 * for compatibility with existing Javascript sort functions.
912			 *
913			 * `{type}-pre`: Functions defined take a single parameter:
914			 *
915		     *  1. `{*}` Data from the column cell to be prepared for ordering
916			 *
917			 * And return:
918			 *
919			 * * `{*}` Data to be sorted upon
920			 *
921			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
922			 * functions, taking two parameters:
923			 *
924		     *  1. `{*}` Data to compare to the second parameter
925		     *  2. `{*}` Data to compare to the first parameter
926			 *
927			 * And returning:
928			 *
929			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
930			 *   than the second parameter, ===0 if the two parameters are equal and
931			 *   >0 if the first parameter should be sorted height than the second
932			 *   parameter.
933			 * 
934			 *  @type object
935			 *  @default {}
936			 *
937			 *  @example
938			 *    // Numeric ordering of formatted numbers with a pre-formatter
939			 *    $.extend( $.fn.dataTable.ext.type.order, {
940			 *      "string-pre": function(x) {
941			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
942			 *        return parseFloat( a );
943			 *      }
944			 *    } );
945			 *
946			 *  @example
947			 *    // Case-sensitive string ordering, with no pre-formatting method
948			 *    $.extend( $.fn.dataTable.ext.order, {
949			 *      "string-case-asc": function(x,y) {
950			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
951			 *      },
952			 *      "string-case-desc": function(x,y) {
953			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
954			 *      }
955			 *    } );
956			 */
957			order: {}
958		},
959	
960		/**
961		 * Unique DataTables instance counter
962		 *
963		 * @type int
964		 * @private
965		 */
966		_unique: 0,
967	
968	
969		//
970		// Depreciated
971		// The following properties are retained for backwards compatibility only.
972		// The should not be used in new projects and will be removed in a future
973		// version
974		//
975	
976		/**
977		 * Version check function.
978		 *  @type function
979		 *  @depreciated Since 1.10
980		 */
981		fnVersionCheck: DataTable.fnVersionCheck,
982	
983	
984		/**
985		 * Index for what 'this' index API functions should use
986		 *  @type int
987		 *  @deprecated Since v1.10
988		 */
989		iApiIndex: 0,
990	
991	
992		/**
993		 * Software version
994		 *  @type string
995		 *  @deprecated Since v1.10
996		 */
997		sVersion: DataTable.version
998	};
999	
1000	
1001	//
1002	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
1003	//
1004	$.extend( _ext, {
1005		afnFiltering: _ext.search,
1006		aTypes:       _ext.type.detect,
1007		ofnSearch:    _ext.type.search,
1008		oSort:        _ext.type.order,
1009		afnSortData:  _ext.order,
1010		aoFeatures:   _ext.feature,
1011		oStdClasses:  _ext.classes,
1012		oPagination:  _ext.pager
1013	} );
1014	
1015	
1016	$.extend( DataTable.ext.classes, {
1017		container: 'dt-container',
1018		empty: {
1019			row: 'dt-empty'
1020		},
1021		info: {
1022			container: 'dt-info'
1023		},
1024		length: {
1025			container: 'dt-length',
1026			select: 'dt-input'
1027		},
1028		order: {
1029			canAsc: 'dt-orderable-asc',
1030			canDesc: 'dt-orderable-desc',
1031			isAsc: 'dt-ordering-asc',
1032			isDesc: 'dt-ordering-desc',
1033			none: 'dt-orderable-none',
1034			position: 'sorting_'
1035		},
1036		processing: {
1037			container: 'dt-processing'
1038		},
1039		scrolling: {
1040			body: 'dt-scroll-body',
1041			container: 'dt-scroll',
1042			footer: {
1043				self: 'dt-scroll-foot',
1044				inner: 'dt-scroll-footInner'
1045			},
1046			header: {
1047				self: 'dt-scroll-head',
1048				inner: 'dt-scroll-headInner'
1049			}
1050		},
1051		search: {
1052			container: 'dt-search',
1053			input: 'dt-input'
1054		},
1055		table: 'dataTable',	
1056		tbody: {
1057			cell: '',
1058			row: ''
1059		},
1060		thead: {
1061			cell: '',
1062			row: ''
1063		},
1064		tfoot: {
1065			cell: '',
1066			row: ''
1067		},
1068		paging: {
1069			active: 'current',
1070			button: 'dt-paging-button',
1071			container: 'dt-paging',
1072			disabled: 'disabled'
1073		}
1074	} );
1075	
1076	
1077	/*
vendor: 25,146 bytes, lines 1078-1988
1078	 * It is useful to have variables which are scoped locally so only the
1079	 * DataTables functions can access them and they don't leak into global space.
1080	 * At the same time these functions are often useful over multiple files in the
1081	 * core and API, so we list, or at least document, all variables which are used
1082	 * by DataTables as private variables here. This also ensures that there is no
1083	 * clashing of variable names and that they can easily referenced for reuse.
1084	 */
1085	
1086	
1087	// Defined else where
1088	//  _selector_run
1089	//  _selector_opts
1090	//  _selector_row_indexes
1091	
1092	var _ext; // DataTable.ext
1093	var _Api; // DataTable.Api
1094	var _api_register; // DataTable.Api.register
1095	var _api_registerPlural; // DataTable.Api.registerPlural
1096	
1097	var _re_dic = {};
1098	var _re_new_lines = /[\r\n\u2028]/g;
1099	var _re_html = /<([^>]*>)/g;
1100	var _max_str_len = Math.pow(2, 28);
1101	
1102	// This is not strict ISO8601 - Date.parse() is quite lax, although
1103	// implementations differ between browsers.
1104	var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
1105	
1106	// Escape regular expression special characters
1107	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1108	
1109	// https://en.wikipedia.org/wiki/Foreign_exchange_market
1110	// - \u20BD - Russian ruble.
1111	// - \u20a9 - South Korean Won
1112	// - \u20BA - Turkish Lira
1113	// - \u20B9 - Indian Rupee
1114	// - R - Brazil (R$) and South Africa
1115	// - fr - Swiss Franc
1116	// - kr - Swedish krona, Norwegian krone and Danish krone
1117	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1118	// - Ƀ - Bitcoin
1119	// - Ξ - Ethereum
1120	//   standards as thousands separators.
1121	var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1122	
1123	
1124	var _empty = function ( d ) {
1125		return !d || d === true || d === '-' ? true : false;
1126	};
1127	
1128	
1129	var _intVal = function ( s ) {
1130		var integer = parseInt( s, 10 );
1131		return !isNaN(integer) && isFinite(s) ? integer : null;
1132	};
1133	
1134	// Convert from a formatted number with characters other than `.` as the
1135	// decimal place, to a Javascript number
1136	var _numToDecimal = function ( num, decimalPoint ) {
1137		// Cache created regular expressions for speed as this function is called often
1138		if ( ! _re_dic[ decimalPoint ] ) {
1139			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1140		}
1141		return typeof num === 'string' && decimalPoint !== '.' ?
1142			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1143			num;
1144	};
1145	
1146	
1147	var _isNumber = function ( d, decimalPoint, formatted ) {
1148		var type = typeof d;
1149		var strType = type === 'string';
1150	
1151		if ( type === 'number' || type === 'bigint') {
1152			return true;
1153		}
1154	
1155		// If empty return immediately so there must be a number if it is a
1156		// formatted string (this stops the string "k", or "kr", etc being detected
1157		// as a formatted number for currency
1158		if ( _empty( d ) ) {
1159			return true;
1160		}
1161	
1162		if ( decimalPoint && strType ) {
1163			d = _numToDecimal( d, decimalPoint );
1164		}
1165	
1166		if ( formatted && strType ) {
1167			d = d.replace( _re_formatted_numeric, '' );
1168		}
1169	
1170		return !isNaN( parseFloat(d) ) && isFinite( d );
1171	};
1172	
1173	
1174	// A string without HTML in it can be considered to be HTML still
1175	var _isHtml = function ( d ) {
1176		return _empty( d ) || typeof d === 'string';
1177	};
1178	
1179	// Is a string a number surrounded by HTML?
1180	var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1181		if ( _empty( d ) ) {
1182			return true;
1183		}
1184	
1185		// input and select strings mean that this isn't just a number
1186		if (typeof d === 'string' && d.match(/<(input|select)/i)) {
1187			return null;
1188		}
1189	
1190		var html = _isHtml( d );
1191		return ! html ?
1192			null :
1193			_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1194				true :
1195				null;
1196	};
1197	
1198	
1199	var _pluck = function ( a, prop, prop2 ) {
1200		var out = [];
1201		var i=0, ien=a.length;
1202	
1203		// Could have the test in the loop for slightly smaller code, but speed
1204		// is essential here
1205		if ( prop2 !== undefined ) {
1206			for ( ; i<ien ; i++ ) {
1207				if ( a[i] && a[i][ prop ] ) {
1208					out.push( a[i][ prop ][ prop2 ] );
1209				}
1210			}
1211		}
1212		else {
1213			for ( ; i<ien ; i++ ) {
1214				if ( a[i] ) {
1215					out.push( a[i][ prop ] );
1216				}
1217			}
1218		}
1219	
1220		return out;
1221	};
1222	
1223	
1224	// Basically the same as _pluck, but rather than looping over `a` we use `order`
1225	// as the indexes to pick from `a`
1226	var _pluck_order = function ( a, order, prop, prop2 )
1227	{
1228		var out = [];
1229		var i=0, ien=order.length;
1230	
1231		// Could have the test in the loop for slightly smaller code, but speed
1232		// is essential here
1233		if ( prop2 !== undefined ) {
1234			for ( ; i<ien ; i++ ) {
1235				if ( a[ order[i] ][ prop ] ) {
1236					out.push( a[ order[i] ][ prop ][ prop2 ] );
1237				}
1238			}
1239		}
1240		else {
1241			for ( ; i<ien ; i++ ) {
1242				if ( a[ order[i] ] ) {
1243					out.push( a[ order[i] ][ prop ] );
1244				}
1245			}
1246		}
1247	
1248		return out;
1249	};
1250	
1251	
1252	var _range = function ( len, start )
1253	{
1254		var out = [];
1255		var end;
1256	
1257		if ( start === undefined ) {
1258			start = 0;
1259			end = len;
1260		}
1261		else {
1262			end = start;
1263			start = len;
1264		}
1265	
1266		for ( var i=start ; i<end ; i++ ) {
1267			out.push( i );
1268		}
1269	
1270		return out;
1271	};
1272	
1273	
1274	var _removeEmpty = function ( a )
1275	{
1276		var out = [];
1277	
1278		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1279			if ( a[i] ) { // careful - will remove all falsy values!
1280				out.push( a[i] );
1281			}
1282		}
1283	
1284		return out;
1285	};
1286	
1287	// Replaceable function in api.util
1288	var _stripHtml = function (input) {
1289		// Irrelevant check to workaround CodeQL's false positive on the regex
1290		if (input.length > _max_str_len) {
1291			throw new Error('Exceeded max str len');
1292		}
1293	
1294		var previous;
1295	
1296		input = input.replace(_re_html, ''); // Complete tags
1297	
1298		// Safety for incomplete script tag - use do / while to ensure that
1299		// we get all instances
1300		do {
1301			previous = input;
1302			input = input.replace(/<script/i, '');
1303		} while (input !== previous);
1304	
1305		return previous;
1306	};
1307	
1308	// Replaceable function in api.util
1309	var _escapeHtml = function ( d ) {
1310		if (Array.isArray(d)) {
1311			d = d.join(',');
1312		}
1313	
1314		return typeof d === 'string' ?
1315			d
1316				.replace(/&/g, '&amp;')
1317				.replace(/</g, '&lt;')
1318				.replace(/>/g, '&gt;')
1319				.replace(/"/g, '&quot;') :
1320			d;
1321	};
1322	
1323	// Remove diacritics from a string by decomposing it and then removing
1324	// non-ascii characters
1325	var _normalize = function (str, both) {
1326		if (typeof str !== 'string') {
1327			return str;
1328		}
1329	
1330		// It is faster to just run `normalize` than it is to check if
1331		// we need to with a regex!
1332		var res = str.normalize("NFD");
1333	
1334		// Equally, here we check if a regex is needed or not
1335		return res.length !== str.length
1336			? (both === true ? str + ' ' : '' ) + res.replace(/[\u0300-\u036f]/g, "")
1337			: res;
1338	}
1339	
1340	/**
1341	 * Determine if all values in the array are unique. This means we can short
1342	 * cut the _unique method at the cost of a single loop. A sorted array is used
1343	 * to easily check the values.
1344	 *
1345	 * @param  {array} src Source array
1346	 * @return {boolean} true if all unique, false otherwise
1347	 * @ignore
1348	 */
1349	var _areAllUnique = function ( src ) {
1350		if ( src.length < 2 ) {
1351			return true;
1352		}
1353	
1354		var sorted = src.slice().sort();
1355		var last = sorted[0];
1356	
1357		for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1358			if ( sorted[i] === last ) {
1359				return false;
1360			}
1361	
1362			last = sorted[i];
1363		}
1364	
1365		return true;
1366	};
1367	
1368	
1369	/**
1370	 * Find the unique elements in a source array.
1371	 *
1372	 * @param  {array} src Source array
1373	 * @return {array} Array of unique items
1374	 * @ignore
1375	 */
1376	var _unique = function ( src )
1377	{
1378		if (Array.from && Set) {
1379			return Array.from(new Set(src));
1380		}
1381	
1382		if ( _areAllUnique( src ) ) {
1383			return src.slice();
1384		}
1385	
1386		// A faster unique method is to use object keys to identify used values,
1387		// but this doesn't work with arrays or objects, which we must also
1388		// consider. See jsperf.app/compare-array-unique-versions/4 for more
1389		// information.
1390		var
1391			out = [],
1392			val,
1393			i, ien=src.length,
1394			j, k=0;
1395	
1396		again: for ( i=0 ; i<ien ; i++ ) {
1397			val = src[i];
1398	
1399			for ( j=0 ; j<k ; j++ ) {
1400				if ( out[j] === val ) {
1401					continue again;
1402				}
1403			}
1404	
1405			out.push( val );
1406			k++;
1407		}
1408	
1409		return out;
1410	};
1411	
1412	// Surprisingly this is faster than [].concat.apply
1413	// https://jsperf.com/flatten-an-array-loop-vs-reduce/2
1414	var _flatten = function (out, val) {
1415		if (Array.isArray(val)) {
1416			for (var i=0 ; i<val.length ; i++) {
1417				_flatten(out, val[i]);
1418			}
1419		}
1420		else {
1421			out.push(val);
1422		}
1423	
1424		return out;
1425	}
1426	
1427	// Similar to jQuery's addClass, but use classList.add
1428	function _addClass(el, name) {
1429		if (name) {
1430			name.split(' ').forEach(function (n) {
1431				if (n) {
1432					// `add` does deduplication, so no need to check `contains`
1433					el.classList.add(n);
1434				}
1435			});
1436		}
1437	}
1438	
1439	/**
1440	 * DataTables utility methods
1441	 * 
1442	 * This namespace provides helper methods that DataTables uses internally to
1443	 * create a DataTable, but which are not exclusively used only for DataTables.
1444	 * These methods can be used by extension authors to save the duplication of
1445	 * code.
1446	 *
1447	 *  @namespace
1448	 */
1449	DataTable.util = {
1450		/**
1451		 * Return a string with diacritic characters decomposed
1452		 * @param {*} mixed Function or string to normalize
1453		 * @param {*} both Return original string and the normalized string
1454		 * @returns String or undefined
1455		 */
1456		diacritics: function (mixed, both) {
1457			var type = typeof mixed;
1458	
1459			if (type !== 'function') {
1460				return _normalize(mixed, both);
1461			}
1462			_normalize = mixed;
1463		},
1464	
1465		/**
1466		 * Debounce a function
1467		 *
1468		 * @param {function} fn Function to be called
1469		 * @param {integer} freq Call frequency in mS
1470		 * @return {function} Wrapped function
1471		 */
1472		debounce: function ( fn, timeout ) {
1473			var timer;
1474	
1475			return function () {
1476				var that = this;
1477				var args = arguments;
1478	
1479				clearTimeout(timer);
1480	
1481				timer = setTimeout( function () {
1482					fn.apply(that, args);
1483				}, timeout || 250 );
1484			};
1485		},
1486	
1487		/**
1488		 * Throttle the calls to a function. Arguments and context are maintained
1489		 * for the throttled function.
1490		 *
1491		 * @param {function} fn Function to be called
1492		 * @param {integer} freq Call frequency in mS
1493		 * @return {function} Wrapped function
1494		 */
1495		throttle: function ( fn, freq ) {
1496			var
1497				frequency = freq !== undefined ? freq : 200,
1498				last,
1499				timer;
1500	
1501			return function () {
1502				var
1503					that = this,
1504					now  = +new Date(),
1505					args = arguments;
1506	
1507				if ( last && now < last + frequency ) {
1508					clearTimeout( timer );
1509	
1510					timer = setTimeout( function () {
1511						last = undefined;
1512						fn.apply( that, args );
1513					}, frequency );
1514				}
1515				else {
1516					last = now;
1517					fn.apply( that, args );
1518				}
1519			};
1520		},
1521	
1522		/**
1523		 * Escape a string such that it can be used in a regular expression
1524		 *
1525		 *  @param {string} val string to escape
1526		 *  @returns {string} escaped string
1527		 */
1528		escapeRegex: function ( val ) {
1529			return val.replace( _re_escape_regex, '\\$1' );
1530		},
1531	
1532		/**
1533		 * Create a function that will write to a nested object or array
1534		 * @param {*} source JSON notation string
1535		 * @returns Write function
1536		 */
1537		set: function ( source ) {
1538			if ( $.isPlainObject( source ) ) {
1539				/* Unlike get, only the underscore (global) option is used for for
1540				 * setting data since we don't know the type here. This is why an object
1541				 * option is not documented for `mData` (which is read/write), but it is
1542				 * for `mRender` which is read only.
1543				 */
1544				return DataTable.util.set( source._ );
1545			}
1546			else if ( source === null ) {
1547				// Nothing to do when the data source is null
1548				return function () {};
1549			}
1550			else if ( typeof source === 'function' ) {
1551				return function (data, val, meta) {
1552					source( data, 'set', val, meta );
1553				};
1554			}
1555			else if (
1556				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1557				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1558			) {
1559				// Like the get, we need to get data from a nested object
1560				var setData = function (data, val, src) {
1561					var a = _fnSplitObjNotation( src ), b;
1562					var aLast = a[a.length-1];
1563					var arrayNotation, funcNotation, o, innerSrc;
1564		
1565					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {
1566						// Protect against prototype pollution
1567						if (a[i] === '__proto__' || a[i] === 'constructor') {
1568							throw new Error('Cannot set prototype values');
1569						}
1570		
1571						// Check if we are dealing with an array notation request
1572						arrayNotation = a[i].match(__reArray);
1573						funcNotation = a[i].match(__reFn);
1574		
1575						if ( arrayNotation ) {
1576							a[i] = a[i].replace(__reArray, '');
1577							data[ a[i] ] = [];
1578		
1579							// Get the remainder of the nested object to set so we can recurse
1580							b = a.slice();
1581							b.splice( 0, i+1 );
1582							innerSrc = b.join('.');
1583		
1584							// Traverse each entry in the array setting the properties requested
1585							if ( Array.isArray( val ) ) {
1586								for ( var j=0, jLen=val.length ; j<jLen ; j++ ) {
1587									o = {};
1588									setData( o, val[j], innerSrc );
1589									data[ a[i] ].push( o );
1590								}
1591							}
1592							else {
1593								// We've been asked to save data to an array, but it
1594								// isn't array data to be saved. Best that can be done
1595								// is to just save the value.
1596								data[ a[i] ] = val;
1597							}
1598		
1599							// The inner call to setData has already traversed through the remainder
1600							// of the source and has set the data, thus we can exit here
1601							return;
1602						}
1603						else if ( funcNotation ) {
1604							// Function call
1605							a[i] = a[i].replace(__reFn, '');
1606							data = data[ a[i] ]( val );
1607						}
1608		
1609						// If the nested object doesn't currently exist - since we are
1610						// trying to set the value - create it
1611						if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {
1612							data[ a[i] ] = {};
1613						}
1614						data = data[ a[i] ];
1615					}
1616		
1617					// Last item in the input - i.e, the actual set
1618					if ( aLast.match(__reFn ) ) {
1619						// Function call
1620						data = data[ aLast.replace(__reFn, '') ]( val );
1621					}
1622					else {
1623						// If array notation is used, we just want to strip it and use the property name
1624						// and assign the value. If it isn't used, then we get the result we want anyway
1625						data[ aLast.replace(__reArray, '') ] = val;
1626					}
1627				};
1628		
1629				return function (data, val) { // meta is also passed in, but not used
1630					return setData( data, val, source );
1631				};
1632			}
1633			else {
1634				// Array or flat object mapping
1635				return function (data, val) { // meta is also passed in, but not used
1636					data[source] = val;
1637				};
1638			}
1639		},
1640	
1641		/**
1642		 * Create a function that will read nested objects from arrays, based on JSON notation
1643		 * @param {*} source JSON notation string
1644		 * @returns Value read
1645		 */
1646		get: function ( source ) {
1647			if ( $.isPlainObject( source ) ) {
1648				// Build an object of get functions, and wrap them in a single call
1649				var o = {};
1650				$.each( source, function (key, val) {
1651					if ( val ) {
1652						o[key] = DataTable.util.get( val );
1653					}
1654				} );
1655		
1656				return function (data, type, row, meta) {
1657					var t = o[type] || o._;
1658					return t !== undefined ?
1659						t(data, type, row, meta) :
1660						data;
1661				};
1662			}
1663			else if ( source === null ) {
1664				// Give an empty string for rendering / sorting etc
1665				return function (data) { // type, row and meta also passed, but not used
1666					return data;
1667				};
1668			}
1669			else if ( typeof source === 'function' ) {
1670				return function (data, type, row, meta) {
1671					return source( data, type, row, meta );
1672				};
1673			}
1674			else if (
1675				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1676				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1677			) {
1678				/* If there is a . in the source string then the data source is in a
1679				 * nested object so we loop over the data for each level to get the next
1680				 * level down. On each loop we test for undefined, and if found immediately
1681				 * return. This allows entire objects to be missing and sDefaultContent to
1682				 * be used if defined, rather than throwing an error
1683				 */
1684				var fetchData = function (data, type, src) {
1685					var arrayNotation, funcNotation, out, innerSrc;
1686		
1687					if ( src !== "" ) {
1688						var a = _fnSplitObjNotation( src );
1689		
1690						for ( var i=0, iLen=a.length ; i<iLen ; i++ ) {
1691							// Check if we are dealing with special notation
1692							arrayNotation = a[i].match(__reArray);
1693							funcNotation = a[i].match(__reFn);
1694		
1695							if ( arrayNotation ) {
1696								// Array notation
1697								a[i] = a[i].replace(__reArray, '');
1698		
1699								// Condition allows simply [] to be passed in
1700								if ( a[i] !== "" ) {
1701									data = data[ a[i] ];
1702								}
1703								out = [];
1704		
1705								// Get the remainder of the nested object to get
1706								a.splice( 0, i+1 );
1707								innerSrc = a.join('.');
1708		
1709								// Traverse each entry in the array getting the properties requested
1710								if ( Array.isArray( data ) ) {
1711									for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1712										out.push( fetchData( data[j], type, innerSrc ) );
1713									}
1714								}
1715		
1716								// If a string is given in between the array notation indicators, that
1717								// is used to join the strings together, otherwise an array is returned
1718								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1719								data = (join==="") ? out : out.join(join);
1720		
1721								// The inner call to fetchData has already traversed through the remainder
1722								// of the source requested, so we exit from the loop
1723								break;
1724							}
1725							else if ( funcNotation ) {
1726								// Function call
1727								a[i] = a[i].replace(__reFn, '');
1728								data = data[ a[i] ]();
1729								continue;
1730							}
1731		
1732							if (data === null || data[ a[i] ] === null) {
1733								return null;
1734							}
1735							else if ( data === undefined || data[ a[i] ] === undefined ) {
1736								return undefined;
1737							}
1738	
1739							data = data[ a[i] ];
1740						}
1741					}
1742		
1743					return data;
1744				};
1745		
1746				return function (data, type) { // row and meta also passed, but not used
1747					return fetchData( data, type, source );
1748				};
1749			}
1750			else {
1751				// Array or flat object mapping
1752				return function (data) { // row and meta also passed, but not used
1753					return data[source];
1754				};
1755			}
1756		},
1757	
1758		stripHtml: function (mixed) {
1759			var type = typeof mixed;
1760	
1761			if (type === 'function') {
1762				_stripHtml = mixed;
1763				return;
1764			}
1765			else if (type === 'string') {
1766				return _stripHtml(mixed);
1767			}
1768			return mixed;
1769		},
1770	
1771		escapeHtml: function (mixed) {
1772			var type = typeof mixed;
1773	
1774			if (type === 'function') {
1775				_escapeHtml = mixed;
1776				return;
1777			}
1778			else if (type === 'string' || Array.isArray(mixed)) {
1779				return _escapeHtml(mixed);
1780			}
1781			return mixed;
1782		},
1783	
1784		unique: _unique
1785	};
1786	
1787	
1788	
1789	/**
1790	 * Create a mapping object that allows camel case parameters to be looked up
1791	 * for their Hungarian counterparts. The mapping is stored in a private
1792	 * parameter called `_hungarianMap` which can be accessed on the source object.
1793	 *  @param {object} o
1794	 *  @memberof DataTable#oApi
1795	 */
1796	function _fnHungarianMap ( o )
1797	{
1798		var
1799			hungarian = 'a aa ai ao as b fn i m o s ',
1800			match,
1801			newKey,
1802			map = {};
1803	
1804		$.each( o, function (key) {
1805			match = key.match(/^([^A-Z]+?)([A-Z])/);
1806	
1807			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1808			{
1809				newKey = key.replace( match[0], match[2].toLowerCase() );
1810				map[ newKey ] = key;
1811	
1812				if ( match[1] === 'o' )
1813				{
1814					_fnHungarianMap( o[key] );
1815				}
1816			}
1817		} );
1818	
1819		o._hungarianMap = map;
1820	}
1821	
1822	
1823	/**
1824	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1825	 * created by _fnHungarianMap.
1826	 *  @param {object} src The model object which holds all parameters that can be
1827	 *    mapped.
1828	 *  @param {object} user The object to convert from camel case to Hungarian.
1829	 *  @param {boolean} force When set to `true`, properties which already have a
1830	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
1831	 *    won't be.
1832	 *  @memberof DataTable#oApi
1833	 */
1834	function _fnCamelToHungarian ( src, user, force )
1835	{
1836		if ( ! src._hungarianMap ) {
1837			_fnHungarianMap( src );
1838		}
1839	
1840		var hungarianKey;
1841	
1842		$.each( user, function (key) {
1843			hungarianKey = src._hungarianMap[ key ];
1844	
1845			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1846			{
1847				// For objects, we need to buzz down into the object to copy parameters
1848				if ( hungarianKey.charAt(0) === 'o' )
1849				{
1850					// Copy the camelCase options over to the hungarian
1851					if ( ! user[ hungarianKey ] ) {
1852						user[ hungarianKey ] = {};
1853					}
1854					$.extend( true, user[hungarianKey], user[key] );
1855	
1856					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1857				}
1858				else {
1859					user[hungarianKey] = user[ key ];
1860				}
1861			}
1862		} );
1863	}
1864	
1865	/**
1866	 * Map one parameter onto another
1867	 *  @param {object} o Object to map
1868	 *  @param {*} knew The new parameter name
1869	 *  @param {*} old The old parameter name
1870	 */
1871	var _fnCompatMap = function ( o, knew, old ) {
1872		if ( o[ knew ] !== undefined ) {
1873			o[ old ] = o[ knew ];
1874		}
1875	};
1876	
1877	
1878	/**
1879	 * Provide backwards compatibility for the main DT options. Note that the new
1880	 * options are mapped onto the old parameters, so this is an external interface
1881	 * change only.
1882	 *  @param {object} init Object to map
1883	 */
1884	function _fnCompatOpts ( init )
1885	{
1886		_fnCompatMap( init, 'ordering',      'bSort' );
1887		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
1888		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
1889		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1890		_fnCompatMap( init, 'order',         'aaSorting' );
1891		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
1892		_fnCompatMap( init, 'paging',        'bPaginate' );
1893		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
1894		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
1895		_fnCompatMap( init, 'searching',     'bFilter' );
1896	
1897		// Boolean initialisation of x-scrolling
1898		if ( typeof init.sScrollX === 'boolean' ) {
1899			init.sScrollX = init.sScrollX ? '100%' : '';
1900		}
1901		if ( typeof init.scrollX === 'boolean' ) {
1902			init.scrollX = init.scrollX ? '100%' : '';
1903		}
1904	
1905		// Column search objects are in an array, so it needs to be converted
1906		// element by element
1907		var searchCols = init.aoSearchCols;
1908	
1909		if ( searchCols ) {
1910			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1911				if ( searchCols[i] ) {
1912					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1913				}
1914			}
1915		}
1916	
1917		// Enable search delay if server-side processing is enabled
1918		if (init.serverSide && ! init.searchDelay) {
1919			init.searchDelay = 400;
1920		}
1921	}
1922	
1923	
1924	/**
1925	 * Provide backwards compatibility for column options. Note that the new options
1926	 * are mapped onto the old parameters, so this is an external interface change
1927	 * only.
1928	 *  @param {object} init Object to map
1929	 */
1930	function _fnCompatCols ( init )
1931	{
1932		_fnCompatMap( init, 'orderable',     'bSortable' );
1933		_fnCompatMap( init, 'orderData',     'aDataSort' );
1934		_fnCompatMap( init, 'orderSequence', 'asSorting' );
1935		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
1936	
1937		// orderData can be given as an integer
1938		var dataSort = init.aDataSort;
1939		if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {
1940			init.aDataSort = [ dataSort ];
1941		}
1942	}
1943	
1944	
1945	/**
1946	 * Browser feature detection for capabilities, quirks
1947	 *  @param {object} settings dataTables settings object
1948	 *  @memberof DataTable#oApi
1949	 */
1950	function _fnBrowserDetect( settings )
1951	{
1952		// We don't need to do this every time DataTables is constructed, the values
1953		// calculated are specific to the browser and OS configuration which we
1954		// don't expect to change between initialisations
1955		if ( ! DataTable.__browser ) {
1956			var browser = {};
1957			DataTable.__browser = browser;
1958	
1959			// Scrolling feature / quirks detection
1960			var n = $('<div/>')
1961				.css( {
1962					position: 'fixed',
1963					top: 0,
1964					left: -1 * window.pageXOffset, // allow for scrolling
1965					height: 1,
1966					width: 1,
1967					overflow: 'hidden'
1968				} )
1969				.append(
1970					$('<div/>')
1971						.css( {
1972							position: 'absolute',
1973							top: 1,
1974							left: 1,
1975							width: 100,
1976							overflow: 'scroll'
1977						} )
1978						.append(
1979							$('<div/>')
1980								.css( {
1981									width: '100%',
1982									height: 10
1983								} )
1984						)
1985				)
1986				.appendTo( 'body' );
1987	
1988			var outer = n.children();
1989			var inner = outer.children();
1990	
1991			// Get scrollbar width
1992			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1993	
1994			// In rtl text layout, some browsers (most, but not all) will place the
1995			// scrollbar on the left, rather than the right.
1996			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1997	
1998			n.remove();
1999		}
2000	
2001		$.extend( settings.oBrowser, DataTable.__browser );
2002		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
2003	}
2004	
2005	/**
2006	 * Add a column to the list used for the table with default values
2007	 *  @param {object} oSettings dataTables settings object
2008	 *  @memberof DataTable#oApi
2009	 */
2010	function _fnAddColumn( oSettings )
2011	{
2012		// Add column to aoColumns array
2013		var oDefaults = DataTable.defaults.column;
2014		var iCol = oSettings.aoColumns.length;
2015		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
2016			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
2017			"mData": oDefaults.mData ? oDefaults.mData : iCol,
2018			idx: iCol,
2019			searchFixed: {},
2020			colEl: $('<col>').attr('data-dt-column', iCol)
2021		} );
2022		oSettings.aoColumns.push( oCol );
2023	
2024		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
2025		// passed into extend can be undefined. This allows the user to give a default
2026		// with only some of the parameters defined, and also not give a default
2027		var searchCols = oSettings.aoPreSearchCols;
2028		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
2029	}
2030	
2031	
2032	/**
2033	 * Apply options for a column
2034	 *  @param {object} oSettings dataTables settings object
2035	 *  @param {int} iCol column index to consider
2036	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
2037	 *  @memberof DataTable#oApi
2038	 */
2039	function _fnColumnOptions( oSettings, iCol, oOptions )
2040	{
2041		var oCol = oSettings.aoColumns[ iCol ];
2042	
2043		/* User specified column options */
2044		if ( oOptions !== undefined && oOptions !== null )
2045		{
2046			// Backwards compatibility
2047			_fnCompatCols( oOptions );
2048	
2049			// Map camel case parameters to their Hungarian counterparts
2050			_fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
2051	
2052			/* Backwards compatibility for mDataProp */
2053			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2054			{
2055				oOptions.mData = oOptions.mDataProp;
2056			}
2057	
2058			if ( oOptions.sType )
2059			{
2060				oCol._sManualType = oOptions.sType;
2061			}
2062		
2063			// `class` is a reserved word in Javascript, so we need to provide
2064			// the ability to use a valid name for the camel case input
2065			if ( oOptions.className && ! oOptions.sClass )
2066			{
2067				oOptions.sClass = oOptions.className;
2068			}
2069	
2070			var origClass = oCol.sClass;
2071	
2072			$.extend( oCol, oOptions );
2073			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2074	
2075			// Merge class from previously defined classes with this one, rather than just
2076			// overwriting it in the extend above
2077			if (origClass !== oCol.sClass) {
2078				oCol.sClass = origClass + ' ' + oCol.sClass;
2079			}
2080	
2081			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
2082			 * priority if defined
2083			 */
2084			if ( oOptions.iDataSort !== undefined )
2085			{
2086				oCol.aDataSort = [ oOptions.iDataSort ];
2087			}
2088			_fnMap( oCol, oOptions, "aDataSort" );
2089		}
2090	
2091		/* Cache the data get and set functions for speed */
2092		var mDataSrc = oCol.mData;
2093		var mData = _fnGetObjectDataFn( mDataSrc );
2094	
2095		// The `render` option can be given as an array to access the helper rendering methods.
2096		// The first element is the rendering method to use, the rest are the parameters to pass
2097		if ( oCol.mRender && Array.isArray( oCol.mRender ) ) {
2098			var copy = oCol.mRender.slice();
2099			var name = copy.shift();
2100	
2101			oCol.mRender = DataTable.render[name].apply(window, copy);
2102		}
2103	
2104		oCol._render = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2105	
2106		var attrTest = function( src ) {
2107			return typeof src === 'string' && src.indexOf('@') !== -1;
2108		};
2109		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2110			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2111		);
2112		oCol._setter = null;
2113	
2114		oCol.fnGetData = function (rowData, type, meta) {
2115			var innerData = mData( rowData, type, undefined, meta );
2116	
2117			return oCol._render && type ?
2118				oCol._render( innerData, type, rowData, meta ) :
2119				innerData;
2120		};
2121		oCol.fnSetData = function ( rowData, val, meta ) {
2122			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2123		};
2124	
2125		// Indicate if DataTables should read DOM data as an object or array
2126		// Used in _fnGetRowElements
2127		if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) {
2128			oSettings._rowReadObject = true;
2129		}
2130	
2131		/* Feature sorting overrides column specific when off */
2132		if ( !oSettings.oFeatures.bSort )
2133		{
2134			oCol.bSortable = false;
2135		}
2136	}
2137	
2138	
2139	/**
2140	 * Adjust the table column widths for new data. Note: you would probably want to
2141	 * do a redraw after calling this function!
2142	 *  @param {object} settings dataTables settings object
2143	 *  @memberof DataTable#oApi
2144	 */
2145	function _fnAdjustColumnSizing ( settings )
2146	{
2147		_fnCalculateColumnWidths( settings );
2148		_fnColumnSizes( settings );
2149	
2150		var scroll = settings.oScroll;
2151		if ( scroll.sY !== '' || scroll.sX !== '') {
2152			_fnScrollDraw( settings );
2153		}
2154	
2155		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
2156	}
2157	
2158	/**
2159	 * Apply column sizes
2160	 *
2161	 * @param {*} settings DataTables settings object
2162	 */
2163	function _fnColumnSizes ( settings )
2164	{
2165		var cols = settings.aoColumns;
2166	
2167		for (var i=0 ; i<cols.length ; i++) {
2168			var width = _fnColumnsSumWidth(settings, [i], false, false);
2169	
2170			cols[i].colEl.css('width', width);
2171		}
2172	}
2173	
2174	
2175	/**
2176	 * Convert the index of a visible column to the index in the data array (take account
2177	 * of hidden columns)
2178	 *  @param {object} oSettings dataTables settings object
2179	 *  @param {int} iMatch Visible column index to lookup
2180	 *  @returns {int} i the data index
2181	 *  @memberof DataTable#oApi
2182	 */
2183	function _fnVisibleToColumnIndex( oSettings, iMatch )
2184	{
2185		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2186	
2187		return typeof aiVis[iMatch] === 'number' ?
2188			aiVis[iMatch] :
2189			null;
2190	}
2191	
2192	
2193	/**
2194	 * Convert the index of an index in the data array and convert it to the visible
2195	 *   column index (take account of hidden columns)
2196	 *  @param {int} iMatch Column index to lookup
2197	 *  @param {object} oSettings dataTables settings object
2198	 *  @returns {int} i the data index
2199	 *  @memberof DataTable#oApi
2200	 */
2201	function _fnColumnIndexToVisible( oSettings, iMatch )
2202	{
2203		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2204		var iPos = aiVis.indexOf(iMatch);
2205	
2206		return iPos !== -1 ? iPos : null;
2207	}
2208	
2209	
2210	/**
2211	 * Get the number of visible columns
2212	 *  @param {object} oSettings dataTables settings object
2213	 *  @returns {int} i the number of visible columns
2214	 *  @memberof DataTable#oApi
2215	 */
2216	function _fnVisbleColumns( settings )
2217	{
2218		var layout = settings.aoHeader;
2219		var columns = settings.aoColumns;
2220		var vis = 0;
2221	
2222		if ( layout.length ) {
2223			for ( var i=0, ien=layout[0].length ; i<ien ; i++ ) {
2224				if ( columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none' ) {
2225					vis++;
2226				}
2227			}
2228		}
2229	
2230		return vis;
2231	}
2232	
2233	
2234	/**
2235	 * Get an array of column indexes that match a given property
2236	 *  @param {object} oSettings dataTables settings object
2237	 *  @param {string} sParam Parameter in aoColumns to look for - typically
2238	 *    bVisible or bSearchable
2239	 *  @returns {array} Array of indexes with matched properties
2240	 *  @memberof DataTable#oApi
2241	 */
2242	function _fnGetColumns( oSettings, sParam )
2243	{
2244		var a = [];
2245	
2246		oSettings.aoColumns.map( function(val, i) {
2247			if ( val[sParam] ) {
2248				a.push( i );
2249			}
2250		} );
2251	
2252		return a;
2253	}
2254	
2255	
2256	/**
2257	 * Calculate the 'type' of a column
2258	 *  @param {object} settings dataTables settings object
2259	 *  @memberof DataTable#oApi
2260	 */
2261	function _fnColumnTypes ( settings )
2262	{
2263		var columns = settings.aoColumns;
2264		var data = settings.aoData;
2265		var types = DataTable.ext.type.detect;
2266		var i, ien, j, jen, k, ken;
2267		var col, detectedType, cache;
2268	
2269		// For each column, spin over the 
2270		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2271			col = columns[i];
2272			cache = [];
2273	
2274			if ( ! col.sType && col._sManualType ) {
2275				col.sType = col._sManualType;
2276			}
2277			else if ( ! col.sType ) {
2278				for ( j=0, jen=types.length ; j<jen ; j++ ) {
2279					for ( k=0, ken=data.length ; k<ken ; k++ ) {
2280	
2281						if (! data[k]) {
2282							continue;
2283						}
2284	
2285						// Use a cache array so we only need to get the type data
2286						// from the formatter once (when using multiple detectors)
2287						if ( cache[k] === undefined ) {
2288							cache[k] = _fnGetCellData( settings, k, i, 'type' );
2289						}
2290	
2291						detectedType = types[j]( cache[k], settings );
2292	
2293						// If null, then this type can't apply to this column, so
2294						// rather than testing all cells, break out. There is an
2295						// exception for the last type which is `html`. We need to
2296						// scan all rows since it is possible to mix string and HTML
2297						// types
2298						if ( ! detectedType && j !== types.length-2 ) {
2299							break;
2300						}
2301	
2302						// Only a single match is needed for html type since it is
2303						// bottom of the pile and very similar to string - but it
2304						// must not be empty
2305						if ( detectedType === 'html' && ! _empty(cache[k]) ) {
2306							break;
2307						}
2308					}
2309	
2310					// Type is valid for all data points in the column - use this
2311					// type
2312					if ( detectedType ) {
2313						col.sType = detectedType;
2314						break;
2315					}
2316				}
2317	
2318				// Fall back - if no type was detected, always use string
2319				if ( ! col.sType ) {
2320					col.sType = 'string';
2321				}
2322			}
2323	
2324			// Set class names for header / footer for auto type classes
2325			var autoClass = _ext.type.className[col.sType];
2326	
2327			if (autoClass) {
2328				_columnAutoClass(settings.aoHeader, i, autoClass);
2329				_columnAutoClass(settings.aoFooter, i, autoClass);
2330			}
2331	
2332			var renderer = _ext.type.render[col.sType];
2333	
2334			// This can only happen once! There is no way to remover
2335			// a renderer. After the first time the renderer has
2336			// already been set so createTr will run the renderer itself.
2337			if (renderer && ! col._render) {
2338				col._render = DataTable.util.get(renderer);
2339	
2340				_columnAutoRender(settings, i);
2341			}
2342		}
2343	}
2344	
2345	/**
2346	 * Apply an auto detected renderer to data which doesn't yet have
2347	 * a renderer
2348	 */
2349	function _columnAutoRender(settings, colIdx) {
2350		var data = settings.aoData;
2351	
2352		for (var i=0 ; i<data.length ; i++) {
2353			if (data[i].nTr) {
2354				// We have to update the display here since there is no
2355				// invalidation check for the data
2356				var display = _fnGetCellData( settings, i, colIdx, 'display' );
2357	
2358				data[i].displayData[colIdx] = display;
2359				_fnWriteCell(data[i].anCells[colIdx], display);
2360	
2361				// No need to update sort / filter data since it has
2362				// been invalidated and will be re-read with the
2363				// renderer now applied
2364			}
2365		}
2366	}
2367	
2368	/**
2369	 * Apply a class name to a column's header cells
2370	 */
2371	function _columnAutoClass(container, colIdx, className) {
2372		container.forEach(function (row) {
2373			if (row[colIdx] && row[colIdx].unique) {
2374				_addClass(row[colIdx].cell, className);
2375			}
2376		});
2377	}
2378	
2379	/**
2380	 * Take the column definitions and static columns arrays and calculate how
2381	 * they relate to column indexes. The callback function will then apply the
2382	 * definition found for a column to a suitable configuration object.
2383	 *  @param {object} oSettings dataTables settings object
2384	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
2385	 *  @param {array} aoCols The aoColumns array that defines columns individually
2386	 *  @param {array} headerLayout Layout for header as it was loaded
2387	 *  @param {function} fn Callback function - takes two parameters, the calculated
2388	 *    column index and the definition for that column.
2389	 *  @memberof DataTable#oApi
2390	 */
2391	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, headerLayout, fn )
2392	{
2393		var i, iLen, j, jLen, k, kLen, def;
2394		var columns = oSettings.aoColumns;
2395	
2396		if ( aoCols ) {
2397			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2398				if (aoCols[i] && aoCols[i].name) {
2399					columns[i].sName = aoCols[i].name;
2400				}
2401			}
2402		}
2403	
2404		// Column definitions with aTargets
2405		if ( aoColDefs )
2406		{
2407			/* Loop over the definitions array - loop in reverse so first instance has priority */
2408			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2409			{
2410				def = aoColDefs[i];
2411	
2412				/* Each definition can target multiple columns, as it is an array */
2413				var aTargets = def.target !== undefined
2414					? def.target
2415					: def.targets !== undefined
2416						? def.targets
2417						: def.aTargets;
2418	
2419				if ( ! Array.isArray( aTargets ) )
2420				{
2421					aTargets = [ aTargets ];
2422				}
2423	
2424				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2425				{
2426					var target = aTargets[j];
2427	
2428					if ( typeof target === 'number' && target >= 0 )
2429					{
2430						/* Add columns that we don't yet know about */
2431						while( columns.length <= target )
2432						{
2433							_fnAddColumn( oSettings );
2434						}
2435	
2436						/* Integer, basic index */
2437						fn( target, def );
2438					}
2439					else if ( typeof target === 'number' && target < 0 )
2440					{
2441						/* Negative integer, right to left column counting */
2442						fn( columns.length+target, def );
2443					}
2444					else if ( typeof target === 'string' )
2445					{
2446						for ( k=0, kLen=columns.length ; k<kLen ; k++ ) {
2447							if (target === '_all') {
2448								// Apply to all columns
2449								fn( k, def );
2450							}
2451							else if (target.indexOf(':name') !== -1) {
2452								// Column selector
2453								if (columns[k].sName === target.replace(':name', '')) {
2454									fn( k, def );
2455								}
2456							}
2457							else {
2458								// Cell selector
2459								headerLayout.forEach(function (row) {
2460									if (row[k]) {
2461										var cell = $(row[k].cell);
2462	
2463										// Legacy support. Note that it means that we don't support
2464										// an element name selector only, since they are treated as
2465										// class names for 1.x compat.
2466										if (target.match(/^[a-z][\w-]*$/i)) {
2467											target = '.' + target;
2468										}
2469	
2470										if (cell.is( target )) {
2471											fn( k, def );
2472										}
2473									}
2474								});
2475							}
2476						}
2477					}
2478				}
2479			}
2480		}
2481	
2482		// Statically defined columns array
2483		if ( aoCols ) {
2484			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2485				fn( i, aoCols[i] );
2486			}
2487		}
2488	}
2489	
2490	
2491	/**
2492	 * Get the width for a given set of columns
2493	 *
2494	 * @param {*} settings DataTables settings object
2495	 * @param {*} targets Columns - comma separated string or array of numbers
2496	 * @param {*} original Use the original width (true) or calculated (false)
2497	 * @param {*} incVisible Include visible columns (true) or not (false)
2498	 * @returns Combined CSS value
2499	 */
2500	function _fnColumnsSumWidth( settings, targets, original, incVisible ) {
2501		if ( ! Array.isArray( targets ) ) {
2502			targets = _fnColumnsFromHeader( targets );
2503		}
2504	
2505		var sum = 0;
2506		var unit;
2507		var columns = settings.aoColumns;
2508		
2509		for ( var i=0, ien=targets.length ; i<ien ; i++ ) {
2510			var column = columns[ targets[i] ];
2511			var definedWidth = original ?
2512				column.sWidthOrig :
2513				column.sWidth;
2514	
2515			if ( ! incVisible && column.bVisible === false ) {
2516				continue;
2517			}
2518	
2519			if ( definedWidth === null || definedWidth === undefined ) {
2520				return null; // can't determine a defined width - browser defined
2521			}
2522			else if ( typeof definedWidth === 'number' ) {
2523				unit = 'px';
2524				sum += definedWidth;
2525			}
2526			else {
2527				var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
2528	
2529				if ( matched ) {
2530					sum += matched[1] * 1;
2531					unit = matched.length === 3 ?
2532						matched[2] :
2533						'px';
2534				}
2535			}
2536		}
2537	
2538		return sum + unit;
2539	}
2540	
2541	function _fnColumnsFromHeader( cell )
2542	{
2543		var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
2544	
2545		if ( ! attr ) {
2546			return [];
2547		}
2548	
2549		return attr.split(',').map( function (val) {
2550			return val * 1;
2551		} );
2552	}
2553	/**
2554	 * Add a data array to the table, creating DOM node etc. This is the parallel to
2555	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2556	 * DOM source.
2557	 *  @param {object} settings dataTables settings object
2558	 *  @param {array} data data array to be added
2559	 *  @param {node} [tr] TR element to add to the table - optional. If not given,
2560	 *    DataTables will create a row automatically
2561	 *  @param {array} [tds] Array of TD|TH elements for the row - must be given
2562	 *    if nTr is.
2563	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2564	 *  @memberof DataTable#oApi
2565	 */
2566	function _fnAddData ( settings, dataIn, tr, tds )
2567	{
2568		/* Create the object for storing information about this new row */
2569		var rowIdx = settings.aoData.length;
2570		var rowModel = $.extend( true, {}, DataTable.models.oRow, {
2571			src: tr ? 'dom' : 'data',
2572			idx: rowIdx
2573		} );
2574	
2575		rowModel._aData = dataIn;
2576		settings.aoData.push( rowModel );
2577	
2578		var columns = settings.aoColumns;
2579	
2580		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2581		{
2582			// Invalidate the column types as the new data needs to be revalidated
2583			columns[i].sType = null;
2584		}
2585	
2586		/* Add to the display array */
2587		settings.aiDisplayMaster.push( rowIdx );
2588	
2589		var id = settings.rowIdFn( dataIn );
2590		if ( id !== undefined ) {
2591			settings.aIds[ id ] = rowModel;
2592		}
2593	
2594		/* Create the DOM information, or register it if already present */
2595		if ( tr || ! settings.oFeatures.bDeferRender )
2596		{
2597			_fnCreateTr( settings, rowIdx, tr, tds );
2598		}
2599	
2600		return rowIdx;
2601	}
2602	
2603	
2604	/**
2605	 * Add one or more TR elements to the table. Generally we'd expect to
2606	 * use this for reading data from a DOM sourced table, but it could be
2607	 * used for an TR element. Note that if a TR is given, it is used (i.e.
2608	 * it is not cloned).
2609	 *  @param {object} settings dataTables settings object
2610	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
2611	 *  @returns {array} Array of indexes for the added rows
2612	 *  @memberof DataTable#oApi
2613	 */
2614	function _fnAddTr( settings, trs )
2615	{
2616		var row;
2617	
2618		// Allow an individual node to be passed in
2619		if ( ! (trs instanceof $) ) {
2620			trs = $(trs);
2621		}
2622	
2623		return trs.map( function (i, el) {
2624			row = _fnGetRowElements( settings, el );
2625			return _fnAddData( settings, row.data, el, row.cells );
2626		} );
2627	}
2628	
2629	
2630	/**
2631	 * Get the data for a given cell from the internal cache, taking into account data mapping
2632	 *  @param {object} settings dataTables settings object
2633	 *  @param {int} rowIdx aoData row id
2634	 *  @param {int} colIdx Column index
2635	 *  @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
2636	 *  @returns {*} Cell data
2637	 *  @memberof DataTable#oApi
2638	 */
2639	function _fnGetCellData( settings, rowIdx, colIdx, type )
2640	{
2641		if (type === 'search') {
2642			type = 'filter';
2643		}
2644		else if (type === 'order') {
2645			type = 'sort';
2646		}
2647	
2648		var row = settings.aoData[rowIdx];
2649	
2650		if (! row) {
2651			return undefined;
2652		}
2653	
2654		var draw           = settings.iDraw;
2655		var col            = settings.aoColumns[colIdx];
2656		var rowData        = row._aData;
2657		var defaultContent = col.sDefaultContent;
2658		var cellData       = col.fnGetData( rowData, type, {
2659			settings: settings,
2660			row:      rowIdx,
2661			col:      colIdx
2662		} );
2663	
2664		// Allow for a node being returned for non-display types
2665		if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
2666			cellData = cellData.innerHTML;
2667		}
2668	
2669		if ( cellData === undefined ) {
2670			if ( settings.iDrawError != draw && defaultContent === null ) {
2671				_fnLog( settings, 0, "Requested unknown parameter "+
2672					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2673					" for row "+rowIdx+", column "+colIdx, 4 );
2674				settings.iDrawError = draw;
2675			}
2676			return defaultContent;
2677		}
2678	
2679		// When the data source is null and a specific data type is requested (i.e.
2680		// not the original data), we can use default column data
2681		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2682			cellData = defaultContent;
2683		}
2684		else if ( typeof cellData === 'function' ) {
2685			// If the data source is a function, then we run it and use the return,
2686			// executing in the scope of the data object (for instances)
2687			return cellData.call( rowData );
2688		}
2689	
2690		if ( cellData === null && type === 'display' ) {
2691			return '';
2692		}
2693	
2694		if ( type === 'filter' ) {
2695			var fomatters = DataTable.ext.type.search;
2696	
2697			if ( fomatters[ col.sType ] ) {
2698				cellData = fomatters[ col.sType ]( cellData );
2699			}
2700		}
2701	
2702		return cellData;
2703	}
2704	
2705	
2706	/**
2707	 * Set the value for a specific cell, into the internal data cache
2708	 *  @param {object} settings dataTables settings object
2709	 *  @param {int} rowIdx aoData row id
2710	 *  @param {int} colIdx Column index
2711	 *  @param {*} val Value to set
2712	 *  @memberof DataTable#oApi
2713	 */
2714	function _fnSetCellData( settings, rowIdx, colIdx, val )
2715	{
2716		var col     = settings.aoColumns[colIdx];
2717		var rowData = settings.aoData[rowIdx]._aData;
2718	
2719		col.fnSetData( rowData, val, {
2720			settings: settings,
2721			row:      rowIdx,
2722			col:      colIdx
2723		}  );
2724	}
2725	
2726	/**
2727	 * Write a value to a cell
2728	 * @param {*} td Cell
2729	 * @param {*} val Value
2730	 */
2731	function _fnWriteCell(td, val)
2732	{
2733		if (val && typeof val === 'object' && val.nodeName) {
2734			$(td)
2735				.empty()
2736				.append(val);
2737		}
2738		else {
2739			td.innerHTML = val;
2740		}
2741	}
2742	
2743	
2744	// Private variable that is used to match action syntax in the data property object
2745	var __reArray = /\[.*?\]$/;
2746	var __reFn = /\(\)$/;
2747	
2748	/**
2749	 * Split string on periods, taking into account escaped periods
2750	 * @param  {string} str String to split
2751	 * @return {array} Split string
2752	 */
2753	function _fnSplitObjNotation( str )
2754	{
2755		var parts = str.match(/(\\.|[^.])+/g) || [''];
2756	
2757		return parts.map( function ( s ) {
2758			return s.replace(/\\\./g, '.');
2759		} );
2760	}
2761	
2762	
2763	/**
2764	 * Return a function that can be used to get data from a source object, taking
2765	 * into account the ability to use nested objects as a source
2766	 *  @param {string|int|function} mSource The data source for the object
2767	 *  @returns {function} Data get function
2768	 *  @memberof DataTable#oApi
2769	 */
2770	var _fnGetObjectDataFn = DataTable.util.get;
2771	
2772	
2773	/**
2774	 * Return a function that can be used to set data from a source object, taking
2775	 * into account the ability to use nested objects as a source
2776	 *  @param {string|int|function} mSource The data source for the object
2777	 *  @returns {function} Data set function
2778	 *  @memberof DataTable#oApi
2779	 */
2780	var _fnSetObjectDataFn = DataTable.util.set;
2781	
2782	
2783	/**
2784	 * Return an array with the full table data
2785	 *  @param {object} oSettings dataTables settings object
2786	 *  @returns array {array} aData Master data array
2787	 *  @memberof DataTable#oApi
2788	 */
2789	function _fnGetDataMaster ( settings )
2790	{
2791		return _pluck( settings.aoData, '_aData' );
2792	}
2793	
2794	
2795	/**
2796	 * Nuke the table
2797	 *  @param {object} oSettings dataTables settings object
2798	 *  @memberof DataTable#oApi
2799	 */
2800	function _fnClearTable( settings )
2801	{
2802		settings.aoData.length = 0;
2803		settings.aiDisplayMaster.length = 0;
2804		settings.aiDisplay.length = 0;
2805		settings.aIds = {};
2806	}
2807	
2808	
2809	/**
2810	 * Mark cached data as invalid such that a re-read of the data will occur when
2811	 * the cached data is next requested. Also update from the data source object.
2812	 *
2813	 * @param {object} settings DataTables settings object
2814	 * @param {int}    rowIdx   Row index to invalidate
2815	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
2816	 *     or 'data'
2817	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
2818	 *     row will be invalidated
2819	 * @memberof DataTable#oApi
2820	 *
2821	 * @todo For the modularisation of v1.11 this will need to become a callback, so
2822	 *   the sort and filter methods can subscribe to it. That will required
2823	 *   initialisation options for sorting, which is why it is not already baked in
2824	 */
2825	function _fnInvalidate( settings, rowIdx, src, colIdx )
2826	{
2827		var row = settings.aoData[ rowIdx ];
2828		var i, ien;
2829	
2830		// Remove the cached data for the row
2831		row._aSortData = null;
2832		row._aFilterData = null;
2833		row.displayData = null;
2834	
2835		// Are we reading last data from DOM or the data object?
2836		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2837			// Read the data from the DOM
2838			row._aData = _fnGetRowElements(
2839					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2840				)
2841				.data;
2842		}
2843		else {
2844			// Reading from data object, update the DOM
2845			var cells = row.anCells;
2846			var display = _fnGetRowDisplay(settings, rowIdx);
2847	
2848			if ( cells ) {
2849				if ( colIdx !== undefined ) {
2850					_fnWriteCell(cells[colIdx], display[colIdx]);
2851				}
2852				else {
2853					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2854						_fnWriteCell(cells[i], display[i]);
2855					}
2856				}
2857			}
2858		}
2859	
2860		// Column specific invalidation
2861		var cols = settings.aoColumns;
2862		if ( colIdx !== undefined ) {
2863			// Type - the data might have changed
2864			cols[ colIdx ].sType = null;
2865	
2866			// Max length string. Its a fairly cheep recalculation, so not worth
2867			// something more complicated
2868			cols[ colIdx ].maxLenString = null;
2869		}
2870		else {
2871			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2872				cols[i].sType = null;
2873				cols[i].maxLenString = null;
2874			}
2875	
2876			// Update DataTables special `DT_*` attributes for the row
2877			_fnRowAttributes( settings, row );
2878		}
2879	}
2880	
2881	
2882	/**
2883	 * Build a data source object from an HTML row, reading the contents of the
2884	 * cells that are in the row.
2885	 *
2886	 * @param {object} settings DataTables settings object
2887	 * @param {node|object} TR element from which to read data or existing row
2888	 *   object from which to re-read the data from the cells
2889	 * @param {int} [colIdx] Optional column index
2890	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2891	 *   parameter should also be given and will be used to write the data into.
2892	 *   Only the column in question will be written
2893	 * @returns {object} Object with two parameters: `data` the data read, in
2894	 *   document order, and `cells` and array of nodes (they can be useful to the
2895	 *   caller, so rather than needing a second traversal to get them, just return
2896	 *   them from here).
2897	 * @memberof DataTable#oApi
2898	 */
2899	function _fnGetRowElements( settings, row, colIdx, d )
2900	{
2901		var
2902			tds = [],
2903			td = row.firstChild,
2904			name, col, i=0, contents,
2905			columns = settings.aoColumns,
2906			objectRead = settings._rowReadObject;
2907	
2908		// Allow the data object to be passed in, or construct
2909		d = d !== undefined ?
2910			d :
2911			objectRead ?
2912				{} :
2913				[];
2914	
2915		var attr = function ( str, td  ) {
2916			if ( typeof str === 'string' ) {
2917				var idx = str.indexOf('@');
2918	
2919				if ( idx !== -1 ) {
2920					var attr = str.substring( idx+1 );
2921					var setter = _fnSetObjectDataFn( str );
2922					setter( d, td.getAttribute( attr ) );
2923				}
2924			}
2925		};
2926	
2927		// Read data from a cell and store into the data object
2928		var cellProcess = function ( cell ) {
2929			if ( colIdx === undefined || colIdx === i ) {
2930				col = columns[i];
2931				contents = (cell.innerHTML).trim();
2932	
2933				if ( col && col._bAttrSrc ) {
2934					var setter = _fnSetObjectDataFn( col.mData._ );
2935					setter( d, contents );
2936	
2937					attr( col.mData.sort, cell );
2938					attr( col.mData.type, cell );
2939					attr( col.mData.filter, cell );
2940				}
2941				else {
2942					// Depending on the `data` option for the columns the data can
2943					// be read to either an object or an array.
2944					if ( objectRead ) {
2945						if ( ! col._setter ) {
2946							// Cache the setter function
2947							col._setter = _fnSetObjectDataFn( col.mData );
2948						}
2949						col._setter( d, contents );
2950					}
2951					else {
2952						d[i] = contents;
2953					}
2954				}
2955			}
2956	
2957			i++;
2958		};
2959	
2960		if ( td ) {
2961			// `tr` element was passed in
2962			while ( td ) {
2963				name = td.nodeName.toUpperCase();
2964	
2965				if ( name == "TD" || name == "TH" ) {
2966					cellProcess( td );
2967					tds.push( td );
2968				}
2969	
2970				td = td.nextSibling;
2971			}
2972		}
2973		else {
2974			// Existing row object passed in
2975			tds = row.anCells;
2976	
2977			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
2978				cellProcess( tds[j] );
2979			}
2980		}
2981	
2982		// Read the ID from the DOM if present
2983		var rowNode = row.firstChild ? row : row.nTr;
2984	
2985		if ( rowNode ) {
2986			var id = rowNode.getAttribute( 'id' );
2987	
2988			if ( id ) {
2989				_fnSetObjectDataFn( settings.rowId )( d, id );
2990			}
2991		}
2992	
2993		return {
2994			data: d,
2995			cells: tds
2996		};
2997	}
2998	
2999	/**
3000	 * Render and cache a row's display data for the columns, if required
3001	 * @returns 
3002	 */
3003	function _fnGetRowDisplay (settings, rowIdx) {
3004		let rowModal = settings.aoData[rowIdx];
3005		let columns = settings.aoColumns;
3006	
3007		if (! rowModal.displayData) {
3008			// Need to render and cache
3009			rowModal.displayData = [];
3010		
3011			for ( var colIdx=0, len=columns.length ; colIdx<len ; colIdx++ ) {
3012				rowModal.displayData.push(
3013					_fnGetCellData( settings, rowIdx, colIdx, 'display' )
3014				);
3015			}
3016		}
3017	
3018		return rowModal.displayData;
3019	}
3020	
3021	/**
3022	 * Create a new TR element (and it's TD children) for a row
3023	 *  @param {object} oSettings dataTables settings object
3024	 *  @param {int} iRow Row to consider
3025	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3026	 *    DataTables will create a row automatically
3027	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
3028	 *    if nTr is.
3029	 *  @memberof DataTable#oApi
3030	 */
3031	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3032	{
3033		var
3034			row = oSettings.aoData[iRow],
3035			rowData = row._aData,
3036			cells = [],
3037			nTr, nTd, oCol,
3038			i, iLen, create,
3039			trClass = oSettings.oClasses.tbody.row;
3040	
3041		if ( row.nTr === null )
3042		{
3043			nTr = nTrIn || document.createElement('tr');
3044	
3045			row.nTr = nTr;
3046			row.anCells = cells;
3047	
3048			_addClass(nTr, trClass);
3049	
3050			/* Use a private property on the node to allow reserve mapping from the node
3051			 * to the aoData array for fast look up
3052			 */
3053			nTr._DT_RowIndex = iRow;
3054	
3055			/* Special parameters can be given by the data source to be used on the row */
3056			_fnRowAttributes( oSettings, row );
3057	
3058			/* Process each column */
3059			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3060			{
3061				oCol = oSettings.aoColumns[i];
3062				create = nTrIn && anTds[i] ? false : true;
3063	
3064				nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
3065	
3066				if (! nTd) {
3067					_fnLog( oSettings, 0, 'Incorrect column count', 18 );
3068				}
3069	
3070				nTd._DT_CellIndex = {
3071					row: iRow,
3072					column: i
3073				};
3074				
3075				cells.push( nTd );
3076				
3077				var display = _fnGetRowDisplay(oSettings, iRow);
3078	
3079				// Need to create the HTML if new, or if a rendering function is defined
3080				if (
3081					create ||
3082					(
3083						(oCol.mRender || oCol.mData !== i) &&
3084						(!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3085					)
3086				) {
3087					_fnWriteCell(nTd, display[i]);
3088				}
3089	
3090				// Visibility - add or remove as required
3091				if ( oCol.bVisible && create )
3092				{
3093					nTr.appendChild( nTd );
3094				}
3095				else if ( ! oCol.bVisible && ! create )
3096				{
3097					nTd.parentNode.removeChild( nTd );
3098				}
3099	
3100				if ( oCol.fnCreatedCell )
3101				{
3102					oCol.fnCreatedCell.call( oSettings.oInstance,
3103						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3104					);
3105				}
3106			}
3107	
3108			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells] );
3109		}
3110		else {
3111			_addClass(row.nTr, trClass);
3112		}
3113	}
3114	
3115	
3116	/**
3117	 * Add attributes to a row based on the special `DT_*` parameters in a data
3118	 * source object.
3119	 *  @param {object} settings DataTables settings object
3120	 *  @param {object} DataTables row object for the row to be modified
3121	 *  @memberof DataTable#oApi
3122	 */
3123	function _fnRowAttributes( settings, row )
3124	{
3125		var tr = row.nTr;
3126		var data = row._aData;
3127	
3128		if ( tr ) {
3129			var id = settings.rowIdFn( data );
3130	
3131			if ( id ) {
3132				tr.id = id;
3133			}
3134	
3135			if ( data.DT_RowClass ) {
3136				// Remove any classes added by DT_RowClass before
3137				var a = data.DT_RowClass.split(' ');
3138				row.__rowc = row.__rowc ?
3139					_unique( row.__rowc.concat( a ) ) :
3140					a;
3141	
3142				$(tr)
3143					.removeClass( row.__rowc.join(' ') )
3144					.addClass( data.DT_RowClass );
3145			}
3146	
3147			if ( data.DT_RowAttr ) {
3148				$(tr).attr( data.DT_RowAttr );
3149			}
3150	
3151			if ( data.DT_RowData ) {
3152				$(tr).data( data.DT_RowData );
3153			}
3154		}
3155	}
3156	
3157	
3158	/**
3159	 * Create the HTML header for the table
3160	 *  @param {object} oSettings dataTables settings object
3161	 *  @memberof DataTable#oApi
3162	 */
3163	function _fnBuildHead( settings, side )
3164	{
3165		var classes = settings.oClasses;
3166		var columns = settings.aoColumns;
3167		var i, ien, row;
3168		var target = side === 'header'
3169			? settings.nTHead
3170			: settings.nTFoot;
3171		var titleProp = side === 'header' ? 'sTitle' : side;
3172	
3173		// Footer might be defined
3174		if (! target) {
3175			return;
3176		}
3177	
3178		// If no cells yet and we have content for them, then create
3179		if (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) {
3180			row = $('tr', target);
3181	
3182			// Add a row if needed
3183			if (! row.length) {
3184				row = $('<tr/>').appendTo(target)
3185			}
3186	
3187			// Add the number of cells needed to make up to the number of columns
3188			if (row.length === 1) {
3189				var cells = $('td, th', row);
3190	
3191				for ( i=cells.length, ien=columns.length ; i<ien ; i++ ) {
3192					$('<th/>')
3193						.html( columns[i][titleProp] || '' )
3194						.appendTo( row );
3195				}
3196			}
3197		}
3198	
3199		var detected = _fnDetectHeader( settings, target, true );
3200	
3201		if (side === 'header') {
3202			settings.aoHeader = detected;
3203		}
3204		else {
3205			settings.aoFooter = detected;
3206		}
3207	
3208		// ARIA role for the rows
3209		$(target).children('tr').attr('role', 'row');
3210	
3211		// Every cell needs to be passed through the renderer
3212		$(target).children('tr').children('th, td')
3213			.each( function () {
3214				_fnRenderer( settings, side )(
3215					settings, $(this), classes
3216				);
3217			} );
3218	}
3219	
3220	/**
3221	 * Build a layout structure for a header or footer
3222	 *
3223	 * @param {*} settings DataTables settings
3224	 * @param {*} source Source layout array
3225	 * @param {*} incColumns What columns should be included
3226	 * @returns Layout array
3227	 */
3228	function _fnHeaderLayout( settings, source, incColumns )
3229	{
3230		var row, column, cell;
3231		var local = [];
3232		var structure = [];
3233		var columns = settings.aoColumns;
3234		var columnCount = columns.length;
3235		var rowspan, colspan;
3236	
3237		if ( ! source ) {
3238			return;
3239		}
3240	
3241		// Default is to work on only visible columns
3242		if ( ! incColumns ) {
3243			incColumns = _range(columnCount)
3244				.filter(function (idx) {
3245					return columns[idx].bVisible;
3246				});
3247		}
3248	
3249		// Make a copy of the master layout array, but with only the columns we want
3250		for ( row=0 ; row<source.length ; row++ ) {
3251			// Remove any columns we haven't selected
3252			local[row] = source[row].slice().filter(function (cell, i) {
3253				return incColumns.includes(i);
3254			});
3255	
3256			// Prep the structure array - it needs an element for each row
3257			structure.push( [] );
3258		}
3259	
3260		for ( row=0 ; row<local.length ; row++ ) {
3261			for ( column=0 ; column<local[row].length ; column++ ) {
3262				rowspan = 1;
3263				colspan = 1;
3264	
3265				// Check to see if there is already a cell (row/colspan) covering our target
3266				// insert point. If there is, then there is nothing to do.
3267				if ( structure[row][column] === undefined ) {
3268					cell = local[row][column].cell;
3269	
3270					// Expand for rowspan
3271					while (
3272						local[row+rowspan] !== undefined &&
3273						local[row][column].cell == local[row+rowspan][column].cell
3274					) {
3275						structure[row+rowspan][column] = null;
3276						rowspan++;
3277					}
3278	
3279					// And for colspan
3280					while (
3281						local[row][column+colspan] !== undefined &&
3282						local[row][column].cell == local[row][column+colspan].cell
3283					) {
3284						// Which also needs to go over rows
3285						for ( var k=0 ; k<rowspan ; k++ ) {
3286							structure[row+k][column+colspan] = null;
3287						}
3288	
3289						colspan++;
3290					}
3291	
3292					var titleSpan = $('span.dt-column-title', cell);
3293	
3294					structure[row][column] = {
3295						cell: cell,
3296						colspan: colspan,
3297						rowspan: rowspan,
3298						title: titleSpan.length
3299							? titleSpan.html()
3300							: $(cell).html()
3301					};
3302				}
3303			}
3304		}
3305	
3306		return structure;
3307	}
3308	
3309	
3310	/**
3311	 * Draw the header (or footer) element based on the column visibility states.
3312	 *
3313	 *  @param object oSettings dataTables settings object
3314	 *  @param array aoSource Layout array from _fnDetectHeader
3315	 *  @memberof DataTable#oApi
3316	 */
3317	function _fnDrawHead( settings, source )
3318	{
3319		var layout = _fnHeaderLayout(settings, source);
3320		var tr, n;
3321	
3322		for ( var row=0 ; row<source.length ; row++ ) {
3323			tr = source[row].row;
3324	
3325			// All cells are going to be replaced, so empty out the row
3326			// Can't use $().empty() as that kills event handlers
3327			if (tr) {
3328				while( (n = tr.firstChild) ) {
3329					tr.removeChild( n );
3330				}
3331			}
3332	
3333			for ( var column=0 ; column<layout[row].length ; column++ ) {
3334				var point = layout[row][column];
3335	
3336				if (point) {
3337					$(point.cell)
3338						.appendTo(tr)
3339						.attr('rowspan', point.rowspan)
3340						.attr('colspan', point.colspan);
3341				}
3342			}
3343		}
3344	}
3345	
3346	
3347	/**
3348	 * Insert the required TR nodes into the table for display
3349	 *  @param {object} oSettings dataTables settings object
3350	 *  @param ajaxComplete true after ajax call to complete rendering
3351	 *  @memberof DataTable#oApi
3352	 */
3353	function _fnDraw( oSettings, ajaxComplete )
3354	{
3355		// Allow for state saving and a custom start position
3356		_fnStart( oSettings );
3357	
3358		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3359		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3360		if ( aPreDraw.indexOf(false) !== -1 )
3361		{
3362			_fnProcessingDisplay( oSettings, false );
3363			return;
3364		}
3365	
3366		var anRows = [];
3367		var iRowCount = 0;
3368		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3369		var aiDisplay = oSettings.aiDisplay;
3370		var iDisplayStart = oSettings._iDisplayStart;
3371		var iDisplayEnd = oSettings.fnDisplayEnd();
3372		var columns = oSettings.aoColumns;
3373		var body = $(oSettings.nTBody);
3374	
3375		oSettings.bDrawing = true;
3376	
3377		/* Server-side processing draw intercept */
3378		if ( !bServerSide )
3379		{
3380			oSettings.iDraw++;
3381		}
3382		else if ( !oSettings.bDestroying && !ajaxComplete)
3383		{
3384			// Show loading message for server-side processing
3385			if (oSettings.iDraw === 0) {
3386				body.empty().append(_emptyRow(oSettings));
3387			}
3388	
3389			_fnAjaxUpdate( oSettings );
3390			return;
3391		}
3392	
3393		if ( aiDisplay.length !== 0 )
3394		{
3395			var iStart = bServerSide ? 0 : iDisplayStart;
3396			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3397	
3398			for ( var j=iStart ; j<iEnd ; j++ )
3399			{
3400				var iDataIndex = aiDisplay[j];
3401				var aoData = oSettings.aoData[ iDataIndex ];
3402				if ( aoData.nTr === null )
3403				{
3404					_fnCreateTr( oSettings, iDataIndex );
3405				}
3406	
3407				var nRow = aoData.nTr;
3408	
3409				// Add various classes as needed
3410				for (var i=0 ; i<columns.length ; i++) {
3411					var col = columns[i];
3412					var td = aoData.anCells[i];
3413	
3414					_addClass(td, _ext.type.className[col.sType]); // auto class
3415					_addClass(td, col.sClass); // column class
3416					_addClass(td, oSettings.oClasses.tbody.cell); // all cells
3417				}
3418	
3419				// Row callback functions - might want to manipulate the row
3420				// iRowCount and j are not currently documented. Are they at all
3421				// useful?
3422				_fnCallbackFire( oSettings, 'aoRowCallback', null,
3423					[nRow, aoData._aData, iRowCount, j, iDataIndex] );
3424	
3425				anRows.push( nRow );
3426				iRowCount++;
3427			}
3428		}
3429		else
3430		{
3431			anRows[ 0 ] = _emptyRow(oSettings);
3432		}
3433	
3434		/* Header and footer callbacks */
3435		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3436			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3437	
3438		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3439			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3440	
3441		// replaceChildren is faster, but only became widespread in 2020,
3442		// so a fall back in jQuery is provided for older browsers.
3443		if (body[0].replaceChildren) {
3444			body[0].replaceChildren.apply(body[0], anRows);
3445		}
3446		else {
3447			body.children().detach();
3448			body.append( $(anRows) );
3449		}
3450	
3451		// Empty table needs a specific class
3452		$(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
3453	
3454		/* Call all required callback functions for the end of a draw */
3455		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings], true );
3456	
3457		/* Draw is complete, sorting and filtering must be as well */
3458		oSettings.bSorted = false;
3459		oSettings.bFiltered = false;
3460		oSettings.bDrawing = false;
3461	}
3462	
3463	
3464	/**
3465	 * Redraw the table - taking account of the various features which are enabled
3466	 *  @param {object} oSettings dataTables settings object
3467	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
3468	 *    the paging is reset to the first page
3469	 *  @memberof DataTable#oApi
3470	 */
3471	function _fnReDraw( settings, holdPosition, recompute )
3472	{
3473		var
3474			features = settings.oFeatures,
3475			sort     = features.bSort,
3476			filter   = features.bFilter;
3477	
3478		if (recompute === undefined || recompute === true) {
3479			if ( sort ) {
3480				_fnSort( settings );
3481			}
3482	
3483			if ( filter ) {
3484				_fnFilterComplete( settings, settings.oPreviousSearch );
3485			}
3486			else {
3487				// No filtering, so we want to just use the display master
3488				settings.aiDisplay = settings.aiDisplayMaster.slice();
3489			}
3490		}
3491	
3492		if ( holdPosition !== true ) {
3493			settings._iDisplayStart = 0;
3494		}
3495	
3496		// Let any modules know about the draw hold position state (used by
3497		// scrolling internally)
3498		settings._drawHold = holdPosition;
3499	
3500		_fnDraw( settings );
3501	
3502		settings._drawHold = false;
3503	}
3504	
3505	
3506	/*
3507	 * Table is empty - create a row with an empty message in it
3508	 */
3509	function _emptyRow ( settings ) {
3510		var oLang = settings.oLanguage;
3511		var zero = oLang.sZeroRecords;
3512		var dataSrc = _fnDataSource( settings );
3513	
3514		if (
3515			(settings.iDraw < 1 && dataSrc === 'ssp') ||
3516			(settings.iDraw <= 1 && dataSrc === 'ajax')
3517		) {
3518			zero = oLang.sLoadingRecords;
3519		}
3520		else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
3521		{
3522			zero = oLang.sEmptyTable;
3523		}
3524	
3525		return $( '<tr/>' )
3526			.append( $('<td />', {
3527				'colSpan': _fnVisbleColumns( settings ),
3528				'class':   settings.oClasses.empty.row
3529			} ).html( zero ) )[0];
3530	}
3531	
3532	
3533	/**
3534	 * Convert a `layout` object given by a user to the object structure needed
3535	 * for the renderer. This is done twice, once for above and once for below
3536	 * the table. Ordering must also be considered.
3537	 *
3538	 * @param {*} settings DataTables settings object
3539	 * @param {*} layout Layout object to convert
3540	 * @param {string} side `top` or `bottom`
3541	 * @returns Converted array structure - one item for each row.
3542	 */
3543	function _layoutArray ( settings, layout, side )
3544	{
3545		var groups = {};
3546	
3547		// Combine into like groups (e.g. `top`, `top2`, etc)
3548		$.each( layout, function ( pos, val ) {
3549			if (val === null) {
3550				return;
3551			}
3552	
3553			var splitPos = pos.replace(/([A-Z])/g, ' $1').split(' ');
3554	
3555			if ( ! groups[ splitPos[0] ] ) {
3556				groups[ splitPos[0] ] = {};
3557			}
3558	
3559			var align = splitPos.length === 1 ?
3560				'full' :
3561				splitPos[1].toLowerCase();
3562			var group = groups[ splitPos[0] ];
3563			var groupRun = function (contents, innerVal) {
3564				// If it is an object, then there can be multiple features contained in it
3565				if ( $.isPlainObject( innerVal ) ) {
3566					Object.keys(innerVal).map(function (key) {
3567						contents.push( {
3568							feature: key,
3569							opts: innerVal[key]
3570						});
3571					});
3572				}
3573				else {
3574					contents.push(innerVal);
3575				}
3576			}
3577	
3578			// Transform to an object with a contents property
3579			if (! group[align] || ! group[align].contents) {
3580				group[align] = { contents: [] };
3581			}
3582	
3583			// Allow for an array or just a single object
3584			if ( Array.isArray(val)) {
3585				for (var i=0 ; i<val.length ; i++) {
3586					groupRun(group[align].contents, val[i]);
3587				}
3588			}
3589			else {
3590				groupRun(group[ align ].contents, val);
3591			}
3592	
3593			// And make contents an array
3594			if ( ! Array.isArray( group[ align ].contents ) ) {
3595				group[ align ].contents = [ group[ align ].contents ];
3596			}
3597		} );
3598	
3599		var filtered = Object.keys(groups)
3600			.map( function ( pos ) {
3601				// Filter to only the side we need
3602				if ( pos.indexOf(side) !== 0 ) {
3603					return null;
3604				}
3605	
3606				return {
3607					name: pos,
3608					val: groups[pos]
3609				};
3610			} )
3611			.filter( function (item) {
3612				return item !== null;
3613			});
3614	
3615		// Order by item identifier
3616		filtered.sort( function ( a, b ) {
3617			var order1 = a.name.replace(/[^0-9]/g, '') * 1;
3618			var order2 = b.name.replace(/[^0-9]/g, '') * 1;
3619	
3620			return order2 - order1;
3621		} );
3622		
3623		if ( side === 'bottom' ) {
3624			filtered.reverse();
3625		}
3626	
3627		// Split into rows
3628		var rows = [];
3629		for ( var i=0, ien=filtered.length ; i<ien ; i++ ) {
3630			if (  filtered[i].val.full ) {
3631				rows.push( { full: filtered[i].val.full } );
3632				_layoutResolve( settings, rows[ rows.length - 1 ] );
3633	
3634				delete filtered[i].val.full;
3635			}
3636	
3637			if ( Object.keys(filtered[i].val).length ) {
3638				rows.push( filtered[i].val );
3639				_layoutResolve( settings, rows[ rows.length - 1 ] );
3640			}
3641		}
3642	
3643		return rows;
3644	}
3645	
3646	
3647	/**
3648	 * Convert the contents of a row's layout object to nodes that can be inserted
3649	 * into the document by a renderer. Execute functions, look up plug-ins, etc.
3650	 *
3651	 * @param {*} settings DataTables settings object
3652	 * @param {*} row Layout object for this row
3653	 */
3654	function _layoutResolve( settings, row ) {
3655		var getFeature = function (feature, opts) {
3656			if ( ! _ext.features[ feature ] ) {
3657				_fnLog( settings, 0, 'Unknown feature: '+ feature );
3658			}
3659	
3660			return _ext.features[ feature ].apply( this, [settings, opts] );
3661		};
3662	
3663		var resolve = function ( item ) {
3664			var line = row[ item ].contents;
3665	
3666			for ( var i=0, ien=line.length ; i<ien ; i++ ) {
3667				if ( ! line[i] ) {
3668					continue;
3669				}
3670				else if ( typeof line[i] === 'string' ) {
3671					line[i] = getFeature( line[i], null );
3672				}
3673				else if ( $.isPlainObject(line[i]) ) {
3674					// If it's an object, it just has feature and opts properties from
3675					// the transform in _layoutArray
3676					line[i] = getFeature(line[i].feature, line[i].opts);
3677				}
3678				else if ( typeof line[i].node === 'function' ) {
3679					line[i] = line[i].node( settings );
3680				}
3681				else if ( typeof line[i] === 'function' ) {
3682					var inst = line[i]( settings );
3683	
3684					line[i] = typeof inst.node === 'function' ?
3685						inst.node() :
3686						inst;
3687				}
3688			}
3689		};
3690	
3691		$.each( row, function ( key ) {
3692			resolve( key );
3693		} );
3694	}
3695	
3696	
3697	/**
3698	 * Add the options to the page HTML for the table
3699	 *  @param {object} settings DataTables settings object
3700	 *  @memberof DataTable#oApi
3701	 */
3702	function _fnAddOptionsHtml ( settings )
3703	{
3704		var classes = settings.oClasses;
3705		var table = $(settings.nTable);
3706	
3707		// Wrapper div around everything DataTables controls
3708		var insert = $('<div/>')
3709			.attr({
3710				id:      settings.sTableId+'_wrapper',
3711				'class': classes.container
3712			})
3713			.insertBefore(table);
3714	
3715		settings.nTableWrapper = insert[0];
3716	
3717		if (settings.sDom) {
3718			// Legacy
3719			_fnLayoutDom(settings, settings.sDom, insert);
3720		}
3721		else {
3722			var top = _layoutArray( settings, settings.layout, 'top' );
3723			var bottom = _layoutArray( settings, settings.layout, 'bottom' );
3724			var renderer = _fnRenderer( settings, 'layout' );
3725		
3726			// Everything above - the renderer will actually insert the contents into the document
3727			top.forEach(function (item) {
3728				renderer( settings, insert, item );
3729			});
3730	
3731			// The table - always the center of attention
3732			renderer( settings, insert, {
3733				full: {
3734					table: true,
3735					contents: [ _fnFeatureHtmlTable(settings) ]
3736				}
3737			} );
3738	
3739			// Everything below
3740			bottom.forEach(function (item) {
3741				renderer( settings, insert, item );
3742			});
3743		}
3744	
3745		// Processing floats on top, so it isn't an inserted feature
3746		_processingHtml( settings );
3747	}
3748	
3749	/**
3750	 * Draw the table with the legacy DOM property
3751	 * @param {*} settings DT settings object
3752	 * @param {*} dom DOM string
3753	 * @param {*} insert Insert point
3754	 */
3755	function _fnLayoutDom( settings, dom, insert )
3756	{
3757		var parts = dom.match(/(".*?")|('.*?')|./g);
3758		var featureNode, option, newNode, next, attr;
3759	
3760		for ( var i=0 ; i<parts.length ; i++ ) {
3761			featureNode = null;
3762			option = parts[i];
3763	
3764			if ( option == '<' ) {
3765				// New container div
3766				newNode = $('<div/>');
3767	
3768				// Check to see if we should append an id and/or a class name to the container
3769				next = parts[i+1];
3770	
3771				if ( next[0] == "'" || next[0] == '"' ) {
3772					attr = next.replace(/['"]/g, '');
3773	
3774					var id = '', className;
3775	
3776					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3777					 * breaks the string into parts and applies them as needed
3778					 */
3779					if ( attr.indexOf('.') != -1 ) {
3780						var split = attr.split('.');
3781	
3782						id = split[0];
3783						className = split[1];
3784					}
3785					else if ( attr[0] == "#" ) {
3786						id = attr;
3787					}
3788					else {
3789						className = attr;
3790					}
3791	
3792					newNode
3793						.attr('id', id.substring(1))
3794						.addClass(className);
3795	
3796					i++; // Move along the position array
3797				}
3798	
3799				insert.append( newNode );
3800				insert = newNode;
3801			}
3802			else if ( option == '>' ) {
3803				// End container div
3804				insert = insert.parent();
3805			}
3806			else if ( option == 't' ) {
3807				// Table
3808				featureNode = _fnFeatureHtmlTable( settings );
3809			}
3810			else
3811			{
3812				DataTable.ext.feature.forEach(function(feature) {
3813					if ( option == feature.cFeature ) {
3814						featureNode = feature.fnInit( settings );
3815					}
3816				});
3817			}
3818	
3819			// Add to the display
3820			if ( featureNode ) {
3821				insert.append( featureNode );
3822			}
3823		}
3824	}
3825	
3826	
3827	/**
3828	 * Use the DOM source to create up an array of header cells. The idea here is to
3829	 * create a layout grid (array) of rows x columns, which contains a reference
3830	 * to the cell that that point in the grid (regardless of col/rowspan), such that
3831	 * any column / row could be removed and the new grid constructed
3832	 *  @param {node} thead The header/footer element for the table
3833	 *  @returns {array} Calculated layout array
3834	 *  @memberof DataTable#oApi
3835	 */
3836	function _fnDetectHeader ( settings, thead, write )
3837	{
3838		var columns = settings.aoColumns;
3839		var rows = $(thead).children('tr');
3840		var row, cell;
3841		var i, k, l, iLen, shifted, column, colspan, rowspan;
3842		var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3843		var layout = [];
3844		var unique;
3845		var shift = function ( a, i, j ) {
3846			var k = a[i];
3847			while ( k[j] ) {
3848				j++;
3849			}
3850			return j;
3851		};
3852	
3853		// We know how many rows there are in the layout - so prep it
3854		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3855			layout.push( [] );
3856		}
3857	
3858		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3859			row = rows[i];
3860			column = 0;
3861	
3862			// For every cell in the row..
3863			cell = row.firstChild;
3864			while ( cell ) {
3865				if (
3866					cell.nodeName.toUpperCase() == 'TD' ||
3867					cell.nodeName.toUpperCase() == 'TH'
3868				) {
3869					var cols = [];
3870	
3871					// Get the col and rowspan attributes from the DOM and sanitise them
3872					colspan = cell.getAttribute('colspan') * 1;
3873					rowspan = cell.getAttribute('rowspan') * 1;
3874					colspan = (!colspan || colspan===0 || colspan===1) ? 1 : colspan;
3875					rowspan = (!rowspan || rowspan===0 || rowspan===1) ? 1 : rows
3875pan;
3876	
3877					// There might be colspan cells already in this row, so shift our target
3878					// accordingly
3879					shifted = shift( layout, i, column );
3880	
3881					// Cache calculation for unique columns
3882					unique = colspan === 1 ?
3883						true :
3884						false;
3885					
3886					// Perform header setup
3887					if ( write ) {
3888						if (unique) {
3889							// Allow column options to be set from HTML attributes
3890							_fnColumnOptions( settings, shifted, $(cell).data() );
3891							
3892							// Get the width for the column. This can be defined from the
3893							// width attribute, style attribute or `columns.width` option
3894							var columnDef = columns[shifted];
3895							var width = cell.getAttribute('width') || null;
3896							var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
3897							if ( t ) {
3898								width = t[1];
3899							}
3900	
3901							columnDef.sWidthOrig = columnDef.sWidth || width;
3902	
3903							if (isHeader) {
3904								// Column title handling - can be user set, or read from the DOM
3905								// This happens before the render, so the original is still in place
3906								if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
3907									cell.innerHTML = columnDef.sTitle;
3908								}
3909	
3910								if (! columnDef.sTitle && unique) {
3911									columnDef.sTitle = _stripHtml(cell.innerHTML);
3912									columnDef.autoTitle = true;
3913								}
3914							}
3915							else {
3916								// Footer specific operations
3917								if (columnDef.footer) {
3918									cell.innerHTML = columnDef.footer;
3919								}
3920							}
3921	
3922							// Fall back to the aria-label attribute on the table header if no ariaTitle is
3923							// provided.
3924							if (! columnDef.ariaTitle) {
3925								columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
3926							}
3927	
3928							// Column specific class names
3929							if ( columnDef.className ) {
3930								$(cell).addClass( columnDef.className );
3931							}
3932						}
3933	
3934						// Wrap the column title so we can write to it in future
3935						if ( $('span.dt-column-title', cell).length === 0) {
3936							$('<span>')
3937								.addClass('dt-column-title')
3938								.append(cell.childNodes)
3939								.appendTo(cell);
3940						}
3941	
3942						if ( isHeader && $('span.dt-column-order', cell).length === 0) {
3943							$('<span>')
3944								.addClass('dt-column-order')
3945								.appendTo(cell);
3946						}
3947					}
3948	
3949					// If there is col / rowspan, copy the information into the layout grid
3950					for ( l=0 ; l<colspan ; l++ ) {
3951						for ( k=0 ; k<rowspan ; k++ ) {
3952							layout[i+k][shifted+l] = {
3953								cell: cell,
3954								unique: unique
3955							};
3956	
3957							layout[i+k].row = row;
3958						}
3959	
3960						cols.push( shifted+l );
3961					}
3962	
3963					// Assign an attribute so spanning cells can still be identified
3964					// as belonging to a column
3965					cell.setAttribute('data-dt-column', _unique(cols).join(','));
3966				}
3967	
3968				cell = cell.nextSibling;
3969			}
3970		}
3971	
3972		return layout;
3973	}
3974	
3975	/**
3976	 * Set the start position for draw
3977	 *  @param {object} oSettings dataTables settings object
3978	 */
3979	function _fnStart( oSettings )
3980	{
3981		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3982		var iInitDisplayStart = oSettings.iInitDisplayStart;
3983	
3984		// Check and see if we have an initial draw position from state saving
3985		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3986		{
3987			oSettings._iDisplayStart = bServerSide ?
3988				iInitDisplayStart :
3989				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3990					0 :
3991					iInitDisplayStart;
3992	
3993			oSettings.iInitDisplayStart = -1;
3994		}
3995	}
3996	
3997	/**
3998	 * Create an Ajax call based on the table's settings, taking into account that
3999	 * parameters can have multiple forms, and backwards compatibility.
4000	 *
4001	 * @param {object} oSettings dataTables settings object
4002	 * @param {array} data Data to send to the server, required by
4003	 *     DataTables - may be augmented by developer callbacks
4004	 * @param {function} fn Callback function to run when data is obtained
4005	 */
4006	function _fnBuildAjax( oSettings, data, fn )
4007	{
4008		var ajaxData;
4009		var ajax = oSettings.ajax;
4010		var instance = oSettings.oInstance;
4011		var callback = function ( json ) {
4012			var status = oSettings.jqXHR
4013				? oSettings.jqXHR.status
4014				: null;
4015	
4016			if ( json === null || (typeof status === 'number' && status == 204 ) ) {
4017				json = {};
4018				_fnAjaxDataSrc( oSettings, json, [] );
4019			}
4020	
4021			var error = json.error || json.sError;
4022			if ( error ) {
4023				_fnLog( oSettings, 0, error );
4024			}
4025	
4026			oSettings.json = json;
4027	
4028			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
4029			fn( json );
4030		};
4031	
4032		if ( $.isPlainObject( ajax ) && ajax.data )
4033		{
4034			ajaxData = ajax.data;
4035	
4036			var newData = typeof ajaxData === 'function' ?
4037				ajaxData( data, oSettings ) :  // fn can manipulate data or return
4038				ajaxData;                      // an object object or array to merge
4039	
4040			// If the function returned something, use that alone
4041			data = typeof ajaxData === 'function' && newData ?
4042				newData :
4043				$.extend( true, data, newData );
4044	
4045			// Remove the data property as we've resolved it already and don't want
4046			// jQuery to do it again (it is restored at the end of the function)
4047			delete ajax.data;
4048		}
4049	
4050		var baseAjax = {
4051			"url": typeof ajax === 'string' ?
4052				ajax :
4053				'',
4054			"data": data,
4055			"success": callback,
4056			"dataType": "json",
4057			"cache": false,
4058			"type": oSettings.sServerMethod,
4059			"error": function (xhr, error) {
4060				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
4061	
4062				if ( ret.indexOf(true) === -1 ) {
4063					if ( error == "parsererror" ) {
4064						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
4065					}
4066					else if ( xhr.readyState === 4 ) {
4067						_fnLog( oSettings, 0, 'Ajax error', 7 );
4068					}
4069				}
4070	
4071				_fnProcessingDisplay( oSettings, false );
4072			}
4073		};
4074	
4075		// If `ajax` option is an object, extend and override our default base
4076		if ( $.isPlainObject( ajax ) ) {
4077			$.extend( baseAjax, ajax )
4078		}
4079	
4080		// Store the data submitted for the API
4081		oSettings.oAjaxData = data;
4082	
4083		// Allow plug-ins and external processes to modify the data
4084		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4085	
4086		if ( typeof ajax === 'function' )
4087		{
4088			// Is a function - let the caller define what needs to be done
4089			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
4090		}
4091		else if (ajax.url === '') {
4092			// No url, so don't load any data. Just apply an empty data array
4093			// to the object for the callback.
4094			var empty = {};
4095	
4096			DataTable.util.set(ajax.dataSrc)(empty, []);
4097			callback(empty);
4098		}
4099		else {
4100			// Object to extend the base settings
4101			oSettings.jqXHR = $.ajax( baseAjax );
4102	
4103			// Restore for next time around
4104			if ( ajaxData ) {
4105				ajax.data = ajaxData;
4106			}
4107		}
4108	}
4109	
4110	
4111	/**
4112	 * Update the table using an Ajax call
4113	 *  @param {object} settings dataTables settings object
4114	 *  @returns {boolean} Block the table drawing or not
4115	 *  @memberof DataTable#oApi
4116	 */
4117	function _fnAjaxUpdate( settings )
4118	{
4119		settings.iDraw++;
4120		_fnProcessingDisplay( settings, true );
4121	
4122		_fnBuildAjax(
4123			settings,
4124			_fnAjaxParameters( settings ),
4125			function(json) {
4126				_fnAjaxUpdateDraw( settings, json );
4127			}
4128		);
4129	}
4130	
4131	
4132	/**
4133	 * Build up the parameters in an object needed for a server-side processing
4134	 * request.
4135	 *  @param {object} oSettings dataTables settings object
4136	 *  @returns {bool} block the table drawing or not
4137	 *  @memberof DataTable#oApi
4138	 */
4139	function _fnAjaxParameters( settings )
4140	{
4141		var
4142			columns = settings.aoColumns,
4143			features = settings.oFeatures,
4144			preSearch = settings.oPreviousSearch,
4145			preColSearch = settings.aoPreSearchCols,
4146			colData = function ( idx, prop ) {
4147				return typeof columns[idx][prop] === 'function' ?
4148					'function' :
4149					columns[idx][prop];
4150			};
4151	
4152		return {
4153			draw: settings.iDraw,
4154			columns: columns.map( function ( column, i ) {
4155				return {
4156					data: colData(i, 'mData'),
4157					name: column.sName,
4158					searchable: column.bSearchable,
4159					orderable: column.bSortable,
4160					search: {
4161						value: preColSearch[i].search,
4162						regex: preColSearch[i].regex,
4163						fixed: Object.keys(column.searchFixed).map( function(name) {
4164							return {
4165								name: name,
4166								term: column.searchFixed[name].toString()
4167							}
4168						})
4169					}
4170				};
4171			} ),
4172			order: _fnSortFlatten( settings ).map( function ( val ) {
4173				return {
4174					column: val.col,
4175					dir: val.dir,
4176					name: colData(val.col, 'sName')
4177				};
4178			} ),
4179			start: settings._iDisplayStart,
4180			length: features.bPaginate ?
4181				settings._iDisplayLength :
4182				-1,
4183			search: {
4184				value: preSearch.search,
4185				regex: preSearch.regex,
4186				fixed: Object.keys(settings.searchFixed).map( function(name) {
4187					return {
4188						name: name,
4189						term: settings.searchFixed[name].toString()
4190					}
4191				})
4192			}
4193		};
4194	}
4195	
4196	
4197	/**
4198	 * Data the data from the server (nuking the old) and redraw the table
4199	 *  @param {object} oSettings dataTables settings object
4200	 *  @param {object} json json data return from the server.
4201	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
4202	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4203	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4204	 *  @param {array} json.aaData The data to display on this page
4205	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4206	 *  @memberof DataTable#oApi
4207	 */
4208	function _fnAjaxUpdateDraw ( settings, json )
4209	{
4210		var data = _fnAjaxDataSrc(settings, json);
4211		var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
4212		var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
4213		var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
4214	
4215		if ( draw !== undefined ) {
4216			// Protect against out of sequence returns
4217			if ( draw*1 < settings.iDraw ) {
4218				return;
4219			}
4220			settings.iDraw = draw * 1;
4221		}
4222	
4223		// No data in returned object, so rather than an array, we show an empty table
4224		if ( ! data ) {
4225			data = [];
4226		}
4227	
4228		_fnClearTable( settings );
4229		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
4230		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4231	
4232		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4233			_fnAddData( settings, data[i] );
4234		}
4235		settings.aiDisplay = settings.aiDisplayMaster.slice();
4236	
4237		_fnDraw( settings, true );
4238		_fnInitComplete( settings );
4239		_fnProcessingDisplay( settings, false );
4240	}
4241	
4242	
4243	/**
4244	 * Get the data from the JSON data source to use for drawing a table. Using
4245	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4246	 * source object, or from a processing function.
4247	 *  @param {object} settings dataTables settings object
4248	 *  @param  {object} json Data source object / array from the server
4249	 *  @return {array} Array of data to use
4250	 */
4251	function _fnAjaxDataSrc ( settings, json, write )
4252	{
4253		var dataProp = 'data';
4254	
4255		if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
4256			// Could in inside a `dataSrc` object, or not!
4257			var dataSrc = settings.ajax.dataSrc;
4258	
4259			// string, function and object are valid types
4260			if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
4261				dataProp = dataSrc;
4262			}
4263			else if (dataSrc.data !== undefined) {
4264				dataProp = dataSrc.data;
4265			}
4266		}
4267	
4268		if ( ! write ) {
4269			if ( dataProp === 'data' ) {
4270				// If the default, then we still want to support the old style, and safely ignore
4271				// it if possible
4272				return json.aaData || json[dataProp];
4273			}
4274	
4275			return dataProp !== "" ?
4276				_fnGetObjectDataFn( dataProp )( json ) :
4277				json;
4278		}
4279		
4280		// set
4281		_fnSetObjectDataFn( dataProp )( json, write );
4282	}
4283	
4284	/**
4285	 * Very similar to _fnAjaxDataSrc, but for the other SSP properties
4286	 * @param {*} settings DataTables settings object
4287	 * @param {*} param Target parameter
4288	 * @param {*} json JSON data
4289	 * @returns Resolved value
4290	 */
4291	function _fnAjaxDataSrcParam (settings, param, json) {
4292		var dataSrc = $.isPlainObject( settings.ajax )
4293			? settings.ajax.dataSrc
4294			: null;
4295	
4296		if (dataSrc && dataSrc[param]) {
4297			// Get from custom location
4298			return _fnGetObjectDataFn( dataSrc[param] )( json );
4299		}
4300	
4301		// else - Default behaviour
4302		var old = '';
4303	
4304		// Legacy support
4305		if (param === 'draw') {
4306			old = 'sEcho';
4307		}
4308		else if (param === 'recordsTotal') {
4309			old = 'iTotalRecords';
4310		}
4311		else if (param === 'recordsFiltered') {
4312			old = 'iTotalDisplayRecords';
4313		}
4314	
4315		return json[old] !== undefined
4316			? json[old]
4317			: json[param];
4318	}
4319	
4320	
4321	/**
4322	 * Filter the table using both the global filter and column based filtering
4323	 *  @param {object} settings dataTables settings object
4324	 *  @param {object} input search information
4325	 *  @memberof DataTable#oApi
4326	 */
4327	function _fnFilterComplete ( settings, input )
4328	{
4329		var columnsSearch = settings.aoPreSearchCols;
4330	
4331		// Resolve any column types that are unknown due to addition or invalidation
4332		// @todo As per sort - can this be moved into an event handler?
4333		_fnColumnTypes( settings );
4334	
4335		// In server-side processing all filtering is done by the server, so no point hanging around here
4336		if ( _fnDataSource( settings ) != 'ssp' )
4337		{
4338			// Check if any of the rows were invalidated
4339			_fnFilterData( settings );
4340	
4341			// Start from the full data set
4342			settings.aiDisplay = settings.aiDisplayMaster.slice();
4343	
4344			// Global filter first
4345			_fnFilter( settings.aiDisplay, settings, input.search, input );
4346	
4347			$.each(settings.searchFixed, function (name, term) {
4348				_fnFilter(settings.aiDisplay, settings, term, {});
4349			});
4350	
4351			// Then individual column filters
4352			for ( var i=0 ; i<columnsSearch.length ; i++ )
4353			{
4354				var col = columnsSearch[i];
4355	
4356				_fnFilter(
4357					settings.aiDisplay,
4358					settings,
4359					col.search,
4360					col,
4361					i
4362				);
4363	
4364				$.each(settings.aoColumns[i].searchFixed, function (name, term) {
4365					_fnFilter(settings.aiDisplay, settings, term, {}, i);
4366				});
4367			}
4368	
4369			// And finally global filtering
4370			_fnFilterCustom( settings );
4371		}
4372	
4373		// Tell the draw function we have been filtering
4374		settings.bFiltered = true;
4375	
4376		_fnCallbackFire( settings, null, 'search', [settings] );
4377	}
4378	
4379	
4380	/**
4381	 * Apply custom filtering functions
4382	 * 
4383	 * This is legacy now that we have named functions, but it is widely used
4384	 * from 1.x, so it is not yet deprecated.
4385	 *  @param {object} oSettings dataTables settings object
4386	 *  @memberof DataTable#oApi
4387	 */
4388	function _fnFilterCustom( settings )
4389	{
4390		var filters = DataTable.ext.search;
4391		var displayRows = settings.aiDisplay;
4392		var row, rowIdx;
4393	
4394		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4395			var rows = [];
4396	
4397			// Loop over each row and see if it should be included
4398			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4399				rowIdx = displayRows[ j ];
4400				row = settings.aoData[ rowIdx ];
4401	
4402				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4403					rows.push( rowIdx );
4404				}
4405			}
4406	
4407			// So the array reference doesn't break set the results into the
4408			// existing array
4409			displayRows.length = 0;
4410			displayRows.push.apply(displayRows, rows);
4411		}
4412	}
4413	
4414	
4415	/**
4416	 * Filter the data table based on user input and draw the table
4417	 */
4418	function _fnFilter( searchRows, settings, input, options, column )
4419	{
4420		if ( input === '' ) {
4421			return;
4422		}
4423	
4424		var i = 0;
4425	
4426		// Search term can be a function, regex or string - if a string we apply our
4427		// smart filtering regex (assuming the options require that)
4428		var searchFunc = typeof input === 'function' ? input : null;
4429		var rpSearch = input instanceof RegExp
4430			? input
4431			: searchFunc
4432				? null
4433				: _fnFilterCreateSearch( input, options );
4434	
4435		// Then for each row, does the test pass. If not, lop the row from the array
4436		while (i < searchRows.length) {
4437			var row = settings.aoData[ searchRows[i] ];
4438			var data = column === undefined
4439				? row._sFilterRow
4440				: row._aFilterData[ column ];
4441	
4442			if ( (searchFunc && ! searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && ! rpSearch.test(data)) ) {
4443				searchRows.splice(i, 1);
4444				i--;
4445			}
4446	
4447			i++;
4448		}
4449	}
4450	
4451	
4452	/**
4453	 * Build a regular expression object suitable for searching a table
4454	 *  @param {string} sSearch string to search for
4455	 *  @param {bool} bRegex treat as a regular expression or not
4456	 *  @param {bool} bSmart perform smart filtering or not
4457	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4458	 *  @returns {RegExp} constructed object
4459	 *  @memberof DataTable#oApi
4460	 */
4461	function _fnFilterCreateSearch( search, inOpts )
4462	{
4463		var not = [];
4464		var options = $.extend({}, {
4465			boundary: false,
4466			caseInsensitive: true,
4467			exact: false,
4468			regex: false,
4469			smart: true
4470		}, inOpts);
4471	
4472		if (typeof search !== 'string') {
4473			search = search.toString();
4474		}
4475	
4476		// Remove diacritics if normalize is set up to do so
4477		search = _normalize(search);
4478	
4479		if (options.exact) {
4480			return new RegExp(
4481				'^'+_fnEscapeRegex(search)+'$',
4482				options.caseInsensitive ? 'i' : ''
4483			);
4484		}
4485	
4486		search = options.regex ?
4487			search :
4488			_fnEscapeRegex( search );
4489		
4490		if ( options.smart ) {
4491			/* For smart filtering we want to allow the search to work regardless of
4492			 * word order. We also want double quoted text to be preserved, so word
4493			 * order is important - a la google. And a negative look around for
4494			 * finding rows which don't contain a given string.
4495			 * 
4496			 * So this is the sort of thing we want to generate:
4497			 * 
4498			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4499			 */
4500			var parts = search.match( /!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''];
4501			var a = parts.map( function ( word ) {
4502				var negative = false;
4503				var m;
4504	
4505				// Determine if it is a "does not include"
4506				if ( word.charAt(0) === '!' ) {
4507					negative = true;
4508					word = word.substring(1);
4509				}
4510	
4511				// Strip the quotes from around matched phrases
4512				if ( word.charAt(0) === '"' ) {
4513					m = word.match( /^"(.*)"$/ );
4514					word = m ? m[1] : word;
4515				}
4516				else if ( word.charAt(0) === '\u201C' ) {
4517					// Smart quote match (iPhone users)
4518					m = word.match( /^\u201C(.*)\u201D$/ );
4519					word = m ? m[1] : word;
4520				}
4521	
4522				// For our "not" case, we need to modify the string that is
4523				// allowed to match at the end of the expression.
4524				if (negative) {
4525					if (word.length > 1) {
4526						not.push('(?!'+word+')');
4527					}
4528	
4529					word = '';
4530				}
4531	
4532				return word.replace(/"/g, '');
4533			} );
4534	
4535			var match = not.length
4536				? not.join('')
4537				: '';
4538	
4539			var boundary = options.boundary
4540				? '\\b'
4541				: '';
4542	
4543			search = '^(?=.*?'+boundary+a.join( ')(?=.*?'+boundary )+')('+match+'.)*$';
4544		}
4545	
4546		return new RegExp( search, options.caseInsensitive ? 'i' : '' );
4547	}
4548	
4549	
4550	/**
4551	 * Escape a string such that it can be used in a regular expression
4552	 *  @param {string} sVal string to escape
4553	 *  @returns {string} escaped string
4554	 *  @memberof DataTable#oApi
4555	 */
4556	var _fnEscapeRegex = DataTable.util.escapeRegex;
4557	
4558	var __filter_div = $('<div>')[0];
4559	var __filter_div_textContent = __filter_div.textContent !== undefined;
4560	
4561	// Update the filtering data for each row if needed (by invalidation or first run)
4562	function _fnFilterData ( settings )
4563	{
4564		var columns = settings.aoColumns;
4565		var data = settings.aoData;
4566		var column;
4567		var j, jen, filterData, cellData, row;
4568		var wasInvalidated = false;
4569	
4570		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
4571			if (! data[rowIdx]) {
4572				continue;
4573			}
4574	
4575			row = data[rowIdx];
4576	
4577			if ( ! row._aFilterData ) {
4578				filterData = [];
4579	
4580				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4581					column = columns[j];
4582	
4583					if ( column.bSearchable ) {
4584						cellData = _fnGetCellData( settings, rowIdx, j, 'filter' );
4585	
4586						// Search in DataTables is string based
4587						if ( cellData === null ) {
4588							cellData = '';
4589						}
4590	
4591						if ( typeof cellData !== 'string' && cellData.toString ) {
4592							cellData = cellData.toString();
4593						}
4594					}
4595					else {
4596						cellData = '';
4597					}
4598	
4599					// If it looks like there is an HTML entity in the string,
4600					// attempt to decode it so sorting works as expected. Note that
4601					// we could use a single line of jQuery to do this, but the DOM
4602					// method used here is much faster https://jsperf.com/html-decode
4603					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4604						__filter_div.innerHTML = cellData;
4605						cellData = __filter_div_textContent ?
4606							__filter_div.textContent :
4607							__filter_div.innerText;
4608					}
4609	
4610					if ( cellData.replace ) {
4611						cellData = cellData.replace(/[\r\n\u2028]/g, '');
4612					}
4613	
4614					filterData.push( cellData );
4615				}
4616	
4617				row._aFilterData = filterData;
4618				row._sFilterRow = filterData.join('  ');
4619				wasInvalidated = true;
4620			}
4621		}
4622	
4623		return wasInvalidated;
4624	}
4625	
4626	
4627	/**
4628	 * Draw the table for the first time, adding all required features
4629	 *  @param {object} settings dataTables settings object
4630	 *  @memberof DataTable#oApi
4631	 */
4632	function _fnInitialise ( settings )
4633	{
4634		var i, iAjaxStart=settings.iInitDisplayStart;
4635	
4636		/* Ensure that the table data is fully initialised */
4637		if ( ! settings.bInitialised ) {
4638			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4639			return;
4640		}
4641	
4642		/* Build and draw the header / footer for the table */
4643		_fnBuildHead( settings, 'header' );
4644		_fnBuildHead( settings, 'footer' );
4645		_fnDrawHead( settings, settings.aoHeader );
4646		_fnDrawHead( settings, settings.aoFooter );
4647	
4648		// Enable features
4649		_fnAddOptionsHtml( settings );
4650		_fnSortInit( settings );
4651	
4652		_colGroup( settings );
4653	
4654		/* Okay to show that something is going on now */
4655		_fnProcessingDisplay( settings, true );
4656	
4657		_fnCallbackFire( settings, null, 'preInit', [settings], true );
4658	
4659		// If there is default sorting required - let's do it. The sort function
4660		// will do the drawing for us. Otherwise we draw the table regardless of the
4661		// Ajax source - this allows the table to look initialised for Ajax sourcing
4662		// data (show 'loading' message possibly)
4663		_fnReDraw( settings );
4664	
4665		var dataSrc = _fnDataSource( settings );
4666	
4667		// Server-side processing init complete is done by _fnAjaxUpdateDraw
4668		if ( dataSrc != 'ssp' ) {
4669			// if there is an ajax source load the data
4670			if ( dataSrc == 'ajax' ) {
4671				_fnBuildAjax( settings, {}, function(json) {
4672					var aData = _fnAjaxDataSrc( settings, json );
4673	
4674					// Got the data - add it to the table
4675					for ( i=0 ; i<aData.length ; i++ ) {
4676						_fnAddData( settings, aData[i] );
4677					}
4678	
4679					// Reset the init display for cookie saving. We've already done
4680					// a filter, and therefore cleared it before. So we need to make
4681					// it appear 'fresh'
4682					settings.iInitDisplayStart = iAjaxStart;
4683	
4684					_fnReDraw( settings );
4685					_fnProcessingDisplay( settings, false );
4686					_fnInitComplete( settings );
4687				}, settings );
4688			}
4689			else {
4690				_fnInitComplete( settings );
4691				_fnProcessingDisplay( settings, false );
4692			}
4693		}
4694	}
4695	
4696	
4697	/**
4698	 * Draw the table for the first time, adding all required features
4699	 *  @param {object} settings dataTables settings object
4700	 *  @memberof DataTable#oApi
4701	 */
4702	function _fnInitComplete ( settings )
4703	{
4704		if (settings._bInitComplete) {
4705			return;
4706		}
4707	
4708		var args = [settings, settings.json];
4709	
4710		settings._bInitComplete = true;
4711	
4712		// Table is fully set up and we have data, so calculate the
4713		// column widths
4714		_fnAdjustColumnSizing( settings );
4715	
4716		_fnCallbackFire( settings, null, 'plugin-init', args, true );
4717		_fnCallbackFire( settings, 'aoInitComplete', 'init', args, true );
4718	}
4719	
4720	function _fnLengthChange ( settings, val )
4721	{
4722		var len = parseInt( val, 10 );
4723		settings._iDisplayLength = len;
4724	
4725		_fnLengthOverflow( settings );
4726	
4727		// Fire length change event
4728		_fnCallbackFire( settings, null, 'length', [settings, len] );
4729	}
4730	
4731	/**
4732	 * Alter the display settings to change the page
4733	 *  @param {object} settings DataTables settings object
4734	 *  @param {string|int} action Paging action to take: "first", "previous",
4735	 *    "next" or "last" or page number to jump to (integer)
4736	 *  @param [bool] redraw Automatically draw the update or not
4737	 *  @returns {bool} true page has changed, false - no change
4738	 *  @memberof DataTable#oApi
4739	 */
4740	function _fnPageChange ( settings, action, redraw )
4741	{
4742		var
4743			start     = settings._iDisplayStart,
4744			len       = settings._iDisplayLength,
4745			records   = settings.fnRecordsDisplay();
4746	
4747		if ( records === 0 || len === -1 )
4748		{
4749			start = 0;
4750		}
4751		else if ( typeof action === "number" )
4752		{
4753			start = action * len;
4754	
4755			if ( start > records )
4756			{
4757				start = 0;
4758			}
4759		}
4760		else if ( action == "first" )
4761		{
4762			start = 0;
4763		}
4764		else if ( action == "previous" )
4765		{
4766			start = len >= 0 ?
4767				start - len :
4768				0;
4769	
4770			if ( start < 0 )
4771			{
4772				start = 0;
4773			}
4774		}
4775		else if ( action == "next" )
4776		{
4777			if ( start + len < records )
4778			{
4779				start += len;
4780			}
4781		}
4782		else if ( action == "last" )
4783		{
4784			start = Math.floor( (records-1) / len) * len;
4785		}
4786		else if ( action === 'ellipsis' )
4787		{
4788			return;
4789		}
4790		else
4791		{
4792			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4793		}
4794	
4795		var changed = settings._iDisplayStart !== start;
4796		settings._iDisplayStart = start;
4797	
4798		_fnCallbackFire( settings, null, changed ? 'page' : 'page-nc', [settings] );
4799	
4800		if ( changed && redraw ) {
4801			_fnDraw( settings );
4802		}
4803	
4804		return changed;
4805	}
4806	
4807	
4808	/**
4809	 * Generate the node required for the processing node
4810	 *  @param {object} settings DataTables settings object
4811	 */
4812	function _processingHtml ( settings )
4813	{
4814		var table = settings.nTable;
4815	
4816		if ( settings.oFeatures.bProcessing ) {
4817			var n = $('<div/>', {
4818					'id': settings.sTableId + '_processing',
4819					'class': settings.oClasses.processing.container,
4820					'role': 'status'
4821				} )
4822				.html( settings.oLanguage.sProcessing )
4823				.append('<div><div></div><div></div><div></div><div></div></div>')
4824				.insertBefore( table );
4825			
4826			$(table).on( 'processing.dt.DT', function (e, s, show) {
4827				n.css( 'display', show ? 'block' : 'none' );
4828			} );
4829		}
4830	}
4831	
4832	
4833	/**
4834	 * Display or hide the processing indicator
4835	 *  @param {object} settings DataTables settings object
4836	 *  @param {bool} show Show the processing indicator (true) or not (false)
4837	 */
4838	function _fnProcessingDisplay ( settings, show )
4839	{
4840		_fnCallbackFire( settings, null, 'processing', [settings, show] );
4841	}
4842	/**
4843	 * Add any control elements for the table - specifically scrolling
4844	 *  @param {object} settings dataTables settings object
4845	 *  @returns {node} Node to add to the DOM
4846	 *  @memberof DataTable#oApi
4847	 */
4848	function _fnFeatureHtmlTable ( settings )
4849	{
4850		var table = $(settings.nTable);
4851	
4852		// Scrolling from here on in
4853		var scroll = settings.oScroll;
4854	
4855		if ( scroll.sX === '' && scroll.sY === '' ) {
4856			return settings.nTable;
4857		}
4858	
4859		var scrollX = scroll.sX;
4860		var scrollY = scroll.sY;
4861		var classes = settings.oClasses.scrolling;
4862		var caption = settings.captionNode;
4863		var captionSide = caption ? caption._captionSide : null;
4864		var headerClone = $( table[0].cloneNode(false) );
4865		var footerClone = $( table[0].cloneNode(false) );
4866		var footer = table.children('tfoot');
4867		var _div = '<div/>';
4868		var size = function ( s ) {
4869			return !s ? null : _fnStringToCss( s );
4870		};
4871	
4872		if ( ! footer.length ) {
4873			footer = null;
4874		}
4875	
4876		/*
4877		 * The HTML structure that we want to generate in this function is:
4878		 *  div - scroller
4879		 *    div - scroll head
4880		 *      div - scroll head inner
4881		 *        table - scroll head table
4882		 *          thead - thead
4883		 *    div - scroll body
4884		 *      table - table (master table)
4885		 *        thead - thead clone for sizing
4886		 *        tbody - tbody
4887		 *    div - scroll foot
4888		 *      div - scroll foot inner
4889		 *        table - scroll foot table
4890		 *          tfoot - tfoot
4891		 */
4892		var scroller = $( _div, { 'class': classes.container } )
4893			.append(
4894				$(_div, { 'class': classes.header.self } )
4895					.css( {
4896						overflow: 'hidden',
4897						position: 'relative',
4898						border: 0,
4899						width: scrollX ? size(scrollX) : '100%'
4900					} )
4901					.append(
4902						$(_div, { 'class': classes.header.inner } )
4903							.css( {
4904								'box-sizing': 'content-box',
4905								width: scroll.sXInner || '100%'
4906							} )
4907							.append(
4908								headerClone
4909									.removeAttr('id')
4910									.css( 'margin-left', 0 )
4911									.append( captionSide === 'top' ? caption : null )
4912									.append(
4913										table.children('thead')
4914									)
4915							)
4916					)
4917			)
4918			.append(
4919				$(_div, { 'class': classes.body } )
4920					.css( {
4921						position: 'relative',
4922						overflow: 'auto',
4923						width: size( scrollX )
4924					} )
4925					.append( table )
4926			);
4927	
4928		if ( footer ) {
4929			scroller.append(
4930				$(_div, { 'class': classes.footer.self } )
4931					.css( {
4932						overflow: 'hidden',
4933						border: 0,
4934						width: scrollX ? size(scrollX) : '100%'
4935					} )
4936					.append(
4937						$(_div, { 'class': classes.footer.inner } )
4938							.append(
4939								footerClone
4940									.removeAttr('id')
4941									.css( 'margin-left', 0 )
4942									.append( captionSide === 'bottom' ? caption : null )
4943									.append(
4944										table.children('tfoot')
4945									)
4946							)
4947					)
4948			);
4949		}
4950	
4951		var children = scroller.children();
4952		var scrollHead = children[0];
4953		var scrollBody = children[1];
4954		var scrollFoot = footer ? children[2] : null;
4955	
4956		// When the body is scrolled, then we also want to scroll the headers
4957		$(scrollBody).on( 'scroll.DT', function () {
4958			var scrollLeft = this.scrollLeft;
4959	
4960			scrollHead.scrollLeft = scrollLeft;
4961	
4962			if ( footer ) {
4963				scrollFoot.scrollLeft = scrollLeft;
4964			}
4965		} );
4966	
4967		// When focus is put on the header cells, we might need to scroll the body
4968		$('th, td', scrollHead).on('focus', function () {
4969			var scrollLeft = scrollHead.scrollLeft;
4970	
4971			scrollBody.scrollLeft = scrollLeft;
4972	
4973			if ( footer ) {
4974				scrollBody.scrollLeft = scrollLeft;
4975			}
4976		});
4977	
4978		$(scrollBody).css('max-height', scrollY);
4979		if (! scroll.bCollapse) {
4980			$(scrollBody).css('height', scrollY);
4981		}
4982	
4983		settings.nScrollHead = scrollHead;
4984		settings.nScrollBody = scrollBody;
4985		settings.nScrollFoot = scrollFoot;
4986	
4987		// On redraw - align columns
4988		settings.aoDrawCallback.push(_fnScrollDraw);
4989	
4990		return scroller[0];
4991	}
4992	
4993	
4994	
4995	/**
4996	 * Update the header, footer and body tables for resizing - i.e. column
4997	 * alignment.
4998	 *
4999	 * Welcome to the most horrible function DataTables. The process that this
5000	 * function follows is basically:
5001	 *   1. Re-create the table inside the scrolling div
5002	 *   2. Correct colgroup > col values if needed
5003	 *   3. Copy colgroup > col over to header and footer
5004	 *   4. Clean up
5005	 *
5006	 *  @param {object} settings dataTables settings object
5007	 *  @memberof DataTable#oApi
5008	 */
5009	function _fnScrollDraw ( settings )
5010	{
5011		// Given that this is such a monster function, a lot of variables are use
5012		// to try and keep the minimised size as small as possible
5013		var
5014			scroll         = settings.oScroll,
5015			barWidth       = scroll.iBarWidth,
5016			divHeader      = $(settings.nScrollHead),
5017			divHeaderInner = divHeader.children('div'),
5018			divHeaderTable = divHeaderInner.children('table'),
5019			divBodyEl      = settings.nScrollBody,
5020			divBody        = $(divBodyEl),
5021			divFooter      = $(settings.nScrollFoot),
5022			divFooterInner = divFooter.children('div'),
5023			divFooterTable = divFooterInner.children('table'),
5024			header         = $(settings.nTHead),
5025			table          = $(settings.nTable),
5026			footer         = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
5027			browser        = settings.oBrowser,
5028			headerCopy, footerCopy;
5029	
5030		// If the scrollbar visibility has changed from the last draw, we need to
5031		// adjust the column sizes as the table width will have changed to account
5032		// for the scrollbar
5033		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5034		
5035		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5036			settings.scrollBarVis = scrollBarVis;
5037			_fnAdjustColumnSizing( settings );
5038			return; // adjust column sizing will call this function again
5039		}
5040		else {
5041			settings.scrollBarVis = scrollBarVis;
5042		}
5043	
5044		// 1. Re-create the table inside the scrolling div
5045		// Remove the old minimised thead and tfoot elements in the inner table
5046		table.children('thead, tfoot').remove();
5047	
5048		// Clone the current header and footer elements and then place it into the inner table
5049		headerCopy = header.clone().prependTo( table );
5050		headerCopy.find('th, td').removeAttr('tabindex');
5051		headerCopy.find('[id]').removeAttr('id');
5052	
5053		if ( footer ) {
5054			footerCopy = footer.clone().prependTo( table );
5055			footerCopy.find('[id]').removeAttr('id');
5056		}
5057	
5058		// 2. Correct colgroup > col values if needed
5059		// It is possible that the cell sizes are smaller than the content, so we need to
5060		// correct colgroup>col for such cases. This can happen if the auto width detection
5061		// uses a cell which has a longer string, but isn't the widest! For example 
5062		// "Chief Executive Officer (CEO)" is the longest string in the demo, but
5063		// "Systems Administrator" is actually the widest string since it doesn't collapse.
5064		// Note the use of translating into a column index to get the `col` element. This
5065		// is because of Responsive which might remove `col` elements, knocking the alignment
5066		// of the indexes out.
5067		if (settings.aiDisplay.length) {
5068			// Get the column sizes from the first row in the table
5069			var colSizes = table.find('tbody tr').eq(0).find('th, td').map(function (vis) {
5070				return {
5071					idx: _fnVisibleToColumnIndex(settings, vis),
5072					width: $(this).outerWidth()
5073				}
5074			});
5075	
5076			// Check against what the colgroup > col is set to and correct if needed
5077			for (var i=0 ; i<colSizes.length ; i++) {
5078				var colEl = settings.aoColumns[ colSizes[i].idx ].colEl[0];
5079				var colWidth = colEl.style.width.replace('px', '');
5080	
5081				if (colWidth !== colSizes[i].width) {
5082					colEl.style.width = colSizes[i].width + 'px';
5083				}
5084			}
5085		}
5086	
5087		// 3. Copy the colgroup over to the header and footer
5088		divHeaderTable
5089			.find('colgroup')
5090			.remove();
5091	
5092		divHeaderTable.append(settings.colgroup.clone());
5093	
5094		if ( footer ) {
5095			divFooterTable
5096				.find('colgroup')
5097				.remove();
5098	
5099			divFooterTable.append(settings.colgroup.clone());
5100		}
5101	
5102		// "Hide" the header and footer that we used for the sizing. We need to keep
5103		// the content of the cell so that the width applied to the header and body
5104		// both match, but we want to hide it completely.
5105		$('th, td', headerCopy).each(function () {
5106			$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5107		});
5108	
5109		if ( footer ) {
5110			$('th, td', footerCopy).each(function () {
5111				$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5112			});
5113		}
5114	
5115		// 4. Clean up
5116		// Figure out if there are scrollbar present - if so then we need a the header and footer to
5117		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5118		var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5119		var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5120	
5121		// Set the width's of the header and footer tables
5122		var outerWidth = table.outerWidth();
5123	
5124		divHeaderTable.css('width', _fnStringToCss( outerWidth ));
5125		divHeaderInner
5126			.css('width', _fnStringToCss( outerWidth ))
5127			.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5128	
5129		if ( footer ) {
5130			divFooterTable.css('width', _fnStringToCss( outerWidth ));
5131			divFooterInner
5132				.css('width', _fnStringToCss( outerWidth ))
5133				.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5134		}
5135	
5136		// Correct DOM ordering for colgroup - comes before the thead
5137		table.children('colgroup').prependTo(table);
5138	
5139		// Adjust the position of the header in case we loose the y-scrollbar
5140		divBody.trigger('scroll');
5141	
5142		// If sorting or filtering has occurred, jump the scrolling back to the top
5143		// only if we aren't holding the position
5144		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5145			divBodyEl.scrollTop = 0;
5146		}
5147	}
5148	
5149	/**
5150	 * Calculate the width of columns for the table
5151	 *  @param {object} settings dataTables settings object
5152	 *  @memberof DataTable#oApi
5153	 */
5154	function _fnCalculateColumnWidths ( settings )
5155	{
5156		// Not interested in doing column width calculation if auto-width is disabled
5157		if (! settings.oFeatures.bAutoWidth) {
5158			return;
5159		}
5160	
5161		var
5162			table = settings.nTable,
5163			columns = settings.aoColumns,
5164			scroll = settings.oScroll,
5165			scrollY = scroll.sY,
5166			scrollX = scroll.sX,
5167			scrollXInner = scroll.sXInner,
5168			visibleColumns = _fnGetColumns( settings, 'bVisible' ),
5169			tableWidthAttr = table.getAttribute('width'), // from DOM element
5170			tableContainer = table.parentNode,
5171			i, column, columnIdx;
5172	
5173		var styleWidth = table.style.width;
5174		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5175			tableWidthAttr = styleWidth;
5176		}
5177	
5178		// Let plug-ins know that we are doing a recalc, in case they have changed any of the
5179		// visible columns their own way (e.g. Responsive uses display:none).
5180		_fnCallbackFire(
5181			settings,
5182			null,
5183			'column-calc',
5184			{visible: visibleColumns},
5185			false
5186		);
5187	
5188		// Construct a single row, worst case, table with the widest
5189		// node in the data, assign any user defined widths, then insert it into
5190		// the DOM and allow the browser to do all the hard work of calculating
5191		// table widths
5192		var tmpTable = $(table.cloneNode())
5193			.css( 'visibility', 'hidden' )
5194			.removeAttr( 'id' );
5195	
5196		// Clean up the table body
5197		tmpTable.append('<tbody>')
5198		var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5199	
5200		// Clone the table header and footer - we can't use the header / footer
5201		// from the cloned table, since if scrolling is active, the table's
5202		// real header and footer are contained in different table tags
5203		tmpTable
5204			.append( $(settings.nTHead).clone() )
5205			.append( $(settings.nTFoot).clone() );
5206	
5207		// Remove any assigned widths from the footer (from scrolling)
5208		tmpTable.find('tfoot th, tfoot td').css('width', '');
5209	
5210		// Apply custom sizing to the cloned header
5211		tmpTable.find('thead th, thead td').each( function () {
5212			// Get the `width` from the header layout
5213			var width = _fnColumnsSumWidth( settings, this, true, false );
5214	
5215			if ( width ) {
5216				this.style.width = width;
5217	
5218				// For scrollX we need to force the column width otherwise the
5219				// browser will collapse it. If this width is smaller than the
5220				// width the column requires, then it will have no effect
5221				if ( scrollX ) {
5222					$( this ).append( $('<div/>').css( {
5223						width: width,
5224						margin: 0,
5225						padding: 0,
5226						border: 0,
5227						height: 1
5228					} ) );
5229				}
5230			}
5231			else {
5232				this.style.width = '';
5233			}
5234		} );
5235	
5236		// Find the widest piece of data for each column and put it into the table
5237		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5238			columnIdx = visibleColumns[i];
5239			column = columns[ columnIdx ];
5240	
5241			var longest = _fnGetMaxLenString(settings, columnIdx);
5242			var autoClass = _ext.type.className[column.sType];
5243			var text = longest + column.sContentPadding;
5244			var insert = longest.indexOf('<') === -1
5245				? document.createTextNode(text)
5246				: text
5247			
5248			$('<td/>')
5249				.addClass(autoClass)
5250				.addClass(column.sClass)
5251				.append(insert)
5252				.appendTo(tr);
5253		}
5254	
5255		// Tidy the temporary table - remove name attributes so there aren't
5256		// duplicated in the dom (radio elements for example)
5257		$('[name]', tmpTable).removeAttr('name');
5258	
5259		// Table has been built, attach to the document so we can work with it.
5260		// A holding element is used, positioned at the top of the container
5261		// with minimal height, so it has no effect on if the container scrolls
5262		// or not. Otherwise it might trigger scrolling when it actually isn't
5263		// needed
5264		var holder = $('<div/>').css( scrollX || scrollY ?
5265				{
5266					position: 'absolute',
5267					top: 0,
5268					left: 0,
5269					height: 1,
5270					right: 0,
5271					overflow: 'hidden'
5272				} :
5273				{}
5274			)
5275			.append( tmpTable )
5276			.appendTo( tableContainer );
5277	
5278		// When scrolling (X or Y) we want to set the width of the table as 
5279		// appropriate. However, when not scrolling leave the table width as it
5280		// is. This results in slightly different, but I think correct behaviour
5281		if ( scrollX && scrollXInner ) {
5282			tmpTable.width( scrollXInner );
5283		}
5284		else if ( scrollX ) {
5285			tmpTable.css( 'width', 'auto' );
5286			tmpTable.removeAttr('width');
5287	
5288			// If there is no width attribute or style, then allow the table to
5289			// collapse
5290			if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5291				tmpTable.width( tableContainer.clientWidth );
5292			}
5293		}
5294		else if ( scrollY ) {
5295			tmpTable.width( tableContainer.clientWidth );
5296		}
5297		else if ( tableWidthAttr ) {
5298			tmpTable.width( tableWidthAttr );
5299		}
5300	
5301		// Get the width of each column in the constructed table
5302		var total = 0;
5303		var bodyCells = tmpTable.find('tbody tr').eq(0).children();
5304	
5305		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5306			// Use getBounding for sub-pixel accuracy, which we then want to round up!
5307			var bounding = bodyCells[i].getBoundingClientRect().width;
5308	
5309			// Total is tracked to remove any sub-pixel errors as the outerWidth
5310			// of the table might not equal the total given here
5311			total += bounding;
5312	
5313			// Width for each column to use
5314			columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding );
5315		}
5316	
5317		table.style.width = _fnStringToCss( total );
5318	
5319		// Finished with the table - ditch it
5320		holder.remove();
5321	
5322		// If there is a width attr, we want to attach an event listener which
5323		// allows the table sizing to automatically adjust when the window is
5324		// resized. Use the width attr rather than CSS, since we can't know if the
5325		// CSS is a relative value or absolute - DOM read is always px.
5326		if ( tableWidthAttr ) {
5327			table.style.width = _fnStringToCss( tableWidthAttr );
5328		}
5329	
5330		if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
5331			var bindResize = function () {
5332				$(window).on('resize.DT-'+settings.sInstance, DataTable.util.throttle( function () {
5333					if (! settings.bDestroying) {
5334						_fnAdjustColumnSizing( settings );
5335					}
5336				} ) );
5337			};
5338	
5339			bindResize();
5340	
5341			settings._reszEvt = true;
5342		}
5343	}
5344	
5345	
5346	/**
5347	 * Get the maximum strlen for each data column
5348	 *  @param {object} settings dataTables settings object
5349	 *  @param {int} colIdx column of interest
5350	 *  @returns {string} string of the max length
5351	 *  @memberof DataTable#oApi
5352	 */
5353	function _fnGetMaxLenString( settings, colIdx )
5354	{
5355		var column = settings.aoColumns[colIdx];
5356	
5357		if (! column.maxLenString) {
5358			var s, max='', maxLen = -1;
5359		
5360			for ( var i=0, ien=settings.aiDisplayMaster.length ; i<ien ; i++ ) {
5361				var rowIdx = settings.aiDisplayMaster[i];
5362				var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
5363	
5364				var cellString = data && typeof data === 'object' && data.nodeType
5365					? data.innerHTML
5366					: data+'';
5367	
5368				// Remove id / name attributes from elements so they
5369				// don't interfere with existing elements
5370				cellString = cellString
5371					.replace(/id=".*?"/g, '')
5372					.replace(/name=".*?"/g, '');
5373	
5374				s = _stripHtml(cellString)
5375					.replace( /&nbsp;/g, ' ' );
5376		
5377				if ( s.length > maxLen ) {
5378					// We want the HTML in the string, but the length that
5379					// is important is the stripped string
5380					max = cellString;
5381					maxLen = s.length;
5382				}
5383			}
5384	
5385			column.maxLenString = max;
5386		}
5387	
5388		return column.maxLenString;
5389	}
5390	
5391	
5392	/**
5393	 * Append a CSS unit (only if required) to a string
5394	 *  @param {string} value to css-ify
5395	 *  @returns {string} value with css unit
5396	 *  @memberof DataTable#oApi
5397	 */
5398	function _fnStringToCss( s )
5399	{
5400		if ( s === null ) {
5401			return '0px';
5402		}
5403	
5404		if ( typeof s == 'number' ) {
5405			return s < 0 ?
5406				'0px' :
5407				s+'px';
5408		}
5409	
5410		// Check it has a unit character already
5411		return s.match(/\d$/) ?
5412			s+'px' :
5413			s;
5414	}
5415	
5416	/**
5417	 * Re-insert the `col` elements for current visibility
5418	 *
5419	 * @param {*} settings DT settings
5420	 */
5421	function _colGroup( settings ) {
5422		var cols = settings.aoColumns;
5423	
5424		settings.colgroup.empty();
5425	
5426		for (i=0 ; i<cols.length ; i++) {
5427			if (cols[i].bVisible) {
5428				settings.colgroup.append(cols[i].colEl);
5429			}
5430		}
5431	}
5432	
5433	
5434	function _fnSortInit( settings ) {
5435		var target = settings.nTHead;
5436		var headerRows = target.querySelectorAll('tr');
5437		var legacyTop = settings.bSortCellsTop;
5438		var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5439		
5440		// Legacy support for `orderCellsTop`
5441		if (legacyTop === true) {
5442			target = headerRows[0];
5443		}
5444		else if (legacyTop === false) {
5445			target = headerRows[ headerRows.length - 1 ];
5446		}
5447	
5448		_fnSortAttachListener(
5449			settings,
5450			target,
5451			target === settings.nTHead
5452				? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5453				: 'th'+notSelector+', td'+notSelector
5454		);
5455	
5456		// Need to resolve the user input array into our internal structure
5457		var order = [];
5458		_fnSortResolve( settings, order, settings.aaSorting );
5459	
5460		settings.aaSorting = order;
5461	}
5462	
5463	
5464	function _fnSortAttachListener(settings, node, selector, column, callback) {
5465		_fnBindAction( node, selector, function (e) {
5466			var run = false;
5467			var columns = column === undefined
5468				? _fnColumnsFromHeader( e.target )
5469				: [column];
5470	
5471			if ( columns.length ) {
5472				for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
5473					var ret = _fnSortAdd( settings, columns[i], i, e.shiftKey );
5474	
5475					if (ret !== false) {
5476						run = true;
5477					}					
5478	
5479					// If the first entry is no sort, then subsequent
5480					// sort columns are ignored
5481					if (settings.aaSorting.length === 1 && settings.aaSorting[0][1] === '') {
5482						break;
5483					}
5484				}
5485	
5486				if (run) {
5487					_fnProcessingDisplay( settings, true );
5488	
5489					// Allow the processing display to show
5490					setTimeout( function () {
5491						_fnSort( settings );
5492						_fnSortDisplay( settings, settings.aiDisplay );
5493	
5494						// Sort processing done - redraw has its own processing display
5495						_fnProcessingDisplay( settings, false );
5496	
5497						_fnReDraw( settings, false, false );
5498	
5499						if (callback) {
5500							callback();
5501						}
5502					}, 0);
5503				}
5504			}
5505		} );
5506	}
5507	
5508	/**
5509	 * Sort the display array to match the master's order
5510	 * @param {*} settings
5511	 */
5512	function _fnSortDisplay(settings, display) {
5513		var master = settings.aiDisplayMaster;
5514		var masterMap = {};
5515		var map = {};
5516		var i;
5517	
5518		// Rather than needing an `indexOf` on master array, we can create a map
5519		for (i=0 ; i<master.length ; i++) {
5520			masterMap[master[i]] = i;
5521		}
5522	
5523		// And then cache what would be the indexOf fom the display
5524		for (i=0 ; i<display.length ; i++) {
5525			map[display[i]] = masterMap[display[i]];
5526		}
5527	
5528		display.sort(function(a, b){
5529			// Short version of this function is simply `master.indexOf(a) - master.indexOf(b);`
5530			return map[a] - map[b];
5531		});
5532	}
5533	
5534	
5535	function _fnSortResolve (settings, nestedSort, sort) {
5536		var push = function ( a ) {
5537			if ($.isPlainObject(a)) {
5538				if (a.idx !== undefined) {
5539					// Index based ordering
5540					nestedSort.push([a.idx, a.dir]);
5541				}
5542				else if (a.name) {
5543					// Name based ordering
5544					var cols = _pluck( settings.aoColumns, 'sName');
5545					var idx = cols.indexOf(a.name);
5546	
5547					if (idx !== -1) {
5548						nestedSort.push([idx, a.dir]);
5549					}
5550				}
5551			}
5552			else {
5553				// Plain column index and direction pair
5554				nestedSort.push(a);
5555			}
5556		};
5557	
5558		if ( $.isPlainObject(sort) ) {
5559			// Object
5560			push(sort);
5561		}
5562		else if ( sort.length && typeof sort[0] === 'number' ) {
5563			// 1D array
5564			push(sort);
5565		}
5566		else if ( sort.length ) {
5567			// 2D array
5568			for (var z=0; z<sort.length; z++) {
5569				push(sort[z]); // Object or array
5570			}
5571		}
5572	}
5573	
5574	
5575	function _fnSortFlatten ( settings )
5576	{
5577		var
5578			i, k, kLen,
5579			aSort = [],
5580			extSort = DataTable.ext.type.order,
5581			aoColumns = settings.aoColumns,
5582			aDataSort, iCol, sType, srcCol,
5583			fixed = settings.aaSortingFixed,
5584			fixedObj = $.isPlainObject( fixed ),
5585			nestedSort = [];
5586		
5587		if ( ! settings.oFeatures.bSort ) {
5588			return aSort;
5589		}
5590	
5591		// Build the sort array, with pre-fix and post-fix options if they have been
5592		// specified
5593		if ( Array.isArray( fixed ) ) {
5594			_fnSortResolve( settings, nestedSort, fixed );
5595		}
5596	
5597		if ( fixedObj && fixed.pre ) {
5598			_fnSortResolve( settings, nestedSort, fixed.pre );
5599		}
5600	
5601		_fnSortResolve( settings, nestedSort, settings.aaSorting );
5602	
5603		if (fixedObj && fixed.post ) {
5604			_fnSortResolve( settings, nestedSort, fixed.post );
5605		}
5606	
5607		for ( i=0 ; i<nestedSort.length ; i++ )
5608		{
5609			srcCol = nestedSort[i][0];
5610	
5611			if ( aoColumns[ srcCol ] ) {
5612				aDataSort = aoColumns[ srcCol ].aDataSort;
5613	
5614				for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5615				{
5616					iCol = aDataSort[k];
5617					sType = aoColumns[ iCol ].sType || 'string';
5618	
5619					if ( nestedSort[i]._idx === undefined ) {
5620						nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
5621					}
5622	
5623					if ( nestedSort[i][1] ) {
5624						aSort.push( {
5625							src:       srcCol,
5626							col:       iCol,
5627							dir:       nestedSort[i][1],
5628							index:     nestedSort[i]._idx,
5629							type:      sType,
5630							formatter: extSort[ sType+"-pre" ],
5631							sorter:    extSort[ sType+"-"+nestedSort[i][1] ]
5632						} );
5633					}
5634				}
5635			}
5636		}
5637	
5638		return aSort;
5639	}
5640	
5641	/**
5642	 * Change the order of the table
5643	 *  @param {object} oSettings dataTables settings object
5644	 *  @memberof DataTable#oApi
5645	 */
5646	function _fnSort ( oSettings, col, dir )
5647	{
5648		var
5649			i, ien, iLen,
5650			aiOrig = [],
5651			extSort = DataTable.ext.type.order,
5652			aoData = oSettings.aoData,
5653			sortCol,
5654			displayMaster = oSettings.aiDisplayMaster,
5655			aSort;
5656	
5657		// Resolve any column types that are unknown due to addition or invalidation
5658		// @todo Can this be moved into a 'data-ready' handler which is called when
5659		//   data is going to be used in the table?
5660		_fnColumnTypes( oSettings );
5661	
5662		// Allow a specific column to be sorted, which will _not_ alter the display
5663		// master
5664		if (col !== undefined) {
5665			var srcCol = oSettings.aoColumns[col];
5666			aSort = [{
5667				src:       col,
5668				col:       col,
5669				dir:       dir,
5670				index:     0,
5671				type:      srcCol.sType,
5672				formatter: extSort[ srcCol.sType+"-pre" ],
5673				sorter:    extSort[ srcCol.sType+"-"+dir ]
5674			}];
5675			displayMaster = displayMaster.slice();
5676		}
5677		else {
5678			aSort = _fnSortFlatten( oSettings );
5679		}
5680	
5681		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5682			sortCol = aSort[i];
5683	
5684			// Load the data needed for the sort, for each cell
5685			_fnSortData( oSettings, sortCol.col );
5686		}
5687	
5688		/* No sorting required if server-side or no sorting array */
5689		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5690		{
5691			// Reset the initial positions on each pass so we get a stable sort
5692			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5693				aiOrig[ i ] = i;
5694			}
5695	
5696			// If the first sort is desc, then reverse the array to preserve original
5697			// order, just in reverse
5698			if (aSort.length && aSort[0].dir === 'desc') {
5699				aiOrig.reverse();
5700			}
5701	
5702			/* Do the sort - here we want multi-column sorting based on a given data source (column)
5703			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5704			 * follow on it's own, but this is what we want (example two column sorting):
5705			 *  fnLocalSorting = function(a,b){
5706			 *    var test;
5707			 *    test = oSort['string-asc']('data11', 'data12');
5708			 *      if (test !== 0)
5709			 *        return test;
5710			 *    test = oSort['numeric-desc']('data21', 'data22');
5711			 *    if (test !== 0)
5712			 *      return test;
5713			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5714			 *  }
5715			 * Basically we have a test for each sorting column, if the data in that column is equal,
5716			 * test the next column. If all columns match, then we use a numeric sort on the row
5717			 * positions in the original data array to provide a stable sort.
5718			 */
5719			displayMaster.sort( function ( a, b ) {
5720				var
5721					x, y, k, test, sort,
5722					len=aSort.length,
5723					dataA = aoData[a]._aSortData,
5724					dataB = aoData[b]._aSortData;
5725	
5726				for ( k=0 ; k<len ; k++ ) {
5727					sort = aSort[k];
5728	
5729					// Data, which may have already been through a `-pre` function
5730					x = dataA[ sort.col ];
5731					y = dataB[ sort.col ];
5732	
5733					if (sort.sorter) {
5734						// If there is a custom sorter (`-asc` or `-desc`) for this
5735						// data type, use it
5736						test = sort.sorter(x, y);
5737	
5738						if ( test !== 0 ) {
5739							return test;
5740						}
5741					}
5742					else {
5743						// Otherwise, use generic sorting
5744						test = x<y ? -1 : x>y ? 1 : 0;
5745	
5746						if ( test !== 0 ) {
5747							return sort.dir === 'asc' ? test : -test;
5748						}
5749					}
5750				}
5751	
5752				x = aiOrig[a];
5753				y = aiOrig[b];
5754	
5755				return x<y ? -1 : x>y ? 1 : 0;
5756			} );
5757		}
5758		else if ( aSort.length === 0 ) {
5759			// Apply index order
5760			displayMaster.sort(function (x, y) {
5761				return x<y ? -1 : x>y ? 1 : 0;
5762			});
5763		}
5764	
5765		if (col === undefined) {
5766			// Tell the draw function that we have sorted the data
5767			oSettings.bSorted = true;
5768	
5769			_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort] );
5770		}
5771	
5772		return displayMaster;
5773	}
5774	
5775	
5776	/**
5777	 * Function to run on user sort request
5778	 *  @param {object} settings dataTables settings object
5779	 *  @param {node} attachTo node to attach the handler to
5780	 *  @param {int} colIdx column sorting index
5781	 *  @param {int} addIndex Counter
5782	 *  @param {boolean} [shift=false] Shift click add
5783	 *  @param {function} [callback] callback function
5784	 *  @memberof DataTable#oApi
5785	 */
5786	function _fnSortAdd ( settings, colIdx, addIndex, shift )
5787	{
5788		var col = settings.aoColumns[ colIdx ];
5789		var sorting = settings.aaSorting;
5790		var asSorting = col.asSorting;
5791		var nextSortIdx;
5792		var next = function ( a, overflow ) {
5793			var idx = a._idx;
5794			if ( idx === undefined ) {
5795				idx = asSorting.indexOf(a[1]);
5796			}
5797	
5798			return idx+1 < asSorting.length ?
5799				idx+1 :
5800				overflow ?
5801					null :
5802					0;
5803		};
5804	
5805		if ( ! col.bSortable ) {
5806			return false;
5807		}
5808	
5809		// Convert to 2D array if needed
5810		if ( typeof sorting[0] === 'number' ) {
5811			sorting = settings.aaSorting = [ sorting ];
5812		}
5813	
5814		// If appending the sort then we are multi-column sorting
5815		if ( (shift || addIndex) && settings.oFeatures.bSortMulti ) {
5816			// Are we already doing some kind of sort on this column?
5817			var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
5818	
5819			if ( sortIdx !== -1 ) {
5820				// Yes, modify the sort
5821				nextSortIdx = next( sorting[sortIdx], true );
5822	
5823				if ( nextSortIdx === null && sorting.length === 1 ) {
5824					nextSortIdx = 0; // can't remove sorting completely
5825				}
5826	
5827				if ( nextSortIdx === null ) {
5828					sorting.splice( sortIdx, 1 );
5829				}
5830				else {
5831					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
5832					sorting[sortIdx]._idx = nextSortIdx;
5833				}
5834			}
5835			else if (shift) {
5836				// No sort on this column yet, being added by shift click
5837				// add it as itself
5838				sorting.push( [ colIdx, asSorting[0], 0 ] );
5839				sorting[sorting.length-1]._idx = 0;
5840			}
5841			else {
5842				// No sort on this column yet, being added from a colspan
5843				// so add with same direction as first column
5844				sorting.push( [ colIdx, sorting[0][1], 0 ] );
5845				sorting[sorting.length-1]._idx = 0;
5846			}
5847		}
5848		else if ( sorting.length && sorting[0][0] == colIdx ) {
5849			// Single column - already sorting on this column, modify the sort
5850			nextSortIdx = next( sorting[0] );
5851	
5852			sorting.length = 1;
5853			sorting[0][1] = asSorting[ nextSortIdx ];
5854			sorting[0]._idx = nextSortIdx;
5855		}
5856		else {
5857			// Single column - sort only on this column
5858			sorting.length = 0;
5859			sorting.push( [ colIdx, asSorting[0] ] );
5860			sorting[0]._idx = 0;
5861		}
5862	}
5863	
5864	
5865	/**
5866	 * Set the sorting classes on table's body, Note: it is safe to call this function
5867	 * when bSort and bSortClasses are false
5868	 *  @param {object} oSettings dataTables settings object
5869	 *  @memberof DataTable#oApi
5870	 */
5871	function _fnSortingClasses( settings )
5872	{
5873		var oldSort = settings.aLastSort;
5874		var sortClass = settings.oClasses.order.position;
5875		var sort = _fnSortFlatten( settings );
5876		var features = settings.oFeatures;
5877		var i, ien, colIdx;
5878	
5879		if ( features.bSort && features.bSortClasses ) {
5880			// Remove old sorting classes
5881			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
5882				colIdx = oldSort[i].src;
5883	
5884				// Remove column sorting
5885				$( _pluck( settings.aoData, 'anCells', colIdx ) )
5886					.removeClass( sortClass + (i<2 ? i+1 : 3) );
5887			}
5888	
5889			// Add new column sorting
5890			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
5891				colIdx = sort[i].src;
5892	
5893				$( _pluck( settings.aoData, 'anCells', colIdx ) )
5894					.addClass( sortClass + (i<2 ? i+1 : 3) );
5895			}
5896		}
5897	
5898		settings.aLastSort = sort;
5899	}
5900	
5901	
5902	// Get the data to sort a column, be it from cache, fresh (populating the
5903	// cache), or from a sort formatter
5904	function _fnSortData( settings, colIdx )
5905	{
5906		// Custom sorting function - provided by the sort data type
5907		var column = settings.aoColumns[ colIdx ];
5908		var customSort = DataTable.ext.order[ column.sSortDataType ];
5909		var customData;
5910	
5911		if ( customSort ) {
5912			customData = customSort.call( settings.oInstance, settings, colIdx,
5913				_fnColumnIndexToVisible( settings, colIdx )
5914			);
5915		}
5916	
5917		// Use / populate cache
5918		var row, cellData;
5919		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
5920		var data = settings.aoData;
5921	
5922		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
5923			// Sparse array
5924			if (! data[rowIdx]) {
5925				continue;
5926			}
5927	
5928			row = data[rowIdx];
5929	
5930			if ( ! row._aSortData ) {
5931				row._aSortData = [];
5932			}
5933	
5934			if ( ! row._aSortData[colIdx] || customSort ) {
5935				cellData = customSort ?
5936					customData[rowIdx] : // If there was a custom sort function, use data from there
5937					_fnGetCellData( settings, rowIdx, colIdx, 'sort' );
5938	
5939				row._aSortData[ colIdx ] = formatter ?
5940					formatter( cellData, settings ) :
5941					cellData;
5942			}
5943		}
5944	}
5945	
5946	
5947	/**
5948	 * State information for a table
5949	 *
5950	 * @param {*} settings
5951	 * @returns State object
5952	 */
5953	function _fnSaveState ( settings )
5954	{
5955		if (settings._bLoadingState) {
5956			return;
5957		}
5958	
5959		/* Store the interesting variables */
5960		var state = {
5961			time:    +new Date(),
5962			start:   settings._iDisplayStart,
5963			length:  settings._iDisplayLength,
5964			order:   $.extend( true, [], settings.aaSorting ),
5965			search:  $.extend({}, settings.oPreviousSearch),
5966			columns: settings.aoColumns.map( function ( col, i ) {
5967				return {
5968					visible: col.bVisible,
5969					search: $.extend({}, settings.aoPreSearchCols[i])
5970				};
5971			} )
5972		};
5973	
5974		settings.oSavedState = state;
5975		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
5976		
vendor: 17,891 bytes, lines 5977-6561
5977		if ( settings.oFeatures.bStateSave && !settings.bDestroying )
5978		{
5979			settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
5980		}	
5981	}
5982	
5983	
5984	/**
5985	 * Attempt to load a saved table state
5986	 *  @param {object} oSettings dataTables settings object
5987	 *  @param {object} oInit DataTables init object so we can override settings
5988	 *  @param {function} callback Callback to execute when the state has been loaded
5989	 *  @memberof DataTable#oApi
5990	 */
5991	function _fnLoadState ( settings, init, callback )
5992	{
5993		if ( ! settings.oFeatures.bStateSave ) {
5994			callback();
5995			return;
5996		}
5997	
5998		var loaded = function(state) {
5999			_fnImplementState(settings, state, callback);
6000		}
6001	
6002		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6003	
6004		if ( state !== undefined ) {
6005			_fnImplementState( settings, state, callback );
6006		}
6007		// otherwise, wait for the loaded callback to be executed
6008	
6009		return true;
6010	}
6011	
6012	function _fnImplementState ( settings, s, callback) {
6013		var i, ien;
6014		var columns = settings.aoColumns;
6015		settings._bLoadingState = true;
6016	
6017		// When StateRestore was introduced the state could now be implemented at any time
6018		// Not just initialisation. To do this an api instance is required in some places
6019		var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
6020	
6021		if ( ! s || ! s.time ) {
6022			settings._bLoadingState = false;
6023			callback();
6024			return;
6025		}
6026	
6027		// Reject old data
6028		var duration = settings.iStateDuration;
6029		if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6030			settings._bLoadingState = false;
6031			callback();
6032			return;
6033		}
6034	
6035		// Allow custom and plug-in manipulation functions to alter the saved data set and
6036		// cancelling of loading by returning false
6037		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6038		if ( abStateLoad.indexOf(false) !== -1 ) {
6039			settings._bLoadingState = false;
6040			callback();
6041			return;
6042		}
6043	
6044		// Number of columns have changed - all bets are off, no restore of settings
6045		if ( s.columns && columns.length !== s.columns.length ) {
6046			settings._bLoadingState = false;
6047			callback();
6048			return;
6049		}
6050	
6051		// Store the saved state so it might be accessed at any time
6052		settings.oLoadedState = $.extend( true, {}, s );
6053	
6054		// This is needed for ColReorder, which has to happen first to allow all
6055		// the stored indexes to be usable. It is not publicly documented.
6056		_fnCallbackFire( settings, null, 'stateLoadInit', [settings, s], true );
6057	
6058		// Page Length
6059		if ( s.length !== undefined ) {
6060			// If already initialised just set the value directly so that the select element is also updated
6061			if (api) {
6062				api.page.len(s.length)
6063			}
6064			else {
6065				settings._iDisplayLength   = s.length;
6066			}
6067		}
6068	
6069		// Restore key features - todo - for 1.11 this needs to be done by
6070		// subscribed events
6071		if ( s.start !== undefined ) {
6072			if(api === null) {
6073				settings._iDisplayStart    = s.start;
6074				settings.iInitDisplayStart = s.start;
6075			}
6076			else {
6077				_fnPageChange(settings, s.start/settings._iDisplayLength);
6078			}
6079		}
6080	
6081		// Order
6082		if ( s.order !== undefined ) {
6083			settings.aaSorting = [];
6084			$.each( s.order, function ( i, col ) {
6085				settings.aaSorting.push( col[0] >= columns.length ?
6086					[ 0, col[1] ] :
6087					col
6088				);
6089			} );
6090		}
6091	
6092		// Search
6093		if ( s.search !== undefined ) {
6094			$.extend( settings.oPreviousSearch, s.search );
6095		}
6096	
6097		// Columns
6098		if ( s.columns ) {
6099			for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6100				var col = s.columns[i];
6101	
6102				// Visibility
6103				if ( col.visible !== undefined ) {
6104					// If the api is defined, the table has been initialised so we need to use it rather than internal settings
6105					if (api) {
6106						// Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6107						api.column(i).visible(col.visible, false);
6108					}
6109					else {
6110						columns[i].bVisible = col.visible;
6111					}
6112				}
6113	
6114				// Search
6115				if ( col.search !== undefined ) {
6116					$.extend( settings.aoPreSearchCols[i], col.search );
6117				}
6118			}
6119			
6120			// If the api is defined then we need to adjust the columns once the visibility has been changed
6121			if (api) {
6122				api.columns.adjust();
6123			}
6124		}
6125	
6126		settings._bLoadingState = false;
6127		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6128		callback();
6129	}
6130	
6131	/**
6132	 * Log an error message
6133	 *  @param {object} settings dataTables settings object
6134	 *  @param {int} level log error messages, or display them to the user
6135	 *  @param {string} msg error message
6136	 *  @param {int} tn Technical note id to get more information about the error.
6137	 *  @memberof DataTable#oApi
6138	 */
6139	function _fnLog( settings, level, msg, tn )
6140	{
6141		msg = 'DataTables warning: '+
6142			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6143	
6144		if ( tn ) {
6145			msg += '. For more information about this error, please see '+
6146			'https://datatables.net/tn/'+tn;
6147		}
6148	
6149		if ( ! level  ) {
6150			// Backwards compatibility pre 1.10
6151			var ext = DataTable.ext;
6152			var type = ext.sErrMode || ext.errMode;
6153	
6154			if ( settings ) {
6155				_fnCallbackFire( settings, null, 'dt-error', [ settings, tn, msg ], true );
6156			}
6157	
6158			if ( type == 'alert' ) {
6159				alert( msg );
6160			}
6161			else if ( type == 'throw' ) {
6162				throw new Error(msg);
6163			}
6164			else if ( typeof type == 'function' ) {
6165				type( settings, tn, msg );
6166			}
6167		}
6168		else if ( window.console && console.log ) {
6169			console.log( msg );
6170		}
6171	}
6172	
6173	
6174	/**
6175	 * See if a property is defined on one object, if so assign it to the other object
6176	 *  @param {object} ret target object
6177	 *  @param {object} src source object
6178	 *  @param {string} name property
6179	 *  @param {string} [mappedName] name to map too - optional, name used if not given
6180	 *  @memberof DataTable#oApi
6181	 */
6182	function _fnMap( ret, src, name, mappedName )
6183	{
6184		if ( Array.isArray( name ) ) {
6185			$.each( name, function (i, val) {
6186				if ( Array.isArray( val ) ) {
6187					_fnMap( ret, src, val[0], val[1] );
6188				}
6189				else {
6190					_fnMap( ret, src, val );
6191				}
6192			} );
6193	
6194			return;
6195		}
6196	
6197		if ( mappedName === undefined ) {
6198			mappedName = name;
6199		}
6200	
6201		if ( src[name] !== undefined ) {
6202			ret[mappedName] = src[name];
6203		}
6204	}
6205	
6206	
6207	/**
6208	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6209	 * shallow copy arrays. The reason we need to do this, is that we don't want to
6210	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6211	 * able to override them, but we do want to deep copy arrays.
6212	 *  @param {object} out Object to extend
6213	 *  @param {object} extender Object from which the properties will be applied to
6214	 *      out
6215	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6216	 *      independent copy with the exception of the `data` or `aaData` parameters
6217	 *      if they are present. This is so you can pass in a collection to
6218	 *      DataTables and have that used as your data source without breaking the
6219	 *      references
6220	 *  @returns {object} out Reference, just for convenience - out === the return.
6221	 *  @memberof DataTable#oApi
6222	 *  @todo This doesn't take account of arrays inside the deep copied objects.
6223	 */
6224	function _fnExtend( out, extender, breakRefs )
6225	{
6226		var val;
6227	
6228		for ( var prop in extender ) {
6229			if ( Object.prototype.hasOwnProperty.call(extender, prop) ) {
6230				val = extender[prop];
6231	
6232				if ( $.isPlainObject( val ) ) {
6233					if ( ! $.isPlainObject( out[prop] ) ) {
6234						out[prop] = {};
6235					}
6236					$.extend( true, out[prop], val );
6237				}
6238				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {
6239					out[prop] = val.slice();
6240				}
6241				else {
6242					out[prop] = val;
6243				}
6244			}
6245		}
6246	
6247		return out;
6248	}
6249	
6250	
6251	/**
6252	 * Bind an event handers to allow a click or return key to activate the callback.
6253	 * This is good for accessibility since a return on the keyboard will have the
6254	 * same effect as a click, if the element has focus.
6255	 *  @param {element} n Element to bind the action to
6256	 *  @param {object|string} selector Selector (for delegated events) or data object
6257	 *   to pass to the triggered function
6258	 *  @param {function} fn Callback function for when the event is triggered
6259	 *  @memberof DataTable#oApi
6260	 */
6261	function _fnBindAction( n, selector, fn )
6262	{
6263		$(n)
6264			.on( 'click.DT', selector, function (e) {
6265				fn(e);
6266			} )
6267			.on( 'keypress.DT', selector, function (e){
6268				if ( e.which === 13 ) {
6269					e.preventDefault();
6270					fn(e);
6271				}
6272			} )
6273			.on( 'selectstart.DT', selector, function () {
6274				// Don't want a double click resulting in text selection
6275				return false;
6276			} );
6277	}
6278	
6279	
6280	/**
6281	 * Register a callback function. Easily allows a callback function to be added to
6282	 * an array store of callback functions that can then all be called together.
6283	 *  @param {object} settings dataTables settings object
6284	 *  @param {string} store Name of the array storage for the callbacks in oSettings
6285	 *  @param {function} fn Function to be called back
6286	 *  @memberof DataTable#oApi
6287	 */
6288	function _fnCallbackReg( settings, store, fn )
6289	{
6290		if ( fn ) {
6291			settings[store].push(fn);
6292		}
6293	}
6294	
6295	
6296	/**
6297	 * Fire callback functions and trigger events. Note that the loop over the
6298	 * callback array store is done backwards! Further note that you do not want to
6299	 * fire off triggers in time sensitive applications (for example cell creation)
6300	 * as its slow.
6301	 *  @param {object} settings dataTables settings object
6302	 *  @param {string} callbackArr Name of the array storage for the callbacks in
6303	 *      oSettings
6304	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
6305	 *      null no trigger is fired
6306	 *  @param {array} args Array of arguments to pass to the callback function /
6307	 *      trigger
6308	 *  @param {boolean} [bubbles] True if the event should bubble
6309	 *  @memberof DataTable#oApi
6310	 */
6311	function _fnCallbackFire( settings, callbackArr, eventName, args, bubbles )
6312	{
6313		var ret = [];
6314	
6315		if ( callbackArr ) {
6316			ret = settings[callbackArr].slice().reverse().map( function (val) {
6317				return val.apply( settings.oInstance, args );
6318			} );
6319		}
6320	
6321		if ( eventName !== null) {
6322			var e = $.Event( eventName+'.dt' );
6323			var table = $(settings.nTable);
6324			
6325			// Expose the DataTables API on the event object for easy access
6326			e.dt = settings.api;
6327	
6328			table[bubbles ?  'trigger' : 'triggerHandler']( e, args );
6329	
6330			// If not yet attached to the document, trigger the event
6331			// on the body directly to sort of simulate the bubble
6332			if (bubbles && table.parents('body').length === 0) {
6333				$('body').trigger( e, args );
6334			}
6335	
6336			ret.push( e.result );
6337		}
6338	
6339		return ret;
6340	}
6341	
6342	
6343	function _fnLengthOverflow ( settings )
6344	{
6345		var
6346			start = settings._iDisplayStart,
6347			end = settings.fnDisplayEnd(),
6348			len = settings._iDisplayLength;
6349	
6350		/* If we have space to show extra rows (backing up from the end point - then do so */
6351		if ( start >= end )
6352		{
6353			start = end - len;
6354		}
6355	
6356		// Keep the start record on the current page
6357		start -= (start % len);
6358	
6359		if ( len === -1 || start < 0 )
6360		{
6361			start = 0;
6362		}
6363	
6364		settings._iDisplayStart = start;
6365	}
6366	
6367	
6368	function _fnRenderer( settings, type )
6369	{
6370		var renderer = settings.renderer;
6371		var host = DataTable.ext.renderer[type];
6372	
6373		if ( $.isPlainObject( renderer ) && renderer[type] ) {
6374			// Specific renderer for this type. If available use it, otherwise use
6375			// the default.
6376			return host[renderer[type]] || host._;
6377		}
6378		else if ( typeof renderer === 'string' ) {
6379			// Common renderer - if there is one available for this type use it,
6380			// otherwise use the default
6381			return host[renderer] || host._;
6382		}
6383	
6384		// Use the default
6385		return host._;
6386	}
6387	
6388	
6389	/**
6390	 * Detect the data source being used for the table. Used to simplify the code
6391	 * a little (ajax) and to make it compress a little smaller.
6392	 *
6393	 *  @param {object} settings dataTables settings object
6394	 *  @returns {string} Data source
6395	 *  @memberof DataTable#oApi
6396	 */
6397	function _fnDataSource ( settings )
6398	{
6399		if ( settings.oFeatures.bServerSide ) {
6400			return 'ssp';
6401		}
6402		else if ( settings.ajax ) {
6403			return 'ajax';
6404		}
6405		return 'dom';
6406	}
6407	
6408	/**
6409	 * Common replacement for language strings
6410	 *
6411	 * @param {*} settings DT settings object
6412	 * @param {*} str String with values to replace
6413	 * @param {*} entries Plural number for _ENTRIES_ - can be undefined
6414	 * @returns String
6415	 */
6416	function _fnMacros ( settings, str, entries )
6417	{
6418		// When infinite scrolling, we are always starting at 1. _iDisplayStart is
6419		// used only internally
6420		var
6421			formatter  = settings.fnFormatNumber,
6422			start      = settings._iDisplayStart+1,
6423			len        = settings._iDisplayLength,
6424			vis        = settings.fnRecordsDisplay(),
6425			max        = settings.fnRecordsTotal(),
6426			all        = len === -1;
6427	
6428		return str.
6429			replace(/_START_/g, formatter.call( settings, start ) ).
6430			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
6431			replace(/_MAX_/g,   formatter.call( settings, max ) ).
6432			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
6433			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
6434			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ).
6435			replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries) ).
6436			replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max) ).
6437			replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
6438	}
6439	
6440	
6441	
6442	/**
6443	 * Computed structure of the DataTables API, defined by the options passed to
6444	 * `DataTable.Api.register()` when building the API.
6445	 *
6446	 * The structure is built in order to speed creation and extension of the Api
6447	 * objects since the extensions are effectively pre-parsed.
6448	 *
6449	 * The array is an array of objects with the following structure, where this
6450	 * base array represents the Api prototype base:
6451	 *
6452	 *     [
6453	 *       {
6454	 *         name:      'data'                -- string   - Property name
6455	 *         val:       function () {},       -- function - Api method (or undefined if just an object
6456	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6457	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6458	 *       },
6459	 *       {
6460	 *         name:     'row'
6461	 *         val:       {},
6462	 *         methodExt: [ ... ],
6463	 *         propExt:   [
6464	 *           {
6465	 *             name:      'data'
6466	 *             val:       function () {},
6467	 *             methodExt: [ ... ],
6468	 *             propExt:   [ ... ]
6469	 *           },
6470	 *           ...
6471	 *         ]
6472	 *       }
6473	 *     ]
6474	 *
6475	 * @type {Array}
6476	 * @ignore
6477	 */
6478	var __apiStruct = [];
6479	
6480	
6481	/**
6482	 * `Array.prototype` reference.
6483	 *
6484	 * @type object
6485	 * @ignore
6486	 */
6487	var __arrayProto = Array.prototype;
6488	
6489	
6490	/**
6491	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6492	 * take several different forms for ease of use.
6493	 *
6494	 * Each of the input parameter types will be converted to a DataTables settings
6495	 * object where possible.
6496	 *
6497	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6498	 *   of:
6499	 *
6500	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6501	 *     with be found and used.
6502	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6503	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6504	 *   * `object` - DataTables settings object
6505	 *   * `DataTables.Api` - API instance
6506	 * @return {array|null} Matching DataTables settings objects. `null` or
6507	 *   `undefined` is returned if no matching DataTable is found.
6508	 * @ignore
6509	 */
6510	var _toSettings = function ( mixed )
6511	{
6512		var idx, jq;
6513		var settings = DataTable.settings;
6514		var tables = _pluck(settings, 'nTable');
6515	
6516		if ( ! mixed ) {
6517			return [];
6518		}
6519		else if ( mixed.nTable && mixed.oFeatures ) {
6520			// DataTables settings object
6521			return [ mixed ];
6522		}
6523		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6524			// Table node
6525			idx = tables.indexOf(mixed);
6526			return idx !== -1 ? [ settings[idx] ] : null;
6527		}
6528		else if ( mixed && typeof mixed.settings === 'function' ) {
6529			return mixed.settings().toArray();
6530		}
6531		else if ( typeof mixed === 'string' ) {
6532			// jQuery selector
6533			jq = $(mixed).get();
6534		}
6535		else if ( mixed instanceof $ ) {
6536			// jQuery object (also DataTables instance)
6537			jq = mixed.get();
6538		}
6539	
6540		if ( jq ) {
6541			return settings.filter(function (v, idx) {
6542				return jq.includes(tables[idx]);
6543			});
6544		}
6545	};
6546	
6547	
6548	/**
6549	 * DataTables API class - used to control and interface with  one or more
6550	 * DataTables enhanced tables.
6551	 *
6552	 * The API class is heavily based on jQuery, presenting a chainable interface
6553	 * that you can use to interact with tables. Each instance of the API class has
6554	 * a "context" - i.e. the tables that it will operate on. This could be a single
6555	 * table, all tables on a page or a sub-set thereof.
6556	 *
6557	 * Additionally the API is designed to allow you to easily work with the data in
6558	 * the tables, retrieving and manipulating it as required. This is done by
6559	 * presenting the API class as an array like interface. The contents of the
6560	 * array depend upon the actions requested by each method (for example
6561	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6562	 * return an array of objects or arrays depending upon your table's
6563	 * configuration). The API object has a number of array like methods (`push`,
6564	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6565	 * `unique` etc) to assist your working with the data held in a table.
6566	 *
6567	 * Most methods (those which return an Api instance) are chainable, which means
6568	 * the return from a method call also has all of the methods available that the
6569	 * top level object had. For example, these two calls are equivalent:
6570	 *
6571	 *     // Not chained
6572	 *     api.row.add( {...} );
6573	 *     api.draw();
6574	 *
6575	 *     // Chained
6576	 *     api.row.add( {...} ).draw();
6577	 *
6578	 * @class DataTable.Api
6579	 * @param {array|object|string|jQuery} context DataTable identifier. This is
6580	 *   used to define which DataTables enhanced tables this API will operate on.
6581	 *   Can be one of:
6582	 *
6583	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6584	 *     with be found and used.
6585	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6586	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6587	 *   * `object` - DataTables settings object
6588	 * @param {array} [data] Data to initialise the Api instance with.
6589	 *
6590	 * @example
6591	 *   // Direct initialisation during DataTables construction
6592	 *   var api = $('#example').DataTable();
6593	 *
6594	 * @example
6595	 *   // Initialisation using a DataTables jQuery object
6596	 *   var api = $('#example').dataTable().api();
6597	 *
6598	 * @example
6599	 *   // Initialisation as a constructor
6600	 *   var api = new DataTable.Api( 'table.dataTable' );
6601	 */
6602	_Api = function ( context, data )
6603	{
6604		if ( ! (this instanceof _Api) ) {
6605			return new _Api( context, data );
6606		}
6607	
6608		var settings = [];
6609		var ctxSettings = function ( o ) {
6610			var a = _toSettings( o );
6611			if ( a ) {
6612				settings.push.apply( settings, a );
6613			}
6614		};
6615	
6616		if ( Array.isArray( context ) ) {
6617			for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6618				ctxSettings( context[i] );
6619			}
6620		}
6621		else {
6622			ctxSettings( context );
6623		}
6624	
6625		// Remove duplicates
6626		this.context = settings.length > 1
6627			? _unique( settings )
6628			: settings;
6629	
6630		// Initial data
6631		if ( data ) {
6632			this.push.apply(this, data);
6633		}
6634	
6635		// selector
6636		this.selector = {
6637			rows: null,
6638			cols: null,
6639			opts: null
6640		};
6641	
6642		_Api.extend( this, this, __apiStruct );
6643	};
6644	
6645	DataTable.Api = _Api;
6646	
6647	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6648	// isPlainObject.
6649	$.extend( _Api.prototype, {
6650		any: function ()
6651		{
6652			return this.count() !== 0;
6653		},
6654	
6655		context: [], // array of table settings objects
6656	
6657		count: function ()
6658		{
6659			return this.flatten().length;
6660		},
6661	
6662		each: function ( fn )
6663		{
6664			for ( var i=0, ien=this.length ; i<ien; i++ ) {
6665				fn.call( this, this[i], i, this );
6666			}
6667	
6668			return this;
6669		},
6670	
6671		eq: function ( idx )
6672		{
6673			var ctx = this.context;
6674	
6675			return ctx.length > idx ?
6676				new _Api( ctx[idx], this[idx] ) :
6677				null;
6678		},
6679	
6680		filter: function ( fn )
6681		{
6682			var a = __arrayProto.filter.call( this, fn, this );
6683	
6684			return new _Api( this.context, a );
6685		},
6686	
6687		flatten: function ()
6688		{
6689			var a = [];
6690	
6691			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6692		},
6693	
6694		get: function ( idx )
6695		{
6696			return this[ idx ];
6697		},
6698	
6699		join:    __arrayProto.join,
6700	
6701		includes: function ( find ) {
6702			return this.indexOf( find ) === -1 ? false : true;
6703		},
6704	
6705		indexOf: __arrayProto.indexOf,
6706	
6707		iterator: function ( flatten, type, fn, alwaysNew ) {
6708			var
6709				a = [], ret,
6710				i, ien, j, jen,
6711				context = this.context,
6712				rows, items, item,
6713				selector = this.selector;
6714	
6715			// Argument shifting
6716			if ( typeof flatten === 'string' ) {
6717				alwaysNew = fn;
6718				fn = type;
6719				type = flatten;
6720				flatten = false;
6721			}
6722	
6723			for ( i=0, ien=context.length ; i<ien ; i++ ) {
6724				var apiInst = new _Api( context[i] );
6725	
6726				if ( type === 'table' ) {
6727					ret = fn.call( apiInst, context[i], i );
6728	
6729					if ( ret !== undefined ) {
6730						a.push( ret );
6731					}
6732				}
6733				else if ( type === 'columns' || type === 'rows' ) {
6734					// this has same length as context - one entry for each table
6735					ret = fn.call( apiInst, context[i], this[i], i );
6736	
6737					if ( ret !== undefined ) {
6738						a.push( ret );
6739					}
6740				}
6741				else if ( type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6742					// columns and rows share the same structure.
6743					// 'this' is an array of column indexes for each context
6744					items = this[i];
6745	
6746					if ( type === 'column-rows' ) {
6747						rows = _selector_row_indexes( context[i], selector.opts );
6748					}
6749	
6750					for ( j=0, jen=items.length ; j<jen ; j++ ) {
6751						item = items[j];
vendor: 4,127 bytes, lines 6752-6939
6752	
6753						if ( type === 'cell' ) {
6754							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6755						}
6756						else {
6757							ret = fn.call( apiInst, context[i], item, i, j, rows );
6758						}
6759	
6760						if ( ret !== undefined ) {
6761							a.push( ret );
6762						}
6763					}
6764				}
6765			}
6766	
6767			if ( a.length || alwaysNew ) {
6768				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6769				var apiSelector = api.selector;
6770				apiSelector.rows = selector.rows;
6771				apiSelector.cols = selector.cols;
6772				apiSelector.opts = selector.opts;
6773				return api;
6774			}
6775			return this;
6776		},
6777	
6778		lastIndexOf: __arrayProto.lastIndexOf,
6779	
6780		length:  0,
6781	
6782		map: function ( fn )
6783		{
6784			var a = __arrayProto.map.call( this, fn, this );
6785	
6786			return new _Api( this.context, a );
6787		},
6788	
6789		pluck: function ( prop )
6790		{
6791			var fn = DataTable.util.get(prop);
6792	
6793			return this.map( function ( el ) {
6794				return fn(el);
6795			} );
6796		},
6797	
6798		pop:     __arrayProto.pop,
6799	
6800		push:    __arrayProto.push,
6801	
6802		reduce: __arrayProto.reduce,
6803	
6804		reduceRight: __arrayProto.reduceRight,
6805	
6806		reverse: __arrayProto.reverse,
6807	
6808		// Object with rows, columns and opts
6809		selector: null,
6810	
6811		shift:   __arrayProto.shift,
6812	
6813		slice: function () {
6814			return new _Api( this.context, this );
6815		},
6816	
6817		sort:    __arrayProto.sort,
6818	
6819		splice:  __arrayProto.splice,
6820	
6821		toArray: function ()
6822		{
6823			return __arrayProto.slice.call( this );
6824		},
6825	
6826		to$: function ()
6827		{
6828			return $( this );
6829		},
6830	
6831		toJQuery: function ()
6832		{
6833			return $( this );
6834		},
6835	
6836		unique: function ()
6837		{
6838			return new _Api( this.context, _unique(this.toArray()) );
6839		},
6840	
6841		unshift: __arrayProto.unshift
6842	} );
6843	
6844	
6845	function _api_scope( scope, fn, struc ) {
6846		return function () {
6847			var ret = fn.apply( scope || this, arguments );
6848	
6849			// Method extension
6850			_Api.extend( ret, ret, struc.methodExt );
6851			return ret;
6852		};
6853	}
6854	
6855	function _api_find( src, name ) {
6856		for ( var i=0, ien=src.length ; i<ien ; i++ ) {
6857			if ( src[i].name === name ) {
6858				return src[i];
6859			}
6860		}
6861		return null;
6862	}
6863	
6864	window.__apiStruct = __apiStruct;
6865	
6866	_Api.extend = function ( scope, obj, ext )
6867	{
6868		// Only extend API instances and static properties of the API
6869		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6870			return;
6871		}
6872	
6873		var
6874			i, ien,
6875			struct;
6876	
6877		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6878			struct = ext[i];
6879	
6880			if (struct.name === '__proto__') {
6881				continue;
6882			}
6883	
6884			// Value
6885			obj[ struct.name ] = struct.type === 'function' ?
6886				_api_scope( scope, struct.val, struct ) :
6887				struct.type === 'object' ?
6888					{} :
6889					struct.val;
6890	
6891			obj[ struct.name ].__dt_wrapper = true;
6892	
6893			// Property extension
6894			_Api.extend( scope, obj[ struct.name ], struct.propExt );
6895		}
6896	};
6897	
6898	//     [
6899	//       {
6900	//         name:      'data'                -- string   - Property name
6901	//         val:       function () {},       -- function - Api method (or undefined if just an object
6902	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6903	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6904	//       },
6905	//       {
6906	//         name:     'row'
6907	//         val:       {},
6908	//         methodExt: [ ... ],
6909	//         propExt:   [
6910	//           {
6911	//             name:      'data'
6912	//             val:       function () {},
6913	//             methodExt: [ ... ],
6914	//             propExt:   [ ... ]
6915	//           },
6916	//           ...
6917	//         ]
6918	//       }
6919	//     ]
6920	
6921	
6922	_Api.register = _api_register = function ( name, val )
6923	{
6924		if ( Array.isArray( name ) ) {
6925			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
6926				_Api.register( name[j], val );
6927			}
6928			return;
6929		}
6930	
6931		var
6932			i, ien,
6933			heir = name.split('.'),
6934			struct = __apiStruct,
6935			key, method;
6936	
6937		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
6938			method = heir[i].indexOf('()') !== -1;
6939			key = method ?
6940				heir[i].replace('()', '') :
6941				heir[i];
6942	
6943			var src = _api_find( struct, key );
6944			if ( ! src ) {
6945				src = {
6946					name:      key,
6947					val:       {},
6948					methodExt: [],
6949					propExt:   [],
6950					type:      'object'
6951				};
6952				struct.push( src );
6953			}
6954	
6955			if ( i === ien-1 ) {
6956				src.val = val;
6957				src.type = typeof val === 'function' ?
6958					'function' :
6959					$.isPlainObject( val ) ?
6960						'object' :
6961						'other';
6962			}
6963			else {
6964				struct = method ?
6965					src.methodExt :
6966					src.propExt;
6967			}
6968		}
6969	};
6970	
6971	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
6972		_Api.register( pluralName, val );
6973	
6974		_Api.register( singularName, function () {
6975			var ret = val.apply( this, arguments );
6976	
6977			if ( ret === this ) {
6978				// Returned item is the API instance that was passed in, return it
6979				return this;
6980			}
6981			else if ( ret instanceof _Api ) {
6982				// New API instance returned, want the value from the first item
6983				// in the returned array for the singular result.
6984				return ret.length ?
6985					Array.isArray( ret[0] ) ?
6986						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
6987						ret[0] :
6988					undefined;
6989			}
6990	
6991			// Non-API return - just fire it back
6992			return ret;
6993		} );
6994	};
6995	
6996	
6997	/**
6998	 * Selector for HTML tables. Apply the given selector to the give array of
6999	 * DataTables settings objects.
7000	 *
7001	 * @param {string|integer} [selector] jQuery selector string or integer
7002	 * @param  {array} Array of DataTables settings objects to be filtered
7003	 * @return {array}
7004	 * @ignore
7005	 */
7006	var __table_selector = function ( selector, a )
7007	{
7008		if ( Array.isArray(selector) ) {
7009			var result = [];
7010	
7011			selector.forEach(function (sel) {
7012				var inner = __table_selector(sel, a);
7013	
7014				result.push.apply(result, inner);
7015			});
7016	
7017			return result.filter( function (item) {
7018				return item;
7019			});
7020		}
7021	
7022		// Integer is used to pick out a table by index
7023		if ( typeof selector === 'number' ) {
7024			return [ a[ selector ] ];
7025		}
7026	
7027		// Perform a jQuery selector on the table nodes
7028		var nodes = a.map( function (el) {
7029			return el.nTable;
7030		} );
7031	
7032		return $(nodes)
7033			.filter( selector )
7034			.map( function () {
7035				// Need to translate back from the table node to the settings
7036				var idx = nodes.indexOf(this);
7037				return a[ idx ];
7038			} )
7039			.toArray();
7040	};
7041	
7042	
7043	
7044	/**
7045	 * Context selector for the API's context (i.e. the tables the API instance
7046	 * refers to.
7047	 *
7048	 * @name    DataTable.Api#tables
7049	 * @param {string|integer} [selector] Selector to pick which tables the iterator
7050	 *   should operate on. If not given, all tables in the current context are
7051	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7052	 *   select multiple tables or as an integer to select a single table.
7053	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7054	 */
7055	_api_register( 'tables()', function ( selector ) {
7056		// A new instance is created if there was a selector specified
7057		return selector !== undefined && selector !== null ?
7058			new _Api( __table_selector( selector, this.context ) ) :
7059			this;
7060	} );
7061	
7062	
7063	_api_register( 'table()', function ( selector ) {
7064		var tables = this.tables( selector );
7065		var ctx = tables.context;
7066	
7067		// Truncate to the first matched table
7068		return ctx.length ?
7069			new _Api( ctx[0] ) :
7070			tables;
7071	} );
7072	
7073	// Common methods, combined to reduce size
7074	[
7075		['nodes', 'node', 'nTable'],
7076		['body', 'body', 'nTBody'],
7077		['header', 'header', 'nTHead'],
7078		['footer', 'footer', 'nTFoot'],
7079	].forEach(function (item) {
7080		_api_registerPlural(
7081			'tables().' + item[0] + '()',
7082			'table().' + item[1] + '()' ,
7083			function () {
7084				return this.iterator( 'table', function ( ctx ) {
7085					return ctx[item[2]];
7086				}, 1 );
7087			}
7088		);
7089	});
7090	
7091	// Structure methods
7092	[
7093		['header', 'aoHeader'],
7094		['footer', 'aoFooter'],
7095	].forEach(function (item) {
7096		_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
7097			var indexes = this.columns(selector).indexes().flatten();
7098			var ctx = this.context[0];
7099			
7100			return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7101		} );
7102	})
7103	
7104	
7105	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7106		return this.iterator( 'table', function ( ctx ) {
7107			return ctx.nTableWrapper;
7108		}, 1 );
7109	} );
7110	
7111	_api_register( 'tables().every()', function ( fn ) {
7112		var that = this;
7113	
7114		return this.iterator('table', function (s, i) {
7115			fn.call(that.table(i), i);
7116		});
7117	});
7118	
7119	_api_register( 'caption()', function ( value, side ) {
7120		var context = this.context;
7121	
7122		// Getter - return existing node's content
7123		if ( value === undefined ) {
7124			var caption = context[0].captionNode;
7125	
7126			return caption && context.length ?
7127				caption.innerHTML : 
7128				null;
7129		}
7130	
7131		return this.iterator( 'table', function ( ctx ) {
7132			var table = $(ctx.nTable);
7133			var caption = $(ctx.captionNode);
7134			var container = $(ctx.nTableWrapper);
7135	
7136			// Create the node if it doesn't exist yet
7137			if ( ! caption.length ) {
7138				caption = $('<caption/>').html( value );
7139				ctx.captionNode = caption[0];
7140	
7141				// If side isn't set, we need to insert into the document to let the
7142				// CSS decide so we can read it back, otherwise there is no way to
7143				// know if the CSS would put it top or bottom for scrolling
vendor: 7,380 bytes, lines 7144-7409
7144				if (! side) {
7145					table.prepend(caption);
7146	
7147					side = caption.css('caption-side');
7148				}
7149			}
7150	
7151			caption.html( value );
7152	
7153			if ( side ) {
7154				caption.css( 'caption-side', side );
7155				caption[0]._captionSide = side;
7156			}
7157	
7158			if (container.find('div.dataTables_scroll').length) {
7159				var selector = (side === 'top' ? 'Head' : 'Foot');
7160	
7161				container.find('div.dataTables_scroll'+ selector +' table').prepend(caption);
7162			}
7163			else {
7164				table.prepend(caption);
7165			}
7166		}, 1 );
7167	} );
7168	
7169	_api_register( 'caption.node()', function () {
7170		var ctx = this.context;
7171	
7172		return ctx.length ? ctx[0].captionNode : null;
7173	} );
7174	
7175	
7176	/**
7177	 * Redraw the tables in the current context.
7178	 */
7179	_api_register( 'draw()', function ( paging ) {
7180		return this.iterator( 'table', function ( settings ) {
7181			if ( paging === 'page' ) {
7182				_fnDraw( settings );
7183			}
7184			else {
7185				if ( typeof paging === 'string' ) {
7186					paging = paging === 'full-hold' ?
7187						false :
7188						true;
7189				}
7190	
7191				_fnReDraw( settings, paging===false );
7192			}
7193		} );
7194	} );
7195	
7196	
7197	
7198	/**
7199	 * Get the current page index.
7200	 *
7201	 * @return {integer} Current page index (zero based)
7202	 *//**
7203	 * Set the current page.
7204	 *
7205	 * Note that if you attempt to show a page which does not exist, DataTables will
7206	 * not throw an error, but rather reset the paging.
7207	 *
7208	 * @param {integer|string} action The paging action to take. This can be one of:
7209	 *  * `integer` - The page index to jump to
7210	 *  * `string` - An action to take:
7211	 *    * `first` - Jump to first page.
7212	 *    * `next` - Jump to the next page
7213	 *    * `previous` - Jump to previous page
7214	 *    * `last` - Jump to the last page.
7215	 * @returns {DataTables.Api} this
7216	 */
7217	_api_register( 'page()', function ( action ) {
7218		if ( action === undefined ) {
7219			return this.page.info().page; // not an expensive call
7220		}
7221	
7222		// else, have an action to take on all tables
7223		return this.iterator( 'table', function ( settings ) {
7224			_fnPageChange( settings, action );
7225		} );
7226	} );
7227	
7228	
7229	/**
7230	 * Paging information for the first table in the current context.
7231	 *
7232	 * If you require paging information for another table, use the `table()` method
7233	 * with a suitable selector.
7234	 *
7235	 * @return {object} Object with the following properties set:
7236	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7237	 *  * `pages` - Total number of pages
7238	 *  * `start` - Display index for the first record shown on the current page
7239	 *  * `end` - Display index for the last record shown on the current page
7240	 *  * `length` - Display length (number of records). Note that generally `start
7241	 *    + length = end`, but this is not always true, for example if there are
7242	 *    only 2 records to show on the final page, with a length of 10.
7243	 *  * `recordsTotal` - Full data set length
7244	 *  * `recordsDisplay` - Data set length once the current filtering criterion
7245	 *    are applied.
7246	 */
7247	_api_register( 'page.info()', function () {
7248		if ( this.context.length === 0 ) {
7249			return undefined;
7250		}
7251	
7252		var
7253			settings   = this.context[0],
7254			start      = settings._iDisplayStart,
7255			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7256			visRecords = settings.fnRecordsDisplay(),
7257			all        = len === -1;
7258	
7259		return {
7260			"page":           all ? 0 : Math.floor( start / len ),
7261			"pages":          all ? 1 : Math.ceil( visRecords / len ),
7262			"start":          start,
7263			"end":            settings.fnDisplayEnd(),
7264			"length":         len,
7265			"recordsTotal":   settings.fnRecordsTotal(),
7266			"recordsDisplay": visRecords,
7267			"serverSide":     _fnDataSource( settings ) === 'ssp'
7268		};
7269	} );
7270	
7271	
7272	/**
7273	 * Get the current page length.
7274	 *
7275	 * @return {integer} Current page length. Note `-1` indicates that all records
7276	 *   are to be shown.
7277	 *//**
7278	 * Set the current page length.
7279	 *
7280	 * @param {integer} Page length to set. Use `-1` to show all records.
7281	 * @returns {DataTables.Api} this
7282	 */
7283	_api_register( 'page.len()', function ( len ) {
7284		// Note that we can't call this function 'length()' because `length`
7285		// is a Javascript property of functions which defines how many arguments
7286		// the function expects.
7287		if ( len === undefined ) {
7288			return this.context.length !== 0 ?
7289				this.context[0]._iDisplayLength :
7290				undefined;
7291		}
7292	
7293		// else, set the page length
7294		return this.iterator( 'table', function ( settings ) {
7295			_fnLengthChange( settings, len );
7296		} );
7297	} );
7298	
7299	
7300	
7301	var __reload = function ( settings, holdPosition, callback ) {
7302		// Use the draw event to trigger a callback
7303		if ( callback ) {
7304			var api = new _Api( settings );
7305	
7306			api.one( 'draw', function () {
7307				callback( api.ajax.json() );
7308			} );
7309		}
7310	
7311		if ( _fnDataSource( settings ) == 'ssp' ) {
7312			_fnReDraw( settings, holdPosition );
7313		}
7314		else {
7315			_fnProcessingDisplay( settings, true );
7316	
7317			// Cancel an existing request
7318			var xhr = settings.jqXHR;
7319			if ( xhr && xhr.readyState !== 4 ) {
7320				xhr.abort();
7321			}
7322	
7323			// Trigger xhr
7324			_fnBuildAjax( settings, {}, function( json ) {
7325				_fnClearTable( settings );
7326	
7327				var data = _fnAjaxDataSrc( settings, json );
7328				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7329					_fnAddData( settings, data[i] );
7330				}
7331	
7332				_fnReDraw( settings, holdPosition );
7333				_fnInitComplete( settings );
7334				_fnProcessingDisplay( settings, false );
7335			} );
7336		}
7337	};
7338	
7339	
7340	/**
7341	 * Get the JSON response from the last Ajax request that DataTables made to the
7342	 * server. Note that this returns the JSON from the first table in the current
7343	 * context.
7344	 *
7345	 * @return {object} JSON received from the server.
7346	 */
7347	_api_register( 'ajax.json()', function () {
7348		var ctx = this.context;
7349	
7350		if ( ctx.length > 0 ) {
7351			return ctx[0].json;
7352		}
7353	
7354		// else return undefined;
7355	} );
7356	
7357	
7358	/**
7359	 * Get the data submitted in the last Ajax request
7360	 */
7361	_api_register( 'ajax.params()', function () {
7362		var ctx = this.context;
7363	
7364		if ( ctx.length > 0 ) {
7365			return ctx[0].oAjaxData;
7366		}
7367	
7368		// else return undefined;
7369	} );
7370	
7371	
7372	/**
7373	 * Reload tables from the Ajax data source. Note that this function will
7374	 * automatically re-draw the table when the remote data has been loaded.
7375	 *
7376	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7377	 *   position. A full re-sort and re-filter is performed when this method is
7378	 *   called, which is why the pagination reset is the default action.
7379	 * @returns {DataTables.Api} this
7380	 */
7381	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7382		return this.iterator( 'table', function (settings) {
7383			__reload( settings, resetPaging===false, callback );
7384		} );
7385	} );
7386	
7387	
7388	/**
7389	 * Get the current Ajax URL. Note that this returns the URL from the first
7390	 * table in the current context.
7391	 *
7392	 * @return {string} Current Ajax source URL
7393	 *//**
7394	 * Set the Ajax URL. Note that this will set the URL for all tables in the
7395	 * current context.
7396	 *
7397	 * @param {string} url URL to set.
7398	 * @returns {DataTables.Api} this
7399	 */
7400	_api_register( 'ajax.url()', function ( url ) {
7401		var ctx = this.context;
7402	
7403		if ( url === undefined ) {
7404			// get
7405			if ( ctx.length === 0 ) {
7406				return undefined;
7407			}
7408			ctx = ctx[0];
7409	
7410			return $.isPlainObject( ctx.ajax ) ?
7411				ctx.ajax.url :
7412				ctx.ajax;
7413		}
7414	
7415		// set
7416		return this.iterator( 'table', function ( settings ) {
7417			if ( $.isPlainObject( settings.ajax ) ) {
7418				settings.ajax.url = url;
7419			}
7420			else {
7421				settings.ajax = url;
7422			}
7423		} );
7424	} );
7425	
7426	
7427	/**
7428	 * Load data from the newly set Ajax URL. Note that this method is only
7429	 * available when `ajax.url()` is used to set a URL. Additionally, this method
7430	 * has the same effect as calling `ajax.reload()` but is provided for
7431	 * convenience when setting a new URL. Like `ajax.reload()` it will
7432	 * automatically redraw the table once the remote data has been loaded.
7433	 *
7434	 * @returns {DataTables.Api} this
7435	 */
7436	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7437		// Same as a reload, but makes sense to present it for easy access after a
7438		// url change
7439		return this.iterator( 'table', function ( ctx ) {
7440			__reload( ctx, resetPaging===false, callback );
7441		} );
7442	} );
7443	
7444	
7445	
7446	
7447	var _selector_run = function ( type, selector, selectFn, settings, opts )
7448	{
7449		var
7450			out = [], res,
7451			a, i, ien, j, jen,
7452			selectorType = typeof selector;
7453	
7454		// Can't just check for isArray here, as an API or jQuery instance might be
7455		// given with their array like look
7456		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7457			selector = [ selector ];
7458		}
7459	
7460		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7461			// Only split on simple strings - complex expressions will be jQuery selectors
7462			a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
7463				selector[i].split(',') :
7464				[ selector[i] ];
7465	
7466			for ( j=0, jen=a.length ; j<jen ; j++ ) {
7467				res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
7468	
7469				// Remove empty items
7470				res = res.filter( function (item) {
7471					return item !== null && item !== undefined;
7472				});
7473	
7474				if ( res && res.length ) {
7475					out = out.concat( res );
7476				}
7477			}
7478		}
7479	
7480		// selector extensions
7481		var ext = _ext.selector[ type ];
7482		if ( ext.length ) {
7483			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7484				out = ext[i]( settings, opts, out );
7485			}
7486		}
7487	
7488		return _unique( out );
7489	};
7490	
7491	
7492	var _selector_opts = function ( opts )
7493	{
7494		if ( ! opts ) {
7495			opts = {};
7496		}
7497	
7498		// Backwards compatibility for 1.9- which used the terminology filter rather
7499		// than search
7500		if ( opts.filter && opts.search === undefined ) {
7501			opts.search = opts.filter;
7502		}
7503	
7504		return $.extend( {
7505			search: 'none',
7506			order: 'current',
7507			page: 'all'
7508		}, opts );
7509	};
7510	
7511	
7512	// Reduce the API instance to the first item found
7513	var _selector_first = function ( old )
7514	{
7515		let inst = new _Api(old.context[0]);
7516	
7517		// Use a push rather than passing to the constructor, since it will
7518		// merge arrays down automatically, which isn't what is wanted here
7519		if (old.length) {
7520			inst.push( old[0] );
7521		}
7522	
7523		inst.selector = old.selector;
7524	
7525		// Limit to a single row / column / cell
7526		if (inst.length && inst[0].length > 1) {
7527			inst[0].splice(1);
7528		}
7529	
7530		return inst;
7531	};
7532	
7533	
7534	var _selector_row_indexes = function ( settings, opts )
7535	{
7536		var
7537			i, ien, tmp, a=[],
7538			displayFiltered = settings.aiDisplay,
7539			displayMaster = settings.aiDisplayMaster;
7540	
7541		var
7542			search = opts.search,  // none, applied, removed
7543			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7544			page   = opts.page;    // all, current
7545	
7546		if ( page == 'current' ) {
7547			// Current page implies that order=current and filter=applied, since it is
7548			// fairly senseless otherwise, regardless of what order and search actually
7549			// are
7550			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7551				a.push( displayFiltered[i] );
7552			}
7553		}
7554		else if ( order == 'current' || order == 'applied' ) {
7555			if ( search == 'none') {
7556				a = displayMaster.slice();
7557			}
7558			else if ( search == 'applied' ) {
7559				a = displayFiltered.slice();
7560			}
7561			else if ( search == 'removed' ) {
7562				// O(n+m) solution by creating a hash map
7563				var displayFilteredMap = {};
7564	
7565				for ( i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7566					displayFilteredMap[displayFiltered[i]] = null;
7567				}
7568	
7569				displayMaster.forEach(function (item) {
7570					if (! Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
7571						a.push(item);
7572					}
7573				});
7574			}
7575		}
7576		else if ( order == 'index' || order == 'original' ) {
7577			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
vendor: 16,850 bytes, lines 7578-8210
7578				if (! settings.aoData[i]) {
7579					continue;
7580				}
7581	
7582				if ( search == 'none' ) {
7583					a.push( i );
7584				}
7585				else { // applied | removed
7586					tmp = displayFiltered.indexOf(i);
7587	
7588					if ((tmp === -1 && search == 'removed') ||
7589						(tmp >= 0   && search == 'applied') )
7590					{
7591						a.push( i );
7592					}
7593				}
7594			}
7595		}
7596		else if ( typeof order === 'number' ) {
7597			// Order the rows by the given column
7598			var ordered = _fnSort(settings, order, 'asc');
7599	
7600			if (search === 'none') {
7601				a = ordered;
7602			}
7603			else { // applied | removed
7604				for (i=0; i<ordered.length; i++) {
7605					tmp = displayFiltered.indexOf(ordered[i]);
7606	
7607					if ((tmp === -1 && search == 'removed') ||
7608						(tmp >= 0   && search == 'applied') )
7609					{
7610						a.push( ordered[i] );
7611					}
7612				}
7613			}
7614		}
7615	
7616		return a;
7617	};
7618	
7619	
7620	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7621	 * Rows
7622	 *
7623	 * {}          - no selector - use all available rows
7624	 * {integer}   - row aoData index
7625	 * {node}      - TR node
7626	 * {string}    - jQuery selector to apply to the TR elements
7627	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
7628	 *
7629	 */
7630	var __row_selector = function ( settings, selector, opts )
7631	{
7632		var rows;
7633		var run = function ( sel ) {
7634			var selInt = _intVal( sel );
7635			var aoData = settings.aoData;
7636	
7637			// Short cut - selector is a number and no options provided (default is
7638			// all records, so no need to check if the index is in there, since it
7639			// must be - dev error if the index doesn't exist).
7640			if ( selInt !== null && ! opts ) {
7641				return [ selInt ];
7642			}
7643	
7644			if ( ! rows ) {
7645				rows = _selector_row_indexes( settings, opts );
7646			}
7647	
7648			if ( selInt !== null && rows.indexOf(selInt) !== -1 ) {
7649				// Selector - integer
7650				return [ selInt ];
7651			}
7652			else if ( sel === null || sel === undefined || sel === '' ) {
7653				// Selector - none
7654				return rows;
7655			}
7656	
7657			// Selector - function
7658			if ( typeof sel === 'function' ) {
7659				return rows.map( function (idx) {
7660					var row = aoData[ idx ];
7661					return sel( idx, row._aData, row.nTr ) ? idx : null;
7662				} );
7663			}
7664	
7665			// Selector - node
7666			if ( sel.nodeName ) {
7667				var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
7668				var cellIdx = sel._DT_CellIndex;
7669	
7670				if ( rowIdx !== undefined ) {
7671					// Make sure that the row is actually still present in the table
7672					return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7673						[ rowIdx ] :
7674						[];
7675				}
7676				else if ( cellIdx ) {
7677					return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
7678						[ cellIdx.row ] :
7679						[];
7680				}
7681				else {
7682					var host = $(sel).closest('*[data-dt-row]');
7683					return host.length ?
7684						[ host.data('dt-row') ] :
7685						[];
7686				}
7687			}
7688	
7689			// ID selector. Want to always be able to select rows by id, regardless
7690			// of if the tr element has been created or not, so can't rely upon
7691			// jQuery here - hence a custom implementation. This does not match
7692			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7693			// but to select it using a CSS selector engine (like Sizzle or
7694			// querySelect) it would need to need to be escaped for some characters.
7695			// DataTables simplifies this for row selectors since you can select
7696			// only a row. A # indicates an id any anything that follows is the id -
7697			// unescaped.
7698			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7699				// get row index from id
7700				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7701				if ( rowObj !== undefined ) {
7702					return [ rowObj.idx ];
7703				}
7704	
7705				// need to fall through to jQuery in case there is DOM id that
7706				// matches
7707			}
7708			
7709			// Get nodes in the order from the `rows` array with null values removed
7710			var nodes = _removeEmpty(
7711				_pluck_order( settings.aoData, rows, 'nTr' )
7712			);
7713	
7714			// Selector - jQuery selector string, array of nodes or jQuery object/
7715			// As jQuery's .filter() allows jQuery objects to be passed in filter,
7716			// it also allows arrays, so this will cope with all three options
7717			return $(nodes)
7718				.filter( sel )
7719				.map( function () {
7720					return this._DT_RowIndex;
7721				} )
7722				.toArray();
7723		};
7724	
7725		var matched = _selector_run( 'row', selector, run, settings, opts );
7726	
7727		if (opts.order === 'current' || opts.order === 'applied') {
7728			_fnSortDisplay(settings, matched);
7729		}
7730	
7731		return matched;
7732	};
7733	
7734	
7735	_api_register( 'rows()', function ( selector, opts ) {
7736		// argument shifting
7737		if ( selector === undefined ) {
7738			selector = '';
7739		}
7740		else if ( $.isPlainObject( selector ) ) {
7741			opts = selector;
7742			selector = '';
7743		}
7744	
7745		opts = _selector_opts( opts );
7746	
7747		var inst = this.iterator( 'table', function ( settings ) {
7748			return __row_selector( settings, selector, opts );
7749		}, 1 );
7750	
7751		// Want argument shifting here and in __row_selector?
7752		inst.selector.rows = selector;
7753		inst.selector.opts = opts;
7754	
7755		return inst;
7756	} );
7757	
7758	_api_register( 'rows().nodes()', function () {
7759		return this.iterator( 'row', function ( settings, row ) {
7760			return settings.aoData[ row ].nTr || undefined;
7761		}, 1 );
7762	} );
7763	
7764	_api_register( 'rows().data()', function () {
7765		return this.iterator( true, 'rows', function ( settings, rows ) {
7766			return _pluck_order( settings.aoData, rows, '_aData' );
7767		}, 1 );
7768	} );
7769	
7770	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7771		return this.iterator( 'row', function ( settings, row ) {
7772			var r = settings.aoData[ row ];
7773			return type === 'search' ? r._aFilterData : r._aSortData;
7774		}, 1 );
7775	} );
7776	
7777	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7778		return this.iterator( 'row', function ( settings, row ) {
7779			_fnInvalidate( settings, row, src );
7780		} );
7781	} );
7782	
7783	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7784		return this.iterator( 'row', function ( settings, row ) {
7785			return row;
7786		}, 1 );
7787	} );
7788	
7789	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7790		var a = [];
7791		var context = this.context;
7792	
7793		// `iterator` will drop undefined values, but in this case we want them
7794		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7795			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7796				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7797				a.push( (hash === true ? '#' : '' )+ id );
7798			}
7799		}
7800	
7801		return new _Api( context, a );
7802	} );
7803	
7804	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7805		this.iterator( 'row', function ( settings, row ) {
7806			var data = settings.aoData;
7807			var rowData = data[ row ];
7808	
7809			// Delete from the display arrays
7810			var idx = settings.aiDisplayMaster.indexOf(row);
7811			if (idx !== -1) {
7812				settings.aiDisplayMaster.splice(idx, 1);
7813			}
7814	
7815			// For server-side processing tables - subtract the deleted row from the count
7816			if ( settings._iRecordsDisplay > 0 ) {
7817				settings._iRecordsDisplay--;
7818			}
7819	
7820			// Check for an 'overflow' they case for displaying the table
7821			_fnLengthOverflow( settings );
7822	
7823			// Remove the row's ID reference if there is one
7824			var id = settings.rowIdFn( rowData._aData );
7825			if ( id !== undefined ) {
7826				delete settings.aIds[ id ];
7827			}
7828	
7829			data[row] = null;
7830		} );
7831	
7832		return this;
7833	} );
7834	
7835	
7836	_api_register( 'rows.add()', function ( rows ) {
7837		var newRows = this.iterator( 'table', function ( settings ) {
7838				var row, i, ien;
7839				var out = [];
7840	
7841				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7842					row = rows[i];
7843	
7844					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7845						out.push( _fnAddTr( settings, row )[0] );
7846					}
7847					else {
7848						out.push( _fnAddData( settings, row ) );
7849					}
7850				}
7851	
7852				return out;
7853			}, 1 );
7854	
7855		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
7856		var modRows = this.rows( -1 );
7857		modRows.pop();
7858		modRows.push.apply(modRows, newRows);
7859	
7860		return modRows;
7861	} );
7862	
7863	
7864	
7865	
7866	
7867	/**
7868	 *
7869	 */
7870	_api_register( 'row()', function ( selector, opts ) {
7871		return _selector_first( this.rows( selector, opts ) );
7872	} );
7873	
7874	
7875	_api_register( 'row().data()', function ( data ) {
7876		var ctx = this.context;
7877	
7878		if ( data === undefined ) {
7879			// Get
7880			return ctx.length && this.length && this[0].length ?
7881				ctx[0].aoData[ this[0] ]._aData :
7882				undefined;
7883		}
7884	
7885		// Set
7886		var row = ctx[0].aoData[ this[0] ];
7887		row._aData = data;
7888	
7889		// If the DOM has an id, and the data source is an array
7890		if ( Array.isArray( data ) && row.nTr && row.nTr.id ) {
7891			_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
7892		}
7893	
7894		// Automatically invalidate
7895		_fnInvalidate( ctx[0], this[0], 'data' );
7896	
7897		return this;
7898	} );
7899	
7900	
7901	_api_register( 'row().node()', function () {
7902		var ctx = this.context;
7903	
7904		return ctx.length && this.length && this[0].length ?
7905			ctx[0].aoData[ this[0] ].nTr || null :
7906			null;
7907	} );
7908	
7909	
7910	_api_register( 'row.add()', function ( row ) {
7911		// Allow a jQuery object to be passed in - only a single row is added from
7912		// it though - the first element in the set
7913		if ( row instanceof $ && row.length ) {
7914			row = row[0];
7915		}
7916	
7917		var rows = this.iterator( 'table', function ( settings ) {
7918			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7919				return _fnAddTr( settings, row )[0];
7920			}
7921			return _fnAddData( settings, row );
7922		} );
7923	
7924		// Return an Api.rows() extended instance, with the newly added row selected
7925		return this.row( rows[0] );
7926	} );
7927	
7928	
7929	$(document).on('plugin-init.dt', function (e, context) {
7930		var api = new _Api( context );
7931	
7932		api.on( 'stateSaveParams.DT', function ( e, settings, d ) {
7933			// This could be more compact with the API, but it is a lot faster as a simple
7934			// internal loop
7935			var idFn = settings.rowIdFn;
7936			var rows = settings.aiDisplayMaster;
7937			var ids = [];
7938	
7939			for (var i=0 ; i<rows.length ; i++) {
7940				var rowIdx = rows[i];
7941				var data = settings.aoData[rowIdx];
7942	
7943				if (data._detailsShow) {
7944					ids.push( '#' + idFn(data._aData) );
7945				}
7946			}
7947	
7948			d.childRows = ids;
7949		});
7950	
7951		// For future state loads (e.g. with StateRestore)
7952		api.on( 'stateLoaded.DT', function (e, settings, state) {
7953			__details_state_load( api, state );
7954		});
7955	
7956		// And the initial load state
7957		__details_state_load( api, api.state.loaded() );
7958	});
7959	
7960	var __details_state_load = function (api, state)
7961	{
7962		if ( state && state.childRows ) {
7963			api
7964				.rows( state.childRows.map(function (id) {
7965					// Escape any `:` characters from the row id, unless previously escaped
7966					return id.replace(/(?<!\\):/g, '\\:');
7967				}) )
7968				.every( function () {
7969					_fnCallbackFire( api.settings()[0], null, 'requestChild', [ this ] )
7970				});
7971		}
7972	}
7973	
7974	var __details_add = function ( ctx, row, data, klass )
7975	{
7976		// Convert to array of TR elements
7977		var rows = [];
7978		var addRow = function ( r, k ) {
7979			// Recursion to allow for arrays of jQuery objects
7980			if ( Array.isArray( r ) || r instanceof $ ) {
7981				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
7982					addRow( r[i], k );
7983				}
7984				return;
7985			}
7986	
7987			// If we get a TR element, then just add it directly - up to the dev
7988			// to add the correct number of columns etc
7989			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
7990				r.setAttribute( 'data-dt-row', row.idx );
7991				rows.push( r );
7992			}
7993			else {
7994				// Otherwise create a row with a wrapper
7995				var created = $('<tr><td></td></tr>')
7996					.attr( 'data-dt-row', row.idx )
7997					.addClass( k );
7998				
7999				$('td', created)
8000					.addClass( k )
8001					.html( r )[0].colSpan = _fnVisbleColumns( ctx );
8002	
8003				rows.push( created[0] );
8004			}
8005		};
8006	
8007		addRow( data, klass );
8008	
8009		if ( row._details ) {
8010			row._details.detach();
8011		}
8012	
8013		row._details = $(rows);
8014	
8015		// If the children were already shown, that state should be retained
8016		if ( row._detailsShow ) {
8017			row._details.insertAfter( row.nTr );
8018		}
8019	};
8020	
8021	
8022	// Make state saving of child row details async to allow them to be batch processed
8023	var __details_state = DataTable.util.throttle(
8024		function (ctx) {
8025			_fnSaveState( ctx[0] )
8026		},
8027		500
8028	);
8029	
8030	
8031	var __details_remove = function ( api, idx )
8032	{
8033		var ctx = api.context;
8034	
8035		if ( ctx.length ) {
8036			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8037	
8038			if ( row && row._details ) {
8039				row._details.remove();
8040	
8041				row._detailsShow = undefined;
8042				row._details = undefined;
8043				$( row.nTr ).removeClass( 'dt-hasChild' );
8044				__details_state( ctx );
8045			}
8046		}
8047	};
8048	
8049	
8050	var __details_display = function ( api, show ) {
8051		var ctx = api.context;
8052	
8053		if ( ctx.length && api.length ) {
8054			var row = ctx[0].aoData[ api[0] ];
8055	
8056			if ( row._details ) {
8057				row._detailsShow = show;
8058	
8059				if ( show ) {
8060					row._details.insertAfter( row.nTr );
8061					$( row.nTr ).addClass( 'dt-hasChild' );
8062				}
8063				else {
8064					row._details.detach();
8065					$( row.nTr ).removeClass( 'dt-hasChild' );
8066				}
8067	
8068				_fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )
8069	
8070				__details_events( ctx[0] );
8071				__details_state( ctx );
8072			}
8073		}
8074	};
8075	
8076	
8077	var __details_events = function ( settings )
8078	{
8079		var api = new _Api( settings );
8080		var namespace = '.dt.DT_details';
8081		var drawEvent = 'draw'+namespace;
8082		var colvisEvent = 'column-sizing'+namespace;
8083		var destroyEvent = 'destroy'+namespace;
8084		var data = settings.aoData;
8085	
8086		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8087	
8088		if ( _pluck( data, '_details' ).length > 0 ) {
8089			// On each draw, insert the required elements into the document
8090			api.on( drawEvent, function ( e, ctx ) {
8091				if ( settings !== ctx ) {
8092					return;
8093				}
8094	
8095				api.rows( {page:'current'} ).eq(0).each( function (idx) {
8096					// Internal data grab
8097					var row = data[ idx ];
8098	
8099					if ( row._detailsShow ) {
8100						row._details.insertAfter( row.nTr );
8101					}
8102				} );
8103			} );
8104	
8105			// Column visibility change - update the colspan
8106			api.on( colvisEvent, function ( e, ctx ) {
8107				if ( settings !== ctx ) {
8108					return;
8109				}
8110	
8111				// Update the colspan for the details rows (note, only if it already has
8112				// a colspan)
8113				var row, visible = _fnVisbleColumns( ctx );
8114	
8115				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8116					row = data[i];
8117	
8118					if ( row && row._details ) {
8119						row._details.each(function () {
8120							var el = $(this).children('td');
8121	
8122							if (el.length == 1) {
8123								el.attr('colspan', visible);
8124							}
8125						});
8126					}
8127				}
8128			} );
8129	
8130			// Table destroyed - nuke any child rows
8131			api.on( destroyEvent, function ( e, ctx ) {
8132				if ( settings !== ctx ) {
8133					return;
8134				}
8135	
8136				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8137					if ( data[i] && data[i]._details ) {
8138						__details_remove( api, i );
8139					}
8140				}
8141			} );
8142		}
8143	};
8144	
8145	// Strings for the method names to help minification
8146	var _emp = '';
8147	var _child_obj = _emp+'row().child';
8148	var _child_mth = _child_obj+'()';
8149	
8150	// data can be:
8151	//  tr
8152	//  string
8153	//  jQuery or array of any of the above
8154	_api_register( _child_mth, function ( data, klass ) {
8155		var ctx = this.context;
8156	
8157		if ( data === undefined ) {
8158			// get
8159			return ctx.length && this.length && ctx[0].aoData[ this[0] ]
8160				? ctx[0].aoData[ this[0] ]._details
8161				: undefined;
8162		}
8163		else if ( data === true ) {
8164			// show
8165			this.child.show();
8166		}
8167		else if ( data === false ) {
8168			// remove
8169			__details_remove( this );
8170		}
8171		else if ( ctx.length && this.length ) {
8172			// set
8173			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8174		}
8175	
8176		return this;
8177	} );
8178	
8179	
8180	_api_register( [
8181		_child_obj+'.show()',
8182		_child_mth+'.show()' // only when `child()` was called with parameters (without
8183	], function () {         // it returns an object and this method is not executed)
8184		__details_display( this, true );
8185		return this;
8186	} );
8187	
8188	
8189	_api_register( [
8190		_child_obj+'.hide()',
8191		_child_mth+'.hide()' // only when `child()` was called with parameters (without
8192	], function () {         // it returns an object and this method is not executed)
8193		__details_display( this, false );
8194		return this;
8195	} );
8196	
8197	
8198	_api_register( [
8199		_child_obj+'.remove()',
8200		_child_mth+'.remove()' // only when `child()` was called with parameters (without
8201	], function () {           // it returns an object and this method is not executed)
8202		__details_remove( this );
8203		return this;
8204	} );
8205	
8206	
8207	_api_register( _child_obj+'.isShown()', function () {
8208		var ctx = this.context;
8209	
8210		if ( ctx.length && this.length ) {
8211			// _detailsShown as false or undefined will fall through to return false
8212			return ctx[0].aoData[ this[0] ]._detailsShow || false;
8213		}
8214		return false;
8215	} );
8216	
8217	
8218	
8219	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8220	 * Columns
8221	 *
8222	 * {integer}           - column index (>=0 count from left, <0 count from right)
8223	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8224	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8225	 * "{string}:name"     - column name
8226	 * "{string}"          - jQuery selector on column header nodes
8227	 *
8228	 */
8229	
8230	// can be an array of these items, comma separated list, or an array of comma
8231	// separated lists
8232	
8233	var __re_column_selector = /^([^:]+):(name|title|visIdx|visible)$/;
8234	
8235	
8236	// r1 and r2 are redundant - but it means that the parameters match for the
8237	// iterator callback in columns().data()
8238	var __columnData = function ( settings, column, r1, r2, rows, type ) {
8239		var a = [];
8240		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8241			a.push( _fnGetCellData( settings, rows[row], column, type ) );
8242		}
8243		return a;
8244	};
8245	
8246	
8247	var __column_header = function ( settings, column, row ) {
8248		var header = settings.aoHeader;
8249		var target = row !== undefined
8250			? row
8251			: settings.bSortCellsTop // legacy support
8252				? 0
8253				: header.length - 1;
8254	
8255		return header[target][column].cell;
8256	};
8257	
8258	var __column_selector = function ( settings, selector, opts )
8259	{
8260		var
8261			columns = settings.aoColumns,
8262			names = _pluck( columns, 'sName' ),
8263			titles = _pluck( columns, 'sTitle' ),
8264			cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
8265			nodes = _unique( _flatten([], cells) );
8266		
8267		var run = function ( s ) {
8268			var selInt = _intVal( s );
8269	
8270			// Selector - all
8271			if ( s === '' ) {
8272				return _range( columns.length );
8273			}
8274	
8275			// Selector - index
8276			if ( selInt !== null ) {
8277				return [ selInt >= 0 ?
8278					selInt : // Count from left
8279					columns.length + selInt // Count from right (+ because its a negative value)
8280				];
8281			}
8282	
8283			// Selector = function
8284			if ( typeof s === 'function' ) {
8285				var rows = _selector_row_indexes( settings, opts );
8286	
8287				return columns.map(function (col, idx) {
8288					return s(
8289							idx,
8290							__columnData( settings, idx, 0, 0, rows ),
8291							__column_header( settings, idx )
8292						) ? idx : null;
8293				});
8294			}
8295	
8296			// jQuery or string selector
8297			var match = typeof s === 'string' ?
8298				s.match( __re_column_selector ) :
8299				'';
8300	
8301			if ( match ) {
8302				switch( match[2] ) {
8303					case 'visIdx':
8304					case 'visible':
8305						var idx = parseInt( match[1], 10 );
8306						// Visible index given, convert to column index
8307						if ( idx < 0 ) {
8308							// Counting from the right
8309							var visColumns = columns.map( function (col,i) {
8310								return col.bVisible ? i : null;
8311							} );
8312							return [ visColumns[ visColumns.length + idx ] ];
8313						}
8314						// Counting from the left
8315						return [ _fnVisibleToColumnIndex( settings, idx ) ];
8316	
8317					case 'name':
8318						// match by name. `names` is column index complete and in order
8319						return names.map( function (name, i) {
8320							return name === match[1] ? i : null;
8321						} );
8322	
8323					case 'title':
8324						// match by column title
8325						return titles.map( function (title, i) {
8326							return title === match[1] ? i : null;
8327						} );
8328	
8329					default:
8330						return [];
8331				}
8332			}
8333	
8334			// Cell in the table body
8335			if ( s.nodeName && s._DT_CellIndex ) {
8336				return [ s._DT_CellIndex.column ];
8337			}
8338	
8339			// jQuery selector on the TH elements for the columns
8340			var jqResult = $( nodes )
8341				.filter( s )
8342				.map( function () {
8343					return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
8344				} )
8345				.toArray();
8346	
8347			if ( jqResult.length || ! s.nodeName ) {
8348				return jqResult;
8349			}
8350	
8351			// Otherwise a node which might have a `dt-column` data attribute, or be
8352			// a child or such an element
8353			var host = $(s).closest('*[data-dt-column]');
8354			return host.length ?
8355				[ host.data('dt-column') ] :
8356				[];
8357		};
8358	
8359		return _selector_run( 'column', selector, run, settings, opts );
8360	};
8361	
8362	
8363	var __setColumnVis = function ( settings, column, vis ) {
8364		var
8365			cols = settings.aoColumns,
8366			col  = cols[ column ],
8367			data = settings.aoData,
8368			cells, i, ien, tr;
8369	
8370		// Get
8371		if ( vis === undefined ) {
8372			return col.bVisible;
8373		}
8374	
8375		// Set
8376		// No change
8377		if ( col.bVisible === vis ) {
8378			return false;
8379		}
8380	
8381		if ( vis ) {
8382			// Insert column
8383			// Need to decide if we should use appendChild or insertBefore
8384			var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column+1);
8385	
8386			for ( i=0, ien=data.length ; i<ien ; i++ ) {
8387				if (data[i]) {
8388					tr = data[i].nTr;
8389					cells = data[i].anCells;
8390	
8391					if ( tr ) {
8392						// insertBefore can act like appendChild if 2nd arg is null
8393						tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8394					}
8395				}
8396			}
8397		}
8398		else {
8399			// Remove column
8400			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
8401		}
8402	
8403		// Common actions
8404		col.bVisible = vis;
8405	
8406		_colGroup(settings);
8407		
8408		return true;
8409	};
8410	
8411	
8412	_api_register( 'columns()', function ( selector, opts ) {
8413		// argument shifting
8414		if ( selector === undefined ) {
8415			selector = '';
8416		}
8417		else if ( $.isPlainObject( selector ) ) {
8418			opts = selector;
8419			selector = '';
8420		}
8421	
8422		opts = _selector_opts( opts );
8423	
8424		var inst = this.iterator( 'table', function ( settings ) {
8425			return __column_selector( settings, selector, opts );
8426		}, 1 );
8427	
8428		// Want argument shifting here and in _row_selector?
8429		inst.selector.cols = selector;
8430		inst.selector.opts = opts;
8431	
8432		return inst;
8433	} );
8434	
8435	_api_registerPlural( 'columns().header()', 'column().header()', function ( row ) {
8436		return this.iterator( 'column', function (settings, column) {
8437			return __column_header(settings, column, row);
8438		}, 1 );
8439	} );
8440	
8441	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( row ) {
8442		return this.iterator( 'column', function ( settings, column ) {
8443			var footer = settings.aoFooter;
8444	
8445			if (! footer.length) {
8446				return null;
8447			}
8448	
8449			return settings.aoFooter[row !== undefined ? row : 0][column].cell;
8450		}, 1 );
8451	} );
8452	
8453	_api_registerPlural( 'columns().data()', 'column().data()', function () {
8454		return this.iterator( 'column-rows', __columnData, 1 );
8455	} );
8456	
8457	_api_registerPlural( 'columns().render()', 'column().render()', function ( type ) {
8458		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8459			return __columnData( settings, column, i, j, rows, type );
8460		}, 1 );
8461	} );
8462	
8463	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8464		return this.iterator( 'column', function ( settings, column ) {
8465			return settings.aoColumns[column].mData;
8466		}, 1 );
8467	} );
8468	
8469	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8470		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8471			return _pluck_order( settings.aoData, rows,
8472				type === 'search' ? '_aFilterData' : '_aSortData', column
8473			);
8474		}, 1 );
8475	} );
8476	
8477	_api_registerPlural( 'columns().init()', 'column().init()', function () {
8478		return this.iterator( 'column', function ( settings, column ) {
8479			return settings.aoColumns[column];
8480		}, 1 );
8481	} );
8482	
8483	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8484		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8485			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8486		}, 1 );
8487	} );
8488	
8489	_api_registerPlural( 'columns().titles()', 'column().title()', function (title, row) {
8490		return this.iterator( 'column', function ( settings, column ) {
8491			// Argument shifting
8492			if (typeof title === 'number') {
8493				row = title;
8494				title = undefined;
8495			}
8496	
8497			var span = $('span.dt-column-title', this.column(column).header(row));
8498	
8499			if (title !== undefined) {
8500				span.html(title);
8501				return this;
8502			}
8503	
8504			return span.html();
8505		}, 1 );
8506	} );
8507	
8508	_api_registerPlural( 'columns().types()', 'column().type()', function () {
8509		return this.iterator( 'column', function ( settings, column ) {
8510			var type = settings.aoColumns[column].sType;
8511	
8512			// If the type was invalidated, then resolve it. This actually does
8513			// all columns at the moment. Would only happen once if getting all
8514			// column's data types.
8515			if (! type) {
8516				_fnColumnTypes(settings);
8517			}
8518	
8519			return type;
8520		}, 1 );
8521	} );
8522	
8523	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8524		var that = this;
8525		var changed = [];
8526		var ret = this.iterator( 'column', function ( settings, column ) {
8527			if ( vis === undefined ) {
8528				return settings.aoColumns[ column ].bVisible;
8529			} // else
8530			
8531			if (__setColumnVis( settings, column, vis )) {
8532				changed.push(column);
8533			}
8534		} );
8535	
8536		// Group the column visibility changes
8537		if ( vis !== undefined ) {
8538			this.iterator( 'table', function ( settings ) {
8539				// Redraw the header after changes
8540				_fnDrawHead( settings, settings.aoHeader );
8541				_fnDrawHead( settings, settings.aoFooter );
8542		
8543				// Update colspan for no records display. Child rows and extensions will use their own
8544				// listeners to do this - only need to update the empty table item here
8545				if ( ! settings.aiDisplay.length ) {
8546					$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8547				}
8548		
8549				_fnSaveState( settings );
8550	
8551				// Second loop once the first is done for events
8552				that.iterator( 'column', function ( settings, column ) {
8553					if (changed.includes(column)) {
8554						_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8555					}
8556				} );
8557	
8558				if ( changed.length && (calc === undefined || calc) ) {
8559					that.columns.adjust();
8560				}
8561			});
8562		}
8563	
8564		return ret;
8565	} );
8566	
8567	_api_registerPlural( 'columns().widths()', 'column().width()', function () {
8568		// Injects a fake row into the table for just a moment so the widths can
8569		// be read, regardless of colspan in the header and rows being present in
8570		// the body
8571		var columns = this.columns(':visible').count();
8572		var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
8573	
8574		$(this.table().body()).append(row);
8575	
8576		var widths = row.children().map(function () {
8577			return $(this).outerWidth();
8578		});
8579	
8580		row.remove();
8581		
8582		return this.iterator( 'column', function ( settings, column ) {
8583			var visIdx = _fnColumnIndexToVisible( settings, column );
8584	
8585			return visIdx !== null ? widths[visIdx] : 0;
8586		}, 1);
8587	} );
8588	
8589	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8590		return this.iterator( 'column', function ( settings, column ) {
8591			return type === 'visible' ?
8592				_fnColumnIndexToVisible( settings, column ) :
8593				column;
8594		}, 1 );
8595	} );
8596	
8597	_api_register( 'columns.adjust()', function () {
8598		return this.iterator( 'table', function ( settings ) {
8599			_fnAdjustColumnSizing( settings );
8600		}, 1 );
8601	} );
8602	
8603	_api_register( 'column.index()', function ( type, idx ) {
8604		if ( this.context.length !== 0 ) {
8605			var ctx = this.context[0];
8606	
8607			if ( type === 'fromVisible' || type === 'toData' ) {
8608				return _fnVisibleToColumnIndex( ctx, idx );
8609			}
8610			else if ( type === 'fromData' || type === 'toVisible' ) {
8611				return _fnColumnIndexToVisible( ctx, idx );
8612			}
8613		}
8614	} );
8615	
8616	_api_register( 'column()', function ( selector, opts ) {
8617		return _selector_first( this.columns( selector, opts ) );
8618	} );
8619	
8620	var __cell_selector = function ( settings, selector, opts )
8621	{
8622		var data = settings.aoData;
8623		var rows = _selector_row_indexes( settings, opts );
8624		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8625		var allCells = $(_flatten( [], cells ));
8626		var row;
8627		var columns = settings.aoColumns.length;
8628		var a, i, ien, j, o, host;
8629	
8630		var run = function ( s ) {
8631			var fnSelector = typeof s === 'function';
8632	
8633			if ( s === null || s === undefined || fnSelector ) {
8634				// All cells and function selectors
8635				a = [];
8636	
8637				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
vendor: 4,056 bytes, lines 8638-8796
8638					row = rows[i];
8639	
8640					for ( j=0 ; j<columns ; j++ ) {
8641						o = {
8642							row: row,
8643							column: j
8644						};
8645	
8646						if ( fnSelector ) {
8647							// Selector - function
8648							host = data[ row ];
8649	
8650							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8651								a.push( o );
8652							}
8653						}
8654						else {
8655							// Selector - all
8656							a.push( o );
8657						}
8658					}
8659				}
8660	
8661				return a;
8662			}
8663			
8664			// Selector - index
8665			if ( $.isPlainObject( s ) ) {
8666				// Valid cell index and its in the array of selectable rows
8667				return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
8668					[s] :
8669					[];
8670			}
8671	
8672			// Selector - jQuery filtered cells
8673			var jqResult = allCells
8674				.filter( s )
8675				.map( function (i, el) {
8676					return { // use a new object, in case someone changes the values
8677						row:    el._DT_CellIndex.row,
8678						column: el._DT_CellIndex.column
8679					};
8680				} )
8681				.toArray();
8682	
8683			if ( jqResult.length || ! s.nodeName ) {
8684				return jqResult;
8685			}
8686	
8687			// Otherwise the selector is a node, and there is one last option - the
8688			// element might be a child of an element which has dt-row and dt-column
8689			// data attributes
8690			host = $(s).closest('*[data-dt-row]');
8691			return host.length ?
8692				[ {
8693					row: host.data('dt-row'),
8694					column: host.data('dt-column')
8695				} ] :
8696				[];
8697		};
8698	
8699		return _selector_run( 'cell', selector, run, settings, opts );
8700	};
8701	
8702	
8703	
8704	
8705	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8706		// Argument shifting
8707		if ( $.isPlainObject( rowSelector ) ) {
8708			// Indexes
8709			if ( rowSelector.row === undefined ) {
8710				// Selector options in first parameter
8711				opts = rowSelector;
8712				rowSelector = null;
8713			}
8714			else {
8715				// Cell index objects in first parameter
8716				opts = columnSelector;
8717				columnSelector = null;
8718			}
8719		}
8720		if ( $.isPlainObject( columnSelector ) ) {
8721			opts = columnSelector;
8722			columnSelector = null;
8723		}
8724	
8725		// Cell selector
8726		if ( columnSelector === null || columnSelector === undefined ) {
8727			return this.iterator( 'table', function ( settings ) {
8728				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8729			} );
8730		}
8731	
8732		// The default built in options need to apply to row and columns
8733		var internalOpts = opts ? {
8734			page: opts.page,
8735			order: opts.order,
8736			search: opts.search
8737		} : {};
8738	
8739		// Row + column selector
8740		var columns = this.columns( columnSelector, internalOpts );
8741		var rows = this.rows( rowSelector, internalOpts );
8742		var i, ien, j, jen;
8743	
8744		var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
8745			var a = [];
8746	
8747			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8748				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8749					a.push( {
8750						row:    rows[idx][i],
8751						column: columns[idx][j]
8752					} );
8753				}
8754			}
8755	
8756			return a;
8757		}, 1 );
8758	
8759		// There is currently only one extension which uses a cell selector extension
8760		// It is a _major_ performance drag to run this if it isn't needed, so this is
8761		// an extension specific check at the moment
8762		var cells = opts && opts.selected ?
8763			this.cells( cellsNoOpts, opts ) :
8764			cellsNoOpts;
8765	
8766		$.extend( cells.selector, {
8767			cols: columnSelector,
8768			rows: rowSelector,
8769			opts: opts
8770		} );
8771	
8772		return cells;
8773	} );
8774	
8775	
8776	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8777		return this.iterator( 'cell', function ( settings, row, column ) {
8778			var data = settings.aoData[ row ];
8779	
8780			return data && data.anCells ?
8781				data.anCells[ column ] :
8782				undefined;
8783		}, 1 );
8784	} );
8785	
8786	
8787	_api_register( 'cells().data()', function () {
8788		return this.iterator( 'cell', function ( settings, row, column ) {
8789			return _fnGetCellData( settings, row, column );
8790		}, 1 );
8791	} );
8792	
8793	
8794	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8795		type = type === 'search' ? '_aFilterData' : '_aSortData';
8796	
8797		return this.iterator( 'cell', function ( settings, row, column ) {
8798			return settings.aoData[ row ][ type ][ column ];
8799		}, 1 );
8800	} );
8801	
8802	
8803	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8804		return this.iterator( 'cell', function ( settings, row, column ) {
8805			return _fnGetCellData( settings, row, column, type );
8806		}, 1 );
8807	} );
8808	
8809	
8810	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8811		return this.iterator( 'cell', function ( settings, row, column ) {
8812			return {
8813				row: row,
8814				column: column,
8815				columnVisible: _fnColumnIndexToVisible( settings, column )
8816			};
8817		}, 1 );
8818	} );
8819	
8820	
8821	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8822		return this.iterator( 'cell', function ( settings, row, column ) {
8823			_fnInvalidate( settings, row, src, column );
8824		} );
8825	} );
8826	
8827	
8828	
8829	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8830		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8831	} );
8832	
8833	
8834	_api_register( 'cell().data()', function ( data ) {
8835		var ctx = this.context;
8836		var cell = this[0];
8837	
8838		if ( data === undefined ) {
8839			// Get
8840			return ctx.length && cell.length ?
8841				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8842				undefined;
8843		}
8844	
8845		// Set
8846		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8847		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8848	
8849		return this;
8850	} );
8851	
8852	
8853	
8854	/**
8855	 * Get current ordering (sorting) that has been applied to the table.
8856	 *
8857	 * @returns {array} 2D array containing the sorting information for the first
8858	 *   table in the current context. Each element in the parent array represents
8859	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
8860	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8861	 *   the column index that the sorting condition applies to, the second is the
8862	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
8863	 *   index of the sorting order from the `column.sorting` initialisation array.
8864	 *//**
8865	 * Set the ordering for the table.
8866	 *
8867	 * @param {integer} order Column index to sort upon.
8868	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8869	 * @returns {DataTables.Api} this
8870	 *//**
8871	 * Set the ordering for the table.
8872	 *
8873	 * @param {array} order 1D array of sorting information to be applied.
8874	 * @param {array} [...] Optional additional sorting conditions
8875	 * @returns {DataTables.Api} this
8876	 *//**
8877	 * Set the ordering for the table.
8878	 *
8879	 * @param {array} order 2D array of sorting information to be applied.
8880	 * @returns {DataTables.Api} this
8881	 */
8882	_api_register( 'order()', function ( order, dir ) {
8883		var ctx = this.context;
8884		var args = Array.prototype.slice.call( arguments );
8885	
8886		if ( order === undefined ) {
8887			// get
8888			return ctx.length !== 0 ?
8889				ctx[0].aaSorting :
8890				undefined;
8891		}
8892	
8893		// set
8894		if ( typeof order === 'number' ) {
8895			// Simple column / direction passed in
8896			order = [ [ order, dir ] ];
8897		}
8898		else if ( args.length > 1 ) {
8899			// Arguments passed in (list of 1D arrays)
8900			order = args;
8901		}
8902		// otherwise a 2D array was passed in
8903	
8904		return this.iterator( 'table', function ( settings ) {
8905			settings.aaSorting = Array.isArray(order) ? order.slice() : order;
8906		} );
8907	} );
8908	
8909	
8910	/**
8911	 * Attach a sort listener to an element for a given column
8912	 *
8913	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8914	 *   listener to. This can take the form of a single DOM node, a jQuery
8915	 *   collection of nodes or a jQuery selector which will identify the node(s).
8916	 * @param {integer} column the column that a click on this node will sort on
8917	 * @param {function} [callback] callback function when sort is run
8918	 * @returns {DataTables.Api} this
8919	 */
8920	_api_register( 'order.listener()', function ( node, column, callback ) {
8921		return this.iterator( 'table', function ( settings ) {
8922			_fnSortAttachListener(settings, node, {}, column, callback);
8923		} );
8924	} );
8925	
8926	
8927	_api_register( 'order.fixed()', function ( set ) {
8928		if ( ! set ) {
8929			var ctx = this.context;
8930			var fixed = ctx.length ?
8931				ctx[0].aaSortingFixed :
8932				undefined;
8933	
8934			return Array.isArray( fixed ) ?
8935				{ pre: fixed } :
8936				fixed;
8937		}
8938	
8939		return this.iterator( 'table', function ( settings ) {
8940			settings.aaSortingFixed = $.extend( true, {}, set );
8941		} );
8942	} );
8943	
8944	
8945	// Order by the selected column(s)
8946	_api_register( [
8947		'columns().order()',
8948		'column().order()'
8949	], function ( dir ) {
8950		var that = this;
8951	
8952		if ( ! dir ) {
8953			return this.iterator( 'column', function ( settings, idx ) {
8954				var sort = _fnSortFlatten( settings );
8955	
8956				for ( var i=0, ien=sort.length ; i<ien ; i++ ) {
8957					if ( sort[i].col === idx ) {
8958						return sort[i].dir;
8959					}
8960				}
8961	
8962				return null;
8963			}, 1 );
8964		}
8965		else {
8966			return this.iterator( 'table', function ( settings, i ) {
8967				settings.aaSorting = that[i].map( function (col) {
8968					return [ col, dir ];
8969				} );
8970			} );
8971		}
8972	} );
8973	
8974	_api_registerPlural('columns().orderable()', 'column().orderable()', function ( directions ) {
8975		return this.iterator( 'column', function ( settings, idx ) {
8976			var col = settings.aoColumns[idx];
8977	
8978			return directions ?
8979				col.asSorting :
8980				col.bSortable;
8981		}, 1 );
8982	} );
8983	
8984	
8985	_api_register( 'processing()', function ( show ) {
8986		return this.iterator( 'table', function ( ctx ) {
8987			_fnProcessingDisplay( ctx, show );
8988		} );
8989	} );
8990	
8991	
8992	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8993		var ctx = this.context;
8994	
8995		if ( input === undefined ) {
8996			// get
8997			return ctx.length !== 0 ?
8998				ctx[0].oPreviousSearch.search :
8999				undefined;
9000		}
9001	
9002		// set
9003		return this.iterator( 'table', function ( settings ) {
9004			if ( ! settings.oFeatures.bFilter ) {
9005				return;
9006			}
9007	
9008			if (typeof regex === 'object') {
9009				// New style options to pass to the search builder
9010				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, regex, {
9011					search: input
9012				} ) );
9013			}
9014			else {
9015				// Compat for the old options
9016				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, {
9017					search: input,
9018					regex:  regex === null ? false : regex,
9019					smart:  smart === null ? true  : smart,
9020					caseInsensitive: caseInsen === null ? true : caseInsen
9021				} ) );
9022			}
9023		} );
9024	} );
9025	
9026	_api_register( 'search.fixed()', function ( name, search ) {
9027		var ret = this.iterator( true, 'table', function ( settings ) {
9028			var fixed = settings.searchFixed;
9029	
9030			if (! name) {
9031				return Object.keys(fixed)
9032			}
9033			else if (search === undefined) {
9034				return fixed[name];
9035			}
9036			else if (search === null) {
9037				delete fixed[name];
9038			}
9039			else {
9040				fixed[name] = search;
9041			}
9042	
9043			return this;
9044		} );
9045	
9046		return name !== undefined && search === undefined
9047			? ret[0]
9048			: ret;
9049	} );
9050	
9051	_api_registerPlural(
9052		'columns().search()',
9053		'column().search()',
9054		function ( input, regex, smart, caseInsen ) {
9055			return this.iterator( 'column', function ( settings, column ) {
9056				var preSearch = settings.aoPreSearchCols;
9057	
9058				if ( input === undefined ) {
9059					// get
9060					return preSearch[ column ].search;
9061				}
9062	
9063				// set
9064				if ( ! settings.oFeatures.bFilter ) {
9065					return;
9066				}
9067	
9068				if (typeof regex === 'object') {
9069					// New style options to pass to the search builder
9070					$.extend( preSearch[ column ], regex, {
9071						search: input
9072					} );
9073				}
9074				else {
9075					// Old style (with not all options available)
9076					$.extend( preSearch[ column ], {
9077						search: input,
9078						regex:  regex === null ? false : regex,
9079						smart:  smart === null ? true  : smart,
9080						caseInsensitive: caseInsen === null ? true : caseInsen
9081					} );
9082				}
9083	
9084				_fnFilterComplete( settings, settings.oPreviousSearch );
9085			} );
9086		}
9087	);
9088	
9089	_api_register([
9090			'columns().search.fixed()',
9091			'column().search.fixed()'
9092		],
9093		function ( name, search ) {
9094			var ret = this.iterator( true, 'column', function ( settings, colIdx ) {
9095				var fixed = settings.aoColumns[colIdx].searchFixed;
9096	
9097				if (! name) {
9098					return Object.keys(fixed)
9099				}
9100				else if (search === undefined) {
9101					return fixed[name];
9102				}
9103				else if (search === null) {
9104					delete fixed[name];
9105				}
9106				else {
9107					fixed[name] = search;
9108				}
9109	
9110				return this;
9111			} );
9112	
9113			return name !== undefined && search === undefined
9114				? ret[0]
9115				: ret;
9116		}
9117	);
9118	/*
9119	 * State API methods
9120	 */
9121	
9122	_api_register( 'state()', function ( set, ignoreTime ) {
9123		// getter
9124		if ( ! set ) {
9125			return this.context.length ?
9126				this.context[0].oSavedState :
9127				null;
9128		}
9129	
9130		var setMutate = $.extend( true, {}, set );
9131	
9132		// setter
9133		return this.iterator( 'table', function ( settings ) {
9134			if ( ignoreTime !== false ) {
9135				setMutate.time = +new Date() + 100;
9136			}
9137	
9138			_fnImplementState( settings, setMutate, function(){} );
9139		} );
9140	} );
9141	
9142	
9143	_api_register( 'state.clear()', function () {
9144		return this.iterator( 'table', function ( settings ) {
9145			// Save an empty object
9146			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9147		} );
9148	} );
9149	
9150	
9151	_api_register( 'state.loaded()', function () {
9152		return this.context.length ?
9153			this.context[0].oLoadedState :
9154			null;
9155	} );
9156	
9157	
9158	_api_register( 'state.save()', function () {
9159		return this.iterator( 'table', function ( settings ) {
9160			_fnSaveState( settings );
9161		} );
9162	} );
9163	
9164	/**
9165	 * Set the jQuery or window object to be used by DataTables
9166	 *
9167	 * @param {*} module Library / container object
9168	 * @param {string} [type] Library or container type `lib`, `win` or `datetime`.
9169	 *   If not provided, automatic detection is attempted.
9170	 */
9171	DataTable.use = function (module, type) {
9172		if (type === 'lib' || module.fn) {
9173			$ = module;
9174		}
9175		else if (type == 'win' || module.document) {
9176			window = module;
9177			document = module.document;
9178		}
9179		else if (type === 'datetime' || module.type === 'DateTime') {
9180			DataTable.DateTime = module;
9181		}
9182	}
9183	
9184	/**
9185	 * CommonJS factory function pass through. This will check if the arguments
9186	 * given are a window object or a jQuery object. If so they are set
9187	 * accordingly.
9188	 * @param {*} root Window
9189	 * @param {*} jq jQUery
9190	 * @returns {boolean} Indicator
9191	 */
9192	DataTable.factory = function (root, jq) {
9193		var is = false;
9194	
9195		// Test if the first parameter is a window object
9196		if (root && root.document) {
9197			window = root;
9198			document = root.document;
9199		}
9200	
9201		// Test if the second parameter is a jQuery object
9202		if (jq && jq.fn && jq.fn.jquery) {
9203			$ = jq;
9204			is = true;
9205		}
9206	
9207		return is;
9208	}
9209	
9210	/**
9211	 * Provide a common method for plug-ins to check the version of DataTables being
9212	 * used, in order to ensure compatibility.
9213	 *
9214	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
9215	 *    Note that the formats "X" and "X.Y" are also acceptable.
9216	 *  @param {string} [version2=current DataTables version] As above, but optional.
9217	 *   If not given the current DataTables version will be used.
9218	 *  @returns {boolean} true if this version of DataTables is greater or equal to
9219	 *    the required version, or false if this version of DataTales is not
9220	 *    suitable
9221	 *  @static
9222	 *  @dtopt API-Static
9223	 *
9224	 *  @example
9225	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9226	 */
9227	DataTable.versionCheck = function( version, version2 )
9228	{
9229		var aThis = version2 ?
9230			version2.split('.') :
9231			DataTable.version.split('.');
9232		var aThat = version.split('.');
9233		var iThis, iThat;
9234	
9235		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9236			iThis = parseInt( aThis[i], 10 ) || 0;
9237			iThat = parseInt( aThat[i], 10 ) || 0;
9238	
9239			// Parts are the same, keep comparing
9240			if (iThis === iThat) {
9241				continue;
9242			}
9243	
9244			// Parts are different, return immediately
9245			return iThis > iThat;
9246		}
9247	
9248		return true;
9249	};
9250	
9251	
9252	/**
9253	 * Check if a `<table>` node is a DataTable table already or not.
9254	 *
9255	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9256	 *      selector for the table to test. Note that if more than more than one
9257	 *      table is passed on, only the first will be checked
9258	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
9259	 *  @static
9260	 *  @dtopt API-Static
9261	 *
9262	 *  @example
9263	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9264	 *      $('#example').dataTable();
9265	 *    }
9266	 */
9267	DataTable.isDataTable = function ( table )
9268	{
9269		var t = $(table).get(0);
9270		var is = false;
9271	
9272		if ( table instanceof DataTable.Api ) {
9273			return true;
9274		}
9275	
9276		$.each( DataTable.settings, function (i, o) {
9277			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9278			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9279	
9280			if ( o.nTable === t || head === t || foot === t ) {
9281				is = true;
9282			}
9283		} );
9284	
9285		return is;
9286	};
9287	
9288	
9289	/**
9290	 * Get all DataTable tables that have been initialised - optionally you can
9291	 * select to get only currently visible tables.
9292	 *
9293	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9294	 *    or visible tables only.
9295	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9296	 *    DataTables
9297	 *  @static
9298	 *  @dtopt API-Static
9299	 *
9300	 *  @example
9301	 *    $.each( $.fn.dataTable.tables(true), function () {
9302	 *      $(table).DataTable().columns.adjust();
9303	 *    } );
9304	 */
9305	DataTable.tables = function ( visible )
9306	{
9307		var api = false;
9308	
9309		if ( $.isPlainObject( visible ) ) {
9310			api = visible.api;
9311			visible = visible.visible;
9312		}
9313	
9314		var a = DataTable.settings
9315			.filter( function (o) {
9316				return !visible || (visible && $(o.nTable).is(':visible')) 
9317					? true
9318					: false;
9319			} )
9320			.map( function (o) {
9321				return o.nTable;
9322			});
9323	
9324		return api ?
9325			new _Api( a ) :
9326			a;
9327	};
9328	
9329	
9330	/**
9331	 * Convert from camel case parameters to Hungarian notation. This is made public
9332	 * for the extensions to provide the same ability as DataTables core to accept
9333	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9334	 * parameters.
9335	 *
9336	 *  @param {object} src The model object which holds all parameters that can be
9337	 *    mapped.
9338	 *  @param {object} user The object to convert from camel case to Hungarian.
9339	 *  @param {boolean} force When set to `true`, properties which already have a
9340	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
9341	 *    won't be.
9342	 */
9343	DataTable.camelToHungarian = _fnCamelToHungarian;
9344	
9345	
9346	
9347	/**
9348	 *
9349	 */
9350	_api_register( '$()', function ( selector, opts ) {
9351		var
9352			rows   = this.rows( opts ).nodes(), // Get all rows
9353			jqRows = $(rows);
9354	
9355		return $( [].concat(
9356			jqRows.filter( selector ).toArray(),
9357			jqRows.find( selector ).toArray()
9358		) );
9359	} );
9360	
9361	
9362	// jQuery functions to operate on the tables
9363	$.each( [ 'on', 'one', 'off' ], function (i, key) {
9364		_api_register( key+'()', function ( /* event, handler */ ) {
9365			var args = Array.prototype.slice.call(arguments);
9366	
9367			// Add the `dt` namespace automatically if it isn't already present
9368			args[0] = args[0].split( /\s/ ).map( function ( e ) {
9369				return ! e.match(/\.dt\b/) ?
9370					e+'.dt' :
9371					e;
9372				} ).join( ' ' );
9373	
9374			var inst = $( this.tables().nodes() );
9375			inst[key].apply( inst, args );
9376			return this;
9377		} );
9378	} );
9379	
9380	
9381	_api_register( 'clear()', function () {
9382		return this.iterator( 'table', function ( settings ) {
9383			_fnClearTable( settings );
9384		} );
9385	} );
9386	
9387	
9388	_api_register( 'error()', function (msg) {
9389		return this.iterator( 'table', function ( settings ) {
9390			_fnLog( settings, 0, msg );
9391		} );
9392	} );
9393	
9394	
9395	_api_register( 'settings()', function () {
9396		return new _Api( this.context, this.context );
9397	} );
9398	
9399	
9400	_api_register( 'init()', function () {
9401		var ctx = this.context;
9402		return ctx.length ? ctx[0].oInit : null;
9403	} );
9404	
9405	
9406	_api_register( 'data()', function () {
9407		return this.iterator( 'table', function ( settings ) {
9408			return _pluck( settings.aoData, '_aData' );
9409		} ).flatten();
9410	} );
9411	
9412	
9413	_api_register( 'trigger()', function ( name, args, bubbles ) {
9414		return this.iterator( 'table', function ( settings ) {
9415			return _fnCallbackFire( settings, null, name, args, bubbles );
9416		} ).flatten();
9417	} );
9418	
9419	
9420	_api_register( 'ready()', function ( fn ) {
9421		var ctx = this.context;
9422	
9423		// Get status of first table
9424		if (! fn) {
9425			return ctx.length
9426				? (ctx[0]._bInitComplete || false)
9427				: null;
9428		}
9429	
9430		// Function to run either once the table becomes ready or
9431		// immediately if it is already ready.
9432		return this.tables().every(function () {
9433			if (this.context[0]._bInitComplete) {
9434				fn.call(this);
9435			}
9436			else {
9437				this.on('init', function () {
9438					fn.call(this);
9439				});
9440			}
9441		} );
9442	} );
9443	
9444	
9445	_api_register( 'destroy()', function ( remove ) {
9446		remove = remove || false;
9447	
9448		return this.iterator( 'table', function ( settings ) {
9449			var classes   = settings.oClasses;
9450			var table     = settings.nTable;
9451			var tbody     = settings.nTBody;
9452			var thead     = settings.nTHead;
9453			var tfoot     = settings.nTFoot;
9454			var jqTable   = $(table);
9455			var jqTbody   = $(tbody);
9456			var jqWrapper = $(settings.nTableWrapper);
9457			var rows      = settings.aoData.map( function (r) { return r ? r.nTr : null; } );
9458			var orderClasses = classes.order;
9459	
9460			// Flag to note that the table is currently being destroyed - no action
9461			// should be taken
9462			settings.bDestroying = true;
9463	
9464			// Fire off the destroy callbacks for plug-ins etc
9465			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings], true );
9466	
9467			// If not being removed from the document, make all columns visible
9468			if ( ! remove ) {
9469				new _Api( settings ).columns().visible( true );
9470			}
9471	
9472			// Blitz all `DT` namespaced events (these are internal events, the
9473			// lowercase, `dt` events are user subscribed and they are responsible
9474			// for removing them
9475			jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9476			$(window).off('.DT-'+settings.sInstance);
9477	
9478			// When scrolling we had to break the table up - restore it
9479			if ( table != thead.parentNode ) {
9480				jqTable.children('thead').detach();
9481				jqTable.append( thead );
9482			}
9483	
9484			if ( tfoot && table != tfoot.parentNode ) {
9485				jqTable.children('tfoot').detach();
9486				jqTable.append( tfoot );
9487			}
9488	
9489			settings.colgroup.remove();
9490	
9491			settings.aaSorting = [];
9492			settings.aaSortingFixed = [];
9493			_fnSortingClasses( settings );
9494	
9495			$('th, td', thead)
9496				.removeClass(
9497					orderClasses.canAsc + ' ' +
9498					orderClasses.canDesc + ' ' +
9499					orderClasses.isAsc + ' ' +
9500					orderClasses.isDesc
9501				)
9502				.css('width', '');
9503	
9504			// Add the TR elements back into the table in their original order
9505			jqTbody.children().detach();
9506			jqTbody.append( rows );
9507	
9508			var orig = settings.nTableWrapper.parentNode;
9509			var insertBefore = settings.nTableWrapper.nextSibling;
9510	
9511			// Remove the DataTables generated nodes, events and classes
9512			var removedMethod = remove ? 'remove' : 'detach';
9513			jqTable[ removedMethod ]();
9514			jqWrapper[ removedMethod ]();
9515	
9516			// If we need to reattach the table to the document
9517			if ( ! remove && orig ) {
9518				// insertBefore acts like appendChild if !arg[1]
9519				orig.insertBefore( table, insertBefore );
9520	
9521				// Restore the width of the original table - was read from the style property,
9522				// so we can restore directly to that
9523				jqTable
9524					.css( 'width', settings.sDestroyWidth )
9525					.removeClass( classes.table );
9526			}
9527	
9528			/* Remove the settings object from the settings array */
9529			var idx = DataTable.settings.indexOf(settings);
9530			if ( idx !== -1 ) {
9531				DataTable.settings.splice( idx, 1 );
9532			}
9533		} );
9534	} );
9535	
9536	
9537	// Add the `every()` method for rows, columns and cells in a compact form
9538	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9539		_api_register( type+'s().every()', function ( fn ) {
9540			var opts = this.selector.opts;
9541			var api = this;
9542			var inst;
9543			var counter = 0;
9544	
9545			return this.iterator( 'every', function ( settings, selectedIdx, tableIdx ) {
9546				inst = api[ type ](selectedIdx, opts);
9547	
9548				if (type === 'cell') {
9549					fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
9550				}
9551				else {
9552					fn.call(inst, selectedIdx, tableIdx, counter);
9553				}
9554	
9555				counter++;
9556			} );
9557		} );
9558	} );
9559	
9560	
9561	// i18n method for extensions to be able to use the language object from the
9562	// DataTable
9563	_api_register( 'i18n()', function ( token, def, plural ) {
9564		var ctx = this.context[0];
9565		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9566	
9567		if ( resolved === undefined ) {
9568			resolved = def;
9569		}
9570	
9571		if ( $.isPlainObject( resolved ) ) {
9572			resolved = plural !== undefined && resolved[ plural ] !== undefined ?
9573				resolved[ plural ] :
9574				resolved._;
9575		}
9576	
9577		return typeof resolved === 'string'
9578			? resolved.replace( '%d', plural ) // nb: plural might be undefined,
9579			: resolved;
9580	} );
9581	
9582	/**
9583	 * Version string for plug-ins to check compatibility. Allowed format is
9584	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9585	 * only for non-release builds. See https://semver.org/ for more information.
9586	 *  @member
9587	 *  @type string
9588	 *  @default Version number
9589	 */
9590	DataTable.version = "2.0.5";
9591	
9592	/**
9593	 * Private data store, containing all of the settings objects that are
9594	 * created for the tables on a given page.
9595	 *
9596	 * Note that the `DataTable.settings` object is aliased to
9597	 * `jQuery.fn.dataTableExt` through which it may be accessed and
9598	 * manipulated, or `jQuery.fn.dataTable.settings`.
9599	 *  @member
9600	 *  @type array
9601	 *  @default []
9602	 *  @private
9603	 */
9604	DataTable.settings = [];
9605	
9606	/**
9607	 * Object models container, for the various models that DataTables has
9608	 * available to it. These models define the objects that are used to hold
9609	 * the active state and configuration of the table.
9610	 *  @namespace
9611	 */
9612	DataTable.models = {};
9613	
9614	
9615	
9616	/**
9617	 * Template object for the way in which DataTables holds information about
9618	 * search information for the global filter and individual column filters.
9619	 *  @namespace
9620	 */
9621	DataTable.models.oSearch = {
9622		/**
9623		 * Flag to indicate if the filtering should be case insensitive or not
9624		 */
9625		"caseInsensitive": true,
9626	
9627		/**
9628		 * Applied search term
9629		 */
9630		"search": "",
9631	
9632		/**
9633		 * Flag to indicate if the search term should be interpreted as a
9634		 * regular expression (true) or not (false) and therefore and special
9635		 * regex characters escaped.
9636		 */
9637		"regex": false,
9638	
9639		/**
9640		 * Flag to indicate if DataTables is to use its smart filtering or not.
9641		 */
9642		"smart": true,
9643	
9644		/**
9645		 * Flag to indicate if DataTables should only trigger a search when
9646		 * the return key is pressed.
9647		 */
9648		"return": false
9649	};
9650	
9651	
9652	
9653	
9654	/**
9655	 * Template object for the way in which DataTables holds information about
9656	 * each individual row. This is the object format used for the settings
9657	 * aoData array.
9658	 *  @namespace
9659	 */
9660	DataTable.models.oRow = {
9661		/**
9662		 * TR element for the row
9663		 */
9664		"nTr": null,
9665	
9666		/**
9667		 * Array of TD elements for each row. This is null until the row has been
9668		 * created.
9669		 */
9670		"anCells": null,
9671	
9672		/**
9673		 * Data object from the original data source for the row. This is either
9674		 * an array if using the traditional form of DataTables, or an object if
9675		 * using mData options. The exact type will depend on the passed in
9676		 * data from the data source, or will be an array if using DOM a data
9677		 * source.
9678		 */
9679		"_aData": [],
9680	
9681		/**
9682		 * Sorting data cache - this array is ostensibly the same length as the
9683		 * number of columns (although each index is generated only as it is
9684		 * needed), and holds the data that is used for sorting each column in the
9685		 * row. We do this cache generation at the start of the sort in order that
9686		 * the formatting of the sort data need be done only once for each cell
9687		 * per sort. This array should not be read from or written to by anything
9688		 * other than the master sorting methods.
9689		 */
9690		"_aSortData": null,
9691	
9692		/**
9693		 * Per cell filtering data cache. As per the sort data cache, used to
9694		 * increase the performance of the filtering in DataTables
9695		 */
9696		"_aFilterData": null,
9697	
9698		/**
9699		 * Filtering data cache. This is the same as the cell filtering cache, but
9700		 * in this case a string rather than an array. This is easily computed with
9701		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9702		 * needed on every search (memory traded for performance)
9703		 */
9704		"_sFilterRow": null,
9705	
9706		/**
9707		 * Denote if the original data source was from the DOM, or the data source
9708		 * object. This is used for invalidating data, so DataTables can
9709		 * automatically read data from the original source, unless uninstructed
9710		 * otherwise.
9711		 */
9712		"src": null,
9713	
9714		/**
9715		 * Index in the aoData array. This saves an indexOf lookup when we have the
9716		 * object, but want to know the index
9717		 */
9718		"idx": -1,
9719	
9720		/**
9721		 * Cached display value
9722		 */
9723		displayData: null
9724	};
9725	
9726	
9727	/**
9728	 * Template object for the column information object in DataTables. This object
9729	 * is held in the settings aoColumns array and contains all the information that
9730	 * DataTables needs about each individual column.
9731	 *
9732	 * Note that this object is related to {@link DataTable.defaults.column}
9733	 * but this one is the internal data store for DataTables's cache of columns.
9734	 * It should NOT be manipulated outside of DataTables. Any configuration should
9735	 * be done through the initialisation options.
9736	 *  @namespace
9737	 */
9738	DataTable.models.oColumn = {
9739		/**
9740		 * Column index.
9741		 */
9742		"idx": null,
9743	
9744		/**
9745		 * A list of the columns that sorting should occur on when this column
9746		 * is sorted. That this property is an array allows multi-column s
9746orting
9747		 * to be defined for a column (for example first name / last name columns
9748		 * would benefit from this). The values are integers pointing to the
9749		 * columns to be sorted on (typically it will be a single integer pointing
9750		 * at itself, but that doesn't need to be the case).
9751		 */
9752		"aDataSort": null,
9753	
9754		/**
9755		 * Define the sorting directions that are applied to the column, in sequence
9756		 * as the column is repeatedly sorted upon - i.e. the first value is used
9757		 * as the sorting direction when the column if first sorted (clicked on).
9758		 * Sort it again (click again) and it will move on to the next index.
9759		 * Repeat until loop.
9760		 */
9761		"asSorting": null,
9762	
9763		/**
9764		 * Flag to indicate if the column is searchable, and thus should be included
9765		 * in the filtering or not.
9766		 */
9767		"bSearchable": null,
9768	
9769		/**
9770		 * Flag to indicate if the column is sortable or not.
9771		 */
9772		"bSortable": null,
9773	
9774		/**
9775		 * Flag to indicate if the column is currently visible in the table or not
9776		 */
9777		"bVisible": null,
9778	
9779		/**
9780		 * Store for manual type assignment using the `column.type` option. This
9781		 * is held in store so we can manipulate the column's `sType` property.
9782		 */
9783		"_sManualType": null,
9784	
9785		/**
9786		 * Flag to indicate if HTML5 data attributes should be used as the data
9787		 * source for filtering or sorting. True is either are.
9788		 */
9789		"_bAttrSrc": false,
9790	
9791		/**
9792		 * Developer definable function that is called whenever a cell is created (Ajax source,
9793		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9794		 * allowing you to modify the DOM element (add background colour for example) when the
9795		 * element is available.
9796		 */
9797		"fnCreatedCell": null,
9798	
9799		/**
9800		 * Function to get data from a cell in a column. You should <b>never</b>
9801		 * access data directly through _aData internally in DataTables - always use
9802		 * the method attached to this property. It allows mData to function as
9803		 * required. This function is automatically assigned by the column
9804		 * initialisation method
9805		 */
9806		"fnGetData": null,
9807	
9808		/**
9809		 * Function to set data for a cell in the column. You should <b>never</b>
9810		 * set the data directly to _aData internally in DataTables - always use
9811		 * this method. It allows mData to function as required. This function
9812		 * is automatically assigned by the column initialisation method
9813		 */
9814		"fnSetData": null,
9815	
9816		/**
9817		 * Property to read the value for the cells in the column from the data
9818		 * source array / object. If null, then the default content is used, if a
9819		 * function is given then the return from the function is used.
9820		 */
9821		"mData": null,
9822	
9823		/**
9824		 * Partner property to mData which is used (only when defined) to get
9825		 * the data - i.e. it is basically the same as mData, but without the
9826		 * 'set' option, and also the data fed to it is the result from mData.
9827		 * This is the rendering method to match the data method of mData.
9828		 */
9829		"mRender": null,
9830	
9831		/**
9832		 * The class to apply to all TD elements in the table's TBODY for the column
9833		 */
9834		"sClass": null,
9835	
9836		/**
9837		 * When DataTables calculates the column widths to assign to each column,
9838		 * it finds the longest string in each column and then constructs a
9839		 * temporary table and reads the widths from that. The problem with this
9840		 * is that "mmm" is much wider then "iiii", but the latter is a longer
9841		 * string - thus the calculation can go wrong (doing it properly and putting
9842		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9843		 * a "work around" we provide this option. It will append its value to the
9844		 * text that is found to be the longest string for the column - i.e. padding.
9845		 */
9846		"sContentPadding": null,
9847	
9848		/**
9849		 * Allows a default value to be given for a column's data, and will be used
9850		 * whenever a null data source is encountered (this can be because mData
9851		 * is set to null, or because the data source itself is null).
9852		 */
9853		"sDefaultContent": null,
9854	
9855		/**
9856		 * Name for the column, allowing reference to the column by name as well as
9857		 * by index (needs a lookup to work by name).
9858		 */
9859		"sName": null,
9860	
9861		/**
9862		 * Custom sorting data type - defines which of the available plug-ins in
9863		 * afnSortData the custom sorting will use - if any is defined.
9864		 */
9865		"sSortDataType": 'std',
9866	
9867		/**
9868		 * Class to be applied to the header element when sorting on this column
9869		 */
9870		"sSortingClass": null,
9871	
9872		/**
9873		 * Title of the column - what is seen in the TH element (nTh).
9874		 */
9875		"sTitle": null,
9876	
9877		/**
9878		 * Column sorting and filtering type
9879		 */
9880		"sType": null,
9881	
9882		/**
9883		 * Width of the column
9884		 */
9885		"sWidth": null,
9886	
9887		/**
9888		 * Width of the column when it was first "encountered"
9889		 */
9890		"sWidthOrig": null,
9891	
9892		/** Cached string which is the longest in the column */
9893		maxLenString: null,
9894	
9895		/**
9896		 * Store for named searches
9897		 */
9898		searchFixed: null
9899	};
9900	
9901	
9902	/*
9903	 * Developer note: The properties of the object below are given in Hungarian
9904	 * notation, that was used as the interface for DataTables prior to v1.10, however
9905	 * from v1.10 onwards the primary interface is camel case. In order to avoid
9906	 * breaking backwards compatibility utterly with this change, the Hungarian
9907	 * version is still, internally the primary interface, but is is not documented
9908	 * - hence the @name tags in each doc comment. This allows a Javascript function
9909	 * to create a map from Hungarian notation to camel case (going the other direction
9910	 * would require each property to be listed, which would add around 3K to the size
9911	 * of DataTables, while this method is about a 0.5K hit).
9912	 *
9913	 * Ultimately this does pave the way for Hungarian notation to be dropped
9914	 * completely, but that is a massive amount of work and will break current
9915	 * installs (therefore is on-hold until v2).
9916	 */
9917	
9918	/**
9919	 * Initialisation options that can be given to DataTables at initialisation
9920	 * time.
9921	 *  @namespace
9922	 */
9923	DataTable.defaults = {
9924		/**
9925		 * An array of data to use for the table, passed in at initialisation which
9926		 * will be used in preference to any data which is already in the DOM. This is
9927		 * particularly useful for constructing tables purely in Javascript, for
9928		 * example with a custom Ajax call.
9929		 */
9930		"aaData": null,
9931	
9932	
9933		/**
9934		 * If ordering is enabled, then DataTables will perform a first pass sort on
9935		 * initialisation. You can define which column(s) the sort is performed
9936		 * upon, and the sorting direction, with this variable. The `sorting` array
9937		 * should contain an array for each column to be sorted initially containing
9938		 * the column's index and a direction string ('asc' or 'desc').
9939		 */
9940		"aaSorting": [[0,'asc']],
9941	
9942	
9943		/**
9944		 * This parameter is basically identical to the `sorting` parameter, but
9945		 * cannot be overridden by user interaction with the table. What this means
9946		 * is that you could have a column (visible or hidden) which the sorting
9947		 * will always be forced on first - any sorting after that (from the user)
9948		 * will then be performed as required. This can be useful for grouping rows
9949		 * together.
9950		 */
9951		"aaSortingFixed": [],
9952	
9953	
9954		/**
9955		 * DataTables can be instructed to load data to display in the table from a
9956		 * Ajax source. This option defines how that Ajax call is made and where to.
9957		 *
9958		 * The `ajax` property has three different modes of operation, depending on
9959		 * how it is defined. These are:
9960		 *
9961		 * * `string` - Set the URL from where the data should be loaded from.
9962		 * * `object` - Define properties for `jQuery.ajax`.
9963		 * * `function` - Custom data get function
9964		 *
9965		 * `string`
9966		 * --------
9967		 *
9968		 * As a string, the `ajax` property simply defines the URL from which
9969		 * DataTables will load data.
9970		 *
9971		 * `object`
9972		 * --------
9973		 *
9974		 * As an object, the parameters in the object are passed to
9975		 * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
9976		 * of the Ajax request. DataTables has a number of default parameters which
9977		 * you can override using this option. Please refer to the jQuery
9978		 * documentation for a full description of the options available, although
9979		 * the following parameters provide additional options in DataTables or
9980		 * require special consideration:
9981		 *
9982		 * * `data` - As with jQuery, `data` can be provided as an object, but it
9983		 *   can also be used as a function to manipulate the data DataTables sends
9984		 *   to the server. The function takes a single parameter, an object of
9985		 *   parameters with the values that DataTables has readied for sending. An
9986		 *   object may be returned which will be merged into the DataTables
9987		 *   defaults, or you can add the items to the object that was passed in and
9988		 *   not return anything from the function. This supersedes `fnServerParams`
9989		 *   from DataTables 1.9-.
9990		 *
9991		 * * `dataSrc` - By default DataTables will look for the property `data` (or
9992		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
9993		 *   from an Ajax source or for server-side processing - this parameter
9994		 *   allows that property to be changed. You can use Javascript dotted
9995		 *   object notation to get a data source for multiple levels of nesting, or
9996		 *   it my be used as a function. As a function it takes a single parameter,
9997		 *   the JSON returned from the server, which can be manipulated as
9998		 *   required, with the returned value being that used by DataTables as the
9999		 *   data source for the table.
10000		 *
10001		 * * `success` - Should not be overridden it is used internally in
10002		 *   DataTables. To manipulate / transform the data returned by the server
10003		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10004		 *
10005		 * `function`
10006		 * ----------
10007		 *
10008		 * As a function, making the Ajax call is left up to yourself allowing
10009		 * complete control of the Ajax request. Indeed, if desired, a method other
10010		 * than Ajax could be used to obtain the required data, such as Web storage
10011		 * or an AIR database.
10012		 *
10013		 * The function is given four parameters and no return is required. The
10014		 * parameters are:
10015		 *
10016		 * 1. _object_ - Data to send to the server
10017		 * 2. _function_ - Callback function that must be executed when the required
10018		 *    data has been obtained. That data should be passed into the callback
10019		 *    as the only parameter
10020		 * 3. _object_ - DataTables settings object for the table
10021		 */
10022		"ajax": null,
10023	
10024	
10025		/**
10026		 * This parameter allows you to readily specify the entries in the length drop
10027		 * down menu that DataTables shows when pagination is enabled. It can be
10028		 * either a 1D array of options which will be used for both the displayed
10029		 * option and the value, or a 2D array which will use the array in the first
10030		 * position as the value, and the array in the second position as the
10031		 * displayed options (useful for language strings such as 'All').
10032		 *
10033		 * Note that the `pageLength` property will be automatically set to the
10034		 * first value given in this array, unless `pageLength` is also provided.
10035		 */
10036		"aLengthMenu": [ 10, 25, 50, 100 ],
10037	
10038	
10039		/**
10040		 * The `columns` option in the initialisation parameter allows you to define
10041		 * details about the way individual columns behave. For a full list of
10042		 * column options that can be set, please see
10043		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10044		 * define your columns, you must have an entry in the array for every single
10045		 * column that you have in your table (these can be null if you don't which
10046		 * to specify any options).
10047		 */
10048		"aoColumns": null,
10049	
10050		/**
10051		 * Very similar to `columns`, `columnDefs` allows you to target a specific
10052		 * column, multiple columns, or all columns, using the `targets` property of
10053		 * each object in the array. This allows great flexibility when creating
10054		 * tables, as the `columnDefs` arrays can be of any length, targeting the
10055		 * columns you specifically want. `columnDefs` may use any of the column
10056		 * options available: {@link DataTable.defaults.column}, but it _must_
10057		 * have `targets` defined in each object in the array. Values in the `targets`
10058		 * array may be:
10059		 *   <ul>
10060		 *     <li>
10060a string - class name will be matched on the TH for the column</li>
10061		 *     <li>0 or a positive integer - column index counting from the left</li>
10062		 *     <li>a negative integer - column index counting from the right</li>
10063		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10064		 *   </ul>
10065		 */
10066		"aoColumnDefs": null,
10067	
10068	
10069		/**
10070		 * Basically the same as `search`, this parameter defines the individual column
10071		 * filtering state at initialisation time. The array must be of the same size
10072		 * as the number of columns, and each element be an object with the parameters
10073		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10074		 * accepted and the default will be used.
10075		 */
10076		"aoSearchCols": [],
10077	
10078	
10079		/**
10080		 * Enable or disable automatic column width calculation. This can be disabled
10081		 * as an optimisation (it takes some time to calculate the widths) if the
10082		 * tables widths are passed in using `columns`.
10083		 */
10084		"bAutoWidth": true,
10085	
10086	
10087		/**
10088		 * Deferred rendering can provide DataTables with a huge speed boost when you
10089		 * are using an Ajax or JS data source for the table. This option, when set to
10090		 * true, will cause DataTables to defer the creation of the table elements for
10091		 * each row until they are needed for a draw - saving a significant amount of
10092		 * time.
10093		 */
10094		"bDeferRender": true,
10095	
10096	
10097		/**
10098		 * Replace a DataTable which matches the given selector and replace it with
10099		 * one which has the properties of the new initialisation object passed. If no
10100		 * table matches the selector, then the new DataTable will be constructed as
10101		 * per normal.
10102		 */
10103		"bDestroy": false,
10104	
10105	
10106		/**
10107		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10108		 * that it allows the end user to input multiple words (space separated) and
10109		 * will match a row containing those words, even if not in the order that was
10110		 * specified (this allow matching across multiple columns). Note that if you
10111		 * wish to use filtering in DataTables this must remain 'true' - to remove the
10112		 * default filtering input box and retain filtering abilities, please use
10113		 * {@link DataTable.defaults.dom}.
10114		 */
10115		"bFilter": true,
10116	
10117		/**
10118		 * Used only for compatiblity with DT1
10119		 * @deprecated
10120		 */
10121		"bInfo": true,
10122	
10123		/**
10124		 * Used only for compatiblity with DT1
10125		 * @deprecated
10126		 */
10127		"bLengthChange": true,
10128	
10129		/**
10130		 * Enable or disable pagination.
10131		 */
10132		"bPaginate": true,
10133	
10134	
10135		/**
10136		 * Enable or disable the display of a 'processing' indicator when the table is
10137		 * being processed (e.g. a sort). This is particularly useful for tables with
10138		 * large amounts of data where it can take a noticeable amount of time to sort
10139		 * the entries.
10140		 */
10141		"bProcessing": false,
10142	
10143	
10144		/**
10145		 * Retrieve the DataTables object for the given selector. Note that if the
10146		 * table has already been initialised, this parameter will cause DataTables
10147		 * to simply return the object that has already been set up - it will not take
10148		 * account of any changes you might have made to the initialisation object
10149		 * passed to DataTables (setting this parameter to true is an acknowledgement
10150		 * that you understand this). `destroy` can be used to reinitialise a table if
10151		 * you need.
10152		 */
10153		"bRetrieve": false,
10154	
10155	
10156		/**
10157		 * When vertical (y) scrolling is enabled, DataTables will force the height of
10158		 * the table's viewport to the given height at all times (useful for layout).
10159		 * However, this can look odd when filtering data down to a small data set,
10160		 * and the footer is left "floating" further down. This parameter (when
10161		 * enabled) will cause DataTables to collapse the table's viewport down when
10162		 * the result set will fit within the given Y height.
10163		 */
10164		"bScrollCollapse": false,
10165	
10166	
10167		/**
10168		 * Configure DataTables to use server-side processing. Note that the
10169		 * `ajax` parameter must also be given in order to give DataTables a
10170		 * source to obtain the required data for each draw.
10171		 */
10172		"bServerSide": false,
10173	
10174	
10175		/**
10176		 * Enable or disable sorting of columns. Sorting of individual columns can be
10177		 * disabled by the `sortable` option for each column.
10178		 */
10179		"bSort": true,
10180	
10181	
10182		/**
10183		 * Enable or display DataTables' ability to sort multiple columns at the
10184		 * same time (activated by shift-click by the user).
10185		 */
10186		"bSortMulti": true,
10187	
10188	
10189		/**
10190		 * Allows control over whether DataTables should use the top (true) unique
10191		 * cell that is found for a single column, or the bottom (false - default).
10192		 * This is useful when using complex headers.
10193		 */
10194		"bSortCellsTop": null,
10195	
10196	
10197		/**
10198		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10199		 * `sorting\_3` to the columns which are currently being sorted on. This is
10200		 * presented as a feature switch as it can increase processing time (while
10201		 * classes are removed and added) so for large data sets you might want to
10202		 * turn this off.
10203		 */
10204		"bSortClasses": true,
10205	
10206	
10207		/**
10208		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10209		 * used to save table display information such as pagination information,
10210		 * display length, filtering and sorting. As such when the end user reloads
10211		 * the page the display display will match what thy had previously set up.
10212		 */
10213		"bStateSave": false,
10214	
10215	
10216		/**
10217		 * This function is called when a TR element is created (and all TD child
10218		 * elements have been inserted), or registered if using a DOM source, allowing
10219		 * manipulation of the TR element (adding classes etc).
10220		 */
10221		"fnCreatedRow": null,
10222	
10223	
10224		/**
10225		 * This function is called on every 'draw' event, and allows you to
10226		 * dynamically modify any aspect you want about the created DOM.
10227		 */
10228		"fnDrawCallback": null,
10229	
10230	
10231		/**
10232		 * Identical to fnHeaderCallback() but for the table footer this function
10233		 * allows you to modify the table footer on every 'draw' event.
10234		 */
10235		"fnFooterCallback": null,
10236	
10237	
10238		/**
10239		 * When rendering large numbers in the information element for the table
10240		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10241		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10242		 * rendered as "1,000,000") to help readability for the end user. This
10243		 * function will override the default method DataTables uses.
10244		 */
10245		"fnFormatNumber": function ( toFormat ) {
10246			return toFormat.toString().replace(
10247				/\B(?=(\d{3})+(?!\d))/g,
10248				this.oLanguage.sThousands
10249			);
10250		},
10251	
10252	
10253		/**
10254		 * This function is called on every 'draw' event, and allows you to
10255		 * dynamically modify the header row. This can be used to calculate and
10256		 * display useful information about the table.
10257		 */
10258		"fnHeaderCallback": null,
10259	
10260	
10261		/**
10262		 * The information element can be used to convey information about the current
10263		 * state of the table. Although the internationalisation options presented by
10264		 * DataTables are quite capable of dealing with most customisations, there may
10265		 * be times where you wish to customise the string further. This callback
10266		 * allows you to do exactly that.
10267		 */
10268		"fnInfoCallback": null,
10269	
10270	
10271		/**
10272		 * Called when the table has been initialised. Normally DataTables will
10273		 * initialise sequentially and there will be no need for this function,
10274		 * however, this does not hold true when using external language information
10275		 * since that is obtained using an async XHR call.
10276		 */
10277		"fnInitComplete": null,
10278	
10279	
10280		/**
10281		 * Called at the very start of each table draw and can be used to cancel the
10282		 * draw by returning false, any other return (including undefined) results in
10283		 * the full draw occurring).
10284		 */
10285		"fnPreDrawCallback": null,
10286	
10287	
10288		/**
10289		 * This function allows you to 'post process' each row after it have been
10290		 * generated for each table draw, but before it is rendered on screen. This
10291		 * function might be used for setting the row class name etc.
10292		 */
10293		"fnRowCallback": null,
10294	
10295	
10296		/**
10297		 * Load the table state. With this function you can define from where, and how, the
10298		 * state of a table is loaded. By default DataTables will load from `localStorage`
10299		 * but you might wish to use a server-side database or cookies.
10300		 */
10301		"fnStateLoadCallback": function ( settings ) {
10302			try {
10303				return JSON.parse(
vendor: 6,442 bytes, lines 10304-10499
10304					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10305						'DataTables_'+settings.sInstance+'_'+location.pathname
10306					)
10307				);
10308			} catch (e) {
10309				return {};
10310			}
10311		},
10312	
10313	
10314		/**
10315		 * Callback which allows modification of the saved state prior to loading that state.
10316		 * This callback is called when the table is loading state from the stored data, but
10317		 * prior to the settings object being modified by the saved state. Note that for
10318		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10319		 * a plug-in.
10320		 */
10321		"fnStateLoadParams": null,
10322	
10323	
10324		/**
10325		 * Callback that is called when the state has been loaded from the state saving method
10326		 * and the DataTables settings object has been modified as a result of the loaded state.
10327		 */
10328		"fnStateLoaded": null,
10329	
10330	
10331		/**
10332		 * Save the table state. This function allows you to define where and how the state
10333		 * information for the table is stored By default DataTables will use `localStorage`
10334		 * but you might wish to use a server-side database or cookies.
10335		 */
10336		"fnStateSaveCallback": function ( settings, data ) {
10337			try {
10338				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10339					'DataTables_'+settings.sInstance+'_'+location.pathname,
10340					JSON.stringify( data )
10341				);
10342			} catch (e) {
10343				// noop
10344			}
10345		},
10346	
10347	
10348		/**
10349		 * Callback which allows modification of the state to be saved. Called when the table
10350		 * has changed state a new state save is required. This method allows modification of
10351		 * the state saving object prior to actually doing the save, including addition or
10352		 * other state properties or modification. Note that for plug-in authors, you should
10353		 * use the `stateSaveParams` event to save parameters for a plug-in.
10354		 */
10355		"fnStateSaveParams": null,
10356	
10357	
10358		/**
10359		 * Duration for which the saved state information is considered valid. After this period
10360		 * has elapsed the state will be returned to the default.
10361		 * Value is given in seconds.
10362		 */
10363		"iStateDuration": 7200,
10364	
10365	
10366		/**
10367		 * Number of rows to display on a single page when using pagination. If
10368		 * feature enabled (`lengthChange`) then the end user will be able to override
10369		 * this to a custom setting using a pop-up menu.
10370		 */
10371		"iDisplayLength": 10,
10372	
10373	
10374		/**
10375		 * Define the starting point for data display when using DataTables with
10376		 * pagination. Note that this parameter is the number of records, rather than
10377		 * the page number, so if you have 10 records per page and want to start on
10378		 * the third page, it should be "20".
10379		 */
10380		"iDisplayStart": 0,
10381	
10382	
10383		/**
10384		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10385		 * and filtering) by adding a `tabindex` attribute to the required elements. This
10386		 * allows you to tab through the controls and press the enter key to activate them.
10387		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10388		 * You can overrule this using this parameter if you wish. Use a value of -1 to
10389		 * disable built-in keyboard navigation.
10390		 */
10391		"iTabIndex": 0,
10392	
10393	
10394		/**
10395		 * Classes that DataTables assigns to the various components and features
10396		 * that it adds to the HTML table. This allows classes to be configured
10397		 * during initialisation in addition to through the static
10398		 * {@link DataTable.ext.oStdClasses} object).
10399		 */
10400		"oClasses": {},
10401	
10402	
10403		/**
10404		 * All strings that DataTables uses in the user interface that it creates
10405		 * are defined in this object, allowing you to modified them individually or
10406		 * completely replace them all as required.
10407		 */
10408		"oLanguage": {
10409			/**
10410			 * Strings that are used for WAI-ARIA labels and controls only (these are not
10411			 * actually visible on the page, but will be read by screenreaders, and thus
10412			 * must be internationalised as well).
10413			 */
10414			"oAria": {
10415				/**
10416				 * ARIA label that is added to the table headers when the column may be sorted
10417				 */
10418				"orderable": ": Activate to sort",
10419	
10420				/**
10421				 * ARIA label that is added to the table headers when the column is currently being sorted
10422				 */
10423				"orderableReverse": ": Activate to invert sorting",
10424	
10425				/**
10426				 * ARIA label that is added to the table headers when the column is currently being 
10427				 * sorted and next step is to remove sorting
10428				 */
10429				"orderableRemove": ": Activate to remove sorting",
10430	
10431				paginate: {
10432					first: 'First',
10433					last: 'Last',
10434					next: 'Next',
10435					previous: 'Previous'
10436				}
10437			},
10438	
10439			/**
10440			 * Pagination string used by DataTables for the built-in pagination
10441			 * control types.
10442			 */
10443			"oPaginate": {
10444				/**
10445				 * Label and character for first page button («)
10446				 */
10447				"sFirst": "\u00AB",
10448	
10449				/**
10450				 * Last page button (»)
10451				 */
10452				"sLast": "\u00BB",
10453	
10454				/**
10455				 * Next page button (›)
10456				 */
10457				"sNext": "\u203A",
10458	
10459				/**
10460				 * Previous page button (‹)
10461				 */
10462				"sPrevious": "\u2039",
10463			},
10464	
10465			/**
10466			 * Plural object for the data type the table is showing
10467			 */
10468			entries: {
10469				_: "entries",
10470				1: "entry"
10471			},
10472	
10473			/**
10474			 * This string is shown in preference to `zeroRecords` when the table is
10475			 * empty of data (regardless of filtering). Note that this is an optional
10476			 * parameter - if it is not given, the value of `zeroRecords` will be used
10477			 * instead (either the default or given value).
10478			 */
10479			"sEmptyTable": "No data available.",
10480	
10481	
10482			/**
10483			 * This string gives information to the end user about the information
10484			 * that is current on display on the page. The following tokens can be
10485			 * used in the string and will be dynamically replaced as the table
10486			 * display updates. This tokens can be placed anywhere in the string, or
10487			 * removed as needed by the language requires:
10488			 *
10489			 * * `\_START\_` - Display index of the first record on the current page
10490			 * * `\_END\_` - Display index of the last record on the current page
10491			 * * `\_TOTAL\_` - Number of records in the table after filtering
10492			 * * `\_MAX\_` - Number of records in the table without filtering
10493			 * * `\_PAGE\_` - Current page number
10494			 * * `\_PAGES\_` - Total number of pages of data in the table
10495			 */
10496			"sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
10497	
10498	
10499			/**
10500			 * Display information string for when the table is empty. Typically the
10501			 * format of this string should match `info`.
10502			 */
10503			"sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
10504	
10505	
10506			/**
10507			 * When a user filters the information in a table, this string is appended
10508			 * to the information (`info`) to give an idea of how strong the filtering
10509			 * is. The variable _MAX_ is dynamically updated.
10510			 */
10511			"sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
10512	
10513	
10514			/**
10515			 * If can be useful to append extra information to the info string at times,
10516			 * and this variable does exactly that. This information will be appended to
10517			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
10518			 * being used) at all times.
10519			 */
10520			"sInfoPostFix": "",
10521	
10522	
10523			/**
10524			 * This decimal place operator is a little different from the other
10525			 * language options since DataTables doesn't output floating point
10526			 * numbers, so it won't ever use this for display of a number. Rather,
10527			 * what this parameter does is modify the sort methods of the table so
10528			 * that numbers which are in a format which has a character other than
10529			 * a period (`.`) as a decimal place will be sorted numerically.
10530			 *
10531			 * Note that numbers with different decimal places cannot be shown in
10532			 * the same table and still be sortable, the table must be consistent.
10533			 * However, multiple different tables on the page can use different
10534			 * decimal place characters.
10535			 */
10536			"sDecimal": "",
10537	
10538	
10539			/**
10540			 * DataTables has a build in number formatter (`formatNumber`) which is
10541			 * used to format large numbers that are used in the table information.
10542			 * By default a comma is used, but this can be trivially changed to any
10543			 * character you wish with this parameter.
10544			 */
10545			"sThousands": ",",
10546	
10547	
10548			/**
10549			 * Detail the action that will be taken when the drop down menu for the
10550			 * pagination length option is changed. The '_MENU_' variable is replaced
10551			 * with a default select list of 10, 25, 50 and 100, and can be replaced
10552			 * with a custom select box if required.
10553			 */
10554			"sLengthMenu": "_MENU_ _ENTRIES_ per page",
10555	
10556	
10557			/**
10558			 * When using Ajax sourced data and during the first draw when DataTables is
10559			 * gathering the data, this message is shown in an empty row in the table to
10560			 * indicate to the end user the the data is being loaded. Note that this
10561			 * parameter is not used when loading data by server-side processing, just
10562			 * Ajax sourced data with client-side processing.
10563			 */
10564			"sLoadingRecords": "Loading...",
10565	
10566	
10567			/**
10568			 * Text which is displayed when the table is processing a user action
10569			 * (usually a sort command or similar).
10570			 */
10571			"sProcessing": "",
10572	
10573	
10574			/**
10575			 * Details the actions that will be taken when the user types into the
10576			 * filtering input text box. The variable "_INPUT_", if used in the string,
10577			 * is replaced with the HTML text box for the filtering input allowing
10578			 * control over where it appears in the string. If "_INPUT_" is not given
10579			 * then the input box is appended to the string automatically.
10580			 */
10581			"sSearch": "Search:",
10582	
10583	
10584			/**
10585			 * Assign a `placeholder` attribute to the search `input` element
10586			 *  @type string
10587			 *  @default 
10588			 *
10589			 *  @dtopt Language
10590			 *  @name DataTable.defaults.language.searchPlaceholder
10591			 */
10592			"sSearchPlaceholder": "",
10593	
10594	
10595			/**
10596			 * All of the language information can be stored in a file on the
10597			 * server-side, which DataTables will look up if this parameter is passed.
10598			 * It must store the URL of the language file, which is in a JSON format,
10599			 * and the object has the same properties as the oLanguage object in the
10600			 * initialiser object (i.e. the above parameters). Please refer to one of
10601			 * the example language files to see how this works in action.
10602			 */
10603			"sUrl": "",
10604	
10605	
10606			/**
10607			 * Text shown inside the table records when the is no information to be
10608			 * displayed after filtering. `emptyTable` is shown when there is simply no
10609			 * information in the table at all (regardless of filtering).
10610			 */
10611			"sZeroRecords": "No matching records found"
10612		},
10613	
10614	
10615		/**
10616		 * This parameter allows you to have define the global filtering state at
10617		 * initialisation time. As an object the `search` parameter must be
10618		 * defined, but all other parameters are optional. When `regex` is true,
10619		 * the search string will be treated as a regular expression, when false
10620		 * (default) it will be treated as a straight string. When `smart`
10621		 * DataTables will use it's smart filtering methods (to word match at
10622		 * any point in the data), when false this will not be done.
10623		 */
10624		"oSearch": $.extend( {}, DataTable.models.oSearch ),
10625	
10626	
10627		/**
10628		 * Table and control layout. This replaces the legacy `dom` option.
10629		 */
10630		layout: {
10631			topStart: 'pageLength',
10632			topEnd: 'search',
10633			bottomStart: 'info',
10634			bottomEnd: 'paging'
10635		},
10636	
10637	
10638		/**
10639		 * Legacy DOM layout option
10640		 */
10641		"sDom": null,
10642	
10643	
10644		/**
10645		 * Search delay option. This will throttle full table searches that use the
10646		 * DataTables provided search input element (it does not effect calls to
10647		 * `dt-api search()`, providing a delay before the search is made.
10648		 */
10649		"searchDelay": null,
10650	
10651	
10652		/**
10653		 * DataTables features six different built-in options for the buttons to
10654		 * display for pagination control:
10655		 *
10656		 * * `numbers` - Page number buttons only
10657		 * * `simple` - 'Previous' and 'Next' buttons only
10658		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
10659		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
10660		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
10661		 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
10662		 */
10663		"sPaginationType": "full_numbers",
10664	
10665	
10666		/**
10667		 * Enable horizontal scrolling. When a table is too wide to fit into a
10668		 * certain layout, or you have a large number of columns in the table, you
10669		 * can enable x-scrolling to show the table in a viewport, which can be
10670		 * scrolled. This property can be `true` which will allow the table to
10671		 * scroll horizontally when needed, or any CSS unit, or a number (in which
10672		 * case it will be treated as a pixel measurement). Setting as simply `true`
10673		 * is recommended.
10674		 */
10675		"sScrollX": "",
10676	
10677	
10678		/**
10679		 * This property can be used to force a DataTable to use more width than it
10680		 * might otherwise do when x-scrolling is enabled. For example if you have a
10681		 * table which requires to be well spaced, this parameter is useful for
10682		 * "over-sizing" the table, and thus forcing scrolling. This property can by
10683		 * any CSS unit, or a number (in which case it will be treated as a pixel
10684		 * measurement).
10685		 */
10686		"sScrollXInner": "",
10687	
10688	
10689		/**
10690		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
10691		 * to the given height, and enable scrolling for any data which overflows the
10692		 * current viewport. This can be used as an alternative to paging to display
10693		 * a lot of data in a small area (although paging and scrolling can both be
10694		 * enabled at the same time). This property can be any CSS unit, or a number
10695		 * (in which case it will be treated as a pixel measurement).
10696		 */
10697		"sScrollY": "",
10698	
10699	
10700		/**
10701		 * __Deprecated__ The functionality provided by this parameter has now been
10702		 * superseded by that provided through `ajax`, which should be used instead.
10703		 *
10704		 * Set the HTTP method that is used to make the Ajax call for server-side
10705		 * processing or Ajax sourced data.
10706		 */
10707		"sServerMethod": "GET",
10708	
10709	
10710		/**
10711		 * DataTables makes use of renderers when displaying HTML elements for
10712		 * a table. These renderers can be added or modified by plug-ins to
10713		 * generate suitable mark-up for a site. For example the Bootstrap
10714		 * integration plug-in for DataTables uses a paging button renderer to
10715		 * display pagination buttons in the mark-up required by Bootstrap.
10716		 *
10717		 * For further information about the renderers available see
10718		 * DataTable.ext.renderer
10719		 */
10720		"renderer": null,
10721	
10722	
10723		/**
10724		 * Set the data property name that DataTables should use to get a row's id
10725		 * to set as the `id` property in the node.
10726		 */
10727		"rowId": "DT_RowId",
10728	
10729	
10730		/**
10731		 * Caption value
10732		 */
10733		"caption": null
10734	};
10735	
10736	_fnHungarianMap( DataTable.defaults );
10737	
10738	
10739	
10740	/*
10741	 * Developer note - See note in model.defaults.js about the use of Hungarian
10742	 * notation and camel case.
10743	 */
10744	
10745	/**
10746	 * Column options that can be given to DataTables at initialisation time.
10747	 *  @namespace
10748	 */
10749	DataTable.defaults.column = {
10750		/**
10751		 * Define which column(s) an order will occur on for this column. This
10752		 * allows a column's ordering to take multiple columns into account when
10753		 * doing a sort or use the data from a different column. For example first
10754		 * name / last name columns make sense to do a multi-column sort over the
10755		 * two columns.
10756		 */
10757		"aDataSort": null,
10758		"iDataSort": -1,
10759	
10760		ariaTitle: '',
10761	
10762	
10763		/**
10764		 * You can control the default ordering direction, and even alter the
10765		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
10766		 * using this parameter.
10767		 */
10768		"asSorting": [ 'asc', 'desc', '' ],
10769	
10770	
10771		/**
10772		 * Enable or disable filtering on the data in this column.
10773		 */
10774		"bSearchable": true,
10775	
10776	
10777		/**
10778		 * Enable or disable ordering on this column.
10779		 */
10780		"bSortable": true,
10781	
10782	
10783		/**
10784		 * Enable or disable the display of this column.
10785		 */
10786		"bVisible": true,
10787	
10788	
10789		/**
10790		 * Developer definable function that is called whenever a cell is created (Ajax source,
10791		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
10792		 * allowing you to modify the DOM element (add background colour for example) when the
10793		 * element is available.
10794		 */
10795		"fnCreatedCell": null,
10796	
10797	
10798		/**
10799		 * This property can be used to read data from any data source property,
10800		 * including deeply nested objects / properties. `data` can be given in a
10801		 * number of different ways which effect its behaviour:
10802		 *
10803		 * * `integer` - treated as an array index for the data source. This is the
10804		 *   default that DataTables uses (incrementally increased for each column).
10805		 * * `string` - read an object property from the data source. There are
10806		 *   three 'special' options that can be used in the string to alter how
10807		 *   DataTables reads the data from the source object:
10808		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
10809		 *      Javascript to read from nested objects, so to can the options
10810		 *      specified in `data`. For example: `browser.version` or
10811		 *      `browser.name`. If your object parameter name contains a period, use
10812		 *      `\\` to escape it - i.e. `first\\.name`.
10813		 *    * `[]` - Array notation. DataTables can automatically combine data
10814		 *      from and array source, joining the data with the characters provided
10815		 *      between the two brackets. For example: `name[, ]` would provide a
10816		 *      comma-space separated list from the source array. If no characters
10817		 *      are provided between the brackets, the original array source is
10818		 *      returned.
10819		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
10820		 *      execute a function of the name given. For example: `browser()` for a
10821		 *      simple function on the data source, `browser.version()` for a
10822		 *      function in a nested property or even `browser().version` to get an
10823		 *      object property if the function called returns an object. Note that
10824		 *      function notation is recommended for use in `render` rather than
10825		 *      `data` as it is much simpler to use as a renderer.
10826		 * * `null` - use the original data source for the row rather than plucking
10827		 *   data directly from it. This action has effects on two other
10828		 *   initialisation options:
10829		 *    * `defaultContent` - When null is given as the `data` option and
10830		 *      `defaultContent` is specified for the column, the value defined by
10831		 *      `defaultContent` will be used for the cell.
10832		 *    * `render` - When null is used for the `data` option and the `render`
10833		 *      option is specified for the column, the whole data source for the
10834		 *      row is used for the renderer.
10835		 * * `function` - the function given will be executed whenever DataTables
10836		 *   needs to set or get the data for a cell in the column. The function
10837		 *   takes three parameters:
10838		 *    * Parameters:
10839		 *      * `{array|object}` The data source for the row
10840		 *      * `{string}` The type call data requested - this will be 'set' when
10841		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
10842		 *        when gathering data. Note that when `undefined` is given for the
10843		 *        type DataTables expects to get the raw data for the object back<
10844		 *      * `{*}` Data to set when the second parameter is 'set'.
10845		 *    * Return:
10846		 *      * The return value from the function is not required when '
10846set' is
10847		 *        the type of call, but otherwise the return is what will be used
10848		 *        for the data requested.
10849		 *
10850		 * Note that `data` is a getter and setter option. If you just require
10851		 * formatting of data for output, you will likely want to use `render` which
10852		 * is simply a getter and thus simpler to use.
10853		 *
10854		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
10855		 * name change reflects the flexibility of this property and is consistent
10856		 * with the naming of mRender. If 'mDataProp' is given, then it will still
10857		 * be used by DataTables, as it automatically maps the old name to the new
10858		 * if required.
10859		 */
10860		"mData": null,
10861	
10862	
10863		/**
10864		 * This property is the rendering partner to `data` and it is suggested that
10865		 * when you want to manipulate data for display (including filtering,
10866		 * sorting etc) without altering the underlying data for the table, use this
10867		 * property. `render` can be considered to be the the read only companion to
10868		 * `data` which is read / write (then as such more complex). Like `data`
10869		 * this option can be given in a number of different ways to effect its
10870		 * behaviour:
10871		 *
10872		 * * `integer` - treated as an array index for the data source. This is the
10873		 *   default that DataTables uses (incrementally increased for each column).
10874		 * * `string` - read an object property from the data source. There are
10875		 *   three 'special' options that can be used in the string to alter how
10876		 *   DataTables reads the data from the source object:
10877		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
10878		 *      Javascript to read from nested objects, so to can the options
10879		 *      specified in `data`. For example: `browser.version` or
10880		 *      `browser.name`. If your object parameter name contains a period, use
10881		 *      `\\` to escape it - i.e. `first\\.name`.
10882		 *    * `[]` - Array notation. DataTables can automatically combine data
10883		 *      from and array source, joining the data with the characters provided
10884		 *      between the two brackets. For example: `name[, ]` would provide a
10885		 *      comma-space separated list from the source array. If no characters
10886		 *      are provided between the brackets, the original array source is
10887		 *      returned.
10888		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
10889		 *      execute a function of the name given. For example: `browser()` for a
10890		 *      simple function on the data source, `browser.version()` for a
10891		 *      function in a nested property or even `browser().version` to get an
10892		 *      object property if the function called returns an object.
10893		 * * `object` - use different data for the different data types requested by
10894		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
10895		 *   of the object is the data type the property refers to and the value can
10896		 *   defined using an integer, string or function using the same rules as
10897		 *   `render` normally does. Note that an `_` option _must_ be specified.
10898		 *   This is the default value to use if you haven't specified a value for
10899		 *   the data type requested by DataTables.
10900		 * * `function` - the function given will be executed whenever DataTables
10901		 *   needs to set or get the data for a cell in the column. The function
10902		 *   takes three parameters:
10903		 *    * Parameters:
10904		 *      * {array|object} The data source for the row (based on `data`)
10905		 *      * {string} The type call data requested - this will be 'filter',
10906		 *        'display', 'type' or 'sort'.
10907		 *      * {array|object} The full data source for the row (not based on
10908		 *        `data`)
10909		 *    * Return:
10910		 *      * The return value from the function is what will be used for the
10911		 *        data requested.
10912		 */
10913		"mRender": null,
10914	
10915	
10916		/**
10917		 * Change the cell type created for the column - either TD cells or TH cells. This
10918		 * can be useful as TH cells have semantic meaning in the table body, allowing them
10919		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
10920		 */
10921		"sCellType": "td",
10922	
10923	
10924		/**
10925		 * Class to give to each cell in this column.
10926		 */
10927		"sClass": "",
10928	
10929		/**
10930		 * When DataTables calculates the column widths to assign to each column,
10931		 * it finds the longest string in each column and then constructs a
10932		 * temporary table and reads the widths from that. The problem with this
10933		 * is that "mmm" is much wider then "iiii", but the latter is a longer
10934		 * string - thus the calculation can go wrong (doing it properly and putting
10935		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
10936		 * a "work around" we provide this option. It will append its value to the
10937		 * text that is found to be the longest string for the column - i.e. padding.
10938		 * Generally you shouldn't need this!
10939		 */
10940		"sContentPadding": "",
10941	
10942	
10943		/**
10944		 * Allows a default value to be given for a column's data, and will be used
10945		 * whenever a null data source is encountered (this can be because `data`
10946		 * is set to null, or because the data source itself is null).
10947		 */
10948		"sDefaultContent": null,
10949	
10950	
10951		/**
10952		 * This parameter is only used in DataTables' server-side processing. It can
10953		 * be exceptionally useful to know what columns are being displayed on the
10954		 * client side, and to map these to database fields. When defined, the names
10955		 * also allow DataTables to reorder information from the server if it comes
10956		 * back in an unexpected order (i.e. if you switch your columns around on the
10957		 * client-side, your server-side code does not also need updating).
10958		 */
10959		"sName": "",
10960	
10961	
10962		/**
10963		 * Defines a data source type for the ordering which can be used to read
10964		 * real-time information from the table (updating the internally cached
10965		 * version) prior to ordering. This allows ordering to occur on user
10966		 * editable elements such as form inputs.
10967		 */
10968		"sSortDataType": "std",
10969	
10970	
10971		/**
10972		 * The title of this column.
10973		 */
10974		"sTitle": null,
10975	
10976	
10977		/**
10978		 * The type allows you to specify how the data for this column will be
10979		 * ordered. Four types (string, numeric, date and html (which will strip
10980		 * HTML tags before ordering)) are currently available. Note that only date
10981		 * formats understood by Javascript's Date() object will be accepted as type
10982		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
10983		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
10984		 * through plug-ins.
10985		 */
10986		"sType": null,
10987	
10988	
10989		/**
10990		 * Defining the width of the column, this parameter may take any CSS value
10991		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
10992		 * been given a specific width through this interface ensuring that the table
10993		 * remains readable.
10994		 */
10995		"sWidth": null
10996	};
10997	
10998	_fnHungarianMap( DataTable.defaults.column );
10999	
11000	
11001	
11002	/**
11003	 * DataTables settings object - this holds all the information needed for a
11004	 * given table, including configuration, data and current application of the
11005	 * table options. DataTables does not have a single instance for each DataTable
11006	 * with the settings attached to that instance, but rather instances of the
11007	 * DataTable "class" are created on-the-fly as needed (typically by a
11008	 * $().dataTable() call) and the settings object is then applied to that
11009	 * instance.
11010	 *
11011	 * Note that this object is related to {@link DataTable.defaults} but this
11012	 * one is the internal data store for DataTables's cache of columns. It should
11013	 * NOT be manipulated outside of DataTables. Any configuration should be done
11014	 * through the initialisation options.
11015	 */
11016	DataTable.models.oSettings = {
11017		/**
11018		 * Primary features of DataTables and their enablement state.
11019		 */
11020		"oFeatures": {
11021	
11022			/**
11023			 * Flag to say if DataTables should automatically try to calculate the
11024			 * optimum table and columns widths (true) or not (false).
11025			 * Note that this parameter will be set by the initialisation routine. To
11026			 * set a default use {@link DataTable.defaults}.
11027			 */
11028			"bAutoWidth": null,
11029	
11030			/**
11031			 * Delay the creation of TR and TD elements until they are actually
11032			 * needed by a driven page draw. This can give a significant speed
11033			 * increase for Ajax source and Javascript source data, but makes no
11034			 * difference at all for DOM and server-side processing tables.
11035			 * Note that this parameter will be set by the initialisation routine. To
11036			 * set a default use {@link DataTable.defaults}.
11037			 */
11038			"bDeferRender": null,
11039	
11040			/**
11041			 * Enable filtering on the table or not. Note that if this is disabled
11042			 * then there is no filtering at all on the table, including fnFilter.
11043			 * To just remove the filtering input use sDom and remove the 'f' option.
11044			 * Note that this parameter will be set by the initialisation routine. To
11045			 * set a default use {@link DataTable.defaults}.
11046			 */
11047			"bFilter": null,
11048	
11049			/**
11050			 * Used only for compatiblity with DT1
11051			 * @deprecated
11052			 */
11053			"bInfo": true,
11054	
11055			/**
11056			 * Used only for compatiblity with DT1
11057			 * @deprecated
11058			 */
11059			"bLengthChange": true,
11060	
11061			/**
11062			 * Pagination enabled or not. Note that if this is disabled then length
11063			 * changing must also be disabled.
11064			 * Note that this parameter will be set by the initialisation routine. To
11065			 * set a default use {@link DataTable.defaults}.
11066			 */
11067			"bPaginate": null,
11068	
11069			/**
11070			 * Processing indicator enable flag whenever DataTables is enacting a
11071			 * user request - typically an Ajax request for server-side processing.
11072			 * Note that this parameter will be set by the initialisation routine. To
11073			 * set a default use {@link DataTable.defaults}.
11074			 */
11075			"bProcessing": null,
11076	
11077			/**
11078			 * Server-side processing enabled flag - when enabled DataTables will
11079			 * get all data from the server for every draw - there is no filtering,
11080			 * sorting or paging done on the client-side.
11081			 * Note that this parameter will be set by the initialisation routine. To
11082			 * set a default use {@link DataTable.defaults}.
11083			 */
11084			"bServerSide": null,
11085	
11086			/**
11087			 * Sorting enablement flag.
11088			 * Note that this parameter will be set by the initialisation routine. To
11089			 * set a default use {@link DataTable.defaults}.
11090			 */
11091			"bSort": null,
11092	
11093			/**
11094			 * Multi-column sorting
11095			 * Note that this parameter will be set by the initialisation routine. To
11096			 * set a default use {@link DataTable.defaults}.
11097			 */
11098			"bSortMulti": null,
11099	
11100			/**
11101			 * Apply a class to the columns which are being sorted to provide a
11102			 * visual highlight or not. This can slow things down when enabled since
11103			 * there is a lot of DOM interaction.
11104			 * Note that this parameter will be set by the initialisation routine. To
11105			 * set a default use {@link DataTable.defaults}.
11106			 */
11107			"bSortClasses": null,
11108	
11109			/**
11110			 * State saving enablement flag.
11111			 * Note that this parameter will be set by the initialisation routine. To
11112			 * set a default use {@link DataTable.defaults}.
11113			 */
11114			"bStateSave": null
11115		},
11116	
11117	
11118		/**
11119		 * Scrolling settings for a table.
11120		 */
11121		"oScroll": {
11122			/**
11123			 * When the table is shorter in height than sScrollY, collapse the
11124			 * table container down to the height of the table (when true).
11125			 * Note that this parameter will be set by the initialisation routine. To
11126			 * set a default use {@link DataTable.defaults}.
11127			 */
11128			"bCollapse": null,
11129	
11130			/**
11131			 * Width of the scrollbar for the web-browser's platform. Calculated
11132			 * during table initialisation.
11133			 */
11134			"iBarWidth": 0,
11135	
11136			/**
11137			 * Viewport width for horizontal scrolling. Horizontal scrolling is
11138			 * disabled if an empty string.
11139			 * Note that this parameter will be set by the initialisation routine. To
11140			 * set a default use {@link DataTable.defaults}.
11141			 */
11142			"sX": null,
11143	
11144			/**
11145			 * Width to expand the table to when using x-scrolling. Typically you
11146			 * should not need to use this.
11147			 * Note that this parameter will be set by the initialisation routine. To
11148			 * set a default use {@link DataTable.defaults}.
11149			 *  @deprecated
11150			 */
11151			"sXInner": null,
11152	
11153			/**
11154			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
11155			 * if an empty string.
11156			 * Note that this parameter will be set by the initialisation routine. To
11157			 * set a default use {@link DataTable.defaults}.
11158			 */
11159			"sY": null
11160		},
11161	
11162		/**
11163		 * Language information for the table.
11164		 */
11165		"oLanguage": {
11166			/**
11167			 * Information callback function. See
11168			 * {@link DataTable.defaults.fnInfoCallback}
11169			 */
11170			"fnInfoCallback": null
11171		},
11172	
11173		/**
11174		 * Browser support parameters
11175		 */
11176		"oBrowser": {
11177			/**
11178			 * Determine if the vertical scrollbar is on the right or left of the
11179			 * scrolling container - needed for rtl language layout, although not
11180			 * all browsers move the scrollbar (Safari).
11181			 */
11182			"bScrollbarLeft": false,
11183	
11184			/**
11185			 * Browser scrollbar width
11186			 */
11187			"barWidth": 0
11188		},
11189	
11190	
11191		"ajax": null,
11192	
11193	
11194		/**
11195		 * Array referencing the nodes which are used for the features. The
11196		 * parameters of this object match what is allowed by sDom - i.e.
11197		 *   <ul>
11198		 *     <li>'l' - Length changing</li>
11199		 *     <li>'f' - Filtering input</li>
11200		 *     <li>'t' - The table!</li>
11201		 *     <li>'i' - Information</li>
11202		 *     <li>'p' - Pagination</li>
11203		 *     <li>'r' - pRocessing</li>
11204		 *   </ul>
11205		 */
11206		"aanFeatures": [],
11207	
11208		/**
11209		 * Store data information - see {@link DataTable.models.oRow} for detailed
11210		 * information.
11211		 */
11212		"aoData": [],
11213	
11214		/**
11215		 * Array of indexes which are in the current display (after filtering etc)
11216		 */
11217		"aiDisplay": [],
11218	
11219		/**
11220		 * Array of indexes for display - no filtering
11221		 */
11222		"aiDisplayMaster": [],
11223	
11224		/**
11225		 * Map of row ids to data indexes
11226		 */
11227		"aIds": {},
11228	
11229		/**
11230		 * Store information about each column that is in use
11231		 */
11232		"aoColumns": [],
11233	
11234		/**
11235		 * Store information about the table's header
11236		 */
11237		"aoHeader": [],
11238	
11239		/**
11240		 * Store information about the table's footer
11241		 */
11242		"aoFooter": [],
11243	
11244		/**
11245		 * Store the applied global search information in case we want to force a
11246		 * research or compare the old search to a new one.
11247		 * Note that this parameter will be set by the initialisation routine. To
11248		 * set a default use {@link DataTable.defaults}.
11249		 */
11250		"oPreviousSearch": {},
11251	
11252		/**
11253		 * Store for named searches
11254		 */
11255		searchFixed: {},
11256	
11257		/**
11258		 * Store the applied search for each column - see
11259		 * {@link DataTable.models.oSearch} for the format that is used for the
11260		 * filtering information for each column.
11261		 */
11262		"aoPreSearchCols": [],
11263	
11264		/**
11265		 * Sorting that is applied to the table. Note that the inner arrays are
11266		 * used in the following manner:
11267		 * <ul>
11268		 *   <li>Index 0 - column number</li>
11269		 *   <li>Index 1 - current sorting direction</li>
11270		 * </ul>
11271		 * Note that this parameter will be set by the initialisation routine. To
11272		 * set a default use {@link DataTable.defaults}.
11273		 */
11274		"aaSorting": null,
11275	
11276		/**
11277		 * Sorting that is always applied to the table (i.e. prefixed in front of
11278		 * aaSorting).
11279		 * Note that this parameter will be set by the initialisation routine. To
11280		 * set a default use {@link DataTable.defaults}.
11281		 */
11282		"aaSortingFixed": [],
11283	
11284		/**
11285		 * If restoring a table - we should restore its width
11286		 */
11287		"sDestroyWidth": 0,
11288	
11289		/**
11290		 * Callback functions array for every time a row is inserted (i.e. on a draw).
11291		 */
11292		"aoRowCallback": [],
11293	
11294		/**
11295		 * Callback functions for the header on each draw.
11296		 */
11297		"aoHeaderCallback": [],
11298	
11299		/**
11300		 * Callback function for the footer on each draw.
11301		 */
11302		"aoFooterCallback": [],
11303	
11304		/**
11305		 * Array of callback functions for draw callback functions
11306		 */
11307		"aoDrawCallback": [],
11308	
11309		/**
11310		 * Array of callback functions for row created function
11311		 */
11312		"aoRowCreatedCallback": [],
11313	
11314		/**
11315		 * Callback functions for just before the table is redrawn. A return of
11316		 * false will be used to cancel the draw.
11317		 */
11318		"aoPreDrawCallback": [],
11319	
11320		/**
11321		 * Callback functions for when the table has been initialised.
11322		 */
11323		"aoInitComplete": [],
11324	
11325	
11326		/**
11327		 * Callbacks for modifying the settings to be stored for state saving, prior to
11328		 * saving state.
11329		 */
11330		"aoStateSaveParams": [],
11331	
11332		/**
11333		 * Callbacks for modifying the settings that have been stored for state saving
11334		 * prior to using the stored values to restore the state.
11335		 */
11336		"aoStateLoadParams": [],
11337	
11338		/**
11339		 * Callbacks for operating on the settings object once the saved state has been
11340		 * loaded
11341		 */
11342		"aoStateLoaded": [],
11343	
11344		/**
11345		 * Cache the table ID for quick access
11346		 */
11347		"sTableId": "",
11348	
11349		/**
11350		 * The TABLE node for the main table
11351		 */
11352		"nTable": null,
11353	
11354		/**
11355		 * Permanent ref to the thead element
11356		 */
11357		"nTHead": null,
11358	
11359		/**
11360		 * Permanent ref to the tfoot element - if it exists
11361		 */
11362		"nTFoot": null,
11363	
11364		/**
11365		 * Permanent ref to the tbody element
11366		 */
11367		"nTBody": null,
11368	
11369		/**
11370		 * Cache the wrapper node (contains all DataTables controlled elements)
11371		 */
11372		"nTableWrapper": null,
11373	
11374		/**
11375		 * Indicate if all required information has been read in
11376		 */
11377		"bInitialised": false,
11378	
11379		/**
11380		 * Information about open rows. Each object in the array has the parameters
11381		 * 'nTr' and 'nParent'
11382		 */
11383		"aoOpenRows": [],
11384	
11385		/**
11386		 * Dictate the positioning of DataTables' control elements - see
11387		 * {@link DataTable.model.oInit.sDom}.
11388		 * Note that this parameter will be set by the initialisation routine. To
11389		 * set a default use {@link DataTable.defaults}.
11390		 */
11391		"sDom": null,
11392	
11393		/**
11394		 * Search delay (in mS)
11395		 */
11396		"searchDelay": null,
11397	
11398		/**
11399		 * Which type of pagination should be used.
11400		 * Note that this parameter will be set by the initialisation routine. To
11401		 * set a default use {@link DataTable.defaults}.
11402		 */
11403		"sPaginationType": "two_button",
11404	
11405		/**
11406		 * Number of paging controls on the page. Only used for backwards compatibility
11407		 */
11408		pagingControls: 0,
11409	
11410		/**
11411		 * The state duration (for `stateSave`) in seconds.
11412		 * Note that this parameter will be set by the initialisation routine. To
11413		 * set a default use {@link DataTable.defaults}.
11414		 */
11415		"iStateDuration": 0,
11416	
11417		/**
11418		 * Array of callback functions for state saving. Each array element is an
11419		 * object with the following parameters:
11420		 *   <ul>
11421		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11422		 *       and the JSON string to save that has been thus far created. Returns
11423		 *       a JSON string to be inserted into a json object
11424		 *       (i.e. '"param": [ 0, 1, 2]')</li>
11425		 *     <li>string:sName - name of callback</li>
11426		 *   </ul>
11427		 */
11428		"aoStateSave": [],
11429	
11430		/**
11431		 * Array of callback functions for state loading. Each array element is an
11432		 * object with the following parameters:
11433		 *   <ul>
11434		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11435		 *       and the object stored. May return false to cancel state loading</li>
11436		 *     <li>string:sName - name of callback</li>
11437		 *   </ul>
11438		 */
11439		"aoStateLoad": [],
11440	
11441		/**
11442		 * State that was saved. Useful for back reference
11443		 */
11444		"oSavedState": null,
11445	
11446		/**
11447		 * State that was loaded. Useful for back reference
11448		 */
11449		"oLoadedState": null,
11450	
11451		/**
11452		 * Note if draw should be blocked while getting data
11453		 */
11454		"bAjaxDataGet": true,
11455	
11456		/**
11457		 * The last jQuery XHR object that was used for server-side data gathering.
11458		 * This can be used for working with the XHR information in one of the
11459		 * callbacks
11460		 */
11461		"jqXHR": null,
11462	
11463		/**
11464		 * JSON returned from the server in the last Ajax request
11465		 */
11466		"json": undefined,
11467	
11468		/**
11469		 * Data submitted as part of the last Ajax request
11470		 */
11471		"oAjaxData": undefined,
11472	
11473		/**
11474		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
11475		 * required).
11476		 * Note that this parameter will be set by the initialisation routine. To
11477		 * set a default use {@link DataTable.defaults}.
11478		 */
11479		"sServerMethod": null,
11480	
11481		/**
11482		 * Format numbers for display.
11483		 * Note that this parameter will be set by the initialisation routine. To
11484		 * set a default use {@link DataTable.defaults}.
11485		 */
11486		"fnFormatNumber": null,
11487	
11488		/**
11489		 * List of options that can be used for the user selectable length menu.
11490		 * Note that this parameter will be set by the initialisation routine. To
11491		 * set a default use {@link DataTable.defaults}.
11492		 */
11493		"aLengthMenu": null,
11494	
11495		/**
11496		 * Counter for the draws that the table does. Also used as a tracker for
11497		 * server-side processing
11498		 */
11499		"iDraw": 0,
11500	
11501		/**
11502		 * Indicate if a redraw is being done - useful for Ajax
11503		 */
11504		"bDrawing": false,
11505	
11506		/**
11507		 * Draw index (iDraw) of the last error when parsing the returned data
11508		 */
11509		"iDrawError": -1,
11510	
11511		/**
11512		 * Paging display length
11513		 */
11514		"_iDisplayLength": 10,
11515	
11516		/**
11517		 * Paging start point - aiDisplay index
11518		 */
11519		"_iDisplayStart": 0,
11520	
11521		/**
11522		 * Server-side processing - number of records in the result set
11523		 * (i.e. before filtering), Use fnRecordsTotal rather than
11524		 * this property to get the value of the number of records, regardless of
11525		 * the server-side processing setting.
11526		 */
11527		"_iRecordsTotal": 0,
11528	
11529		/**
11530		 * Server-side processing - number of records in the current display set
11531		 * (i.e. after filtering). Use fnRecordsDisplay rather than
11532		 * this property to get the value of the number of records, regardless of
11533		 * the server-side processing setting.
11534		 */
11535		"_iRecordsDisplay": 0,
11536	
11537		/**
11538		 * The classes to use for the table
11539		 */
11540		"oClasses": {},
11541	
11542		/**
11543		 * Flag attached to the settings object so you can check in the draw
11544		 * callback if filtering has been done in the draw. Deprecated in favour of
11545		 * events.
11546		 *  @deprecated
11547		 */
11548		"bFiltered": false,
11549	
11550		/**
11551		 * Flag attached to the settings object so you can check in the draw
11552		 * callback if sorting has been done in the draw. Deprecated in favour of
11553		 * events.
11554		 *  @deprecated
11555		 */
11556		"bSorted": false,
11557	
11558		/**
11559		 * Indicate that if multiple rows are in the header and there is more than
11560		 * one unique cell per column, if the top one (true) or bottom one (false)
11561		 * should be used for sorting / title by DataTables.
11562		 * Note that this parameter will be set by the initialisation routine. To
11563		 * set a default use {@link DataTable.defaults}.
11564		 */
11565		"bSortCellsTop": null,
11566	
11567		/**
11568		 * Initialisation object that is used for the table
11569		 */
11570		"oInit": null,
11571	
11572		/**
11573		 * Destroy callback functions - for plug-ins to attach themselves to the
11574		 * destroy so they can clean up markup and events.
11575		 */
11576		"aoDestroyCallback": [],
11577	
11578	
11579		/**
11580		 * Get the number of records in the current record set, before filtering
11581		 */
11582		"fnRecordsTotal": function ()
11583		{
11584			return _fnDataSource( this ) == 'ssp' ?
11585				this._iRecordsTotal * 1 :
11586				this.aiDisplayMaster.length;
11587		},
11588	
11589		/**
11590		 * Get the number of records in the current record set, after filtering
11591		 */
11592		"fnRecordsDisplay": function ()
11593		{
11594			return _fnDataSource( this ) == 'ssp' ?
11595				this._iRecordsDisplay * 1 :
11596				this.aiDisplay.length;
11597		},
11598	
11599		/**
11600		 * Get the display end point - aiDisplay index
11601		 */
11602		"fnDisplayEnd": function ()
11603		{
11604			var
11605				len      = this._iDisplayLength,
11606				start    = this._iDisplayStart,
11607				calc     = start + len,
11608				records  = this.aiDisplay.length,
11609				features = this.oFeatures,
11610				paginate = features.bPaginate;
11611	
11612			if ( features.bServerSide ) {
11613				return paginate === false || len === -1 ?
11614					start + records :
11615					Math.min( start+len, this._iRecordsDisplay );
11616			}
11617			else {
11618				return ! paginate || calc>records || len===-1 ?
11619					records :
11620					calc;
11621			}
11622		},
11623	
11624		/**
11625		 * The DataTables object for this table
11626		 */
11627		"oInstance": null,
11628	
11629		/**
11630		 * Unique identifier for each instance of the DataTables object. If there
11631		 * is an ID on the table node, then it takes that value, otherwise an
11632		 * incrementing internal counter is used.
11633		 */
11634		"sInstance": null,
11635	
11636		/**
11637		 * tabindex attribute value that is added to DataTables control elements, allowing
11638		 * keyboard navigation of the table and its controls.
11639		 */
11640		"iTabIndex": 0,
11641	
11642		/**
11643		 * DIV container for the footer scrolling table if scrolling
11644		 */
11645		"nScrollHead": null,
11646	
11647		/**
11648		 * DIV container for the footer scrolling table if scrolling
11649		 */
11650		"nScrollFoot": null,
11651	
11652		/**
11653		 * Last applied sort
11654		 */
11655		"aLastSort": [],
11656	
11657		/**
11658		 * Stored plug-in instances
11659		 */
11660		"oPlugins": {},
11661	
11662		/**
11663		 * Function used to get a row's id from the row's data
11664		 */
11665		"rowIdFn": null,
11666	
11667		/**
11668		 * Data location where to store a row's id
11669		 */
11670		"rowId": null,
11671	
11672		caption: '',
11673	
11674		captionNode: null,
11675	
11676		colgroup: null
11677	};
11678	
11679	/**
11680	 * Extension object for DataTables that is used to provide all extension
11681	 * options.
11682	 *
11683	 * Note that the `DataTable.ext` object is available through
11684	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
11685	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
11686	 *  @namespace
11687	 *  @extends DataTable.models.ext
11688	 */
11689	
11690	
11691	var extPagination = DataTable.ext.pager;
11692	
11693	// Paging buttons configuration
11694	$.extend( extPagination, {
11695		simple: function () {
11696			return [ 'previous', 'next' ];
11697		},
11698	
11699		full: function () {
11700			return [  'first', 'previous', 'next', 'last' ];
11701		},
11702	
11703		numbers: function () {
11704			return [ 'numbers' ];
11705		},
11706	
11707		simple_numbers: function () {
11708			return [ 'previous', 'numbers', 'next' ];
11709		},
11710	
11711		full_numbers: function () {
11712			return [ 'first', 'previous', 'numbers', 'next', 'last' ];
11713		},
11714		
11715		first_last: function () {
11716			return ['first', 'last'];
11717		},
11718		
11719		first_last_numbers: function () {
11720			return ['first', 'numbers', 'last'];
11721		},
11722	
11723		// For testing and plug-ins to use
11724		_numbers: _pagingNumbers,
11725	
11726		// Number of number buttons - legacy, use `numbers` option for paging feature
11727		numbers_length: 7
11728	} );
11729	
11730	
11731	$.extend( true, DataTable.ext.renderer, {
11732		pagingButton: {
11733			_: function (settings, buttonType, content, active, disabled) {
11734				var classes = settings.oClasses.paging;
11735				var btnClasses = [classes.button];
11736				var btn;
11737	
11738				if (active) {
11739					btnClasses.push(classes.active);
11740				}
11741	
11742				if (disabled) {
11743					btnClasses.push(classes.disabled)
11744				}
11745	
11746				if (buttonType === 'ellipsis') {
11747					btn = $('<span class="ellipsis"></span>').html(content)[0];
11748				}
11749				else {
11750					btn = $('<button>', {
11751						class: btnClasses.join(' '),
11752						role: 'link',
11753						type: 'button'
11754					}).html(content);
11755				}
11756	
11757				return {
11758					display: btn,
11759					clicker: btn
11760				}
11761			}
11762		},
11763	
11764		pagingContainer: {
11765			_: function (settings, buttons) {
11766				// No wrapping element - just append directly to the host
11767				return buttons;
11768			}
11769		}
11770	} );
11771	
11772	// Common function to remove new lines, strip HTML and diacritic control
11773	var _filterString = function (stripHtml, normalize) {
11774		return function (str) {
11775			if (_empty(str) || typeof str !== 'string') {
11776				return str;
11777			}
11778	
11779			str = str.replace( _re_new_lines, " " );
11780	
11781			if (stripHtml) {
11782				str = _stripHtml(str);
11783			}
11784	
11785			if (normalize) {
11786				str = _normalize(str, false);
11787			}
11788	
11789			return str;
11790		};
11791	}
11792	
11793	/*
11794	 * Public helper functions. These aren't used internally by DataTables, or
11795	 * called by any of the options passed into DataTables, but they can be used
11796	 * externally by developers working with DataTables. They are helper functions
11797	 * to make working with DataTables a little bit easier.
11798	 */
11799	
11800	function __mldFnName(name) {
11801		return name.replace(/[\W]/g, '_')
11802	}
11803	
11804	// Common logic for moment, luxon or a date action
11805	function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) {
11806		if (window.moment) {
11807			return dt[momentFn]( arg1 );
11808		}
11809		else if (window.luxon) {
11810			return dt[luxonFn]( arg1 );
11811		}
11812		
11813		return dateFn ? dt[dateFn]( arg1 ) : dt;
11814	}
11815	
11816	
11817	var __mlWarning = false;
11818	function __mldObj (d, format, locale) {
11819		var dt;
11820	
11821		if (window.moment) {
11822			dt = window.moment.utc( d, format, locale, true );
11823	
11824			if (! dt.isValid()) {
11825				return null;
11826			}
11827		}
11828		else if (window.luxon) {
11829			dt = format && typeof d === 'string'
11830				? window.luxon.DateTime.fromFormat( d, format )
11831				: window.luxon.DateTime.fromISO( d );
11832	
11833			if (! dt.isValid) {
11834				return null;
11835			}
11836	
11837			dt.setLocale(locale);
11838		}
11839		else if (! format) {
11840			// No format given, must be ISO
11841			dt = new Date(d);
11842		}
11843		else {
11844			if (! __mlWarning) {
11845				alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
11846			}
11847	
11848			__mlWarning = true;
11849		}
11850	
11851		return dt;
11852	}
11853	
11854	// Wrapper for date, datetime and time which all operate the same way with the exception of
11855	// the output string for auto locale support
11856	function __mlHelper (localeString) {
11857		return function ( from, to, locale, def ) {
11858			// Luxon and Moment support
11859			// Argument shifting
11860			if ( arguments.length === 0 ) {
11861				locale = 'en';
11862				to = null;
vendor: 5,221 bytes, lines 11862-12039
11862 // means toLocaleString
11863				from = null; // means iso8601
11864			}
11865			else if ( arguments.length === 1 ) {
11866				locale = 'en';
11867				to = from;
11868				from = null;
11869			}
11870			else if ( arguments.length === 2 ) {
11871				locale = to;
11872				to = from;
11873				from = null;
11874			}
11875	
11876			var typeName = 'datetime' + (to ? '-' + __mldFnName(to) : '');
11877	
11878			// Add type detection and sorting specific to this date format - we need to be able to identify
11879			// date type columns as such, rather than as numbers in extensions. Hence the need for this.
11880			if (! DataTable.ext.type.order[typeName]) {
11881				DataTable.type(typeName, {
11882					detect: function (d) {
11883						// The renderer will give the value to type detect as the type!
11884						return d === typeName ? typeName : false;
11885					},
11886					order: {
11887						pre: function (d) {
11888							// The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
11889							// `valueOf` which gives milliseconds epoch
11890							return d.valueOf();
11891						}
11892					},
11893					className: 'dt-right'
11894				});
11895			}
11896		
11897			return function ( d, type ) {
11898				// Allow for a default value
11899				if (d === null || d === undefined) {
11900					if (def === '--now') {
11901						// We treat everything as UTC further down, so no changes are
11902						// made, as such need to get the local date / time as if it were
11903						// UTC
11904						var local = new Date();
11905						d = new Date( Date.UTC(
11906							local.getFullYear(), local.getMonth(), local.getDate(),
11907							local.getHours(), local.getMinutes(), local.getSeconds()
11908						) );
11909					}
11910					else {
11911						d = '';
11912					}
11913				}
11914	
11915				if (type === 'type') {
11916					// Typing uses the type name for fast matching
11917					return typeName;
11918				}
11919	
11920				if (d === '') {
11921					return type !== 'sort'
11922						? ''
11923						: __mldObj('0000-01-01 00:00:00', null, locale);
11924				}
11925	
11926				// Shortcut. If `from` and `to` are the same, we are using the renderer to
11927				// format for ordering, not display - its already in the display format.
11928				if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) {
11929					return d;
11930				}
11931	
11932				var dt = __mldObj(d, from, locale);
11933	
11934				if (dt === null) {
11935					return d;
11936				}
11937	
11938				if (type === 'sort') {
11939					return dt;
11940				}
11941				
11942				var formatted = to === null
11943					? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
11944					: __mld(dt, 'format', 'toFormat', 'toISOString', to);
11945	
11946				// XSS protection
11947				return type === 'display' ?
11948					_escapeHtml( formatted ) :
11949					formatted;
11950			};
11951		}
11952	}
11953	
11954	// Based on locale, determine standard number formatting
11955	// Fallback for legacy browsers is US English
11956	var __thousands = ',';
11957	var __decimal = '.';
11958	
11959	if (window.Intl !== undefined) {
11960		try {
11961			var num = new Intl.NumberFormat().formatToParts(100000.1);
11962		
11963			for (var i=0 ; i<num.length ; i++) {
11964				if (num[i].type === 'group') {
11965					__thousands = num[i].value;
11966				}
11967				else if (num[i].type === 'decimal') {
11968					__decimal = num[i].value;
11969				}
11970			}
11971		}
11972		catch (e) {
11973			// noop
11974		}
11975	}
11976	
11977	// Formatted date time detection - use by declaring the formats you are going to use
11978	DataTable.datetime = function ( format, locale ) {
11979		var typeName = 'datetime-detect-' + __mldFnName(format);
11980	
11981		if (! locale) {
11982			locale = 'en';
11983		}
11984	
11985		if (! DataTable.ext.type.order[typeName]) {
11986			DataTable.type(typeName, {
11987				detect: function (d) {
11988					var dt = __mldObj(d, format, locale);
11989					return d === '' || dt ? typeName : false;
11990				},
11991				order: {
11992					pre: function (d) {
11993						return __mldObj(d, format, locale) || 0;
11994					}
11995				},
11996				className: 'dt-right'
11997			});
11998		}
11999	}
12000	
12001	/**
12002	 * Helpers for `columns.render`.
12003	 *
12004	 * The options defined here can be used with the `columns.render` initialisation
12005	 * option to provide a display renderer. The following functions are defined:
12006	 *
12007	 * * `moment` - Uses the MomentJS library to convert from a given format into another.
12008	 * This renderer has three overloads:
12009	 *   * 1 parameter:
12010	 *     * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
12011	 *   * 2 parameters:
12012	 *     * `string` - Format to convert from
12013	 *     * `string` - Format to convert to. Assumes `en` locale
12014	 *   * 3 parameters:
12015	 *     * `string` - Format to convert from
12016	 *     * `string` - Format to convert to
12017	 *     * `string` - Locale
12018	 * * `number` - Will format numeric data (defined by `columns.data`) for
12019	 *   display, retaining the original unformatted data for sorting and filtering.
12020	 *   It takes 5 parameters:
12021	 *   * `string` - Thousands grouping separator
12022	 *   * `string` - Decimal point indicator
12023	 *   * `integer` - Number of decimal points to show
12024	 *   * `string` (optional) - Prefix.
12025	 *   * `string` (optional) - Postfix (/suffix).
12026	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
12027	 *   parameters.
12028	 *
12029	 * @example
12030	 *   // Column definition using the number renderer
12031	 *   {
12032	 *     data: "salary",
12033	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
12034	 *   }
12035	 *
12036	 * @namespace
12037	 */
12038	DataTable.render = {
12039		date: __mlHelper('toLocaleDateString'),
12040		datetime: __mlHelper('toLocaleString'),
12041		time: __mlHelper('toLocaleTimeString'),
12042		number: function ( thousands, decimal, precision, prefix, postfix ) {
12043			// Auto locale detection
12044			if (thousands === null || thousands === undefined) {
12045				thousands = __thousands;
12046			}
12047	
12048			if (decimal === null || decimal === undefined) {
12049				decimal = __decimal;
12050			}
12051	
12052			return {
12053				display: function ( d ) {
12054					if ( typeof d !== 'number' && typeof d !== 'string' ) {
12055						return d;
12056					}
12057	
12058					if (d === '' || d === null) {
12059						return d;
12060					}
12061	
12062					var negative = d < 0 ? '-' : '';
12063					var flo = parseFloat( d );
12064					var abs = Math.abs(flo);
12065	
12066					// Scientific notation for large and small numbers
12067					if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0) ) {
12068						var exp = flo.toExponential(precision).split(/e\+?/);
12069						return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
12070					}
12071	
12072					// If NaN then there isn't much formatting that we can do - just
12073					// return immediately, escaping any HTML (this was supposed to
12074					// be a number after all)
12075					if ( isNaN( flo ) ) {
12076						return _escapeHtml( d );
12077					}
12078	
12079					flo = flo.toFixed( precision );
12080					d = Math.abs( flo );
12081	
12082					var intPart = parseInt( d, 10 );
12083					var floatPart = precision ?
12084						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
12085						'';
12086	
12087					// If zero, then can't have a negative prefix
12088					if (intPart === 0 && parseFloat(floatPart) === 0) {
12089						negative = '';
12090					}
12091	
12092					return negative + (prefix||'') +
12093						intPart.toString().replace(
12094							/\B(?=(\d{3})+(?!\d))/g, thousands
12095						) +
12096						floatPart +
12097						(postfix||'');
12098				}
12099			};
12100		},
12101	
12102		text: function () {
12103			return {
12104				display: _escapeHtml,
12105				filter: _escapeHtml
12106			};
12107		}
12108	};
12109	
12110	
12111	var _extTypes = DataTable.ext.type;
12112	
12113	// Get / set type
12114	DataTable.type = function (name, prop, val) {
12115		if (! prop) {
12116			return {
12117				className: _extTypes.className[name],
12118				detect: _extTypes.detect.find(function (fn) {
12119					return fn.name === name;
12120				}),
12121				order: {
12122					pre: _extTypes.order[name + '-pre'],
12123					asc: _extTypes.order[name + '-asc'],
12124					desc: _extTypes.order[name + '-desc']
12125				},
12126				render: _extTypes.render[name],
12127				search: _extTypes.search[name]
12128			};
12129		}
12130	
12131		var setProp = function(prop, propVal) {
12132			_extTypes[prop][name] = propVal;
12133		};
12134		var setDetect = function (fn) {
12135			// Wrap to allow the function to return `true` rather than
12136			// specifying the type name.
12137			var cb = function (d, s) {
12138				var ret = fn(d, s);
12139	
12140				return ret === true
12141					? name
12142					: ret;
12143			};
12144			Object.defineProperty(cb, "name", {value: name});
12145	
12146			var idx = _extTypes.detect.findIndex(function (fn) {
12147				return fn.name === name;
12148			});
12149	
12150			if (idx === -1) {
12151				_extTypes.detect.unshift(cb);
12152			}
12153			else {
12154				_extTypes.detect.splice(idx, 1, cb);
12155			}
12156		};
12157		var setOrder = function (obj) {
12158			_extTypes.order[name + '-pre'] = obj.pre; // can be undefined
12159			_extTypes.order[name + '-asc'] = obj.asc; // can be undefined
12160			_extTypes.order[name + '-desc'] = obj.desc; // can be undefined
12161		};
12162	
12163		// prop is optional
12164		if (val === undefined) {
12165			val = prop;
12166			prop = null;
12167		}
12168	
12169		if (prop === 'className') {
12170			setProp('className', val);
12171		}
12172		else if (prop === 'detect') {
12173			setDetect(val);
12174		}
12175		else if (prop === 'order') {
12176			setOrder(val);
12177		}
12178		else if (prop === 'render') {
12179			setProp('render', val);
12180		}
12181		else if (prop === 'search') {
12182			setProp('search', val);
12183		}
12184		else if (! prop) {
12185			if (val.className) {
12186				setProp('className', val.className);
12187			}
12188	
12189			if (val.detect !== undefined) {
12190				setDetect(val.detect);
12191			}
12192	
12193			if (val.order) {
12194				setOrder(val.order);
12195			}
12196	
12197			if (val.render !== undefined) {
12198				setProp('render', val.render);
12199			}
12200	
12201			if (val.search !== undefined) {
12202				setProp('search', val.search);
12203			}
12204		}
12205	}
12206	
12207	// Get a list of types
12208	DataTable.types = function () {
12209		return _extTypes.detect.map(function (fn) {
12210			return fn.name;
12211		});
12212	};
12213	
12214	//
12215	// Built in data types
12216	//
12217	
12218	DataTable.type('string', {
12219		detect: function () {
12220			return 'string';
12221		},
12222		order: {
12223			pre: function ( a ) {
12224				// This is a little complex, but faster than always calling toString,
12225				// http://jsperf.com/tostring-v-check
12226				return _empty(a) ?
12227					'' :
12228					typeof a === 'string' ?
12229						a.toLowerCase() :
12230						! a.toString ?
12231							'' :
12232							a.toString();
12233			}
12234		},
12235		search: _filterString(false, true)
12236	});
12237	
12238	
12239	DataTable.type('html', {
12240		detect: function ( d ) {
12241			return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
12242				'html' : null;
12243		},
12244		order: {
12245			pre: function ( a ) {
12246				return _empty(a) ?
12247					'' :
12248					a.replace ?
12249						_stripHtml(a).trim().toLowerCase() :
12250						a+'';
12251			}
12252		},
12253		search: _filterString(true, true)
12254	});
12255	
12256	
12257	DataTable.type('date', {
12258		className: 'dt-type-date',
12259		detect: function ( d )
12260		{
12261			// V8 tries _very_ hard to make a string passed into `Date.parse()`
12262			// valid, so we need to use a regex to restrict date formats. Use a
12263			// plug-in for anything other than ISO8601 style strings
12264			if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
12265				return null;
12266			}
12267			var parsed = Date.parse(d);
12268			return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
12269		},
12270		order: {
12271			pre: function ( d ) {
12272				var ts = Date.parse( d );
12273				return isNaN(ts) ? -Infinity : ts;
12274			}
12275		}
12276	});
12277	
12278	
12279	DataTable.type('html-num-fmt', {
12280		className: 'dt-type-numeric',
12281		detect: function ( d, settings )
12282		{
12283			var decimal = settings.oLanguage.sDecimal;
12284			return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt' : null;
12285		},
12286		order: {
12287			pre: function ( d, s ) {
12288				var dp = s.oLanguage.sDecimal;
12289				return __numericReplace( d, dp, _re_html, _re_formatted_numeric );
12290			}
12291		},
12292		search: _filterString(true, true)
12293	});
12294	
12295	
12296	DataTable.type('html-num', {
12297		className: 'dt-type-numeric',
12298		detect: function ( d, settings )
12299		{
12300			var decimal = settings.oLanguage.sDecimal;
12301			return _htmlNumeric( d, decimal ) ? 'html-num' : null;
12302		},
12303		order: {
12304			pre: function ( d, s ) {
12305				var dp = s.oLanguage.sDecimal;
12306				return __numericReplace( d, dp, _re_html );
12307			}
12308		},
12309		search: _filterString(true, true)
12310	});
12311	
12312	
12313	DataTable.type('num-fmt', {
12314		className: 'dt-type-numeric',
12315		detect: function ( d, settings )
12316		{
12317			var decimal = settings.oLanguage.sDecimal;
12318			return _isNumber( d, decimal, true ) ? 'num-fmt' : null;
12319		},
12320		order: {
12321			pre: function ( d, s ) {
12322				var dp = s.oLanguage.sDecimal;
12323				return __numericReplace( d, dp, _re_formatted_numeric );
12324			}
12325		}
12326	});
12327	
12328	
12329	DataTable.type('num', {
12330		className: 'dt-type-numeric',
12331		detect: function ( d, settings )
12332		{
12333			var decimal = settings.oLanguage.sDecimal;
12334			return _isNumber( d, decimal ) ? 'num' : null;
12335		},
12336		order: {
12337			pre: function (d, s) {
12338				var dp = s.oLanguage.sDecimal;
12339				return __numericReplace( d, dp );
12340			}
12341		}
12342	});
12343	
12344	
12345	
12346	
12347	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
12348		if ( d !== 0 && (!d || d === '-') ) {
12349			return -Infinity;
12350		}
12351		
12352		var type = typeof d;
12353	
12354		if (type === 'number' || type === 'bigint') {
12355			return d;
12356		}
12357	
12358		// If a decimal place other than `.` is used, it needs to be given to the
12359		// function so we can detect it and replace with a `.` which is the only
12360		// decimal place Javascript recognises - it is not locale aware.
12361		if ( decimalPlace ) {
12362			d = _numToDecimal( d, decimalPlace );
12363		}
12364	
12365		if ( d.replace ) {
12366			if ( re1 ) {
12367				d = d.replace( re1, '' );
12368			}
12369	
12370			if ( re2 ) {
12371				d = d.replace( re2, '' );
12372			}
12373		}
12374	
12375		return d * 1;
12376	};
12377	
12378	
12379	$.extend( true, DataTable.ext.renderer, {
12380		footer: {
12381			_: function ( settings, cell, classes ) {
12382				cell.addClass(classes.tfoot.cell);
12383			}
12384		},
12385	
12386		header: {
12387			_: function ( settings, cell, classes ) {
12388				cell.addClass(classes.thead.cell);
12389	
12390				if (! settings.oFeatures.bSort) {
12391					cell.addClass(classes.order.none);
12392				}
12393	
12394				var legacyTop = settings.bSortCellsTop;
12395				var headerRows = cell.closest('thead').find('tr');
12396				var rowIdx = cell.parent().index();
12397	
12398				// Conditions to not apply the ordering icons
12399				if (
12400					// Cells and rows which have the attribute to disable the icons
12401					cell.attr('data-dt-order') === 'disable' ||
12402					cell.parent().attr('data-dt-order') === 'disable' ||
12403	
12404					// Legacy support for `orderCellsTop`. If it is set, then cells
12405					// which are not in the top or bottom row of the header (depending
12406					// on the value) do not get the sorting classes applied to them
12407					(legacyTop === true && rowIdx !== 0) ||
12408					(legacyTop === false && rowIdx !== headerRows.length - 1)
12409				) {
12410					return;
12411				}
12412	
12413				// No additional mark-up required
12414				// Attach a sort listener to update on sort - note that using the
12415				// `DT` namespace will allow the event to be removed automatically
12416				// on destroy, while the `dt` namespaced event is the one we are
12417				// listening for
12418				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting ) {
12419					if ( settings !== ctx ) { // need to check this this is the host
12420						return;               // table, not a nested one
12421					}
12422	
12423					var orderClasses = classes.order;
12424					var columns = ctx.api.columns( cell );
12425					var col = settings.aoColumns[columns.flatten()[0]];
12426					var orderable = columns.orderable().includes(true);
12427					var ariaType = '';
12428					var indexes = columns.indexes();
12429					var sortDirs = columns.orderable(true).flatten();
12430					var orderedColumns = ',' + sorting.map( function (val) {
12431						return val.col;
12432					} ).join(',') + ',';
12433	
12434					cell
12435						.removeClass(
12436							orderClasses.isAsc +' '+
12437							orderClasses.isDesc
12438						)
12439						.toggleClass( orderClasses.none, ! orderable )
12440						.toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
12441						.toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
12442					
12443					var sortIdx = orderedColumns.indexOf( ',' + indexes.toArray().join(',') + ',' );
12444	
12445					if ( sortIdx !== -1 ) {
12446						// Get the ordering direction for the columns under this cell
12447						// Note that it is possible for a cell to be asc and desc sorting
12448						// (column spanning cells)
12449						var orderDirs = columns.order();
12450	
12451						cell.addClass(
12452							orderDirs.includes('asc') ? orderClasses.isAsc : '' +
12453							orderDirs.includes('desc') ? orderClasses.isDesc : ''
12454						);
12455					}
12456	
12457					// The ARIA spec says that only one column should be marked with aria-sort
12458					if ( sortIdx === 0 ) {
12459						var firstSort = sorting[0];
12460						var sortOrder = col.asSorting;
12461	
12462						cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
12463	
12464						// Determine if the next click will remove sorting or change the sort
12465						ariaType = ! sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
12466					}
12467					else {
12468						cell.removeAttr('aria-sort');
12469					}
12470	
12471					cell.attr('aria-label', orderable
12472						? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
12473						: col.ariaTitle
12474					);
12475	
12476					if (orderable) {
12477						cell.find('.dt-column-title').attr('role', 'button');
12478						cell.attr('tabindex', 0)
12479					}
12480				} );
12481			}
12482		},
12483	
12484		layout: {
12485			_: function ( settings, container, items ) {
12486				var row = $('<div/>')
12487					.addClass('dt-layout-row')
12488					.appendTo( container );
12489	
12490				$.each( items, function (key, val) {
12491					var klass = ! val.table ?
12492						'dt-'+key+' ' :
12493						'';
12494	
12495					if (val.table) {
12496						row.addClass('dt-layout-table');
12497					}
12498	
12499					$('<div/>')
12500						.attr({
12501							id: val.id || null,
12502							"class": 'dt-layout-cell '+klass+(val.className || '')
12503						})
12504						.append( val.contents )
12505						.appendTo( row );
12506				} );
12507			}
12508		}
12509	} );
12510	
12511	
12512	DataTable.feature = {};
12513	
12514	// Third parameter is internal only!
12515	DataTable.feature.register = function ( name, cb, legacy ) {
12516		DataTable.ext.features[ name ] = cb;
12517	
12518		if (legacy) {
12519			_ext.feature.push({
12520				cFeature: legacy,
12521				fnInit: cb
12522			});
12523		}
12524	};
12525	
12526	DataTable.feature.register( 'info', function ( settings, opts ) {
12527		// For compatibility with the legacy `info` top level option
12528		if (! settings.oFeatures.bInfo) {
12529			return null;
12530		}
12531	
12532		var
12533			lang  = settings.oLanguage,
12534			tid = settings.sTableId,
12535			n = $('<div/>', {
12536				'class': settings.oClasses.info.container,
12537			} );
12538	
12539		opts = $.extend({
12540			callback: lang.fnInfoCallback,
12541			empty: lang.sInfoEmpty,
12542			postfix: lang.sInfoPostFix,
12543			search: lang.sInfoFiltered,
12544			text: lang.sInfo,
12545		}, opts);
12546	
12547	
12548		// Update display on each draw
12549		settings.aoDrawCallback.push(function (s) {
12550			_fnUpdateInfo(s, opts, n);
12551		});
12552	
12553		// For the first info display in the table, we add a callback and aria information.
12554		if (! settings._infoEl) {
12555			n.attr({
12556				'aria-live': 'polite',
12557				id: tid+'_info',
12558				role: 'status'
12559			});
12560	
12561			// Table is described by our info div
12562			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
12563	
12564			settings._infoEl = n;
12565		}
12566	
12567		return n;
12568	}, 'i' );
12569	
12570	/**
12571	 * Update the information elements in the display
12572	 *  @param {object} settings dataTables settings object
12573	 *  @memberof DataTable#oApi
12574	 */
12575	function _fnUpdateInfo ( settings, opts, node )
12576	{
12577		var
12578			start = settings._iDisplayStart+1,
12579			end   = settings.fnDisplayEnd(),
12580			max   = settings.fnRecordsTotal(),
12581			total = settings.fnRecordsDisplay(),
12582			out   = total
12583				? opts.text
12584				: opts.empty;
12585	
12586		if ( total !== max ) {
12587			// Record set after filtering
12588			out += ' ' + opts.search;
12589		}
12590	
12591		// Convert the macros
12592		out += opts.postfix;
12593		out = _fnMacros( settings, out );
12594	
12595		if ( opts.callback ) {
12596			out = opts.callback.call( settings.oInstance,
12597				settings, start, end, max, total, out
12598			);
12599		}
12600	
12601		node.html( out );
12602	
12603		_fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
12604	}
12605	
12606	var __searchCounter = 0;
12607	
12608	// opts
12609	// - text
12610	// - placeholder
12611	DataTable.feature.register( 'search', function ( settings, opts ) {
12612		// Don't show the input if filtering isn't available on the table
12613		if (! settings.oFeatures.bFilter) {
12614			return null;
12615		}
12616	
12617		var classes = settings.oClasses.search;
12618		var tableId = settings.sTableId;
12619		var language = settings.oLanguage;
12620		var previousSearch = settings.oPreviousSearch;
12621		var input = '<input type="search" class="'+classes.input+'"/>';
12622	
12623		opts = $.extend({
12624			placeholder: language.sSearchPlaceholder,
12625			text: language.sSearch
12626		}, opts);
12627	
12628		// The _INPUT_ is optional - is appended if not present
12629		if (opts.text.indexOf('_INPUT_') === -1) {
12630			opts.text += '_INPUT_';
12631		}
12632	
12633		opts.text = _fnMacros(settings, opts.text);
12634	
12635		// We can put the <input> outside of the label if it is at the start or end
12636		// which helps improve accessability (not all screen readers like implicit
12637		// for elements).
12638		var end = opts.text.match(/_INPUT_$/);
12639		var start = opts.text.match(/^_INPUT_/);
12640		var removed = opts.text.replace(/_INPUT_/, '');
12641		var str = '<label>' + opts.text + '</label>';
12642	
12643		if (start) {
12644			str = '_INPUT_<label>' + removed + '</label>';
12645		}
12646		else if (end) {
12647			str = '<label>' + removed + '</label>_INPUT_';
12648		}
12649	
12650		var filter = $('<div>')
12651			.addClass(classes.container)
12652			.append(str.replace(/_INPUT_/, input));
12653	
12654		// add for and id to label and input
12655		filter.find('label').attr('for', 'dt-search-' + __searchCounter);
12656		filter.find('input').attr('id', 'dt-search-' + __searchCounter);
12657		__searchCounter++;
12658	
12659		var searchFn = function(event) {
12660			var val = this.value;
12661	
12662			if(previousSearch.return && event.key !== "Enter") {
12663				return;
12664			}
12665	
12666			/* Now do the filter */
12667			if ( val != previousSearch.search ) {
12668				previousSearch.search = val;
12669	
12670				_fnFilterComplete( settings, previousSearch );
12671	
12672				// Need to redraw, without resorting
12673				settings._iDisplayStart = 0;
12674				_fnDraw( settings );
12675			}
12676		};
12677	
12678		var searchDelay = settings.searchDelay !== null ?
12679			settings.searchDelay :
12680			0;
12681	
12682		var jqFilter = $('input', filter)
12683			.val( previousSearch.search )
12684			.attr( 'placeholder', opts.placeholder )
12685			.on(
12686				'keyup.DT search.DT input.DT paste.DT cut.DT',
12687				searchDelay ?
12688					DataTable.util.debounce( searchFn, searchDelay ) :
12689					searchFn
12690			)
12691			.on( 'mouseup.DT', function(e) {
12692				// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
12693				// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
12694				// checks the value to see if it has changed. In other browsers it won't have.
12695				setTimeout( function () {
12696					searchFn.call(jqFilter[0], e);
12697				}, 10);
12698			} )
12699			.on( 'keypress.DT', function(e) {
12700				/* Prevent form submission */
12701				if ( e.keyCode == 13 ) {
12702					return false;
12703				}
12704			} )
12705			.attr('aria-controls', tableId);
12706	
12707		// Update the input elements whenever the table is filtered
12708		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
12709			if ( settings === s && jqFilter[0] !== document.activeElement ) {
12710				jqFilter.val( typeof previousSearch.search !== 'function'
12711					? previousSearch.search
12712					: ''
12713				);
12714			}
12715		} );
12716	
12717		return filter;
12718	}, 'f' );
12719	
12720	// opts
12721	// - type - button configuration
12722	// - buttons - number of buttons to show - must be odd
12723	DataTable.feature.register( 'paging', function ( settings, opts ) {
12724		// Don't show the paging input if the table doesn't have paging enabled
12725		if (! settings.oFeatures.bPaginate) {
12726			return null;
12727		}
12728	
12729		opts = $.extend({
12730			buttons: DataTable.ext.pager.numbers_length,
12731			type: settings.sPaginationType,
12732			boundaryNumbers: true
12733		}, opts);
12734	
12735		// To be removed in 2.1
12736		if (opts.numbers) {
12737			opts.buttons = opts.numbers;
12738		}
12739	
12740		var host = $('<div/>').addClass( settings.oClasses.paging.container + ' paging_' + opts.type );
12741		var draw = function () {
12742			_pagingDraw(settings, host, opts);
12743		};
12744	
12745		settings.aoDrawCallback.push(draw);
12746	
12747		// Responsive redraw of paging control
12748		$(settings.nTable).on('column-sizing.dt.DT', draw);
12749	
12750		return host;
12751	}, 'p' );
12752	
12753	function _pagingDraw(settings, host, opts) {
12754		if (! settings._bInitComplete) {
12755			return;
12756		}
12757	
12758		var
12759			plugin = DataTable.ext.pager[ opts.type ],
12760			aria = settings.oLanguage.oAria.paginate || {},
12761			start      = settings._iDisplayStart,
12762			len        = settings._iDisplayLength,
12763			visRecords = settings.fnRecordsDisplay(),
12764			all        = len === -1,
12765			page = all ? 0 : Math.ceil( start / len ),
12766			pages = all ? 1 : Math.ceil( visRecords / len ),
12767			buttons = plugin()
12768				.map(function (val) {
12769					return val === 'numbers'
12770						? _pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
12771						: val;
12772				})
12773				.flat();
12774	
12775		var buttonEls = [];
12776	
12777		for (var i=0 ; i<buttons.length ; i++) {
12778			var button = buttons[i];
12779	
12780			var btnInfo = _pagingButtonInfo(settings, button, page, pages);
12781			var btn = _fnRenderer( settings, 'pagingButton' )(
12782				settings,
12783				button,
12784				btnInfo.display,
12785				btnInfo.active,
12786				btnInfo.disabled
12787			);
12788	
12789			// Common attributes
12790			$(btn.clicker).attr({
12791				'aria-controls': settings.sTableId,
12792				'aria-disabled': btnInfo.disabled ? 'true' : null,
12793				'aria-current': btnInfo.active ? 'page' : null,
12794				'aria-label': aria[ button ],
12795				'data-dt-idx': button,
12796				'tabIndex': btnInfo.disabled ? -1 : settings.iTabIndex,
12797			});
12798	
12799			if (typeof button !== 'number') {
12800				$(btn.clicker).addClass(button);
12801			}
12802	
12803			_fnBindAction(
12804				btn.clicker, {action: button}, function(e) {
12805					e.preventDefault();
12806	
12807					_fnPageChange( settings, e.data.action, true );
12808				}
12809			);
12810	
12811			buttonEls.push(btn.display);
12812		}
12813	
12814		var wrapped = _fnRenderer(settings, 'pagingContainer')(
12815			settings, buttonEls
12816		);
12817	
12818		var activeEl = host.find(document.activeElement).data('dt-idx');
12819	
12820		host.empty().append(wrapped);
12821	
12822		if ( activeEl !== undefined ) {
12823			host.find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
12824		}
12825	
12826		// Responsive - check if the buttons are over two lines based on the
12827		// height of the buttons and the container.
12828		if (
12829			buttonEls.length && // any buttons
12830			opts.numbers > 1 && // prevent infinite
12831			$(host).height() >= ($(buttonEls[0]).outerHeight() * 2) - 10
12832		) {
12833			_pagingDraw(settings, host, $.extend({}, opts, { numbers: opts.numbers - 2 }));
12834		}
12835	}
12836	
12837	/**
12838	 * Get properties for a button based on the current paging state of the table
12839	 *
12840	 * @param {*} settings DT settings object
12841	 * @param {*} button The button type in question
12842	 * @param {*} page Table's current page
12843	 * @param {*} pages Number of pages
12844	 * @returns Info object
12845	 */
12846	function _pagingButtonInfo(settings, button, page, pages) {
12847		var lang = settings.oLanguage.oPaginate;
12848		var o = {
12849			display: '',
12850			active: false,
12851			disabled: false
12852		};
12853	
12854		switch ( button ) {
12855			case 'ellipsis':
12856				o.display = '&#x2026;';
12857				o.disabled = true;
12858				break;
12859	
12860			case 'first':
12861				o.display = lang.sFirst;
12862	
12863				if (page === 0) {
12864					o.disabled = true;
12865				}
12866				break;
12867	
12868			case 'previous':
12869				o.display = lang.sPrevious;
12870	
12871				if ( page === 0 ) {
12872					o.disabled = true;
12873				}
12874				break;
12875	
12876			case 'next':
12877				o.display = lang.sNext;
12878	
12879				if ( pages === 0 || page === pages-1 ) {
12880					o.disabled = true;
12881				}
12882				break;
12883	
12884			case 'last':
12885				o.display = lang.sLast;
12886	
12887				if ( pages === 0 || page === pages-1 ) {
12888					o.disabled = true;
12889				}
12890				break;
12891	
12892			default:
12893				if ( typeof button === 'number' ) {
12894					o.display = settings.fnFormatNumber( button + 1 );
12895					
12896					if (page === button) {
12897						o.active = true;
12898					}
12899				}
12900				break;
12901		}
12902	
12903		return o;
12904	}
12905	
12906	/**
12907	 * Compute what number buttons to show in the paging control
12908	 *
12909	 * @param {*} page Current page
12910	 * @param {*} pages Total number of pages
12911	 * @param {*} buttons Target number of number buttons
12912	 * @param {boolean} addFirstLast Indicate if page 1 and end should be included
12913	 * @returns Buttons to show
12914	 */
12915	function _pagingNumbers ( page, pages, buttons, addFirstLast ) {
12916		var
12917			numbers = [],
12918			half = Math.floor(buttons / 2),
12919			before = addFirstLast ? 2 : 1,
12920			after = addFirstLast ? 1 : 0;
12921	
12922		if ( pages <= buttons ) {
12923			numbers = _range(0, pages);
12924		}
12925		else if (buttons === 1) {
12926			// Single button - current page only
12927			numbers = [page];
12928		}
12929		else if (buttons === 3) {
12930			// Special logic for just three buttons
12931			if (page <= 1) {
12932				numbers = [0, 1, 'ellipsis'];
12933			}
12934			else if (page >= pages - 2) {
12935				numbers = _range(pages-2, pages);
12936				numbers.unshift('ellipsis');
12937			}
12938			else {
12939				numbers = ['ellipsis', page, 'ellipsis'];
12940			}
12941		}
12942		else if ( page <= half ) {
12943			numbers = _range(0, buttons-before);
12944			numbers.push('ellipsis');
12945	
12946			if (addFirstLast) {
12947				numbers.push(pages-1);
12948			}
12949		}
12950		else if ( page >= pages - 1 - half ) {
12951			numbers = _range(pages-(buttons-before), pages);
12952			numbers.unshift('ellipsis');
12953	
12954			if (addFirstLast) {
12955				numbers.unshift(0);
12956			}
12957		}
12958		else {
12959			numbers = _range(page-half+before, page+half-after);
12960			numbers.push('ellipsis');
12961			numbers.unshift('ellipsis');
12962	
12963			if (addFirstLast) {
12964				numbers.push(pages-1);
12965				numbers.unshift(0);
12966			}
12967		}
12968	
12969		return numbers;
12970	}
12971	
12972	var __lengthCounter = 0;
12973	
12974	// opts
12975	// - menu
12976	// - text
12977	DataTable.feature.register( 'pageLength', function ( settings, opts ) {
12978		var features = settings.oFeatures;
12979	
12980		// For compatibility with the legacy `pageLength` top level option
12981		if (! features.bPaginate || ! features.bLengthChange) {
12982			return null;
12983		}
12984	
12985		opts = $.extend({
12986			menu: settings.aLengthMenu,
12987			text: settings.oLanguage.sLengthMenu
12988		}, opts);
12989	
12990		var
12991			classes  = settings.oClasses.length,
12992			tableId  = settings.sTableId,
12993			menu     = opts.menu,
12994			lengths  = [],
12995			language = [],
12996			i;
12997	
12998		// Options can be given in a number of ways
12999		if (Array.isArray( menu[0] )) {
13000			// Old 1.x style - 2D array
13001			lengths = menu[0];
13002			language = menu[1];
13003		}
13004		else {
13005			for ( i=0 ; i<menu.length ; i++ ) {
13006				// An object with different label and value
13007				if ($.isPlainObject(menu[i])) {
13008					lengths.push(menu[i].value);
13009					language.push(menu[i].label);
13010				}
13011				else {
13012					// Or just a number to display and use
13013					lengths.push(menu[i]);
13014					language.push(menu[i]);
13015				}
13016			}
13017		}
13018	
13019		// We can put the <select> outside of the label if it is at the start or
13020		// end which helps improve accessability (not all screen readers like
13021		// implicit for elements).
13022		var end = opts.text.match(/_MENU_$/);
13023		var start = opts.text.match(/^_MENU_/);
13024		var removed = opts.text.replace(/_MENU_/, '');
13025		var str = '<label>' + opts.text + '</label>';
13026	
13027		if (start) {
13028			str = '_MENU_<label>' + removed + '</label>';
13029		}
13030		else if (end) {
13031			str = '<label>' + removed + '</label>_MENU_';
13032		}
13033	
13034		// Wrapper element - use a span as a holder for where the select will go
13035		var div = $('<div/>')
13036			.addClass( classes.container )
13037			.append(
13038				str.replace( '_MENU_', '<span></span>' )
13039			);
13040	
13041		// Save text node content for macro updating
13042		var textNodes = [];
13043		div.find('label')[0].childNodes.forEach(function (el) {
13044			if (el.nodeType === Node.TEXT_NODE) {
13045				textNodes.push({
13046					el: el,
13047					text: el.textContent
13048				});
13049			}
13050		})
13051	
13052		// Update the label text in case it has an entries value
13053		var updateEntries = function (len) {
13054			textNodes.forEach(function (node) {
13055				node.el.textContent = _fnMacros(settings, node.text, len);
13056			});
13057		}
13058	
13059		// Next, the select itself, along with the options
13060		var select = $('<select/>', {
13061			'name':          tableId+'_length',
13062			'aria-controls': tableId,
13063			'class':         classes.select
13064		} );
13065	
13066		for ( i=0 ; i<lengths.length ; i++ ) {
13067			select[0][ i ] = new Option(
13068				typeof language[i] === 'number' ?
13069					settings.fnFormatNumber( language[i] ) :
13070					language[i],
13071				lengths[i]
13072			);
13073		}
13074	
13075		// add for and id to label and input
13076		div.find('label').attr('for', 'dt-length-' + __lengthCounter);
13077		select.attr('id', 'dt-length-' + __lengthCounter);
13078		__lengthCounter++;
13079	
13080		// Swap in the select list
13081		div.find('span').replaceWith(select);
13082	
13083		// Can't use `select` variable as user might provide their own and the
13084		// reference is broken by the use of outerHTML
13085		$('select', div)
13086			.val( settings._iDisplayLength )
13087			.on( 'change.DT', function() {
13088				_fnLengthChange( settings, $(this).val() );
13089				_fnDraw( settings );
13090			} );
13091	
13092		// Update node value whenever anything changes the table's length
13093		$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
13094			if ( settings === s ) {
13095				$('select', div).val( len );
13096	
13097				// Resolve plurals in the text for the new length
13098				updateEntries(len);
13099			}
13100		} );
13101	
13102		updateEntries(settings._iDisplayLength);
13103	
13104		return div;
13105	}, 'l' );
13106	
13107	// jQuery access
13108	$.fn.dataTable = DataTable;
13109	
13110	// Provide access to the host jQuery object (circular reference)
13111	DataTable.$ = $;
13112	
13113	// Legacy aliases
13114	$.fn.dataTableSettings = DataTable.settings;
13115	$.fn.dataTableExt = DataTable.ext;
13116	
13117	// With a capital `D` we return a DataTables API instance rather than a
13118	// jQuery object
13119	$.fn.DataTable = function ( opts ) {
13120		return $(this).dataTable( opts ).api();
13121	};
13122	
13123	// All properties that are available to $.fn.dataTable should also be
13124	// available on $.fn.DataTable
13125	$.each( DataTable, function ( prop, val ) {
13126		$.fn.DataTable[ prop ] = val;
13127	} );
13128
13129	return DataTable;
13130}));

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.