PageSourceSearch

https://openanesthesiajournal.com/js/pagination/dataTables.js

js openanesthesiajournal.com collected 2026-09-28 10:06:12 UTC 366,859 bytes, 13,154 lines download raw bytes

vendor: 5,308 bytes, lines 1-190
1/*! DataTables 2.0.7
2 * © SpryMedia Ltd - datatables.net/license
3 */
4
5/**
6 * @summary     DataTables
7 * @description Paginate, search and order HTML tables
8 * @version     2.0.7
9 * @author      SpryMedia Ltd
10 * @contact     www.datatables.net
11 * @copyright   SpryMedia Ltd.
12 *
13 * This source file is free software, available under the following license:
14 *   MIT license - https://datatables.net/license
15 *
16 * This source file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
19 *
20 * For details please refer to: https://www.datatables.net
21 */
22
23(function( factory ) {
24	"use strict";
25
26	if ( typeof define === 'function' && define.amd ) {
27		// AMD
28		define( ['jquery'], function ( $ ) {
29			return factory( $, window, document );
30		} );
31	}
32	else if ( typeof exports === 'object' ) {
33		// CommonJS
34		// jQuery's factory checks for a global window - if it isn't present then it
35		// returns a factory function that expects the window object
36		var jq = require('jquery');
37
38		if (typeof window === 'undefined') {
39			module.exports = function (root, $) {
40				if ( ! root ) {
41					// CommonJS environments without a window global must pass a
42					// root. This will give an error otherwise
43					root = window;
44				}
45
46				if ( ! $ ) {
47					$ = jq( root );
48				}
49
50				return factory( $, root, root.document );
51			};
52		}
53		else {
54			module.exports = factory( jq, window, window.document );
55		}
56	}
57	else {
58		// Browser
59		window.DataTable = factory( jQuery, window, document );
60	}
61}(function( $, window, document ) {
62	"use strict";
63
64	
65	var DataTable = function ( selector, options )
66	{
67		// Check if called with a window or jQuery object for DOM less applications
68		// This is for backwards compatibility
69		if (DataTable.factory(selector, options)) {
70			return DataTable;
71		}
72	
73		// When creating with `new`, create a new DataTable, returning the API instance
74		if (this instanceof DataTable) {
75			return $(selector).DataTable(options);
76		}
77		else {
78			// Argument switching
79			options = selector;
80		}
81	
82		var _that = this;
83		var emptyInit = options === undefined;
84		var len = this.length;
85	
86		if ( emptyInit ) {
87			options = {};
88		}
89	
90		// Method to get DT API instance from jQuery object
91		this.api = function ()
92		{
93			return new _Api( this );
94		};
95	
96		this.each(function() {
97			// For each initialisation we want to give it a clean initialisation
98			// object that can be bashed around
99			var o = {};
100			var oInit = len > 1 ? // optimisation for single table case
101				_fnExtend( o, options, true ) :
102				options;
103	
104			
105			var i=0, iLen;
106			var sId = this.getAttribute( 'id' );
107			var bInitHandedOff = false;
108			var defaults = DataTable.defaults;
109			var $this = $(this);
110			
111			
112			/* Sanity check */
113			if ( this.nodeName.toLowerCase() != 'table' )
114			{
115				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
116				return;
117			}
118			
119			$(this).trigger( 'options.dt', oInit );
120			
121			/* Backwards compatibility for the defaults */
122			_fnCompatOpts( defaults );
123			_fnCompatCols( defaults.column );
124			
125			/* Convert the camel-case defaults to Hungarian */
126			_fnCamelToHungarian( defaults, defaults, true );
127			_fnCamelToHungarian( defaults.column, defaults.column, true );
128			
129			/* Setting up the initialisation object */
130			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
131			
132			
133			
134			/* Check to see if we are re-initialising a table */
135			var allSettings = DataTable.settings;
136			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
137			{
138				var s = allSettings[i];
139			
140				/* Base check on table node */
141				if (
142					s.nTable == this ||
143					(s.nTHead && s.nTHead.parentNode == this) ||
144					(s.nTFoot && s.nTFoot.parentNode == this)
145				) {
146					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
147					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
148			
149					if ( emptyInit || bRetrieve )
150					{
151						return s.oInstance;
152					}
153					else if ( bDestroy )
154					{
155						new DataTable.Api(s).destroy();
156						break;
157					}
158					else
159					{
160						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
161						return;
162					}
163				}
164			
165				/* If the element we are initialising has the same ID as a table which was previously
166				 * initialised, but the table nodes don't match (from before) then we destroy the old
167				 * instance by simply deleting it. This is under the assumption that the table has been
168				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
169				 */
170				if ( s.sTableId == this.id )
171				{
172					allSettings.splice( i, 1 );
173					break;
174				}
175			}
176			
177			/* Ensure the table has an ID - required for accessibility */
178			if ( sId === null || sId === "" )
179			{
180				sId = "DataTables_Table_"+(DataTable.ext._unique++);
181				this.id = sId;
182			}
183			
184			/* Create the settings object for this table and set some of the default parameters */
185			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
186				"sDestroyWidth": $this[0].style.width,
187				"sInstance":     sId,
188				"sTableId":      sId,
189				colgroup: $('<colgroup>').prependTo(this),
190				fastData: function (row, column, type) {
191					return _fnGetCellData(oSettings, row, column, type);
192				}
193			} );
194			oSettings.nTable = this;
195			oSettings.oInit  = oInit;
196			
197			allSettings.push( oSettings );
198			
199			// Make a single API instance available for internal handling
200			oSettings.api = new _Api( oSettings );
201			
202			// Need to add the instance after the instance after the settings object has been added
203			// to the settings array, so we can self reference the table instance if more than one
204			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
205			
206			// Backwards compatibility, before we apply all the defaults
207			_fnCompatOpts( oInit );
208			
209			// If the length menu is given, but the init display length is not, use the length menu
210			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
211			{
212				oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
213					? oInit.aLengthMenu[0][0]
214					: $.isPlainObject( oInit.aLengthMenu[0] )
215						? oInit.aLengthMenu[0].value
216						: oInit.aLengthMenu[0];
217			}
218			
219			// Apply the defaults and init options to make a single init object will all
220			// options defined from defaults and instance options.
221			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
222			
223			
224			// Map the initialisation options onto the settings object
225			_fnMap( oSettings.oFeatures, oInit, [
226				"bPaginate",
227				"bLengthChange",
228				"bFilter",
229				"bSort",
230				"bSortMulti",
231				"bInfo",
232				"bProcessing",
233				"bAutoWidth",
234				"bSortClasses",
235				"bServerSide",
236				"bDeferRender"
237			] );
238			_fnMap( oSettings, oInit, [
239				"ajax",
240				"fnFormatNumber",
241				"sServerMethod",
242				"aaSorting",
243				"aaSortingFixed",
244				"aLengthMenu",
245				"sPaginationType",
246				"iStateDuration",
247				"bSortCellsTop",
248				"iTabIndex",
249				"sDom",
250				"fnStateLoadCallback",
251				"fnStateSaveCallback",
252				"renderer",
253				"searchDelay",
254				"rowId",
255				"caption",
256				"layout",
257				[ "iCookieDuration", "iStateDuration" ], // backwards compat
258				[ "oSearch", "oPreviousSearch" ],
259				[ "aoSearchCols", "aoPreSearchCols" ],
260				[ "iDisplayLength", "_iDisplayLength" ]
261			] );
262			_fnMap( oSettings.oScroll, oInit, [
263				[ "sScrollX", "sX" ],
264				[ "sScrollXInner", "sXInner" ],
265				[ "sScrollY", "sY" ],
266				[ "bScrollCollapse", "bCollapse" ]
267			] );
268			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
269			
270			/* Callback functions which are array driven */
271			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback );
272			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams );
273			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams );
274			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded );
275			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback );
276			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
277			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback );
278			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback );
279			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete );
280			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback );
281			
282			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
283			
284			/* Browser support detection */
285			_fnBrowserDetect( oSettings );
286			
287			var oClasses = oSettings.oClasses;
288			
289			$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
290			$this.addClass( oClasses.table );
291			
292			if (! oSettings.oFeatures.bPaginate) {
293				oInit.iDisplayStart = 0;
294			}
295			
296			if ( oSettings.iInitDisplayStart === undefined )
297			{
298				/* Display start point, taking into account the save saving */
299				oSettings.iInitDisplayStart = oInit.iDisplayStart;
300				oSettings._iDisplayStart = oInit.iDisplayStart;
301			}
302			
303			/* Language definitions */
304			var oLanguage = oSettings.oLanguage;
305			$.extend( true, oLanguage, oInit.oLanguage );
306			
307			if ( oLanguage.sUrl )
308			{
309				/* Get the language definitions from a file - because this Ajax call makes the language
310				 * get async to the remainder of this function we use bInitHandedOff to indicate that
311				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
312				 */
313				$.ajax( {
314					dataType: 'json',
315					url: oLanguage.sUrl,
316					success: function ( json ) {
317						_fnCamelToHungarian( defaults.oLanguage, json );
318						$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
319			
320						_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
321						_fnInitialise( oSettings );
322					},
323					error: function () {
324						// Error occurred loading language file
325						_fnLog( oSettings, 0, 'i18n file loading error', 21 );
326			
327						// continue on as best we can
328						_fnInitialise( oSettings );
329					}
330				} );
331				bInitHandedOff = true;
332			}
333			else {
334				_fnCallbackFire( oSettings, null, 'i18n', [oSettings]);
335			}
336			
337			/*
338			 * Columns
339			 * See if we should load columns automatically or use defined ones
340			 */
341			var columnsInit = [];
342			var thead = this.getElementsByTagName('thead');
343			var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
344			
345			// If we don't have a columns array, then generate one with nulls
346			if ( oInit.aoColumns ) {
347				columnsInit = oInit.aoColumns;
348			}
349			else if ( initHeaderLayout.length ) {
350				for ( i=0, iLen=initHeaderLayout[0].length ; i<iLen ; i++ ) {
351					columnsInit.push( null );
352				}
353			}
354			
355			// Add the columns
356			for ( i=0, iLen=columnsInit.length ; i<iLen ; i++ ) {
357				_fnAddColumn( oSettings );
358			}
359			
360			// Apply the column definitions
361			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
362				_fnColumnOptions( oSettings, iCol, oDef );
363			} );
364			
365			/* HTML5 attribute detection - build an mData object automatically if the
366			 * attributes are found
367			 */
368			var rowOne = $this.children('tbody').find('tr').eq(0);
369			
370			if ( rowOne.length ) {
371				var a = function ( cell, name ) {
372					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
373				};
374			
375				$( rowOne[0] ).children('th, td').each( function (i, cell) {
376					var col = oSettings.aoColumns[i];
377			
378					if (! col) {
379						_fnLog( oSettings, 0, 'Incorrect column count', 18 );
380					}
381			
382					if ( col.mData === i ) {
383						var sort = a( cell, 'sort' ) || a( cell, 'order' );
384						var filter = a( cell, 'filter' ) || a( cell, 'search' );
385			
386						if ( sort !== null || filter !== null ) {
387							col.mData = {
388								_:      i+'.display',
389								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
390								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
391								filter: filter !== null ? i+'.@data-'+filter : undefined
392							};
393							col._isArrayHost = true;
394			
395							_fnColumnOptions( oSettings, i );
396						}
397					}
398				} );
399			}
400			
401			var features = oSettings.oFeatures;
402			var loadedInit = function () {
403				/*
404				 * Sorting
405				 * @todo For modularisation (1.11) this needs to do into a sort start up handler
406				 */
407			
408				// If aaSorting is not defined, then we use the first indicator in asSorting
409				// in case that has been altered, so the default sort reflects that option
410				if ( oInit.aaSorting === undefined ) {
411					var sorting = oSettings.aaSorting;
412					for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
413						sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
414					}
415				}
416			
417				/* Do a first pass on the sorting classes (allows any size changes to be taken into
418				 * account, and also will apply sorting disabled classes if disabled
419				 */
420				_fnSortingClasses( oSettings );
421			
422				_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
423					if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
424						_fnSortingClasses( oSettings );
425					}
426				} );
427			
428			
429				/*
430				 * Final init
431				 * Cache the header, body and footer as required, creating them if needed
432				 */
433				var caption = $this.children('caption');
434			
435				if ( oSettings.caption ) {
436					if ( caption.length === 0 ) {
437						caption = $('<caption/>').appendTo( $this );
438					}
439			
440					caption.html( oSettings.caption );
441				}
442			
443				// Store the caption side, so we can remove the element from the document
444				// when creating the element
445				if (caption.length) {
446					caption[0]._captionSide = caption.css('caption-side');
447					oSettings.captionNode = caption[0];
448				}
449			
450				if ( thead.length === 0 ) {
451					thead = $('<thead/>').appendTo($this);
452				}
453				oSettings.nTHead = thead[0];
454				$('tr', thead).addClass(oClasses.thead.row);
455			
456				var tbody = $this.children('tbody');
457				if ( tbody.length === 0 ) {
458					tbody = $('<tbody/>').insertAfter(thead);
459				}
460				oSettings.nTBody = tbody[0];
461			
462				var tfoot = $this.children('tfoot');
463				if ( tfoot.length === 0 ) {
464					// If we are a scrolling table, and no footer has been given, then we need to create
465					// a tfoot element for the caption element to be appended to
466					tfoot = $('<tfoot/>').appendTo($this);
467				}
468				oSettings.nTFoot = tfoot[0];
469				$('tr', tfoot).addClass(oClasses.tfoot.row);
470			
471				// Check if there is data passing into the constructor
472				if ( oInit.aaData ) {
473					for ( i=0 ; i<oInit.aaData.length ; i++ ) {
474						_fnAddData( oSettings, oInit.aaData[ i ] );
475					}
476				}
477				else if ( _fnDataSource( oSettings ) == 'dom' ) {
478					// Grab the data from the page
479					_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
480				}
481			
482				/* Copy the data index array */
483				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
484			
485				/* Initialisation complete - table can be drawn */
486				oSettings.bInitialised = true;
487			
488				/* Check if we need to initialise the table (it might not have been handed off to the
489				 * language processor)
490				 */
491				if ( bInitHandedOff === false ) {
492					_fnInitialise( oSettings );
493				}
494			};
495			
496			/* Must be done after everything which can be overridden by the state saving! */
497			_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState );
498			
499			if ( oInit.bStateSave )
500			{
501				features.bStateSave = true;
502				_fnLoadState( oSettings, oInit, loadedInit );
503			}
504			else {
505				loadedInit();
506			}
507			
508		} );
509		_that = null;
510		return this;
511	};
512	
513	
514	
515	/**
516	 * DataTables extensions
517	 * 
518	 * This namespace acts as a collection area for plug-ins that can be used to
519	 * extend DataTables capabilities. Indeed many of the build in methods
520	 * use this method to provide their own capabilities (sorting methods for
521	 * example).
522	 *
523	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
524	 * reasons
525	 *
526	 *  @namespace
527	 */
528	DataTable.ext = _ext = {
529		/**
530		 * Buttons. For use with the Buttons extension for DataTables. This is
531		 * defined here so other extensions can define buttons regardless of load
532		 * order. It is _not_ used by DataTables core.
533		 *
534		 *  @type object
535		 *  @default {}
536		 */
537		buttons: {},
538	
539	
540		/**
541		 * Element class names
542		 *
543		 *  @type object
544		 *  @default {}
545		 */
546		classes: {},
547	
548	
549		/**
550		 * DataTables build type (expanded by the download builder)
551		 *
552		 *  @type string
553		 */
554		builder: "-source-",
555	
556	
557		/**
558		 * Error reporting.
559		 * 
560		 * How should DataTables report an error. Can take the value 'alert',
561		 * 'throw', 'none' or a function.
562		 *
563		 *  @type string|function
564		 *  @default alert
565		 */
566		errMode: "alert",
567	
568	
569		/**
570		 * Legacy so v1 plug-ins don't throw js errors on load
571		 */
572		feature: [],
573	
574		/**
575		 * Feature plug-ins.
576		 * 
577		 * This is an object of callbacks which provide the features for DataTables
578		 * to be initialised via the `layout` option.
579		 */
580		features: {},
581	
582	
583		/**
584		 * Row searching.
585		 * 
586		 * This method of searching is complimentary to the default type based
587		 * searching, and a lot more comprehensive as it allows you complete control
588		 * over the searching logic. Each element in this array is a function
589		 * (parameters described below) that is called for every row in the table,
590		 * and your logic decides if it should be included in the searching data set
591		 * or not.
592		 *
593		 * Searching functions have the following input parameters:
594		 *
595		 * 1. `{object}` DataTables settings object: see
596		 *    {@link DataTable.models.oSettings}
597		 * 2. `{array|object}` Data for the row to be processed (same as the
598		 *    original format that was passed in as the data source, or an array
599		 *    from a DOM data source
600		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
601		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
602		 *
603		 * And the following return is expected:
604		 *
605		 * * {boolean} Include the row in the searched result set (true) or not
606		 *   (false)
607		 *
608		 * Note that as with the main search ability in DataTables, technically this
609		 * is "filtering", since it is subtractive. However, for consistency in
610		 * naming we call it searching here.
611		 *
612		 *  @type array
613		 *  @default []
614		 *
615		 *  @example
616		 *    // The following example shows custom search being applied to the
617		 *    // fourth column (i.e. the data[3] index) based on two input values
618		 *    // from the end-user, matching the data in a certain range.
619		 *    $.fn.dataTable.ext.search.push(
620		 *      function( settings, data, dataIndex ) {
621		 *        var min = document.getElementById('min').value * 1;
622		 *        var max = document.getElementById('max').value * 1;
623		 *        var version = data[3] == "-" ? 0 : data[3]*1;
624		 *
625		 *        if ( min == "" && max == "" ) {
626		 *          return true;
627		 *        }
628		 *        else if ( min == "" && version < max ) {
629		 *          return true;
630		 *        }
631		 *        else if ( min < version && "" == max ) {
632		 *          return true;
633		 *        }
634		 *        else if ( min < version && version < max ) {
635		 *          return true;
636		 *        }
637		 *        return false;
638		 *      }
639		 *    );
640		 */
641		search: [],
642	
643	
644		/**
645		 * Selector extensions
646		 *
647		 * The `selector` option can be used to extend the options available for the
648		 * selector modifier options (`selector-modifier` object data type) that
649		 * each of the three built in selector types offer (row, column and cell +
650		 * their plural counterparts). For example the Select extension uses this
651		 * mechanism to provide an option to select only rows, columns and cells
652		 * that have been marked as selected by the end user (`{selected: true}`),
653		 * which can be used in conjunction with the existing built in selector
654		 * options.
655		 *
656		 * Each property is an array to which functions can be pushed. The functions
657		 * take three attributes:
658		 *
659		 * * Settings object for the host table
660		 * * Options object (`selector-modifier` object type)
661		 * * Array of selected item indexes
662		 *
663		 * The return is an array of the resulting item indexes after the custom
664		 * selector has been applied.
665		 *
666		 *  @type object
667		 */
668		selector: {
669			cell: [],
670			column: [],
671			row: []
672		},
673	
674	
675		/**
676		 * Legacy configuration options. Enable and disable legacy options that
677		 * are available in DataTables.
678		 *
679		 *  @type object
680		 */
681		legacy: {
682			/**
683			 * Enable / disable DataTables 1.9 compatible server-side processing
684			 * requests
685			 *
686			 *  @type boolean
687			 *  @default null
688			 */
689			ajax: null
690		},
691	
692	
693		/**
694		 * Pagination plug-in methods.
695		 * 
696		 * Each entry in this object is a function and defines which buttons should
697		 * be shown by the pagination rendering method that is used for the table:
698		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
699		 * buttons are displayed in the document, while the functions here tell it
700		 * what buttons to display. This is done by returning an array of button
701		 * descriptions (what each button will do).
702		 *
703		 * Pagination types (the four built in options and any additional plug-in
704		 * options defined here) can be used through the `paginationType`
705		 * initialisation parameter.
706		 *
707		 * The functions defined take two parameters:
708		 *
709		 * 1. `{int} page` The current page index
710		 * 2. `{int} pages` The number of pages in the table
711		 *
712		 * Each function is expected to return an array where each element of the
713		 * array can be one of:
714		 *
715		 * * `first` - Jump to first page when activated
716		 * * `last` - Jump to last page when activated
717		 * * `previous` - Show previous page when activated
718		 * * `next` - Show next page when activated
719		 * * `{int}` - Show page of the index given
720		 * * `{array}` - A nested array containing the above elements to add a
721		 *   containing 'DIV' element (might be useful for styling).
722		 *
723		 * Note that DataTables v1.9- used this object slightly differently whereby
724		 * an object with two functions would be defined for each plug-in. That
725		 * ability is still supported by DataTables 1.10+ to provide backwards
726		 * compatibility, but this option of use is now decremented and no longer
727		 * documented in DataTables 1.10+.
728		 *
729		 *  @type object
730		 *  @default {}
731		 *
732		 *  @example
733		 *    // Show previous, next and current page buttons only
734		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
735		 *      return [ 'previous', page, 'next' ];
736		 *    };
737		 */
738		pager: {},
739	
740	
741		renderer: {
742			pageButton: {},
743			header: {}
744		},
745	
746	
747		/**
748		 * Ordering plug-ins - custom data source
749		 * 
750		 * The extension options for ordering of data available here is complimentary
751		 * to the default type based ordering that DataTables typically uses. It
752		 * allows much greater control over the the data that is being used to
753		 * order a column, but is necessarily therefore more complex.
754		 * 
755		 * This type of ordering is useful if you want to do ordering based on data
756		 * live from the DOM (for example the contents of an 'input' element) rather
757		 * than just the static string that DataTables knows of.
758		 * 
759		 * The way these plug-ins work is that you create an array of the values you
760		 * wish to be ordering for the column in question and then return that
761		 * array. The data in the array much be in the index order of the rows in
762		 * the table (not the currently ordering order!). Which order data gathering
763		 * function is run here depends on the `dt-init columns.orderDataType`
764		 * parameter that is used for the column (if any).
765		 *
766		 * The functions defined take two parameters:
767		 *
768		 * 1. `{object}` DataTables settings object: see
769		 *    {@link DataTable.models.oSettings}
770		 * 2. `{int}` Target column index
771		 *
772		 * Each function is expected to return an array:
773		 *
774		 * * `{array}` Data for the column to be ordering upon
775		 *
776		 *  @type array
777		 *
778		 *  @example
779		 *    // Ordering using `input` node values
780		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
781		 *    {
782		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
783		 *        return $('input', td).val();
784		 *      } );
785		 *    }
786		 */
787		order: {},
788	
789	
790		/**
791		 * Type based plug-ins.
792		 *
793		 * Each column in DataTables has a type assigned to it, either by automatic
794		 * detection or by direct assignment using the `type` option for the column.
795		 * The type of a column will effect how it is ordering and search (plug-ins
796		 * can also make use of the column type if required).
797		 *
798		 * @namespace
799		 */
800		type: {
801			/**
802			 * Automatic column class assignment
803			 */
804			className: {},
805	
806			/**
807			 * Type detection functions.
808			 *
809			 * The functions defined in this object are used to automatically detect
810			 * a column's type, making initialisation of DataTables super easy, even
811			 * when complex data is in the table.
812			 *
813			 * The functions defined take two parameters:
814			 *
815		     *  1. `{*}` Data from the column cell to be analysed
816		     *  2. `{settings}` DataTables settings object. This can be used to
817		     *     perform context specific type detection - for example detection
818		     *     based on language settings such as using a comma for a decimal
819		     *     place. Generally speaking the options from the settings will not
820		     *     be required
821			 *
822			 * Each function is expected to return:
823			 *
824			 * * `{string|null}` Data type detected, or null if unknown (and thus
825			 *   pass it on to the other type detection functions.
826			 *
827			 *  @type array
828			 *
829			 *  @example
830			 *    // Currency type detection plug-in:
831			 *    $.fn.dataTable.ext.type.detect.push(
832			 *      function ( data, settings ) {
833			 *        // Check the numeric part
834			 *        if ( ! data.substring(1).match(/[0-9]/) ) {
835			 *          return null;
836			 *        }
837			 *
838			 *        // Check prefixed by currency
839			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
840			 *          return 'currency';
841			 *        }
842			 *        return null;
843			 *      }
844			 *    );
845			 */
846			detect: [],
847	
848			/**
849			 * Automatic renderer assignment
850			 */
851			render: {},
852	
853	
854			/**
855			 * Type based search formatting.
856			 *
857			 * The type based searching functions can be used to pre-format the
858			 * data to be search on. For example, it can be used to strip HTML
859			 * tags or to de-format telephone numbers for numeric only searching.
860			 *
861			 * Note that is a search is not defined for a column of a given type,
862			 * no search formatting will be performed.
863			 * 
864			 * Pre-processing of searching data plug-ins - When you assign the sType
865			 * for a column (or have it automatically detected for you by DataTables
866			 * or a type detection plug-in), you will typically be using this for
867			 * custom sorting, but it can also be used to provide custom searching
868			 * by allowing you to pre-processing the data and returning the data in
869			 * the format that should be searched upon. This is done by adding
870			 * functions this object with a parameter name which matches the sType
871			 * for that target column. This is the corollary of <i>afnSortData</i>
872			 * for searching data.
873			 *
874			 * The functions defined take a single parameter:
875			 *
876		     *  1. `{*}` Data from the column cell to be prepared for searching
877			 *
878			 * Each function is expected to return:
879			 *
880			 * * `{string|null}` Formatted string that will be used for the searching.
881			 *
882			 *  @type object
883			 *  @default {}
884			 *
885			 *  @example
886			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
887			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
888			 *    }
889			 */
890			search: {},
891	
892	
893			/**
894			 * Type based ordering.
895			 *
896			 * The column type tells DataTables what ordering to apply to the table
897			 * when a column is sorted upon. The order for each type that is defined,
898			 * is defined by the functions available in this object.
899			 *
900			 * Each ordering option can be described by three properties added to
901			 * this object:
902			 *
903			 * * `{type}-pre` - Pre-formatting function
904			 * * `{type}-asc` - Ascending order function
905			 * * `{type}-desc` - Descending order function
906			 *
907			 * All three can be used together, only `{type}-pre` or only
908			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
909			 * that only `{type}-pre` is used, as this provides the optimal
910			 * implementation in terms of speed, although the others are provided
911			 * for compatibility with existing Javascript sort functions.
912			 *
913			 * `{type}-pre`: Functions defined take a single parameter:
914			 *
915		     *  1. `{*}` Data from the column cell to be prepared for ordering
916			 *
917			 * And return:
918			 *
919			 * * `{*}` Data to be sorted upon
920			 *
921			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
922			 * functions, taking two parameters:
923			 *
924		     *  1. `{*}` Data to compare to the second parameter
925		     *  2. `{*}` Data to compare to the first parameter
926			 *
927			 * And returning:
928			 *
929			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
930			 *   than the second parameter, ===0 if the two parameters are equal and
931			 *   >0 if the first parameter should be sorted height than the second
932			 *   parameter.
933			 * 
934			 *  @type object
935			 *  @default {}
936			 *
937			 *  @example
938			 *    // Numeric ordering of formatted numbers with a pre-formatter
939			 *    $.extend( $.fn.dataTable.ext.type.order, {
940			 *      "string-pre": function(x) {
941			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
942			 *        return parseFloat( a );
943			 *      }
944			 *    } );
945			 *
946			 *  @example
947			 *    // Case-sensitive string ordering, with no pre-formatting method
948			 *    $.extend( $.fn.dataTable.ext.order, {
949			 *      "string-case-asc": function(x,y) {
950			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
951			 *      },
952			 *      "string-case-desc": function(x,y) {
953			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
954			 *      }
955			 *    } );
956			 */
957			order: {}
958		},
959	
960		/**
961		 * Unique DataTables instance counter
962		 *
963		 * @type int
964		 * @private
965		 */
966		_unique: 0,
967	
968	
969		//
970		// Depreciated
971		// The following properties are retained for backwards compatibility only.
972		// The should not be used in new projects and will be removed in a future
973		// version
974		//
975	
976		/**
977		 * Version check function.
978		 *  @type function
979		 *  @depreciated Since 1.10
980		 */
981		fnVersionCheck: DataTable.fnVersionCheck,
982	
983	
984		/**
985		 * Index for what 'this' index API functions should use
986		 *  @type int
987		 *  @deprecated Since v1.10
988		 */
989		iApiIndex: 0,
990	
991	
992		/**
993		 * Software version
994		 *  @type string
995		 *  @deprecated Since v1.10
996		 */
997		sVersion: DataTable.version
998	};
999	
1000	
1001	//
1002	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
1003	//
1004	$.extend( _ext, {
1005		afnFiltering: _ext.search,
1006		aTypes:       _ext.type.detect,
1007		ofnSearch:    _ext.type.search,
1008		oSort:        _ext.type.order,
1009		afnSortData:  _ext.order,
1010		aoFeatures:   _ext.feature,
1011		oStdClasses:  _ext.classes,
1012		oPagination:  _ext.pager
1013	} );
1014	
1015	
1016	$.extend( DataTable.ext.classes, {
1017		container: 'dt-container',
1018		empty: {
1019			row: 'dt-empty'
1020		},
1021		info: {
1022			container: 'dt-info'
1023		},
1024		length: {
1025			container: 'dt-length',
1026			select: 'dt-input'
1027		},
1028		order: {
1029			canAsc: 'dt-orderable-asc',
1030			canDesc: 'dt-orderable-desc',
1031			isAsc: 'dt-ordering-asc',
1032			isDesc: 'dt-ordering-desc',
1033			none: 'dt-orderable-none',
1034			position: 'sorting_'
1035		},
1036		processing: {
1037			container: 'dt-processing'
1038		},
1039		scrolling: {
1040			body: 'dt-scroll-body',
1041			container: 'dt-scroll',
1042			footer: {
1043				self: 'dt-scroll-foot',
1044				inner: 'dt-scroll-footInner'
1045			},
1046			header: {
1047				self: 'dt-scroll-head',
1048				inner: 'dt-scroll-headInner'
1049			}
1050		},
1051		search: {
1052			container: 'dt-search',
1053			input: 'dt-input'
1054		},
1055		table: 'dataTable',	
1056		tbody: {
1057			cell: '',
1058			row: ''
1059		},
1060		thead: {
1061			cell: '',
1062			row: ''
1063		},
1064		tfoot: {
1065			cell: '',
1066			row: ''
1067		},
1068		paging: {
1069			active: 'current',
1070			button: 'dt-paging-button',
1071			container: 'dt-paging',
1072			disabled: 'disabled'
1073		}
1074	} );
1075	
1076	
1077	/*
1078	 * It is useful to have variables which are scoped locally so only the
1079	 * DataTables functions can access them and they don't leak into global space.
1080	 * At the same time these functions are often useful over multiple files in the
1081	 * core and API, so we list, or at least document, all variables which are used
1082	 * by DataTables as private variables here. This also ensures that there is no
1083	 * clashing of variable names and that they can easily referenced for reuse.
1084	 */
1085	
1086	
1087	// Defined else where
1088	//  _selector_run
1089	//  _selector_opts
1090	//  _selector_row_indexes
1091	
1092	var _ext; // DataTable.ext
1093	var _Api; // DataTable.Api
1094	var _api_register; // DataTable.Api.register
1095	var _api_registerPlural; // DataTable.Api.registerPlural
1096	
1097	var _re_dic = {};
1098	var _re_new_lines = /[\r\n\u2028]/g;
1099	var _re_html = /<([^>]*>)/g;
1100	var _max_str_len = Math.pow(2, 28);
1101	
1102	// This is not strict ISO8601 - Date.parse() is quite lax, although
1103	// implementations differ between browsers.
1104	var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
1105	
1106	// Escape regular expression special characters
1107	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1108	
1109	// https://en.wikipedia.org/wiki/Foreign_exchange_market
1110	// - \u20BD - Russian ruble.
1111	// - \u20a9 - South Korean Won
1112	// - \u20BA - Turkish Lira
1113	// - \u20B9 - Indian Rupee
1114	// - R - Brazil (R$) and South Africa
1115	// - fr - Swiss Franc
1116	// - kr - Swedish krona, Norwegian krone and Danish krone
1117	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1118	// - Ƀ - Bitcoin
1119	// - Ξ - Ethereum
1120	//   standards as thousands separators.
1121	var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1122	
1123	
1124	var _empty = function ( d ) {
1125		return !d || d === true || d === '-' ? true : false;
1126	};
1127	
1128	
1129	var _intVal = function ( s ) {
1130		var integer = parseInt( s, 10 );
1131		return !isNaN(integer) && isFinite(s) ? integer : null;
1132	};
1133	
1134	// Convert from a formatted number with characters other than `.` as the
1135	// decimal place, to a Javascript number
1136	var _numToDecimal = function ( num, decimalPoint ) {
1137		// Cache created regular expressions for speed as this function is called often
1138		if ( ! _re_dic[ decimalPoint ] ) {
1139			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1140		}
1141		return typeof num === 'string' && decimalPoint !== '.' ?
1142			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1143			num;
1144	};
1145	
1146	
1147	var _isNumber = function ( d, decimalPoint, formatted ) {
1148		var type = typeof d;
1149		var strType = type === 'string';
1150	
1151		if ( type === 'number' || type === 'bigint') {
1152			return true;
1153		}
1154	
1155		// If empty return immediately so there must be a number if it is a
1156		// formatted string (this stops the string "k", or "kr", etc being detected
1157		// as a formatted number for currency
1158		if ( _empty( d ) ) {
1159			return true;
1160		}
1161	
1162		if ( decimalPoint && strType ) {
1163			d = _numToDecimal( d, decimalPoint );
1164		}
1165	
1166		if ( formatted && strType ) {
1167			d = d.replace( _re_formatted_numeric, '' );
1168		}
1169	
1170		return !isNaN( parseFloat(d) ) && isFinite( d );
1171	};
1172	
1173	
1174	// A string without HTML in it can be considered to be HTML still
1175	var _isHtml = function ( d ) {
1176		return _empty( d ) || typeof d === 'string';
1177	};
1178	
1179	// Is a string a number surrounded by HTML?
1180	var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1181		if ( _empty( d ) ) {
1182			return true;
1183		}
1184	
1185		// input and select strings mean that this isn't just a number
1186		if (typeof d === 'string' && d.match(/<(input|select)/i)) {
1187			return null;
1188		}
1189	
1190		var html = _isHtml( d );
1191		return ! html ?
1192			null :
1193			_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1194				true :
1195				null;
1196	};
1197	
1198	
1199	var _pluck = function ( a, prop, prop2 ) {
1200		var out = [];
1201		var i=0, ien=a.length;
1202	
1203		// Could have the test in the loop for slightly smaller code, but speed
1204		// is essential here
1205		if ( prop2 !== undefined ) {
1206			for ( ; i<ien ; i++ ) {
1207				if ( a[i] && a[i][ prop ] ) {
1208					out.push( a[i][ prop ][ prop2 ] );
1209				}
1210			}
1211		}
1212		else {
1213			for ( ; i<ien ; i++ ) {
1214				if ( a[i] ) {
1215					out.push( a[i][ prop ] );
1216				}
1217			}
1218		}
1219	
1220		return out;
1221	};
1222	
1223	
1224	// Basically the same as _pluck, but rather than looping over `a` we use `order`
1225	// as the indexes to pick from `a`
1226	var _pluck_order = function ( a, order, prop, prop2 )
1227	{
1228		var out = [];
1229		var i=0, ien=order.length;
1230	
1231		// Could have the test in the loop for slightly smaller code, but speed
1232		// is essential here
1233		if ( prop2 !== undefined ) {
1234			for ( ; i<ien ; i++ ) {
1235				if ( a[ order[i] ][ prop ] ) {
1236					out.push( a[ order[i] ][ prop ][ prop2 ] );
1237				}
1238			}
1239		}
1240		else {
1241			for ( ; i<ien ; i++ ) {
1242				if ( a[ order[i] ] ) {
1243					out.push( a[ order[i] ][ prop ] );
1244				}
1245			}
1246		}
1247	
1248		return out;
1249	};
1250	
1251	
1252	var _range = function ( len, start )
1253	{
1254		var out = [];
1255		var end;
1256	
1257		if ( start === undefined ) {
1258			start = 0;
1259			end = len;
1260		}
1261		else {
1262			end = start;
1263			start = len;
1264		}
1265	
1266		for ( var i=start ; i<end ; i++ ) {
1267			out.push( i );
1268		}
1269	
1270		return out;
1271	};
1272	
1273	
1274	var _removeEmpty = function ( a )
1275	{
1276		var out = [];
1277	
1278		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1279			if ( a[i] ) { // careful - will remove all falsy values!
1280				out.push( a[i] );
1281			}
1282		}
1283	
1284		return out;
1285	};
1286	
1287	// Replaceable function in api.util
1288	var _stripHtml = function (input) {
1289		// Irrelevant check to workaround CodeQL's false positive on the regex
1290		if (input.length > _max_str_len) {
1291			throw new Error('Exceeded max str len');
1292		}
1293	
1294		var previous;
1295	
1296		input = input.replace(_re_html, ''); // Complete tags
1297	
1298		// Safety for incomplete script tag - use do / while to ensure that
1299		// we get all instances
1300		do {
1301			previous = input;
1302			input = input.replace(/<script/i, '');
1303		} while (input !== previous);
1304	
1305		return previous;
1306	};
1307	
1308	// Replaceable function in api.util
1309	var _escapeHtml = function ( d ) {
1310		if (Array.isArray(d)) {
1311			d = d.join(',');
1312		}
1313	
1314		return typeof d === 'string' ?
1315			d
1316				.replace(/&/g, '&amp;')
1317				.replace(/</g, '&lt;')
1318				.replace(/>/g, '&gt;')
1319				.replace(/"/g, '&quot;') :
1320			d;
1321	};
1322	
1323	// Remove diacritics from a string by decomposing it and then removing
1324	// non-ascii characters
1325	var _normalize = function (str, both) {
1326		if (typeof str !== 'string') {
1327			return str;
1328		}
1329	
1330		// It is faster to just run `normalize` than it is to check if
1331		// we need to with a regex!
1332		var res = str.normalize("NFD");
1333	
1334		// Equally, here we check if a regex is needed or not
1335		return res.length !== str.length
1336			? (both === true ? str + ' ' : '' ) + res.replace(/[\u0300-\u036f]/g, "")
1337			: res;
1338	}
1339	
1340	/**
1341	 * Determine if all values in the array are unique. This means we can short
1342	 * cut the _unique method at the cost of a single loop. A sorted array is used
1343	 * to easily check the values.
1344	 *
1345	 * @param  {array} src Source array
1346	 * @return {boolean} true if all unique, false otherwise
1347	 * @ignore
1348	 */
1349	var _areAllUnique = function ( src ) {
1350		if ( src.length < 2 ) {
1351			return true;
1352		}
1353	
1354		var sorted = src.slice().sort();
1355		var last = sorted[0];
1356	
1357		for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1358			if ( sorted[i] === last ) {
1359				return false;
vendor: 17,993 bytes, lines 1360-2019
1360			}
1361	
1362			last = sorted[i];
1363		}
1364	
1365		return true;
1366	};
1367	
1368	
1369	/**
1370	 * Find the unique elements in a source array.
1371	 *
1372	 * @param  {array} src Source array
1373	 * @return {array} Array of unique items
1374	 * @ignore
1375	 */
1376	var _unique = function ( src )
1377	{
1378		if (Array.from && Set) {
1379			return Array.from(new Set(src));
1380		}
1381	
1382		if ( _areAllUnique( src ) ) {
1383			return src.slice();
1384		}
1385	
1386		// A faster unique method is to use object keys to identify used values,
1387		// but this doesn't work with arrays or objects, which we must also
1388		// consider. See jsperf.app/compare-array-unique-versions/4 for more
1389		// information.
1390		var
1391			out = [],
1392			val,
1393			i, ien=src.length,
1394			j, k=0;
1395	
1396		again: for ( i=0 ; i<ien ; i++ ) {
1397			val = src[i];
1398	
1399			for ( j=0 ; j<k ; j++ ) {
1400				if ( out[j] === val ) {
1401					continue again;
1402				}
1403			}
1404	
1405			out.push( val );
1406			k++;
1407		}
1408	
1409		return out;
1410	};
1411	
1412	// Surprisingly this is faster than [].concat.apply
1413	// https://jsperf.com/flatten-an-array-loop-vs-reduce/2
1414	var _flatten = function (out, val) {
1415		if (Array.isArray(val)) {
1416			for (var i=0 ; i<val.length ; i++) {
1417				_flatten(out, val[i]);
1418			}
1419		}
1420		else {
1421			out.push(val);
1422		}
1423	
1424		return out;
1425	}
1426	
1427	// Similar to jQuery's addClass, but use classList.add
1428	function _addClass(el, name) {
1429		if (name) {
1430			name.split(' ').forEach(function (n) {
1431				if (n) {
1432					// `add` does deduplication, so no need to check `contains`
1433					el.classList.add(n);
1434				}
1435			});
1436		}
1437	}
1438	
1439	/**
1440	 * DataTables utility methods
1441	 * 
1442	 * This namespace provides helper methods that DataTables uses internally to
1443	 * create a DataTable, but which are not exclusively used only for DataTables.
1444	 * These methods can be used by extension authors to save the duplication of
1445	 * code.
1446	 *
1447	 *  @namespace
1448	 */
1449	DataTable.util = {
1450		/**
1451		 * Return a string with diacritic characters decomposed
1452		 * @param {*} mixed Function or string to normalize
1453		 * @param {*} both Return original string and the normalized string
1454		 * @returns String or undefined
1455		 */
1456		diacritics: function (mixed, both) {
1457			var type = typeof mixed;
1458	
1459			if (type !== 'function') {
1460				return _normalize(mixed, both);
1461			}
1462			_normalize = mixed;
1463		},
1464	
1465		/**
1466		 * Debounce a function
1467		 *
1468		 * @param {function} fn Function to be called
1469		 * @param {integer} freq Call frequency in mS
1470		 * @return {function} Wrapped function
1471		 */
1472		debounce: function ( fn, timeout ) {
1473			var timer;
1474	
1475			return function () {
1476				var that = this;
1477				var args = arguments;
1478	
1479				clearTimeout(timer);
1480	
1481				timer = setTimeout( function () {
1482					fn.apply(that, args);
1483				}, timeout || 250 );
1484			};
1485		},
1486	
1487		/**
1488		 * Throttle the calls to a function. Arguments and context are maintained
1489		 * for the throttled function.
1490		 *
1491		 * @param {function} fn Function to be called
1492		 * @param {integer} freq Call frequency in mS
1493		 * @return {function} Wrapped function
1494		 */
1495		throttle: function ( fn, freq ) {
1496			var
1497				frequency = freq !== undefined ? freq : 200,
1498				last,
1499				timer;
1500	
1501			return function () {
1502				var
1503					that = this,
1504					now  = +new Date(),
1505					args = arguments;
1506	
1507				if ( last && now < last + frequency ) {
1508					clearTimeout( timer );
1509	
1510					timer = setTimeout( function () {
1511						last = undefined;
1512						fn.apply( that, args );
1513					}, frequency );
1514				}
1515				else {
1516					last = now;
1517					fn.apply( that, args );
1518				}
1519			};
1520		},
1521	
1522		/**
1523		 * Escape a string such that it can be used in a regular expression
1524		 *
1525		 *  @param {string} val string to escape
1526		 *  @returns {string} escaped string
1527		 */
1528		escapeRegex: function ( val ) {
1529			return val.replace( _re_escape_regex, '\\$1' );
1530		},
1531	
1532		/**
1533		 * Create a function that will write to a nested object or array
1534		 * @param {*} source JSON notation string
1535		 * @returns Write function
1536		 */
1537		set: function ( source ) {
1538			if ( $.isPlainObject( source ) ) {
1539				/* Unlike get, only the underscore (global) option is used for for
1540				 * setting data since we don't know the type here. This is why an object
1541				 * option is not documented for `mData` (which is read/write), but it is
1542				 * for `mRender` which is read only.
1543				 */
1544				return DataTable.util.set( source._ );
1545			}
1546			else if ( source === null ) {
1547				// Nothing to do when the data source is null
1548				return function () {};
1549			}
1550			else if ( typeof source === 'function' ) {
1551				return function (data, val, meta) {
1552					source( data, 'set', val, meta );
1553				};
1554			}
1555			else if (
1556				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1557				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1558			) {
1559				// Like the get, we need to get data from a nested object
1560				var setData = function (data, val, src) {
1561					var a = _fnSplitObjNotation( src ), b;
1562					var aLast = a[a.length-1];
1563					var arrayNotation, funcNotation, o, innerSrc;
1564		
1565					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {
1566						// Protect against prototype pollution
1567						if (a[i] === '__proto__' || a[i] === 'constructor') {
1568							throw new Error('Cannot set prototype values');
1569						}
1570		
1571						// Check if we are dealing with an array notation request
1572						arrayNotation = a[i].match(__reArray);
1573						funcNotation = a[i].match(__reFn);
1574		
1575						if ( arrayNotation ) {
1576							a[i] = a[i].replace(__reArray, '');
1577							data[ a[i] ] = [];
1578		
1579							// Get the remainder of the nested object to set so we can recurse
1580							b = a.slice();
1581							b.splice( 0, i+1 );
1582							innerSrc = b.join('.');
1583		
1584							// Traverse each entry in the array setting the properties requested
1585							if ( Array.isArray( val ) ) {
1586								for ( var j=0, jLen=val.length ; j<jLen ; j++ ) {
1587									o = {};
1588									setData( o, val[j], innerSrc );
1589									data[ a[i] ].push( o );
1590								}
1591							}
1592							else {
1593								// We've been asked to save data to an array, but it
1594								// isn't array data to be saved. Best that can be done
1595								// is to just save the value.
1596								data[ a[i] ] = val;
1597							}
1598		
1599							// The inner call to setData has already traversed through the remainder
1600							// of the source and has set the data, thus we can exit here
1601							return;
1602						}
1603						else if ( funcNotation ) {
1604							// Function call
1605							a[i] = a[i].replace(__reFn, '');
1606							data = data[ a[i] ]( val );
1607						}
1608		
1609						// If the nested object doesn't currently exist - since we are
1610						// trying to set the value - create it
1611						if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {
1612							data[ a[i] ] = {};
1613						}
1614						data = data[ a[i] ];
1615					}
1616		
1617					// Last item in the input - i.e, the actual set
1618					if ( aLast.match(__reFn ) ) {
1619						// Function call
1620						data = data[ aLast.replace(__reFn, '') ]( val );
1621					}
1622					else {
1623						// If array notation is used, we just want to strip it and use the property name
1624						// and assign the value. If it isn't used, then we get the result we want anyway
1625						data[ aLast.replace(__reArray, '') ] = val;
1626					}
1627				};
1628		
1629				return function (data, val) { // meta is also passed in, but not used
1630					return setData( data, val, source );
1631				};
1632			}
1633			else {
1634				// Array or flat object mapping
1635				return function (data, val) { // meta is also passed in, but not used
1636					data[source] = val;
1637				};
1638			}
1639		},
1640	
1641		/**
1642		 * Create a function that will read nested objects from arrays, based on JSON notation
1643		 * @param {*} source JSON notation string
1644		 * @returns Value read
1645		 */
1646		get: function ( source ) {
1647			if ( $.isPlainObject( source ) ) {
1648				// Build an object of get functions, and wrap them in a single call
1649				var o = {};
1650				$.each( source, function (key, val) {
1651					if ( val ) {
1652						o[key] = DataTable.util.get( val );
1653					}
1654				} );
1655		
1656				return function (data, type, row, meta) {
1657					var t = o[type] || o._;
1658					return t !== undefined ?
1659						t(data, type, row, meta) :
1660						data;
1661				};
1662			}
1663			else if ( source === null ) {
1664				// Give an empty string for rendering / sorting etc
1665				return function (data) { // type, row and meta also passed, but not used
1666					return data;
1667				};
1668			}
1669			else if ( typeof source === 'function' ) {
1670				return function (data, type, row, meta) {
1671					return source( data, type, row, meta );
1672				};
1673			}
1674			else if (
1675				typeof source === 'string' && (source.indexOf('.') !== -1 ||
1676				source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1677			) {
1678				/* If there is a . in the source string then the data source is in a
1679				 * nested object so we loop over the data for each level to get the next
1680				 * level down. On each loop we test for undefined, and if found immediately
1681				 * return. This allows entire objects to be missing and sDefaultContent to
1682				 * be used if defined, rather than throwing an error
1683				 */
1684				var fetchData = function (data, type, src) {
1685					var arrayNotation, funcNotation, out, innerSrc;
1686		
1687					if ( src !== "" ) {
1688						var a = _fnSplitObjNotation( src );
1689		
1690						for ( var i=0, iLen=a.length ; i<iLen ; i++ ) {
1691							// Check if we are dealing with special notation
1692							arrayNotation = a[i].match(__reArray);
1693							funcNotation = a[i].match(__reFn);
1694		
1695							if ( arrayNotation ) {
1696								// Array notation
1697								a[i] = a[i].replace(__reArray, '');
1698		
1699								// Condition allows simply [] to be passed in
1700								if ( a[i] !== "" ) {
1701									data = data[ a[i] ];
1702								}
1703								out = [];
1704		
1705								// Get the remainder of the nested object to get
1706								a.splice( 0, i+1 );
1707								innerSrc = a.join('.');
1708		
1709								// Traverse each entry in the array getting the properties requested
1710								if ( Array.isArray( data ) ) {
1711									for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1712										out.push( fetchData( data[j], type, innerSrc ) );
1713									}
1714								}
1715		
1716								// If a string is given in between the array notation indicators, that
1717								// is used to join the strings together, otherwise an array is returned
1718								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1719								data = (join==="") ? out : out.join(join);
1720		
1721								// The inner call to fetchData has already traversed through the remainder
1722								// of the source requested, so we exit from the loop
1723								break;
1724							}
1725							else if ( funcNotation ) {
1726								// Function call
1727								a[i] = a[i].replace(__reFn, '');
1728								data = data[ a[i] ]();
1729								continue;
1730							}
1731		
1732							if (data === null || data[ a[i] ] === null) {
1733								return null;
1734							}
1735							else if ( data === undefined || data[ a[i] ] === undefined ) {
1736								return undefined;
1737							}
1738	
1739							data = data[ a[i] ];
1740						}
1741					}
1742		
1743					return data;
1744				};
1745		
1746				return function (data, type) { // row and meta also passed, but not used
1747					return fetchData( data, type, source );
1748				};
1749			}
1750			else {
1751				// Array or flat object mapping
1752				return function (data) { // row and meta also passed, but not used
1753					return data[source];
1754				};
1755			}
1756		},
1757	
1758		stripHtml: function (mixed) {
1759			var type = typeof mixed;
1760	
1761			if (type === 'function') {
1762				_stripHtml = mixed;
1763				return;
1764			}
1765			else if (type === 'string') {
1766				return _stripHtml(mixed);
1767			}
1768			return mixed;
1769		},
1770	
1771		escapeHtml: function (mixed) {
1772			var type = typeof mixed;
1773	
1774			if (type === 'function') {
1775				_escapeHtml = mixed;
1776				return;
1777			}
1778			else if (type === 'string' || Array.isArray(mixed)) {
1779				return _escapeHtml(mixed);
1780			}
1781			return mixed;
1782		},
1783	
1784		unique: _unique
1785	};
1786	
1787	
1788	
1789	/**
1790	 * Create a mapping object that allows camel case parameters to be looked up
1791	 * for their Hungarian counterparts. The mapping is stored in a private
1792	 * parameter called `_hungarianMap` which can be accessed on the source object.
1793	 *  @param {object} o
1794	 *  @memberof DataTable#oApi
1795	 */
1796	function _fnHungarianMap ( o )
1797	{
1798		var
1799			hungarian = 'a aa ai ao as b fn i m o s ',
1800			match,
1801			newKey,
1802			map = {};
1803	
1804		$.each( o, function (key) {
1805			match = key.match(/^([^A-Z]+?)([A-Z])/);
1806	
1807			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1808			{
1809				newKey = key.replace( match[0], match[2].toLowerCase() );
1810				map[ newKey ] = key;
1811	
1812				if ( match[1] === 'o' )
1813				{
1814					_fnHungarianMap( o[key] );
1815				}
1816			}
1817		} );
1818	
1819		o._hungarianMap = map;
1820	}
1821	
1822	
1823	/**
1824	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1825	 * created by _fnHungarianMap.
1826	 *  @param {object} src The model object which holds all parameters that can be
1827	 *    mapped.
1828	 *  @param {object} user The object to convert from camel case to Hungarian.
1829	 *  @param {boolean} force When set to `true`, properties which already have a
1830	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
1831	 *    won't be.
1832	 *  @memberof DataTable#oApi
1833	 */
1834	function _fnCamelToHungarian ( src, user, force )
1835	{
1836		if ( ! src._hungarianMap ) {
1837			_fnHungarianMap( src );
1838		}
1839	
1840		var hungarianKey;
1841	
1842		$.each( user, function (key) {
1843			hungarianKey = src._hungarianMap[ key ];
1844	
1845			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1846			{
1847				// For objects, we need to buzz down into the object to copy parameters
1848				if ( hungarianKey.charAt(0) === 'o' )
1849				{
1850					// Copy the camelCase options over to the hungarian
1851					if ( ! user[ hungarianKey ] ) {
1852						user[ hungarianKey ] = {};
1853					}
1854					$.extend( true, user[hungarianKey], user[key] );
1855	
1856					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1857				}
1858				else {
1859					user[hungarianKey] = user[ key ];
1860				}
1861			}
1862		} );
1863	}
1864	
1865	/**
1866	 * Map one parameter onto another
1867	 *  @param {object} o Object to map
1868	 *  @param {*} knew The new parameter name
1869	 *  @param {*} old The old parameter name
1870	 */
1871	var _fnCompatMap = function ( o, knew, old ) {
1872		if ( o[ knew ] !== undefined ) {
1873			o[ old ] = o[ knew ];
1874		}
1875	};
1876	
1877	
1878	/**
1879	 * Provide backwards compatibility for the main DT options. Note that the new
1880	 * options are mapped onto the old parameters, so this is an external interface
1881	 * change only.
1882	 *  @param {object} init Object to map
1883	 */
1884	function _fnCompatOpts ( init )
1885	{
1886		_fnCompatMap( init, 'ordering',      'bSort' );
1887		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
1888		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
1889		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1890		_fnCompatMap( init, 'order',         'aaSorting' );
1891		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
1892		_fnCompatMap( init, 'paging',        'bPaginate' );
1893		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
1894		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
1895		_fnCompatMap( init, 'searching',     'bFilter' );
1896	
1897		// Boolean initialisation of x-scrolling
1898		if ( typeof init.sScrollX === 'boolean' ) {
1899			init.sScrollX = init.sScrollX ? '100%' : '';
1900		}
1901		if ( typeof init.scrollX === 'boolean' ) {
1902			init.scrollX = init.scrollX ? '100%' : '';
1903		}
1904	
1905		// Column search objects are in an array, so it needs to be converted
1906		// element by element
1907		var searchCols = init.aoSearchCols;
1908	
1909		if ( searchCols ) {
1910			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1911				if ( searchCols[i] ) {
1912					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1913				}
1914			}
1915		}
1916	
1917		// Enable search delay if server-side processing is enabled
1918		if (init.serverSide && ! init.searchDelay) {
1919			init.searchDelay = 400;
1920		}
1921	}
1922	
1923	
1924	/**
1925	 * Provide backwards compatibility for column options. Note that the new options
1926	 * are mapped onto the old parameters, so this is an external interface change
1927	 * only.
1928	 *  @param {object} init Object to map
1929	 */
1930	function _fnCompatCols ( init )
1931	{
1932		_fnCompatMap( init, 'orderable',     'bSortable' );
1933		_fnCompatMap( init, 'orderData',     'aDataSort' );
1934		_fnCompatMap( init, 'orderSequence', 'asSorting' );
1935		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
1936	
1937		// orderData can be given as an integer
1938		var dataSort = init.aDataSort;
1939		if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {
1940			init.aDataSort = [ dataSort ];
1941		}
1942	}
1943	
1944	
1945	/**
1946	 * Browser feature detection for capabilities, quirks
1947	 *  @param {object} settings dataTables settings object
1948	 *  @memberof DataTable#oApi
1949	 */
1950	function _fnBrowserDetect( settings )
1951	{
1952		// We don't need to do this every time DataTables is constructed, the values
1953		// calculated are specific to the browser and OS configuration which we
1954		// don't expect to change between initialisations
1955		if ( ! DataTable.__browser ) {
1956			var browser = {};
1957			DataTable.__browser = browser;
1958	
1959			// Scrolling feature / quirks detection
1960			var n = $('<div/>')
1961				.css( {
1962					position: 'fixed',
1963					top: 0,
1964					left: -1 * window.pageXOffset, // allow for scrolling
1965					height: 1,
1966					width: 1,
1967					overflow: 'hidden'
1968				} )
1969				.append(
1970					$('<div/>')
1971						.css( {
1972							position: 'absolute',
1973							top: 1,
1974							left: 1,
1975							width: 100,
1976							overflow: 'scroll'
1977						} )
1978						.append(
1979							$('<div/>')
1980								.css( {
1981									width: '100%',
1982									height: 10
1983								} )
1984						)
1985				)
1986				.appendTo( 'body' );
1987	
1988			var outer = n.children();
1989			var inner = outer.children();
1990	
1991			// Get scrollbar width
1992			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1993	
1994			// In rtl text layout, some browsers (most, but not all) will place the
1995			// scrollbar on the left, rather than the right.
1996			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1997	
1998			n.remove();
1999		}
2000	
2001		$.extend( settings.oBrowser, DataTable.__browser );
2002		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
2003	}
2004	
2005	/**
2006	 * Add a column to the list used for the table with default values
2007	 *  @param {object} oSettings dataTables settings object
2008	 *  @memberof DataTable#oApi
2009	 */
2010	function _fnAddColumn( oSettings )
2011	{
2012		// Add column to aoColumns array
2013		var oDefaults = DataTable.defaults.column;
2014		var iCol = oSettings.aoColumns.length;
2015		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
2016			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
2017			"mData": oDefaults.mData ? oDefaults.mData : iCol,
2018			idx: iCol,
2019			searchFixed: {},
2020			colEl: $('<col>').attr('data-dt-column', iCol)
2021		} );
2022		oSettings.aoColumns.push( oCol );
2023	
2024		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
2025		// passed into extend can be undefined. This allows the user to give a default
2026		// with only some of the parameters defined, and also not give a default
2027		var searchCols = oSettings.aoPreSearchCols;
2028		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
2029	}
2030	
2031	
2032	/**
2033	 * Apply options for a column
2034	 *  @param {object} oSettings dataTables settings object
2035	 *  @param {int} iCol column index to consider
2036	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
2037	 *  @memberof DataTable#oApi
2038	 */
2039	function _fnColumnOptions( oSettings, iCol, oOptions )
2040	{
2041		var oCol = oSettings.aoColumns[ iCol ];
2042	
2043		/* User specified column options */
2044		if ( oOptions !== undefined && oOptions !== null )
2045		{
2046			// Backwards compatibility
2047			_fnCompatCols( oOptions );
2048	
2049			// Map camel case parameters to their Hungarian counterparts
2050			_fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
2051	
2052			/* Backwards compatibility for mDataProp */
2053			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2054			{
2055				oOptions.mData = oOptions.mDataProp;
2056			}
2057	
2058			if ( oOptions.sType )
2059			{
2060				oCol._sManualType = oOptions.sType;
2061			}
2062		
2063			// `class` is a reserved word in Javascript, so we need to provide
2064			// the ability to use a valid name for the camel case input
2065			if ( oOptions.className && ! oOptions.sClass )
2066			{
2067				oOptions.sClass = oOptions.className;
2068			}
2069	
2070			var origClass = oCol.sClass;
2071	
2072			$.extend( oCol, oOptions );
2073			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2074	
2075			// Merge class from previously defined classes with this one, rather than just
2076			// overwriting it in the extend above
2077			if (origClass !== oCol.sClass) {
2078				oCol.sClass = origClass + ' ' + oCol.sClass;
2079			}
2080	
2081			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
2082			 * priority if defined
2083			 */
2084			if ( oOptions.iDataSort !== undefined )
2085			{
2086				oCol.aDataSort = [ oOptions.iDataSort ];
2087			}
2088			_fnMap( oCol, oOptions, "aDataSort" );
2089		}
2090	
2091		/* Cache the data get and set functions for speed */
2092		var mDataSrc = oCol.mData;
2093		var mData = _fnGetObjectDataFn( mDataSrc );
2094	
2095		// The `render` option can be given as an array to access the helper rendering methods.
2096		// The first element is the rendering method to use, the rest are the parameters to pass
2097		if ( oCol.mRender && Array.isArray( oCol.mRender ) ) {
2098			var copy = oCol.mRender.slice();
2099			var name = copy.shift();
2100	
2101			oCol.mRender = DataTable.render[name].apply(window, copy);
2102		}
2103	
2104		oCol._render = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2105	
2106		var attrTest = function( src ) {
2107			return typeof src === 'string' && src.indexOf('@') !== -1;
2108		};
2109		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2110			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2111		);
2112		oCol._setter = null;
2113	
2114		oCol.fnGetData = function (rowData, type, meta) {
2115			var innerData = mData( rowData, type, undefined, meta );
2116	
2117			return oCol._render && type ?
2118				oCol._render( innerData, type, rowData, meta ) :
2119				innerData;
2120		};
2121		oCol.fnSetData = function ( rowData, val, meta ) {
2122			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2123		};
2124	
2125		// Indicate if DataTables should read DOM data as an object or array
2126		// Used in _fnGetRowElements
2127		if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) {
2128			oSettings._rowReadObject = true;
2129		}
2130	
2131		/* Feature sorting overrides column specific when off */
2132		if ( !oSettings.oFeatures.bSort )
2133		{
2134			oCol.bSortable = false;
2135		}
2136	}
2137	
2138	
2139	/**
2140	 * Adjust the table column widths for new data. Note: you would probably want to
2141	 * do a redraw after calling this function!
2142	 *  @param {object} settings dataTables settings object
2143	 *  @memberof DataTable#oApi
2144	 */
2145	function _fnAdjustColumnSizing ( settings )
2146	{
2147		_fnCalculateColumnWidths( settings );
2148		_fnColumnSizes( settings );
2149	
2150		var scroll = settings.oScroll;
2151		if ( scroll.sY !== '' || scroll.sX !== '') {
2152			_fnScrollDraw( settings );
2153		}
2154	
2155		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
2156	}
2157	
2158	/**
2159	 * Apply column sizes
2160	 *
2161	 * @param {*} settings DataTables settings object
2162	 */
2163	function _fnColumnSizes ( settings )
2164	{
2165		var cols = settings.aoColumns;
2166	
2167		for (var i=0 ; i<cols.length ; i++) {
2168			var width = _fnColumnsSumWidth(settings, [i], false, false);
2169	
2170			cols[i].colEl.css('width', width);
2171		}
2172	}
2173	
2174	
2175	/**
2176	 * Convert the index of a visible column to the index in the data array (take account
2177	 * of hidden columns)
2178	 *  @param {object} oSettings dataTables settings object
2179	 *  @param {int} iMatch Visible column index to lookup
2180	 *  @returns {int} i the data index
2181	 *  @memberof DataTable#oApi
2182	 */
2183	function _fnVisibleToColumnIndex( oSettings, iMatch )
2184	{
2185		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2186	
2187		return typeof aiVis[iMatch] === 'number' ?
2188			aiVis[iMatch] :
2189			null;
2190	}
2191	
2192	
2193	/**
2194	 * Convert the index of an index in the data array and convert it to the visible
2195	 *   column index (take account of hidden columns)
2196	 *  @param {int} iMatch Column index to lookup
2197	 *  @param {object} oSettings dataTables settings object
2198	 *  @returns {int} i the data index
2199	 *  @memberof DataTable#oApi
2200	 */
2201	function _fnColumnIndexToVisible( oSettings, iMatch )
2202	{
2203		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2204		var iPos = aiVis.indexOf(iMatch);
2205	
2206		return iPos !== -1 ? iPos : null;
2207	}
2208	
2209	
2210	/**
2211	 * Get the number of visible columns
2212	 *  @param {object} oSettings dataTables settings object
2213	 *  @returns {int} i the number of visible columns
2214	 *  @memberof DataTable#oApi
2215	 */
2216	function _fnVisbleColumns( settings )
2217	{
2218		var layout = settings.aoHeader;
2219		var columns = settings.aoColumns;
2220		var vis = 0;
2221	
2222		if ( layout.length ) {
2223			for ( var i=0, ien=layout[0].length ; i<ien ; i++ ) {
2224				if ( columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none' ) {
2225					vis++;
2226				}
2227			}
2228		}
2229	
2230		return vis;
2231	}
2232	
2233	
2234	/**
2235	 * Get an array of column indexes that match a given property
2236	 *  @param {object} oSettings dataTables settings object
2237	 *  @param {string} sParam Parameter in aoColumns to look for - typically
2238	 *    bVisible or bSearchable
2239	 *  @returns {array} Array of indexes with matched properties
2240	 *  @memberof DataTable#oApi
2241	 */
2242	function _fnGetColumns( oSettings, sParam )
2243	{
2244		var a = [];
2245	
2246		oSettings.aoColumns.map( function(val, i) {
2247			if ( val[sParam] ) {
2248				a.push( i );
2249			}
2250		} );
2251	
2252		return a;
2253	}
2254	
2255	
2256	/**
2257	 * Calculate the 'type' of a column
2258	 *  @param {object} settings dataTables settings object
2259	 *  @memberof DataTable#oApi
2260	 */
2261	function _fnColumnTypes ( settings )
2262	{
2263		var columns = settings.aoColumns;
2264		var data = settings.aoData;
2265		var types = DataTable.ext.type.detect;
2266		var i, ien, j, jen, k, ken;
2267		var col, detectedType, cache;
2268	
2269		// For each column, spin over the 
2270		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2271			col = columns[i];
2272			cache = [];
2273	
2274			if ( ! col.sType && col._sManualType ) {
2275				col.sType = col._sManualType;
2276			}
2277			else if ( ! col.sType ) {
2278				for ( j=0, jen=types.length ; j<jen ; j++ ) {
2279					for ( k=0, ken=data.length ; k<ken ; k++ ) {
2280	
2281						if (! data[k]) {
2282							continue;
2283						}
2284	
2285						// Use a cache array so we only need to get the type data
2286						// from the formatter once (when using multiple detectors)
2287						if ( cache[k] === undefined ) {
2288							cache[k] = _fnGetCellData( settings, k, i, 'type' );
2289						}
2290	
2291						detectedType = types[j]( cache[k], settings );
2292	
2293						// If null, then this type can't apply to this column, so
2294						// rather than testing all cells, break out. There is an
2295						// exception for the last type which is `html`. We need to
2296						// scan all rows since it is possible to mix string and HTML
2297						// types
2298						if ( ! detectedType && j !== types.length-2 ) {
2299							break;
2300						}
2301	
2302						// Only a single match is needed for html type since it is
2303						// bottom of the pile and very similar to string - but it
2304						// must not be empty
2305						if ( detectedType === 'html' && ! _empty(cache[k]) ) {
2306							break;
2307						}
2308					}
2309	
2310					// Type is valid for all data points in the column - use this
2311					// type
2312					if ( detectedType ) {
2313						col.sType = detectedType;
2314						break;
2315					}
2316				}
2317	
2318				// Fall back - if no type was detected, always use string
2319				if ( ! col.sType ) {
2320					col.sType = 'string';
2321				}
2322			}
2323	
2324			// Set class names for header / footer for auto type classes
2325			var autoClass = _ext.type.className[col.sType];
2326	
2327			if (autoClass) {
2328				_columnAutoClass(settings.aoHeader, i, autoClass);
2329				_columnAutoClass(settings.aoFooter, i, autoClass);
2330			}
2331	
2332			var renderer = _ext.type.render[col.sType];
2333	
2334			// This can only happen once! There is no way to remover
2335			// a renderer. After the first time the renderer has
2336			// already been set so createTr will run the renderer itself.
2337			if (renderer && ! col._render) {
2338				col._render = DataTable.util.get(renderer);
2339	
2340				_columnAutoRender(settings, i);
2341			}
2342		}
2343	}
2344	
2345	/**
2346	 * Apply an auto detected renderer to data which doesn't yet have
2347	 * a renderer
2348	 */
2349	function _columnAutoRender(settings, colIdx) {
2350		var data = settings.aoData;
2351	
2352		for (var i=0 ; i<data.length ; i++) {
2353			if (data[i].nTr) {
2354				// We have to update the display here since there is no
2355				// invalidation check for the data
2356				var display = _fnGetCellData( settings, i, colIdx, 'display' );
2357	
2358				data[i].displayData[colIdx] = display;
2359				_fnWriteCell(data[i].anCells[colIdx], display);
2360	
2361				// No need to update sort / filter data since it has
2362				// been invalidated and will be re-read with the
2363				// renderer now applied
2364			}
2365		}
2366	}
2367	
2368	/**
2369	 * Apply a class name to a column's header cells
2370	 */
2371	function _columnAutoClass(container, colIdx, className) {
2372		container.forEach(function (row) {
2373			if (row[colIdx] && row[colIdx].unique) {
2374				_addClass(row[colIdx].cell, className);
2375			}
2376		});
2377	}
2378	
2379	/**
2380	 * Take the column definitions and static columns arrays and calculate how
2381	 * they relate to column indexes. The callback function will then apply the
2382	 * definition found for a column to a suitable configuration object.
2383	 *  @param {object} oSettings dataTables settings object
2384	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
2385	 *  @param {array} aoCols The aoColumns array that defines columns individually
2386	 *  @param {array} headerLayout Layout for header as it was loaded
2387	 *  @param {function} fn Callback function - takes two parameters, the calculated
2388	 *    column index and the definition for that column.
2389	 *  @memberof DataTable#oApi
2390	 */
2391	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, headerLayout, fn )
2392	{
2393		var i, iLen, j, jLen, k, kLen, def;
2394		var columns = oSettings.aoColumns;
2395	
2396		if ( aoCols ) {
2397			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2398				if (aoCols[i] && aoCols[i].name) {
2399					columns[i].sName = aoCols[i].name;
2400				}
2401			}
2402		}
2403	
2404		// Column definitions with aTargets
2405		if ( aoColDefs )
2406		{
2407			/* Loop over the definitions array - loop in reverse so first instance has priority */
2408			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2409			{
2410				def = aoColDefs[i];
2411	
2412				/* Each definition can target multiple columns, as it is an array */
2413				var aTargets = def.target !== undefined
2414					? def.target
2415					: def.targets !== undefined
2416						? def.targets
2417						: def.aTargets;
2418	
2419				if ( ! Array.isArray( aTargets ) )
2420				{
2421					aTargets = [ aTargets ];
2422				}
2423	
2424				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2425				{
2426					var target = aTargets[j];
2427	
2428					if ( typeof target === 'number' && target >= 0 )
2429					{
2430						/* Add columns that we don't yet know about */
2431						while( columns.length <= target )
2432						{
2433							_fnAddColumn( oSettings );
2434						}
2435	
2436						/* Integer, basic index */
2437						fn( target, def );
2438					}
2439					else if ( typeof target === 'number' && target < 0 )
2440					{
2441						/* Negative integer, right to left column counting */
2442						fn( columns.length+target, def );
2443					}
2444					else if ( typeof target === 'string' )
2445					{
2446						for ( k=0, kLen=columns.length ; k<kLen ; k++ ) {
2447							if (target === '_all') {
2448								// Apply to all columns
2449								fn( k, def );
2450							}
2451							else if (target.indexOf(':name') !== -1) {
2452								// Column selector
2453								if (columns[k].sName === target.replace(':name', '')) {
2454									fn( k, def );
2455								}
2456							}
2457							else {
2458								// Cell selector
2459								headerLayout.forEach(function (row) {
2460									if (row[k]) {
2461										var cell = $(row[k].cell);
2462	
2463										// Legacy support. Note that it means that we don't support
2464										// an element name selector only, since they are treated as
2465										// class names for 1.x compat.
2466										if (target.match(/^[a-z][\w-]*$/i)) {
2467											target = '.' + target;
2468										}
2469	
2470										if (cell.is( target )) {
2471											fn( k, def );
2472										}
2473									}
2474								});
2475							}
2476						}
2477					}
2478				}
2479			}
2480		}
2481	
2482		// Statically defined columns array
2483		if ( aoCols ) {
2484			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) {
2485				fn( i, aoCols[i] );
2486			}
2487		}
2488	}
2489	
2490	
2491	/**
2492	 * Get the width for a given set of columns
2493	 *
2494	 * @param {*} settings DataTables settings object
2495	 * @param {*} targets Columns - comma separated string or array of numbers
2496	 * @param {*} original Use the original width (true) or calculated (false)
2497	 * @param {*} incVisible Include visible columns (true) or not (false)
2498	 * @returns Combined CSS value
2499	 */
2500	function _fnColumnsSumWidth( settings, targets, original, incVisible ) {
2501		if ( ! Array.isArray( targets ) ) {
2502			targets = _fnColumnsFromHeader( targets );
2503		}
2504	
2505		var sum = 0;
2506		var unit;
2507		var columns = settings.aoColumns;
2508		
2509		for ( var i=0, ien=targets.length ; i<ien ; i++ ) {
2510			var column = columns[ targets[i] ];
2511			var definedWidth = original ?
2512				column.sWidthOrig :
2513				column.sWidth;
2514	
2515			if ( ! incVisible && column.bVisible === false ) {
2516				continue;
2517			}
2518	
2519			if ( definedWidth === null || definedWidth === undefined ) {
2520				return null; // can't determine a defined width - browser defined
2521			}
2522			else if ( typeof definedWidth === 'number' ) {
2523				unit = 'px';
2524				sum += definedWidth;
2525			}
2526			else {
2527				var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
2528	
2529				if ( matched ) {
2530					sum += matched[1] * 1;
2531					unit = matched.length === 3 ?
2532						matched[2] :
2533						'px';
2534				}
2535			}
2536		}
2537	
2538		return sum + unit;
2539	}
2540	
2541	function _fnColumnsFromHeader( cell )
2542	{
2543		var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
2544	
2545		if ( ! attr ) {
2546			return [];
2547		}
2548	
2549		return attr.split(',').map( function (val) {
2550			return val * 1;
2551		} );
2552	}
2553	/**
2554	 * Add a data array to the table, creating DOM node etc. This is the parallel to
2555	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2556	 * DOM source.
2557	 *  @param {object} settings dataTables settings object
2558	 *  @param {array} data data array to be added
2559	 *  @param {node} [tr] TR element to add to the table - optional. If not given,
2560	 *    DataTables will create a row automatically
2561	 *  @param {array} [tds] Array of TD|TH elements for the row - must be given
2562	 *    if nTr is.
2563	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2564	 *  @memberof DataTable#oApi
2565	 */
2566	function _fnAddData ( settings, dataIn, tr, tds )
2567	{
2568		/* Create the object for storing information about this new row */
2569		var rowIdx = settings.aoData.length;
2570		var rowModel = $.extend( true, {}, DataTable.models.oRow, {
2571			src: tr ? 'dom' : 'data',
2572			idx: rowIdx
2573		} );
2574	
2575		rowModel._aData = dataIn;
2576		settings.aoData.push( rowModel );
2577	
2578		var columns = settings.aoColumns;
2579	
2580		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2581		{
2582			// Invalidate the column types as the new data needs to be revalidated
2583			columns[i].sType = null;
2584		}
2585	
2586		/* Add to the display array */
2587		settings.aiDisplayMaster.push( rowIdx );
2588	
2589		var id = settings.rowIdFn( dataIn );
2590		if ( id !== undefined ) {
2591			settings.aIds[ id ] = rowModel;
2592		}
2593	
2594		/* Create the DOM information, or register it if already present */
2595		if ( tr || ! settings.oFeatures.bDeferRender )
2596		{
2597			_fnCreateTr( settings, rowIdx, tr, tds );
2598		}
2599	
2600		return rowIdx;
2601	}
2602	
2603	
2604	/**
2605	 * Add one or more TR elements to the table. Generally we'd expect to
2606	 * use this for reading data from a DOM sourced table, but it could be
2607	 * used for an TR element. Note that if a TR is given, it is used (i.e.
2608	 * it is not cloned).
2609	 *  @param {object} settings dataTables settings object
2610	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
2611	 *  @returns {array} Array of indexes for the added rows
2612	 *  @memberof DataTable#oApi
2613	 */
2614	function _fnAddTr( settings, trs )
2615	{
2616		var row;
2617	
2618		// Allow an individual node to be passed in
2619		if ( ! (trs instanceof $) ) {
2620			trs = $(trs);
2621		}
2622	
2623		return trs.map( function (i, el) {
2624			row = _fnGetRowElements( settings, el );
2625			return _fnAddData( settings, row.data, el, row.cells );
2626		} );
2627	}
2628	
2629	
2630	/**
2631	 * Get the data for a given cell from the internal cache, taking into account data mapping
2632	 *  @param {object} settings dataTables settings object
2633	 *  @param {int} rowIdx aoData row id
2634	 *  @param {int} colIdx Column index
2635	 *  @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
2636	 *  @returns {*} Cell data
2637	 *  @memberof DataTable#oApi
2638	 */
2639	function _fnGetCellData( settings, rowIdx, colIdx, type )
2640	{
2641		if (type === 'search') {
2642			type = 'filter';
2643		}
2644		else if (type === 'order') {
2645			type = 'sort';
2646		}
2647	
2648		var row = settings.aoData[rowIdx];
2649	
2650		if (! row) {
2651			return undefined;
2652		}
2653	
2654		var draw           = settings.iDraw;
2655		var col            = settings.aoColumns[colIdx];
2656		var rowData        = row._aData;
2657		var defaultContent = col.sDefaultContent;
2658		var cellData       = col.fnGetData( rowData, type, {
2659			settings: settings,
2660			row:      rowIdx,
2661			col:      colIdx
2662		} );
2663	
2664		// Allow for a node being returned for non-display types
2665		if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
2666			cellData = cellData.innerHTML;
2667		}
2668	
2669		if ( cellData === undefined ) {
2670			if ( settings.iDrawError != draw && defaultContent === null ) {
2671				_fnLog( settings, 0, "Requested unknown parameter "+
2672					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2673					" for row "+rowIdx+", column "+colIdx, 4 );
2674				settings.iDrawError = draw;
2675			}
2676			return defaultContent;
2677		}
2678	
2679		// When the data source is null and a specific data type is requested (i.e.
2680		// not the original data), we can use default column data
2681		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2682			cellData = defaultContent;
2683		}
2684		else if ( typeof cellData === 'function' ) {
2685			// If the data source is a function, then we run it and use the return,
2686			// executing in the scope of the data object (for instances)
2687			return cellData.call( rowData );
2688		}
2689	
2690		if ( cellData === null && type === 'display' ) {
2691			return '';
2692		}
2693	
2694		if ( type === 'filter' ) {
2695			var fomatters = DataTable.ext.type.search;
2696	
2697			if ( fomatters[ col.sType ] ) {
2698				cellData = fomatters[ col.sType ]( cellData );
2699			}
2700		}
2701	
2702		return cellData;
2703	}
2704	
2705	
2706	/**
2707	 * Set the value for a specific cell, into the internal data cache
2708	 *  @param {object} settings dataTables settings object
2709	 *  @param {int} rowIdx aoData row id
2710	 *  @param {int} colIdx Column index
2711	 *  @param {*} val Value to set
2712	 *  @memberof DataTable#oApi
2713	 */
2714	function _fnSetCellData( settings, rowIdx, colIdx, val )
2715	{
2716		var col     = settings.aoColumns[colIdx];
2717		var rowData = settings.aoData[rowIdx]._aData;
2718	
2719		col.fnSetData( rowData, val, {
2720			settings: settings,
2721			row:      rowIdx,
2722			col:      colIdx
2723		}  );
2724	}
2725	
2726	/**
2727	 * Write a value to a cell
2728	 * @param {*} td Cell
2729	 * @param {*} val Value
2730	 */
2731	function _fnWriteCell(td, val)
2732	{
2733		if (val && typeof val === 'object' && val.nodeName) {
2734			$(td)
2735				.empty()
2736				.append(val);
2737		}
2738		else {
2739			td.innerHTML = val;
2740		}
2741	}
2742	
2743	
2744	// Private variable that is used to match action syntax in the data property object
2745	var __reArray = /\[.*?\]$/;
2746	var __reFn = /\(\)$/;
2747	
2748	/**
2749	 * Split string on periods, taking into account escaped periods
2750	 * @param  {string} str String to split
2751	 * @return {array} Split string
2752	 */
2753	function _fnSplitObjNotation( str )
2754	{
2755		var parts = str.match(/(\\.|[^.])+/g) || [''];
2756	
2757		return parts.map( function ( s ) {
2758			return s.replace(/\\\./g, '.');
2759		} );
2760	}
2761	
2762	
2763	/**
2764	 * Return a function that can be used to get data from a source object, taking
2765	 * into account the ability to use nested objects as a source
2766	 *  @param {string|int|function} mSource The data source for the object
2767	 *  @returns {function} Data get function
2768	 *  @memberof DataTable#oApi
2769	 */
2770	var _fnGetObjectDataFn = DataTable.util.get;
2771	
2772	
2773	/**
2774	 * Return a function that can be used to set data from a source object, taking
2775	 * into account the ability to use nested objects as a source
2776	 *  @param {string|int|function} mSource The data source for the object
2777	 *  @returns {function} Data set function
2778	 *  @memberof DataTable#oApi
2779	 */
2780	var _fnSetObjectDataFn = DataTable.util.set;
2781	
2782	
2783	/**
2784	 * Return an array with the full table data
2785	 *  @param {object} oSettings dataTables settings object
2786	 *  @returns array {array} aData Master data array
2787	 *  @memberof DataTable#oApi
2788	 */
2789	function _fnGetDataMaster ( settings )
2790	{
2791		return _pluck( settings.aoData, '_aData' );
2792	}
2793	
2794	
2795	/**
2796	 * Nuke the table
2797	 *  @param {object} oSettings dataTables settings object
2798	 *  @memberof DataTable#oApi
2799	 */
2800	function _fnClearTable( settings )
2801	{
2802		settings.aoData.length = 0;
2803		settings.aiDisplayMaster.length = 0;
2804		settings.aiDisplay.length = 0;
2805		settings.aIds = {};
2806	}
2807	
2808	
2809	/**
2810	 * Mark cached data as invalid such that a re-read of the data will occur when
2811	 * the cached data is next requested. Also update from the data source object.
2812	 *
2813	 * @param {object} settings DataTables settings object
2814	 * @param {int}    rowIdx   Row index to invalidate
2815	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
2816	 *     or 'data'
2817	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
2818	 *     row will be invalidated
2819	 * @memberof DataTable#oApi
2820	 *
2821	 * @todo For the modularisation of v1.11 this will need to become a callback, so
2822	 *   the sort and filter methods can subscribe to it. That will required
2823	 *   initialisation options for sorting, which is why it is not already baked in
2824	 */
2825	function _fnInvalidate( settings, rowIdx, src, colIdx )
2826	{
2827		var row = settings.aoData[ rowIdx ];
2828		var i, ien;
2829	
2830		// Remove the cached data for the row
2831		row._aSortData = null;
2832		row._aFilterData = null;
2833		row.displayData = null;
2834	
2835		// Are we reading last data from DOM or the data object?
2836		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2837			// Read the data from the DOM
2838			row._aData = _fnGetRowElements(
2839					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2840				)
2841				.data;
2842		}
2843		else {
2844			// Reading from data object, update the DOM
2845			var cells = row.anCells;
2846			var display = _fnGetRowDisplay(settings, rowIdx);
2847	
2848			if ( cells ) {
2849				if ( colIdx !== undefined ) {
2850					_fnWriteCell(cells[colIdx], display[colIdx]);
2851				}
2852				else {
2853					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2854						_fnWriteCell(cells[i], display[i]);
2855					}
2856				}
2857			}
2858		}
2859	
2860		// Column specific invalidation
2861		var cols = settings.aoColumns;
2862		if ( colIdx !== undefined ) {
2863			// Type - the data might have changed
2864			cols[ colIdx ].sType = null;
2865	
2866			// Max length string. Its a fairly cheep recalculation, so not worth
2867			// something more complicated
2868			cols[ colIdx ].maxLenString = null;
2869		}
2870		else {
2871			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2872				cols[i].sType = null;
2873				cols[i].maxLenString = null;
2874			}
2875	
2876			// Update DataTables special `DT_*` attributes for the row
2877			_fnRowAttributes( settings, row );
2878		}
2879	}
2880	
2881	
2882	/**
2883	 * Build a data source object from an HTML row, reading the contents of the
2884	 * cells that are in the row.
2885	 *
2886	 * @param {object} settings DataTables settings object
2887	 * @param {node|object} TR element from which to read data or existing row
2888	 *   object from which to re-read the data from the cells
2889	 * @param {int} [colIdx] Optional column index
2890	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2891	 *   parameter should also be given and will be used to write the data into.
2892	 *   Only the column in question will be written
2893	 * @returns {object} Object with two parameters: `data` the data read, in
2894	 *   document order, and `cells` and array of nodes (they can be useful to the
2895	 *   caller, so rather than needing a second traversal to get them, just return
2896	 *   them from here).
2897	 * @memberof DataTable#oApi
2898	 */
2899	function _fnGetRowElements( settings, row, colIdx, d )
2900	{
2901		var
2902			tds = [],
2903			td = row.firstChild,
2904			name, col, i=0, contents,
2905			columns = settings.aoColumns,
2906			objectRead = settings._rowReadObject;
2907	
2908		// Allow the data object to be passed in, or construct
2909		d = d !== undefined ?
2910			d :
2911			objectRead ?
2912				{} :
2913				[];
2914	
2915		var attr = function ( str, td  ) {
2916			if ( typeof str === 'string' ) {
2917				var idx = str.indexOf('@');
2918	
2919				if ( idx !== -1 ) {
2920					var attr = str.substring( idx+1 );
2921					var setter = _fnSetObjectDataFn( str );
2922					setter( d, td.getAttribute( attr ) );
2923				}
2924			}
2925		};
2926	
2927		// Read data from a cell and store into the data object
2928		var cellProcess = function ( cell ) {
2929			if ( colIdx === undefined || colIdx === i ) {
2930				col = columns[i];
2931				contents = (cell.innerHTML).trim();
2932	
2933				if ( col && col._bAttrSrc ) {
2934					var setter = _fnSetObjectDataFn( col.mData._ );
2935					setter( d, contents );
2936	
2937					attr( col.mData.sort, cell );
2938					attr( col.mData.type, cell );
2939					attr( col.mData.filter, cell );
2940				}
2941				else {
2942					// Depending on the `data` option for the columns the data can
2943					// be read to either an object or an array.
2944					if ( objectRead ) {
2945						if ( ! col._setter ) {
2946							// Cache the setter function
2947							col._setter = _fnSetObjectDataFn( col.mData );
2948						}
2949						col._setter( d, contents );
2950					}
2951					else {
2952						d[i] = contents;
2953					}
2954				}
2955			}
2956	
2957			i++;
2958		};
2959	
2960		if ( td ) {
2961			// `tr` element was passed in
2962			while ( td ) {
2963				name = td.nodeName.toUpperCase();
2964	
2965				if ( name == "TD" || name == "TH" ) {
2966					cellProcess( td );
2967					tds.push( td );
2968				}
2969	
2970				td = td.nextSibling;
2971			}
2972		}
2973		else {
2974			// Existing row object passed in
2975			tds = row.anCells;
2976	
2977			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
2978				cellProcess( tds[j] );
2979			}
2980		}
2981	
2982		// Read the ID from the DOM if present
2983		var rowNode = row.firstChild ? row : row.nTr;
2984	
2985		if ( rowNode ) {
2986			var id = rowNode.getAttribute( 'id' );
2987	
2988			if ( id ) {
2989				_fnSetObjectDataFn( settings.rowId )( d, id );
2990			}
2991		}
2992	
2993		return {
2994			data: d,
2995			cells: tds
2996		};
2997	}
2998	
2999	/**
3000	 * Render and cache a row's display data for the columns, if required
3001	 * @returns 
3002	 */
3003	function _fnGetRowDisplay (settings, rowIdx) {
3004		let rowModal = settings.aoData[rowIdx];
3005		let columns = settings.aoColumns;
3006	
3007		if (! rowModal.displayData) {
3008			// Need to render and cache
3009			rowModal.displayData = [];
3010		
3011			for ( var colIdx=0, len=columns.length ; colIdx<len ; colIdx++ ) {
3012				rowModal.displayData.push(
3013					_fnGetCellData( settings, rowIdx, colIdx, 'display' )
3014				);
3015			}
3016		}
3017	
3018		return rowModal.displayData;
3019	}
3020	
3021	/**
3022	 * Create a new TR element (and it's TD children) for a row
3023	 *  @param {object} oSettings dataTables settings object
3024	 *  @param {int} iRow Row to consider
3025	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3026	 *    DataTables will create a row automatically
3027	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
3028	 *    if nTr is.
3029	 *  @memberof DataTable#oApi
3030	 */
3031	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3032	{
3033		var
3034			row = oSettings.aoData[iRow],
3035			rowData = row._aData,
3036			cells = [],
3037			nTr, nTd, oCol,
3038			i, iLen, create,
3039			trClass = oSettings.oClasses.tbody.row;
3040	
3041		if ( row.nTr === null )
3042		{
3043			nTr = nTrIn || document.createElement('tr');
3044	
3045			row.nTr = nTr;
3046			row.anCells = cells;
3047	
3048			_addClass(nTr, trClass);
3049	
3050			/* Use a private property on the node to allow reserve mapping from the node
3051			 * to the aoData array for fast look up
3052			 */
3053			nTr._DT_RowIndex = iRow;
3054	
3055			/* Special parameters can be given by the data source to be used on the row */
3056			_fnRowAttributes( oSettings, row );
3057	
3058			/* Process each column */
3059			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3060			{
3061				oCol = oSettings.aoColumns[i];
3062				create = nTrIn && anTds[i] ? false : true;
3063	
3064				nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
3065	
3066				if (! nTd) {
3067					_fnLog( oSettings, 0, 'Incorrect column count', 18 );
3068				}
3069	
3070				nTd._DT_CellIndex = {
3071					row: iRow,
3072					column: i
3073				};
3074				
3075				cells.push( nTd );
3076				
3077				var display = _fnGetRowDisplay(oSettings, iRow);
3078	
3079				// Need to create the HTML if new, or if a rendering function is defined
3080				if (
3081					create ||
3082					(
3083						(oCol.mRender || oCol.mData !== i) &&
3084						(!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3085					)
3086				) {
3087					_fnWriteCell(nTd, display[i]);
3088				}
3089	
3090				// Visibility - add or remove as required
3091				if ( oCol.bVisible && create )
3092				{
3093					nTr.appendChild( nTd );
3094				}
3095				else if ( ! oCol.bVisible && ! create )
3096				{
3097					nTd.parentNode.removeChild( nTd );
3098				}
3099	
3100				if ( oCol.fnCreatedCell )
3101				{
3102					oCol.fnCreatedCell.call( oSettings.oInstance,
3103						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3104					);
3105				}
3106			}
3107	
3108			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells] );
3109		}
3110		else {
3111			_addClass(row.nTr, trClass);
3112		}
3113	}
3114	
3115	
3116	/**
3117	 * Add attributes to a row based on the special `DT_*` parameters in a data
3118	 * source object.
3119	 *  @param {object} settings DataTables settings object
3120	 *  @param {object} DataTables row object for the row to be modified
3121	 *  @memberof DataTable#oApi
3122	 */
3123	function _fnRowAttributes( settings, row )
3124	{
3125		var tr = row.nTr;
3126		var data = row._aData;
3127	
3128		if ( tr ) {
3129			var id = settings.rowIdFn( data );
3130	
3131			if ( id ) {
3132				tr.id = id;
3133			}
3134	
3135			if ( data.DT_RowClass ) {
3136				// Remove any classes added by DT_RowClass before
3137				var a = data.DT_RowClass.split(' ');
3138				row.__rowc = row.__rowc ?
3139					_unique( row.__rowc.concat( a ) ) :
3140					a;
3141	
3142				$(tr)
3143					.removeClass( row.__rowc.join(' ') )
3144					.addClass( data.DT_RowClass );
3145			}
3146	
3147			if ( data.DT_RowAttr ) {
3148				$(tr).attr( data.DT_RowAttr );
3149			}
3150	
3151			if ( data.DT_RowData ) {
3152				$(tr).data( data.DT_RowData );
3153			}
3154		}
3155	}
3156	
3157	
3158	/**
3159	 * Create the HTML header for the table
3160	 *  @param {object} oSettings dataTables settings object
3161	 *  @memberof DataTable#oApi
3162	 */
3163	function _fnBuildHead( settings, side )
3164	{
3165		var classes = settings.oClasses;
3166		var columns = settings.aoColumns;
3167		var i, ien, row;
3168		var target = side === 'header'
3169			? settings.nTHead
3170			: settings.nTFoot;
3171		var titleProp = side === 'header' ? 'sTitle' : side;
3172	
3173		// Footer might be defined
3174		if (! target) {
3175			return;
3176		}
3177	
3178		// If no cells yet and we have content for them, then create
3179		if (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) {
3180			row = $('tr', target);
3181	
3182			// Add a row if needed
3183			if (! row.length) {
3184				row = $('<tr/>').appendTo(target)
3185			}
3186	
3187			// Add the number of cells needed to make up to the number of columns
3188			if (row.length === 1) {
3189				var cells = $('td, th', row);
3190	
3191				for ( i=cells.length, ien=columns.length ; i<ien ; i++ ) {
3192					$('<th/>')
3193						.html( columns[i][titleProp] || '' )
3194						.appendTo( row );
3195				}
3196			}
3197		}
3198	
3199		var detected = _fnDetectHeader( settings, target, true );
3200	
3201		if (side === 'header') {
3202			settings.aoHeader = detected;
3203		}
3204		else {
3205			settings.aoFooter = detected;
3206		}
3207	
3208		// ARIA role for the rows
3209		$(target).children('tr').attr('role', 'row');
3210	
3211		// Every cell needs to be passed through the renderer
3212		$(target).children('tr').children('th, td')
3213			.each( function () {
3214				_fnRenderer( settings, side )(
3215					settings, $(this), classes
3216				);
3217			} );
3218	}
3219	
3220	/**
3221	 * Build a layout structure for a header or footer
3222	 *
3223	 * @param {*} settings DataTables settings
3224	 * @param {*} source Source layout array
3225	 * @param {*} incColumns What columns should be included
3226	 * @returns Layout array
3227	 */
3228	function _fnHeaderLayout( settings, source, incColumns )
3229	{
3230		var row, column, cell;
3231		var local = [];
3232		var structure = [];
3233		var columns = settings.aoColumns;
3234		var columnCount = columns.length;
3235		var rowspan, colspan;
3236	
3237		if ( ! source ) {
3238			return;
3239		}
3240	
3241		// Default is to work on only visible columns
3242		if ( ! incColumns ) {
3243			incColumns = _range(columnCount)
3244				.filter(function (idx) {
3245					return columns[idx].bVisible;
3246				});
3247		}
3248	
3249		// Make a copy of the master layout array, but with only the columns we want
3250		for ( row=0 ; row<source.length ; row++ ) {
3251			// Remove any columns we haven't selected
3252			local[row] = source[row].slice().filter(function (cell, i) {
3253				return incColumns.includes(i);
3254			});
3255	
3256			// Prep the structure array - it needs an element for each row
3257			structure.push( [] );
3258		}
3259	
3260		for ( row=0 ; row<local.length ; row++ ) {
3261			for ( column=0 ; column<local[row].length ; column++ ) {
3262				rowspan = 1;
3263				colspan = 1;
3264	
3265				// Check to see if there is already a cell (row/colspan) covering our target
3266				// insert point. If there is, then there is nothing to do.
3267				if ( structure[row][column] === undefined ) {
3268					cell = local[row][column].cell;
3269	
3270					// Expand for rowspan
3271					while (
3272						local[row+rowspan] !== undefined &&
3273						local[row][column].cell == local[row+rowspan][column].cell
3274					) {
3275						structure[row+rowspan][column] = null;
3276						rowspan++;
3277					}
3278	
3279					// And for colspan
3280					while (
3281						local[row][column+colspan] !== undefined &&
3282						local[row][column].cell == local[row][column+colspan].cell
3283					) {
3284						// Which also needs to go over rows
3285						for ( var k=0 ; k<rowspan ; k++ ) {
3286							structure[row+k][column+colspan] = null;
3287						}
3288	
3289						colspan++;
3290					}
3291	
3292					var titleSpan = $('span.dt-column-title', cell);
3293	
3294					structure[row][column] = {
3295						cell: cell,
3296						colspan: colspan,
3297						rowspan: rowspan,
3298						title: titleSpan.length
3299							? titleSpan.html()
3300							: $(cell).html()
3301					};
3302				}
3303			}
3304		}
3305	
3306		return structure;
3307	}
3308	
3309	
3310	/**
3311	 * Draw the header (or footer) element based on the column visibility states.
3312	 *
3313	 *  @param object oSettings dataTables settings object
3314	 *  @param array aoSource Layout array from _fnDetectHeader
3315	 *  @memberof DataTable#oApi
3316	 */
3317	function _fnDrawHead( settings, source )
3318	{
3319		var layout = _fnHeaderLayout(settings, source);
3320		var tr, n;
3321	
3322		for ( var row=0 ; row<source.length ; row++ ) {
3323			tr = source[row].row;
3324	
3325			// All cells are going to be replaced, so empty out the row
3326			// Can't use $().empty() as that kills event handlers
3327			if (tr) {
3328				while( (n = tr.firstChild) ) {
3329					tr.removeChild( n );
3330				}
3331			}
3332	
3333			for ( var column=0 ; column<layout[row].length ; column++ ) {
3334				var point = layout[row][column];
3335	
3336				if (point) {
3337					$(point.cell)
3338						.appendTo(tr)
3339						.attr('rowspan', point.rowspan)
3340						.attr('colspan', point.colspan);
3341				}
3342			}
3343		}
3344	}
3345	
3346	
3347	/**
3348	 * Insert the required TR nodes into the table for display
3349	 *  @param {object} oSettings dataTables settings object
3350	 *  @param ajaxComplete true after ajax call to complete rendering
3351	 *  @memberof DataTable#oApi
3352	 */
3353	function _fnDraw( oSettings, ajaxComplete )
3354	{
3355		// Allow for state saving and a custom start position
3356		_fnStart( oSettings );
3357	
3358		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3359		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3360		if ( aPreDraw.indexOf(false) !== -1 )
3361		{
3362			_fnProcessingDisplay( oSettings, false );
3363			return;
3364		}
3365	
3366		var anRows = [];
3367		var iRowCount = 0;
3368		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3369		var aiDisplay = oSettings.aiDisplay;
3370		var iDisplayStart = oSettings._iDisplayStart;
3371		var iDisplayEnd = oSettings.fnDisplayEnd();
3372		var columns = oSettings.aoColumns;
3373		var body = $(oSettings.nTBody);
3374	
3375		oSettings.bDrawing = true;
3376	
3377		/* Server-side processing draw intercept */
3378		if ( !bServerSide )
3379		{
3380			oSettings.iDraw++;
3381		}
3382		else if ( !oSettings.bDestroying && !ajaxComplete)
3383		{
3384			// Show loading message for server-side processing
3385			if (oSettings.iDraw === 0) {
3386				body.empty().append(_emptyRow(oSettings));
3387			}
3388	
3389			_fnAjaxUpdate( oSettings );
3390			return;
3391		}
3392	
3393		if ( aiDisplay.length !== 0 )
3394		{
3395			var iStart = bServerSide ? 0 : iDisplayStart;
3396			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3397	
3398			for ( var j=iStart ; j<iEnd ; j++ )
3399			{
3400				var iDataIndex = aiDisplay[j];
3401				var aoData = oSettings.aoData[ iDataIndex ];
3402				if ( aoData.nTr === null )
3403				{
3404					_fnCreateTr( oSettings, iDataIndex );
3405				}
3406	
3407				var nRow = aoData.nTr;
3408	
3409				// Add various classes as needed
3410				for (var i=0 ; i<columns.length ; i++) {
3411					var col = columns[i];
3412					var td = aoData.anCells[i];
3413	
3414					_addClass(td, _ext.type.className[col.sType]); // auto class
3415					_addClass(td, col.sClass); // column class
3416					_addClass(td, oSettings.oClasses.tbody.cell); // all cells
3417				}
3418	
3419				// Row callback functions - might want to manipulate the row
3420				// iRowCount and j are not currently documented. Are they at all
3421				// useful?
3422				_fnCallbackFire( oSettings, 'aoRowCallback', null,
3423					[nRow, aoData._aData, iRowCount, j, iDataIndex] );
3424	
3425				anRows.push( nRow );
3426				iRowCount++;
3427			}
3428		}
3429		else
3430		{
3431			anRows[ 0 ] = _emptyRow(oSettings);
3432		}
3433	
3434		/* Header and footer callbacks */
3435		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3436			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3437	
3438		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3439			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3440	
3441		// replaceChildren is faster, but only became widespread in 2020,
3442		// so a fall back in jQuery is provided for older browsers.
3443		if (body[0].replaceChildren) {
3444			body[0].replaceChildren.apply(body[0], anRows);
3445		}
3446		else {
3447			body.children().detach();
3448			body.append( $(anRows) );
3449		}
3450	
3451		// Empty table needs a specific class
3452		$(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
3453	
3454		/* Call all required callback functions for the end of a draw */
3455		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings], true );
3456	
3457		/* Draw is complete, sorting and filtering must be as well */
3458		oSettings.bSorted = false;
3459		oSettings.bFiltered = false;
3460		oSettings.bDrawing = false;
3461	}
3462	
3463	
3464	/**
3465	 * Redraw the table - taking account of the various features which are enabled
3466	 *  @param {object} oSettings dataTables settings object
3467	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
3468	 *    the paging is reset to the first page
3469	 *  @memberof DataTable#oApi
3470	 */
3471	function _fnReDraw( settings, holdPosition, recompute )
3472	{
3473		var
3474			features = settings.oFeatures,
3475			sort     = features.bSort,
3476			filter   = features.bFilter;
3477	
3478		if (recompute === undefined || recompute === true) {
3479			if ( sort ) {
3480				_fnSort( settings );
3481			}
3482	
3483			if ( filter ) {
3484				_fnFilterComplete( settings, settings.oPreviousSearch );
3485			}
3486			else {
3487				// No filtering, so we want to just use the display master
3488				settings.aiDisplay = settings.aiDisplayMaster.slice();
3489			}
3490		}
3491	
3492		if ( holdPosition !== true ) {
3493			settings._iDisplayStart = 0;
3494		}
3495	
3496		// Let any modules know about the draw hold position state (used by
3497		// scrolling internally)
3498		settings._drawHold = holdPosition;
3499	
3500		_fnDraw( settings );
3501	
3502		settings._drawHold = false;
3503	}
3504	
3505	
3506	/*
3507	 * Table is empty - create a row with an empty message in it
3508	 */
3509	function _emptyRow ( settings ) {
3510		var oLang = settings.oLanguage;
3511		var zero = oLang.sZeroRecords;
3512		var dataSrc = _fnDataSource( settings );
3513	
3514		if (
3515			(settings.iDraw < 1 && dataSrc === 'ssp') ||
3516			(settings.iDraw <= 1 && dataSrc === 'ajax')
3517		) {
3518			zero = oLang.sLoadingRecords;
3519		}
3520		else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
3521		{
3522			zero = oLang.sEmptyTable;
3523		}
3524	
3525		return $( '<tr/>' )
3526			.append( $('<td />', {
3527				'colSpan': _fnVisbleColumns( settings ),
3528				'class':   settings.oClasses.empty.row
3529			} ).html( zero ) )[0];
3530	}
3531	
3532	
3533	/**
3534	 * Convert a `layout` object given by a user to the object structure needed
3535	 * for the renderer. This is done twice, once for above and once for below
3536	 * the table. Ordering must also be considered.
3537	 *
3538	 * @param {*} settings DataTables settings object
3539	 * @param {*} layout Layout object to convert
3540	 * @param {string} side `top` or `bottom`
3541	 * @returns Converted array structure - one item for each row.
3542	 */
3543	function _layoutArray ( settings, layout, side )
3544	{
3545		var groups = {};
3546	
3547		// Combine into like groups (e.g. `top`, `top2`, etc)
3548		$.each( layout, function ( pos, val ) {
3549			if (val === null) {
3550				return;
3551			}
3552	
3553			var splitPos = pos.replace(/([A-Z])/g, ' $1').split(' ');
3554	
3555			if ( ! groups[ splitPos[0] ] ) {
3556				groups[ splitPos[0] ] = {};
3557			}
3558	
3559			var align = splitPos.length === 1 ?
3560				'full' :
3561				splitPos[1].toLowerCase();
3562			var group = groups[ splitPos[0] ];
3563			var groupRun = function (contents, innerVal) {
3564				// If it is an object, then there can be multiple features contained in it
3565				if ( $.isPlainObject( innerVal ) ) {
3566					Object.keys(innerVal).map(function (key) {
3567						contents.push( {
3568							feature: key,
3569							opts: innerVal[key]
3570						});
3571					});
3572				}
3573				else {
3574					contents.push(innerVal);
3575				}
3576			}
3577	
3578			// Transform to an object with a contents property
3579			if (! group[align] || ! group[align].contents) {
3580				group[align] = { contents: [] };
3581			}
3582	
3583			// Allow for an array or just a single object
3584			if ( Array.isArray(val)) {
3585				for (var i=0 ; i<val.length ; i++) {
3586					groupRun(group[align].contents, val[i]);
3587				}
3588			}
3589			else {
3590				groupRun(group[ align ].contents, val);
3591			}
3592	
3593			// And make contents an array
3594			if ( ! Array.isArray( group[ align ].contents ) ) {
3595				group[ align ].contents = [ group[ align ].contents ];
3596			}
3597		} );
3598	
3599		var filtered = Object.keys(groups)
3600			.map( function ( pos ) {
3601				// Filter to only the side we need
3602				if ( pos.indexOf(side) !== 0 ) {
3603					return null;
3604				}
3605	
3606				return {
3607					name: pos,
3608					val: groups[pos]
3609				};
3610			} )
3611			.filter( function (item) {
3612				return item !== null;
3613			});
3614	
3615		// Order by item identifier
3616		filtered.sort( function ( a, b ) {
3617			var order1 = a.name.replace(/[^0-9]/g, '') * 1;
3618			var order2 = b.name.replace(/[^0-9]/g, '') * 1;
3619	
3620			return order2 - order1;
3621		} );
3622		
3623		if ( side === 'bottom' ) {
3624			filtered.reverse();
3625		}
3626	
3627		// Split into rows
3628		var rows = [];
3629		for ( var i=0, ien=filtered.length ; i<ien ; i++ ) {
3630			if (  filtered[i].val.full ) {
3631				rows.push( { full: filtered[i].val.full } );
3632				_layoutResolve( settings, rows[ rows.length - 1 ] );
3633	
3634				delete filtered[i].val.full;
3635			}
3636	
3637			if ( Object.keys(filtered[i].val).length ) {
3638				rows.push( filtered[i].val );
3639				_layoutResolve( settings, rows[ rows.length - 1 ] );
3640			}
3641		}
3642	
3643		return rows;
3644	}
3645	
3646	
3647	/**
3648	 * Convert the contents of a row's layout object to nodes that can be inserted
3649	 * into the document by a renderer. Execute functions, look up plug-ins, etc.
3650	 *
3651	 * @param {*} settings DataTables settings object
3652	 * @param {*} row Layout object for this row
3653	 */
3654	function _layoutResolve( settings, row ) {
3655		var getFeature = function (feature, opts) {
3656			if ( ! _ext.features[ feature ] ) {
3657				_fnLog( settings, 0, 'Unknown feature: '+ feature );
3658			}
3659	
3660			return _ext.features[ feature ].apply( this, [settings, opts] );
3661		};
3662	
3663		var resolve = function ( item ) {
3664			var line = row[ item ].contents;
3665	
3666			for ( var i=0, ien=line.length ; i<ien ; i++ ) {
3667				if ( ! line[i] ) {
3668					continue;
3669				}
3670				else if ( typeof line[i] === 'string' ) {
3671					line[i] = getFeature( line[i], null );
3672				}
3673				else if ( $.isPlainObject(line[i]) ) {
3674					// If it's an object, it just has feature and opts properties from
3675					// the transform in _layoutArray
3676					line[i] = getFeature(line[i].feature, line[i].opts);
3677				}
3678				else if ( typeof line[i].node === 'function' ) {
3679					line[i] = line[i].node( settings );
3680				}
3681				else if ( typeof line[i] === 'function' ) {
3682					var inst = line[i]( settings );
3683	
3684					line[i] = typeof inst.node === 'function' ?
3685						inst.node() :
3686						inst;
3687				}
3688			}
3689		};
3690	
3691		$.each( row, function ( key ) {
3692			resolve( key );
3693		} );
3694	}
3695	
3696	
3697	/**
3698	 * Add the options to the page HTML for the table
3699	 *  @param {object} settings DataTables settings object
3700	 *  @memberof DataTable#oApi
3701	 */
3702	function _fnAddOptionsHtml ( settings )
3703	{
3704		var classes = settings.oClasses;
3705		var table = $(settings.nTable);
3706	
3707		// Wrapper div around everything DataTables controls
3708		var insert = $('<div/>')
3709			.attr({
3710				id:      settings.sTableId+'_wrapper',
3711				'class': classes.container
3712			})
3713			.insertBefore(table);
3714	
3715		settings.nTableWrapper = insert[0];
3716	
3717		if (settings.sDom) {
3718			// Legacy
3719			_fnLayoutDom(settings, settings.sDom, insert);
3720		}
3721		else {
3722			var top = _layoutArray( settings, settings.layout, 'top' );
3723			var bottom = _layoutArray( settings, settings.layout, 'bottom' );
3724			var renderer = _fnRenderer( settings, 'layout' );
3725		
3726			// Everything above - the renderer will actually insert the contents into the document
3727			top.forEach(function (item) {
3728				renderer( settings, insert, item );
3729			});
3730	
3731			// The table - always the center of attention
3732			renderer( settings, insert, {
3733				full: {
3734					table: true,
3735					contents: [ _fnFeatureHtmlTable(settings) ]
3736				}
3737			} );
3738	
3739			// Everything below
3740			bottom.forEach(function (item) {
3741				renderer( settings, insert, item );
3742			});
3743		}
3744	
3745		// Processing floats on top, so it isn't an inserted feature
3746		_processingHtml( settings );
3747	}
3748	
3749	/**
3750	 * Draw the table with the legacy DOM property
3751	 * @param {*} settings DT settings object
3752	 * @param {*} dom DOM string
3753	 * @param {*} insert Insert point
3754	 */
3755	function _fnLayoutDom( settings, dom, insert )
3756	{
3757		var parts = dom.match(/(".*?")|('.*?')|./g);
3758		var featureNode, option, newNode, next, attr;
3759	
3760		for ( var i=0 ; i<parts.length ; i++ ) {
3761			featureNode = null;
3762			option = parts[i];
3763	
3764			if ( option == '<' ) {
3765				// New container div
3766				newNode = $('<div/>');
3767	
3768				// Check to see if we should append an id and/or a class name to the container
3769				next = parts[i+1];
3770	
3771				if ( next[0] == "'" || next[0] == '"' ) {
3772					attr = next.replace(/['"]/g, '');
3773	
3774					var id = '', className;
3775	
3776					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3777					 * breaks the string into parts and applies them as needed
3778					 */
3779					if ( attr.indexOf('.') != -1 ) {
3780						var split = attr.split('.');
3781	
3782						id = split[0];
3783						className = split[1];
3784					}
3785					else if ( attr[0] == "#" ) {
3786						id = attr;
3787					}
3788					else {
3789						className = attr;
3790					}
3791	
3792					newNode
3793						.attr('id', id.substring(1))
3794						.addClass(className);
3795	
3796					i++; // Move along the position array
3797				}
3798	
3799				insert.append( newNode );
3800				insert = newNode;
3801			}
3802			else if ( option == '>' ) {
3803				// End container div
3804				insert = insert.parent();
3805			}
3806			else if ( option == 't' ) {
3807				// Table
3808				featureNode = _fnFeatureHtmlTable( settings );
3809			}
3810			else
3811			{
3812				DataTable.ext.feature.forEach(function(feature) {
3813					if ( option == feature.cFeature ) {
3814						featureNode = feature.fnInit( settings );
3815					}
3816				});
3817			}
3818	
3819			// Add to the display
3820			if ( featureNode ) {
3821				insert.append( featureNode );
3822			}
3823		}
3824	}
3825	
3826	
3827	/**
3828	 * Use the DOM source to create up an array of header cells. The idea here is to
3829	 * create a layout grid (array) of rows x columns, which contains a reference
3830	 * to the cell that that point in the grid (regardless of col/rowspan), such that
3831	 * any column / row could be removed and the new grid constructed
3832	 *  @param {node} thead The header/footer element for the table
3833	 *  @returns {array} Calculated layout array
3834	 *  @memberof DataTable#oApi
3835	 */
3836	function _fnDetectHeader ( settings, thead, write )
3837	{
3838		var columns = settings.aoColumns;
3839		var rows = $(thead).children('tr');
3840		var row, cell;
3841		var i, k, l, iLen, shifted, column, colspan, rowspan;
3842		var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3843		var layout = [];
3844		var unique;
3845		var shift = function ( a, i, j ) {
3846			var k = a[i];
3847			while ( k[j] ) {
3848				j++;
3849			}
3850			return j;
3851		};
3852	
3853		// We know how many rows there are in the layout - so prep it
3854		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3855			layout.push( [] );
3856		}
3857	
3858		for ( i=0, iLen=rows.length ; i<iLen ; i++ ) {
3859			row = rows[i];
3860			column = 0;
3861	
3862			// For every cell in the row..
3863			cell = row.firstChild;
3864			while ( cell ) {
3865				if (
3866					cell.nodeName.toUpperCase() == 'TD' ||
3867					cell.nodeName.toUpperCase() == 'TH'
3868				) {
3869					var cols = [];
3870	
3871					// Get the col and rowspan attributes from the DOM and sanitise them
3872					colspan = cell.getAttribute('colspan') * 1;
3873					rowspan = cell.getAttribute('rowspan') * 1;
3874					colspan = (!colspan || colspan===0 || colspan===1) ? 1 : colspan;
3875					rowspan = (!rowspan || rowspan===0 || rowspan===1) ? 1 : rows
3875pan;
3876	
3877					// There might be colspan cells already in this row, so shift our target
3878					// accordingly
3879					shifted = shift( layout, i, column );
3880	
3881					// Cache calculation for unique columns
3882					unique = colspan === 1 ?
3883						true :
3884						false;
3885					
3886					// Perform header setup
3887					if ( write ) {
3888						if (unique) {
3889							// Allow column options to be set from HTML attributes
3890							_fnColumnOptions( settings, shifted, $(cell).data() );
3891							
3892							// Get the width for the column. This can be defined from the
3893							// width attribute, style attribute or `columns.width` option
3894							var columnDef = columns[shifted];
3895							var width = cell.getAttribute('width') || null;
3896							var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
3897							if ( t ) {
3898								width = t[1];
3899							}
3900	
3901							columnDef.sWidthOrig = columnDef.sWidth || width;
3902	
3903							if (isHeader) {
3904								// Column title handling - can be user set, or read from the DOM
3905								// This happens before the render, so the original is still in place
3906								if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
3907									cell.innerHTML = columnDef.sTitle;
3908								}
3909	
3910								if (! columnDef.sTitle && unique) {
3911									columnDef.sTitle = _stripHtml(cell.innerHTML);
3912									columnDef.autoTitle = true;
3913								}
3914							}
3915							else {
3916								// Footer specific operations
3917								if (columnDef.footer) {
3918									cell.innerHTML = columnDef.footer;
3919								}
3920							}
3921	
3922							// Fall back to the aria-label attribute on the table header if no ariaTitle is
3923							// provided.
3924							if (! columnDef.ariaTitle) {
3925								columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
3926							}
3927	
3928							// Column specific class names
3929							if ( columnDef.className ) {
3930								$(cell).addClass( columnDef.className );
3931							}
3932						}
3933	
3934						// Wrap the column title so we can write to it in future
3935						if ( $('span.dt-column-title', cell).length === 0) {
3936							$('<span>')
3937								.addClass('dt-column-title')
3938								.append(cell.childNodes)
3939								.appendTo(cell);
3940						}
3941	
3942						if ( isHeader && $('span.dt-column-order', cell).length === 0) {
3943							$('<span>')
3944								.addClass('dt-column-order')
3945								.appendTo(cell);
3946						}
3947					}
3948	
3949					// If there is col / rowspan, copy the information into the layout grid
3950					for ( l=0 ; l<colspan ; l++ ) {
3951						for ( k=0 ; k<rowspan ; k++ ) {
3952							layout[i+k][shifted+l] = {
3953								cell: cell,
3954								unique: unique
3955							};
3956	
3957							layout[i+k].row = row;
3958						}
3959	
3960						cols.push( shifted+l );
3961					}
3962	
3963					// Assign an attribute so spanning cells can still be identified
3964					// as belonging to a column
3965					cell.setAttribute('data-dt-column', _unique(cols).join(','));
3966				}
3967	
3968				cell = cell.nextSibling;
3969			}
3970		}
3971	
3972		return layout;
3973	}
3974	
3975	/**
3976	 * Set the start position for draw
3977	 *  @param {object} oSettings dataTables settings object
3978	 */
3979	function _fnStart( oSettings )
3980	{
3981		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3982		var iInitDisplayStart = oSettings.iInitDisplayStart;
3983	
3984		// Check and see if we have an initial draw position from state saving
3985		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3986		{
3987			oSettings._iDisplayStart = bServerSide ?
3988				iInitDisplayStart :
3989				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3990					0 :
3991					iInitDisplayStart;
3992	
3993			oSettings.iInitDisplayStart = -1;
3994		}
3995	}
3996	
3997	/**
3998	 * Create an Ajax call based on the table's settings, taking into account that
3999	 * parameters can have multiple forms, and backwards compatibility.
4000	 *
4001	 * @param {object} oSettings dataTables settings object
4002	 * @param {array} data Data to send to the server, required by
4003	 *     DataTables - may be augmented by developer callbacks
4004	 * @param {function} fn Callback function to run when data is obtained
4005	 */
4006	function _fnBuildAjax( oSettings, data, fn )
4007	{
4008		var ajaxData;
4009		var ajax = oSettings.ajax;
4010		var instance = oSettings.oInstance;
4011		var callback = function ( json ) {
4012			var status = oSettings.jqXHR
4013				? oSettings.jqXHR.status
4014				: null;
4015	
4016			if ( json === null || (typeof status === 'number' && status == 204 ) ) {
4017				json = {};
4018				_fnAjaxDataSrc( oSettings, json, [] );
4019			}
4020	
4021			var error = json.error || json.sError;
4022			if ( error ) {
4023				_fnLog( oSettings, 0, error );
4024			}
4025	
4026			oSettings.json = json;
4027	
4028			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
4029			fn( json );
4030		};
4031	
4032		if ( $.isPlainObject( ajax ) && ajax.data )
4033		{
4034			ajaxData = ajax.data;
4035	
4036			var newData = typeof ajaxData === 'function' ?
4037				ajaxData( data, oSettings ) :  // fn can manipulate data or return
4038				ajaxData;                      // an object object or array to merge
4039	
4040			// If the function returned something, use that alone
4041			data = typeof ajaxData === 'function' && newData ?
4042				newData :
4043				$.extend( true, data, newData );
4044	
4045			// Remove the data property as we've resolved it already and don't want
4046			// jQuery to do it again (it is restored at the end of the function)
4047			delete ajax.data;
4048		}
4049	
4050		var baseAjax = {
4051			"url": typeof ajax === 'string' ?
4052				ajax :
4053				'',
4054			"data": data,
4055			"success": callback,
4056			"dataType": "json",
4057			"cache": false,
4058			"type": oSettings.sServerMethod,
4059			"error": function (xhr, error) {
4060				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
4061	
4062				if ( ret.indexOf(true) === -1 ) {
4063					if ( error == "parsererror" ) {
4064						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
4065					}
4066					else if ( xhr.readyState === 4 ) {
4067						_fnLog( oSettings, 0, 'Ajax error', 7 );
4068					}
4069				}
4070	
4071				_fnProcessingDisplay( oSettings, false );
4072			}
4073		};
4074	
4075		// If `ajax` option is an object, extend and override our default base
4076		if ( $.isPlainObject( ajax ) ) {
4077			$.extend( baseAjax, ajax )
4078		}
4079	
4080		// Store the data submitted for the API
4081		oSettings.oAjaxData = data;
4082	
4083		// Allow plug-ins and external processes to modify the data
4084		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4085	
4086		if ( typeof ajax === 'function' )
4087		{
4088			// Is a function - let the caller define what needs to be done
4089			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
4090		}
4091		else if (ajax.url === '') {
4092			// No url, so don't load any data. Just apply an empty data array
4093			// to the object for the callback.
4094			var empty = {};
4095	
4096			DataTable.util.set(ajax.dataSrc)(empty, []);
4097			callback(empty);
4098		}
4099		else {
4100			// Object to extend the base settings
4101			oSettings.jqXHR = $.ajax( baseAjax );
4102	
4103			// Restore for next time around
4104			if ( ajaxData ) {
4105				ajax.data = ajaxData;
4106			}
4107		}
4108	}
4109	
4110	
4111	/**
4112	 * Update the table using an Ajax call
4113	 *  @param {object} settings dataTables settings object
4114	 *  @returns {boolean} Block the table drawing or not
4115	 *  @memberof DataTable#oApi
4116	 */
4117	function _fnAjaxUpdate( settings )
4118	{
4119		settings.iDraw++;
4120		_fnProcessingDisplay( settings, true );
4121	
4122		_fnBuildAjax(
4123			settings,
4124			_fnAjaxParameters( settings ),
4125			function(json) {
4126				_fnAjaxUpdateDraw( settings, json );
4127			}
4128		);
4129	}
4130	
4131	
4132	/**
4133	 * Build up the parameters in an object needed for a server-side processing
4134	 * request.
4135	 *  @param {object} oSettings dataTables settings object
4136	 *  @returns {bool} block the table drawing or not
4137	 *  @memberof DataTable#oApi
4138	 */
4139	function _fnAjaxParameters( settings )
4140	{
4141		var
4142			columns = settings.aoColumns,
4143			features = settings.oFeatures,
4144			preSearch = settings.oPreviousSearch,
4145			preColSearch = settings.aoPreSearchCols,
4146			colData = function ( idx, prop ) {
4147				return typeof columns[idx][prop] === 'function' ?
4148					'function' :
4149					columns[idx][prop];
4150			};
4151	
4152		return {
4153			draw: settings.iDraw,
4154			columns: columns.map( function ( column, i ) {
4155				return {
4156					data: colData(i, 'mData'),
4157					name: column.sName,
4158					searchable: column.bSearchable,
4159					orderable: column.bSortable,
4160					search: {
4161						value: preColSearch[i].search,
4162						regex: preColSearch[i].regex,
4163						fixed: Object.keys(column.searchFixed).map( function(name) {
4164							return {
4165								name: name,
4166								term: column.searchFixed[name].toString()
4167							}
4168						})
4169					}
4170				};
4171			} ),
4172			order: _fnSortFlatten( settings ).map( function ( val ) {
4173				return {
4174					column: val.col,
4175					dir: val.dir,
4176					name: colData(val.col, 'sName')
4177				};
4178			} ),
4179			start: settings._iDisplayStart,
4180			length: features.bPaginate ?
4181				settings._iDisplayLength :
4182				-1,
4183			search: {
4184				value: preSearch.search,
4185				regex: preSearch.regex,
4186				fixed: Object.keys(settings.searchFixed).map( function(name) {
4187					return {
4188						name: name,
4189						term: settings.searchFixed[name].toString()
4190					}
4191				})
4192			}
4193		};
4194	}
4195	
4196	
4197	/**
4198	 * Data the data from the server (nuking the old) and redraw the table
4199	 *  @param {object} oSettings dataTables settings object
4200	 *  @param {object} json json data return from the server.
4201	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
4202	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4203	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4204	 *  @param {array} json.aaData The data to display on this page
4205	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4206	 *  @memberof DataTable#oApi
4207	 */
4208	function _fnAjaxUpdateDraw ( settings, json )
4209	{
4210		var data = _fnAjaxDataSrc(settings, json);
4211		var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
4212		var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
4213		var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
4214	
4215		if ( draw !== undefined ) {
4216			// Protect against out of sequence returns
4217			if ( draw*1 < settings.iDraw ) {
4218				return;
4219			}
4220			settings.iDraw = draw * 1;
4221		}
4222	
4223		// No data in returned object, so rather than an array, we show an empty table
4224		if ( ! data ) {
4225			data = [];
4226		}
4227	
4228		_fnClearTable( settings );
4229		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
4230		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4231	
4232		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4233			_fnAddData( settings, data[i] );
4234		}
4235		settings.aiDisplay = settings.aiDisplayMaster.slice();
4236	
4237		_fnDraw( settings, true );
4238		_fnInitComplete( settings );
4239		_fnProcessingDisplay( settings, false );
4240	}
4241	
4242	
4243	/**
4244	 * Get the data from the JSON data source to use for drawing a table. Using
4245	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4246	 * source object, or from a processing function.
4247	 *  @param {object} settings dataTables settings object
4248	 *  @param  {object} json Data source object / array from the server
4249	 *  @return {array} Array of data to use
4250	 */
4251	function _fnAjaxDataSrc ( settings, json, write )
4252	{
4253		var dataProp = 'data';
4254	
4255		if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
4256			// Could in inside a `dataSrc` object, or not!
4257			var dataSrc = settings.ajax.dataSrc;
4258	
4259			// string, function and object are valid types
4260			if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
4261				dataProp = dataSrc;
4262			}
4263			else if (dataSrc.data !== undefined) {
4264				dataProp = dataSrc.data;
4265			}
4266		}
4267	
4268		if ( ! write ) {
4269			if ( dataProp === 'data' ) {
4270				// If the default, then we still want to support the old style, and safely ignore
4271				// it if possible
4272				return json.aaData || json[dataProp];
4273			}
4274	
4275			return dataProp !== "" ?
4276				_fnGetObjectDataFn( dataProp )( json ) :
4277				json;
4278		}
4279		
4280		// set
4281		_fnSetObjectDataFn( dataProp )( json, write );
4282	}
4283	
4284	/**
4285	 * Very similar to _fnAjaxDataSrc, but for the other SSP properties
4286	 * @param {*} settings DataTables settings object
4287	 * @param {*} param Target parameter
4288	 * @param {*} json JSON data
4289	 * @returns Resolved value
4290	 */
4291	function _fnAjaxDataSrcParam (settings, param, json) {
4292		var dataSrc = $.isPlainObject( settings.ajax )
4293			? settings.ajax.dataSrc
4294			: null;
4295	
4296		if (dataSrc && dataSrc[param]) {
4297			// Get from custom location
4298			return _fnGetObjectDataFn( dataSrc[param] )( json );
4299		}
4300	
4301		// else - Default behaviour
4302		var old = '';
4303	
4304		// Legacy support
4305		if (param === 'draw') {
4306			old = 'sEcho';
4307		}
4308		else if (param === 'recordsTotal') {
4309			old = 'iTotalRecords';
4310		}
4311		else if (param === 'recordsFiltered') {
4312			old = 'iTotalDisplayRecords';
4313		}
4314	
4315		return json[old] !== undefined
4316			? json[old]
4317			: json[param];
4318	}
4319	
4320	
4321	/**
4322	 * Filter the table using both the global filter and column based filtering
4323	 *  @param {object} settings dataTables settings object
4324	 *  @param {object} input search information
4325	 *  @memberof DataTable#oApi
4326	 */
4327	function _fnFilterComplete ( settings, input )
4328	{
4329		var columnsSearch = settings.aoPreSearchCols;
4330	
4331		// Resolve any column types that are unknown due to addition or invalidation
4332		// @todo As per sort - can this be moved into an event handler?
4333		_fnColumnTypes( settings );
4334	
4335		// In server-side processing all filtering is done by the server, so no point hanging around here
4336		if ( _fnDataSource( settings ) != 'ssp' )
4337		{
4338			// Check if any of the rows were invalidated
4339			_fnFilterData( settings );
4340	
4341			// Start from the full data set
4342			settings.aiDisplay = settings.aiDisplayMaster.slice();
4343	
4344			// Global filter first
4345			_fnFilter( settings.aiDisplay, settings, input.search, input );
4346	
4347			$.each(settings.searchFixed, function (name, term) {
4348				_fnFilter(settings.aiDisplay, settings, term, {});
4349			});
4350	
4351			// Then individual column filters
4352			for ( var i=0 ; i<columnsSearch.length ; i++ )
4353			{
4354				var col = columnsSearch[i];
4355	
4356				_fnFilter(
4357					settings.aiDisplay,
4358					settings,
4359					col.search,
4360					col,
4361					i
4362				);
4363	
4364				$.each(settings.aoColumns[i].searchFixed, function (name, term) {
4365					_fnFilter(settings.aiDisplay, settings, term, {}, i);
4366				});
4367			}
4368	
4369			// And finally global filtering
4370			_fnFilterCustom( settings );
4371		}
4372	
4373		// Tell the draw function we have been filtering
4374		settings.bFiltered = true;
4375	
4376		_fnCallbackFire( settings, null, 'search', [settings] );
4377	}
4378	
4379	
4380	/**
4381	 * Apply custom filtering functions
4382	 * 
4383	 * This is legacy now that we have named functions, but it is widely used
4384	 * from 1.x, so it is not yet deprecated.
4385	 *  @param {object} oSettings dataTables settings object
4386	 *  @memberof DataTable#oApi
4387	 */
4388	function _fnFilterCustom( settings )
4389	{
4390		var filters = DataTable.ext.search;
4391		var displayRows = settings.aiDisplay;
4392		var row, rowIdx;
4393	
4394		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4395			var rows = [];
4396	
4397			// Loop over each row and see if it should be included
4398			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4399				rowIdx = displayRows[ j ];
4400				row = settings.aoData[ rowIdx ];
4401	
4402				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4403					rows.push( rowIdx );
4404				}
4405			}
4406	
4407			// So the array reference doesn't break set the results into the
4408			// existing array
4409			displayRows.length = 0;
4410			displayRows.push.apply(displayRows, rows);
4411		}
4412	}
4413	
4414	
4415	/**
4416	 * Filter the data table based on user input and draw the table
4417	 */
4418	function _fnFilter( searchRows, settings, input, options, column )
4419	{
4420		if ( input === '' ) {
4421			return;
4422		}
4423	
4424		var i = 0;
4425		var matched = [];
4426	
4427		// Search term can be a function, regex or string - if a string we apply our
4428		// smart filtering regex (assuming the options require that)
4429		var searchFunc = typeof input === 'function' ? input : null;
4430		var rpSearch = input instanceof RegExp
4431			? input
4432			: searchFunc
4433				? null
4434				: _fnFilterCreateSearch( input, options );
4435	
4436		// Then for each row, does the test pass. If not, lop the row from the array
4437		for (i=0 ; i<searchRows.length ; i++) {
4438			var row = settings.aoData[ searchRows[i] ];
4439			var data = column === undefined
4440				? row._sFilterRow
4441				: row._aFilterData[ column ];
4442	
4443			if ( (searchFunc && searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && rpSearch.test(data)) ) {
4444				matched.push(searchRows[i]);
4445			}
4446		}
4447	
4448		// Mutate the searchRows array
4449		searchRows.length = matched.length;
4450	
4451		for (i=0 ; i<matched.length ; i++) {
4452			searchRows[i] = matched[i];
4453		}
4454	}
4455	
4456	
4457	/**
4458	 * Build a regular expression object suitable for searching a table
4459	 *  @param {string} sSearch string to search for
4460	 *  @param {bool} bRegex treat as a regular expression or not
4461	 *  @param {bool} bSmart perform smart filtering or not
4462	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4463	 *  @returns {RegExp} constructed object
4464	 *  @memberof DataTable#oApi
4465	 */
4466	function _fnFilterCreateSearch( search, inOpts )
4467	{
4468		var not = [];
4469		var options = $.extend({}, {
4470			boundary: false,
4471			caseInsensitive: true,
4472			exact: false,
4473			regex: false,
4474			smart: true
4475		}, inOpts);
4476	
4477		if (typeof search !== 'string') {
4478			search = search.toString();
4479		}
4480	
4481		// Remove diacritics if normalize is set up to do so
4482		search = _normalize(search);
4483	
4484		if (options.exact) {
4485			return new RegExp(
4486				'^'+_fnEscapeRegex(search)+'$',
4487				options.caseInsensitive ? 'i' : ''
4488			);
4489		}
4490	
4491		search = options.regex ?
4492			search :
4493			_fnEscapeRegex( search );
4494		
4495		if ( options.smart ) {
4496			/* For smart filtering we want to allow the search to work regardless of
4497			 * word order. We also want double quoted text to be preserved, so word
4498			 * order is important - a la google. And a negative look around for
4499			 * finding rows which don't contain a given string.
4500			 * 
4501			 * So this is the sort of thing we want to generate:
4502			 * 
4503			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4504			 */
4505			var parts = search.match( /!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''];
4506			var a = parts.map( function ( word ) {
4507				var negative = false;
4508				var m;
4509	
4510				// Determine if it is a "does not include"
4511				if ( word.charAt(0) === '!' ) {
4512					negative = true;
4513					word = word.substring(1);
4514				}
4515	
4516				// Strip the quotes from around matched phrases
4517				if ( word.charAt(0) === '"' ) {
4518					m = word.match( /^"(.*)"$/ );
4519					word = m ? m[1] : word;
4520				}
4521				else if ( word.charAt(0) === '\u201C' ) {
4522					// Smart quote match (iPhone users)
4523					m = word.match( /^\u201C(.*)\u201D$/ );
4524					word = m ? m[1] : word;
4525				}
4526	
4527				// For our "not" case, we need to modify the string that is
4528				// allowed to match at the end of the expression.
4529				if (negative) {
4530					if (word.length > 1) {
4531						not.push('(?!'+word+')');
4532					}
4533	
4534					word = '';
4535				}
4536	
4537				return word.replace(/"/g, '');
4538			} );
4539	
4540			var match = not.length
4541				? not.join('')
4542				: '';
4543	
4544			var boundary = options.boundary
4545				? '\\b'
4546				: '';
4547	
4548			search = '^(?=.*?'+boundary+a.join( ')(?=.*?'+boundary )+')('+match+'.)*$';
4549		}
4550	
4551		return new RegExp( search, options.caseInsensitive ? 'i' : '' );
4552	}
4553	
4554	
4555	/**
4556	 * Escape a string such that it can be used in a regular expression
4557	 *  @param {string} sVal string to escape
4558	 *  @returns {string} escaped string
4559	 *  @memberof DataTable#oApi
4560	 */
4561	var _fnEscapeRegex = DataTable.util.escapeRegex;
4562	
4563	var __filter_div = $('<div>')[0];
4564	var __filter_div_textContent = __filter_div.textContent !== undefined;
4565	
4566	// Update the filtering data for each row if needed (by invalidation or first run)
4567	function _fnFilterData ( settings )
4568	{
4569		var columns = settings.aoColumns;
4570		var data = settings.aoData;
4571		var column;
4572		var j, jen, filterData, cellData, row;
4573		var wasInvalidated = false;
4574	
4575		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
4576			if (! data[rowIdx]) {
4577				continue;
4578			}
4579	
4580			row = data[rowIdx];
4581	
4582			if ( ! row._aFilterData ) {
4583				filterData = [];
4584	
4585				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4586					column = columns[j];
4587	
4588					if ( column.bSearchable ) {
4589						cellData = _fnGetCellData( settings, rowIdx, j, 'filter' );
4590	
4591						// Search in DataTables is string based
4592						if ( cellData === null ) {
4593							cellData = '';
4594						}
4595	
4596						if ( typeof cellData !== 'string' && cellData.toString ) {
4597							cellData = cellData.toString();
4598						}
4599					}
4600					else {
4601						cellData = '';
4602					}
4603	
4604					// If it looks like there is an HTML entity in the string,
4605					// attempt to decode it so sorting works as expected. Note that
4606					// we could use a single line of jQuery to do this, but the DOM
4607					// method used here is much faster https://jsperf.com/html-decode
4608					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4609						__filter_div.innerHTML = cellData;
4610						cellData = __filter_div_textContent ?
4611							__filter_div.textContent :
4612							__filter_div.innerText;
4613					}
4614	
4615					if ( cellData.replace ) {
4616						cellData = cellData.replace(/[\r\n\u2028]/g, '');
4617					}
4618	
4619					filterData.push( cellData );
4620				}
4621	
4622				row._aFilterData = filterData;
4623				row._sFilterRow = filterData.join('  ');
4624				wasInvalidated = true;
4625			}
4626		}
4627	
4628		return wasInvalidated;
4629	}
4630	
4631	
4632	/**
4633	 * Draw the table for the first time, adding all required features
4634	 *  @param {object} settings dataTables settings object
4635	 *  @memberof DataTable#oApi
4636	 */
4637	function _fnInitialise ( settings )
4638	{
4639		var i, iAjaxStart=settings.iInitDisplayStart;
4640	
4641		/* Ensure that the table data is fully initialised */
4642		if ( ! settings.bInitialised ) {
4643			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4644			return;
4645		}
4646	
4647		/* Build and draw the header / footer for the table */
4648		_fnBuildHead( settings, 'header' );
4649		_fnBuildHead( settings, 'footer' );
4650		_fnDrawHead( settings, settings.aoHeader );
4651		_fnDrawHead( settings, settings.aoFooter );
4652	
4653		// Enable features
4654		_fnAddOptionsHtml( settings );
4655		_fnSortInit( settings );
4656	
4657		_colGroup( settings );
4658	
4659		/* Okay to show that something is going on now */
4660		_fnProcessingDisplay( settings, true );
4661	
4662		_fnCallbackFire( settings, null, 'preInit', [settings], true );
4663	
4664		// If there is default sorting required - let's do it. The sort function
4665		// will do the drawing for us. Otherwise we draw the table regardless of the
4666		// Ajax source - this allows the table to look initialised for Ajax sourcing
4667		// data (show 'loading' message possibly)
4668		_fnReDraw( settings );
4669	
4670		var dataSrc = _fnDataSource( settings );
4671	
4672		// Server-side processing init complete is done by _fnAjaxUpdateDraw
4673		if ( dataSrc != 'ssp' ) {
4674			// if there is an ajax source load the data
4675			if ( dataSrc == 'ajax' ) {
4676				_fnBuildAjax( settings, {}, function(json) {
4677					var aData = _fnAjaxDataSrc( settings, json );
4678	
4679					// Got the data - add it to the table
4680					for ( i=0 ; i<aData.length ; i++ ) {
4681						_fnAddData( settings, aData[i] );
4682					}
4683	
4684					// Reset the init display for cookie saving. We've already done
4685					// a filter, and therefore cleared it before. So we need to make
4686					// it appear 'fresh'
4687					settings.iInitDisplayStart = iAjaxStart;
4688	
4689					_fnReDraw( settings );
4690					_fnProcessingDisplay( settings, false );
4691					_fnInitComplete( settings );
4692				}, settings );
4693			}
4694			else {
4695				_fnInitComplete( settings );
4696				_fnProcessingDisplay( settings, false );
4697			}
4698		}
4699	}
4700	
4701	
4702	/**
4703	 * Draw the table for the first time, adding all required features
4704	 *  @param {object} settings dataTables settings object
4705	 *  @memberof DataTable#oApi
4706	 */
4707	function _fnInitComplete ( settings )
4708	{
4709		if (settings._bInitComplete) {
4710			return;
4711		}
4712	
4713		var args = [settings, settings.json];
4714	
4715		settings._bInitComplete = true;
4716	
4717		// Table is fully set up and we have data, so calculate the
4718		// column widths
4719		_fnAdjustColumnSizing( settings );
4720	
4721		_fnCallbackFire( settings, null, 'plugin-init', args, true );
4722		_fnCallbackFire( settings, 'aoInitComplete', 'init', args, true );
4723	}
4724	
4725	function _fnLengthChange ( settings, val )
4726	{
4727		var len = parseInt( val, 10 );
4728		settings._iDisplayLength = len;
4729	
4730		_fnLengthOverflow( settings );
4731	
4732		// Fire length change event
4733		_fnCallbackFire( settings, null, 'length', [settings, len] );
4734	}
4735	
4736	/**
4737	 * Alter the display settings to change the page
4738	 *  @param {object} settings DataTables settings object
4739	 *  @param {string|int} action Paging action to take: "first", "previous",
4740	 *    "next" or "last" or page number to jump to (integer)
4741	 *  @param [bool] redraw Automatically draw the update or not
4742	 *  @returns {bool} true page has changed, false - no change
4743	 *  @memberof DataTable#oApi
4744	 */
4745	function _fnPageChange ( settings, action, redraw )
4746	{
4747		var
4748			start     = settings._iDisplayStart,
4749			len       = settings._iDisplayLength,
4750			records   = settings.fnRecordsDisplay();
4751	
4752		if ( records === 0 || len === -1 )
4753		{
4754			start = 0;
4755		}
4756		else if ( typeof action === "number" )
4757		{
4758			start = action * len;
4759	
4760			if ( start > records )
4761			{
4762				start = 0;
4763			}
4764		}
4765		else if ( action == "first" )
4766		{
4767			start = 0;
4768		}
4769		else if ( action == "previous" )
4770		{
4771			start = len >= 0 ?
4772				start - len :
4773				0;
4774	
4775			if ( start < 0 )
4776			{
4777				start = 0;
4778			}
4779		}
4780		else if ( action == "next" )
4781		{
4782			if ( start + len < records )
4783			{
4784				start += len;
4785			}
4786		}
4787		else if ( action == "last" )
4788		{
4789			start = Math.floor( (records-1) / len) * len;
4790		}
4791		else if ( action === 'ellipsis' )
4792		{
4793			return;
4794		}
4795		else
4796		{
4797			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4798		}
4799	
4800		var changed = settings._iDisplayStart !== start;
4801		settings._iDisplayStart = start;
4802	
4803		_fnCallbackFire( settings, null, changed ? 'page' : 'page-nc', [settings] );
4804	
4805		if ( changed && redraw ) {
4806			_fnDraw( settings );
4807		}
4808	
4809		return changed;
4810	}
4811	
4812	
4813	/**
4814	 * Generate the node required for the processing node
4815	 *  @param {object} settings DataTables settings object
4816	 */
4817	function _processingHtml ( settings )
4818	{
4819		var table = settings.nTable;
4820		var scrolling = settings.oScroll.sX !== '' || settings.oScroll.sY !== '';
4821	
4822		if ( settings.oFeatures.bProcessing ) {
4823			var n = $('<div/>', {
4824					'id': settings.sTableId + '_processing',
4825					'class': settings.oClasses.processing.container,
4826					'role': 'status'
4827				} )
4828				.html( settings.oLanguage.sProcessing )
4829				.append('<div><div></div><div></div><div></div><div></div></div>');
4830	
4831			// Different positioning depending on if scrolling is enabled or not
4832			if (scrolling) {
4833				n.prependTo( $('div.dt-scroll', settings.nTableWrapper) );
4834			}
4835			else {
4836				n.insertBefore( table );
4837			}
4838	
4839			$(table).on( 'processing.dt.DT', function (e, s, show) {
4840				n.css( 'display', show ? 'block' : 'none' );
4841			} );
4842		}
4843	}
4844	
4845	
4846	/**
4847	 * Display or hide the processing indicator
4848	 *  @param {object} settings DataTables settings object
4849	 *  @param {bool} show Show the processing indicator (true) or not (false)
4850	 */
4851	function _fnProcessingDisplay ( settings, show )
4852	{
4853		_fnCallbackFire( settings, null, 'processing', [settings, show] );
4854	}
4855	/**
4856	 * Add any control elements for the table - specifically scrolling
4857	 *  @param {object} settings dataTables settings object
4858	 *  @returns {node} Node to add to the DOM
4859	 *  @memberof DataTable#oApi
4860	 */
4861	function _fnFeatureHtmlTable ( settings )
4862	{
4863		var table = $(settings.nTable);
4864	
4865		// Scrolling from here on in
4866		var scroll = settings.oScroll;
4867	
vendor: 4,403 bytes, lines 4868-5032
4868		if ( scroll.sX === '' && scroll.sY === '' ) {
4869			return settings.nTable;
4870		}
4871	
4872		var scrollX = scroll.sX;
4873		var scrollY = scroll.sY;
4874		var classes = settings.oClasses.scrolling;
4875		var caption = settings.captionNode;
4876		var captionSide = caption ? caption._captionSide : null;
4877		var headerClone = $( table[0].cloneNode(false) );
4878		var footerClone = $( table[0].cloneNode(false) );
4879		var footer = table.children('tfoot');
4880		var _div = '<div/>';
4881		var size = function ( s ) {
4882			return !s ? null : _fnStringToCss( s );
4883		};
4884	
4885		if ( ! footer.length ) {
4886			footer = null;
4887		}
4888	
4889		/*
4890		 * The HTML structure that we want to generate in this function is:
4891		 *  div - scroller
4892		 *    div - scroll head
4893		 *      div - scroll head inner
4894		 *        table - scroll head table
4895		 *          thead - thead
4896		 *    div - scroll body
4897		 *      table - table (master table)
4898		 *        thead - thead clone for sizing
4899		 *        tbody - tbody
4900		 *    div - scroll foot
4901		 *      div - scroll foot inner
4902		 *        table - scroll foot table
4903		 *          tfoot - tfoot
4904		 */
4905		var scroller = $( _div, { 'class': classes.container } )
4906			.append(
4907				$(_div, { 'class': classes.header.self } )
4908					.css( {
4909						overflow: 'hidden',
4910						position: 'relative',
4911						border: 0,
4912						width: scrollX ? size(scrollX) : '100%'
4913					} )
4914					.append(
4915						$(_div, { 'class': classes.header.inner } )
4916							.css( {
4917								'box-sizing': 'content-box',
4918								width: scroll.sXInner || '100%'
4919							} )
4920							.append(
4921								headerClone
4922									.removeAttr('id')
4923									.css( 'margin-left', 0 )
4924									.append( captionSide === 'top' ? caption : null )
4925									.append(
4926										table.children('thead')
4927									)
4928							)
4929					)
4930			)
4931			.append(
4932				$(_div, { 'class': classes.body } )
4933					.css( {
4934						position: 'relative',
4935						overflow: 'auto',
4936						width: size( scrollX )
4937					} )
4938					.append( table )
4939			);
4940	
4941		if ( footer ) {
4942			scroller.append(
4943				$(_div, { 'class': classes.footer.self } )
4944					.css( {
4945						overflow: 'hidden',
4946						border: 0,
4947						width: scrollX ? size(scrollX) : '100%'
4948					} )
4949					.append(
4950						$(_div, { 'class': classes.footer.inner } )
4951							.append(
4952								footerClone
4953									.removeAttr('id')
4954									.css( 'margin-left', 0 )
4955									.append( captionSide === 'bottom' ? caption : null )
4956									.append(
4957										table.children('tfoot')
4958									)
4959							)
4960					)
4961			);
4962		}
4963	
4964		var children = scroller.children();
4965		var scrollHead = children[0];
4966		var scrollBody = children[1];
4967		var scrollFoot = footer ? children[2] : null;
4968	
4969		// When the body is scrolled, then we also want to scroll the headers
4970		$(scrollBody).on( 'scroll.DT', function () {
4971			var scrollLeft = this.scrollLeft;
4972	
4973			scrollHead.scrollLeft = scrollLeft;
4974	
4975			if ( footer ) {
4976				scrollFoot.scrollLeft = scrollLeft;
4977			}
4978		} );
4979	
4980		// When focus is put on the header cells, we might need to scroll the body
4981		$('th, td', scrollHead).on('focus', function () {
4982			var scrollLeft = scrollHead.scrollLeft;
4983	
4984			scrollBody.scrollLeft = scrollLeft;
4985	
4986			if ( footer ) {
4987				scrollBody.scrollLeft = scrollLeft;
4988			}
4989		});
4990	
4991		$(scrollBody).css('max-height', scrollY);
4992		if (! scroll.bCollapse) {
4993			$(scrollBody).css('height', scrollY);
4994		}
4995	
4996		settings.nScrollHead = scrollHead;
4997		settings.nScrollBody = scrollBody;
4998		settings.nScrollFoot = scrollFoot;
4999	
5000		// On redraw - align columns
5001		settings.aoDrawCallback.push(_fnScrollDraw);
5002	
5003		return scroller[0];
5004	}
5005	
5006	
5007	
5008	/**
5009	 * Update the header, footer and body tables for resizing - i.e. column
5010	 * alignment.
5011	 *
5012	 * Welcome to the most horrible function DataTables. The process that this
5013	 * function follows is basically:
5014	 *   1. Re-create the table inside the scrolling div
5015	 *   2. Correct colgroup > col values if needed
5016	 *   3. Copy colgroup > col over to header and footer
5017	 *   4. Clean up
5018	 *
5019	 *  @param {object} settings dataTables settings object
5020	 *  @memberof DataTable#oApi
5021	 */
5022	function _fnScrollDraw ( settings )
5023	{
5024		// Given that this is such a monster function, a lot of variables are use
5025		// to try and keep the minimised size as small as possible
5026		var
5027			scroll         = settings.oScroll,
5028			barWidth       = scroll.iBarWidth,
5029			divHeader      = $(settings.nScrollHead),
5030			divHeaderInner = divHeader.children('div'),
5031			divHeaderTable = divHeaderInner.children('table'),
5032			divBodyEl      = settings.nScrollBody,
5033			divBody        = $(divBodyEl),
5034			divFooter      = $(settings.nScrollFoot),
5035			divFooterInner = divFooter.children('div'),
5036			divFooterTable = divFooterInner.children('table'),
5037			header         = $(settings.nTHead),
5038			table          = $(settings.nTable),
5039			footer         = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
5040			browser        = settings.oBrowser,
5041			headerCopy, footerCopy;
5042	
5043		// If the scrollbar visibility has changed from the last draw, we need to
5044		// adjust the column sizes as the table width will have changed to account
5045		// for the scrollbar
5046		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5047		
5048		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5049			settings.scrollBarVis = scrollBarVis;
5050			_fnAdjustColumnSizing( settings );
5051			return; // adjust column sizing will call this function again
5052		}
5053		else {
5054			settings.scrollBarVis = scrollBarVis;
5055		}
5056	
5057		// 1. Re-create the table inside the scrolling div
5058		// Remove the old minimised thead and tfoot elements in the inner table
5059		table.children('thead, tfoot').remove();
5060	
5061		// Clone the current header and footer elements and then place it into the inner table
5062		headerCopy = header.clone().prependTo( table );
5063		headerCopy.find('th, td').removeAttr('tabindex');
5064		headerCopy.find('[id]').removeAttr('id');
5065	
5066		if ( footer ) {
5067			footerCopy = footer.clone().prependTo( table );
5068			footerCopy.find('[id]').removeAttr('id');
5069		}
5070	
5071		// 2. Correct colgroup > col values if needed
5072		// It is possible that the cell sizes are smaller than the content, so we need to
5073		// correct colgroup>col for such cases. This can happen if the auto width detection
5074		// uses a cell which has a longer string, but isn't the widest! For example 
5075		// "Chief Executive Officer (CEO)" is the longest string in the demo, but
5076		// "Systems Administrator" is actually the widest string since it doesn't collapse.
5077		// Note the use of translating into a column index to get the `col` element. This
5078		// is because of Responsive which might remove `col` elements, knocking the alignment
5079		// of the indexes out.
5080		if (settings.aiDisplay.length) {
5081			// Get the column sizes from the first row in the table
5082			var colSizes = table.children('tbody').eq(0).children('tr').eq(0).children('th, td').map(function (vis) {
5083				return {
5084					idx: _fnVisibleToColumnIndex(settings, vis),
5085					width: $(this).outerWidth()
5086				}
5087			});
5088	
5089			// Check against what the colgroup > col is set to and correct if needed
5090			for (var i=0 ; i<colSizes.length ; i++) {
5091				var colEl = settings.aoColumns[ colSizes[i].idx ].colEl[0];
5092				var colWidth = colEl.style.width.replace('px', '');
5093	
5094				if (colWidth !== colSizes[i].width) {
5095					colEl.style.width = colSizes[i].width + 'px';
5096				}
5097			}
5098		}
5099	
5100		// 3. Copy the colgroup over to the header and footer
5101		divHeaderTable
5102			.find('colgroup')
5103			.remove();
5104	
5105		divHeaderTable.append(settings.colgroup.clone());
5106	
5107		if ( footer ) {
5108			divFooterTable
5109				.find('colgroup')
5110				.remove();
5111	
5112			divFooterTable.append(settings.colgroup.clone());
5113		}
5114	
5115		// "Hide" the header and footer that we used for the sizing. We need to keep
5116		// the content of the cell so that the width applied to the header and body
5117		// both match, but we want to hide it completely.
5118		$('th, td', headerCopy).each(function () {
5119			$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5120		});
5121	
5122		if ( footer ) {
5123			$('th, td', footerCopy).each(function () {
5124				$(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5125			});
5126		}
5127	
5128		// 4. Clean up
5129		// Figure out if there are scrollbar present - if so then we need a the header and footer to
5130		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5131		var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5132		var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5133	
5134		// Set the width's of the header and footer tables
5135		var outerWidth = table.outerWidth();
5136	
5137		divHeaderTable.css('width', _fnStringToCss( outerWidth ));
5138		divHeaderInner
5139			.css('width', _fnStringToCss( outerWidth ))
5140			.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5141	
5142		if ( footer ) {
5143			divFooterTable.css('width', _fnStringToCss( outerWidth ));
5144			divFooterInner
5145				.css('width', _fnStringToCss( outerWidth ))
5146				.css(paddingSide, isScrolling ? barWidth+"px" : "0px");
5147		}
5148	
5149		// Correct DOM ordering for colgroup - comes before the thead
5150		table.children('colgroup').prependTo(table);
5151	
5152		// Adjust the position of the header in case we loose the y-scrollbar
5153		divBody.trigger('scroll');
5154	
5155		// If sorting or filtering has occurred, jump the scrolling back to the top
5156		// only if we aren't holding the position
5157		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5158			divBodyEl.scrollTop = 0;
5159		}
5160	}
5161	
5162	/**
5163	 * Calculate the width of columns for the table
5164	 *  @param {object} settings dataTables settings object
5165	 *  @memberof DataTable#oApi
5166	 */
5167	function _fnCalculateColumnWidths ( settings )
5168	{
5169		// Not interested in doing column width calculation if auto-width is disabled
5170		if (! settings.oFeatures.bAutoWidth) {
5171			return;
5172		}
5173	
5174		var
5175			table = settings.nTable,
5176			columns = settings.aoColumns,
5177			scroll = settings.oScroll,
5178			scrollY = scroll.sY,
5179			scrollX = scroll.sX,
5180			scrollXInner = scroll.sXInner,
5181			visibleColumns = _fnGetColumns( settings, 'bVisible' ),
5182			tableWidthAttr = table.getAttribute('width'), // from DOM element
5183			tableContainer = table.parentNode,
5184			i, column, columnIdx;
5185	
5186		var styleWidth = table.style.width;
5187		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5188			tableWidthAttr = styleWidth;
5189		}
5190	
5191		// Let plug-ins know that we are doing a recalc, in case they have changed any of the
5192		// visible columns their own way (e.g. Responsive uses display:none).
5193		_fnCallbackFire(
5194			settings,
5195			null,
5196			'column-calc',
5197			{visible: visibleColumns},
5198			false
5199		);
5200	
5201		// Construct a single row, worst case, table with the widest
5202		// node in the data, assign any user defined widths, then insert it into
5203		// the DOM and allow the browser to do all the hard work of calculating
5204		// table widths
5205		var tmpTable = $(table.cloneNode())
5206			.css( 'visibility', 'hidden' )
5207			.removeAttr( 'id' );
5208	
5209		// Clean up the table body
5210		tmpTable.append('<tbody>')
5211		var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5212	
5213		// Clone the table header and footer - we can't use the header / footer
5214		// from the cloned table, since if scrolling is active, the table's
5215		// real header and footer are contained in different table tags
5216		tmpTable
5217			.append( $(settings.nTHead).clone() )
5218			.append( $(settings.nTFoot).clone() );
5219	
5220		// Remove any assigned widths from the footer (from scrolling)
5221		tmpTable.find('tfoot th, tfoot td').css('width', '');
5222	
5223		// Apply custom sizing to the cloned header
5224		tmpTable.find('thead th, thead td').each( function () {
5225			// Get the `width` from the header layout
5226			var width = _fnColumnsSumWidth( settings, this, true, false );
5227	
5228			if ( width ) {
5229				this.style.width = width;
5230	
5231				// For scrollX we need to force the column width otherwise the
5232				// browser will collapse it. If this width is smaller than the
5233				// width the column requires, then it will have no effect
5234				if ( scrollX ) {
5235					$( this ).append( $('<div/>').css( {
5236						width: width,
5237						margin: 0,
5238						padding: 0,
5239						border: 0,
5240						height: 1
5241					} ) );
5242				}
5243			}
5244			else {
5245				this.style.width = '';
5246			}
5247		} );
5248	
5249		// Find the widest piece of data for each column and put it into the table
5250		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5251			columnIdx = visibleColumns[i];
5252			column = columns[ columnIdx ];
5253	
5254			var longest = _fnGetMaxLenString(settings, columnIdx);
5255			var autoClass = _ext.type.className[column.sType];
5256			var text = longest + column.sContentPadding;
5257			var insert = longest.indexOf('<') === -1
5258				? document.createTextNode(text)
5259				: text
5260			
5261			$('<td/>')
5262				.addClass(autoClass)
5263				.addClass(column.sClass)
5264				.append(insert)
5265				.appendTo(tr);
5266		}
5267	
5268		// Tidy the temporary table - remove name attributes so there aren't
5269		// duplicated in the dom (radio elements for example)
5270		$('[name]', tmpTable).removeAttr('name');
5271	
5272		// Table has been built, attach to the document so we can work with it.
5273		// A holding element is used, positioned at the top of the container
5274		// with minimal height, so it has no effect on if the container scrolls
5275		// or not. Otherwise it might trigger scrolling when it actually isn't
5276		// needed
5277		var holder = $('<div/>').css( scrollX || scrollY ?
5278				{
5279					position: 'absolute',
5280					top: 0,
5281					left: 0,
5282					height: 1,
5283					right: 0,
5284					overflow: 'hidden'
5285				} :
5286				{}
5287			)
5288			.append( tmpTable )
5289			.appendTo( tableContainer );
5290	
5291		// When scrolling (X or Y) we want to set the width of the table as 
5292		// appropriate. However, when not scrolling leave the table width as it
5293		// is. This results in slightly different, but I think correct behaviour
5294		if ( scrollX && scrollXInner ) {
5295			tmpTable.width( scrollXInner );
5296		}
5297		else if ( scrollX ) {
5298			tmpTable.css( 'width', 'auto' );
5299			tmpTable.removeAttr('width');
5300	
5301			// If there is no width attribute or style, then allow the table to
5302			// collapse
5303			if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5304				tmpTable.width( tableContainer.clientWidth );
5305			}
5306		}
5307		else if ( scrollY ) {
5308			tmpTable.width( tableContainer.clientWidth );
5309		}
5310		else if ( tableWidthAttr ) {
5311			tmpTable.width( tableWidthAttr );
5312		}
5313	
5314		// Get the width of each column in the constructed table
5315		var total = 0;
5316		var bodyCells = tmpTable.find('tbody tr').eq(0).children();
5317	
5318		for ( i=0 ; i<visibleColumns.length ; i++ ) {
5319			// Use getBounding for sub-pixel accuracy, which we then want to round up!
5320			var bounding = bodyCells[i].getBoundingClientRect().width;
5321	
5322			// Total is tracked to remove any sub-pixel errors as the outerWidth
5323			// of the table might not equal the total given here
5324			total += bounding;
5325	
5326			// Width for each column to use
5327			columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding );
5328		}
5329	
5330		table.style.width = _fnStringToCss( total );
5331	
5332		// Finished with the table - ditch it
5333		holder.remove();
5334	
5335		// If there is a width attr, we want to attach an event listener which
5336		// allows the table sizing to automatically adjust when the window is
5337		// resized. Use the width attr rather than CSS, since we can't know if the
5338		// CSS is a relative value or absolute - DOM read is always px.
5339		if ( tableWidthAttr ) {
5340			table.style.width = _fnStringToCss( tableWidthAttr );
5341		}
5342	
5343		if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
5344			var bindResize = function () {
5345				$(window).on('resize.DT-'+settings.sInstance, DataTable.util.throttle( function () {
5346					if (! settings.bDestroying) {
5347						_fnAdjustColumnSizing( settings );
5348					}
5349				} ) );
5350			};
5351	
5352			bindResize();
5353	
5354			settings._reszEvt = true;
5355		}
5356	}
5357	
5358	
5359	/**
5360	 * Get the maximum strlen for each data column
5361	 *  @param {object} settings dataTables settings object
5362	 *  @param {int} colIdx column of interest
5363	 *  @returns {string} string of the max length
5364	 *  @memberof DataTable#oApi
5365	 */
5366	function _fnGetMaxLenString( settings, colIdx )
5367	{
5368		var column = settings.aoColumns[colIdx];
5369	
5370		if (! column.maxLenString) {
5371			var s, max='', maxLen = -1;
5372		
5373			for ( var i=0, ien=settings.aiDisplayMaster.length ; i<ien ; i++ ) {
5374				var rowIdx = settings.aiDisplayMaster[i];
5375				var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
5376	
5377				var cellString = data && typeof data === 'object' && data.nodeType
5378					? data.innerHTML
5379					: data+'';
5380	
5381				// Remove id / name attributes from elements so they
5382				// don't interfere with existing elements
5383				cellString = cellString
5384					.replace(/id=".*?"/g, '')
5385					.replace(/name=".*?"/g, '');
5386	
5387				s = _stripHtml(cellString)
5388					.replace( /&nbsp;/g, ' ' );
5389		
5390				if ( s.length > maxLen ) {
5391					// We want the HTML in the string, but the length that
5392					// is important is the stripped string
5393					max = cellString;
5394					maxLen = s.length;
5395				}
5396			}
5397	
5398			column.maxLenString = max;
5399		}
5400	
5401		return column.maxLenString;
5402	}
5403	
5404	
5405	/**
5406	 * Append a CSS unit (only if required) to a string
5407	 *  @param {string} value to css-ify
5408	 *  @returns {string} value with css unit
5409	 *  @memberof DataTable#oApi
5410	 */
5411	function _fnStringToCss( s )
5412	{
5413		if ( s === null ) {
5414			return '0px';
5415		}
5416	
5417		if ( typeof s == 'number' ) {
5418			return s < 0 ?
5419				'0px' :
5420				s+'px';
5421		}
5422	
5423		// Check it has a unit character already
5424		return s.match(/\d$/) ?
5425			s+'px' :
5426			s;
5427	}
5428	
5429	/**
5430	 * Re-insert the `col` elements for current visibility
5431	 *
5432	 * @param {*} settings DT settings
5433	 */
5434	function _colGroup( settings ) {
5435		var cols = settings.aoColumns;
5436	
5437		settings.colgroup.empty();
5438	
5439		for (i=0 ; i<cols.length ; i++) {
5440			if (cols[i].bVisible) {
5441				settings.colgroup.append(cols[i].colEl);
5442			}
5443		}
5444	}
5445	
5446	
5447	function _fnSortInit( settings ) {
5448		var target = settings.nTHead;
5449		var headerRows = target.querySelectorAll('tr');
5450		var legacyTop = settings.bSortCellsTop;
5451		var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5452		
5453		// Legacy support for `orderCellsTop`
5454		if (legacyTop === true) {
5455			target = headerRows[0];
5456		}
5457		else if (legacyTop === false) {
5458			target = headerRows[ headerRows.length - 1 ];
5459		}
5460	
5461		_fnSortAttachListener(
5462			settings,
5463			target,
5464			target === settings.nTHead
5465				? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5466				: 'th'+notSelector+', td'+notSelector
5467		);
5468	
5469		// Need to resolve the user input array into our internal structure
5470		var order = [];
5471		_fnSortResolve( settings, order, settings.aaSorting );
5472	
5473		settings.aaSorting = order;
5474	}
5475	
5476	
5477	function _fnSortAttachListener(settings, node, selector, column, callback) {
5478		_fnBindAction( node, selector, function (e) {
5479			var run = false;
5480			var columns = column === undefined
5481				? _fnColumnsFromHeader( e.target )
5482				: [column];
5483	
5484			if ( columns.length ) {
5485				for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
5486					var ret = _fnSortAdd( settings, columns[i], i, e.shiftKey );
5487	
5488					if (ret !== false) {
5489						run = true;
5490					}					
5491	
5492					// If the first entry is no sort, then subsequent
5493					// sort columns are ignored
5494					if (settings.aaSorting.length === 1 && settings.aaSorting[0][1] === '') {
5495						break;
5496					}
5497				}
5498	
5499				if (run) {
5500					_fnProcessingDisplay( settings, true );
5501	
5502					// Allow the processing display to show
5503					setTimeout( function () {
5504						_fnSort( settings );
5505						_fnSortDisplay( settings, settings.aiDisplay );
5506	
5507						// Sort processing done - redraw has its own processing display
5508						_fnProcessingDisplay( settings, false );
5509	
5510						_fnReDraw( settings, false, false );
5511	
5512						if (callback) {
5513							callback();
5514						}
5515					}, 0);
5516				}
5517			}
5518		} );
5519	}
5520	
5521	/**
5522	 * Sort the display array to match the master's order
5523	 * @param {*} settings
5524	 */
5525	function _fnSortDisplay(settings, display) {
5526		if (display.length < 2) {
5527			return;
5528		}
5529	
5530		var master = settings.aiDisplayMaster;
5531		var masterMap = {};
5532		var map = {};
5533		var i;
5534	
5535		// Rather than needing an `indexOf` on master array, we can create a map
5536		for (i=0 ; i<master.length ; i++) {
5537			masterMap[master[i]] = i;
5538		}
5539	
5540		// And then cache what would be the indexOf fom the display
5541		for (i=0 ; i<display.length ; i++) {
5542			map[display[i]] = masterMap[display[i]];
5543		}
5544	
5545		display.sort(function(a, b){
5546			// Short version of this function is simply `master.indexOf(a) - master.indexOf(b);`
5547			return map[a] - map[b];
5548		});
5549	}
5550	
5551	
5552	function _fnSortResolve (settings, nestedSort, sort) {
5553		var push = function ( a ) {
5554			if ($.isPlainObject(a)) {
5555				if (a.idx !== undefined) {
5556					// Index based ordering
5557					nestedSort.push([a.idx, a.dir]);
5558				}
5559				else if (a.name) {
5560					// Name based ordering
5561					var cols = _pluck( settings.aoColumns, 'sName');
5562					var idx = cols.indexOf(a.name);
5563	
5564					if (idx !== -1) {
5565						nestedSort.push([idx, a.dir]);
5566					}
5567				}
5568			}
5569			else {
5570				// Plain column index and direction pair
5571				nestedSort.push(a);
5572			}
5573		};
5574	
5575		if ( $.isPlainObject(sort) ) {
5576			// Object
5577			push(sort);
5578		}
5579		else if ( sort.length && typeof sort[0] === 'number' ) {
5580			// 1D array
5581			push(sort);
5582		}
5583		else if ( sort.length ) {
5584			// 2D array
5585			for (var z=0; z<sort.length; z++) {
5586				push(sort[z]); // Object or array
5587			}
5588		}
5589	}
5590	
5591	
5592	function _fnSortFlatten ( settings )
5593	{
5594		var
5595			i, k, kLen,
5596			aSort = [],
5597			extSort = DataTable.ext.type.order,
5598			aoColumns = settings.aoColumns,
5599			aDataSort, iCol, sType, srcCol,
5600			fixed = settings.aaSortingFixed,
5601			fixedObj = $.isPlainObject( fixed ),
5602			nestedSort = [];
5603		
5604		if ( ! settings.oFeatures.bSort ) {
5605			return aSort;
5606		}
5607	
5608		// Build the sort array, with pre-fix and post-fix options if they have been
5609		// specified
5610		if ( Array.isArray( fixed ) ) {
5611			_fnSortResolve( settings, nestedSort, fixed );
5612		}
5613	
5614		if ( fixedObj && fixed.pre ) {
5615			_fnSortResolve( settings, nestedSort, fixed.pre );
5616		}
5617	
5618		_fnSortResolve( settings, nestedSort, settings.aaSorting );
5619	
5620		if (fixedObj && fixed.post ) {
5621			_fnSortResolve( settings, nestedSort, fixed.post );
5622		}
5623	
5624		for ( i=0 ; i<nestedSort.length ; i++ )
5625		{
5626			srcCol = nestedSort[i][0];
5627	
5628			if ( aoColumns[ srcCol ] ) {
5629				aDataSort = aoColumns[ srcCol ].aDataSort;
5630	
5631				for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5632				{
5633					iCol = aDataSort[k];
5634					sType = aoColumns[ iCol ].sType || 'string';
5635	
5636					if ( nestedSort[i]._idx === undefined ) {
5637						nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
5638					}
5639	
5640					if ( nestedSort[i][1] ) {
5641						aSort.push( {
5642							src:       srcCol,
5643							col:       iCol,
5644							dir:       nestedSort[i][1],
5645							index:     nestedSort[i]._idx,
5646							type:      sType,
5647							formatter: extSort[ sType+"-pre" ],
5648							sorter:    extSort[ sType+"-"+nestedSort[i][1] ]
5649						} );
5650					}
5651				}
5652			}
5653		}
5654	
5655		return aSort;
5656	}
5657	
5658	/**
5659	 * Change the order of the table
5660	 *  @param {object} oSettings dataTables settings object
5661	 *  @memberof DataTable#oApi
5662	 */
5663	function _fnSort ( oSettings, col, dir )
5664	{
5665		var
5666			i, ien, iLen,
5667			aiOrig = [],
5668			extSort = DataTable.ext.type.order,
5669			aoData = oSettings.aoData,
5670			sortCol,
5671			displayMaster = oSettings.aiDisplayMaster,
5672			aSort;
5673	
5674		// Resolve any column types that are unknown due to addition or invalidation
5675		// @todo Can this be moved into a 'data-ready' handler which is called when
5676		//   data is going to be used in the table?
5677		_fnColumnTypes( oSettings );
5678	
5679		// Allow a specific column to be sorted, which will _not_ alter the display
5680		// master
5681		if (col !== undefined) {
5682			var srcCol = oSettings.aoColumns[col];
5683			aSort = [{
5684				src:       col,
5685				col:       col,
5686				dir:       dir,
5687				index:     0,
5688				type:      srcCol.sType,
5689				formatter: extSort[ srcCol.sType+"-pre" ],
5690				sorter:    extSort[ srcCol.sType+"-"+dir ]
5691			}];
5692			displayMaster = displayMaster.slice();
5693		}
5694		else {
5695			aSort = _fnSortFlatten( oSettings );
5696		}
5697	
5698		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5699			sortCol = aSort[i];
5700	
5701			// Load the data needed for the sort, for each cell
5702			_fnSortData( oSettings, sortCol.col );
5703		}
5704	
5705		/* No sorting required if server-side or no sorting array */
5706		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5707		{
5708			// Reset the initial positions on each pass so we get a stable sort
5709			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5710				aiOrig[ i ] = i;
5711			}
5712	
5713			// If the first sort is desc, then reverse the array to preserve original
5714			// order, just in reverse
5715			if (aSort.length && aSort[0].dir === 'desc') {
5716				aiOrig.reverse();
5717			}
5718	
5719			/* Do the sort - here we want multi-column sorting based on a given data source (column)
5720			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5721			 * follow on it's own, but this is what we want (example two column sorting):
5722			 *  fnLocalSorting = function(a,b){
5723			 *    var test;
5724			 *    test = oSort['string-asc']('data11', 'data12');
5725			 *      if (test !== 0)
5726			 *        return test;
5727			 *    test = oSort['numeric-desc']('data21', 'data22');
5728			 *    if (test !== 0)
5729			 *      return test;
5730			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5731			 *  }
5732			 * Basically we have a test for each sorting column, if the data in that column is equal,
5733			 * test the next column. If all columns match, then we use a numeric sort on the row
5734			 * positions in the original data array to provide a stable sort.
5735			 */
5736			displayMaster.sort( function ( a, b ) {
5737				var
5738					x, y, k, test, sort,
5739					len=aSort.length,
5740					dataA = aoData[a]._aSortData,
5741					dataB = aoData[b]._aSortData;
5742	
5743				for ( k=0 ; k<len ; k++ ) {
5744					sort = aSort[k];
5745	
5746					// Data, which may have already been through a `-pre` function
5747					x = dataA[ sort.col ];
5748					y = dataB[ sort.col ];
5749	
5750					if (sort.sorter) {
5751						// If there is a custom sorter (`-asc` or `-desc`) for this
5752						// data type, use it
5753						test = sort.sorter(x, y);
5754	
5755						if ( test !== 0 ) {
5756							return test;
5757						}
5758					}
5759					else {
5760						// Otherwise, use generic sorting
5761						test = x<y ? -1 : x>y ? 1 : 0;
5762	
5763						if ( test !== 0 ) {
5764							return sort.dir === 'asc' ? test : -test;
5765						}
5766					}
5767				}
5768	
5769				x = aiOrig[a];
5770				y = aiOrig[b];
5771	
5772				return x<y ? -1 : x>y ? 1 : 0;
5773			} );
5774		}
5775		else if ( aSort.length === 0 ) {
5776			// Apply index order
5777			displayMaster.sort(function (x, y) {
5778				return x<y ? -1 : x>y ? 1 : 0;
5779			});
5780		}
5781	
5782		if (col === undefined) {
5783			// Tell the draw function that we have sorted the data
5784			oSettings.bSorted = true;
5785	
5786			_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort] );
5787		}
5788	
5789		return displayMaster;
5790	}
5791	
5792	
5793	/**
5794	 * Function to run on user sort request
5795	 *  @param {object} settings dataTables settings object
5796	 *  @param {node} attachTo node to attach the handler to
5797	 *  @param {int} colIdx column sorting index
5798	 *  @param {int} addIndex Counter
5799	 *  @param {boolean} [shift=false] Shift click add
5800	 *  @param {function} [callback] callback function
5801	 *  @memberof DataTable#oApi
5802	 */
5803	function _fnSortAdd ( settings, colIdx, addIndex, shift )
5804	{
5805		var col = settings.aoColumns[ colIdx ];
5806		var sorting = settings.aaSorting;
5807		var asSorting = col.asSorting;
5808		var nextSortIdx;
5809		var next = function ( a, overflow ) {
5810			var idx = a._idx;
5811			if ( idx === undefined ) {
5812				idx = asSorting.indexOf(a[1]);
5813			}
5814	
5815			return idx+1 < asSorting.length ?
5816				idx+1 :
5817				overflow ?
5818					null :
5819					0;
5820		};
5821	
5822		if ( ! col.bSortable ) {
5823			return false;
5824		}
5825	
5826		// Convert to 2D array if needed
5827		if ( typeof sorting[0] === 'number' ) {
5828			sorting = settings.aaSorting = [ sorting ];
5829		}
5830	
5831		// If appending the sort then we are multi-column sorting
5832		if ( (shift || addIndex) && settings.oFeatures.bSortMulti ) {
5833			// Are we already doing some kind of sort on this column?
5834			var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
5835	
5836			if ( sortIdx !== -1 ) {
5837				// Yes, modify the sort
5838				nextSortIdx = next( sorting[sortIdx], true );
5839	
5840				if ( nextSortIdx === null && sorting.length === 1 ) {
5841					nextSortIdx = 0; // can't remove sorting completely
5842				}
5843	
5844				if ( nextSortIdx === null ) {
5845					sorting.splice( sortIdx, 1 );
5846				}
5847				else {
5848					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
5849					sorting[sortIdx]._idx = nextSortIdx;
5850				}
5851			}
5852			else if (shift) {
5853				// No sort on this column yet, being added by shift click
5854				// add it as itself
5855				sorting.push( [ colIdx, asSorting[0], 0 ] );
5856				sorting[sorting.length-1]._idx = 0;
5857			}
5858			else {
5859				// No sort on this column yet, being added from a colspan
5860				// so add with same direction as first column
5861				sorting.push( [ colIdx, sorting[0][1], 0 ] );
5862				sorting[sorting.length-1]._idx = 0;
5863			}
5864		}
5865		else if ( sorting.length && sorting[0][0] == colIdx ) {
5866			// Single column - already sorting on this column, modify the sort
5867			nextSortIdx = next( sorting[0] );
5868	
5869			sorting.length = 1;
5870			sorting[0][1] = asSorting[ nextSortIdx ];
5871			sorting[0]._idx = nextSortIdx;
5872		}
5873		else {
5874			// Single column - sort only on this column
5875			sorting.length = 0;
5876			sorting.push( [ colIdx, asSorting[0] ] );
5877			sorting[0]._idx = 0;
5878		}
5879	}
5880	
5881	
5882	/**
5883	 * Set the sorting classes on table's body, Note: it is safe to call this function
5884	 * when bSort and bSortClasses are false
5885	 *  @param {object} oSettings dataTables settings object
5886	 *  @memberof DataTable#oApi
5887	 */
5888	function _fnSortingClasses( settings )
5889	{
5890		var oldSort = settings.aLastSort;
5891		var sortClass = settings.oClasses.order.position;
5892		var sort = _fnSortFlatten( settings );
5893		var features = settings.oFeatures;
5894		var i, ien, colIdx;
5895	
5896		if ( features.bSort && features.bSortClasses ) {
5897			// Remove old sorting classes
5898			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
5899				colIdx = oldSort[i].src;
5900	
5901				// Remove column sorting
5902				$( _pluck( settings.aoData, 'anCells', colIdx ) )
5903					.removeClass( sortClass + (i<2 ? i+1 : 3) );
5904			}
5905	
5906			// Add new column sorting
5907			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
5908				colIdx = sort[i].src;
5909	
5910				$( _pluck( settings.aoData, 'anCells', colIdx ) )
5911					.addClass( sortClass + (i<2 ? i+1 : 3) );
5912			}
5913		}
5914	
5915		settings.aLastSort = sort;
5916	}
5917	
5918	
5919	// Get the data to sort a column, be it from cache, fresh (populating the
5920	// cache), or from a sort formatter
5921	function _fnSortData( settings, colIdx )
5922	{
5923		// Custom sorting function - provided by the sort data type
5924		var column = settings.aoColumns[ colIdx ];
5925		var customSort = DataTable.ext.order[ column.sSortDataType ];
5926		var customData;
5927	
5928		if ( customSort ) {
5929			customData = customSort.call( settings.oInstance, settings, colIdx,
5930				_fnColumnIndexToVisible( settings, colIdx )
5931			);
5932		}
5933	
5934		// Use / populate cache
5935		var row, cellData;
5936		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
5937		var data = settings.aoData;
5938	
5939		for ( var rowIdx=0 ; rowIdx<data.length ; rowIdx++ ) {
5940			// Sparse array
5941			if (! data[rowIdx]) {
5942				continue;
5943			}
5944	
5945			row = data[rowIdx];
5946	
5947			if ( ! row._aSortData ) {
5948				row._aSortData = [];
5949			}
5950	
5951			if ( ! row._aSortData[colIdx] || customSort ) {
5952				cellData = customSort ?
5953					customData[rowIdx] : // If there was a custom sort function, use data from there
5954					_fnGetCellData( settings, rowIdx, colIdx, 'sort' );
5955	
5956				row._aSortData[ colIdx ] = formatter ?
5957					formatter( cellData, settings ) :
5958					cellData;
5959			}
5960		}
5961	}
5962	
5963	
5964	/**
5965	 * State information for a table
5966	 *
5967	 * @param {*} settings
5968	 * @returns State object
5969	 */
5970	function _fnSaveState ( settings )
5971	{
5972		if (settings._bLoadingState) {
5973			return;
5974		}
5975	
5976		/* Store the interesting variables */
5977		var state = {
5978			time:    +new Date(),
5979			start:   settings._iDisplayStart,
5980			length:  settings._iDisplayLength,
5981			order:   $.extend( true, [], settings.aaSorting ),
5982			search:  $.extend({}, settings.oPreviousSearch),
5983			columns: settings.aoColumns.map( function ( col, i ) {
5984				return {
5985					visible: col.bVisible,
5986					search: $.extend({}, settings.aoPreSearchCols[i])
5987				};
5988			} )
5989		};
5990	
5991		settings.oSavedState = state;
5992		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
5993		
vendor: 17,306 bytes, lines 5994-6578
5994		if ( settings.oFeatures.bStateSave && !settings.bDestroying )
5995		{
5996			settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
5997		}	
5998	}
5999	
6000	
6001	/**
6002	 * Attempt to load a saved table state
6003	 *  @param {object} oSettings dataTables settings object
6004	 *  @param {object} oInit DataTables init object so we can override settings
6005	 *  @param {function} callback Callback to execute when the state has been loaded
6006	 *  @memberof DataTable#oApi
6007	 */
6008	function _fnLoadState ( settings, init, callback )
6009	{
6010		if ( ! settings.oFeatures.bStateSave ) {
6011			callback();
6012			return;
6013		}
6014	
6015		var loaded = function(state) {
6016			_fnImplementState(settings, state, callback);
6017		}
6018	
6019		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6020	
6021		if ( state !== undefined ) {
6022			_fnImplementState( settings, state, callback );
6023		}
6024		// otherwise, wait for the loaded callback to be executed
6025	
6026		return true;
6027	}
6028	
6029	function _fnImplementState ( settings, s, callback) {
6030		var i, ien;
6031		var columns = settings.aoColumns;
6032		settings._bLoadingState = true;
6033	
6034		// When StateRestore was introduced the state could now be implemented at any time
6035		// Not just initialisation. To do this an api instance is required in some places
6036		var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
6037	
6038		if ( ! s || ! s.time ) {
6039			settings._bLoadingState = false;
6040			callback();
6041			return;
6042		}
6043	
6044		// Reject old data
6045		var duration = settings.iStateDuration;
6046		if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6047			settings._bLoadingState = false;
6048			callback();
6049			return;
6050		}
6051	
6052		// Allow custom and plug-in manipulation functions to alter the saved data set and
6053		// cancelling of loading by returning false
6054		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6055		if ( abStateLoad.indexOf(false) !== -1 ) {
6056			settings._bLoadingState = false;
6057			callback();
6058			return;
6059		}
6060	
6061		// Number of columns have changed - all bets are off, no restore of settings
6062		if ( s.columns && columns.length !== s.columns.length ) {
6063			settings._bLoadingState = false;
6064			callback();
6065			return;
6066		}
6067	
6068		// Store the saved state so it might be accessed at any time
6069		settings.oLoadedState = $.extend( true, {}, s );
6070	
6071		// This is needed for ColReorder, which has to happen first to allow all
6072		// the stored indexes to be usable. It is not publicly documented.
6073		_fnCallbackFire( settings, null, 'stateLoadInit', [settings, s], true );
6074	
6075		// Page Length
6076		if ( s.length !== undefined ) {
6077			// If already initialised just set the value directly so that the select element is also updated
6078			if (api) {
6079				api.page.len(s.length)
6080			}
6081			else {
6082				settings._iDisplayLength   = s.length;
6083			}
6084		}
6085	
6086		// Restore key features - todo - for 1.11 this needs to be done by
6087		// subscribed events
6088		if ( s.start !== undefined ) {
6089			if(api === null) {
6090				settings._iDisplayStart    = s.start;
6091				settings.iInitDisplayStart = s.start;
6092			}
6093			else {
6094				_fnPageChange(settings, s.start/settings._iDisplayLength);
6095			}
6096		}
6097	
6098		// Order
6099		if ( s.order !== undefined ) {
6100			settings.aaSorting = [];
6101			$.each( s.order, function ( i, col ) {
6102				settings.aaSorting.push( col[0] >= columns.length ?
6103					[ 0, col[1] ] :
6104					col
6105				);
6106			} );
6107		}
6108	
6109		// Search
6110		if ( s.search !== undefined ) {
6111			$.extend( settings.oPreviousSearch, s.search );
6112		}
6113	
6114		// Columns
6115		if ( s.columns ) {
6116			for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6117				var col = s.columns[i];
6118	
6119				// Visibility
6120				if ( col.visible !== undefined ) {
6121					// If the api is defined, the table has been initialised so we need to use it rather than internal settings
6122					if (api) {
6123						// Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6124						api.column(i).visible(col.visible, false);
6125					}
6126					else {
6127						columns[i].bVisible = col.visible;
6128					}
6129				}
6130	
6131				// Search
6132				if ( col.search !== undefined ) {
6133					$.extend( settings.aoPreSearchCols[i], col.search );
6134				}
6135			}
6136			
6137			// If the api is defined then we need to adjust the columns once the visibility has been changed
6138			if (api) {
6139				api.columns.adjust();
6140			}
6141		}
6142	
6143		settings._bLoadingState = false;
6144		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6145		callback();
6146	}
6147	
6148	/**
6149	 * Log an error message
6150	 *  @param {object} settings dataTables settings object
6151	 *  @param {int} level log error messages, or display them to the user
6152	 *  @param {string} msg error message
6153	 *  @param {int} tn Technical note id to get more information about the error.
6154	 *  @memberof DataTable#oApi
6155	 */
6156	function _fnLog( settings, level, msg, tn )
6157	{
6158		msg = 'DataTables warning: '+
6159			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6160	
6161		if ( tn ) {
6162			msg += '. For more information about this error, please see '+
6163			'https://datatables.net/tn/'+tn;
6164		}
6165	
6166		if ( ! level  ) {
6167			// Backwards compatibility pre 1.10
6168			var ext = DataTable.ext;
6169			var type = ext.sErrMode || ext.errMode;
6170	
6171			if ( settings ) {
6172				_fnCallbackFire( settings, null, 'dt-error', [ settings, tn, msg ], true );
6173			}
6174	
6175			if ( type == 'alert' ) {
6176				alert( msg );
6177			}
6178			else if ( type == 'throw' ) {
6179				throw new Error(msg);
6180			}
6181			else if ( typeof type == 'function' ) {
6182				type( settings, tn, msg );
6183			}
6184		}
6185		else if ( window.console && console.log ) {
6186			console.log( msg );
6187		}
6188	}
6189	
6190	
6191	/**
6192	 * See if a property is defined on one object, if so assign it to the other object
6193	 *  @param {object} ret target object
6194	 *  @param {object} src source object
6195	 *  @param {string} name property
6196	 *  @param {string} [mappedName] name to map too - optional, name used if not given
6197	 *  @memberof DataTable#oApi
6198	 */
6199	function _fnMap( ret, src, name, mappedName )
6200	{
6201		if ( Array.isArray( name ) ) {
6202			$.each( name, function (i, val) {
6203				if ( Array.isArray( val ) ) {
6204					_fnMap( ret, src, val[0], val[1] );
6205				}
6206				else {
6207					_fnMap( ret, src, val );
6208				}
6209			} );
6210	
6211			return;
6212		}
6213	
6214		if ( mappedName === undefined ) {
6215			mappedName = name;
6216		}
6217	
6218		if ( src[name] !== undefined ) {
6219			ret[mappedName] = src[name];
6220		}
6221	}
6222	
6223	
6224	/**
6225	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6226	 * shallow copy arrays. The reason we need to do this, is that we don't want to
6227	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6228	 * able to override them, but we do want to deep copy arrays.
6229	 *  @param {object} out Object to extend
6230	 *  @param {object} extender Object from which the properties will be applied to
6231	 *      out
6232	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6233	 *      independent copy with the exception of the `data` or `aaData` parameters
6234	 *      if they are present. This is so you can pass in a collection to
6235	 *      DataTables and have that used as your data source without breaking the
6236	 *      references
6237	 *  @returns {object} out Reference, just for convenience - out === the return.
6238	 *  @memberof DataTable#oApi
6239	 *  @todo This doesn't take account of arrays inside the deep copied objects.
6240	 */
6241	function _fnExtend( out, extender, breakRefs )
6242	{
6243		var val;
6244	
6245		for ( var prop in extender ) {
6246			if ( Object.prototype.hasOwnProperty.call(extender, prop) ) {
6247				val = extender[prop];
6248	
6249				if ( $.isPlainObject( val ) ) {
6250					if ( ! $.isPlainObject( out[prop] ) ) {
6251						out[prop] = {};
6252					}
6253					$.extend( true, out[prop], val );
6254				}
6255				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {
6256					out[prop] = val.slice();
6257				}
6258				else {
6259					out[prop] = val;
6260				}
6261			}
6262		}
6263	
6264		return out;
6265	}
6266	
6267	
6268	/**
6269	 * Bind an event handers to allow a click or return key to activate the callback.
6270	 * This is good for accessibility since a return on the keyboard will have the
6271	 * same effect as a click, if the element has focus.
6272	 *  @param {element} n Element to bind the action to
6273	 *  @param {object|string} selector Selector (for delegated events) or data object
6274	 *   to pass to the triggered function
6275	 *  @param {function} fn Callback function for when the event is triggered
6276	 *  @memberof DataTable#oApi
6277	 */
6278	function _fnBindAction( n, selector, fn )
6279	{
6280		$(n)
6281			.on( 'click.DT', selector, function (e) {
6282				fn(e);
6283			} )
6284			.on( 'keypress.DT', selector, function (e){
6285				if ( e.which === 13 ) {
6286					e.preventDefault();
6287					fn(e);
6288				}
6289			} )
6290			.on( 'selectstart.DT', selector, function () {
6291				// Don't want a double click resulting in text selection
6292				return false;
6293			} );
6294	}
6295	
6296	
6297	/**
6298	 * Register a callback function. Easily allows a callback function to be added to
6299	 * an array store of callback functions that can then all be called together.
6300	 *  @param {object} settings dataTables settings object
6301	 *  @param {string} store Name of the array storage for the callbacks in oSettings
6302	 *  @param {function} fn Function to be called back
6303	 *  @memberof DataTable#oApi
6304	 */
6305	function _fnCallbackReg( settings, store, fn )
6306	{
6307		if ( fn ) {
6308			settings[store].push(fn);
6309		}
6310	}
6311	
6312	
6313	/**
6314	 * Fire callback functions and trigger events. Note that the loop over the
6315	 * callback array store is done backwards! Further note that you do not want to
6316	 * fire off triggers in time sensitive applications (for example cell creation)
6317	 * as its slow.
6318	 *  @param {object} settings dataTables settings object
6319	 *  @param {string} callbackArr Name of the array storage for the callbacks in
6320	 *      oSettings
6321	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
6322	 *      null no trigger is fired
6323	 *  @param {array} args Array of arguments to pass to the callback function /
6324	 *      trigger
6325	 *  @param {boolean} [bubbles] True if the event should bubble
6326	 *  @memberof DataTable#oApi
6327	 */
6328	function _fnCallbackFire( settings, callbackArr, eventName, args, bubbles )
6329	{
6330		var ret = [];
6331	
6332		if ( callbackArr ) {
6333			ret = settings[callbackArr].slice().reverse().map( function (val) {
6334				return val.apply( settings.oInstance, args );
6335			} );
6336		}
6337	
6338		if ( eventName !== null) {
6339			var e = $.Event( eventName+'.dt' );
6340			var table = $(settings.nTable);
6341			
6342			// Expose the DataTables API on the event object for easy access
6343			e.dt = settings.api;
6344	
6345			table[bubbles ?  'trigger' : 'triggerHandler']( e, args );
6346	
6347			// If not yet attached to the document, trigger the event
6348			// on the body directly to sort of simulate the bubble
6349			if (bubbles && table.parents('body').length === 0) {
6350				$('body').trigger( e, args );
6351			}
6352	
6353			ret.push( e.result );
6354		}
6355	
6356		return ret;
6357	}
6358	
6359	
6360	function _fnLengthOverflow ( settings )
6361	{
6362		var
6363			start = settings._iDisplayStart,
6364			end = settings.fnDisplayEnd(),
6365			len = settings._iDisplayLength;
6366	
6367		/* If we have space to show extra rows (backing up from the end point - then do so */
6368		if ( start >= end )
6369		{
6370			start = end - len;
6371		}
6372	
6373		// Keep the start record on the current page
6374		start -= (start % len);
6375	
6376		if ( len === -1 || start < 0 )
6377		{
6378			start = 0;
6379		}
6380	
6381		settings._iDisplayStart = start;
6382	}
6383	
6384	
6385	function _fnRenderer( settings, type )
6386	{
6387		var renderer = settings.renderer;
6388		var host = DataTable.ext.renderer[type];
6389	
6390		if ( $.isPlainObject( renderer ) && renderer[type] ) {
6391			// Specific renderer for this type. If available use it, otherwise use
6392			// the default.
6393			return host[renderer[type]] || host._;
6394		}
6395		else if ( typeof renderer === 'string' ) {
6396			// Common renderer - if there is one available for this type use it,
6397			// otherwise use the default
6398			return host[renderer] || host._;
6399		}
6400	
6401		// Use the default
6402		return host._;
6403	}
6404	
6405	
6406	/**
6407	 * Detect the data source being used for the table. Used to simplify the code
6408	 * a little (ajax) and to make it compress a little smaller.
6409	 *
6410	 *  @param {object} settings dataTables settings object
6411	 *  @returns {string} Data source
6412	 *  @memberof DataTable#oApi
6413	 */
6414	function _fnDataSource ( settings )
6415	{
6416		if ( settings.oFeatures.bServerSide ) {
6417			return 'ssp';
6418		}
6419		else if ( settings.ajax ) {
6420			return 'ajax';
6421		}
6422		return 'dom';
6423	}
6424	
6425	/**
6426	 * Common replacement for language strings
6427	 *
6428	 * @param {*} settings DT settings object
6429	 * @param {*} str String with values to replace
6430	 * @param {*} entries Plural number for _ENTRIES_ - can be undefined
6431	 * @returns String
6432	 */
6433	function _fnMacros ( settings, str, entries )
6434	{
6435		// When infinite scrolling, we are always starting at 1. _iDisplayStart is
6436		// used only internally
6437		var
6438			formatter  = settings.fnFormatNumber,
6439			start      = settings._iDisplayStart+1,
6440			len        = settings._iDisplayLength,
6441			vis        = settings.fnRecordsDisplay(),
6442			max        = settings.fnRecordsTotal(),
6443			all        = len === -1;
6444	
6445		return str.
6446			replace(/_START_/g, formatter.call( settings, start ) ).
6447			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
6448			replace(/_MAX_/g,   formatter.call( settings, max ) ).
6449			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
6450			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
6451			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ).
6452			replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries) ).
6453			replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max) ).
6454			replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
6455	}
6456	
6457	
6458	
6459	/**
6460	 * Computed structure of the DataTables API, defined by the options passed to
6461	 * `DataTable.Api.register()` when building the API.
6462	 *
6463	 * The structure is built in order to speed creation and extension of the Api
6464	 * objects since the extensions are effectively pre-parsed.
6465	 *
6466	 * The array is an array of objects with the following structure, where this
6467	 * base array represents the Api prototype base:
6468	 *
6469	 *     [
6470	 *       {
6471	 *         name:      'data'                -- string   - Property name
6472	 *         val:       function () {},       -- function - Api method (or undefined if just an object
6473	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6474	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6475	 *       },
6476	 *       {
6477	 *         name:     'row'
6478	 *         val:       {},
6479	 *         methodExt: [ ... ],
6480	 *         propExt:   [
6481	 *           {
6482	 *             name:      'data'
6483	 *             val:       function () {},
6484	 *             methodExt: [ ... ],
6485	 *             propExt:   [ ... ]
6486	 *           },
6487	 *           ...
6488	 *         ]
6489	 *       }
6490	 *     ]
6491	 *
6492	 * @type {Array}
6493	 * @ignore
6494	 */
6495	var __apiStruct = [];
6496	
6497	
6498	/**
6499	 * `Array.prototype` reference.
6500	 *
6501	 * @type object
6502	 * @ignore
6503	 */
6504	var __arrayProto = Array.prototype;
6505	
6506	
6507	/**
6508	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6509	 * take several different forms for ease of use.
6510	 *
6511	 * Each of the input parameter types will be converted to a DataTables settings
6512	 * object where possible.
6513	 *
6514	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6515	 *   of:
6516	 *
6517	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6518	 *     with be found and used.
6519	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6520	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6521	 *   * `object` - DataTables settings object
6522	 *   * `DataTables.Api` - API instance
6523	 * @return {array|null} Matching DataTables settings objects. `null` or
6524	 *   `undefined` is returned if no matching DataTable is found.
6525	 * @ignore
6526	 */
6527	var _toSettings = function ( mixed )
6528	{
6529		var idx, jq;
6530		var settings = DataTable.settings;
6531		var tables = _pluck(settings, 'nTable');
6532	
6533		if ( ! mixed ) {
6534			return [];
6535		}
6536		else if ( mixed.nTable && mixed.oFeatures ) {
6537			// DataTables settings object
6538			return [ mixed ];
6539		}
6540		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6541			// Table node
6542			idx = tables.indexOf(mixed);
6543			return idx !== -1 ? [ settings[idx] ] : null;
6544		}
6545		else if ( mixed && typeof mixed.settings === 'function' ) {
6546			return mixed.settings().toArray();
6547		}
6548		else if ( typeof mixed === 'string' ) {
6549			// jQuery selector
6550			jq = $(mixed).get();
6551		}
6552		else if ( mixed instanceof $ ) {
6553			// jQuery object (also DataTables instance)
6554			jq = mixed.get();
6555		}
6556	
6557		if ( jq ) {
6558			return settings.filter(function (v, idx) {
6559				return jq.includes(tables[idx]);
6560			});
6561		}
6562	};
6563	
6564	
6565	/**
6566	 * DataTables API class - used to control and interface with  one or more
6567	 * DataTables enhanced tables.
6568	 *
6569	 * The API class is heavily based on jQuery, presenting a chainable interface
6570	 * that you can use to interact with tables. Each instance of the API class has
6571	 * a "context" - i.e. the tables that it will operate on. This could be a single
6572	 * table, all tables on a page or a sub-set thereof.
6573	 *
6574	 * Additionally the API is designed to allow you to easily work with the data in
6575	 * the tables, retrieving and manipulating it as required. This is done by
6576	 * presenting the API class as an array like interface. The contents of the
6577	 * array depend upon the actions requested by each method (for example
6578	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6579	 * return an array of objects or arrays depending upon your table's
6580	 * configuration). The API object has a number of array like methods (`push`,
6581	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6582	 * `unique` etc) to assist your working with the data held in a table.
6583	 *
6584	 * Most methods (those which return an Api instance) are chainable, which means
6585	 * the return from a method call also has all of the methods available that the
6586	 * top level object had. For example, these two calls are equivalent:
6587	 *
6588	 *     // Not chained
6589	 *     api.row.add( {...} );
6590	 *     api.draw();
6591	 *
6592	 *     // Chained
6593	 *     api.row.add( {...} ).draw();
6594	 *
6595	 * @class DataTable.Api
6596	 * @param {array|object|string|jQuery} context DataTable identifier. This is
6597	 *   used to define which DataTables enhanced tables this API will operate on.
6598	 *   Can be one of:
6599	 *
6600	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6601	 *     with be found and used.
6602	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6603	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6604	 *   * `object` - DataTables settings object
6605	 * @param {array} [data] Data to initialise the Api instance with.
6606	 *
6607	 * @example
6608	 *   // Direct initialisation during DataTables construction
6609	 *   var api = $('#example').DataTable();
6610	 *
6611	 * @example
6612	 *   // Initialisation using a DataTables jQuery object
6613	 *   var api = $('#example').dataTable().api();
6614	 *
6615	 * @example
6616	 *   // Initialisation as a constructor
6617	 *   var api = new DataTable.Api( 'table.dataTable' );
6618	 */
6619	_Api = function ( context, data )
6620	{
6621		if ( ! (this instanceof _Api) ) {
6622			return new _Api( context, data );
6623		}
6624	
6625		var settings = [];
6626		var ctxSettings = function ( o ) {
6627			var a = _toSettings( o );
6628			if ( a ) {
6629				settings.push.apply( settings, a );
6630			}
6631		};
6632	
6633		if ( Array.isArray( context ) ) {
6634			for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6635				ctxSettings( context[i] );
6636			}
6637		}
6638		else {
6639			ctxSettings( context );
6640		}
6641	
6642		// Remove duplicates
6643		this.context = settings.length > 1
6644			? _unique( settings )
6645			: settings;
6646	
6647		// Initial data
6648		if ( data ) {
6649			this.push.apply(this, data);
6650		}
6651	
6652		// selector
6653		this.selector = {
6654			rows: null,
6655			cols: null,
6656			opts: null
6657		};
6658	
6659		_Api.extend( this, this, __apiStruct );
6660	};
6661	
6662	DataTable.Api = _Api;
6663	
6664	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6665	// isPlainObject.
6666	$.extend( _Api.prototype, {
6667		any: function ()
6668		{
6669			return this.count() !== 0;
6670		},
6671	
6672		context: [], // array of table settings objects
6673	
6674		count: function ()
6675		{
6676			return this.flatten().length;
6677		},
6678	
6679		each: function ( fn )
6680		{
6681			for ( var i=0, ien=this.length ; i<ien; i++ ) {
6682				fn.call( this, this[i], i, this );
6683			}
6684	
6685			return this;
6686		},
6687	
6688		eq: function ( idx )
6689		{
6690			var ctx = this.context;
6691	
6692			return ctx.length > idx ?
6693				new _Api( ctx[idx], this[idx] ) :
6694				null;
6695		},
6696	
6697		filter: function ( fn )
6698		{
6699			var a = __arrayProto.filter.call( this, fn, this );
6700	
6701			return new _Api( this.context, a );
6702		},
6703	
6704		flatten: function ()
6705		{
6706			var a = [];
6707	
6708			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6709		},
6710	
6711		get: function ( idx )
6712		{
6713			return this[ idx ];
6714		},
6715	
6716		join:    __arrayProto.join,
6717	
6718		includes: function ( find ) {
6719			return this.indexOf( find ) === -1 ? false : true;
6720		},
6721	
6722		indexOf: __arrayProto.indexOf,
6723	
6724		iterator: function ( flatten, type, fn, alwaysNew ) {
6725			var
6726				a = [], ret,
6727				i, ien, j, jen,
6728				context = this.context,
6729				rows, items, item,
6730				selector = this.selector;
6731	
6732			// Argument shifting
6733			if ( typeof flatten === 'string' ) {
6734				alwaysNew = fn;
6735				fn = type;
6736				type = flatten;
6737				flatten = false;
6738			}
6739	
6740			for ( i=0, ien=context.length ; i<ien ; i++ ) {
6741				var apiInst = new _Api( context[i] );
6742	
6743				if ( type === 'table' ) {
6744					ret = fn.call( apiInst, context[i], i );
6745	
6746					if ( ret !== undefined ) {
6747						a.push( ret );
6748					}
6749				}
6750				else if ( type === 'columns' || type === 'rows' ) {
6751					// this has same length as context - one entry for each table
6752					ret = fn.call( apiInst, context[i], this[i], i );
6753	
6754					if ( ret !== undefined ) {
6755						a.push( ret );
6756					}
6757				}
6758				else if ( type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6759					// columns and rows share the same structure.
6760					// 'this' is an array of column indexes for each context
6761					items = this[i];
6762	
6763					if ( type === 'column-rows' ) {
6764						rows = _selector_row_indexes( context[i], selector.opts );
6765					}
6766	
6767					for ( j=0, jen=items.length ; j<jen ; j++ ) {
6768						item = items[j];
6769	
6770						if ( type === 'cell' ) {
6771							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6772						}
6773						else {
6774							ret = fn.call( apiInst, context[i], item, i, j, rows );
6775						}
6776	
6777						if ( ret !== undefined ) {
6778							a.push( ret );
6779						}
6780					}
6781				}
6782			}
6783	
6784			if ( a.length || alwaysNew ) {
6785				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6786				var apiSelector = api.selector;
6787				apiSelector.rows = selector.rows;
6788				apiSelector.cols = selector.cols;
6789				apiSelector.opts = selector.opts;
6790				return api;
6791			}
6792			return this;
6793		},
6794	
6795		lastIndexOf: __arrayProto.lastIndexOf,
6796	
6797		length:  0,
6798	
6799		map: function ( fn )
6800		{
6801			var a = __arrayProto.map.call( this, fn, this );
6802	
6803			return new _Api( this.context, a );
6804		},
6805	
6806		pluck: function ( prop )
6807		{
6808			var fn = DataTable.util.get(prop);
6809	
6810			return this.map( function ( el ) {
6811				return fn(el);
6812			} );
6813		},
6814	
6815		pop:     __arrayProto.pop,
6816	
6817		push:    __arrayProto.push,
6818	
6819		reduce: __arrayProto.reduce,
6820	
6821		reduceRight: __arrayProto.reduceRight,
6822	
6823		reverse: __arrayProto.reverse,
6824	
6825		// Object with rows, columns and opts
6826		selector: null,
6827	
6828		shift:   __arrayProto.shift,
6829	
6830		slice: function () {
6831			return new _Api( this.context, this );
6832		},
6833	
6834		sort:    __arrayProto.sort,
6835	
6836		splice:  __arrayProto.splice,
6837	
6838		toArray: function ()
6839		{
6840			return __arrayProto.slice.call( this );
6841		},
6842	
6843		to$: function ()
6844		{
6845			return $( this );
6846		},
6847	
6848		toJQuery: function ()
6849		{
6850			return $( this );
6851		},
6852	
6853		unique: function ()
6854		{
6855			return new _Api( this.context, _unique(this.toArray()) );
6856		},
6857	
6858		unshift: __arrayProto.unshift
6859	} );
6860	
6861	
6862	function _api_scope( scope, fn, struc ) {
6863		return function () {
6864			var ret = fn.apply( scope || this, arguments );
6865	
6866			// Method extension
6867			_Api.extend( ret, ret, struc.methodExt );
6868			return ret;
6869		};
6870	}
6871	
6872	function _api_find( src, name ) {
6873		for ( var i=0, ien=src.length ; i<ien ; i++ ) {
6874			if ( src[i].name === name ) {
6875				return src[i];
6876			}
6877		}
6878		return null;
6879	}
6880	
6881	window.__apiStruct = __apiStruct;
6882	
6883	_Api.extend = function ( scope, obj, ext )
6884	{
6885		// Only extend API instances and static properties of the API
6886		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6887			return;
6888		}
6889	
6890		var
6891			i, ien,
6892			struct;
6893	
6894		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6895			struct = ext[i];
6896	
6897			if (struct.name === '__proto__') {
6898				continue;
6899			}
6900	
6901			// Value
6902			obj[ struct.name ] = struct.type === 'function' ?
6903				_api_scope( scope, struct.val, struct ) :
6904				struct.type === 'object' ?
6905					{} :
6906					struct.val;
6907	
6908			obj[ struct.name ].__dt_wrapper = true;
6909	
6910			// Property extension
6911			_Api.extend( scope, obj[ struct.name ], struct.propExt );
6912		}
6913	};
6914	
6915	//     [
6916	//       {
6917	//         name:      'data'                -- string   - Property name
6918	//         val:       function () {},       -- function - Api method (or undefined if just an object
6919	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6920	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6921	//       },
6922	//       {
6923	//         name:     'row'
6924	//         val:       {},
6925	//         methodExt: [ ... ],
6926	//         propExt:   [
6927	//           {
6928	//             name:      'data'
6929	//             val:       function () {},
6930	//             methodExt: [ ... ],
6931	//             propExt:   [ ... ]
6932	//           },
6933	//           ...
6934	//         ]
6935	//       }
6936	//     ]
6937	
6938	
6939	_Api.register = _api_register = function ( name, val )
6940	{
6941		if ( Array.isArray( name ) ) {
6942			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
6943				_Api.register( name[j], val );
6944			}
6945			return;
6946		}
6947	
6948		var
6949			i, ien,
6950			heir = name.split('.'),
6951			struct = __apiStruct,
6952			key, method;
6953	
6954		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
6955			method = heir[i].indexOf('()') !== -1;
6956			key = method ?
6957				heir[i].replace('()', '') :
6958				heir[i];
6959	
6960			var src = _api_find( struct, key );
6961			if ( ! src ) {
6962				src = {
6963					name:      key,
6964					val:       {},
6965					methodExt: [],
6966					propExt:   [],
6967					type:      'object'
6968				};
6969				struct.push( src );
6970			}
6971	
6972			if ( i === ien-1 ) {
6973				src.val = val;
6974				src.type = typeof val === 'function' ?
6975					'function' :
6976					$.isPlainObject( val ) ?
6977						'object' :
6978						'other';
6979			}
6980			else {
6981				struct = method ?
6982					src.methodExt :
6983					src.propExt;
6984			}
6985		}
6986	};
6987	
6988	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
6989		_Api.register( pluralName, val );
6990	
6991		_Api.register( singularName, function () {
6992			var ret = val.apply( this, arguments );
6993	
6994			if ( ret === this ) {
6995				// Returned item is the API instance that was passed in, return it
6996				return this;
6997			}
6998			else if ( ret instanceof _Api ) {
6999				// New API instance returned, want the value from the first item
7000				// in the returned array for the singular result.
7001				return ret.length ?
7002					Array.isArray( ret[0] ) ?
7003						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7004						ret[0] :
7005					undefined;
7006			}
7007	
7008			// Non-API return - just fire it back
7009			return ret;
7010		} );
7011	};
7012	
7013	
7014	/**
7015	 * Selector for HTML tables. Apply the given selector to the give array of
7016	 * DataTables settings objects.
7017	 *
7018	 * @param {string|integer} [selector] jQuery selector string or integer
7019	 * @param  {array} Array of DataTables settings objects to be filtered
7020	 * @return {array}
7021	 * @ignore
7022	 */
7023	var __table_selector = function ( selector, a )
7024	{
7025		if ( Array.isArray(selector) ) {
7026			var result = [];
7027	
7028			selector.forEach(function (sel) {
7029				var inner = __table_selector(sel, a);
7030	
7031				result.push.apply(result, inner);
7032			});
7033	
7034			return result.filter( function (item) {
7035				return item;
7036			});
7037		}
7038	
7039		// Integer is used to pick out a table by index
7040		if ( typeof selector === 'number' ) {
7041			return [ a[ selector ] ];
7042		}
7043	
7044		// Perform a jQuery selector on the table nodes
7045		var nodes = a.map( function (el) {
7046			return el.nTable;
7047		} );
7048	
7049		return $(nodes)
7050			.filter( selector )
7051			.map( function () {
7052				// Need to translate back from the table node to the settings
7053				var idx = nodes.indexOf(this);
7054				return a[ idx ];
7055			} )
7056			.toArray();
7057	};
7058	
7059	
7060	
7061	/**
7062	 * Context selector for the API's context (i.e. the tables the API instance
7063	 * refers to.
7064	 *
7065	 * @name    DataTable.Api#tables
7066	 * @param {string|integer} [selector] Selector to pick which tables the iterator
7067	 *   should operate on. If not given, all tables in the current context are
7068	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7069	 *   select multiple tables or as an integer to select a single table.
7070	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7071	 */
7072	_api_register( 'tables()', function ( selector ) {
7073		// A new instance is created if there was a selector specified
7074		return selector !== undefined && selector !== null ?
7075			new _Api( __table_selector( selector, this.context ) ) :
7076			this;
7077	} );
7078	
7079	
7080	_api_register( 'table()', function ( selector ) {
7081		var tables = this.tables( selector );
7082		var ctx = tables.context;
7083	
7084		// Truncate to the first matched table
7085		return ctx.length ?
7086			new _Api( ctx[0] ) :
7087			tables;
7088	} );
7089	
7090	// Common methods, combined to reduce size
7091	[
7092		['nodes', 'node', 'nTable'],
7093		['body', 'body', 'nTBody'],
7094		['header', 'header', 'nTHead'],
7095		['footer', 'footer', 'nTFoot'],
7096	].forEach(function (item) {
7097		_api_registerPlural(
7098			'tables().' + item[0] + '()',
7099			'table().' + item[1] + '()' ,
7100			function () {
7101				return this.iterator( 'table', function ( ctx ) {
7102					return ctx[item[2]];
7103				}, 1 );
7104			}
7105		);
7106	});
7107	
7108	// Structure methods
7109	[
7110		['header', 'aoHeader'],
7111		['footer', 'aoFooter'],
7112	].forEach(function (item) {
7113		_api_register( 'table().' + item[0] + '.structure()' , function (selector) {
7114			var indexes = this.columns(selector).indexes().flatten();
7115			var ctx = this.context[0];
7116			
7117			return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7118		} );
7119	})
7120	
7121	
7122	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7123		return this.iterator( 'table', function ( ctx ) {
7124			return ctx.nTableWrapper;
7125		}, 1 );
7126	} );
7127	
7128	_api_register( 'tables().every()', function ( fn ) {
7129		var that = this;
7130	
7131		return this.iterator('table', function (s, i) {
7132			fn.call(that.table(i), i);
7133		});
7134	});
7135	
7136	_api_register( 'caption()', function ( value, side ) {
7137		var context = this.context;
7138	
7139		// Getter - return existing node's content
7140		if ( value === undefined ) {
7141			var caption = context[0].captionNode;
7142	
7143			return caption && context.length ?
7144				caption.innerHTML : 
7145				null;
7146		}
7147	
7148		return this.iterator( 'table', function ( ctx ) {
7149			var table = $(ctx.nTable);
7150			var caption = $(ctx.captionNode);
7151			var container = $(ctx.nTableWrapper);
7152	
7153			// Create the node if it doesn't exist yet
7154			if ( ! caption.length ) {
7155				caption = $('<caption/>').html( value );
7156				ctx.captionNode = caption[0];
7157	
7158				// If side isn't set, we need to insert into the document to let the
7159				// CSS decide so we can read it back, otherwise there is no way to
7160				// know if the CSS would put it top or bottom for scrolling
vendor: 7,114 bytes, lines 7161-7426
7161				if (! side) {
7162					table.prepend(caption);
7163	
7164					side = caption.css('caption-side');
7165				}
7166			}
7167	
7168			caption.html( value );
7169	
7170			if ( side ) {
7171				caption.css( 'caption-side', side );
7172				caption[0]._captionSide = side;
7173			}
7174	
7175			if (container.find('div.dataTables_scroll').length) {
7176				var selector = (side === 'top' ? 'Head' : 'Foot');
7177	
7178				container.find('div.dataTables_scroll'+ selector +' table').prepend(caption);
7179			}
7180			else {
7181				table.prepend(caption);
7182			}
7183		}, 1 );
7184	} );
7185	
7186	_api_register( 'caption.node()', function () {
7187		var ctx = this.context;
7188	
7189		return ctx.length ? ctx[0].captionNode : null;
7190	} );
7191	
7192	
7193	/**
7194	 * Redraw the tables in the current context.
7195	 */
7196	_api_register( 'draw()', function ( paging ) {
7197		return this.iterator( 'table', function ( settings ) {
7198			if ( paging === 'page' ) {
7199				_fnDraw( settings );
7200			}
7201			else {
7202				if ( typeof paging === 'string' ) {
7203					paging = paging === 'full-hold' ?
7204						false :
7205						true;
7206				}
7207	
7208				_fnReDraw( settings, paging===false );
7209			}
7210		} );
7211	} );
7212	
7213	
7214	
7215	/**
7216	 * Get the current page index.
7217	 *
7218	 * @return {integer} Current page index (zero based)
7219	 *//**
7220	 * Set the current page.
7221	 *
7222	 * Note that if you attempt to show a page which does not exist, DataTables will
7223	 * not throw an error, but rather reset the paging.
7224	 *
7225	 * @param {integer|string} action The paging action to take. This can be one of:
7226	 *  * `integer` - The page index to jump to
7227	 *  * `string` - An action to take:
7228	 *    * `first` - Jump to first page.
7229	 *    * `next` - Jump to the next page
7230	 *    * `previous` - Jump to previous page
7231	 *    * `last` - Jump to the last page.
7232	 * @returns {DataTables.Api} this
7233	 */
7234	_api_register( 'page()', function ( action ) {
7235		if ( action === undefined ) {
7236			return this.page.info().page; // not an expensive call
7237		}
7238	
7239		// else, have an action to take on all tables
7240		return this.iterator( 'table', function ( settings ) {
7241			_fnPageChange( settings, action );
7242		} );
7243	} );
7244	
7245	
7246	/**
7247	 * Paging information for the first table in the current context.
7248	 *
7249	 * If you require paging information for another table, use the `table()` method
7250	 * with a suitable selector.
7251	 *
7252	 * @return {object} Object with the following properties set:
7253	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7254	 *  * `pages` - Total number of pages
7255	 *  * `start` - Display index for the first record shown on the current page
7256	 *  * `end` - Display index for the last record shown on the current page
7257	 *  * `length` - Display length (number of records). Note that generally `start
7258	 *    + length = end`, but this is not always true, for example if there are
7259	 *    only 2 records to show on the final page, with a length of 10.
7260	 *  * `recordsTotal` - Full data set length
7261	 *  * `recordsDisplay` - Data set length once the current filtering criterion
7262	 *    are applied.
7263	 */
7264	_api_register( 'page.info()', function () {
7265		if ( this.context.length === 0 ) {
7266			return undefined;
7267		}
7268	
7269		var
7270			settings   = this.context[0],
7271			start      = settings._iDisplayStart,
7272			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7273			visRecords = settings.fnRecordsDisplay(),
7274			all        = len === -1;
7275	
7276		return {
7277			"page":           all ? 0 : Math.floor( start / len ),
7278			"pages":          all ? 1 : Math.ceil( visRecords / len ),
7279			"start":          start,
7280			"end":            settings.fnDisplayEnd(),
7281			"length":         len,
7282			"recordsTotal":   settings.fnRecordsTotal(),
7283			"recordsDisplay": visRecords,
7284			"serverSide":     _fnDataSource( settings ) === 'ssp'
7285		};
7286	} );
7287	
7288	
7289	/**
7290	 * Get the current page length.
7291	 *
7292	 * @return {integer} Current page length. Note `-1` indicates that all records
7293	 *   are to be shown.
7294	 *//**
7295	 * Set the current page length.
7296	 *
7297	 * @param {integer} Page length to set. Use `-1` to show all records.
7298	 * @returns {DataTables.Api} this
7299	 */
7300	_api_register( 'page.len()', function ( len ) {
7301		// Note that we can't call this function 'length()' because `length`
7302		// is a Javascript property of functions which defines how many arguments
7303		// the function expects.
7304		if ( len === undefined ) {
7305			return this.context.length !== 0 ?
7306				this.context[0]._iDisplayLength :
7307				undefined;
7308		}
7309	
7310		// else, set the page length
7311		return this.iterator( 'table', function ( settings ) {
7312			_fnLengthChange( settings, len );
7313		} );
7314	} );
7315	
7316	
7317	
7318	var __reload = function ( settings, holdPosition, callback ) {
7319		// Use the draw event to trigger a callback
7320		if ( callback ) {
7321			var api = new _Api( settings );
7322	
7323			api.one( 'draw', function () {
7324				callback( api.ajax.json() );
7325			} );
7326		}
7327	
7328		if ( _fnDataSource( settings ) == 'ssp' ) {
7329			_fnReDraw( settings, holdPosition );
7330		}
7331		else {
7332			_fnProcessingDisplay( settings, true );
7333	
7334			// Cancel an existing request
7335			var xhr = settings.jqXHR;
7336			if ( xhr && xhr.readyState !== 4 ) {
7337				xhr.abort();
7338			}
7339	
7340			// Trigger xhr
7341			_fnBuildAjax( settings, {}, function( json ) {
7342				_fnClearTable( settings );
7343	
7344				var data = _fnAjaxDataSrc( settings, json );
7345				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7346					_fnAddData( settings, data[i] );
7347				}
7348	
7349				_fnReDraw( settings, holdPosition );
7350				_fnInitComplete( settings );
7351				_fnProcessingDisplay( settings, false );
7352			} );
7353		}
7354	};
7355	
7356	
7357	/**
7358	 * Get the JSON response from the last Ajax request that DataTables made to the
7359	 * server. Note that this returns the JSON from the first table in the current
7360	 * context.
7361	 *
7362	 * @return {object} JSON received from the server.
7363	 */
7364	_api_register( 'ajax.json()', function () {
7365		var ctx = this.context;
7366	
7367		if ( ctx.length > 0 ) {
7368			return ctx[0].json;
7369		}
7370	
7371		// else return undefined;
7372	} );
7373	
7374	
7375	/**
7376	 * Get the data submitted in the last Ajax request
7377	 */
7378	_api_register( 'ajax.params()', function () {
7379		var ctx = this.context;
7380	
7381		if ( ctx.length > 0 ) {
7382			return ctx[0].oAjaxData;
7383		}
7384	
7385		// else return undefined;
7386	} );
7387	
7388	
7389	/**
7390	 * Reload tables from the Ajax data source. Note that this function will
7391	 * automatically re-draw the table when the remote data has been loaded.
7392	 *
7393	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7394	 *   position. A full re-sort and re-filter is performed when this method is
7395	 *   called, which is why the pagination reset is the default action.
7396	 * @returns {DataTables.Api} this
7397	 */
7398	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7399		return this.iterator( 'table', function (settings) {
7400			__reload( settings, resetPaging===false, callback );
7401		} );
7402	} );
7403	
7404	
7405	/**
7406	 * Get the current Ajax URL. Note that this returns the URL from the first
7407	 * table in the current context.
7408	 *
7409	 * @return {string} Current Ajax source URL
7410	 *//**
7411	 * Set the Ajax URL. Note that this will set the URL for all tables in the
7412	 * current context.
7413	 *
7414	 * @param {string} url URL to set.
7415	 * @returns {DataTables.Api} this
7416	 */
7417	_api_register( 'ajax.url()', function ( url ) {
7418		var ctx = this.context;
7419	
7420		if ( url === undefined ) {
7421			// get
7422			if ( ctx.length === 0 ) {
7423				return undefined;
7424			}
7425			ctx = ctx[0];
7426	
7427			return $.isPlainObject( ctx.ajax ) ?
7428				ctx.ajax.url :
7429				ctx.ajax;
7430		}
7431	
7432		// set
7433		return this.iterator( 'table', function ( settings ) {
7434			if ( $.isPlainObject( settings.ajax ) ) {
7435				settings.ajax.url = url;
7436			}
7437			else {
7438				settings.ajax = url;
7439			}
7440		} );
7441	} );
7442	
7443	
7444	/**
7445	 * Load data from the newly set Ajax URL. Note that this method is only
7446	 * available when `ajax.url()` is used to set a URL. Additionally, this method
7447	 * has the same effect as calling `ajax.reload()` but is provided for
7448	 * convenience when setting a new URL. Like `ajax.reload()` it will
7449	 * automatically redraw the table once the remote data has been loaded.
7450	 *
7451	 * @returns {DataTables.Api} this
7452	 */
7453	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7454		// Same as a reload, but makes sense to present it for easy access after a
7455		// url change
7456		return this.iterator( 'table', function ( ctx ) {
7457			__reload( ctx, resetPaging===false, callback );
7458		} );
7459	} );
7460	
7461	
7462	
7463	
7464	var _selector_run = function ( type, selector, selectFn, settings, opts )
7465	{
7466		var
7467			out = [], res,
7468			a, i, ien, j, jen,
7469			selectorType = typeof selector;
7470	
7471		// Can't just check for isArray here, as an API or jQuery instance might be
7472		// given with their array like look
7473		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7474			selector = [ selector ];
7475		}
7476	
7477		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7478			// Only split on simple strings - complex expressions will be jQuery selectors
7479			a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
7480				selector[i].split(',') :
7481				[ selector[i] ];
7482	
7483			for ( j=0, jen=a.length ; j<jen ; j++ ) {
7484				res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
7485	
7486				// Remove empty items
7487				res = res.filter( function (item) {
7488					return item !== null && item !== undefined;
7489				});
7490	
7491				if ( res && res.length ) {
7492					out = out.concat( res );
7493				}
7494			}
7495		}
7496	
7497		// selector extensions
7498		var ext = _ext.selector[ type ];
7499		if ( ext.length ) {
7500			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7501				out = ext[i]( settings, opts, out );
7502			}
7503		}
7504	
7505		return _unique( out );
7506	};
7507	
7508	
7509	var _selector_opts = function ( opts )
7510	{
7511		if ( ! opts ) {
7512			opts = {};
7513		}
7514	
7515		// Backwards compatibility for 1.9- which used the terminology filter rather
7516		// than search
7517		if ( opts.filter && opts.search === undefined ) {
7518			opts.search = opts.filter;
7519		}
7520	
7521		return $.extend( {
7522			search: 'none',
7523			order: 'current',
7524			page: 'all'
7525		}, opts );
7526	};
7527	
7528	
7529	// Reduce the API instance to the first item found
7530	var _selector_first = function ( old )
7531	{
7532		let inst = new _Api(old.context[0]);
7533	
7534		// Use a push rather than passing to the constructor, since it will
7535		// merge arrays down automatically, which isn't what is wanted here
7536		if (old.length) {
7537			inst.push( old[0] );
7538		}
7539	
7540		inst.selector = old.selector;
7541	
7542		// Limit to a single row / column / cell
7543		if (inst.length && inst[0].length > 1) {
7544			inst[0].splice(1);
7545		}
7546	
7547		return inst;
7548	};
7549	
7550	
7551	var _selector_row_indexes = function ( settings, opts )
7552	{
7553		var
7554			i, ien, tmp, a=[],
7555			displayFiltered = settings.aiDisplay,
7556			displayMaster = settings.aiDisplayMaster;
7557	
7558		var
7559			search = opts.search,  // none, applied, removed
7560			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7561			page   = opts.page;    // all, current
7562	
7563		if ( page == 'current' ) {
7564			// Current page implies that order=current and filter=applied, since it is
7565			// fairly senseless otherwise, regardless of what order and search actually
7566			// are
7567			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7568				a.push( displayFiltered[i] );
7569			}
7570		}
7571		else if ( order == 'current' || order == 'applied' ) {
7572			if ( search == 'none') {
7573				a = displayMaster.slice();
7574			}
7575			else if ( search == 'applied' ) {
7576				a = displayFiltered.slice();
7577			}
7578			else if ( search == 'removed' ) {
7579				// O(n+m) solution by creating a hash map
7580				var displayFilteredMap = {};
7581	
7582				for ( i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7583					displayFilteredMap[displayFiltered[i]] = null;
7584				}
7585	
7586				displayMaster.forEach(function (item) {
7587					if (! Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
7588						a.push(item);
7589					}
7590				});
7591			}
7592		}
7593		else if ( order == 'index' || order == 'original' ) {
7594			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
vendor: 20,168 bytes, lines 7595-8371
7595				if (! settings.aoData[i]) {
7596					continue;
7597				}
7598	
7599				if ( search == 'none' ) {
7600					a.push( i );
7601				}
7602				else { // applied | removed
7603					tmp = displayFiltered.indexOf(i);
7604	
7605					if ((tmp === -1 && search == 'removed') ||
7606						(tmp >= 0   && search == 'applied') )
7607					{
7608						a.push( i );
7609					}
7610				}
7611			}
7612		}
7613		else if ( typeof order === 'number' ) {
7614			// Order the rows by the given column
7615			var ordered = _fnSort(settings, order, 'asc');
7616	
7617			if (search === 'none') {
7618				a = ordered;
7619			}
7620			else { // applied | removed
7621				for (i=0; i<ordered.length; i++) {
7622					tmp = displayFiltered.indexOf(ordered[i]);
7623	
7624					if ((tmp === -1 && search == 'removed') ||
7625						(tmp >= 0   && search == 'applied') )
7626					{
7627						a.push( ordered[i] );
7628					}
7629				}
7630			}
7631		}
7632	
7633		return a;
7634	};
7635	
7636	
7637	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7638	 * Rows
7639	 *
7640	 * {}          - no selector - use all available rows
7641	 * {integer}   - row aoData index
7642	 * {node}      - TR node
7643	 * {string}    - jQuery selector to apply to the TR elements
7644	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
7645	 *
7646	 */
7647	var __row_selector = function ( settings, selector, opts )
7648	{
7649		var rows;
7650		var run = function ( sel ) {
7651			var selInt = _intVal( sel );
7652			var aoData = settings.aoData;
7653	
7654			// Short cut - selector is a number and no options provided (default is
7655			// all records, so no need to check if the index is in there, since it
7656			// must be - dev error if the index doesn't exist).
7657			if ( selInt !== null && ! opts ) {
7658				return [ selInt ];
7659			}
7660	
7661			if ( ! rows ) {
7662				rows = _selector_row_indexes( settings, opts );
7663			}
7664	
7665			if ( selInt !== null && rows.indexOf(selInt) !== -1 ) {
7666				// Selector - integer
7667				return [ selInt ];
7668			}
7669			else if ( sel === null || sel === undefined || sel === '' ) {
7670				// Selector - none
7671				return rows;
7672			}
7673	
7674			// Selector - function
7675			if ( typeof sel === 'function' ) {
7676				return rows.map( function (idx) {
7677					var row = aoData[ idx ];
7678					return sel( idx, row._aData, row.nTr ) ? idx : null;
7679				} );
7680			}
7681	
7682			// Selector - node
7683			if ( sel.nodeName ) {
7684				var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
7685				var cellIdx = sel._DT_CellIndex;
7686	
7687				if ( rowIdx !== undefined ) {
7688					// Make sure that the row is actually still present in the table
7689					return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7690						[ rowIdx ] :
7691						[];
7692				}
7693				else if ( cellIdx ) {
7694					return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
7695						[ cellIdx.row ] :
7696						[];
7697				}
7698				else {
7699					var host = $(sel).closest('*[data-dt-row]');
7700					return host.length ?
7701						[ host.data('dt-row') ] :
7702						[];
7703				}
7704			}
7705	
7706			// ID selector. Want to always be able to select rows by id, regardless
7707			// of if the tr element has been created or not, so can't rely upon
7708			// jQuery here - hence a custom implementation. This does not match
7709			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7710			// but to select it using a CSS selector engine (like Sizzle or
7711			// querySelect) it would need to need to be escaped for some characters.
7712			// DataTables simplifies this for row selectors since you can select
7713			// only a row. A # indicates an id any anything that follows is the id -
7714			// unescaped.
7715			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7716				// get row index from id
7717				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7718				if ( rowObj !== undefined ) {
7719					return [ rowObj.idx ];
7720				}
7721	
7722				// need to fall through to jQuery in case there is DOM id that
7723				// matches
7724			}
7725			
7726			// Get nodes in the order from the `rows` array with null values removed
7727			var nodes = _removeEmpty(
7728				_pluck_order( settings.aoData, rows, 'nTr' )
7729			);
7730	
7731			// Selector - jQuery selector string, array of nodes or jQuery object/
7732			// As jQuery's .filter() allows jQuery objects to be passed in filter,
7733			// it also allows arrays, so this will cope with all three options
7734			return $(nodes)
7735				.filter( sel )
7736				.map( function () {
7737					return this._DT_RowIndex;
7738				} )
7739				.toArray();
7740		};
7741	
7742		var matched = _selector_run( 'row', selector, run, settings, opts );
7743	
7744		if (opts.order === 'current' || opts.order === 'applied') {
7745			_fnSortDisplay(settings, matched);
7746		}
7747	
7748		return matched;
7749	};
7750	
7751	
7752	_api_register( 'rows()', function ( selector, opts ) {
7753		// argument shifting
7754		if ( selector === undefined ) {
7755			selector = '';
7756		}
7757		else if ( $.isPlainObject( selector ) ) {
7758			opts = selector;
7759			selector = '';
7760		}
7761	
7762		opts = _selector_opts( opts );
7763	
7764		var inst = this.iterator( 'table', function ( settings ) {
7765			return __row_selector( settings, selector, opts );
7766		}, 1 );
7767	
7768		// Want argument shifting here and in __row_selector?
7769		inst.selector.rows = selector;
7770		inst.selector.opts = opts;
7771	
7772		return inst;
7773	} );
7774	
7775	_api_register( 'rows().nodes()', function () {
7776		return this.iterator( 'row', function ( settings, row ) {
7777			return settings.aoData[ row ].nTr || undefined;
7778		}, 1 );
7779	} );
7780	
7781	_api_register( 'rows().data()', function () {
7782		return this.iterator( true, 'rows', function ( settings, rows ) {
7783			return _pluck_order( settings.aoData, rows, '_aData' );
7784		}, 1 );
7785	} );
7786	
7787	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7788		return this.iterator( 'row', function ( settings, row ) {
7789			var r = settings.aoData[ row ];
7790			return type === 'search' ? r._aFilterData : r._aSortData;
7791		}, 1 );
7792	} );
7793	
7794	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7795		return this.iterator( 'row', function ( settings, row ) {
7796			_fnInvalidate( settings, row, src );
7797		} );
7798	} );
7799	
7800	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7801		return this.iterator( 'row', function ( settings, row ) {
7802			return row;
7803		}, 1 );
7804	} );
7805	
7806	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7807		var a = [];
7808		var context = this.context;
7809	
7810		// `iterator` will drop undefined values, but in this case we want them
7811		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7812			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7813				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7814				a.push( (hash === true ? '#' : '' )+ id );
7815			}
7816		}
7817	
7818		return new _Api( context, a );
7819	} );
7820	
7821	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7822		this.iterator( 'row', function ( settings, row ) {
7823			var data = settings.aoData;
7824			var rowData = data[ row ];
7825	
7826			// Delete from the display arrays
7827			var idx = settings.aiDisplayMaster.indexOf(row);
7828			if (idx !== -1) {
7829				settings.aiDisplayMaster.splice(idx, 1);
7830			}
7831	
7832			// For server-side processing tables - subtract the deleted row from the count
7833			if ( settings._iRecordsDisplay > 0 ) {
7834				settings._iRecordsDisplay--;
7835			}
7836	
7837			// Check for an 'overflow' they case for displaying the table
7838			_fnLengthOverflow( settings );
7839	
7840			// Remove the row's ID reference if there is one
7841			var id = settings.rowIdFn( rowData._aData );
7842			if ( id !== undefined ) {
7843				delete settings.aIds[ id ];
7844			}
7845	
7846			data[row] = null;
7847		} );
7848	
7849		return this;
7850	} );
7851	
7852	
7853	_api_register( 'rows.add()', function ( rows ) {
7854		var newRows = this.iterator( 'table', function ( settings ) {
7855				var row, i, ien;
7856				var out = [];
7857	
7858				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7859					row = rows[i];
7860	
7861					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7862						out.push( _fnAddTr( settings, row )[0] );
7863					}
7864					else {
7865						out.push( _fnAddData( settings, row ) );
7866					}
7867				}
7868	
7869				return out;
7870			}, 1 );
7871	
7872		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
7873		var modRows = this.rows( -1 );
7874		modRows.pop();
7875		modRows.push.apply(modRows, newRows);
7876	
7877		return modRows;
7878	} );
7879	
7880	
7881	
7882	
7883	
7884	/**
7885	 *
7886	 */
7887	_api_register( 'row()', function ( selector, opts ) {
7888		return _selector_first( this.rows( selector, opts ) );
7889	} );
7890	
7891	
7892	_api_register( 'row().data()', function ( data ) {
7893		var ctx = this.context;
7894	
7895		if ( data === undefined ) {
7896			// Get
7897			return ctx.length && this.length && this[0].length ?
7898				ctx[0].aoData[ this[0] ]._aData :
7899				undefined;
7900		}
7901	
7902		// Set
7903		var row = ctx[0].aoData[ this[0] ];
7904		row._aData = data;
7905	
7906		// If the DOM has an id, and the data source is an array
7907		if ( Array.isArray( data ) && row.nTr && row.nTr.id ) {
7908			_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
7909		}
7910	
7911		// Automatically invalidate
7912		_fnInvalidate( ctx[0], this[0], 'data' );
7913	
7914		return this;
7915	} );
7916	
7917	
7918	_api_register( 'row().node()', function () {
7919		var ctx = this.context;
7920	
7921		if (ctx.length && this.length && this[0].length) {
7922			var row = ctx[0].aoData[ this[0] ];
7923	
7924			if (row && row.nTr) {
7925				return row.nTr;
7926			}
7927		}
7928	
7929		return null;
7930	} );
7931	
7932	
7933	_api_register( 'row.add()', function ( row ) {
7934		// Allow a jQuery object to be passed in - only a single row is added from
7935		// it though - the first element in the set
7936		if ( row instanceof $ && row.length ) {
7937			row = row[0];
7938		}
7939	
7940		var rows = this.iterator( 'table', function ( settings ) {
7941			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7942				return _fnAddTr( settings, row )[0];
7943			}
7944			return _fnAddData( settings, row );
7945		} );
7946	
7947		// Return an Api.rows() extended instance, with the newly added row selected
7948		return this.row( rows[0] );
7949	} );
7950	
7951	
7952	$(document).on('plugin-init.dt', function (e, context) {
7953		var api = new _Api( context );
7954	
7955		api.on( 'stateSaveParams.DT', function ( e, settings, d ) {
7956			// This could be more compact with the API, but it is a lot faster as a simple
7957			// internal loop
7958			var idFn = settings.rowIdFn;
7959			var rows = settings.aiDisplayMaster;
7960			var ids = [];
7961	
7962			for (var i=0 ; i<rows.length ; i++) {
7963				var rowIdx = rows[i];
7964				var data = settings.aoData[rowIdx];
7965	
7966				if (data._detailsShow) {
7967					ids.push( '#' + idFn(data._aData) );
7968				}
7969			}
7970	
7971			d.childRows = ids;
7972		});
7973	
7974		// For future state loads (e.g. with StateRestore)
7975		api.on( 'stateLoaded.DT', function (e, settings, state) {
7976			__details_state_load( api, state );
7977		});
7978	
7979		// And the initial load state
7980		__details_state_load( api, api.state.loaded() );
7981	});
7982	
7983	var __details_state_load = function (api, state)
7984	{
7985		if ( state && state.childRows ) {
7986			api
7987				.rows( state.childRows.map(function (id) {
7988					// Escape any `:` characters from the row id. Accounts for
7989					// already escaped characters.
7990					return id.replace(/([^:\\]*(?:\\.[^:\\]*)*):/g, "$1\\:");
7991				}) )
7992				.every( function () {
7993					_fnCallbackFire( api.settings()[0], null, 'requestChild', [ this ] )
7994				});
7995		}
7996	}
7997	
7998	var __details_add = function ( ctx, row, data, klass )
7999	{
8000		// Convert to array of TR elements
8001		var rows = [];
8002		var addRow = function ( r, k ) {
8003			// Recursion to allow for arrays of jQuery objects
8004			if ( Array.isArray( r ) || r instanceof $ ) {
8005				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8006					addRow( r[i], k );
8007				}
8008				return;
8009			}
8010	
8011			// If we get a TR element, then just add it directly - up to the dev
8012			// to add the correct number of columns etc
8013			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8014				r.setAttribute( 'data-dt-row', row.idx );
8015				rows.push( r );
8016			}
8017			else {
8018				// Otherwise create a row with a wrapper
8019				var created = $('<tr><td></td></tr>')
8020					.attr( 'data-dt-row', row.idx )
8021					.addClass( k );
8022				
8023				$('td', created)
8024					.addClass( k )
8025					.html( r )[0].colSpan = _fnVisbleColumns( ctx );
8026	
8027				rows.push( created[0] );
8028			}
8029		};
8030	
8031		addRow( data, klass );
8032	
8033		if ( row._details ) {
8034			row._details.detach();
8035		}
8036	
8037		row._details = $(rows);
8038	
8039		// If the children were already shown, that state should be retained
8040		if ( row._detailsShow ) {
8041			row._details.insertAfter( row.nTr );
8042		}
8043	};
8044	
8045	
8046	// Make state saving of child row details async to allow them to be batch processed
8047	var __details_state = DataTable.util.throttle(
8048		function (ctx) {
8049			_fnSaveState( ctx[0] )
8050		},
8051		500
8052	);
8053	
8054	
8055	var __details_remove = function ( api, idx )
8056	{
8057		var ctx = api.context;
8058	
8059		if ( ctx.length ) {
8060			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8061	
8062			if ( row && row._details ) {
8063				row._details.remove();
8064	
8065				row._detailsShow = undefined;
8066				row._details = undefined;
8067				$( row.nTr ).removeClass( 'dt-hasChild' );
8068				__details_state( ctx );
8069			}
8070		}
8071	};
8072	
8073	
8074	var __details_display = function ( api, show ) {
8075		var ctx = api.context;
8076	
8077		if ( ctx.length && api.length ) {
8078			var row = ctx[0].aoData[ api[0] ];
8079	
8080			if ( row._details ) {
8081				row._detailsShow = show;
8082	
8083				if ( show ) {
8084					row._details.insertAfter( row.nTr );
8085					$( row.nTr ).addClass( 'dt-hasChild' );
8086				}
8087				else {
8088					row._details.detach();
8089					$( row.nTr ).removeClass( 'dt-hasChild' );
8090				}
8091	
8092				_fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )
8093	
8094				__details_events( ctx[0] );
8095				__details_state( ctx );
8096			}
8097		}
8098	};
8099	
8100	
8101	var __details_events = function ( settings )
8102	{
8103		var api = new _Api( settings );
8104		var namespace = '.dt.DT_details';
8105		var drawEvent = 'draw'+namespace;
8106		var colvisEvent = 'column-sizing'+namespace;
8107		var destroyEvent = 'destroy'+namespace;
8108		var data = settings.aoData;
8109	
8110		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8111	
8112		if ( _pluck( data, '_details' ).length > 0 ) {
8113			// On each draw, insert the required elements into the document
8114			api.on( drawEvent, function ( e, ctx ) {
8115				if ( settings !== ctx ) {
8116					return;
8117				}
8118	
8119				api.rows( {page:'current'} ).eq(0).each( function (idx) {
8120					// Internal data grab
8121					var row = data[ idx ];
8122	
8123					if ( row._detailsShow ) {
8124						row._details.insertAfter( row.nTr );
8125					}
8126				} );
8127			} );
8128	
8129			// Column visibility change - update the colspan
8130			api.on( colvisEvent, function ( e, ctx ) {
8131				if ( settings !== ctx ) {
8132					return;
8133				}
8134	
8135				// Update the colspan for the details rows (note, only if it already has
8136				// a colspan)
8137				var row, visible = _fnVisbleColumns( ctx );
8138	
8139				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8140					row = data[i];
8141	
8142					if ( row && row._details ) {
8143						row._details.each(function () {
8144							var el = $(this).children('td');
8145	
8146							if (el.length == 1) {
8147								el.attr('colspan', visible);
8148							}
8149						});
8150					}
8151				}
8152			} );
8153	
8154			// Table destroyed - nuke any child rows
8155			api.on( destroyEvent, function ( e, ctx ) {
8156				if ( settings !== ctx ) {
8157					return;
8158				}
8159	
8160				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8161					if ( data[i] && data[i]._details ) {
8162						__details_remove( api, i );
8163					}
8164				}
8165			} );
8166		}
8167	};
8168	
8169	// Strings for the method names to help minification
8170	var _emp = '';
8171	var _child_obj = _emp+'row().child';
8172	var _child_mth = _child_obj+'()';
8173	
8174	// data can be:
8175	//  tr
8176	//  string
8177	//  jQuery or array of any of the above
8178	_api_register( _child_mth, function ( data, klass ) {
8179		var ctx = this.context;
8180	
8181		if ( data === undefined ) {
8182			// get
8183			return ctx.length && this.length && ctx[0].aoData[ this[0] ]
8184				? ctx[0].aoData[ this[0] ]._details
8185				: undefined;
8186		}
8187		else if ( data === true ) {
8188			// show
8189			this.child.show();
8190		}
8191		else if ( data === false ) {
8192			// remove
8193			__details_remove( this );
8194		}
8195		else if ( ctx.length && this.length ) {
8196			// set
8197			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8198		}
8199	
8200		return this;
8201	} );
8202	
8203	
8204	_api_register( [
8205		_child_obj+'.show()',
8206		_child_mth+'.show()' // only when `child()` was called with parameters (without
8207	], function () {         // it returns an object and this method is not executed)
8208		__details_display( this, true );
8209		return this;
8210	} );
8211	
8212	
8213	_api_register( [
8214		_child_obj+'.hide()',
8215		_child_mth+'.hide()' // only when `child()` was called with parameters (without
8216	], function () {         // it returns an object and this method is not executed)
8217		__details_display( this, false );
8218		return this;
8219	} );
8220	
8221	
8222	_api_register( [
8223		_child_obj+'.remove()',
8224		_child_mth+'.remove()' // only when `child()` was called with parameters (without
8225	], function () {           // it returns an object and this method is not executed)
8226		__details_remove( this );
8227		return this;
8228	} );
8229	
8230	
8231	_api_register( _child_obj+'.isShown()', function () {
8232		var ctx = this.context;
8233	
8234		if ( ctx.length && this.length ) {
8235			// _detailsShown as false or undefined will fall through to return false
8236			return ctx[0].aoData[ this[0] ]._detailsShow || false;
8237		}
8238		return false;
8239	} );
8240	
8241	
8242	
8243	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8244	 * Columns
8245	 *
8246	 * {integer}           - column index (>=0 count from left, <0 count from right)
8247	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8248	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8249	 * "{string}:name"     - column name
8250	 * "{string}"          - jQuery selector on column header nodes
8251	 *
8252	 */
8253	
8254	// can be an array of these items, comma separated list, or an array of comma
8255	// separated lists
8256	
8257	var __re_column_selector = /^([^:]+):(name|title|visIdx|visible)$/;
8258	
8259	
8260	// r1 and r2 are redundant - but it means that the parameters match for the
8261	// iterator callback in columns().data()
8262	var __columnData = function ( settings, column, r1, r2, rows, type ) {
8263		var a = [];
8264		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8265			a.push( _fnGetCellData( settings, rows[row], column, type ) );
8266		}
8267		return a;
8268	};
8269	
8270	
8271	var __column_header = function ( settings, column, row ) {
8272		var header = settings.aoHeader;
8273		var target = row !== undefined
8274			? row
8275			: settings.bSortCellsTop // legacy support
8276				? 0
8277				: header.length - 1;
8278	
8279		return header[target][column].cell;
8280	};
8281	
8282	var __column_selector = function ( settings, selector, opts )
8283	{
8284		var
8285			columns = settings.aoColumns,
8286			names = _pluck( columns, 'sName' ),
8287			titles = _pluck( columns, 'sTitle' ),
8288			cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
8289			nodes = _unique( _flatten([], cells) );
8290		
8291		var run = function ( s ) {
8292			var selInt = _intVal( s );
8293	
8294			// Selector - all
8295			if ( s === '' ) {
8296				return _range( columns.length );
8297			}
8298	
8299			// Selector - index
8300			if ( selInt !== null ) {
8301				return [ selInt >= 0 ?
8302					selInt : // Count from left
8303					columns.length + selInt // Count from right (+ because its a negative value)
8304				];
8305			}
8306	
8307			// Selector = function
8308			if ( typeof s === 'function' ) {
8309				var rows = _selector_row_indexes( settings, opts );
8310	
8311				return columns.map(function (col, idx) {
8312					return s(
8313							idx,
8314							__columnData( settings, idx, 0, 0, rows ),
8315							__column_header( settings, idx )
8316						) ? idx : null;
8317				});
8318			}
8319	
8320			// jQuery or string selector
8321			var match = typeof s === 'string' ?
8322				s.match( __re_column_selector ) :
8323				'';
8324	
8325			if ( match ) {
8326				switch( match[2] ) {
8327					case 'visIdx':
8328					case 'visible':
8329						var idx = parseInt( match[1], 10 );
8330						// Visible index given, convert to column index
8331						if ( idx < 0 ) {
8332							// Counting from the right
8333							var visColumns = columns.map( function (col,i) {
8334								return col.bVisible ? i : null;
8335							} );
8336							return [ visColumns[ visColumns.length + idx ] ];
8337						}
8338						// Counting from the left
8339						return [ _fnVisibleToColumnIndex( settings, idx ) ];
8340	
8341					case 'name':
8342						// match by name. `names` is column index complete and in order
8343						return names.map( function (name, i) {
8344							return name === match[1] ? i : null;
8345						} );
8346	
8347					case 'title':
8348						// match by column title
8349						return titles.map( function (title, i) {
8350							return title === match[1] ? i : null;
8351						} );
8352	
8353					default:
8354						return [];
8355				}
8356			}
8357	
8358			// Cell in the table body
8359			if ( s.nodeName && s._DT_CellIndex ) {
8360				return [ s._DT_CellIndex.column ];
8361			}
8362	
8363			// jQuery selector on the TH elements for the columns
8364			var jqResult = $( nodes )
8365				.filter( s )
8366				.map( function () {
8367					return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
8368				} )
8369				.toArray();
8370	
8371			if ( jqResult.length || ! s.nodeName ) {
8372				return jqResult;
8373			}
8374	
8375			// Otherwise a node which might have a `dt-column` data attribute, or be
8376			// a child or such an element
8377			var host = $(s).closest('*[data-dt-column]');
8378			return host.length ?
8379				[ host.data('dt-column') ] :
8380				[];
8381		};
8382	
8383		return _selector_run( 'column', selector, run, settings, opts );
8384	};
8385	
8386	
8387	var __setColumnVis = function ( settings, column, vis ) {
8388		var
8389			cols = settings.aoColumns,
8390			col  = cols[ column ],
8391			data = settings.aoData,
8392			cells, i, ien, tr;
8393	
8394		// Get
8395		if ( vis === undefined ) {
8396			return col.bVisible;
8397		}
8398	
8399		// Set
8400		// No change
8401		if ( col.bVisible === vis ) {
8402			return false;
8403		}
8404	
8405		if ( vis ) {
8406			// Insert column
8407			// Need to decide if we should use appendChild or insertBefore
8408			var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column+1);
8409	
8410			for ( i=0, ien=data.length ; i<ien ; i++ ) {
8411				if (data[i]) {
8412					tr = data[i].nTr;
8413					cells = data[i].anCells;
8414	
8415					if ( tr ) {
8416						// insertBefore can act like appendChild if 2nd arg is null
8417						tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8418					}
8419				}
8420			}
8421		}
8422		else {
8423			// Remove column
8424			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
8425		}
8426	
8427		// Common actions
8428		col.bVisible = vis;
8429	
8430		_colGroup(settings);
8431		
8432		return true;
8433	};
8434	
8435	
8436	_api_register( 'columns()', function ( selector, opts ) {
8437		// argument shifting
8438		if ( selector === undefined ) {
8439			selector = '';
8440		}
8441		else if ( $.isPlainObject( selector ) ) {
8442			opts = selector;
8443			selector = '';
8444		}
8445	
8446		opts = _selector_opts( opts );
8447	
8448		var inst = this.iterator( 'table', function ( settings ) {
8449			return __column_selector( settings, selector, opts );
8450		}, 1 );
8451	
8452		// Want argument shifting here and in _row_selector?
8453		inst.selector.cols = selector;
8454		inst.selector.opts = opts;
8455	
8456		return inst;
8457	} );
8458	
8459	_api_registerPlural( 'columns().header()', 'column().header()', function ( row ) {
8460		return this.iterator( 'column', function (settings, column) {
8461			return __column_header(settings, column, row);
8462		}, 1 );
8463	} );
8464	
8465	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( row ) {
8466		return this.iterator( 'column', function ( settings, column ) {
8467			var footer = settings.aoFooter;
8468	
8469			if (! footer.length) {
8470				return null;
8471			}
8472	
8473			return settings.aoFooter[row !== undefined ? row : 0][column].cell;
8474		}, 1 );
8475	} );
8476	
8477	_api_registerPlural( 'columns().data()', 'column().data()', function () {
8478		return this.iterator( 'column-rows', __columnData, 1 );
8479	} );
8480	
8481	_api_registerPlural( 'columns().render()', 'column().render()', function ( type ) {
8482		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8483			return __columnData( settings, column, i, j, rows, type );
8484		}, 1 );
8485	} );
8486	
8487	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8488		return this.iterator( 'column', function ( settings, column ) {
8489			return settings.aoColumns[column].mData;
8490		}, 1 );
8491	} );
8492	
8493	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8494		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8495			return _pluck_order( settings.aoData, rows,
8496				type === 'search' ? '_aFilterData' : '_aSortData', column
8497			);
8498		}, 1 );
8499	} );
8500	
8501	_api_registerPlural( 'columns().init()', 'column().init()', function () {
8502		return this.iterator( 'column', function ( settings, column ) {
8503			return settings.aoColumns[column];
8504		}, 1 );
8505	} );
8506	
8507	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8508		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8509			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8510		}, 1 );
8511	} );
8512	
8513	_api_registerPlural( 'columns().titles()', 'column().title()', function (title, row) {
8514		return this.iterator( 'column', function ( settings, column ) {
8515			// Argument shifting
8516			if (typeof title === 'number') {
8517				row = title;
8518				title = undefined;
8519			}
8520	
8521			var span = $('span.dt-column-title', this.column(column).header(row));
8522	
8523			if (title !== undefined) {
8524				span.html(title);
8525				return this;
8526			}
8527	
8528			return span.html();
8529		}, 1 );
8530	} );
8531	
8532	_api_registerPlural( 'columns().types()', 'column().type()', function () {
8533		return this.iterator( 'column', function ( settings, column ) {
8534			var type = settings.aoColumns[column].sType;
8535	
8536			// If the type was invalidated, then resolve it. This actually does
8537			// all columns at the moment. Would only happen once if getting all
8538			// column's data types.
8539			if (! type) {
8540				_fnColumnTypes(settings);
8541			}
8542	
8543			return type;
8544		}, 1 );
8545	} );
8546	
8547	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8548		var that = this;
8549		var changed = [];
8550		var ret = this.iterator( 'column', function ( settings, column ) {
8551			if ( vis === undefined ) {
8552				return settings.aoColumns[ column ].bVisible;
8553			} // else
8554			
8555			if (__setColumnVis( settings, column, vis )) {
8556				changed.push(column);
8557			}
8558		} );
8559	
8560		// Group the column visibility changes
8561		if ( vis !== undefined ) {
8562			this.iterator( 'table', function ( settings ) {
8563				// Redraw the header after changes
8564				_fnDrawHead( settings, settings.aoHeader );
8565				_fnDrawHead( settings, settings.aoFooter );
8566		
8567				// Update colspan for no records display. Child rows and extensions will use their own
8568				// listeners to do this - only need to update the empty table item here
8569				if ( ! settings.aiDisplay.length ) {
8570					$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8571				}
8572		
8573				_fnSaveState( settings );
8574	
8575				// Second loop once the first is done for events
8576				that.iterator( 'column', function ( settings, column ) {
8577					if (changed.includes(column)) {
8578						_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8579					}
8580				} );
8581	
8582				if ( changed.length && (calc === undefined || calc) ) {
8583					that.columns.adjust();
8584				}
8585			});
8586		}
8587	
8588		return ret;
8589	} );
8590	
8591	_api_registerPlural( 'columns().widths()', 'column().width()', function () {
8592		// Injects a fake row into the table for just a moment so the widths can
8593		// be read, regardless of colspan in the header and rows being present in
8594		// the body
8595		var columns = this.columns(':visible').count();
8596		var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
8597	
8598		$(this.table().body()).append(row);
8599	
8600		var widths = row.children().map(function () {
8601			return $(this).outerWidth();
8602		});
8603	
8604		row.remove();
8605		
8606		return this.iterator( 'column', function ( settings, column ) {
8607			var visIdx = _fnColumnIndexToVisible( settings, column );
8608	
8609			return visIdx !== null ? widths[visIdx] : 0;
8610		}, 1);
8611	} );
8612	
8613	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8614		return this.iterator( 'column', function ( settings, column ) {
8615			return type === 'visible' ?
8616				_fnColumnIndexToVisible( settings, column ) :
8617				column;
8618		}, 1 );
8619	} );
8620	
8621	_api_register( 'columns.adjust()', function () {
8622		return this.iterator( 'table', function ( settings ) {
8623			_fnAdjustColumnSizing( settings );
8624		}, 1 );
8625	} );
8626	
8627	_api_register( 'column.index()', function ( type, idx ) {
8628		if ( this.context.length !== 0 ) {
8629			var ctx = this.context[0];
8630	
8631			if ( type === 'fromVisible' || type === 'toData' ) {
8632				return _fnVisibleToColumnIndex( ctx, idx );
8633			}
8634			else if ( type === 'fromData' || type === 'toVisible' ) {
8635				return _fnColumnIndexToVisible( ctx, idx );
8636			}
8637		}
8638	} );
8639	
8640	_api_register( 'column()', function ( selector, opts ) {
8641		return _selector_first( this.columns( selector, opts ) );
8642	} );
8643	
8644	var __cell_selector = function ( settings, selector, opts )
8645	{
8646		var data = settings.aoData;
8647		var rows = _selector_row_indexes( settings, opts );
8648		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8649		var allCells = $(_flatten( [], cells ));
8650		var row;
8651		var columns = settings.aoColumns.length;
8652		var a, i, ien, j, o, host;
8653	
8654		var run = function ( s ) {
8655			var fnSelector = typeof s === 'function';
8656	
8657			if ( s === null || s === undefined || fnSelector ) {
8658				// All cells and function selectors
8659				a = [];
8660	
8661				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8662					row = rows[i];
8663	
8664					for ( j=0 ; j<columns ; j++ ) {
8665						o = {
8666							row: row,
8667							column: j
8668						};
8669	
8670						if ( fnSelector ) {
8671							// Selector - function
8672							host = data[ row ];
8673	
8674							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8675								a.push( o );
8676							}
8677						}
8678						else {
8679							// Selector - all
8680							a.push( o );
8681						}
8682					}
8683				}
8684	
8685				return a;
8686			}
8687			
8688			// Selector - index
8689			if ( $.isPlainObject( s ) ) {
8690				// Valid cell index and its in the array of selectable rows
8691				return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
8692					[s] :
8693					[];
8694			}
8695	
8696			// Selector - jQuery filtered cells
8697			var jqResult = allCells
8698				.filter( s )
8699				.map( function (i, el) {
8700					return { // use a new object, in case someone changes the values
8701						row:    el._DT_CellIndex.row,
8702						column: el._DT_CellIndex.column
8703					};
8704				} )
8705				.toArray();
8706	
8707			if ( jqResult.length || ! s.nodeName ) {
vendor: 4,988 bytes, lines 8708-8887
8708				return jqResult;
8709			}
8710	
8711			// Otherwise the selector is a node, and there is one last option - the
8712			// element might be a child of an element which has dt-row and dt-column
8713			// data attributes
8714			host = $(s).closest('*[data-dt-row]');
8715			return host.length ?
8716				[ {
8717					row: host.data('dt-row'),
8718					column: host.data('dt-column')
8719				} ] :
8720				[];
8721		};
8722	
8723		return _selector_run( 'cell', selector, run, settings, opts );
8724	};
8725	
8726	
8727	
8728	
8729	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8730		// Argument shifting
8731		if ( $.isPlainObject( rowSelector ) ) {
8732			// Indexes
8733			if ( rowSelector.row === undefined ) {
8734				// Selector options in first parameter
8735				opts = rowSelector;
8736				rowSelector = null;
8737			}
8738			else {
8739				// Cell index objects in first parameter
8740				opts = columnSelector;
8741				columnSelector = null;
8742			}
8743		}
8744		if ( $.isPlainObject( columnSelector ) ) {
8745			opts = columnSelector;
8746			columnSelector = null;
8747		}
8748	
8749		// Cell selector
8750		if ( columnSelector === null || columnSelector === undefined ) {
8751			return this.iterator( 'table', function ( settings ) {
8752				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8753			} );
8754		}
8755	
8756		// The default built in options need to apply to row and columns
8757		var internalOpts = opts ? {
8758			page: opts.page,
8759			order: opts.order,
8760			search: opts.search
8761		} : {};
8762	
8763		// Row + column selector
8764		var columns = this.columns( columnSelector, internalOpts );
8765		var rows = this.rows( rowSelector, internalOpts );
8766		var i, ien, j, jen;
8767	
8768		var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
8769			var a = [];
8770	
8771			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8772				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8773					a.push( {
8774						row:    rows[idx][i],
8775						column: columns[idx][j]
8776					} );
8777				}
8778			}
8779	
8780			return a;
8781		}, 1 );
8782	
8783		// There is currently only one extension which uses a cell selector extension
8784		// It is a _major_ performance drag to run this if it isn't needed, so this is
8785		// an extension specific check at the moment
8786		var cells = opts && opts.selected ?
8787			this.cells( cellsNoOpts, opts ) :
8788			cellsNoOpts;
8789	
8790		$.extend( cells.selector, {
8791			cols: columnSelector,
8792			rows: rowSelector,
8793			opts: opts
8794		} );
8795	
8796		return cells;
8797	} );
8798	
8799	
8800	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8801		return this.iterator( 'cell', function ( settings, row, column ) {
8802			var data = settings.aoData[ row ];
8803	
8804			return data && data.anCells ?
8805				data.anCells[ column ] :
8806				undefined;
8807		}, 1 );
8808	} );
8809	
8810	
8811	_api_register( 'cells().data()', function () {
8812		return this.iterator( 'cell', function ( settings, row, column ) {
8813			return _fnGetCellData( settings, row, column );
8814		}, 1 );
8815	} );
8816	
8817	
8818	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8819		type = type === 'search' ? '_aFilterData' : '_aSortData';
8820	
8821		return this.iterator( 'cell', function ( settings, row, column ) {
8822			return settings.aoData[ row ][ type ][ column ];
8823		}, 1 );
8824	} );
8825	
8826	
8827	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8828		return this.iterator( 'cell', function ( settings, row, column ) {
8829			return _fnGetCellData( settings, row, column, type );
8830		}, 1 );
8831	} );
8832	
8833	
8834	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8835		return this.iterator( 'cell', function ( settings, row, column ) {
8836			return {
8837				row: row,
8838				column: column,
8839				columnVisible: _fnColumnIndexToVisible( settings, column )
8840			};
8841		}, 1 );
8842	} );
8843	
8844	
8845	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8846		return this.iterator( 'cell', function ( settings, row, column ) {
8847			_fnInvalidate( settings, row, src, column );
8848		} );
8849	} );
8850	
8851	
8852	
8853	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8854		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8855	} );
8856	
8857	
8858	_api_register( 'cell().data()', function ( data ) {
8859		var ctx = this.context;
8860		var cell = this[0];
8861	
8862		if ( data === undefined ) {
8863			// Get
8864			return ctx.length && cell.length ?
8865				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8866				undefined;
8867		}
8868	
8869		// Set
8870		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8871		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8872	
8873		return this;
8874	} );
8875	
8876	
8877	
8878	/**
8879	 * Get current ordering (sorting) that has been applied to the table.
8880	 *
8881	 * @returns {array} 2D array containing the sorting information for the first
8882	 *   table in the current context. Each element in the parent array represents
8883	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
8884	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8885	 *   the column index that the sorting condition applies to, the second is the
8886	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
8887	 *   index of the sorting order from the `column.sorting` initialisation array.
8888	 *//**
8889	 * Set the ordering for the table.
8890	 *
8891	 * @param {integer} order Column index to sort upon.
8892	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8893	 * @returns {DataTables.Api} this
8894	 *//**
8895	 * Set the ordering for the table.
8896	 *
8897	 * @param {array} order 1D array of sorting information to be applied.
8898	 * @param {array} [...] Optional additional sorting conditions
8899	 * @returns {DataTables.Api} this
8900	 *//**
8901	 * Set the ordering for the table.
8902	 *
8903	 * @param {array} order 2D array of sorting information to be applied.
8904	 * @returns {DataTables.Api} this
8905	 */
8906	_api_register( 'order()', function ( order, dir ) {
8907		var ctx = this.context;
8908		var args = Array.prototype.slice.call( arguments );
8909	
8910		if ( order === undefined ) {
8911			// get
8912			return ctx.length !== 0 ?
8913				ctx[0].aaSorting :
8914				undefined;
8915		}
8916	
8917		// set
8918		if ( typeof order === 'number' ) {
8919			// Simple column / direction passed in
8920			order = [ [ order, dir ] ];
8921		}
8922		else if ( args.length > 1 ) {
8923			// Arguments passed in (list of 1D arrays)
8924			order = args;
8925		}
8926		// otherwise a 2D array was passed in
8927	
8928		return this.iterator( 'table', function ( settings ) {
8929			settings.aaSorting = Array.isArray(order) ? order.slice() : order;
8930		} );
8931	} );
8932	
8933	
8934	/**
8935	 * Attach a sort listener to an element for a given column
8936	 *
8937	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8938	 *   listener to. This can take the form of a single DOM node, a jQuery
8939	 *   collection of nodes or a jQuery selector which will identify the node(s).
8940	 * @param {integer} column the column that a click on this node will sort on
8941	 * @param {function} [callback] callback function when sort is run
8942	 * @returns {DataTables.Api} this
8943	 */
8944	_api_register( 'order.listener()', function ( node, column, callback ) {
8945		return this.iterator( 'table', function ( settings ) {
8946			_fnSortAttachListener(settings, node, {}, column, callback);
8947		} );
8948	} );
8949	
8950	
8951	_api_register( 'order.fixed()', function ( set ) {
8952		if ( ! set ) {
8953			var ctx = this.context;
8954			var fixed = ctx.length ?
8955				ctx[0].aaSortingFixed :
8956				undefined;
8957	
8958			return Array.isArray( fixed ) ?
8959				{ pre: fixed } :
8960				fixed;
8961		}
8962	
8963		return this.iterator( 'table', function ( settings ) {
8964			settings.aaSortingFixed = $.extend( true, {}, set );
8965		} );
8966	} );
8967	
8968	
8969	// Order by the selected column(s)
8970	_api_register( [
8971		'columns().order()',
8972		'column().order()'
8973	], function ( dir ) {
8974		var that = this;
8975	
8976		if ( ! dir ) {
8977			return this.iterator( 'column', function ( settings, idx ) {
8978				var sort = _fnSortFlatten( settings );
8979	
8980				for ( var i=0, ien=sort.length ; i<ien ; i++ ) {
8981					if ( sort[i].col === idx ) {
8982						return sort[i].dir;
8983					}
8984				}
8985	
8986				return null;
8987			}, 1 );
8988		}
8989		else {
8990			return this.iterator( 'table', function ( settings, i ) {
8991				settings.aaSorting = that[i].map( function (col) {
8992					return [ col, dir ];
8993				} );
8994			} );
8995		}
8996	} );
8997	
8998	_api_registerPlural('columns().orderable()', 'column().orderable()', function ( directions ) {
8999		return this.iterator( 'column', function ( settings, idx ) {
9000			var col = settings.aoColumns[idx];
9001	
9002			return directions ?
9003				col.asSorting :
9004				col.bSortable;
9005		}, 1 );
9006	} );
9007	
9008	
9009	_api_register( 'processing()', function ( show ) {
9010		return this.iterator( 'table', function ( ctx ) {
9011			_fnProcessingDisplay( ctx, show );
9012		} );
9013	} );
9014	
9015	
9016	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9017		var ctx = this.context;
9018	
9019		if ( input === undefined ) {
9020			// get
9021			return ctx.length !== 0 ?
9022				ctx[0].oPreviousSearch.search :
9023				undefined;
9024		}
9025	
9026		// set
9027		return this.iterator( 'table', function ( settings ) {
9028			if ( ! settings.oFeatures.bFilter ) {
9029				return;
9030			}
9031	
9032			if (typeof regex === 'object') {
9033				// New style options to pass to the search builder
9034				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, regex, {
9035					search: input
9036				} ) );
9037			}
9038			else {
9039				// Compat for the old options
9040				_fnFilterComplete( settings, $.extend( settings.oPreviousSearch, {
9041					search: input,
9042					regex:  regex === null ? false : regex,
9043					smart:  smart === null ? true  : smart,
9044					caseInsensitive: caseInsen === null ? true : caseInsen
9045				} ) );
9046			}
9047		} );
9048	} );
9049	
9050	_api_register( 'search.fixed()', function ( name, search ) {
9051		var ret = this.iterator( true, 'table', function ( settings ) {
9052			var fixed = settings.searchFixed;
9053	
9054			if (! name) {
9055				return Object.keys(fixed)
9056			}
9057			else if (search === undefined) {
9058				return fixed[name];
9059			}
9060			else if (search === null) {
9061				delete fixed[name];
9062			}
9063			else {
9064				fixed[name] = search;
9065			}
9066	
9067			return this;
9068		} );
9069	
9070		return name !== undefined && search === undefined
9071			? ret[0]
9072			: ret;
9073	} );
9074	
9075	_api_registerPlural(
9076		'columns().search()',
9077		'column().search()',
9078		function ( input, regex, smart, caseInsen ) {
9079			return this.iterator( 'column', function ( settings, column ) {
9080				var preSearch = settings.aoPreSearchCols;
9081	
9082				if ( input === undefined ) {
9083					// get
9084					return preSearch[ column ].search;
9085				}
9086	
9087				// set
9088				if ( ! settings.oFeatures.bFilter ) {
9089					return;
9090				}
9091	
9092				if (typeof regex === 'object') {
9093					// New style options to pass to the search builder
9094					$.extend( preSearch[ column ], regex, {
9095						search: input
9096					} );
9097				}
9098				else {
9099					// Old style (with not all options available)
9100					$.extend( preSearch[ column ], {
9101						search: input,
9102						regex:  regex === null ? false : regex,
9103						smart:  smart === null ? true  : smart,
9104						caseInsensitive: caseInsen === null ? true : caseInsen
9105					} );
9106				}
9107	
9108				_fnFilterComplete( settings, settings.oPreviousSearch );
9109			} );
9110		}
9111	);
9112	
9113	_api_register([
9114			'columns().search.fixed()',
9115			'column().search.fixed()'
9116		],
9117		function ( name, search ) {
9118			var ret = this.iterator( true, 'column', function ( settings, colIdx ) {
9119				var fixed = settings.aoColumns[colIdx].searchFixed;
9120	
9121				if (! name) {
9122					return Object.keys(fixed)
9123				}
9124				else if (search === undefined) {
9125					return fixed[name];
9126				}
9127				else if (search === null) {
9128					delete fixed[name];
9129				}
9130				else {
9131					fixed[name] = search;
9132				}
9133	
9134				return this;
9135			} );
9136	
9137			return name !== undefined && search === undefined
9138				? ret[0]
9139				: ret;
9140		}
9141	);
9142	/*
9143	 * State API methods
9144	 */
9145	
9146	_api_register( 'state()', function ( set, ignoreTime ) {
9147		// getter
9148		if ( ! set ) {
9149			return this.context.length ?
9150				this.context[0].oSavedState :
9151				null;
9152		}
9153	
9154		var setMutate = $.extend( true, {}, set );
9155	
9156		// setter
9157		return this.iterator( 'table', function ( settings ) {
9158			if ( ignoreTime !== false ) {
9159				setMutate.time = +new Date() + 100;
9160			}
9161	
9162			_fnImplementState( settings, setMutate, function(){} );
9163		} );
9164	} );
9165	
9166	
9167	_api_register( 'state.clear()', function () {
9168		return this.iterator( 'table', function ( settings ) {
9169			// Save an empty object
9170			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9171		} );
9172	} );
9173	
9174	
9175	_api_register( 'state.loaded()', function () {
9176		return this.context.length ?
9177			this.context[0].oLoadedState :
9178			null;
9179	} );
9180	
9181	
9182	_api_register( 'state.save()', function () {
9183		return this.iterator( 'table', function ( settings ) {
9184			_fnSaveState( settings );
9185		} );
9186	} );
9187	
9188	/**
9189	 * Set the jQuery or window object to be used by DataTables
9190	 *
9191	 * @param {*} module Library / container object
9192	 * @param {string} [type] Library or container type `lib`, `win` or `datetime`.
9193	 *   If not provided, automatic detection is attempted.
9194	 */
9195	DataTable.use = function (module, type) {
9196		if (type === 'lib' || module.fn) {
9197			$ = module;
9198		}
9199		else if (type == 'win' || module.document) {
9200			window = module;
9201			document = module.document;
9202		}
9203		else if (type === 'datetime' || module.type === 'DateTime') {
9204			DataTable.DateTime = module;
9205		}
9206	}
9207	
9208	/**
9209	 * CommonJS factory function pass through. This will check if the arguments
9210	 * given are a window object or a jQuery object. If so they are set
9211	 * accordingly.
9212	 * @param {*} root Window
9213	 * @param {*} jq jQUery
9214	 * @returns {boolean} Indicator
9215	 */
9216	DataTable.factory = function (root, jq) {
9217		var is = false;
9218	
9219		// Test if the first parameter is a window object
9220		if (root && root.document) {
9221			window = root;
9222			document = root.document;
9223		}
9224	
9225		// Test if the second parameter is a jQuery object
9226		if (jq && jq.fn && jq.fn.jquery) {
9227			$ = jq;
9228			is = true;
9229		}
9230	
9231		return is;
9232	}
9233	
9234	/**
9235	 * Provide a common method for plug-ins to check the version of DataTables being
9236	 * used, in order to ensure compatibility.
9237	 *
9238	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
9239	 *    Note that the formats "X" and "X.Y" are also acceptable.
9240	 *  @param {string} [version2=current DataTables version] As above, but optional.
9241	 *   If not given the current DataTables version will be used.
9242	 *  @returns {boolean} true if this version of DataTables is greater or equal to
9243	 *    the required version, or false if this version of DataTales is not
9244	 *    suitable
9245	 *  @static
9246	 *  @dtopt API-Static
9247	 *
9248	 *  @example
9249	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9250	 */
9251	DataTable.versionCheck = function( version, version2 )
9252	{
9253		var aThis = version2 ?
9254			version2.split('.') :
9255			DataTable.version.split('.');
9256		var aThat = version.split('.');
9257		var iThis, iThat;
9258	
9259		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9260			iThis = parseInt( aThis[i], 10 ) || 0;
9261			iThat = parseInt( aThat[i], 10 ) || 0;
9262	
9263			// Parts are the same, keep comparing
9264			if (iThis === iThat) {
9265				continue;
9266			}
9267	
9268			// Parts are different, return immediately
9269			return iThis > iThat;
9270		}
9271	
9272		return true;
9273	};
9274	
9275	
9276	/**
9277	 * Check if a `<table>` node is a DataTable table already or not.
9278	 *
9279	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9280	 *      selector for the table to test. Note that if more than more than one
9281	 *      table is passed on, only the first will be checked
9282	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
9283	 *  @static
9284	 *  @dtopt API-Static
9285	 *
9286	 *  @example
9287	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9288	 *      $('#example').dataTable();
9289	 *    }
9290	 */
9291	DataTable.isDataTable = function ( table )
9292	{
9293		var t = $(table).get(0);
9294		var is = false;
9295	
9296		if ( table instanceof DataTable.Api ) {
9297			return true;
9298		}
9299	
9300		$.each( DataTable.settings, function (i, o) {
9301			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9302			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9303	
9304			if ( o.nTable === t || head === t || foot === t ) {
9305				is = true;
9306			}
9307		} );
9308	
9309		return is;
9310	};
9311	
9312	
9313	/**
9314	 * Get all DataTable tables that have been initialised - optionally you can
9315	 * select to get only currently visible tables.
9316	 *
9317	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9318	 *    or visible tables only.
9319	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9320	 *    DataTables
9321	 *  @static
9322	 *  @dtopt API-Static
9323	 *
9324	 *  @example
9325	 *    $.each( $.fn.dataTable.tables(true), function () {
9326	 *      $(table).DataTable().columns.adjust();
9327	 *    } );
9328	 */
9329	DataTable.tables = function ( visible )
9330	{
9331		var api = false;
9332	
9333		if ( $.isPlainObject( visible ) ) {
9334			api = visible.api;
9335			visible = visible.visible;
9336		}
9337	
9338		var a = DataTable.settings
9339			.filter( function (o) {
9340				return !visible || (visible && $(o.nTable).is(':visible')) 
9341					? true
9342					: false;
9343			} )
9344			.map( function (o) {
9345				return o.nTable;
9346			});
9347	
9348		return api ?
9349			new _Api( a ) :
9350			a;
9351	};
9352	
9353	
9354	/**
9355	 * Convert from camel case parameters to Hungarian notation. This is made public
9356	 * for the extensions to provide the same ability as DataTables core to accept
9357	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9358	 * parameters.
9359	 *
9360	 *  @param {object} src The model object which holds all parameters that can be
9361	 *    mapped.
9362	 *  @param {object} user The object to convert from camel case to Hungarian.
9363	 *  @param {boolean} force When set to `true`, properties which already have a
9364	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
9365	 *    won't be.
9366	 */
9367	DataTable.camelToHungarian = _fnCamelToHungarian;
9368	
9369	
9370	
9371	/**
9372	 *
9373	 */
9374	_api_register( '$()', function ( selector, opts ) {
9375		var
9376			rows   = this.rows( opts ).nodes(), // Get all rows
9377			jqRows = $(rows);
9378	
9379		return $( [].concat(
9380			jqRows.filter( selector ).toArray(),
9381			jqRows.find( selector ).toArray()
9382		) );
9383	} );
9384	
9385	
9386	// jQuery functions to operate on the tables
9387	$.each( [ 'on', 'one', 'off' ], function (i, key) {
9388		_api_register( key+'()', function ( /* event, handler */ ) {
9389			var args = Array.prototype.slice.call(arguments);
9390	
9391			// Add the `dt` namespace automatically if it isn't already present
9392			args[0] = args[0].split( /\s/ ).map( function ( e ) {
9393				return ! e.match(/\.dt\b/) ?
9394					e+'.dt' :
9395					e;
9396				} ).join( ' ' );
9397	
9398			var inst = $( this.tables().nodes() );
9399			inst[key].apply( inst, args );
9400			return this;
9401		} );
9402	} );
9403	
9404	
9405	_api_register( 'clear()', function () {
9406		return this.iterator( 'table', function ( settings ) {
9407			_fnClearTable( settings );
9408		} );
9409	} );
9410	
9411	
9412	_api_register( 'error()', function (msg) {
9413		return this.iterator( 'table', function ( settings ) {
9414			_fnLog( settings, 0, msg );
9415		} );
9416	} );
9417	
9418	
9419	_api_register( 'settings()', function () {
9420		return new _Api( this.context, this.context );
9421	} );
9422	
9423	
9424	_api_register( 'init()', function () {
9425		var ctx = this.context;
9426		return ctx.length ? ctx[0].oInit : null;
9427	} );
9428	
9429	
9430	_api_register( 'data()', function () {
9431		return this.iterator( 'table', function ( settings ) {
9432			return _pluck( settings.aoData, '_aData' );
9433		} ).flatten();
9434	} );
9435	
9436	
9437	_api_register( 'trigger()', function ( name, args, bubbles ) {
9438		return this.iterator( 'table', function ( settings ) {
9439			return _fnCallbackFire( settings, null, name, args, bubbles );
9440		} ).flatten();
9441	} );
9442	
9443	
9444	_api_register( 'ready()', function ( fn ) {
9445		var ctx = this.context;
9446	
9447		// Get status of first table
9448		if (! fn) {
9449			return ctx.length
9450				? (ctx[0]._bInitComplete || false)
9451				: null;
9452		}
9453	
9454		// Function to run either once the table becomes ready or
9455		// immediately if it is already ready.
9456		return this.tables().every(function () {
9457			if (this.context[0]._bInitComplete) {
9458				fn.call(this);
9459			}
9460			else {
9461				this.on('init', function () {
9462					fn.call(this);
9463				});
9464			}
9465		} );
9466	} );
9467	
9468	
9469	_api_register( 'destroy()', function ( remove ) {
9470		remove = remove || false;
9471	
9472		return this.iterator( 'table', function ( settings ) {
9473			var classes   = settings.oClasses;
9474			var table     = settings.nTable;
9475			var tbody     = settings.nTBody;
9476			var thead     = settings.nTHead;
9477			var tfoot     = settings.nTFoot;
9478			var jqTable   = $(table);
9479			var jqTbody   = $(tbody);
9480			var jqWrapper = $(settings.nTableWrapper);
9481			var rows      = settings.aoData.map( function (r) { return r ? r.nTr : null; } );
9482			var orderClasses = classes.order;
9483	
9484			// Flag to note that the table is currently being destroyed - no action
9485			// should be taken
9486			settings.bDestroying = true;
9487	
9488			// Fire off the destroy callbacks for plug-ins etc
9489			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings], true );
9490	
9491			// If not being removed from the document, make all columns visible
9492			if ( ! remove ) {
9493				new _Api( settings ).columns().visible( true );
9494			}
9495	
9496			// Blitz all `DT` namespaced events (these are internal events, the
9497			// lowercase, `dt` events are user subscribed and they are responsible
9498			// for removing them
9499			jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9500			$(window).off('.DT-'+settings.sInstance);
9501	
9502			// When scrolling we had to break the table up - restore it
9503			if ( table != thead.parentNode ) {
9504				jqTable.children('thead').detach();
9505				jqTable.append( thead );
9506			}
9507	
9508			if ( tfoot && table != tfoot.parentNode ) {
9509				jqTable.children('tfoot').detach();
9510				jqTable.append( tfoot );
9511			}
9512	
9513			settings.colgroup.remove();
9514	
9515			settings.aaSorting = [];
9516			settings.aaSortingFixed = [];
9517			_fnSortingClasses( settings );
9518	
9519			$('th, td', thead)
9520				.removeClass(
9521					orderClasses.canAsc + ' ' +
9522					orderClasses.canDesc + ' ' +
9523					orderClasses.isAsc + ' ' +
9524					orderClasses.isDesc
9525				)
9526				.css('width', '');
9527	
9528			// Add the TR elements back into the table in their original order
9529			jqTbody.children().detach();
9530			jqTbody.append( rows );
9531	
9532			var orig = settings.nTableWrapper.parentNode;
9533			var insertBefore = settings.nTableWrapper.nextSibling;
9534	
9535			// Remove the DataTables generated nodes, events and classes
9536			var removedMethod = remove ? 'remove' : 'detach';
9537			jqTable[ removedMethod ]();
9538			jqWrapper[ removedMethod ]();
9539	
9540			// If we need to reattach the table to the document
9541			if ( ! remove && orig ) {
9542				// insertBefore acts like appendChild if !arg[1]
9543				orig.insertBefore( table, insertBefore );
9544	
9545				// Restore the width of the original table - was read from the style property,
9546				// so we can restore directly to that
9547				jqTable
9548					.css( 'width', settings.sDestroyWidth )
9549					.removeClass( classes.table );
9550			}
9551	
9552			/* Remove the settings object from the settings array */
9553			var idx = DataTable.settings.indexOf(settings);
9554			if ( idx !== -1 ) {
9555				DataTable.settings.splice( idx, 1 );
9556			}
9557		} );
9558	} );
9559	
9560	
9561	// Add the `every()` method for rows, columns and cells in a compact form
9562	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9563		_api_register( type+'s().every()', function ( fn ) {
9564			var opts = this.selector.opts;
9565			var api = this;
9566			var inst;
9567			var counter = 0;
9568	
9569			return this.iterator( 'every', function ( settings, selectedIdx, tableIdx ) {
9570				inst = api[ type ](selectedIdx, opts);
9571	
9572				if (type === 'cell') {
9573					fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
9574				}
9575				else {
9576					fn.call(inst, selectedIdx, tableIdx, counter);
9577				}
9578	
9579				counter++;
9580			} );
9581		} );
9582	} );
9583	
9584	
9585	// i18n method for extensions to be able to use the language object from the
9586	// DataTable
9587	_api_register( 'i18n()', function ( token, def, plural ) {
9588		var ctx = this.context[0];
9589		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9590	
9591		if ( resolved === undefined ) {
9592			resolved = def;
9593		}
9594	
9595		if ( $.isPlainObject( resolved ) ) {
9596			resolved = plural !== undefined && resolved[ plural ] !== undefined ?
9597				resolved[ plural ] :
9598				resolved._;
9599		}
9600	
9601		return typeof resolved === 'string'
9602			? resolved.replace( '%d', plural ) // nb: plural might be undefined,
9603			: resolved;
9604	} );
9605	
9606	/**
9607	 * Version string for plug-ins to check compatibility. Allowed format is
9608	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9609	 * only for non-release builds. See https://semver.org/ for more information.
9610	 *  @member
9611	 *  @type string
9612	 *  @default Version number
9613	 */
9614	DataTable.version = "2.0.7";
9615	
9616	/**
9617	 * Private data store, containing all of the settings objects that are
9618	 * created for the tables on a given page.
9619	 *
9620	 * Note that the `DataTable.settings` object is aliased to
9621	 * `jQuery.fn.dataTableExt` through which it may be accessed and
9622	 * manipulated, or `jQuery.fn.dataTable.settings`.
9623	 *  @member
9624	 *  @type array
9625	 *  @default []
9626	 *  @private
9627	 */
9628	DataTable.settings = [];
9629	
9630	/**
9631	 * Object models container, for the various models that DataTables has
9632	 * available to it. These models define the objects that are used to hold
9633	 * the active state and configuration of the table.
9634	 *  @namespace
9635	 */
9636	DataTable.models = {};
9637	
9638	
9639	
9640	/**
9641	 * Template object for the way in which DataTables holds information about
9642	 * search information for the global filter and individual column filters.
9643	 *  @namespace
9644	 */
9645	DataTable.models.oSearch = {
9646		/**
9647		 * Flag to indicate if the filtering should be case insensitive or not
9648		 */
9649		"caseInsensitive": true,
9650	
9651		/**
9652		 * Applied search term
9653		 */
9654		"search": "",
9655	
9656		/**
9657		 * Flag to indicate if the search term should be interpreted as a
9658		 * regular expression (true) or not (false) and therefore and special
9659		 * regex characters escaped.
9660		 */
9661		"regex": false,
9662	
9663		/**
9664		 * Flag to indicate if DataTables is to use its smart filtering or not.
9665		 */
9666		"smart": true,
9667	
9668		/**
9669		 * Flag to indicate if DataTables should only trigger a search when
9670		 * the return key is pressed.
9671		 */
9672		"return": false
9673	};
9674	
9675	
9676	
9677	
9678	/**
9679	 * Template object for the way in which DataTables holds information about
9680	 * each individual row. This is the object format used for the settings
9681	 * aoData array.
9682	 *  @namespace
9683	 */
9684	DataTable.models.oRow = {
9685		/**
9686		 * TR element for the row
9687		 */
9688		"nTr": null,
9689	
9690		/**
9691		 * Array of TD elements for each row. This is null until the row has been
9692		 * created.
9693		 */
9694		"anCells": null,
9695	
9696		/**
9697		 * Data object from the original data source for the row. This is either
9698		 * an array if using the traditional form of DataTables, or an object if
9699		 * using mData options. The exact type will depend on the passed in
9700		 * data from the data source, or will be an array if using DOM a data
9701		 * source.
9702		 */
9703		"_aData": [],
9704	
9705		/**
9706		 * Sorting data cache - this array is ostensibly the same length as the
9707		 * number of columns (although each index is generated only as it is
9708		 * needed), and holds the data that is used for sorting each column in the
9709		 * row. We do this cache generation at the start of the sort in order that
9710		 * the formatting of the sort data need be done only once for each cell
9711		 * per sort. This array should not be read from or written to by anything
9712		 * other than the master sorting methods.
9713		 */
9714		"_aSortData": null,
9715	
9716		/**
9717		 * Per cell filtering data cache. As per the sort data cache, used to
9718		 * increase the performance of the filtering in DataTables
9719		 */
9720		"_aFilterData": null,
9721	
9722		/**
9723		 * Filtering data cache. This is the same as the cell filtering cache, but
9724		 * in this case a string rather than an array. This is easily computed with
9725		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9726		 * needed on every search (memory traded for performance)
9727		 */
9728		"_sFilterRow": null,
9729	
9730		/**
9731		 * Denote if the original data source was from the DOM, or the data source
9732		 * object. This is used for invalidating data, so DataTables can
9733		 * automatically read data from the original source, unless uninstructed
9734		 * otherwise.
9735		 */
9736		"src": null,
9737	
9738		/**
9739		 * Index in the aoData array. This saves an indexOf lookup when we have the
9740		 * object, but want to know the index
9741		 */
9742		"idx": -1,
9743	
9744		/**
9745		 * Cached display value
9746		 */
9747		displayData: null
9748	};
9749	
9750	
9751	/**
9752	 * Template object for the column information object in DataTables. This object
9753	 * is held in the settings aoColumns array and contains all the information that
9754	 * DataTables needs about each individual column.
9755	 *
9756	 * Note that this object is related to {@link DataTable.defaults.column}
9757	 * but this one is the internal data store for DataTables's cache of columns.
9758	 * It should NOT be manipulated outside of DataTables. Any configuration should
9759	 * be done through the initialisation options.
9760	 *  @namespace
9761	 */
9762	DataTable.models.oColumn = {
9763		/**
9764		 * Column index.
9765		 */
9766		"idx": null,
9767	
9768		/**
9769		 * A list of the columns that sorting should occur on when this column
9770		 * is sorted. That this property is an array allows multi-column sorting
9771		 * to be defined for a column (for example first name / last name columns
9772		 * would benefit from this). The values are integers pointing to the
9773		 * columns to be sorted on (typically it will be a single integer pointing
9774		 * at itself, but that doesn't need to be the case).
9775		 */
9776		"aDataSort": null,
9777	
9778		/**
9779		 * Define the sorting directions that are applied to the column, in sequence
9780		 * as the column is repeatedly sorted upon - i.e. the first value is used
9781		 * as the sorting direction when the column if first sorted (clicked on).
9782		 * Sort it again (click again) and it will move on to the next index.
9783		 * Repeat until loop.
9784		 */
9785		"asSorting": null,
9786	
9787		/**
9788		 * Flag to indicate if the column is searchable, and thus should be included
9789		 * in the filtering or not.
9790		 */
9791		"bSearchable": null,
9792	
9793		/**
9794		 * Flag to indicate if the column is sortable or not.
9795		 */
9796		"bSortable": null,
9797	
9798		/**
9799		 * Flag to indicate if the column is currently visible in the table or not
9800		 */
9801		"bVisible": null,
9802	
9803		/**
9804		 * Store for manual type assignment using the `column.type` option. This
9805		 * is held in store so we can manipulate the column's `sType` property.
9806		 */
9807		"_sManualType": null,
9808	
9809		/**
9810		 * Flag to indicate if HTML5 data attributes should be used as the data
9811		 * source for filtering or sorting. True is either are.
9812		 */
9813		"_bAttrSrc": false,
9814	
9815		/**
9816		 * Developer definable function that is called whenever a cell is created (Ajax source,
9817		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9818		 * allowing you to modify the DOM element (add background colour for example) when the
9819		 * element is available.
9820		 */
9821		"fnCreatedCell": null,
9822	
9823		/**
9824		 * Function to get data from a cell in a column. You should <b>never</b>
9825		 * access data directly through _aData internally in DataTables - always use
9826		 * the method attached to this property. It allows mData to function as
9827		 * required. This function is automatically assigned by the column
9828		 * initialisation method
9829		 */
9830		"fnGetData": null,
9831	
9832		/**
9833		 * Function to set data for a cell in the column. You should <b>never</b>
9834		 * set the data directly to _aData internally in DataTables - always use
9835		 * this method. It allows mData to function as required. This function
9836		 * is automatically assigned by the column initialisation method
9837		 */
9838		"fnSetData": null,
9839	
9840		/**
9841		 * Property to read the value for the cells in the column from the data
9842		 * source array / object. If null, then the default content is used, if a
9843		 * function is given then the return from the function is used.
9844		 */
9845		"mData": null,
9846	
9847		/**
9848		 * Partner property to mData which is used (only when defined) to get
9849		 * the data - i.e. it is basically the same as mData, but without the
9850		 * 'set' option, and also the data fed to it is the result from mData.
9851		 * This is the rendering method to match the data method of mData.
9852		 */
9853		"mRender": null,
9854	
9855		/**
9856		 * The class to apply to all TD elements in the table's TBODY for the column
9857		 */
9858		"sClass": null,
9859	
9860		/**
9861		 * When DataTables calculates the column widths to assign to each column,
9862		 * it finds the longest string in each column and then constructs a
9863		 * temporary table and reads the widths from that. The problem with this
9864		 * is that "mmm" is much wider then "iiii", but the latter is a longer
9865		 * string - thus the calculation can go wrong (doing it properly and putting
9866		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9867		 * a "work around" we provide this option. It will append its value to the
9868		 * text that is found to be the longest string for the column - i.e. padding.
9869		 */
9870		"sContentPadding": null,
9871	
9872		/**
9873		 * Allows a default value to be given for a column's data, and will be used
9874		 * whenever a null data source is encountered (this can be because mData
9875		 * is set to null, or because the data source itself is null).
9876		 */
9877		"sDefaultContent": null,
9878	
9879		/**
9880		 * Name for the column, allowing reference to the column by name as well as
9881		 * by index (needs a lookup to work by name).
9882		 */
9883		"sName": null,
9884	
9885		/**
9886		 * Custom sorting data type - defines which of the available plug-ins in
9887		 * afnSortData the custom sorting will use - if any is defined.
9888		 */
9889		"sSortDataType": 'std',
9890	
9891		/**
9892		 * Class to be applied to the header element when sorting on this column
9893		 */
9894		"sSortingClass": null,
9895	
9896		/**
9897		 * Title of the column - what is seen in the TH element (nTh).
9898		 */
9899		"sTitle": null,
9900	
9901		/**
9902		 * Column sorting and filtering type
9903		 */
9904		"sType": null,
9905	
9906		/**
9907		 * Width of the column
9908		 */
9909		"sWidth": null,
9910	
9911		/**
9912		 * Width of the column when it was first "encountered"
9913		 */
9914		"sWidthOrig": null,
9915	
9916		/** Cached string which is the longest in the column */
9917		maxLenString: null,
9918	
9919		/**
9920		 * Store for named searches
9921		 */
9922		searchFixed: null
9923	};
9924	
9925	
9926	/*
9927	 * Developer note: The properties of the object below are given in Hungarian
9928	 * notation, that was used as the interface for DataTables prior to v1.10, however
9929	 * from v1.10 onwards the primary interface is camel case. In order to avoid
9930	 * breaking backwards compatibility utterly with this change, the Hungarian
9931	 * version is still, internally the primary interface, but is is not documented
9932	 * - hence the @name tags in each doc comment. This allows a Javascript function
9933	 * to create a map from Hungarian notation to camel case (going the other direction
9934	 * would require each property to be listed, which would add around 3K to the size
9935	 * of DataTables, while this method is about a 0.5K hit).
9936	 *
9937	 * Ultimately this does pave the way for Hungarian notation to be dropped
9938	 * completely, but that is a massive amount of work and will break current
9939	 * installs (therefore is on-hold until v2).
9940	 */
9941	
9942	/**
9943	 * Initialisation options that can be given to DataTables at initialisation
9944	 * time.
9945	 *  @namespace
9946	 */
9947	DataTable.defaults = {
9948		/**
9949		 * An array of data to use for the table, passed in at initialisation which
9950		 * will be used in preference to any data which is already in the DOM. This is
9951		 * particularly useful for constructing tables purely in Javascript, for
9952		 * example with a custom Ajax call.
9953		 */
9954		"aaData": null,
9955	
9956	
9957		/**
9958		 * If ordering is enabled, then DataTables will perform a first pass sort on
9959		 * initialisation. You can define which column(s) the sort is performed
9960		 * upon, and the sorting direction, with this variable. The `sorting` array
9961		 * should contain an array for each column to be sorted initially containing
9962		 * the column's index and a direction string ('asc' or 'desc').
9963		 */
9964		"aaSorting": [[0,'asc']],
9965	
9966	
9967		/**
9968		 * This parameter is basically identical to the `sorting` parameter, but
9969		 * cannot be overridden by user interaction with the table. What this means
9970		 * is that you could have a column (visible or hidden) which the sorting
9971		 * will always be forced on first - any sorting after that (from the user)
9972		 * will then be performed as required. This can be useful for grouping rows
9973		 * together.
9974		 */
9975		"aaSortingFixed": [],
9976	
9977	
9978		/**
9979		 * DataTables can be instructed to load data to display in the table from a
9980		 * Ajax source. This option defines how that Ajax call is made and where to.
9981		 *
9982		 * The `ajax` property has three different modes of operation, depending on
9983		 * how it is defined. These are:
9984		 *
9985		 * * `string` - Set the URL from where the data should be loaded from.
9986		 * * `object` - Define properties for `jQuery.ajax`.
9987		 * * `function` - Custom data get function
9988		 *
9989		 * `string`
9990		 * --------
9991		 *
9992		 * As a string, the `ajax` property simply defines the URL from which
9993		 * DataTables will load data.
9994		 *
9995		 * `object`
9996		 * --------
9997		 *
9998		 * As an object, the parameters in the object are passed to
9999		 * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
10000		 * of the Ajax request. DataTables has a number of default parameters which
10001		 * you can override using this option. Please refer to the jQuery
10002		 * documentation for a full description of the options available, although
10003		 * the following parameters provide additional options in DataTables or
10004		 * require special consideration:
10005		 *
10006		 * * `data` - As with jQuery, `data` can be provided as an object, but it
10007		 *   can also be used as a function to manipulate the data DataTables sends
10008		 *   to the server. The function takes a single parameter, an object of
10009		 *   parameters with the values that DataTables has readied for sending. An
10010		 *   object may be returned which will be merged into the DataTables
10011		 *   defaults, or you can add the items to the object that was passed in and
10012		 *   not return anything from the function. This supersedes `fnServerParams`
10013		 *   from DataTables 1.9-.
10014		 *
10015		 * * `dataSrc` - By default DataTables will look for the property `data` (or
10016		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
10017		 *   from an Ajax source or for server-side processing - this parameter
10018		 *   allows that property to be changed. You can use Javascript dotted
10019		 *   object notation to get a data source for multiple levels of nesting, or
10020		 *   it my be used as a function. As a function it takes a single parameter,
10021		 *   the JSON returned from the server, which can be manipulated as
10022		 *   required, with the returned value being that used by DataTables as the
10023		 *   data source for the table.
10024		 *
10025		 * * `success` - Should not be overridden it is used internally in
10026		 *   DataTables. To manipulate / transform the data returned by the server
10027		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10028		 *
10029		 * `function`
10030		 * ----------
10031		 *
10032		 * As a function, making the Ajax call is left up to yourself allowing
10033		 * complete control of the Ajax request. Indeed, if desired, a method other
10034		 * than Ajax could be used to obtain the required data, such as Web storage
10035		 * or an AIR database.
10036		 *
10037		 * The function is given four parameters and no return is required. The
10038		 * parameters are:
10039		 *
10040		 * 1. _object_ - Data to send to the server
10041		 * 2. _function_ - Callback function that must be executed when the required
10042		 *    data has been obtained. That data should be passed into the callback
10043		 *    as the only parameter
10044		 * 3. _object_ - DataTables settings object for the table
10045		 */
10046		"ajax": null,
10047	
10048	
10049		/**
10050		 * This parameter allows you to readily specify the entries in the length drop
10051		 * down menu that DataTables shows when pagination is enabled. It can be
10052		 * either a 1D array of options which will be used for both the displayed
10053		 * option and the value, or a 2D array which will use the array in the first
10054		 * position as the value, and the array in the second position as the
10055		 * displayed options (useful for language strings such as 'All').
10056		 *
10057		 * Note that the `pageLength` property will be automatically set to the
10058		 * first value given in this array, unless `pageLength` is also provided.
10059		 */
10060		"aLengthMenu": [ 10, 25, 50, 100 ],
10061	
10062	
10063		/**
10064		 * The `columns` option in the initialisation parameter allows you to define
10065		 * details about the way individual columns behave. For a full list of
10066		 * column options that can be set, please see
10067		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10068		 * define your columns, you must have an entry in the array for every single
10069		 * column that you have in your table (these can be null if you don't which
10070		 * to specify any options).
10071		 */
10072		"aoColumns": null,
10073	
10074		/**
10075		 * Very similar to `columns`, `columnDefs` allows you to target a specific
10076		 * column, multiple columns, or all columns, using the `targets` property of
10077		 * each object in the array. This allows great flexibility when creating
10078		 * tables, as the `columnDefs` arrays can be of any length, targeting the
10079		 * columns you specifically want. `columnDefs` may use any of the column
10080		 * options available: {@link DataTable.defaults.column}, but it _must_
10081		 * have `targets` defined in each object in the array. Values in the `targets`
10082		 * array may be:
10083		 *   <ul>
10084		 *     <li>
10084a string - class name will be matched on the TH for the column</li>
10085		 *     <li>0 or a positive integer - column index counting from the left</li>
10086		 *     <li>a negative integer - column index counting from the right</li>
10087		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10088		 *   </ul>
10089		 */
10090		"aoColumnDefs": null,
10091	
10092	
10093		/**
10094		 * Basically the same as `search`, this parameter defines the individual column
10095		 * filtering state at initialisation time. The array must be of the same size
10096		 * as the number of columns, and each element be an object with the parameters
10097		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10098		 * accepted and the default will be used.
10099		 */
10100		"aoSearchCols": [],
10101	
10102	
10103		/**
10104		 * Enable or disable automatic column width calculation. This can be disabled
10105		 * as an optimisation (it takes some time to calculate the widths) if the
10106		 * tables widths are passed in using `columns`.
10107		 */
10108		"bAutoWidth": true,
10109	
10110	
10111		/**
10112		 * Deferred rendering can provide DataTables with a huge speed boost when you
10113		 * are using an Ajax or JS data source for the table. This option, when set to
10114		 * true, will cause DataTables to defer the creation of the table elements for
10115		 * each row until they are needed for a draw - saving a significant amount of
10116		 * time.
10117		 */
10118		"bDeferRender": true,
10119	
10120	
10121		/**
10122		 * Replace a DataTable which matches the given selector and replace it with
10123		 * one which has the properties of the new initialisation object passed. If no
10124		 * table matches the selector, then the new DataTable will be constructed as
10125		 * per normal.
10126		 */
10127		"bDestroy": false,
10128	
10129	
10130		/**
10131		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10132		 * that it allows the end user to input multiple words (space separated) and
10133		 * will match a row containing those words, even if not in the order that was
10134		 * specified (this allow matching across multiple columns). Note that if you
10135		 * wish to use filtering in DataTables this must remain 'true' - to remove the
10136		 * default filtering input box and retain filtering abilities, please use
10137		 * {@link DataTable.defaults.dom}.
10138		 */
10139		"bFilter": true,
10140	
10141		/**
10142		 * Used only for compatiblity with DT1
10143		 * @deprecated
10144		 */
10145		"bInfo": true,
10146	
10147		/**
10148		 * Used only for compatiblity with DT1
10149		 * @deprecated
10150		 */
10151		"bLengthChange": true,
10152	
10153		/**
10154		 * Enable or disable pagination.
10155		 */
10156		"bPaginate": true,
10157	
10158	
10159		/**
10160		 * Enable or disable the display of a 'processing' indicator when the table is
10161		 * being processed (e.g. a sort). This is particularly useful for tables with
10162		 * large amounts of data where it can take a noticeable amount of time to sort
10163		 * the entries.
10164		 */
10165		"bProcessing": false,
10166	
10167	
10168		/**
10169		 * Retrieve the DataTables object for the given selector. Note that if the
10170		 * table has already been initialised, this parameter will cause DataTables
10171		 * to simply return the object that has already been set up - it will not take
10172		 * account of any changes you might have made to the initialisation object
10173		 * passed to DataTables (setting this parameter to true is an acknowledgement
10174		 * that you understand this). `destroy` can be used to reinitialise a table if
10175		 * you need.
10176		 */
10177		"bRetrieve": false,
10178	
10179	
10180		/**
10181		 * When vertical (y) scrolling is enabled, DataTables will force the height of
10182		 * the table's viewport to the given height at all times (useful for layout).
10183		 * However, this can look odd when filtering data down to a small data set,
10184		 * and the footer is left "floating" further down. This parameter (when
10185		 * enabled) will cause DataTables to collapse the table's viewport down when
10186		 * the result set will fit within the given Y height.
10187		 */
10188		"bScrollCollapse": false,
10189	
10190	
10191		/**
10192		 * Configure DataTables to use server-side processing. Note that the
10193		 * `ajax` parameter must also be given in order to give DataTables a
10194		 * source to obtain the required data for each draw.
10195		 */
10196		"bServerSide": false,
10197	
10198	
10199		/**
10200		 * Enable or disable sorting of columns. Sorting of individual columns can be
10201		 * disabled by the `sortable` option for each column.
10202		 */
10203		"bSort": true,
10204	
10205	
10206		/**
10207		 * Enable or display DataTables' ability to sort multiple columns at the
10208		 * same time (activated by shift-click by the user).
10209		 */
10210		"bSortMulti": true,
10211	
10212	
10213		/**
10214		 * Allows control over whether DataTables should use the top (true) unique
10215		 * cell that is found for a single column, or the bottom (false - default).
10216		 * This is useful when using complex headers.
10217		 */
10218		"bSortCellsTop": null,
10219	
10220	
10221		/**
10222		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10223		 * `sorting\_3` to the columns which are currently being sorted on. This is
10224		 * presented as a feature switch as it can increase processing time (while
10225		 * classes are removed and added) so for large data sets you might want to
10226		 * turn this off.
10227		 */
10228		"bSortClasses": true,
10229	
10230	
10231		/**
10232		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10233		 * used to save table display information such as pagination information,
10234		 * display length, filtering and sorting. As such when the end user reloads
10235		 * the page the display display will match what thy had previously set up.
10236		 */
10237		"bStateSave": false,
10238	
10239	
10240		/**
10241		 * This function is called when a TR element is created (and all TD child
10242		 * elements have been inserted), or registered if using a DOM source, allowing
10243		 * manipulation of the TR element (adding classes etc).
10244		 */
10245		"fnCreatedRow": null,
10246	
10247	
10248		/**
10249		 * This function is called on every 'draw' event, and allows you to
10250		 * dynamically modify any aspect you want about the created DOM.
10251		 */
10252		"fnDrawCallback": null,
10253	
10254	
10255		/**
10256		 * Identical to fnHeaderCallback() but for the table footer this function
10257		 * allows you to modify the table footer on every 'draw' event.
10258		 */
10259		"fnFooterCallback": null,
10260	
10261	
10262		/**
10263		 * When rendering large numbers in the information element for the table
10264		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10265		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10266		 * rendered as "1,000,000") to help readability for the end user. This
10267		 * function will override the default method DataTables uses.
10268		 */
10269		"fnFormatNumber": function ( toFormat ) {
10270			return toFormat.toString().replace(
10271				/\B(?=(\d{3})+(?!\d))/g,
10272				this.oLanguage.sThousands
10273			);
10274		},
10275	
10276	
10277		/**
10278		 * This function is called on every 'draw' event, and allows you to
10279		 * dynamically modify the header row. This can be used to calculate and
10280		 * display useful information about the table.
10281		 */
10282		"fnHeaderCallback": null,
10283	
10284	
10285		/**
10286		 * The information element can be used to convey information about the current
10287		 * state of the table. Although the internationalisation options presented by
10288		 * DataTables are quite capable of dealing with most customisations, there may
10289		 * be times where you wish to customise the string further. This callback
10290		 * allows you to do exactly that.
10291		 */
10292		"fnInfoCallback": null,
10293	
10294	
10295		/**
10296		 * Called when the table has been initialised. Normally DataTables will
10297		 * initialise sequentially and there will be no need for this function,
10298		 * however, this does not hold true when using external language information
10299		 * since that is obtained using an async XHR call.
10300		 */
10301		"fnInitComplete": null,
10302	
10303	
10304		/**
10305		 * Called at the very start of each table draw and can be used to cancel the
10306		 * draw by returning false, any other return (including undefined) results in
10307		 * the full draw occurring).
10308		 */
10309		"fnPreDrawCallback": null,
10310	
10311	
10312		/**
10313		 * This function allows you to 'post process' each row after it have been
10314		 * generated for each table draw, but before it is rendered on screen. This
10315		 * function might be used for setting the row class name etc.
10316		 */
10317		"fnRowCallback": null,
10318	
10319	
10320		/**
10321		 * Load the table state. With this function you can define from where, and how, the
10322		 * state of a table is loaded. By default DataTables will load from `localStorage`
10323		 * but you might wish to use a server-side database or cookies.
10324		 */
10325		"fnStateLoadCallback": function ( settings ) {
10326			try {
10327				return JSON.parse(
vendor: 6,254 bytes, lines 10328-10523
10328					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10329						'DataTables_'+settings.sInstance+'_'+location.pathname
10330					)
10331				);
10332			} catch (e) {
10333				return {};
10334			}
10335		},
10336	
10337	
10338		/**
10339		 * Callback which allows modification of the saved state prior to loading that state.
10340		 * This callback is called when the table is loading state from the stored data, but
10341		 * prior to the settings object being modified by the saved state. Note that for
10342		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10343		 * a plug-in.
10344		 */
10345		"fnStateLoadParams": null,
10346	
10347	
10348		/**
10349		 * Callback that is called when the state has been loaded from the state saving method
10350		 * and the DataTables settings object has been modified as a result of the loaded state.
10351		 */
10352		"fnStateLoaded": null,
10353	
10354	
10355		/**
10356		 * Save the table state. This function allows you to define where and how the state
10357		 * information for the table is stored By default DataTables will use `localStorage`
10358		 * but you might wish to use a server-side database or cookies.
10359		 */
10360		"fnStateSaveCallback": function ( settings, data ) {
10361			try {
10362				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10363					'DataTables_'+settings.sInstance+'_'+location.pathname,
10364					JSON.stringify( data )
10365				);
10366			} catch (e) {
10367				// noop
10368			}
10369		},
10370	
10371	
10372		/**
10373		 * Callback which allows modification of the state to be saved. Called when the table
10374		 * has changed state a new state save is required. This method allows modification of
10375		 * the state saving object prior to actually doing the save, including addition or
10376		 * other state properties or modification. Note that for plug-in authors, you should
10377		 * use the `stateSaveParams` event to save parameters for a plug-in.
10378		 */
10379		"fnStateSaveParams": null,
10380	
10381	
10382		/**
10383		 * Duration for which the saved state information is considered valid. After this period
10384		 * has elapsed the state will be returned to the default.
10385		 * Value is given in seconds.
10386		 */
10387		"iStateDuration": 7200,
10388	
10389	
10390		/**
10391		 * Number of rows to display on a single page when using pagination. If
10392		 * feature enabled (`lengthChange`) then the end user will be able to override
10393		 * this to a custom setting using a pop-up menu.
10394		 */
10395		"iDisplayLength": 10,
10396	
10397	
10398		/**
10399		 * Define the starting point for data display when using DataTables with
10400		 * pagination. Note that this parameter is the number of records, rather than
10401		 * the page number, so if you have 10 records per page and want to start on
10402		 * the third page, it should be "20".
10403		 */
10404		"iDisplayStart": 0,
10405	
10406	
10407		/**
10408		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10409		 * and filtering) by adding a `tabindex` attribute to the required elements. This
10410		 * allows you to tab through the controls and press the enter key to activate them.
10411		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10412		 * You can overrule this using this parameter if you wish. Use a value of -1 to
10413		 * disable built-in keyboard navigation.
10414		 */
10415		"iTabIndex": 0,
10416	
10417	
10418		/**
10419		 * Classes that DataTables assigns to the various components and features
10420		 * that it adds to the HTML table. This allows classes to be configured
10421		 * during initialisation in addition to through the static
10422		 * {@link DataTable.ext.oStdClasses} object).
10423		 */
10424		"oClasses": {},
10425	
10426	
10427		/**
10428		 * All strings that DataTables uses in the user interface that it creates
10429		 * are defined in this object, allowing you to modified them individually or
10430		 * completely replace them all as required.
10431		 */
10432		"oLanguage": {
10433			/**
10434			 * Strings that are used for WAI-ARIA labels and controls only (these are not
10435			 * actually visible on the page, but will be read by screenreaders, and thus
10436			 * must be internationalised as well).
10437			 */
10438			"oAria": {
10439				/**
10440				 * ARIA label that is added to the table headers when the column may be sorted
10441				 */
10442				"orderable": ": Activate to sort",
10443	
10444				/**
10445				 * ARIA label that is added to the table headers when the column is currently being sorted
10446				 */
10447				"orderableReverse": ": Activate to invert sorting",
10448	
10449				/**
10450				 * ARIA label that is added to the table headers when the column is currently being 
10451				 * sorted and next step is to remove sorting
10452				 */
10453				"orderableRemove": ": Activate to remove sorting",
10454	
10455				paginate: {
10456					first: 'First',
10457					last: 'Last',
10458					next: 'Next',
10459					previous: 'Previous'
10460				}
10461			},
10462	
10463			/**
10464			 * Pagination string used by DataTables for the built-in pagination
10465			 * control types.
10466			 */
10467			"oPaginate": {
10468				/**
10469				 * Label and character for first page button («)
10470				 */
10471				"sFirst": "\u00AB",
10472	
10473				/**
10474				 * Last page button (»)
10475				 */
10476				"sLast": "\u00BB",
10477	
10478				/**
10479				 * Next page button (›)
10480				 */
10481				"sNext": "\u203A",
10482	
10483				/**
10484				 * Previous page button (‹)
10485				 */
10486				"sPrevious": "\u2039",
10487			},
10488	
10489			/**
10490			 * Plural object for the data type the table is showing
10491			 */
10492			entries: {
10493				_: "entries",
10494				1: "entry"
10495			},
10496	
10497			/**
10498			 * This string is shown in preference to `zeroRecords` when the table is
10499			 * empty of data (regardless of filtering). Note that this is an optional
10500			 * parameter - if it is not given, the value of `zeroRecords` will be used
10501			 * instead (either the default or given value).
10502			 */
10503			"sEmptyTable": "No data available in table",
10504	
10505	
10506			/**
10507			 * This string gives information to the end user about the information
10508			 * that is current on display on the page. The following tokens can be
10509			 * used in the string and will be dynamically replaced as the table
10510			 * display updates. This tokens can be placed anywhere in the string, or
10511			 * removed as needed by the language requires:
10512			 *
10513			 * * `\_START\_` - Display index of the first record on the current page
10514			 * * `\_END\_` - Display index of the last record on the current page
10515			 * * `\_TOTAL\_` - Number of records in the table after filtering
10516			 * * `\_MAX\_` - Number of records in the table without filtering
10517			 * * `\_PAGE\_` - Current page number
10518			 * * `\_PAGES\_` - Total number of pages of data in the table
10519			 */
10520			"sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
10521	
10522	
10523			/**
10524			 * Display information string for when the table is empty. Typically the
10525			 * format of this string should match `info`.
10526			 */
10527			"sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
10528	
10529	
10530			/**
10531			 * When a user filters the information in a table, this string is appended
10532			 * to the information (`info`) to give an idea of how strong the filtering
10533			 * is. The variable _MAX_ is dynamically updated.
10534			 */
10535			"sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
10536	
10537	
10538			/**
10539			 * If can be useful to append extra information to the info string at times,
10540			 * and this variable does exactly that. This information will be appended to
10541			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
10542			 * being used) at all times.
10543			 */
10544			"sInfoPostFix": "",
10545	
10546	
10547			/**
10548			 * This decimal place operator is a little different from the other
10549			 * language options since DataTables doesn't output floating point
10550			 * numbers, so it won't ever use this for display of a number. Rather,
10551			 * what this parameter does is modify the sort methods of the table so
10552			 * that numbers which are in a format which has a character other than
10553			 * a period (`.`) as a decimal place will be sorted numerically.
10554			 *
10555			 * Note that numbers with different decimal places cannot be shown in
10556			 * the same table and still be sortable, the table must be consistent.
10557			 * However, multiple different tables on the page can use different
10558			 * decimal place characters.
10559			 */
10560			"sDecimal": "",
10561	
10562	
10563			/**
10564			 * DataTables has a build in number formatter (`formatNumber`) which is
10565			 * used to format large numbers that are used in the table information.
10566			 * By default a comma is used, but this can be trivially changed to any
10567			 * character you wish with this parameter.
10568			 */
10569			"sThousands": ",",
10570	
10571	
10572			/**
10573			 * Detail the action that will be taken when the drop down menu for the
10574			 * pagination length option is changed. The '_MENU_' variable is replaced
10575			 * with a default select list of 10, 25, 50 and 100, and can be replaced
10576			 * with a custom select box if required.
10577			 */
10578			"sLengthMenu": "_MENU_ _ENTRIES_ per page",
10579	
10580	
10581			/**
10582			 * When using Ajax sourced data and during the first draw when DataTables is
10583			 * gathering the data, this message is shown in an empty row in the table to
10584			 * indicate to the end user the the data is being loaded. Note that this
10585			 * parameter is not used when loading data by server-side processing, just
10586			 * Ajax sourced data with client-side processing.
10587			 */
10588			"sLoadingRecords": "Loading...",
10589	
10590	
10591			/**
10592			 * Text which is displayed when the table is processing a user action
10593			 * (usually a sort command or similar).
10594			 */
10595			"sProcessing": "",
10596	
10597	
10598			/**
10599			 * Details the actions that will be taken when the user types into the
10600			 * filtering input text box. The variable "_INPUT_", if used in the string,
10601			 * is replaced with the HTML text box for the filtering input allowing
10602			 * control over where it appears in the string. If "_INPUT_" is not given
10603			 * then the input box is appended to the string automatically.
10604			 */
10605			"sSearch": "Search:",
10606	
10607	
10608			/**
10609			 * Assign a `placeholder` attribute to the search `input` element
10610			 *  @type string
10611			 *  @default 
10612			 *
10613			 *  @dtopt Language
10614			 *  @name DataTable.defaults.language.searchPlaceholder
10615			 */
10616			"sSearchPlaceholder": "",
10617	
10618	
10619			/**
10620			 * All of the language information can be stored in a file on the
10621			 * server-side, which DataTables will look up if this parameter is passed.
10622			 * It must store the URL of the language file, which is in a JSON format,
10623			 * and the object has the same properties as the oLanguage object in the
10624			 * initialiser object (i.e. the above parameters). Please refer to one of
10625			 * the example language files to see how this works in action.
10626			 */
10627			"sUrl": "",
10628	
10629	
10630			/**
10631			 * Text shown inside the table records when the is no information to be
10632			 * displayed after filtering. `emptyTable` is shown when there is simply no
10633			 * information in the table at all (regardless of filtering).
10634			 */
10635			"sZeroRecords": "No matching records found"
10636		},
10637	
10638	
10639		/**
10640		 * This parameter allows you to have define the global filtering state at
10641		 * initialisation time. As an object the `search` parameter must be
10642		 * defined, but all other parameters are optional. When `regex` is true,
10643		 * the search string will be treated as a regular expression, when false
10644		 * (default) it will be treated as a straight string. When `smart`
10645		 * DataTables will use it's smart filtering methods (to word match at
10646		 * any point in the data), when false this will not be done.
10647		 */
10648		"oSearch": $.extend( {}, DataTable.models.oSearch ),
10649	
10650	
10651		/**
10652		 * Table and control layout. This replaces the legacy `dom` option.
10653		 */
10654		layout: {
10655			topStart: 'pageLength',
10656			topEnd: 'search',
10657			bottomStart: 'info',
10658			bottomEnd: 'paging'
10659		},
10660	
10661	
10662		/**
10663		 * Legacy DOM layout option
10664		 */
10665		"sDom": null,
10666	
10667	
10668		/**
10669		 * Search delay option. This will throttle full table searches that use the
10670		 * DataTables provided search input element (it does not effect calls to
10671		 * `dt-api search()`, providing a delay before the search is made.
10672		 */
10673		"searchDelay": null,
10674	
10675	
10676		/**
10677		 * DataTables features six different built-in options for the buttons to
10678		 * display for pagination control:
10679		 *
10680		 * * `numbers` - Page number buttons only
10681		 * * `simple` - 'Previous' and 'Next' buttons only
10682		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
10683		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
10684		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
10685		 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
10686		 */
10687		"sPaginationType": "full_numbers",
10688	
10689	
10690		/**
10691		 * Enable horizontal scrolling. When a table is too wide to fit into a
10692		 * certain layout, or you have a large number of columns in the table, you
10693		 * can enable x-scrolling to show the table in a viewport, which can be
10694		 * scrolled. This property can be `true` which will allow the table to
10695		 * scroll horizontally when needed, or any CSS unit, or a number (in which
10696		 * case it will be treated as a pixel measurement). Setting as simply `true`
10697		 * is recommended.
10698		 */
10699		"sScrollX": "",
10700	
10701	
10702		/**
10703		 * This property can be used to force a DataTable to use more width than it
10704		 * might otherwise do when x-scrolling is enabled. For example if you have a
10705		 * table which requires to be well spaced, this parameter is useful for
10706		 * "over-sizing" the table, and thus forcing scrolling. This property can by
10707		 * any CSS unit, or a number (in which case it will be treated as a pixel
10708		 * measurement).
10709		 */
10710		"sScrollXInner": "",
10711	
10712	
10713		/**
10714		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
10715		 * to the given height, and enable scrolling for any data which overflows the
10716		 * current viewport. This can be used as an alternative to paging to display
10717		 * a lot of data in a small area (although paging and scrolling can both be
10718		 * enabled at the same time). This property can be any CSS unit, or a number
10719		 * (in which case it will be treated as a pixel measurement).
10720		 */
10721		"sScrollY": "",
10722	
10723	
10724		/**
10725		 * __Deprecated__ The functionality provided by this parameter has now been
10726		 * superseded by that provided through `ajax`, which should be used instead.
10727		 *
10728		 * Set the HTTP method that is used to make the Ajax call for server-side
10729		 * processing or Ajax sourced data.
10730		 */
10731		"sServerMethod": "GET",
10732	
10733	
10734		/**
10735		 * DataTables makes use of renderers when displaying HTML elements for
10736		 * a table. These renderers can be added or modified by plug-ins to
10737		 * generate suitable mark-up for a site. For example the Bootstrap
10738		 * integration plug-in for DataTables uses a paging button renderer to
10739		 * display pagination buttons in the mark-up required by Bootstrap.
10740		 *
10741		 * For further information about the renderers available see
10742		 * DataTable.ext.renderer
10743		 */
10744		"renderer": null,
10745	
10746	
10747		/**
10748		 * Set the data property name that DataTables should use to get a row's id
10749		 * to set as the `id` property in the node.
10750		 */
10751		"rowId": "DT_RowId",
10752	
10753	
10754		/**
10755		 * Caption value
10756		 */
10757		"caption": null
10758	};
10759	
10760	_fnHungarianMap( DataTable.defaults );
10761	
10762	
10763	
10764	/*
10765	 * Developer note - See note in model.defaults.js about the use of Hungarian
10766	 * notation and camel case.
10767	 */
10768	
10769	/**
10770	 * Column options that can be given to DataTables at initialisation time.
10771	 *  @namespace
10772	 */
10773	DataTable.defaults.column = {
10774		/**
10775		 * Define which column(s) an order will occur on for this column. This
10776		 * allows a column's ordering to take multiple columns into account when
10777		 * doing a sort or use the data from a different column. For example first
10778		 * name / last name columns make sense to do a multi-column sort over the
10779		 * two columns.
10780		 */
10781		"aDataSort": null,
10782		"iDataSort": -1,
10783	
10784		ariaTitle: '',
10785	
10786	
10787		/**
10788		 * You can control the default ordering direction, and even alter the
10789		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
10790		 * using this parameter.
10791		 */
10792		"asSorting": [ 'asc', 'desc', '' ],
10793	
10794	
10795		/**
10796		 * Enable or disable filtering on the data in this column.
10797		 */
10798		"bSearchable": true,
10799	
10800	
10801		/**
10802		 * Enable or disable ordering on this column.
10803		 */
10804		"bSortable": true,
10805	
10806	
10807		/**
10808		 * Enable or disable the display of this column.
10809		 */
10810		"bVisible": true,
10811	
10812	
10813		/**
10814		 * Developer definable function that is called whenever a cell is created (Ajax source,
10815		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
10816		 * allowing you to modify the DOM element (add background colour for example) when the
10817		 * element is available.
10818		 */
10819		"fnCreatedCell": null,
10820	
10821	
10822		/**
10823		 * This property can be used to read data from any data source property,
10824		 * including deeply nested objects / properties. `data` can be given in a
10825		 * number of different ways which effect its behaviour:
10826		 *
10827		 * * `integer` - treated as an array index for the data source. This is the
10828		 *   default that DataTables uses (incrementally increased for each column).
10829		 * * `string` - read an object property from the data source. There are
10830		 *   three 'special' options that can be used in the string to alter how
10831		 *   DataTables reads the data from the source object:
10832		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
10833		 *      Javascript to read from nested objects, so to can the options
10834		 *      specified in `data`. For example: `browser.version` or
10835		 *      `browser.name`. If your object parameter name contains a period, use
10836		 *      `\\` to escape it - i.e. `first\\.name`.
10837		 *    * `[]` - Array notation. DataTables can automatically combine data
10838		 *      from and array source, joining the data with the characters provided
10839		 *      between the two brackets. For example: `name[, ]` would provide a
10840		 *      comma-space separated list from the source array. If no characters
10841		 *      are provided between the brackets, the original array source is
10842		 *      returned.
10843		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
10844		 *      execute a function of the name given. For example: `browser()` for a
10845		 *      simple function on the data source, `browser.version()` for a
10846		 *      function in a nested property or even `browser().version` to get an
10847		 *      object property if the function called returns an object. Note that
10848		 *      function notation is recommended for use in `render` rather than
10849		 *      `data` as it is much simpler to use as a renderer.
10850		 * * `null` - use the original data source for the row rather than plucking
10851		 *   data directly from it. This action has effects on two other
10852		 *   initialisation options:
10853		 *    * `defaultContent` - When null is given as the `data` option and
10854		 *      `defaultContent` is specified for the column, the value defined by
10855		 *      `defaultContent` will be used for the cell.
10856		 *    * `render` - When null is used for the `data` option and the `render`
10857		 *      option is specified for the column, the whole data source for the
10858		 *      row is used for the renderer.
10859		 * * `function` - the function given will be executed whenever DataTables
10860		 *   needs to set or get the data for a cell in the column. The function
10861		 *   takes three parameters:
10862		 *    * Parameters:
10863		 *      * `{array|object}` The data source for the row
10864		 *      * `{string}` The type call data requested - this will be 'set' when
10865		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
10866		 *        when gathering data. Note that when `undefined` is given for the
10867		 *        type DataTables expects to get the raw data for the object back<
10868		 *      * `{*}` Data to set when the second parameter is 'set'.
10869		 *    * Return:
10870		 *      * The return value from the function is not required when '
10870set' is
10871		 *        the type of call, but otherwise the return is what will be used
10872		 *        for the data requested.
10873		 *
10874		 * Note that `data` is a getter and setter option. If you just require
10875		 * formatting of data for output, you will likely want to use `render` which
10876		 * is simply a getter and thus simpler to use.
10877		 *
10878		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
10879		 * name change reflects the flexibility of this property and is consistent
10880		 * with the naming of mRender. If 'mDataProp' is given, then it will still
10881		 * be used by DataTables, as it automatically maps the old name to the new
10882		 * if required.
10883		 */
10884		"mData": null,
10885	
10886	
10887		/**
10888		 * This property is the rendering partner to `data` and it is suggested that
10889		 * when you want to manipulate data for display (including filtering,
10890		 * sorting etc) without altering the underlying data for the table, use this
10891		 * property. `render` can be considered to be the the read only companion to
10892		 * `data` which is read / write (then as such more complex). Like `data`
10893		 * this option can be given in a number of different ways to effect its
10894		 * behaviour:
10895		 *
10896		 * * `integer` - treated as an array index for the data source. This is the
10897		 *   default that DataTables uses (incrementally increased for each column).
10898		 * * `string` - read an object property from the data source. There are
10899		 *   three 'special' options that can be used in the string to alter how
10900		 *   DataTables reads the data from the source object:
10901		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
10902		 *      Javascript to read from nested objects, so to can the options
10903		 *      specified in `data`. For example: `browser.version` or
10904		 *      `browser.name`. If your object parameter name contains a period, use
10905		 *      `\\` to escape it - i.e. `first\\.name`.
10906		 *    * `[]` - Array notation. DataTables can automatically combine data
10907		 *      from and array source, joining the data with the characters provided
10908		 *      between the two brackets. For example: `name[, ]` would provide a
10909		 *      comma-space separated list from the source array. If no characters
10910		 *      are provided between the brackets, the original array source is
10911		 *      returned.
10912		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
10913		 *      execute a function of the name given. For example: `browser()` for a
10914		 *      simple function on the data source, `browser.version()` for a
10915		 *      function in a nested property or even `browser().version` to get an
10916		 *      object property if the function called returns an object.
10917		 * * `object` - use different data for the different data types requested by
10918		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
10919		 *   of the object is the data type the property refers to and the value can
10920		 *   defined using an integer, string or function using the same rules as
10921		 *   `render` normally does. Note that an `_` option _must_ be specified.
10922		 *   This is the default value to use if you haven't specified a value for
10923		 *   the data type requested by DataTables.
10924		 * * `function` - the function given will be executed whenever DataTables
10925		 *   needs to set or get the data for a cell in the column. The function
10926		 *   takes three parameters:
10927		 *    * Parameters:
10928		 *      * {array|object} The data source for the row (based on `data`)
10929		 *      * {string} The type call data requested - this will be 'filter',
10930		 *        'display', 'type' or 'sort'.
10931		 *      * {array|object} The full data source for the row (not based on
10932		 *        `data`)
10933		 *    * Return:
10934		 *      * The return value from the function is what will be used for the
10935		 *        data requested.
10936		 */
10937		"mRender": null,
10938	
10939	
10940		/**
10941		 * Change the cell type created for the column - either TD cells or TH cells. This
10942		 * can be useful as TH cells have semantic meaning in the table body, allowing them
10943		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
10944		 */
10945		"sCellType": "td",
10946	
10947	
10948		/**
10949		 * Class to give to each cell in this column.
10950		 */
10951		"sClass": "",
10952	
10953		/**
10954		 * When DataTables calculates the column widths to assign to each column,
10955		 * it finds the longest string in each column and then constructs a
10956		 * temporary table and reads the widths from that. The problem with this
10957		 * is that "mmm" is much wider then "iiii", but the latter is a longer
10958		 * string - thus the calculation can go wrong (doing it properly and putting
10959		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
10960		 * a "work around" we provide this option. It will append its value to the
10961		 * text that is found to be the longest string for the column - i.e. padding.
10962		 * Generally you shouldn't need this!
10963		 */
10964		"sContentPadding": "",
10965	
10966	
10967		/**
10968		 * Allows a default value to be given for a column's data, and will be used
10969		 * whenever a null data source is encountered (this can be because `data`
10970		 * is set to null, or because the data source itself is null).
10971		 */
10972		"sDefaultContent": null,
10973	
10974	
10975		/**
10976		 * This parameter is only used in DataTables' server-side processing. It can
10977		 * be exceptionally useful to know what columns are being displayed on the
10978		 * client side, and to map these to database fields. When defined, the names
10979		 * also allow DataTables to reorder information from the server if it comes
10980		 * back in an unexpected order (i.e. if you switch your columns around on the
10981		 * client-side, your server-side code does not also need updating).
10982		 */
10983		"sName": "",
10984	
10985	
10986		/**
10987		 * Defines a data source type for the ordering which can be used to read
10988		 * real-time information from the table (updating the internally cached
10989		 * version) prior to ordering. This allows ordering to occur on user
10990		 * editable elements such as form inputs.
10991		 */
10992		"sSortDataType": "std",
10993	
10994	
10995		/**
10996		 * The title of this column.
10997		 */
10998		"sTitle": null,
10999	
11000	
11001		/**
11002		 * The type allows you to specify how the data for this column will be
11003		 * ordered. Four types (string, numeric, date and html (which will strip
11004		 * HTML tags before ordering)) are currently available. Note that only date
11005		 * formats understood by Javascript's Date() object will be accepted as type
11006		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
11007		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
11008		 * through plug-ins.
11009		 */
11010		"sType": null,
11011	
11012	
11013		/**
11014		 * Defining the width of the column, this parameter may take any CSS value
11015		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
11016		 * been given a specific width through this interface ensuring that the table
11017		 * remains readable.
11018		 */
11019		"sWidth": null
11020	};
11021	
11022	_fnHungarianMap( DataTable.defaults.column );
11023	
11024	
11025	
11026	/**
11027	 * DataTables settings object - this holds all the information needed for a
11028	 * given table, including configuration, data and current application of the
11029	 * table options. DataTables does not have a single instance for each DataTable
11030	 * with the settings attached to that instance, but rather instances of the
11031	 * DataTable "class" are created on-the-fly as needed (typically by a
11032	 * $().dataTable() call) and the settings object is then applied to that
11033	 * instance.
11034	 *
11035	 * Note that this object is related to {@link DataTable.defaults} but this
11036	 * one is the internal data store for DataTables's cache of columns. It should
11037	 * NOT be manipulated outside of DataTables. Any configuration should be done
11038	 * through the initialisation options.
11039	 */
11040	DataTable.models.oSettings = {
11041		/**
11042		 * Primary features of DataTables and their enablement state.
11043		 */
11044		"oFeatures": {
11045	
11046			/**
11047			 * Flag to say if DataTables should automatically try to calculate the
11048			 * optimum table and columns widths (true) or not (false).
11049			 * Note that this parameter will be set by the initialisation routine. To
11050			 * set a default use {@link DataTable.defaults}.
11051			 */
11052			"bAutoWidth": null,
11053	
11054			/**
11055			 * Delay the creation of TR and TD elements until they are actually
11056			 * needed by a driven page draw. This can give a significant speed
11057			 * increase for Ajax source and Javascript source data, but makes no
11058			 * difference at all for DOM and server-side processing tables.
11059			 * Note that this parameter will be set by the initialisation routine. To
11060			 * set a default use {@link DataTable.defaults}.
11061			 */
11062			"bDeferRender": null,
11063	
11064			/**
11065			 * Enable filtering on the table or not. Note that if this is disabled
11066			 * then there is no filtering at all on the table, including fnFilter.
11067			 * To just remove the filtering input use sDom and remove the 'f' option.
11068			 * Note that this parameter will be set by the initialisation routine. To
11069			 * set a default use {@link DataTable.defaults}.
11070			 */
11071			"bFilter": null,
11072	
11073			/**
11074			 * Used only for compatiblity with DT1
11075			 * @deprecated
11076			 */
11077			"bInfo": true,
11078	
11079			/**
11080			 * Used only for compatiblity with DT1
11081			 * @deprecated
11082			 */
11083			"bLengthChange": true,
11084	
11085			/**
11086			 * Pagination enabled or not. Note that if this is disabled then length
11087			 * changing must also be disabled.
11088			 * Note that this parameter will be set by the initialisation routine. To
11089			 * set a default use {@link DataTable.defaults}.
11090			 */
11091			"bPaginate": null,
11092	
11093			/**
11094			 * Processing indicator enable flag whenever DataTables is enacting a
11095			 * user request - typically an Ajax request for server-side processing.
11096			 * Note that this parameter will be set by the initialisation routine. To
11097			 * set a default use {@link DataTable.defaults}.
11098			 */
11099			"bProcessing": null,
11100	
11101			/**
11102			 * Server-side processing enabled flag - when enabled DataTables will
11103			 * get all data from the server for every draw - there is no filtering,
11104			 * sorting or paging done on the client-side.
11105			 * Note that this parameter will be set by the initialisation routine. To
11106			 * set a default use {@link DataTable.defaults}.
11107			 */
11108			"bServerSide": null,
11109	
11110			/**
11111			 * Sorting enablement flag.
11112			 * Note that this parameter will be set by the initialisation routine. To
11113			 * set a default use {@link DataTable.defaults}.
11114			 */
11115			"bSort": null,
11116	
11117			/**
11118			 * Multi-column sorting
11119			 * Note that this parameter will be set by the initialisation routine. To
11120			 * set a default use {@link DataTable.defaults}.
11121			 */
11122			"bSortMulti": null,
11123	
11124			/**
11125			 * Apply a class to the columns which are being sorted to provide a
11126			 * visual highlight or not. This can slow things down when enabled since
11127			 * there is a lot of DOM interaction.
11128			 * Note that this parameter will be set by the initialisation routine. To
11129			 * set a default use {@link DataTable.defaults}.
11130			 */
11131			"bSortClasses": null,
11132	
11133			/**
11134			 * State saving enablement flag.
11135			 * Note that this parameter will be set by the initialisation routine. To
11136			 * set a default use {@link DataTable.defaults}.
11137			 */
11138			"bStateSave": null
11139		},
11140	
11141	
11142		/**
11143		 * Scrolling settings for a table.
11144		 */
11145		"oScroll": {
11146			/**
11147			 * When the table is shorter in height than sScrollY, collapse the
11148			 * table container down to the height of the table (when true).
11149			 * Note that this parameter will be set by the initialisation routine. To
11150			 * set a default use {@link DataTable.defaults}.
11151			 */
11152			"bCollapse": null,
11153	
11154			/**
11155			 * Width of the scrollbar for the web-browser's platform. Calculated
11156			 * during table initialisation.
11157			 */
11158			"iBarWidth": 0,
11159	
11160			/**
11161			 * Viewport width for horizontal scrolling. Horizontal scrolling is
11162			 * disabled if an empty string.
11163			 * Note that this parameter will be set by the initialisation routine. To
11164			 * set a default use {@link DataTable.defaults}.
11165			 */
11166			"sX": null,
11167	
11168			/**
11169			 * Width to expand the table to when using x-scrolling. Typically you
11170			 * should not need to use this.
11171			 * Note that this parameter will be set by the initialisation routine. To
11172			 * set a default use {@link DataTable.defaults}.
11173			 *  @deprecated
11174			 */
11175			"sXInner": null,
11176	
11177			/**
11178			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
11179			 * if an empty string.
11180			 * Note that this parameter will be set by the initialisation routine. To
11181			 * set a default use {@link DataTable.defaults}.
11182			 */
11183			"sY": null
11184		},
11185	
11186		/**
11187		 * Language information for the table.
11188		 */
11189		"oLanguage": {
11190			/**
11191			 * Information callback function. See
11192			 * {@link DataTable.defaults.fnInfoCallback}
11193			 */
11194			"fnInfoCallback": null
11195		},
11196	
11197		/**
11198		 * Browser support parameters
11199		 */
11200		"oBrowser": {
11201			/**
11202			 * Determine if the vertical scrollbar is on the right or left of the
11203			 * scrolling container - needed for rtl language layout, although not
11204			 * all browsers move the scrollbar (Safari).
11205			 */
11206			"bScrollbarLeft": false,
11207	
11208			/**
11209			 * Browser scrollbar width
11210			 */
11211			"barWidth": 0
11212		},
11213	
11214	
11215		"ajax": null,
11216	
11217	
11218		/**
11219		 * Array referencing the nodes which are used for the features. The
11220		 * parameters of this object match what is allowed by sDom - i.e.
11221		 *   <ul>
11222		 *     <li>'l' - Length changing</li>
11223		 *     <li>'f' - Filtering input</li>
11224		 *     <li>'t' - The table!</li>
11225		 *     <li>'i' - Information</li>
11226		 *     <li>'p' - Pagination</li>
11227		 *     <li>'r' - pRocessing</li>
11228		 *   </ul>
11229		 */
11230		"aanFeatures": [],
11231	
11232		/**
11233		 * Store data information - see {@link DataTable.models.oRow} for detailed
11234		 * information.
11235		 */
11236		"aoData": [],
11237	
11238		/**
11239		 * Array of indexes which are in the current display (after filtering etc)
11240		 */
11241		"aiDisplay": [],
11242	
11243		/**
11244		 * Array of indexes for display - no filtering
11245		 */
11246		"aiDisplayMaster": [],
11247	
11248		/**
11249		 * Map of row ids to data indexes
11250		 */
11251		"aIds": {},
11252	
11253		/**
11254		 * Store information about each column that is in use
11255		 */
11256		"aoColumns": [],
11257	
11258		/**
11259		 * Store information about the table's header
11260		 */
11261		"aoHeader": [],
11262	
11263		/**
11264		 * Store information about the table's footer
11265		 */
11266		"aoFooter": [],
11267	
11268		/**
11269		 * Store the applied global search information in case we want to force a
11270		 * research or compare the old search to a new one.
11271		 * Note that this parameter will be set by the initialisation routine. To
11272		 * set a default use {@link DataTable.defaults}.
11273		 */
11274		"oPreviousSearch": {},
11275	
11276		/**
11277		 * Store for named searches
11278		 */
11279		searchFixed: {},
11280	
11281		/**
11282		 * Store the applied search for each column - see
11283		 * {@link DataTable.models.oSearch} for the format that is used for the
11284		 * filtering information for each column.
11285		 */
11286		"aoPreSearchCols": [],
11287	
11288		/**
11289		 * Sorting that is applied to the table. Note that the inner arrays are
11290		 * used in the following manner:
11291		 * <ul>
11292		 *   <li>Index 0 - column number</li>
11293		 *   <li>Index 1 - current sorting direction</li>
11294		 * </ul>
11295		 * Note that this parameter will be set by the initialisation routine. To
11296		 * set a default use {@link DataTable.defaults}.
11297		 */
11298		"aaSorting": null,
11299	
11300		/**
11301		 * Sorting that is always applied to the table (i.e. prefixed in front of
11302		 * aaSorting).
11303		 * Note that this parameter will be set by the initialisation routine. To
11304		 * set a default use {@link DataTable.defaults}.
11305		 */
11306		"aaSortingFixed": [],
11307	
11308		/**
11309		 * If restoring a table - we should restore its width
11310		 */
11311		"sDestroyWidth": 0,
11312	
11313		/**
11314		 * Callback functions array for every time a row is inserted (i.e. on a draw).
11315		 */
11316		"aoRowCallback": [],
11317	
11318		/**
11319		 * Callback functions for the header on each draw.
11320		 */
11321		"aoHeaderCallback": [],
11322	
11323		/**
11324		 * Callback function for the footer on each draw.
11325		 */
11326		"aoFooterCallback": [],
11327	
11328		/**
11329		 * Array of callback functions for draw callback functions
11330		 */
11331		"aoDrawCallback": [],
11332	
11333		/**
11334		 * Array of callback functions for row created function
11335		 */
11336		"aoRowCreatedCallback": [],
11337	
11338		/**
11339		 * Callback functions for just before the table is redrawn. A return of
11340		 * false will be used to cancel the draw.
11341		 */
11342		"aoPreDrawCallback": [],
11343	
11344		/**
11345		 * Callback functions for when the table has been initialised.
11346		 */
11347		"aoInitComplete": [],
11348	
11349	
11350		/**
11351		 * Callbacks for modifying the settings to be stored for state saving, prior to
11352		 * saving state.
11353		 */
11354		"aoStateSaveParams": [],
11355	
11356		/**
11357		 * Callbacks for modifying the settings that have been stored for state saving
11358		 * prior to using the stored values to restore the state.
11359		 */
11360		"aoStateLoadParams": [],
11361	
11362		/**
11363		 * Callbacks for operating on the settings object once the saved state has been
11364		 * loaded
11365		 */
11366		"aoStateLoaded": [],
11367	
11368		/**
11369		 * Cache the table ID for quick access
11370		 */
11371		"sTableId": "",
11372	
11373		/**
11374		 * The TABLE node for the main table
11375		 */
11376		"nTable": null,
11377	
11378		/**
11379		 * Permanent ref to the thead element
11380		 */
11381		"nTHead": null,
11382	
11383		/**
11384		 * Permanent ref to the tfoot element - if it exists
11385		 */
11386		"nTFoot": null,
11387	
11388		/**
11389		 * Permanent ref to the tbody element
11390		 */
11391		"nTBody": null,
11392	
11393		/**
11394		 * Cache the wrapper node (contains all DataTables controlled elements)
11395		 */
11396		"nTableWrapper": null,
11397	
11398		/**
11399		 * Indicate if all required information has been read in
11400		 */
11401		"bInitialised": false,
11402	
11403		/**
11404		 * Information about open rows. Each object in the array has the parameters
11405		 * 'nTr' and 'nParent'
11406		 */
11407		"aoOpenRows": [],
11408	
11409		/**
11410		 * Dictate the positioning of DataTables' control elements - see
11411		 * {@link DataTable.model.oInit.sDom}.
11412		 * Note that this parameter will be set by the initialisation routine. To
11413		 * set a default use {@link DataTable.defaults}.
11414		 */
11415		"sDom": null,
11416	
11417		/**
11418		 * Search delay (in mS)
11419		 */
11420		"searchDelay": null,
11421	
11422		/**
11423		 * Which type of pagination should be used.
11424		 * Note that this parameter will be set by the initialisation routine. To
11425		 * set a default use {@link DataTable.defaults}.
11426		 */
11427		"sPaginationType": "two_button",
11428	
11429		/**
11430		 * Number of paging controls on the page. Only used for backwards compatibility
11431		 */
11432		pagingControls: 0,
11433	
11434		/**
11435		 * The state duration (for `stateSave`) in seconds.
11436		 * Note that this parameter will be set by the initialisation routine. To
11437		 * set a default use {@link DataTable.defaults}.
11438		 */
11439		"iStateDuration": 0,
11440	
11441		/**
11442		 * Array of callback functions for state saving. Each array element is an
11443		 * object with the following parameters:
11444		 *   <ul>
11445		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11446		 *       and the JSON string to save that has been thus far created. Returns
11447		 *       a JSON string to be inserted into a json object
11448		 *       (i.e. '"param": [ 0, 1, 2]')</li>
11449		 *     <li>string:sName - name of callback</li>
11450		 *   </ul>
11451		 */
11452		"aoStateSave": [],
11453	
11454		/**
11455		 * Array of callback functions for state loading. Each array element is an
11456		 * object with the following parameters:
11457		 *   <ul>
11458		 *     <li>function:fn - function to call. Takes two parameters, oSettings
11459		 *       and the object stored. May return false to cancel state loading</li>
11460		 *     <li>string:sName - name of callback</li>
11461		 *   </ul>
11462		 */
11463		"aoStateLoad": [],
11464	
11465		/**
11466		 * State that was saved. Useful for back reference
11467		 */
11468		"oSavedState": null,
11469	
11470		/**
11471		 * State that was loaded. Useful for back reference
11472		 */
11473		"oLoadedState": null,
11474	
11475		/**
11476		 * Note if draw should be blocked while getting data
11477		 */
11478		"bAjaxDataGet": true,
11479	
11480		/**
11481		 * The last jQuery XHR object that was used for server-side data gathering.
11482		 * This can be used for working with the XHR information in one of the
11483		 * callbacks
11484		 */
11485		"jqXHR": null,
11486	
11487		/**
11488		 * JSON returned from the server in the last Ajax request
11489		 */
11490		"json": undefined,
11491	
11492		/**
11493		 * Data submitted as part of the last Ajax request
11494		 */
11495		"oAjaxData": undefined,
11496	
11497		/**
11498		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
11499		 * required).
11500		 * Note that this parameter will be set by the initialisation routine. To
11501		 * set a default use {@link DataTable.defaults}.
11502		 */
11503		"sServerMethod": null,
11504	
11505		/**
11506		 * Format numbers for display.
11507		 * Note that this parameter will be set by the initialisation routine. To
11508		 * set a default use {@link DataTable.defaults}.
11509		 */
11510		"fnFormatNumber": null,
11511	
11512		/**
11513		 * List of options that can be used for the user selectable length menu.
11514		 * Note that this parameter will be set by the initialisation routine. To
11515		 * set a default use {@link DataTable.defaults}.
11516		 */
11517		"aLengthMenu": null,
11518	
11519		/**
11520		 * Counter for the draws that the table does. Also used as a tracker for
11521		 * server-side processing
11522		 */
11523		"iDraw": 0,
11524	
11525		/**
11526		 * Indicate if a redraw is being done - useful for Ajax
11527		 */
11528		"bDrawing": false,
11529	
11530		/**
11531		 * Draw index (iDraw) of the last error when parsing the returned data
11532		 */
11533		"iDrawError": -1,
11534	
11535		/**
11536		 * Paging display length
11537		 */
11538		"_iDisplayLength": 10,
11539	
11540		/**
11541		 * Paging start point - aiDisplay index
11542		 */
11543		"_iDisplayStart": 0,
11544	
11545		/**
11546		 * Server-side processing - number of records in the result set
11547		 * (i.e. before filtering), Use fnRecordsTotal rather than
11548		 * this property to get the value of the number of records, regardless of
11549		 * the server-side processing setting.
11550		 */
11551		"_iRecordsTotal": 0,
11552	
11553		/**
11554		 * Server-side processing - number of records in the current display set
11555		 * (i.e. after filtering). Use fnRecordsDisplay rather than
11556		 * this property to get the value of the number of records, regardless of
11557		 * the server-side processing setting.
11558		 */
11559		"_iRecordsDisplay": 0,
11560	
11561		/**
11562		 * The classes to use for the table
11563		 */
11564		"oClasses": {},
11565	
11566		/**
11567		 * Flag attached to the settings object so you can check in the draw
11568		 * callback if filtering has been done in the draw. Deprecated in favour of
11569		 * events.
11570		 *  @deprecated
11571		 */
11572		"bFiltered": false,
11573	
11574		/**
11575		 * Flag attached to the settings object so you can check in the draw
11576		 * callback if sorting has been done in the draw. Deprecated in favour of
11577		 * events.
11578		 *  @deprecated
11579		 */
11580		"bSorted": false,
11581	
11582		/**
11583		 * Indicate that if multiple rows are in the header and there is more than
11584		 * one unique cell per column, if the top one (true) or bottom one (false)
11585		 * should be used for sorting / title by DataTables.
11586		 * Note that this parameter will be set by the initialisation routine. To
11587		 * set a default use {@link DataTable.defaults}.
11588		 */
11589		"bSortCellsTop": null,
11590	
11591		/**
11592		 * Initialisation object that is used for the table
11593		 */
11594		"oInit": null,
11595	
11596		/**
11597		 * Destroy callback functions - for plug-ins to attach themselves to the
11598		 * destroy so they can clean up markup and events.
11599		 */
11600		"aoDestroyCallback": [],
11601	
11602	
11603		/**
11604		 * Get the number of records in the current record set, before filtering
11605		 */
11606		"fnRecordsTotal": function ()
11607		{
11608			return _fnDataSource( this ) == 'ssp' ?
11609				this._iRecordsTotal * 1 :
11610				this.aiDisplayMaster.length;
11611		},
11612	
11613		/**
11614		 * Get the number of records in the current record set, after filtering
11615		 */
11616		"fnRecordsDisplay": function ()
11617		{
11618			return _fnDataSource( this ) == 'ssp' ?
11619				this._iRecordsDisplay * 1 :
11620				this.aiDisplay.length;
11621		},
11622	
11623		/**
11624		 * Get the display end point - aiDisplay index
11625		 */
11626		"fnDisplayEnd": function ()
11627		{
11628			var
11629				len      = this._iDisplayLength,
11630				start    = this._iDisplayStart,
11631				calc     = start + len,
11632				records  = this.aiDisplay.length,
11633				features = this.oFeatures,
11634				paginate = features.bPaginate;
11635	
11636			if ( features.bServerSide ) {
11637				return paginate === false || len === -1 ?
11638					start + records :
11639					Math.min( start+len, this._iRecordsDisplay );
11640			}
11641			else {
11642				return ! paginate || calc>records || len===-1 ?
11643					records :
11644					calc;
11645			}
11646		},
11647	
11648		/**
11649		 * The DataTables object for this table
11650		 */
11651		"oInstance": null,
11652	
11653		/**
11654		 * Unique identifier for each instance of the DataTables object. If there
11655		 * is an ID on the table node, then it takes that value, otherwise an
11656		 * incrementing internal counter is used.
11657		 */
11658		"sInstance": null,
11659	
11660		/**
11661		 * tabindex attribute value that is added to DataTables control elements, allowing
11662		 * keyboard navigation of the table and its controls.
11663		 */
11664		"iTabIndex": 0,
11665	
11666		/**
11667		 * DIV container for the footer scrolling table if scrolling
11668		 */
11669		"nScrollHead": null,
11670	
11671		/**
11672		 * DIV container for the footer scrolling table if scrolling
11673		 */
11674		"nScrollFoot": null,
11675	
11676		/**
11677		 * Last applied sort
11678		 */
11679		"aLastSort": [],
11680	
11681		/**
11682		 * Stored plug-in instances
11683		 */
11684		"oPlugins": {},
11685	
11686		/**
11687		 * Function used to get a row's id from the row's data
11688		 */
11689		"rowIdFn": null,
11690	
11691		/**
11692		 * Data location where to store a row's id
11693		 */
11694		"rowId": null,
11695	
11696		caption: '',
11697	
11698		captionNode: null,
11699	
11700		colgroup: null
11701	};
11702	
11703	/**
11704	 * Extension object for DataTables that is used to provide all extension
11705	 * options.
11706	 *
11707	 * Note that the `DataTable.ext` object is available through
11708	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
11709	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
11710	 *  @namespace
11711	 *  @extends DataTable.models.ext
11712	 */
11713	
11714	
11715	var extPagination = DataTable.ext.pager;
11716	
11717	// Paging buttons configuration
11718	$.extend( extPagination, {
11719		simple: function () {
11720			return [ 'previous', 'next' ];
11721		},
11722	
11723		full: function () {
11724			return [  'first', 'previous', 'next', 'last' ];
11725		},
11726	
11727		numbers: function () {
11728			return [ 'numbers' ];
11729		},
11730	
11731		simple_numbers: function () {
11732			return [ 'previous', 'numbers', 'next' ];
11733		},
11734	
11735		full_numbers: function () {
11736			return [ 'first', 'previous', 'numbers', 'next', 'last' ];
11737		},
11738		
11739		first_last: function () {
11740			return ['first', 'last'];
11741		},
11742		
11743		first_last_numbers: function () {
11744			return ['first', 'numbers', 'last'];
11745		},
11746	
11747		// For testing and plug-ins to use
11748		_numbers: _pagingNumbers,
11749	
11750		// Number of number buttons - legacy, use `numbers` option for paging feature
11751		numbers_length: 7
11752	} );
11753	
11754	
11755	$.extend( true, DataTable.ext.renderer, {
11756		pagingButton: {
11757			_: function (settings, buttonType, content, active, disabled) {
11758				var classes = settings.oClasses.paging;
11759				var btnClasses = [classes.button];
11760				var btn;
11761	
11762				if (active) {
11763					btnClasses.push(classes.active);
11764				}
11765	
11766				if (disabled) {
11767					btnClasses.push(classes.disabled)
11768				}
11769	
11770				if (buttonType === 'ellipsis') {
11771					btn = $('<span class="ellipsis"></span>').html(content)[0];
11772				}
11773				else {
11774					btn = $('<button>', {
11775						class: btnClasses.join(' '),
11776						role: 'link',
11777						type: 'button'
11778					}).html(content);
11779				}
11780	
11781				return {
11782					display: btn,
11783					clicker: btn
11784				}
11785			}
11786		},
11787	
11788		pagingContainer: {
11789			_: function (settings, buttons) {
11790				// No wrapping element - just append directly to the host
11791				return buttons;
11792			}
11793		}
11794	} );
11795	
11796	// Common function to remove new lines, strip HTML and diacritic control
11797	var _filterString = function (stripHtml, normalize) {
11798		return function (str) {
11799			if (_empty(str) || typeof str !== 'string') {
11800				return str;
11801			}
11802	
11803			str = str.replace( _re_new_lines, " " );
11804	
11805			if (stripHtml) {
11806				str = _stripHtml(str);
11807			}
11808	
11809			if (normalize) {
11810				str = _normalize(str, false);
11811			}
11812	
11813			return str;
11814		};
11815	}
11816	
11817	/*
11818	 * Public helper functions. These aren't used internally by DataTables, or
11819	 * called by any of the options passed into DataTables, but they can be used
11820	 * externally by developers working with DataTables. They are helper functions
11821	 * to make working with DataTables a little bit easier.
11822	 */
11823	
11824	function __mldFnName(name) {
11825		return name.replace(/[\W]/g, '_')
11826	}
11827	
11828	// Common logic for moment, luxon or a date action
11829	function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) {
11830		if (window.moment) {
11831			return dt[momentFn]( arg1 );
11832		}
11833		else if (window.luxon) {
11834			return dt[luxonFn]( arg1 );
11835		}
11836		
11837		return dateFn ? dt[dateFn]( arg1 ) : dt;
11838	}
11839	
11840	
11841	var __mlWarning = false;
vendor: 4,458 bytes, lines 11842-12013
11842	function __mldObj (d, format, locale) {
11843		var dt;
11844	
11845		if (window.moment) {
11846			dt = window.moment.utc( d, format, locale, true );
11847	
11848			if (! dt.isValid()) {
11849				return null;
11850			}
11851		}
11852		else if (window.luxon) {
11853			dt = format && typeof d === 'string'
11854				? window.luxon.DateTime.fromFormat( d, format )
11855				: window.luxon.DateTime.fromISO( d );
11856	
11857			if (! dt.isValid) {
11858				return null;
11859			}
11860	
11861			dt.setLocale(locale);
11862		}
11863		else if (! format) {
11864			// No format given, must be ISO
11865			dt = new Date(d);
11866		}
11867		else {
11868			if (! __mlWarning) {
11869				alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
11870			}
11871	
11872			__mlWarning = true;
11873		}
11874	
11875		return dt;
11876	}
11877	
11878	// Wrapper for date, datetime and time which all operate the same way with the exception of
11879	// the output string for auto locale support
11880	function __mlHelper (localeString) {
11881		return function ( from, to, locale, def ) {
11882			// Luxon and Moment support
11883			// Argument shifting
11884			if ( arguments.length === 0 ) {
11885				locale = 'en';
11886				to = null; // means toLocaleString
11887				from = null; // means iso8601
11888			}
11889			else if ( arguments.length === 1 ) {
11890				locale = 'en';
11891				to = from;
11892				from = null;
11893			}
11894			else if ( arguments.length === 2 ) {
11895				locale = to;
11896				to = from;
11897				from = null;
11898			}
11899	
11900			var typeName = 'datetime' + (to ? '-' + __mldFnName(to) : '');
11901	
11902			// Add type detection and sorting specific to this date format - we need to be able to identify
11903			// date type columns as such, rather than as numbers in extensions. Hence the need for this.
11904			if (! DataTable.ext.type.order[typeName]) {
11905				DataTable.type(typeName, {
11906					detect: function (d) {
11907						// The renderer will give the value to type detect as the type!
11908						return d === typeName ? typeName : false;
11909					},
11910					order: {
11911						pre: function (d) {
11912							// The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
11913							// `valueOf` which gives milliseconds epoch
11914							return d.valueOf();
11915						}
11916					},
11917					className: 'dt-right'
11918				});
11919			}
11920		
11921			return function ( d, type ) {
11922				// Allow for a default value
11923				if (d === null || d === undefined) {
11924					if (def === '--now') {
11925						// We treat everything as UTC further down, so no changes are
11926						// made, as such need to get the local date / time as if it were
11927						// UTC
11928						var local = new Date();
11929						d = new Date( Date.UTC(
11930							local.getFullYear(), local.getMonth(), local.getDate(),
11931							local.getHours(), local.getMinutes(), local.getSeconds()
11932						) );
11933					}
11934					else {
11935						d = '';
11936					}
11937				}
11938	
11939				if (type === 'type') {
11940					// Typing uses the type name for fast matching
11941					return typeName;
11942				}
11943	
11944				if (d === '') {
11945					return type !== 'sort'
11946						? ''
11947						: __mldObj('0000-01-01 00:00:00', null, locale);
11948				}
11949	
11950				// Shortcut. If `from` and `to` are the same, we are using the renderer to
11951				// format for ordering, not display - its already in the display format.
11952				if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) {
11953					return d;
11954				}
11955	
11956				var dt = __mldObj(d, from, locale);
11957	
11958				if (dt === null) {
11959					return d;
11960				}
11961	
11962				if (type === 'sort') {
11963					return dt;
11964				}
11965				
11966				var formatted = to === null
11967					? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
11968					: __mld(dt, 'format', 'toFormat', 'toISOString', to);
11969	
11970				// XSS protection
11971				return type === 'display' ?
11972					_escapeHtml( formatted ) :
11973					formatted;
11974			};
11975		}
11976	}
11977	
11978	// Based on locale, determine standard number formatting
11979	// Fallback for legacy browsers is US English
11980	var __thousands = ',';
11981	var __decimal = '.';
11982	
11983	if (window.Intl !== undefined) {
11984		try {
11985			var num = new Intl.NumberFormat().formatToParts(100000.1);
11986		
11987			for (var i=0 ; i<num.length ; i++) {
11988				if (num[i].type === 'group') {
11989					__thousands = num[i].value;
11990				}
11991				else if (num[i].type === 'decimal') {
11992					__decimal = num[i].value;
11993				}
11994			}
11995		}
11996		catch (e) {
11997			// noop
11998		}
11999	}
12000	
12001	// Formatted date time detection - use by declaring the formats you are going to use
12002	DataTable.datetime = function ( format, locale ) {
12003		var typeName = 'datetime-detect-' + __mldFnName(format);
12004	
12005		if (! locale) {
12006			locale = 'en';
12007		}
12008	
12009		if (! DataTable.ext.type.order[typeName]) {
12010			DataTable.type(typeName, {
12011				detect: function (d) {
12012					var dt = __mldObj(d, format, locale);
12013					return d === '' || dt ? typeName : false;
12014				},
12015				order: {
12016					pre: function (d) {
12017						return __mldObj(d, format, locale) || 0;
12018					}
12019				},
12020				className: 'dt-right'
12021			});
12022		}
12023	}
12024	
12025	/**
12026	 * Helpers for `columns.render`.
12027	 *
12028	 * The options defined here can be used with the `columns.render` initialisation
12029	 * option to provide a display renderer. The following functions are defined:
12030	 *
12031	 * * `moment` - Uses the MomentJS library to convert from a given format into another.
12032	 * This renderer has three overloads:
12033	 *   * 1 parameter:
12034	 *     * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
12035	 *   * 2 parameters:
12036	 *     * `string` - Format to convert from
12037	 *     * `string` - Format to convert to. Assumes `en` locale
12038	 *   * 3 parameters:
12039	 *     * `string` - Format to convert from
12040	 *     * `string` - Format to convert to
12041	 *     * `string` - Locale
12042	 * * `number` - Will format numeric data (defined by `columns.data`) for
12043	 *   display, retaining the original unformatted data for sorting and filtering.
12044	 *   It takes 5 parameters:
12045	 *   * `string` - Thousands grouping separator
12046	 *   * `string` - Decimal point indicator
12047	 *   * `integer` - Number of decimal points to show
12048	 *   * `string` (optional) - Prefix.
12049	 *   * `string` (optional) - Postfix (/suffix).
12050	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
12051	 *   parameters.
12052	 *
12053	 * @example
12054	 *   // Column definition using the number renderer
12055	 *   {
12056	 *     data: "salary",
12057	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
12058	 *   }
12059	 *
12060	 * @namespace
12061	 */
12062	DataTable.render = {
12063		date: __mlHelper('toLocaleDateString'),
12064		datetime: __mlHelper('toLocaleString'),
12065		time: __mlHelper('toLocaleTimeString'),
12066		number: function ( thousands, decimal, precision, prefix, postfix ) {
12067			// Auto locale detection
12068			if (thousands === null || thousands === undefined) {
12069				thousands = __thousands;
12070			}
12071	
12072			if (decimal === null || decimal === undefined) {
12073				decimal = __decimal;
12074			}
12075	
12076			return {
12077				display: function ( d ) {
12078					if ( typeof d !== 'number' && typeof d !== 'string' ) {
12079						return d;
12080					}
12081	
12082					if (d === '' || d === null) {
12083						return d;
12084					}
12085	
12086					var negative = d < 0 ? '-' : '';
12087					var flo = parseFloat( d );
12088					var abs = Math.abs(flo);
12089	
12090					// Scientific notation for large and small numbers
12091					if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0) ) {
12092						var exp = flo.toExponential(precision).split(/e\+?/);
12093						return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
12094					}
12095	
12096					// If NaN then there isn't much formatting that we can do - just
12097					// return immediately, escaping any HTML (this was supposed to
12098					// be a number after all)
12099					if ( isNaN( flo ) ) {
12100						return _escapeHtml( d );
12101					}
12102	
12103					flo = flo.toFixed( precision );
12104					d = Math.abs( flo );
12105	
12106					var intPart = parseInt( d, 10 );
12107					var floatPart = precision ?
12108						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
12109						'';
12110	
12111					// If zero, then can't have a negative prefix
12112					if (intPart === 0 && parseFloat(floatPart) === 0) {
12113						negative = '';
12114					}
12115	
12116					return negative + (prefix||'') +
12117						intPart.toString().replace(
12118							/\B(?=(\d{3})+(?!\d))/g, thousands
12119						) +
12120						floatPart +
12121						(postfix||'');
12122				}
12123			};
12124		},
12125	
12126		text: function () {
12127			return {
12128				display: _escapeHtml,
12129				filter: _escapeHtml
12130			};
12131		}
12132	};
12133	
12134	
12135	var _extTypes = DataTable.ext.type;
12136	
12137	// Get / set type
12138	DataTable.type = function (name, prop, val) {
12139		if (! prop) {
12140			return {
12141				className: _extTypes.className[name],
12142				detect: _extTypes.detect.find(function (fn) {
12143					return fn.name === name;
12144				}),
12145				order: {
12146					pre: _extTypes.order[name + '-pre'],
12147					asc: _extTypes.order[name + '-asc'],
12148					desc: _extTypes.order[name + '-desc']
12149				},
12150				render: _extTypes.render[name],
12151				search: _extTypes.search[name]
12152			};
12153		}
12154	
12155		var setProp = function(prop, propVal) {
12156			_extTypes[prop][name] = propVal;
12157		};
12158		var setDetect = function (fn) {
12159			// Wrap to allow the function to return `true` rather than
12160			// specifying the type name.
12161			var cb = function (d, s) {
12162				var ret = fn(d, s);
12163	
12164				return ret === true
12165					? name
12166					: ret;
12167			};
12168			Object.defineProperty(cb, "name", {value: name});
12169	
12170			var idx = _extTypes.detect.findIndex(function (fn) {
12171				return fn.name === name;
12172			});
12173	
12174			if (idx === -1) {
12175				_extTypes.detect.unshift(cb);
12176			}
12177			else {
12178				_extTypes.detect.splice(idx, 1, cb);
12179			}
12180		};
12181		var setOrder = function (obj) {
12182			_extTypes.order[name + '-pre'] = obj.pre; // can be undefined
12183			_extTypes.order[name + '-asc'] = obj.asc; // can be undefined
12184			_extTypes.order[name + '-desc'] = obj.desc; // can be undefined
12185		};
12186	
12187		// prop is optional
12188		if (val === undefined) {
12189			val = prop;
12190			prop = null;
12191		}
12192	
12193		if (prop === 'className') {
12194			setProp('className', val);
12195		}
12196		else if (prop === 'detect') {
12197			setDetect(val);
12198		}
12199		else if (prop === 'order') {
12200			setOrder(val);
12201		}
12202		else if (prop === 'render') {
12203			setProp('render', val);
12204		}
12205		else if (prop === 'search') {
12206			setProp('search', val);
12207		}
12208		else if (! prop) {
12209			if (val.className) {
12210				setProp('className', val.className);
12211			}
12212	
12213			if (val.detect !== undefined) {
12214				setDetect(val.detect);
12215			}
12216	
12217			if (val.order) {
12218				setOrder(val.order);
12219			}
12220	
12221			if (val.render !== undefined) {
12222				setProp('render', val.render);
12223			}
12224	
12225			if (val.search !== undefined) {
12226				setProp('search', val.search);
12227			}
12228		}
12229	}
12230	
12231	// Get a list of types
12232	DataTable.types = function () {
12233		return _extTypes.detect.map(function (fn) {
12234			return fn.name;
12235		});
12236	};
12237	
12238	//
12239	// Built in data types
12240	//
12241	
12242	DataTable.type('string', {
12243		detect: function () {
12244			return 'string';
12245		},
12246		order: {
12247			pre: function ( a ) {
12248				// This is a little complex, but faster than always calling toString,
12249				// http://jsperf.com/tostring-v-check
12250				return _empty(a) ?
12251					'' :
12252					typeof a === 'string' ?
12253						a.toLowerCase() :
12254						! a.toString ?
12255							'' :
12256							a.toString();
12257			}
12258		},
12259		search: _filterString(false, true)
12260	});
12261	
12262	
12263	DataTable.type('html', {
12264		detect: function ( d ) {
12265			return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
12266				'html' : null;
12267		},
12268		order: {
12269			pre: function ( a ) {
12270				return _empty(a) ?
12271					'' :
12272					a.replace ?
12273						_stripHtml(a).trim().toLowerCase() :
12274						a+'';
12275			}
12276		},
12277		search: _filterString(true, true)
12278	});
12279	
12280	
12281	DataTable.type('date', {
12282		className: 'dt-type-date',
12283		detect: function ( d )
12284		{
12285			// V8 tries _very_ hard to make a string passed into `Date.parse()`
12286			// valid, so we need to use a regex to restrict date formats. Use a
12287			// plug-in for anything other than ISO8601 style strings
12288			if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
12289				return null;
12290			}
12291			var parsed = Date.parse(d);
12292			return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
12293		},
12294		order: {
12295			pre: function ( d ) {
12296				var ts = Date.parse( d );
12297				return isNaN(ts) ? -Infinity : ts;
12298			}
12299		}
12300	});
12301	
12302	
12303	DataTable.type('html-num-fmt', {
12304		className: 'dt-type-numeric',
12305		detect: function ( d, settings )
12306		{
12307			var decimal = settings.oLanguage.sDecimal;
12308			return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt' : null;
12309		},
12310		order: {
12311			pre: function ( d, s ) {
12312				var dp = s.oLanguage.sDecimal;
12313				return __numericReplace( d, dp, _re_html, _re_formatted_numeric );
12314			}
12315		},
12316		search: _filterString(true, true)
12317	});
12318	
12319	
12320	DataTable.type('html-num', {
12321		className: 'dt-type-numeric',
12322		detect: function ( d, settings )
12323		{
12324			var decimal = settings.oLanguage.sDecimal;
12325			return _htmlNumeric( d, decimal ) ? 'html-num' : null;
12326		},
12327		order: {
12328			pre: function ( d, s ) {
12329				var dp = s.oLanguage.sDecimal;
12330				return __numericReplace( d, dp, _re_html );
12331			}
12332		},
12333		search: _filterString(true, true)
12334	});
12335	
12336	
12337	DataTable.type('num-fmt', {
12338		className: 'dt-type-numeric',
12339		detect: function ( d, settings )
12340		{
12341			var decimal = settings.oLanguage.sDecimal;
12342			return _isNumber( d, decimal, true ) ? 'num-fmt' : null;
12343		},
12344		order: {
12345			pre: function ( d, s ) {
12346				var dp = s.oLanguage.sDecimal;
12347				return __numericReplace( d, dp, _re_formatted_numeric );
12348			}
12349		}
12350	});
12351	
12352	
12353	DataTable.type('num', {
12354		className: 'dt-type-numeric',
12355		detect: function ( d, settings )
12356		{
12357			var decimal = settings.oLanguage.sDecimal;
12358			return _isNumber( d, decimal ) ? 'num' : null;
12359		},
12360		order: {
12361			pre: function (d, s) {
12362				var dp = s.oLanguage.sDecimal;
12363				return __numericReplace( d, dp );
12364			}
12365		}
12366	});
12367	
12368	
12369	
12370	
12371	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
12372		if ( d !== 0 && (!d || d === '-') ) {
12373			return -Infinity;
12374		}
12375		
12376		var type = typeof d;
12377	
12378		if (type === 'number' || type === 'bigint') {
12379			return d;
12380		}
12381	
12382		// If a decimal place other than `.` is used, it needs to be given to the
12383		// function so we can detect it and replace with a `.` which is the only
12384		// decimal place Javascript recognises - it is not locale aware.
12385		if ( decimalPlace ) {
12386			d = _numToDecimal( d, decimalPlace );
12387		}
12388	
12389		if ( d.replace ) {
12390			if ( re1 ) {
12391				d = d.replace( re1, '' );
12392			}
12393	
12394			if ( re2 ) {
12395				d = d.replace( re2, '' );
12396			}
12397		}
12398	
12399		return d * 1;
12400	};
12401	
12402	
12403	$.extend( true, DataTable.ext.renderer, {
12404		footer: {
12405			_: function ( settings, cell, classes ) {
12406				cell.addClass(classes.tfoot.cell);
12407			}
12408		},
12409	
12410		header: {
12411			_: function ( settings, cell, classes ) {
12412				cell.addClass(classes.thead.cell);
12413	
12414				if (! settings.oFeatures.bSort) {
12415					cell.addClass(classes.order.none);
12416				}
12417	
12418				var legacyTop = settings.bSortCellsTop;
12419				var headerRows = cell.closest('thead').find('tr');
12420				var rowIdx = cell.parent().index();
12421	
12422				// Conditions to not apply the ordering icons
12423				if (
12424					// Cells and rows which have the attribute to disable the icons
12425					cell.attr('data-dt-order') === 'disable' ||
12426					cell.parent().attr('data-dt-order') === 'disable' ||
12427	
12428					// Legacy support for `orderCellsTop`. If it is set, then cells
12429					// which are not in the top or bottom row of the header (depending
12430					// on the value) do not get the sorting classes applied to them
12431					(legacyTop === true && rowIdx !== 0) ||
12432					(legacyTop === false && rowIdx !== headerRows.length - 1)
12433				) {
12434					return;
12435				}
12436	
12437				// No additional mark-up required
12438				// Attach a sort listener to update on sort - note that using the
12439				// `DT` namespace will allow the event to be removed automatically
12440				// on destroy, while the `dt` namespaced event is the one we are
12441				// listening for
12442				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting ) {
12443					if ( settings !== ctx ) { // need to check this this is the host
12444						return;               // table, not a nested one
12445					}
12446	
12447					var orderClasses = classes.order;
12448					var columns = ctx.api.columns( cell );
12449					var col = settings.aoColumns[columns.flatten()[0]];
12450					var orderable = columns.orderable().includes(true);
12451					var ariaType = '';
12452					var indexes = columns.indexes();
12453					var sortDirs = columns.orderable(true).flatten();
12454					var orderedColumns = ',' + sorting.map( function (val) {
12455						return val.col;
12456					} ).join(',') + ',';
12457	
12458					cell
12459						.removeClass(
12460							orderClasses.isAsc +' '+
12461							orderClasses.isDesc
12462						)
12463						.toggleClass( orderClasses.none, ! orderable )
12464						.toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
12465						.toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
12466					
12467					var sortIdx = orderedColumns.indexOf( ',' + indexes.toArray().join(',') + ',' );
12468	
12469					if ( sortIdx !== -1 ) {
12470						// Get the ordering direction for the columns under this cell
12471						// Note that it is possible for a cell to be asc and desc sorting
12472						// (column spanning cells)
12473						var orderDirs = columns.order();
12474	
12475						cell.addClass(
12476							orderDirs.includes('asc') ? orderClasses.isAsc : '' +
12477							orderDirs.includes('desc') ? orderClasses.isDesc : ''
12478						);
12479					}
12480	
12481					// The ARIA spec says that only one column should be marked with aria-sort
12482					if ( sortIdx === 0 ) {
12483						var firstSort = sorting[0];
12484						var sortOrder = col.asSorting;
12485	
12486						cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
12487	
12488						// Determine if the next click will remove sorting or change the sort
12489						ariaType = ! sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
12490					}
12491					else {
12492						cell.removeAttr('aria-sort');
12493					}
12494	
12495					cell.attr('aria-label', orderable
12496						? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
12497						: col.ariaTitle
12498					);
12499	
12500					if (orderable) {
12501						cell.find('.dt-column-title').attr('role', 'button');
12502						cell.attr('tabindex', 0)
12503					}
12504				} );
12505			}
12506		},
12507	
12508		layout: {
12509			_: function ( settings, container, items ) {
12510				var row = $('<div/>')
12511					.addClass('dt-layout-row')
12512					.appendTo( container );
12513	
12514				$.each( items, function (key, val) {
12515					var klass = ! val.table ?
12516						'dt-'+key+' ' :
12517						'';
12518	
12519					if (val.table) {
12520						row.addClass('dt-layout-table');
12521					}
12522	
12523					$('<div/>')
12524						.attr({
12525							id: val.id || null,
12526							"class": 'dt-layout-cell '+klass+(val.className || '')
12527						})
12528						.append( val.contents )
12529						.appendTo( row );
12530				} );
12531			}
12532		}
12533	} );
12534	
12535	
12536	DataTable.feature = {};
12537	
12538	// Third parameter is internal only!
12539	DataTable.feature.register = function ( name, cb, legacy ) {
12540		DataTable.ext.features[ name ] = cb;
12541	
12542		if (legacy) {
12543			_ext.feature.push({
12544				cFeature: legacy,
12545				fnInit: cb
12546			});
12547		}
12548	};
12549	
12550	DataTable.feature.register( 'info', function ( settings, opts ) {
12551		// For compatibility with the legacy `info` top level option
12552		if (! settings.oFeatures.bInfo) {
12553			return null;
12554		}
12555	
12556		var
12557			lang  = settings.oLanguage,
12558			tid = settings.sTableId,
12559			n = $('<div/>', {
12560				'class': settings.oClasses.info.container,
12561			} );
12562	
12563		opts = $.extend({
12564			callback: lang.fnInfoCallback,
12565			empty: lang.sInfoEmpty,
12566			postfix: lang.sInfoPostFix,
12567			search: lang.sInfoFiltered,
12568			text: lang.sInfo,
12569		}, opts);
12570	
12571	
12572		// Update display on each draw
12573		settings.aoDrawCallback.push(function (s) {
12574			_fnUpdateInfo(s, opts, n);
12575		});
12576	
12577		// For the first info display in the table, we add a callback and aria information.
12578		if (! settings._infoEl) {
12579			n.attr({
12580				'aria-live': 'polite',
12581				id: tid+'_info',
12582				role: 'status'
12583			});
12584	
12585			// Table is described by our info div
12586			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
12587	
12588			settings._infoEl = n;
12589		}
12590	
12591		return n;
12592	}, 'i' );
12593	
12594	/**
12595	 * Update the information elements in the display
12596	 *  @param {object} settings dataTables settings object
12597	 *  @memberof DataTable#oApi
12598	 */
12599	function _fnUpdateInfo ( settings, opts, node )
12600	{
12601		var
12602			start = settings._iDisplayStart+1,
12603			end   = settings.fnDisplayEnd(),
12604			max   = settings.fnRecordsTotal(),
12605			total = settings.fnRecordsDisplay(),
12606			out   = total
12607				? opts.text
12608				: opts.empty;
12609	
12610		if ( total !== max ) {
12611			// Record set after filtering
12612			out += ' ' + opts.search;
12613		}
12614	
12615		// Convert the macros
12616		out += opts.postfix;
12617		out = _fnMacros( settings, out );
12618	
12619		if ( opts.callback ) {
12620			out = opts.callback.call( settings.oInstance,
12621				settings, start, end, max, total, out
12622			);
12623		}
12624	
12625		node.html( out );
12626	
12627		_fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
12628	}
12629	
12630	var __searchCounter = 0;
12631	
12632	// opts
12633	// - text
12634	// - placeholder
12635	DataTable.feature.register( 'search', function ( settings, opts ) {
12636		// Don't show the input if filtering isn't available on the table
12637		if (! settings.oFeatures.bFilter) {
12638			return null;
12639		}
12640	
12641		var classes = settings.oClasses.search;
12642		var tableId = settings.sTableId;
12643		var language = settings.oLanguage;
12644		var previousSearch = settings.oPreviousSearch;
12645		var input = '<input type="search" class="'+classes.input+'"/>';
12646	
12647		opts = $.extend({
12648			placeholder: language.sSearchPlaceholder,
12649			text: language.sSearch
12650		}, opts);
12651	
12652		// The _INPUT_ is optional - is appended if not present
12653		if (opts.text.indexOf('_INPUT_') === -1) {
12654			opts.text += '_INPUT_';
12655		}
12656	
12657		opts.text = _fnMacros(settings, opts.text);
12658	
12659		// We can put the <input> outside of the label if it is at the start or end
12660		// which helps improve accessability (not all screen readers like implicit
12661		// for elements).
12662		var end = opts.text.match(/_INPUT_$/);
12663		var start = opts.text.match(/^_INPUT_/);
12664		var removed = opts.text.replace(/_INPUT_/, '');
12665		var str = '<label>' + opts.text + '</label>';
12666	
12667		if (start) {
12668			str = '_INPUT_<label>' + removed + '</label>';
12669		}
12670		else if (end) {
12671			str = '<label>' + removed + '</label>_INPUT_';
12672		}
12673	
12674		var filter = $('<div>')
12675			.addClass(classes.container)
12676			.append(str.replace(/_INPUT_/, input));
12677	
12678		// add for and id to label and input
12679		filter.find('label').attr('for', 'dt-search-' + __searchCounter);
12680		filter.find('input').attr('id', 'dt-search-' + __searchCounter);
12681		__searchCounter++;
12682	
12683		var searchFn = function(event) {
12684			var val = this.value;
12685	
12686			if(previousSearch.return && event.key !== "Enter") {
12687				return;
12688			}
12689	
12690			/* Now do the filter */
12691			if ( val != previousSearch.search ) {
12692				previousSearch.search = val;
12693	
12694				_fnFilterComplete( settings, previousSearch );
12695	
12696				// Need to redraw, without resorting
12697				settings._iDisplayStart = 0;
12698				_fnDraw( settings );
12699			}
12700		};
12701	
12702		var searchDelay = settings.searchDelay !== null ?
12703			settings.searchDelay :
12704			0;
12705	
12706		var jqFilter = $('input', filter)
12707			.val( previousSearch.search )
12708			.attr( 'placeholder', opts.placeholder )
12709			.on(
12710				'keyup.DT search.DT input.DT paste.DT cut.DT',
12711				searchDelay ?
12712					DataTable.util.debounce( searchFn, searchDelay ) :
12713					searchFn
12714			)
12715			.on( 'mouseup.DT', function(e) {
12716				// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
12717				// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
12718				// checks the value to see if it has changed. In other browsers it won't have.
12719				setTimeout( function () {
12720					searchFn.call(jqFilter[0], e);
12721				}, 10);
12722			} )
12723			.on( 'keypress.DT', function(e) {
12724				/* Prevent form submission */
12725				if ( e.keyCode == 13 ) {
12726					return false;
12727				}
12728			} )
12729			.attr('aria-controls', tableId);
12730	
12731		// Update the input elements whenever the table is filtered
12732		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
12733			if ( settings === s && jqFilter[0] !== document.activeElement ) {
12734				jqFilter.val( typeof previousSearch.search !== 'function'
12735					? previousSearch.search
12736					: ''
12737				);
12738			}
12739		} );
12740	
12741		return filter;
12742	}, 'f' );
12743	
12744	// opts
12745	// - type - button configuration
12746	// - buttons - number of buttons to show - must be odd
12747	DataTable.feature.register( 'paging', function ( settings, opts ) {
12748		// Don't show the paging input if the table doesn't have paging enabled
12749		if (! settings.oFeatures.bPaginate) {
12750			return null;
12751		}
12752	
12753		opts = $.extend({
12754			buttons: DataTable.ext.pager.numbers_length,
12755			type: settings.sPaginationType,
12756			boundaryNumbers: true
12757		}, opts);
12758	
12759		// To be removed in 2.1
12760		if (opts.numbers) {
12761			opts.buttons = opts.numbers;
12762		}
12763	
12764		var host = $('<div/>').addClass( settings.oClasses.paging.container + ' paging_' + opts.type );
12765		var draw = function () {
12766			_pagingDraw(settings, host, opts);
12767		};
12768	
12769		settings.aoDrawCallback.push(draw);
12770	
12771		// Responsive redraw of paging control
12772		$(settings.nTable).on('column-sizing.dt.DT', draw);
12773	
12774		return host;
12775	}, 'p' );
12776	
12777	function _pagingDraw(settings, host, opts) {
12778		if (! settings._bInitComplete) {
12779			return;
12780		}
12781	
12782		var
12783			plugin = DataTable.ext.pager[ opts.type ],
12784			aria = settings.oLanguage.oAria.paginate || {},
12785			start      = settings._iDisplayStart,
12786			len        = settings._iDisplayLength,
12787			visRecords = settings.fnRecordsDisplay(),
12788			all        = len === -1,
12789			page = all ? 0 : Math.ceil( start / len ),
12790			pages = all ? 1 : Math.ceil( visRecords / len ),
12791			buttons = plugin()
12792				.map(function (val) {
12793					return val === 'numbers'
12794						? _pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
12795						: val;
12796				})
12797				.flat();
12798	
12799		var buttonEls = [];
12800	
12801		for (var i=0 ; i<buttons.length ; i++) {
12802			var button = buttons[i];
12803	
12804			var btnInfo = _pagingButtonInfo(settings, button, page, pages);
12805			var btn = _fnRenderer( settings, 'pagingButton' )(
12806				settings,
12807				button,
12808				btnInfo.display,
12809				btnInfo.active,
12810				btnInfo.disabled
12811			);
12812	
12813			// Common attributes
12814			$(btn.clicker).attr({
12815				'aria-controls': settings.sTableId,
12816				'aria-disabled': btnInfo.disabled ? 'true' : null,
12817				'aria-current': btnInfo.active ? 'page' : null,
12818				'aria-label': aria[ button ],
12819				'data-dt-idx': button,
12820				'tabIndex': btnInfo.disabled ? -1 : settings.iTabIndex,
12821			});
12822	
12823			if (typeof button !== 'number') {
12824				$(btn.clicker).addClass(button);
12825			}
12826	
12827			_fnBindAction(
12828				btn.clicker, {action: button}, function(e) {
12829					e.preventDefault();
12830	
12831					_fnPageChange( settings, e.data.action, true );
12832				}
12833			);
12834	
12835			buttonEls.push(btn.display);
12836		}
12837	
12838		var wrapped = _fnRenderer(settings, 'pagingContainer')(
12839			settings, buttonEls
12840		);
12841	
12842		var activeEl = host.find(document.activeElement).data('dt-idx');
12843	
12844		host.empty().append(wrapped);
12845	
12846		if ( activeEl !== undefined ) {
12847			host.find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
12848		}
12849	
12850		// Responsive - check if the buttons are over two lines based on the
12851		// height of the buttons and the container.
12852		if (
12853			buttonEls.length && // any buttons
12854			opts.numbers > 1 && // prevent infinite
12855			$(host).height() >= ($(buttonEls[0]).outerHeight() * 2) - 10
12856		) {
12857			_pagingDraw(settings, host, $.extend({}, opts, { numbers: opts.numbers - 2 }));
12858		}
12859	}
12860	
12861	/**
12862	 * Get properties for a button based on the current paging state of the table
12863	 *
12864	 * @param {*} settings DT settings object
12865	 * @param {*} button The button type in question
12866	 * @param {*} page Table's current page
12867	 * @param {*} pages Number of pages
12868	 * @returns Info object
12869	 */
12870	function _pagingButtonInfo(settings, button, page, pages) {
12871		var lang = settings.oLanguage.oPaginate;
12872		var o = {
12873			display: '',
12874			active: false,
12875			disabled: false
12876		};
12877	
12878		switch ( button ) {
12879			case 'ellipsis':
12880				o.display = '&#x2026;';
12881				o.disabled = true;
12882				break;
12883	
12884			case 'first':
12885				o.display = lang.sFirst;
12886	
12887				if (page === 0) {
12888					o.disabled = true;
12889				}
12890				break;
12891	
12892			case 'previous':
12893				o.display = lang.sPrevious;
12894	
12895				if ( page === 0 ) {
12896					o.disabled = true;
12897				}
12898				break;
12899	
12900			case 'next':
12901				o.display = lang.sNext;
12902	
12903				if ( pages === 0 || page === pages-1 ) {
12904					o.disabled = true;
12905				}
12906				break;
12907	
12908			case 'last':
12909				o.display = lang.sLast;
12910	
12911				if ( pages === 0 || page === pages-1 ) {
12912					o.disabled = true;
12913				}
12914				break;
12915	
12916			default:
12917				if ( typeof button === 'number' ) {
12918					o.display = settings.fnFormatNumber( button + 1 );
12919					
12920					if (page === button) {
12921						o.active = true;
12922					}
12923				}
12924				break;
12925		}
12926	
12927		return o;
12928	}
12929	
12930	/**
12931	 * Compute what number buttons to show in the paging control
12932	 *
12933	 * @param {*} page Current page
12934	 * @param {*} pages Total number of pages
12935	 * @param {*} buttons Target number of number buttons
12936	 * @param {boolean} addFirstLast Indicate if page 1 and end should be included
12937	 * @returns Buttons to show
12938	 */
12939	function _pagingNumbers ( page, pages, buttons, addFirstLast ) {
12940		var
12941			numbers = [],
12942			half = Math.floor(buttons / 2),
12943			before = addFirstLast ? 2 : 1,
12944			after = addFirstLast ? 1 : 0;
12945	
12946		if ( pages <= buttons ) {
12947			numbers = _range(0, pages);
12948		}
12949		else if (buttons === 1) {
12950			// Single button - current page only
12951			numbers = [page];
12952		}
12953		else if (buttons === 3) {
12954			// Special logic for just three buttons
12955			if (page <= 1) {
12956				numbers = [0, 1, 'ellipsis'];
12957			}
12958			else if (page >= pages - 2) {
12959				numbers = _range(pages-2, pages);
12960				numbers.unshift('ellipsis');
12961			}
12962			else {
12963				numbers = ['ellipsis', page, 'ellipsis'];
12964			}
12965		}
12966		else if ( page <= half ) {
12967			numbers = _range(0, buttons-before);
12968			numbers.push('ellipsis');
12969	
12970			if (addFirstLast) {
12971				numbers.push(pages-1);
12972			}
12973		}
12974		else if ( page >= pages - 1 - half ) {
12975			numbers = _range(pages-(buttons-before), pages);
12976			numbers.unshift('ellipsis');
12977	
12978			if (addFirstLast) {
12979				numbers.unshift(0);
12980			}
12981		}
12982		else {
12983			numbers = _range(page-half+before, page+half-after);
12984			numbers.push('ellipsis');
12985			numbers.unshift('ellipsis');
12986	
12987			if (addFirstLast) {
12988				numbers.push(pages-1);
12989				numbers.unshift(0);
12990			}
12991		}
12992	
12993		return numbers;
12994	}
12995	
12996	var __lengthCounter = 0;
12997	
12998	// opts
12999	// - menu
13000	// - text
13001	DataTable.feature.register( 'pageLength', function ( settings, opts ) {
13002		var features = settings.oFeatures;
13003	
13004		// For compatibility with the legacy `pageLength` top level option
13005		if (! features.bPaginate || ! features.bLengthChange) {
13006			return null;
13007		}
13008	
13009		opts = $.extend({
13010			menu: settings.aLengthMenu,
13011			text: settings.oLanguage.sLengthMenu
13012		}, opts);
13013	
13014		var
13015			classes  = settings.oClasses.length,
13016			tableId  = settings.sTableId,
13017			menu     = opts.menu,
13018			lengths  = [],
13019			language = [],
13020			i;
13021	
13022		// Options can be given in a number of ways
13023		if (Array.isArray( menu[0] )) {
13024			// Old 1.x style - 2D array
13025			lengths = menu[0];
13026			language = menu[1];
13027		}
13028		else {
13029			for ( i=0 ; i<menu.length ; i++ ) {
13030				// An object with different label and value
13031				if ($.isPlainObject(menu[i])) {
13032					lengths.push(menu[i].value);
13033					language.push(menu[i].label);
13034				}
13035				else {
13036					// Or just a number to display and use
13037					lengths.push(menu[i]);
13038					language.push(menu[i]);
13039				}
13040			}
13041		}
13042	
13043		// We can put the <select> outside of the label if it is at the start or
13044		// end which helps improve accessability (not all screen readers like
13045		// implicit for elements).
13046		var end = opts.text.match(/_MENU_$/);
13047		var start = opts.text.match(/^_MENU_/);
13048		var removed = opts.text.replace(/_MENU_/, '');
13049		var str = '<label>' + opts.text + '</label>';
13050	
13051		if (start) {
13052			str = '_MENU_<label>' + removed + '</label>';
13053		}
13054		else if (end) {
13055			str = '<label>' + removed + '</label>_MENU_';
13056		}
13057	
13058		// Wrapper element - use a span as a holder for where the select will go
13059		var div = $('<div/>')
13060			.addClass( classes.container )
13061			.append(
13062				str.replace( '_MENU_', '<span></span>' )
13063			);
13064	
13065		// Save text node content for macro updating
13066		var textNodes = [];
13067		div.find('label')[0].childNodes.forEach(function (el) {
13068			if (el.nodeType === Node.TEXT_NODE) {
13069				textNodes.push({
13070					el: el,
13071					text: el.textContent
13072				});
13073			}
13074		})
13075	
13076		// Update the label text in case it has an entries value
13077		var updateEntries = function (len) {
13078			textNodes.forEach(function (node) {
13079				node.el.textContent = _fnMacros(settings, node.text, len);
13080			});
13081		}
13082	
13083		// Next, the select itself, along with the options
13084		var select = $('<select/>', {
13085			'name':          tableId+'_length',
13086			'aria-controls': tableId,
13087			'class':         classes.select
13088		} );
13089	
13090		for ( i=0 ; i<lengths.length ; i++ ) {
13091			select[0][ i ] = new Option(
13092				typeof language[i] === 'number' ?
13093					settings.fnFormatNumber( language[i] ) :
13094					language[i],
13095				lengths[i]
13096			);
13097		}
13098	
13099		// add for and id to label and input
13100		div.find('label').attr('for', 'dt-length-' + __lengthCounter);
13101		select.attr('id', 'dt-length-' + __lengthCounter);
13102		__lengthCounter++;
13103	
13104		// Swap in the select list
13105		div.find('span').replaceWith(select);
13106	
13107		// Can't use `select` variable as user might provide their own and the
13108		// reference is broken by the use of outerHTML
13109		$('select', div)
13110			.val( settings._iDisplayLength )
13111			.on( 'change.DT', function() {
13112				_fnLengthChange( settings, $(this).val() );
13113				_fnDraw( settings );
13114			} );
13115	
13116		// Update node value whenever anything changes the table's length
13117		$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
13118			if ( settings === s ) {
13119				$('select', div).val( len );
13120	
13121				// Resolve plurals in the text for the new length
13122				updateEntries(len);
13123			}
13124		} );
13125	
13126		updateEntries(settings._iDisplayLength);
13127	
13128		return div;
13129	}, 'l' );
13130	
13131	// jQuery access
13132	$.fn.dataTable = DataTable;
13133	
13134	// Provide access to the host jQuery object (circular reference)
13135	DataTable.$ = $;
13136	
13137	// Legacy aliases
13138	$.fn.dataTableSettings = DataTable.settings;
13139	$.fn.dataTableExt = DataTable.ext;
13140	
13141	// With a capital `D` we return a DataTables API instance rather than a
13142	// jQuery object
13143	$.fn.DataTable = function ( opts ) {
13144		return $(this).dataTable( opts ).api();
13145	};
13146	
13147	// All properties that are available to $.fn.dataTable should also be
13148	// available on $.fn.DataTable
13149	$.each( DataTable, function ( prop, val ) {
13150		$.fn.DataTable[ prop ] = val;
13151	} );
13152
13153	return DataTable;
13154}));

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.