PageSourceSearch

https://theartssociety.org/sites/all/modules/custom/civi_societyad…/media/js/jquery.dataTables.js?tlvm4t

js theartssociety.org collected 2026-09-24 20:56:33 UTC 551,871 bytes, 19,469 lines download raw bytes

1/*
2 * This combined file was created by the DataTables downloader builder:
3 *   https://datatables.net/download
4 *
5 * To rebuild or modify this file with the latest versions of the included
6 * software please visit:
7 *   https://datatables.net/download/#dt/dt-1.10.11,af-2.1.1,b-1.1.2,b-html5-1.1.2,fh-3.1.1
8 *
9 * Included libraries:
10 *   DataTables 1.10.11, AutoFill 2.1.1, Buttons 1.1.2, HTML5 export 1.1.2, FixedHeader 3.1.1
11 */
12
13/*! DataTables 1.10.11
14 * ©2008-2015 SpryMedia Ltd - datatables.net/license
15 */
16
17/**
18 * @summary     DataTables
19 * @description Paginate, search and order HTML tables
20 * @version     1.10.11
21 * @file        jquery.dataTables.js
22 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
23 * @contact     www.sprymedia.co.uk/contact
24 * @copyright   Copyright 2008-2015 SpryMedia Ltd.
25 *
26 * This source file is free software, available under the following license:
27 *   MIT license - http://datatables.net/license
28 *
29 * This source file is distributed in the hope that it will be useful, but
30 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
32 *
33 * For details please refer to: http://www.datatables.net
34 */
35
36/*jslint evil: true, undef: true, browser: true */
37/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
38
39(function( factory ) {
40	"use strict";
41
42	if ( typeof define === 'function' && define.amd ) {
43		// AMD
44		define( ['jquery'], function ( $ ) {
45			return factory( $, window, document );
46		} );
47	}
48	else if ( typeof exports === 'object' ) {
49		// CommonJS
50		module.exports = function (root, $) {
51			if ( ! root ) {
52				// CommonJS environments without a window global must pass a
53				// root. This will give an error otherwise
54				root = window;
55			}
56
57			if ( ! $ ) {
58				$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
59					require('jquery') :
60					require('jquery')( root );
61			}
62
63			return factory( $, root, root.document );
64		};
65	}
66	else {
67		// Browser
68		factory( jQuery, window, document );
69	}
70}
71(function( $, window, document, undefined ) {
72	"use strict";
73
74	/**
75	 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
76	 * flexible tool, based upon the foundations of progressive enhancement,
77	 * which will add advanced interaction controls to any HTML table. For a
78	 * full list of features please refer to
79	 * [DataTables.net](href="http://datatables.net).
80	 *
81	 * Note that the `DataTable` object is not a global variable but is aliased
82	 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
83	 * be  accessed.
84	 *
85	 *  @class
86	 *  @param {object} [init={}] Configuration object for DataTables. Options
87	 *    are defined by {@link DataTable.defaults}
88	 *  @requires jQuery 1.7+
89	 *
90	 *  @example
91	 *    // Basic initialisation
92	 *    $(document).ready( function {
93	 *      $('#example').dataTable();
94	 *    } );
95	 *
96	 *  @example
97	 *    // Initialisation with configuration options - in this case, disable
98	 *    // pagination and sorting.
99	 *    $(document).ready( function {
100	 *      $('#example').dataTable( {
101	 *        "paginate": false,
102	 *        "sort": false
103	 *      } );
104	 *    } );
105	 */
106	var DataTable;
107
108	
109	/*
110	 * It is useful to have variables which are scoped locally so only the
111	 * DataTables functions can access them and they don't leak into global space.
112	 * At the same time these functions are often useful over multiple files in the
113	 * core and API, so we list, or at least document, all variables which are used
114	 * by DataTables as private variables here. This also ensures that there is no
115	 * clashing of variable names and that they can easily referenced for reuse.
116	 */
117	
118	
119	// Defined else where
120	//  _selector_run
121	//  _selector_opts
122	//  _selector_first
123	//  _selector_row_indexes
124	
125	var _ext; // DataTable.ext
126	var _Api; // DataTable.Api
127	var _api_register; // DataTable.Api.register
128	var _api_registerPlural; // DataTable.Api.registerPlural
129	
130	var _re_dic = {};
131	var _re_new_lines = /[\r\n]/g;
132	var _re_html = /<.*?>/g;
133	var _re_date_start = /^[\w\+\-]/;
134	var _re_date_end = /[\w\+\-]$/;
135	
136	// Escape regular expression special characters
137	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
138	
139	// http://en.wikipedia.org/wiki/Foreign_exchange_market
140	// - \u20BD - Russian ruble.
141	// - \u20a9 - South Korean Won
142	// - \u20BA - Turkish Lira
143	// - \u20B9 - Indian Rupee
144	// - R - Brazil (R$) and South Africa
145	// - fr - Swiss Franc
146	// - kr - Swedish krona, Norwegian krone and Danish krone
147	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
148	//   standards as thousands separators.
149	var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
150	
151	
152	var _empty = function ( d ) {
153		return !d || d === true || d === '-' ? true : false;
154	};
155	
156	
157	var _intVal = function ( s ) {
158		var integer = parseInt( s, 10 );
159		return !isNaN(integer) && isFinite(s) ? integer : null;
160	};
161	
162	// Convert from a formatted number with characters other than `.` as the
163	// decimal place, to a Javascript number
164	var _numToDecimal = function ( num, decimalPoint ) {
165		// Cache created regular expressions for speed as this function is called often
166		if ( ! _re_dic[ decimalPoint ] ) {
167			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
168		}
169		return typeof num === 'string' && decimalPoint !== '.' ?
170			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
171			num;
172	};
173	
174	
175	var _isNumber = function ( d, decimalPoint, formatted ) {
176		var strType = typeof d === 'string';
177	
178		// If empty return immediately so there must be a number if it is a
179		// formatted string (this stops the string "k", or "kr", etc being detected
180		// as a formatted number for currency
181		if ( _empty( d ) ) {
182			return true;
183		}
184	
185		if ( decimalPoint && strType ) {
186			d = _numToDecimal( d, decimalPoint );
187		}
188	
189		if ( formatted && strType ) {
190			d = d.replace( _re_formatted_numeric, '' );
191		}
192	
193		return !isNaN( parseFloat(d) ) && isFinite( d );
194	};
195	
196	
197	// A string without HTML in it can be considered to be HTML still
198	var _isHtml = function ( d ) {
199		return _empty( d ) || typeof d === 'string';
200	};
201	
202	
203	var _htmlNumeric = function ( d, decimalPoint, formatted ) {
204		if ( _empty( d ) ) {
205			return true;
206		}
207	
208		var html = _isHtml( d );
209		return ! html ?
210			null :
211			_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
212				true :
213				null;
214	};
215	
216	
217	var _pluck = function ( a, prop, prop2 ) {
218		var out = [];
219		var i=0, ien=a.length;
220	
221		// Could have the test in the loop for slightly smaller code, but speed
222		// is essential here
223		if ( prop2 !== undefined ) {
224			for ( ; i<ien ; i++ ) {
225				if ( a[i] && a[i][ prop ] ) {
226					out.push( a[i][ prop ][ prop2 ] );
227				}
228			}
229		}
230		else {
231			for ( ; i<ien ; i++ ) {
232				if ( a[i] ) {
233					out.push( a[i][ prop ] );
234				}
235			}
236		}
237	
238		return out;
239	};
240	
241	
242	// Basically the same as _pluck, but rather than looping over `a` we use `order`
243	// as the indexes to pick from `a`
244	var _pluck_order = function ( a, order, prop, prop2 )
245	{
246		var out = [];
247		var i=0, ien=order.length;
248	
249		// Could have the test in the loop for slightly smaller code, but speed
250		// is essential here
251		if ( prop2 !== undefined ) {
252			for ( ; i<ien ; i++ ) {
253				if ( a[ order[i] ][ prop ] ) {
254					out.push( a[ order[i] ][ prop ][ prop2 ] );
255				}
256			}
257		}
258		else {
259			for ( ; i<ien ; i++ ) {
260				out.push( a[ order[i] ][ prop ] );
261			}
262		}
263	
264		return out;
265	};
266	
267	
268	var _range = function ( len, start )
269	{
270		var out = [];
271		var end;
272	
273		if ( start === undefined ) {
274			start = 0;
275			end = len;
276		}
277		else {
278			end = start;
279			start = len;
280		}
281	
282		for ( var i=start ; i<end ; i++ ) {
283			out.push( i );
284		}
285	
286		return out;
287	};
288	
289	
290	var _removeEmpty = function ( a )
291	{
292		var out = [];
293	
294		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
295			if ( a[i] ) { // careful - will remove all falsy values!
296				out.push( a[i] );
297			}
298		}
299	
300		return out;
301	};
302	
303	
304	var _stripHtml = function ( d ) {
305		return d.replace( _re_html, '' );
306	};
307	
308	
309	/**
310	 * Find the unique elements in a source array.
311	 *
312	 * @param  {array} src Source array
313	 * @return {array} Array of unique items
314	 * @ignore
315	 */
316	var _unique = function ( src )
317	{
318		// A faster unique method is to use object keys to identify used values,
319		// but this doesn't work with arrays or objects, which we must also
320		// consider. See jsperf.com/compare-array-unique-versions/4 for more
321		// information.
322		var
323			out = [],
324			val,
325			i, ien=src.length,
326			j, k=0;
327	
328		again: for ( i=0 ; i<ien ; i++ ) {
329			val = src[i];
330	
331			for ( j=0 ; j<k ; j++ ) {
332				if ( out[j] === val ) {
333					continue again;
334				}
335			}
336	
337			out.push( val );
338			k++;
339		}
340	
341		return out;
342	};
343	
344	
345	
346	/**
347	 * Create a mapping object that allows camel case parameters to be looked up
348	 * for their Hungarian counterparts. The mapping is stored in a private
349	 * parameter called `_hungarianMap` which can be accessed on the source object.
350	 *  @param {object} o
351	 *  @memberof DataTable#oApi
352	 */
353	function _fnHungarianMap ( o )
354	{
355		var
356			hungarian = 'a aa ai ao as b fn i m o s ',
357			match,
358			newKey,
359			map = {};
360	
361		$.each( o, function (key, val) {
362			match = key.match(/^([^A-Z]+?)([A-Z])/);
363	
364			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
365			{
366				newKey = key.replace( match[0], match[2].toLowerCase() );
367				map[ newKey ] = key;
368	
369				if ( match[1] === 'o' )
370				{
371					_fnHungarianMap( o[key] );
372				}
373			}
374		} );
375	
376		o._hungarianMap = map;
377	}
378	
379	
380	/**
381	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
382	 * created by _fnHungarianMap.
383	 *  @param {object} src The model object which holds all parameters that can be
384	 *    mapped.
385	 *  @param {object} user The object to convert from camel case to Hungarian.
386	 *  @param {boolean} force When set to `true`, properties which already have a
387	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
388	 *    won't be.
389	 *  @memberof DataTable#oApi
390	 */
391	function _fnCamelToHungarian ( src, user, force )
392	{
393		if ( ! src._hungarianMap ) {
394			_fnHungarianMap( src );
395		}
396	
397		var hungarianKey;
398	
399		$.each( user, function (key, val) {
400			hungarianKey = src._hungarianMap[ key ];
401	
402			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
403			{
404				// For objects, we need to buzz down into the object to copy parameters
405				if ( hungarianKey.charAt(0) === 'o' )
406				{
407					// Copy the camelCase options over to the hungarian
408					if ( ! user[ hungarianKey ] ) {
409						user[ hungarianKey ] = {};
410					}
411					$.extend( true, user[hungarianKey], user[key] );
412	
413					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
414				}
415				else {
416					user[hungarianKey] = user[ key ];
417				}
418			}
419		} );
420	}
421	
422	
423	/**
424	 * Language compatibility - when certain options are given, and others aren't, we
425	 * need to duplicate the values over, in order to provide backwards compatibility
426	 * with older language files.
427	 *  @param {object} oSettings dataTables settings object
428	 *  @memberof DataTable#oApi
429	 */
430	function _fnLanguageCompat( lang )
431	{
432		var defaults = DataTable.defaults.oLanguage;
433		var zeroRecords = lang.sZeroRecords;
434	
435		/* Backwards compatibility - if there is no sEmptyTable given, then use the same as
436		 * sZeroRecords - assuming that is given.
437		 */
438		if ( ! lang.sEmptyTable && zeroRecords &&
439			defaults.sEmptyTable === "No data available in table" )
440		{
441			_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
442		}
443	
444		/* Likewise with loading records */
445		if ( ! lang.sLoadingRecords && zeroRecords &&
446			defaults.sLoadingRecords === "Loading..." )
447		{
448			_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
449		}
450	
451		// Old parameter name of the thousands separator mapped onto the new
452		if ( lang.sInfoThousands ) {
453			lang.sThousands = lang.sInfoThousands;
454		}
455	
456		var decimal = lang.sDecimal;
457		if ( decimal ) {
458			_addNumericSort( decimal );
459		}
460	}
461	
462	
463	/**
464	 * Map one parameter onto another
465	 *  @param {object} o Object to map
466	 *  @param {*} knew The new parameter name
467	 *  @param {*} old The old parameter name
468	 */
469	var _fnCompatMap = function ( o, knew, old ) {
470		if ( o[ knew ] !== undefined ) {
471			o[ old ] = o[ knew ];
472		}
473	};
474	
475	
476	/**
477	 * Provide backwards compatibility for the main DT options. Note that the new
478	 * options are mapped onto the old parameters, so this is an external interface
479	 * change only.
480	 *  @param {object} init Object to map
481	 */
482	function _fnCompatOpts ( init )
483	{
484		_fnCompatMap( init, 'ordering',      'bSort' );
485		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
486		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
487		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
488		_fnCompatMap( init, 'order',         'aaSorting' );
489		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
490		_fnCompatMap( init, 'paging',        'bPaginate' );
491		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
492		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
493		_fnCompatMap( init, 'searching',     'bFilter' );
494	
495		// Boolean initialisation of x-scrolling
496		if ( typeof init.sScrollX === 'boolean' ) {
497			init.sScrollX = init.sScrollX ? '100%' : '';
498		}
499		if ( typeof init.scrollX === 'boolean' ) {
500			init.scrollX = init.scrollX ? '100%' : '';
501		}
502	
503		// Column search objects are in an array, so it needs to be converted
504		// element by element
505		var searchCols = init.aoSearchCols;
506	
507		if ( searchCols ) {
508			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
509				if ( searchCols[i] ) {
510					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
511				}
512			}
513		}
514	}
515	
516	
517	/**
518	 * Provide backwards compatibility for column options. Note that the new options
519	 * are mapped onto the old parameters, so this is an external interface change
520	 * only.
521	 *  @param {object} init Object to map
522	 */
523	function _fnCompatCols ( init )
524	{
525		_fnCompatMap( init, 'orderable',     'bSortable' );
526		_fnCompatMap( init, 'orderData',     'aDataSort' );
527		_fnCompatMap( init, 'orderSequence', 'asSorting' );
528		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
529	
530		// orderData can be given as an integer
531		var dataSort = init.aDataSort;
532		if ( dataSort && ! $.isArray( dataSort ) ) {
533			init.aDataSort = [ dataSort ];
534		}
535	}
536	
537	
538	/**
539	 * Browser feature detection for capabilities, quirks
540	 *  @param {object} settings dataTables settings object
541	 *  @memberof DataTable#oApi
542	 */
543	function _fnBrowserDetect( settings )
544	{
545		// We don't need to do this every time DataTables is constructed, the values
546		// calculated are specific to the browser and OS configuration which we
547		// don't expect to change between initialisations
548		if ( ! DataTable.__browser ) {
549			var browser = {};
550			DataTable.__browser = browser;
551	
552			// Scrolling feature / quirks detection
553			var n = $('<div/>')
554				.css( {
555					position: 'fixed',
556					top: 0,
557					left: 0,
558					height: 1,
559					width: 1,
560					overflow: 'hidden'
561				} )
562				.append(
563					$('<div/>')
564						.css( {
565							position: 'absolute',
566							top: 1,
567							left: 1,
568							width: 100,
569							overflow: 'scroll'
570						} )
571						.append(
572							$('<div/>')
573								.css( {
574									width: '100%',
575									height: 10
576								} )
577						)
578				)
579				.appendTo( 'body' );
580	
581			var outer = n.children();
582			var inner = outer.children();
583	
584			// Numbers below, in order, are:
585			// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
586			//
587			// IE6 XP:                           100 100 100  83
588			// IE7 Vista:                        100 100 100  83
589			// IE 8+ Windows:                     83  83 100  83
590			// Evergreen Windows:                 83  83 100  83
591			// Evergreen Mac with scrollbars:     85  85 100  85
592			// Evergreen Mac without scrollbars: 100 100 100 100
593	
594			// Get scrollbar width
595			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
596	
597			// IE6/7 will oversize a width 100% element inside a scrolling element, to
598			// include the width of the scrollbar, while other browsers ensure the inner
599			// element is contained without forcing scrolling
600			browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
601	
602			// In rtl text layout, some browsers (most, but not all) will place the
603			// scrollbar on the left, rather than the right.
604			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
605	
606			// IE8- don't provide height and width for getBoundingClientRect
607			browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
608	
609			n.remove();
610		}
611	
612		$.extend( settings.oBrowser, DataTable.__browser );
613		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
614	}
615	
616	
617	/**
618	 * Array.prototype reduce[Right] method, used for browsers which don't support
619	 * JS 1.6. Done this way to reduce code size, since we iterate either way
620	 *  @param {object} settings dataTables settings object
621	 *  @memberof DataTable#oApi
622	 */
623	function _fnReduce ( that, fn, init, start, end, inc )
624	{
625		var
626			i = start,
627			value,
628			isSet = false;
629	
630		if ( init !== undefined ) {
631			value = init;
632			isSet = true;
633		}
634	
635		while ( i !== end ) {
636			if ( ! that.hasOwnProperty(i) ) {
637				continue;
638			}
639	
640			value = isSet ?
641				fn( value, that[i], i, that ) :
642				that[i];
643	
644			isSet = true;
645			i += inc;
646		}
647	
648		return value;
649	}
650	
651	/**
652	 * Add a column to the list used for the table with default values
653	 *  @param {object} oSettings dataTables settings object
654	 *  @param {node} nTh The th element for this column
655	 *  @memberof DataTable#oApi
656	 */
657	function _fnAddColumn( oSettings, nTh )
658	{
659		// Add column to aoColumns array
660		var oDefaults = DataTable.defaults.column;
661		var iCol = oSettings.aoColumns.length;
662		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
663			"nTh": nTh ? nTh : document.createElement('th'),
664			"sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
665			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
666			"mData": oDefaults.mData ? oDefaults.mData : iCol,
667			idx: iCol
668		} );
669		oSettings.aoColumns.push( oCol );
670	
671		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
672		// passed into extend can be undefined. This allows the user to give a default
673		// with only some of the parameters defined, and also not give a default
674		var searchCols = oSettings.aoPreSearchCols;
675		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
676	
677		// Use the default column options function to initialise classes etc
678		_fnColumnOptions( oSettings, iCol, $(nTh).data() );
679	}
680	
681	
682	/**
683	 * Apply options for a column
684	 *  @param {object} oSettings dataTables settings object
685	 *  @param {int} iCol column index to consider
686	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
687	 *  @memberof DataTable#oApi
688	 */
689	function _fnColumnOptions( oSettings, iCol, oOptions )
690	{
691		var oCol = oSettings.aoColumns[ iCol ];
692		var oClasses = oSettings.oClasses;
693		var th = $(oCol.nTh);
694	
695		// Try to get width information from the DOM. We can't get it from CSS
696		// as we'd need to parse the CSS stylesheet. `width` option can override
697		if ( ! oCol.sWidthOrig ) {
698			// Width attribute
699			oCol.sWidthOrig = th.attr('width') || null;
700	
701			// Style attribute
702			var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
703			if ( t ) {
704				oCol.sWidthOrig = t[1];
705			}
706		}
707	
708		/* User specified column options */
709		if ( oOptions !== undefined && oOptions !== null )
710		{
711			// Backwards compatibility
712			_fnCompatCols( oOptions );
713	
714			// Map camel case parameters to their Hungarian counterparts
715			_fnCamelToHungarian( DataTable.defaults.column, oOptions );
716	
717			/* Backwards compatibility for mDataProp */
718			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
719			{
720				oOptions.mData = oOptions.mDataProp;
721			}
722	
723			if ( oOptions.sType )
724			{
725				oCol._sManualType = oOptions.sType;
726			}
727	
728			// `class` is a reserved word in Javascript, so we need to provide
729			// the ability to use a valid name for the camel case input
730			if ( oOptions.className && ! oOptions.sClass )
731			{
732				oOptions.sClass = oOptions.className;
733			}
734	
735			$.extend( oCol, oOptions );
736			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
737	
738			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
739			 * priority if defined
740			 */
741			if ( oOptions.iDataSort !== undefined )
742			{
743				oCol.aDataSort = [ oOptions.iDataSort ];
744			}
745			_fnMap( oCol, oOptions, "aDataSort" );
746		}
747	
748		/* Cache the data get and set functions for speed */
749		var mDataSrc = oCol.mData;
750		var mData = _fnGetObjectDataFn( mDataSrc );
751		var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
752	
753		var attrTest = function( src ) {
754			return typeof src === 'string' && src.indexOf('@') !== -1;
755		};
756		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
757			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
758		);
759		oCol._setter = null;
760	
761		oCol.fnGetData = function (rowData, type, meta) {
762			var innerData = mData( rowData, type, undefined, meta );
763	
764			return mRender && type ?
765				mRender( innerData, type, rowData, meta ) :
766				innerData;
767		};
768		oCol.fnSetData = function ( rowData, val, meta ) {
769			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
770		};
771	
772		// Indicate if DataTables should read DOM data as an object or array
773		// Used in _fnGetRowElements
774		if ( typeof mDataSrc !== 'number' ) {
775			oSettings._rowReadObject = true;
776		}
777	
778		/* Feature sorting overrides column specific when off */
779		if ( !oSettings.oFeatures.bSort )
780		{
781			oCol.bSortable = false;
782			th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
783		}
784	
785		/* Check that the class assignment is correct for sorting */
786		var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
787		var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
788		if ( !oCol.bSortable || (!bAsc && !bDesc) )
789		{
790			oCol.sSortingClass = oClasses.sSortableNone;
791			oCol.sSortingClassJUI = "";
792		}
793		else if ( bAsc && !bDesc )
794		{
795			oCol.sSortingClass = oClasses.sSortableAsc;
796			oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
797		}
798		else if ( !bAsc && bDesc )
799		{
800			oCol.sSortingClass = oClasses.sSortableDesc;
801			oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
802		}
803		else
804		{
805			oCol.sSortingClass = oClasses.sSortable;
806			oCol.sSortingClassJUI = oClasses.sSortJUI;
807		}
808	}
809	
810	
811	/**
812	 * Adjust the table column widths for new data. Note: you would probably want to
813	 * do a redraw after calling this function!
814	 *  @param {object} settings dataTables settings object
815	 *  @memberof DataTable#oApi
816	 */
817	function _fnAdjustColumnSizing ( settings )
818	{
819		/* Not interested in doing column width calculation if auto-width is disabled */
820		if ( settings.oFeatures.bAutoWidth !== false )
821		{
822			var columns = settings.aoColumns;
823	
824			_fnCalculateColumnWidths( settings );
825			for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
826			{
827				columns[i].nTh.style.width = columns[i].sWidth;
828			}
829		}
830	
831		var scroll = settings.oScroll;
832		if ( scroll.sY !== '' || scroll.sX !== '')
833		{
834			_fnScrollDraw( settings );
835		}
836	
837		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
838	}
839	
840	
841	/**
842	 * Covert the index of a visible column to the index in the data array (take account
843	 * of hidden columns)
844	 *  @param {object} oSettings dataTables settings object
845	 *  @param {int} iMatch Visible column index to lookup
846	 *  @returns {int} i the data index
847	 *  @memberof DataTable#oApi
848	 */
849	function _fnVisibleToColumnIndex( oSettings, iMatch )
850	{
851		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
852	
853		return typeof aiVis[iMatch] === 'number' ?
854			aiVis[iMatch] :
855			null;
856	}
857	
858	
859	/**
860	 * Covert the index of an index in the data array and convert it to the visible
861	 *   column index (take account of hidden columns)
862	 *  @param {int} iMatch Column index to lookup
863	 *  @param {object} oSettings dataTables settings object
864	 *  @returns {int} i the data index
865	 *  @memberof DataTable#oApi
866	 */
867	function _fnColumnIndexToVisible( oSettings, iMatch )
868	{
869		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
870		var iPos = $.inArray( iMatch, aiVis );
871	
872		return iPos !== -1 ? iPos : null;
873	}
874	
875	
876	/**
877	 * Get the number of visible columns
878	 *  @param {object} oSettings dataTables settings object
879	 *  @returns {int} i the number of visible columns
880	 *  @memberof DataTable#oApi
881	 */
882	function _fnVisbleColumns( oSettings )
883	{
884		return $( _pluck( oSettings.aoColumns, 'nTh' ) ).filter(':visible').length;
885	}
886	
887	
888	/**
889	 * Get an array of column indexes that match a given property
890	 *  @param {object} oSettings dataTables settings object
891	 *  @param {string} sParam Parameter in aoColumns to look for - typically
892	 *    bVisible or bSearchable
893	 *  @returns {array} Array of indexes with matched properties
894	 *  @memberof DataTable#oApi
895	 */
896	function _fnGetColumns( oSettings, sParam )
897	{
898		var a = [];
899	
900		$.map( oSettings.aoColumns, function(val, i) {
901			if ( val[sParam] ) {
902				a.push( i );
903			}
904		} );
905	
906		return a;
907	}
908	
909	
910	/**
911	 * Calculate the 'type' of a column
912	 *  @param {object} settings dataTables settings object
913	 *  @memberof DataTable#oApi
914	 */
915	function _fnColumnTypes ( settings )
916	{
917		var columns = settings.aoColumns;
918		var data = settings.aoData;
919		var types = DataTable.ext.type.detect;
920		var i, ien, j, jen, k, ken;
921		var col, cell, detectedType, cache;
922	
923		// For each column, spin over the 
924		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
925			col = columns[i];
926			cache = [];
927	
928			if ( ! col.sType && col._sManualType ) {
929				col.sType = col._sManualType;
930			}
931			else if ( ! col.sType ) {
932				for ( j=0, jen=types.length ; j<jen ; j++ ) {
933					for ( k=0, ken=data.length ; k<ken ; k++ ) {
934						// Use a cache array so we only need to get the type data
935						// from the formatter once (when using multiple detectors)
936						if ( cache[k] === undefined ) {
937							cache[k] = _fnGetCellData( settings, k, i, 'type' );
938						}
939	
940						detectedType = types[j]( cache[k], settings );
941	
942						// If null, then this type can't apply to this column, so
943						// rather than testing all cells, break out. There is an
944						// exception for the last type which is `html`. We need to
945						// scan all rows since it is possible to mix string and HTML
946						// types
947						if ( ! detectedType && j !== types.length-1 ) {
948							break;
949						}
950	
951						// Only a single match is needed for html type since it is
952						// bottom of the pile and very similar to string
953						if ( detectedType === 'html' ) {
954							break;
955						}
956					}
957	
958					// Type is valid for all data points in the column - use this
959					// type
960					if ( detectedType ) {
961						col.sType = detectedType;
962						break;
963					}
964				}
965	
966				// Fall back - if no type was detected, always use string
967				if ( ! col.sType ) {
968					col.sType = 'string';
969				}
970			}
971		}
972	}
973	
974	
975	/**
976	 * Take the column definitions and static columns arrays and calculate how
977	 * they relate to column indexes. The callback function will then apply the
978	 * definition found for a column to a suitable configuration object.
979	 *  @param {object} oSettings dataTables settings object
980	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
981	 *  @param {array} aoCols The aoColumns array that defines columns individually
982	 *  @param {function} fn Callback function - takes two parameters, the calculated
983	 *    column index and the definition for that column.
984	 *  @memberof DataTable#oApi
985	 */
986	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
987	{
988		var i, iLen, j, jLen, k, kLen, def;
989		var columns = oSettings.aoColumns;
990	
991		// Column definitions with aTargets
992		if ( aoColDefs )
993		{
994			/* Loop over the definitions array - loop in reverse so first instance has priority */
995			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
996			{
997				def = aoColDefs[i];
998	
999				/* Each definition can target multiple columns, as it is an array */
1000				var aTargets = def.targets !== undefined ?
1001					def.targets :
1002					def.aTargets;
1003	
1004				if ( ! $.isArray( aTargets ) )
1005				{
1006					aTargets = [ aTargets ];
1007				}
1008	
1009				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
1010				{
1011					if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
1012					{
1013						/* Add columns that we don't yet know about */
1014						while( columns.length <= aTargets[j] )
1015						{
1016							_fnAddColumn( oSettings );
1017						}
1018	
1019						/* Integer, basic index */
1020						fn( aTargets[j], def );
1021					}
1022					else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
1023					{
1024						/* Negative integer, right to left column counting */
1025						fn( columns.length+aTargets[j], def );
1026					}
1027					else if ( typeof aTargets[j] === 'string' )
1028					{
1029						/* Class name matching on TH element */
1030						for ( k=0, kLen=columns.length ; k<kLen ; k++ )
1031						{
1032							if ( aTargets[j] == "_all" ||
1033							     $(columns[k].nTh).hasClass( aTargets[j] ) )
1034							{
1035								fn( k, def );
1036							}
1037						}
1038					}
1039				}
1040			}
1041		}
1042	
1043		// Statically defined columns array
1044		if ( aoCols )
1045		{
1046			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
1047			{
1048				fn( i, aoCols[i] );
1049			}
1050		}
1051	}
1052	
1053	/**
1054	 * Add a data array to the table, creating DOM node etc. This is the parallel to
1055	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
1056	 * DOM source.
1057	 *  @param {object} oSettings dataTables settings object
1058	 *  @param {array} aData data array to be added
1059	 *  @param {node} [nTr] TR element to add to the table - optional. If not given,
1060	 *    DataTables will create a row automatically
1061	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
1062	 *    if nTr is.
1063	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
1064	 *  @memberof DataTable#oApi
1065	 */
1066	function _fnAddData ( oSettings, aDataIn, nTr, anTds )
1067	{
1068		/* Create the object for storing information about this new row */
1069		var iRow = oSettings.aoData.length;
1070		var oData = $.extend( true, {}, DataTable.models.oRow, {
1071			src: nTr ? 'dom' : 'data',
1072			idx: iRow
1073		} );
1074	
1075		oData._aData = aDataIn;
1076		oSettings.aoData.push( oData );
1077	
1078		/* Create the cells */
1079		var nTd, sThisType;
1080		var columns = oSettings.aoColumns;
1081	
1082		// Invalidate the column types as the new data needs to be revalidated
1083		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1084		{
1085			columns[i].sType = null;
1086		}
1087	
1088		/* Add to the display array */
1089		oSettings.aiDisplayMaster.push( iRow );
1090	
1091		var id = oSettings.rowIdFn( aDataIn );
1092		if ( id !== undefined ) {
1093			oSettings.aIds[ id ] = oData;
1094		}
1095	
1096		/* Create the DOM information, or register it if already present */
1097		if ( nTr || ! oSettings.oFeatures.bDeferRender )
1098		{
1099			_fnCreateTr( oSettings, iRow, nTr, anTds );
1100		}
1101	
1102		return iRow;
1103	}
1104	
1105	
1106	/**
1107	 * Add one or more TR elements to the table. Generally we'd expect to
1108	 * use this for reading data from a DOM sourced table, but it could be
1109	 * used for an TR element. Note that if a TR is given, it is used (i.e.
1110	 * it is not cloned).
1111	 *  @param {object} settings dataTables settings object
1112	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
1113	 *  @returns {array} Array of indexes for the added rows
1114	 *  @memberof DataTable#oApi
1115	 */
1116	function _fnAddTr( settings, trs )
1117	{
1118		var row;
1119	
1120		// Allow an individual node to be passed in
1121		if ( ! (trs instanceof $) ) {
1122			trs = $(trs);
1123		}
1124	
1125		return trs.map( function (i, el) {
1126			row = _fnGetRowElements( settings, el );
1127			return _fnAddData( settings, row.data, el, row.cells );
1128		} );
1129	}
1130	
1131	
1132	/**
1133	 * Take a TR element and convert it to an index in aoData
1134	 *  @param {object} oSettings dataTables settings object
1135	 *  @param {node} n the TR element to find
1136	 *  @returns {int} index if the node is found, null if not
1137	 *  @memberof DataTable#oApi
1138	 */
1139	function _fnNodeToDataIndex( oSettings, n )
1140	{
1141		return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1142	}
1143	
1144	
1145	/**
1146	 * Take a TD element and convert it into a column data index (not the visible index)
1147	 *  @param {object} oSettings dataTables settings object
1148	 *  @param {int} iRow The row number the TD/TH can be found in
1149	 *  @param {node} n The TD/TH element to find
1150	 *  @returns {int} index if the node is found, -1 if not
1151	 *  @memberof DataTable#oApi
1152	 */
1153	function _fnNodeToColumnIndex( oSettings, iRow, n )
1154	{
1155		return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1156	}
1157	
1158	
1159	/**
1160	 * Get the data for a given cell from the internal cache, taking into account data mapping
1161	 *  @param {object} settings dataTables settings object
1162	 *  @param {int} rowIdx aoData row id
1163	 *  @param {int} colIdx Column index
1164	 *  @param {string} type data get type ('display', 'type' 'filter' 'sort')
1165	 *  @returns {*} Cell data
1166	 *  @memberof DataTable#oApi
1167	 */
1168	function _fnGetCellData( settings, rowIdx, colIdx, type )
1169	{
1170		var draw           = settings.iDraw;
1171		var col            = settings.aoColumns[colIdx];
1172		var rowData        = settings.aoData[rowIdx]._aData;
1173		var defaultContent = col.sDefaultContent;
1174		var cellData       = col.fnGetData( rowData, type, {
1175			settings: settings,
1176			row:      rowIdx,
1177			col:      colIdx
1178		} );
1179	
1180		if ( cellData === undefined ) {
1181			if ( settings.iDrawError != draw && defaultContent === null ) {
1182				_fnLog( settings, 0, "Requested unknown parameter "+
1183					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1184					" for row "+rowIdx+", column "+colIdx, 4 );
1185				settings.iDrawError = draw;
1186			}
1187			return defaultContent;
1188		}
1189	
1190		// When the data source is null and a specific data type is requested (i.e.
1191		// not the original data), we can use default column data
1192		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
1193			cellData = defaultContent;
1194		}
1195		else if ( typeof cellData === 'function' ) {
1196			// If the data source is a function, then we run it and use the return,
1197			// executing in the scope of the data object (for instances)
1198			return cellData.call( rowData );
1199		}
1200	
1201		if ( cellData === null && type == 'display' ) {
1202			return '';
1203		}
1204		return cellData;
1205	}
1206	
1207	
1208	/**
1209	 * Set the value for a specific cell, into the internal data cache
1210	 *  @param {object} settings dataTables settings object
1211	 *  @param {int} rowIdx aoData row id
1212	 *  @param {int} colIdx Column index
1213	 *  @param {*} val Value to set
1214	 *  @memberof DataTable#oApi
1215	 */
1216	function _fnSetCellData( settings, rowIdx, colIdx, val )
1217	{
1218		var col     = settings.aoColumns[colIdx];
1219		var rowData = settings.aoData[rowIdx]._aData;
1220	
1221		col.fnSetData( rowData, val, {
1222			settings: settings,
1223			row:      rowIdx,
1224			col:      colIdx
1225		}  );
1226	}
1227	
1228	
1229	// Private variable that is used to match action syntax in the data property object
1230	var __reArray = /\[.*?\]$/;
1231	var __reFn = /\(\)$/;
1232	
1233	/**
1234	 * Split string on periods, taking into account escaped periods
1235	 * @param  {string} str String to split
1236	 * @return {array} Split string
1237	 */
1238	function _fnSplitObjNotation( str )
1239	{
1240		return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
1241			return s.replace(/\\./g, '.');
1242		} );
1243	}
1244	
1245	
1246	/**
1247	 * Return a function that can be used to get data from a source object, taking
1248	 * into account the ability to use nested objects as a source
1249	 *  @param {string|int|function} mSource The data source for the object
1250	 *  @returns {function} Data get function
1251	 *  @memberof DataTable#oApi
1252	 */
1253	function _fnGetObjectDataFn( mSource )
1254	{
1255		if ( $.isPlainObject( mSource ) )
1256		{
1257			/* Build an object of get functions, and wrap them in a single call */
1258			var o = {};
1259			$.each( mSource, function (key, val) {
1260				if ( val ) {
1261					o[key] = _fnGetObjectDataFn( val );
1262				}
1263			} );
1264	
1265			return function (data, type, row, meta) {
1266				var t = o[type] || o._;
1267				return t !== undefined ?
1268					t(data, type, row, meta) :
1269					data;
1270			};
1271		}
1272		else if ( mSource === null )
1273		{
1274			/* Give an empty string for rendering / sorting etc */
1275			return function (data) { // type, row and meta also passed, but not used
1276				return data;
1277			};
1278		}
1279		else if ( typeof mSource === 'function' )
1280		{
1281			return function (data, type, row, meta) {
1282				return mSource( data, type, row, meta );
1283			};
1284		}
1285		else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1286			      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1287		{
1288			/* If there is a . in the source string then the data source is in a
1289			 * nested object so we loop over the data for each level to get the next
1290			 * level down. On each loop we test for undefined, and if found immediately
1291			 * return. This allows entire objects to be missing and sDefaultContent to
1292			 * be used if defined, rather than throwing an error
1293			 */
1294			var fetchData = function (data, type, src) {
1295				var arrayNotation, funcNotation, out, innerSrc;
1296	
1297				if ( src !== "" )
1298				{
1299					var a = _fnSplitObjNotation( src );
1300	
1301					for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1302					{
1303						// Check if we are dealing with special notation
1304						arrayNotation = a[i].match(__reArray);
1305						funcNotation = a[i].match(__reFn);
1306	
1307						if ( arrayNotation )
1308						{
1309							// Array notation
1310							a[i] = a[i].replace(__reArray, '');
1311	
1312							// Condition allows simply [] to be passed in
1313							if ( a[i] !== "" ) {
1314								data = data[ a[i] ];
1315							}
1316							out = [];
1317	
1318							// Get the remainder of the nested object to get
1319							a.splice( 0, i+1 );
1320							innerSrc = a.join('.');
1321	
1322							// Traverse each entry in the array getting the properties requested
1323							if ( $.isArray( data ) ) {
1324								for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1325									out.push( fetchData( data[j], type, innerSrc ) );
1326								}
1327							}
1328	
1329							// If a string is given in between the array notation indicators, that
1330							// is used to join the strings together, otherwise an array is returned
1331							var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1332							data = (join==="") ? out : out.join(join);
1333	
1334							// The inner call to fetchData has already traversed through the remainder
1335							// of the source requested, so we exit from the loop
1336							break;
1337						}
1338						else if ( funcNotation )
1339						{
1340							// Function call
1341							a[i] = a[i].replace(__reFn, '');
1342							data = data[ a[i] ]();
1343							continue;
1344						}
1345	
1346						if ( data === null || data[ a[i] ] === undefined )
1347						{
1348							return undefined;
1349						}
1350						data = data[ a[i] ];
1351					}
1352				}
1353	
1354				return data;
1355			};
1356	
1357			return function (data, type) { // row and meta also passed, but not used
1358				return fetchData( data, type, mSource );
1359			};
1360		}
1361		else
1362		{
1363			/* Array or flat object mapping */
1364			return function (data, type) { // row and meta also passed, but not used
1365				return data[mSource];
1366			};
1367		}
1368	}
1369	
1370	
1371	/**
1372	 * Return a function that can be used to set data from a source object, taking
1373	 * into account the ability to use nested objects as a source
1374	 *  @param {string|int|function} mSource The data source for the object
1375	 *  @returns {function} Data set function
1376	 *  @memberof DataTable#oApi
1377	 */
1378	function _fnSetObjectDataFn( mSource )
1379	{
1380		if ( $.isPlainObject( mSource ) )
1381		{
1382			/* Unlike get, only the underscore (global) option is used for for
1383			 * setting data since we don't know the type here. This is why an object
1384			 * option is not documented for `mData` (which is read/write), but it is
1385			 * for `mRender` which is read only.
1386			 */
1387			return _fnSetObjectDataFn( mSource._ );
1388		}
1389		else if ( mSource === null )
1390		{
1391			/* Nothing to do when the data source is null */
1392			return function () {};
1393		}
1394		else if ( typeof mSource === 'function' )
1395		{
1396			return function (data, val, meta) {
1397				mSource( data, 'set', val, meta );
1398			};
1399		}
1400		else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1401			      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1402		{
1403			/* Like the get, we need to get data from a nested object */
1404			var setData = function (data, val, src) {
1405				var a = _fnSplitObjNotation( src ), b;
1406				var aLast = a[a.length-1];
1407				var arrayNotation, funcNotation, o, innerSrc;
1408	
1409				for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1410				{
1411					// Check if we are dealing with an array notation request
1412					arrayNotation = a[i].match(__reArray);
1413					funcNotation = a[i].match(__reFn);
1414	
1415					if ( arrayNotation )
1416					{
1417						a[i] = a[i].replace(__reArray, '');
1418						data[ a[i] ] = [];
1419	
1420						// Get the remainder of the nested object to set so we can recurse
1421						b = a.slice();
1422						b.splice( 0, i+1 );
1423						innerSrc = b.join('.');
1424	
1425						// Traverse each entry in the array setting the properties requested
1426						if ( $.isArray( val ) )
1427						{
1428							for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1429							{
1430								o = {};
1431								setData( o, val[j], innerSrc );
1432								data[ a[i] ].push( o );
1433							}
1434						}
1435						else
1436						{
1437							// We've been asked to save data to an array, but it
1438							// isn't array data to be saved. Best that can be done
1439							// is to just save the value.
1440							data[ a[i] ] = val;
1441						}
1442	
1443						// The inner call to setData has already traversed through the remainder
1444						// of the source and has set the data, thus we can exit here
1445						return;
1446					}
1447					else if ( funcNotation )
1448					{
1449						// Function call
1450						a[i] = a[i].replace(__reFn, '');
1451						data = data[ a[i] ]( val );
1452					}
1453	
1454					// If the nested object doesn't currently exist - since we are
1455					// trying to set the value - create it
1456					if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1457					{
1458						data[ a[i] ] = {};
1459					}
1460					data = data[ a[i] ];
1461				}
1462	
1463				// Last item in the input - i.e, the actual set
1464				if ( aLast.match(__reFn ) )
1465				{
1466					// Function call
1467					data = data[ aLast.replace(__reFn, '') ]( val );
1468				}
1469				else
1470				{
1471					// If array notation is used, we just want to strip it and use the property name
1472					// and assign the value. If it isn't used, then we get the result we want anyway
1473					data[ aLast.replace(__reArray, '') ] = val;
1474				}
1475			};
1476	
1477			return function (data, val) { // meta is also passed in, but not used
1478				return setData( data, val, mSource );
1479			};
1480		}
1481		else
1482		{
1483			/* Array or flat object mapping */
1484			return function (data, val) { // meta is also passed in, but not used
1485				data[mSource] = val;
1486			};
1487		}
1488	}
1489	
1490	
1491	/**
1492	 * Return an array with the full table data
1493	 *  @param {object} oSettings dataTables settings object
1494	 *  @returns array {array} aData Master data array
1495	 *  @memberof DataTable#oApi
1496	 */
1497	function _fnGetDataMaster ( settings )
1498	{
1499		return _pluck( settings.aoData, '_aData' );
1500	}
1501	
1502	
1503	/**
1504	 * Nuke the table
1505	 *  @param {object} oSettings dataTables settings object
1506	 *  @memberof DataTable#oApi
1507	 */
1508	function _fnClearTable( settings )
1509	{
1510		settings.aoData.length = 0;
1511		settings.aiDisplayMaster.length = 0;
1512		settings.aiDisplay.length = 0;
1513		settings.aIds = {};
1514	}
1515	
1516	
1517	 /**
1518	 * Take an array of integers (index array) and remove a target integer (value - not
1519	 * the key!)
1520	 *  @param {array} a Index array to target
1521	 *  @param {int} iTarget value to find
1522	 *  @memberof DataTable#oApi
1523	 */
1524	function _fnDeleteIndex( a, iTarget, splice )
1525	{
1526		var iTargetIndex = -1;
1527	
1528		for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1529		{
1530			if ( a[i] == iTarget )
1531			{
1532				iTargetIndex = i;
1533			}
1534			else if ( a[i] > iTarget )
1535			{
1536				a[i]--;
1537			}
1538		}
1539	
1540		if ( iTargetIndex != -1 && splice === undefined )
1541		{
1542			a.splice( iTargetIndex, 1 );
1543		}
1544	}
1545	
1546	
1547	/**
1548	 * Mark cached data as invalid such that a re-read of the data will occur when
1549	 * the cached data is next requested. Also update from the data source object.
1550	 *
1551	 * @param {object} settings DataTables settings object
1552	 * @param {int}    rowIdx   Row index to invalidate
1553	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
1554	 *     or 'data'
1555	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
1556	 *     row will be invalidated
1557	 * @memberof DataTable#oApi
1558	 *
1559	 * @todo For the modularisation of v1.11 this will need to become a callback, so
1560	 *   the sort and filter methods can subscribe to it. That will required
1561	 *   initialisation options for sorting, which is why it is not already baked in
1562	 */
1563	function _fnInvalidate( settings, rowIdx, src, colIdx )
1564	{
1565		var row = settings.aoData[ rowIdx ];
1566		var i, ien;
1567		var cellWrite = function ( cell, col ) {
1568			// This is very frustrating, but in IE if you just write directly
1569			// to innerHTML, and elements that are overwritten are GC'ed,
1570			// even if there is a reference to them elsewhere
1571			while ( cell.childNodes.length ) {
1572				cell.removeChild( cell.firstChild );
1573			}
1574	
1575			cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1576		};
1577	
1578		// Are we reading last data from DOM or the data object?
1579		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1580			// Read the data from the DOM
1581			row._aData = _fnGetRowElements(
1582					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1583				)
1584				.data;
1585		}
1586		else {
1587			// Reading from data object, update the DOM
1588			var cells = row.anCells;
1589	
1590			if ( cells ) {
1591				if ( colIdx !== undefined ) {
1592					cellWrite( cells[colIdx], colIdx );
1593				}
1594				else {
1595					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1596						cellWrite( cells[i], i );
1597					}
1598				}
1599			}
1600		}
1601	
1602		// For both row and cell invalidation, the cached data for sorting and
1603		// filtering is nulled out
1604		row._aSortData = null;
1605		row._aFilterData = null;
1606	
1607		// Invalidate the type for a specific column (if given) or all columns since
1608		// the data might have changed
1609		var cols = settings.aoColumns;
1610		if ( colIdx !== undefined ) {
1611			cols[ colIdx ].sType = null;
1612		}
1613		else {
1614			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1615				cols[i].sType = null;
1616			}
1617	
1618			// Update DataTables special `DT_*` attributes for the row
1619			_fnRowAttributes( settings, row );
1620		}
1621	}
1622	
1623	
1624	/**
1625	 * Build a data source object from an HTML row, reading the contents of the
1626	 * cells that are in the row.
1627	 *
1628	 * @param {object} settings DataTables settings object
1629	 * @param {node|object} TR element from which to read data or existing row
1630	 *   object from which to re-read the data from the cells
1631	 * @param {int} [colIdx] Optional column index
1632	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
1633	 *   parameter should also be given and will be used to write the data into.
1634	 *   Only the column in question will be written
1635	 * @returns {object} Object with two parameters: `data` the data read, in
1636	 *   document order, and `cells` and array of nodes (they can be useful to the
1637	 *   caller, so rather than needing a second traversal to get them, just return
1638	 *   them from here).
1639	 * @memberof DataTable#oApi
1640	 */
1641	function _fnGetRowElements( settings, row, colIdx, d )
1642	{
1643		var
1644			tds = [],
1645			td = row.firstChild,
1646			name, col, o, i=0, contents,
1647			columns = settings.aoColumns,
1648			objectRead = settings._rowReadObject;
1649	
1650		// Allow the data object to be passed in, or construct
1651		d = d !== undefined ?
1652			d :
1653			objectRead ?
1654				{} :
1655				[];
1656	
1657		var attr = function ( str, td  ) {
1658			if ( typeof str === 'string' ) {
1659				var idx = str.indexOf('@');
1660	
1661				if ( idx !== -1 ) {
1662					var attr = str.substring( idx+1 );
1663					var setter = _fnSetObjectDataFn( str );
1664					setter( d, td.getAttribute( attr ) );
1665				}
1666			}
1667		};
1668	
1669		// Read data from a cell and store into the data object
1670		var cellProcess = function ( cell ) {
1671			if ( colIdx === undefined || colIdx === i ) {
1672				col = columns[i];
1673				contents = $.trim(cell.innerHTML);
1674	
1675				if ( col && col._bAttrSrc ) {
1676					var setter = _fnSetObjectDataFn( col.mData._ );
1677					setter( d, contents );
1678	
1679					attr( col.mData.sort, cell );
1680					attr( col.mData.type, cell );
1681					attr( col.mData.filter, cell );
1682				}
1683				else {
1684					// Depending on the `data` option for the columns the data can
1685					// be read to either an object or an array.
1686					if ( objectRead ) {
1687						if ( ! col._setter ) {
1688							// Cache the setter function
1689							col._setter = _fnSetObjectDataFn( col.mData );
1690						}
1691						col._setter( d, contents );
1692					}
1693					else {
1694						d[i] = contents;
1695					}
1696				}
1697			}
1698	
1699			i++;
1700		};
1701	
1702		if ( td ) {
1703			// `tr` element was passed in
1704			while ( td ) {
1705				name = td.nodeName.toUpperCase();
1706	
1707				if ( name == "TD" || name == "TH" ) {
1708					cellProcess( td );
1709					tds.push( td );
1710				}
1711	
1712				td = td.nextSibling;
1713			}
1714		}
1715		else {
1716			// Existing row object passed in
1717			tds = row.anCells;
1718	
1719			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1720				cellProcess( tds[j] );
1721			}
1722		}
1723	
1724		// Read the ID from the DOM if present
1725		var rowNode = row.firstChild ? row : row.nTr;
1726	
1727		if ( rowNode ) {
1728			var id = rowNode.getAttribute( 'id' );
1729	
1730			if ( id ) {
1731				_fnSetObjectDataFn( settings.rowId )( d, id );
1732			}
1733		}
1734	
1735		return {
1736			data: d,
1737			cells: tds
1738		};
1739	}
1740	/**
1741	 * Create a new TR element (and it's TD children) for a row
1742	 *  @param {object} oSettings dataTables settings object
1743	 *  @param {int} iRow Row to consider
1744	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1745	 *    DataTables will create a row automatically
1746	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
1747	 *    if nTr is.
1748	 *  @memberof DataTable#oApi
1749	 */
1750	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1751	{
1752		var
1753			row = oSettings.aoData[iRow],
1754			rowData = row._aData,
1755			cells = [],
1756			nTr, nTd, oCol,
1757			i, iLen;
1758	
1759		if ( row.nTr === null )
1760		{
1761			nTr = nTrIn || document.createElement('tr');
1762	
1763			row.nTr = nTr;
1764			row.anCells = cells;
1765	
1766			/* Use a private property on the node to allow reserve mapping from the node
1767			 * to the aoData array for fast look up
1768			 */
1769			nTr._DT_RowIndex = iRow;
1770	
1771			/* Special parameters can be given by the data source to be used on the row */
1772			_fnRowAttributes( oSettings, row );
1773	
1774			/* Process each column */
1775			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1776			{
1777				oCol = oSettings.aoColumns[i];
1778	
1779				nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1780				nTd._DT_CellIndex = {
1781					row: iRow,
1782					column: i
1783				};
1784				
1785				cells.push( nTd );
1786	
1787				// Need to create the HTML if new, or if a rendering function is defined
1788				if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
1789					 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
1790				) {
1791					nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1792				}
1793	
1794				/* Add user defined class */
1795				if ( oCol.sClass )
1796				{
1797					nTd.className += ' '+oCol.sClass;
1798				}
1799	
1800				// Visibility - add or remove as required
1801				if ( oCol.bVisible && ! nTrIn )
1802				{
1803					nTr.appendChild( nTd );
1804				}
1805				else if ( ! oCol.bVisible && nTrIn )
1806				{
1807					nTd.parentNode.removeChild( nTd );
1808				}
1809	
1810				if ( oCol.fnCreatedCell )
1811				{
1812					oCol.fnCreatedCell.call( oSettings.oInstance,
1813						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1814					);
1815				}
1816			}
1817	
1818			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1819		}
1820	
1821		// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1822		// and deployed
1823		row.nTr.setAttribute( 'role', 'row' );
1824	}
1825	
1826	
1827	/**
1828	 * Add attributes to a row based on the special `DT_*` parameters in a data
1829	 * source object.
1830	 *  @param {object} settings DataTables settings object
1831	 *  @param {object} DataTables row object for the row to be modified
1832	 *  @memberof DataTable#oApi
1833	 */
1834	function _fnRowAttributes( settings, row )
1835	{
1836		var tr = row.nTr;
1837		var data = row._aData;
1838	
1839		if ( tr ) {
1840			var id = settings.rowIdFn( data );
1841	
1842			if ( id ) {
1843				tr.id = id;
1844			}
1845	
1846			if ( data.DT_RowClass ) {
1847				// Remove any classes added by DT_RowClass before
1848				var a = data.DT_RowClass.split(' ');
1849				row.__rowc = row.__rowc ?
1850					_unique( row.__rowc.concat( a ) ) :
1851					a;
1852	
1853				$(tr)
1854					.removeClass( row.__rowc.join(' ') )
1855					.addClass( data.DT_RowClass );
1856			}
1857	
1858			if ( data.DT_RowAttr ) {
1859				$(tr).attr( data.DT_RowAttr );
1860			}
1861	
1862			if ( data.DT_RowData ) {
1863				$(tr).data( data.DT_RowData );
1864			}
1865		}
1866	}
1867	
1868	
1869	/**
1870	 * Create the HTML header for the table
1871	 *  @param {object} oSettings dataTables settings object
1872	 *  @memberof DataTable#oApi
1873	 */
1874	function _fnBuildHead( oSettings )
1875	{
1876		var i, ien, cell, row, column;
1877		var thead = oSettings.nTHead;
1878		var tfoot = oSettings.nTFoot;
1879		var createHeader = $('th, td', thead).length === 0;
1880		var classes = oSettings.oClasses;
1881		var columns = oSettings.aoColumns;
1882	
1883		if ( createHeader ) {
1884			row = $('<tr/>').appendTo( thead );
1885		}
1886	
1887		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1888			column = columns[i];
1889			cell = $( column.nTh ).addClass( column.sClass );
1890	
1891			if ( createHeader ) {
1892				cell.appendTo( row );
1893			}
1894	
1895			// 1.11 move into sorting
1896			if ( oSettings.oFeatures.bSort ) {
1897				cell.addClass( column.sSortingClass );
1898	
1899				if ( column.bSortable !== false ) {
1900					cell
1901						.attr( 'tabindex', oSettings.iTabIndex )
1902						.attr( 'aria-controls', oSettings.sTableId );
1903	
1904					_fnSortAttachListener( oSettings, column.nTh, i );
1905				}
1906			}
1907	
1908			if ( column.sTitle != cell[0].innerHTML ) {
1909				cell.html( column.sTitle );
1910			}
1911	
1912			_fnRenderer( oSettings, 'header' )(
1913				oSettings, cell, column, classes
1914			);
1915		}
1916	
1917		if ( createHeader ) {
1918			_fnDetectHeader( oSettings.aoHeader, thead );
1919		}
1920		
1921		/* ARIA role for the rows */
1922	 	$(thead).find('>tr').attr('role', 'row');
1923	
1924		/* Deal with the footer - add classes if required */
1925		$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1926		$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1927	
1928		// Cache the footer cells. Note that we only take the cells from the first
1929		// row in the footer. If there is more than one row the user wants to
1930		// interact with, they need to use the table().foot() method. Note also this
1931		// allows cells to be used for multiple columns using colspan
1932		if ( tfoot !== null ) {
1933			var cells = oSettings.aoFooter[0];
1934	
1935			for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1936				column = columns[i];
1937				column.nTf = cells[i].cell;
1938	
1939				if ( column.sClass ) {
1940					$(column.nTf).addClass( column.sClass );
1941				}
1942			}
1943		}
1944	}
1945	
1946	
1947	/**
1948	 * Draw the header (or footer) element based on the column visibility states. The
1949	 * methodology here is to use the layout array from _fnDetectHeader, modified for
1950	 * the instantaneous column visibility, to construct the new layout. The grid is
1951	 * traversed over cell at a time in a rows x columns grid fashion, although each
1952	 * cell insert can cover multiple elements in the grid - which is tracks using the
1953	 * aApplied array. Cell inserts in the grid will only occur where there isn't
1954	 * already a cell in that position.
1955	 *  @param {object} oSettings dataTables settings object
1956	 *  @param array {objects} aoSource Layout array from _fnDetectHeader
1957	 *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1958	 *  @memberof DataTable#oApi
1959	 */
1960	function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1961	{
1962		var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1963		var aoLocal = [];
1964		var aApplied = [];
1965		var iColumns = oSettings.aoColumns.length;
1966		var iRowspan, iColspan;
1967	
1968		if ( ! aoSource )
1969		{
1970			return;
1971		}
1972	
1973		if (  bIncludeHidden === undefined )
1974		{
1975			bIncludeHidden = false;
1976		}
1977	
1978		/* Make a copy of the master layout array, but without the visible columns in it */
1979		for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1980		{
1981			aoLocal[i] = aoSource[i].slice();
1982			aoLocal[i].nTr = aoSource[i].nTr;
1983	
1984			/* Remove any columns which are currently hidden */
1985			for ( j=iColumns-1 ; j>=0 ; j-- )
1986			{
1987				if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1988				{
1989					aoLocal[i].splice( j, 1 );
1990				}
1991			}
1992	
1993			/* Prep the applied array - it needs an element for each row */
1994			aApplied.push( [] );
1995		}
1996	
1997		for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1998		{
1999			nLocalTr = aoLocal[i].nTr;
2000	
2001			/* All cells are going to be replaced, so empty out the row */
2002			if ( nLocalTr )
2003			{
2004				while( (n = nLocalTr.firstChild) )
2005				{
2006					nLocalTr.removeChild( n );
2007				}
2008			}
2009	
2010			for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
2011			{
2012				iRowspan = 1;
2013				iColspan = 1;
2014	
2015				/* Check to see if there is already a cell (row/colspan) covering our target
2016				 * insert point. If there is, then there is nothing to do.
2017				 */
2018				if ( aApplied[i][j] === undefined )
2019				{
2020					nLocalTr.appendChild( aoLocal[i][j].cell );
2021					aApplied[i][j] = 1;
2022	
2023					/* Expand the cell to cover as many rows as needed */
2024					while ( aoLocal[i+iRowspan] !== undefined &&
2025					        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
2026					{
2027						aApplied[i+iRowspan][j] = 1;
2028						iRowspan++;
2029					}
2030	
2031					/* Expand the cell to cover as many columns as needed */
2032					while ( aoLocal[i][j+iColspan] !== undefined &&
2033					        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
2034					{
2035						/* Must update the applied array over the rows for the columns */
2036						for ( k=0 ; k<iRowspan ; k++ )
2037						{
2038							aApplied[i+k][j+iColspan] = 1;
2039						}
2040						iColspan++;
2041					}
2042	
2043					/* Do the actual expansion in the DOM */
2044					$(aoLocal[i][j].cell)
2045						.attr('rowspan', iRowspan)
2046						.attr('colspan', iColspan);
2047				}
2048			}
2049		}
2050	}
2051	
2052	
2053	/**
2054	 * Insert the required TR nodes into the table for display
2055	 *  @param {object} oSettings dataTables settings object
2056	 *  @memberof DataTable#oApi
2057	 */
2058	function _fnDraw( oSettings )
2059	{
2060		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
2061		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
2062		if ( $.inArray( false, aPreDraw ) !== -1 )
2063		{
2064			_fnProcessingDisplay( oSettings, false );
2065			return;
2066		}
2067	
2068		var i, iLen, n;
2069		var anRows = [];
2070		var iRowCount = 0;
2071		var asStripeClasses = oSettings.asStripeClasses;
2072		var iStripes = asStripeClasses.length;
2073		var iOpenRows = oSettings.aoOpenRows.length;
2074		var oLang = oSettings.oLanguage;
2075		var iInitDisplayStart = oSettings.iInitDisplayStart;
2076		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
2077		var aiDisplay = oSettings.aiDisplay;
2078	
2079		oSettings.bDrawing = true;
2080	
2081		/* Check and see if we have an initial draw position from state saving */
2082		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
2083		{
2084			oSettings._iDisplayStart = bServerSide ?
2085				iInitDisplayStart :
2086				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
2087					0 :
2088					iInitDisplayStart;
2089	
2090			oSettings.iInitDisplayStart = -1;
2091		}
2092	
2093		var iDisplayStart = oSettings._iDisplayStart;
2094		var iDisplayEnd = oSettings.fnDisplayEnd();
2095	
2096		/* Server-side processing draw intercept */
2097		if ( oSettings.bDeferLoading )
2098		{
2099			oSettings.bDeferLoading = false;
2100			oSettings.iDraw++;
2101			_fnProcessingDisplay( oSettings, false );
2102		}
2103		else if ( !bServerSide )
2104		{
2105			oSettings.iDraw++;
2106		}
2107		else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
2108		{
2109			return;
2110		}
2111	
2112		if ( aiDisplay.length !== 0 )
2113		{
2114			var iStart = bServerSide ? 0 : iDisplayStart;
2115			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
2116	
2117			for ( var j=iStart ; j<iEnd ; j++ )
2118			{
2119				var iDataIndex = aiDisplay[j];
2120				var aoData = oSettings.aoData[ iDataIndex ];
2121				if ( aoData.nTr === null )
2122				{
2123					_fnCreateTr( oSettings, iDataIndex );
2124				}
2125	
2126				var nRow = aoData.nTr;
2127	
2128				/* Remove the old striping classes and then add the new one */
2129				if ( iStripes !== 0 )
2130				{
2131					var sStripe = asStripeClasses[ iRowCount % iStripes ];
2132					if ( aoData._sRowStripe != sStripe )
2133					{
2134						$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
2135						aoData._sRowStripe = sStripe;
2136					}
2137				}
2138	
2139				// Row callback functions - might want to manipulate the row
2140				// iRowCount and j are not currently documented. Are they at all
2141				// useful?
2142				_fnCallbackFire( oSettings, 'aoRowCallback', null,
2143					[nRow, aoData._aData, iRowCount, j] );
2144	
2145				anRows.push( nRow );
2146				iRowCount++;
2147			}
2148		}
2149		else
2150		{
2151			/* Table is empty - create a row with an empty message in it */
2152			var sZero = oLang.sZeroRecords;
2153			if ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )
2154			{
2155				sZero = oLang.sLoadingRecords;
2156			}
2157			else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
2158			{
2159				sZero = oLang.sEmptyTable;
2160			}
2161	
2162			anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
2163				.append( $('<td />', {
2164					'valign':  'top',
2165					'colSpan': _fnVisbleColumns( oSettings ),
2166					'class':   oSettings.oClasses.sRowEmpty
2167				} ).html( sZero ) )[0];
2168		}
2169	
2170		/* Header and footer callbacks */
2171		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
2172			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2173	
2174		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
2175			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2176	
2177		var body = $(oSettings.nTBody);
2178	
2179		body.children().detach();
2180		body.append( $(anRows) );
2181	
2182		/* Call all required callback functions for the end of a draw */
2183		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
2184	
2185		/* Draw is complete, sorting and filtering must be as well */
2186		oSettings.bSorted = false;
2187		oSettings.bFiltered = false;
2188		oSettings.bDrawing = false;
2189	}
2190	
2191	
2192	/**
2193	 * Redraw the table - taking account of the various features which are enabled
2194	 *  @param {object} oSettings dataTables settings object
2195	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
2196	 *    the paging is reset to the first page
2197	 *  @memberof DataTable#oApi
2198	 */
2199	function _fnReDraw( settings, holdPosition )
2200	{
2201		var
2202			features = settings.oFeatures,
2203			sort     = features.bSort,
2204			filter   = features.bFilter;
2205	
2206		if ( sort ) {
2207			_fnSort( settings );
2208		}
2209	
2210		if ( filter ) {
2211			_fnFilterComplete( settings, settings.oPreviousSearch );
2212		}
2213		else {
2214			// No filtering, so we want to just use the display master
2215			settings.aiDisplay = settings.aiDisplayMaster.slice();
2216		}
2217	
2218		if ( holdPosition !== true ) {
2219			settings._iDisplayStart = 0;
2220		}
2221	
2222		// Let any modules know about the draw hold position state (used by
2223		// scrolling internally)
2224		settings._drawHold = holdPosition;
2225	
2226		_fnDraw( settings );
2227	
2228		settings._drawHold = false;
2229	}
2230	
2231	
2232	/**
2233	 * Add the options to the page HTML for the table
2234	 *  @param {object} oSettings dataTables settings object
2235	 *  @memberof DataTable#oApi
2236	 */
2237	function _fnAddOptionsHtml ( oSettings )
2238	{
2239		var classes = oSettings.oClasses;
2240		var table = $(oSettings.nTable);
2241		var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2242		var features = oSettings.oFeatures;
2243	
2244		// All DataTables are wrapped in a div
2245		var insert = $('<div/>', {
2246			id:      oSettings.sTableId+'_wrapper',
2247			'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2248		} );
2249	
2250		oSettings.nHolding = holding[0];
2251		oSettings.nTableWrapper = insert[0];
2252		oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2253	
2254		/* Loop over the user set positioning and place the elements as needed */
2255		var aDom = oSettings.sDom.split('');
2256		var featureNode, cOption, nNewNode, cNext, sAttr, j;
2257		for ( var i=0 ; i<aDom.length ; i++ )
2258		{
2259			featureNode = null;
2260			cOption = aDom[i];
2261	
2262			if ( cOption == '<' )
2263			{
2264				/* New container div */
2265				nNewNode = $('<div/>')[0];
2266	
2267				/* Check to see if we should append an id and/or a class name to the container */
2268				cNext = aDom[i+1];
2269				if ( cNext == "'" || cNext == '"' )
2270				{
2271					sAttr = "";
2272					j = 2;
2273					while ( aDom[i+j] != cNext )
2274					{
2275						sAttr += aDom[i+j];
2276						j++;
2277					}
2278	
2279					/* Replace jQuery UI constants @todo depreciated */
2280					if ( sAttr == "H" )
2281					{
2282						sAttr = classes.sJUIHeader;
2283					}
2284					else if ( sAttr == "F" )
2285					{
2286						sAttr = classes.sJUIFooter;
2287					}
2288	
2289					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2290					 * breaks the string into parts and applies them as needed
2291					 */
2292					if ( sAttr.indexOf('.') != -1 )
2293					{
2294						var aSplit = sAttr.split('.');
2295						nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2296						nNewNode.className = aSplit[1];
2297					}
2298					else if ( sAttr.charAt(0) == "#" )
2299					{
2300						nNewNode.id = sAttr.substr(1, sAttr.length-1);
2301					}
2302					else
2303					{
2304						nNewNode.className = sAttr;
2305					}
2306	
2307					i += j; /* Move along the position array */
2308				}
2309	
2310				insert.append( nNewNode );
2311				insert = $(nNewNode);
2312			}
2313			else if ( cOption == '>' )
2314			{
2315				/* End container div */
2316				insert = insert.parent();
2317			}
2318			// @todo Move options into their own plugins?
2319			else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2320			{
2321				/* Length */
2322				featureNode = _fnFeatureHtmlLength( oSettings );
2323			}
2324			else if ( cOption == 'f' && features.bFilter )
2325			{
2326				/* Filter */
2327				featureNode = _fnFeatureHtmlFilter( oSettings );
2328			}
2329			else if ( cOption == 'r' && features.bProcessing )
2330			{
2331				/* pRocessing */
2332				featureNode = _fnFeatureHtmlProcessing( oSettings );
2333			}
2334			else if ( cOption == 't' )
2335			{
2336				/* Table */
2337				featureNode = _fnFeatureHtmlTable( oSettings );
2338			}
2339			else if ( cOption ==  'i' && features.bInfo )
2340			{
2341				/* Info */
2342				featureNode = _fnFeatureHtmlInfo( oSettings );
2343			}
2344			else if ( cOption == 'p' && features.bPaginate )
2345			{
2346				/* Pagination */
2347				featureNode = _fnFeatureHtmlPaginate( oSettings );
2348			}
2349			else if ( DataTable.ext.feature.length !== 0 )
2350			{
2351				/* Plug-in features */
2352				var aoFeatures = DataTable.ext.feature;
2353				for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2354				{
2355					if ( cOption == aoFeatures[k].cFeature )
2356					{
2357						featureNode = aoFeatures[k].fnInit( oSettings );
2358						break;
2359					}
2360				}
2361			}
2362	
2363			/* Add to the 2D features array */
2364			if ( featureNode )
2365			{
2366				var aanFeatures = oSettings.aanFeatures;
2367	
2368				if ( ! aanFeatures[cOption] )
2369				{
2370					aanFeatures[cOption] = [];
2371				}
2372	
2373				aanFeatures[cOption].push( featureNode );
2374				insert.append( featureNode );
2375			}
2376		}
2377	
2378		/* Built our DOM structure - replace the holding div with what we want */
2379		holding.replaceWith( insert );
2380		oSettings.nHolding = null;
2381	}
2382	
2383	
2384	/**
2385	 * Use the DOM source to create up an array of header cells. The idea here is to
2386	 * create a layout grid (array) of rows x columns, which contains a reference
2387	 * to the cell that that point in the grid (regardless of col/rowspan), such that
2388	 * any column / row could be removed and the new grid constructed
2389	 *  @param array {object} aLayout Array to store the calculated layout in
2390	 *  @param {node} nThead The header/footer element for the table
2391	 *  @memberof DataTable#oApi
2392	 */
2393	function _fnDetectHeader ( aLayout, nThead )
2394	{
2395		var nTrs = $(nThead).children('tr');
2396		var nTr, nCell;
2397		var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2398		var bUnique;
2399		var fnShiftCol = function ( a, i, j ) {
2400			var k = a[i];
2401	                while ( k[j] ) {
2402				j++;
2403			}
2404			return j;
2405		};
2406	
2407		aLayout.splice( 0, aLayout.length );
2408	
2409		/* We know how many rows there are in the layout - so prep it */
2410		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2411		{
2412			aLayout.push( [] );
2413		}
2414	
2415		/* Calculate a layout array */
2416		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2417		{
2418			nTr = nTrs[i];
2419			iColumn = 0;
2420	
2421			/* For every cell in the row... */
2422			nCell = nTr.firstChild;
2423			while ( nCell ) {
2424				if ( nCell.nodeName.toUpperCase() == "TD" ||
2425				     nCell.nodeName.toUpperCase() == "TH" )
2426				{
2427					/* Get the col and rowspan attributes from the DOM and sanitise them */
2428					iColspan = nCell.getAttribute('colspan') * 1;
2429					iRowspan = nCell.getAttribute('rowspan') * 1;
2430					iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2431					iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2432	
2433					/* There might be colspan cells already in this row, so shift our target
2434					 * accordingly
2435					 */
2436					iColShifted = fnShiftCol( aLayout, i, iColumn );
2437	
2438					/* Cache calculation for unique columns */
2439					bUnique = iColspan === 1 ? true : false;
2440	
2441					/* If there is col / rowspan, copy the information into the layout grid */
2442					for ( l=0 ; l<iColspan ; l++ )
2443					{
2444						for ( k=0 ; k<iRowspan ; k++ )
2445						{
2446							aLayout[i+k][iColShifted+l] = {
2447								"cell": nCell,
2448								"unique": bUnique
2449							};
2450							aLayout[i+k].nTr = nTr;
2451						}
2452					}
2453				}
2454				nCell = nCell.nextSibling;
2455			}
2456		}
2457	}
2458	
2459	
2460	/**
2461	 * Get an array of unique th elements, one for each column
2462	 *  @param {object} oSettings dataTables settings object
2463	 *  @param {node} nHeader automatically detect the layout from this node - optional
2464	 *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2465	 *  @returns array {node} aReturn list of unique th's
2466	 *  @memberof DataTable#oApi
2467	 */
2468	function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2469	{
2470		var aReturn = [];
2471		if ( !aLayout )
2472		{
2473			aLayout = oSettings.aoHeader;
2474			if ( nHeader )
2475			{
2476				aLayout = [];
2477				_fnDetectHeader( aLayout, nHeader );
2478			}
2479		}
2480	
2481		for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2482		{
2483			for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2484			{
2485				if ( aLayout[i][j].unique &&
2486					 (!aReturn[j] || !oSettings.bSortCellsTop) )
2487				{
2488					aReturn[j] = aLayout[i][j].cell;
2489				}
2490			}
2491		}
2492	
2493		return aReturn;
2494	}
2495	
2496	/**
2497	 * Create an Ajax call based on the table's settings, taking into account that
2498	 * parameters can have multiple forms, and backwards compatibility.
2499	 *
2500	 * @param {object} oSettings dataTables settings object
2501	 * @param {array} data Data to send to the server, required by
2502	 *     DataTables - may be augmented by developer callbacks
2503	 * @param {function} fn Callback function to run when data is obtained
2504	 */
2505	function _fnBuildAjax( oSettings, data, fn )
2506	{
2507		// Compatibility with 1.9-, allow fnServerData and event to manipulate
2508		_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2509	
2510		// Convert to object based for 1.10+ if using the old array scheme which can
2511		// come from server-side processing or serverParams
2512		if ( data && $.isArray(data) ) {
2513			var tmp = {};
2514			var rbracket = /(.*?)\[\]$/;
2515	
2516			$.each( data, function (key, val) {
2517				var match = val.name.match(rbracket);
2518	
2519				if ( match ) {
2520					// Support for arrays
2521					var name = match[0];
2522	
2523					if ( ! tmp[ name ] ) {
2524						tmp[ name ] = [];
2525					}
2526					tmp[ name ].push( val.value );
2527				}
2528				else {
2529					tmp[val.name] = val.value;
2530				}
2531			} );
2532			data = tmp;
2533		}
2534	
2535		var ajaxData;
2536		var ajax = oSettings.ajax;
2537		var instance = oSettings.oInstance;
2538		var callback = function ( json ) {
2539			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
2540			fn( json );
2541		};
2542	
2543		if ( $.isPlainObject( ajax ) && ajax.data )
2544		{
2545			ajaxData = ajax.data;
2546	
2547			var newData = $.isFunction( ajaxData ) ?
2548				ajaxData( data, oSettings ) :  // fn can manipulate data or return
2549				ajaxData;                      // an object object or array to merge
2550	
2551			// If the function returned something, use that alone
2552			data = $.isFunction( ajaxData ) && newData ?
2553				newData :
2554				$.extend( true, data, newData );
2555	
2556			// Remove the data property as we've resolved it already and don't want
2557			// jQuery to do it again (it is restored at the end of the function)
2558			delete ajax.data;
2559		}
2560	
2561		var baseAjax = {
2562			"data": data,
2563			"success": function (json) {
2564				var error = json.error || json.sError;
2565				if ( error ) {
2566					_fnLog( oSettings, 0, error );
2567				}
2568	
2569				oSettings.json = json;
2570				callback( json );
2571			},
2572			"dataType": "json",
2573			"cache": false,
2574			"type": oSettings.sServerMethod,
2575			"error": function (xhr, error, thrown) {
2576				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
2577	
2578				if ( $.inArray( true, ret ) === -1 ) {
2579					if ( error == "parsererror" ) {
2580						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
2581					}
2582					else if ( xhr.readyState === 4 ) {
2583						_fnLog( oSettings, 0, 'Ajax error', 7 );
2584					}
2585				}
2586	
2587				_fnProcessingDisplay( oSettings, false );
2588			}
2589		};
2590	
2591		// Store the data submitted for the API
2592		oSettings.oAjaxData = data;
2593	
2594		// Allow plug-ins and external processes to modify the data
2595		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2596	
2597		if ( oSettings.fnServerData )
2598		{
2599			// DataTables 1.9- compatibility
2600			oSettings.fnServerData.call( instance,
2601				oSettings.sAjaxSource,
2602				$.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2603					return { name: key, value: val };
2604				} ),
2605				callback,
2606				oSettings
2607			);
2608		}
2609		else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2610		{
2611			// DataTables 1.9- compatibility
2612			oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2613				url: ajax || oSettings.sAjaxSource
2614			} ) );
2615		}
2616		else if ( $.isFunction( ajax ) )
2617		{
2618			// Is a function - let the caller define what needs to be done
2619			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
2620		}
2621		else
2622		{
2623			// Object to extend the base settings
2624			oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2625	
2626			// Restore for next time around
2627			ajax.data = ajaxData;
2628		}
2629	}
2630	
2631	
2632	/**
2633	 * Update the table using an Ajax call
2634	 *  @param {object} settings dataTables settings object
2635	 *  @returns {boolean} Block the table drawing or not
2636	 *  @memberof DataTable#oApi
2637	 */
2638	function _fnAjaxUpdate( settings )
2639	{
2640		if ( settings.bAjaxDataGet ) {
2641			settings.iDraw++;
2642			_fnProcessingDisplay( settings, true );
2643	
2644			_fnBuildAjax(
2645				settings,
2646				_fnAjaxParameters( settings ),
2647				function(json) {
2648					_fnAjaxUpdateDraw( settings, json );
2649				}
2650			);
2651	
2652			return false;
2653		}
2654		return true;
2655	}
2656	
2657	
2658	/**
2659	 * Build up the parameters in an object needed for a server-side processing
2660	 * request. Note that this is basically done twice, is different ways - a modern
2661	 * method which is used by default in DataTables 1.10 which uses objects and
2662	 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2663	 * the sAjaxSource option is used in the initialisation, or the legacyAjax
2664	 * option is set.
2665	 *  @param {object} oSettings dataTables settings object
2666	 *  @returns {bool} block the table drawing or not
2667	 *  @memberof DataTable#oApi
2668	 */
2669	function _fnAjaxParameters( settings )
2670	{
2671		var
2672			columns = settings.aoColumns,
2673			columnCount = columns.length,
2674			features = settings.oFeatures,
2675			preSearch = settings.oPreviousSearch,
2676			preColSearch = settings.aoPreSearchCols,
2677			i, data = [], dataProp, column, columnSearch,
2678			sort = _fnSortFlatten( settings ),
2679			displayStart = settings._iDisplayStart,
2680			displayLength = features.bPaginate !== false ?
2681				settings._iDisplayLength :
2682				-1;
2683	
2684		var param = function ( name, value ) {
2685			data.push( { 'name': name, 'value': value } );
2686		};
2687	
2688		// DataTables 1.9- compatible method
2689		param( 'sEcho',          settings.iDraw );
2690		param( 'iColumns',       columnCount );
2691		param( 'sColumns',       _pluck( columns, 'sName' ).join(',') );
2692		param( 'iDisplayStart',  displayStart );
2693		param( 'iDisplayLength', displayLength );
2694	
2695		// DataTables 1.10+ method
2696		var d = {
2697			draw:    settings.iDraw,
2698			columns: [],
2699			order:   [],
2700			start:   displayStart,
2701			length:  displayLength,
2702			search:  {
2703				value: preSearch.sSearch,
2704				regex: preSearch.bRegex
2705			}
2706		};
2707	
2708		for ( i=0 ; i<columnCount ; i++ ) {
2709			column = columns[i];
2710			columnSearch = preColSearch[i];
2711			dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2712	
2713			d.columns.push( {
2714				data:       dataProp,
2715				name:       column.sName,
2716				searchable: column.bSearchable,
2717				orderable:  column.bSortable,
2718				search:     {
2719					value: columnSearch.sSearch,
2720					regex: columnSearch.bRegex
2721				}
2722			} );
2723	
2724			param( "mDataProp_"+i, dataProp );
2725	
2726			if ( features.bFilter ) {
2727				param( 'sSearch_'+i,     columnSearch.sSearch );
2728				param( 'bRegex_'+i,      columnSearch.bRegex );
2729				param( 'bSearchable_'+i, column.bSearchable );
2730			}
2731	
2732			if ( features.bSort ) {
2733				param( 'bSortable_'+i, column.bSortable );
2734			}
2735		}
2736	
2737		if ( features.bFilter ) {
2738			param( 'sSearch', preSearch.sSearch );
2739			param( 'bRegex', preSearch.bRegex );
2740		}
2741	
2742		if ( features.bSort ) {
2743			$.each( sort, function ( i, val ) {
2744				d.order.push( { column: val.col, dir: val.dir } );
2745	
2746				param( 'iSortCol_'+i, val.col );
2747				param( 'sSortDir_'+i, val.dir );
2748			} );
2749	
2750			param( 'iSortingCols', sort.length );
2751		}
2752	
2753		// If the legacy.ajax parameter is null, then we automatically decide which
2754		// form to use, based on sAjaxSource
2755		var legacy = DataTable.ext.legacy.ajax;
2756		if ( legacy === null ) {
2757			return settings.sAjaxSource ? data : d;
2758		}
2759	
2760		// Otherwise, if legacy has been specified then we use that to decide on the
2761		// form
2762		return legacy ? data : d;
2763	}
2764	
2765	
2766	/**
2767	 * Data the data from the server (nuking the old) and redraw the table
2768	 *  @param {object} oSettings dataTables settings object
2769	 *  @param {object} json json data return from the server.
2770	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
2771	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2772	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2773	 *  @param {array} json.aaData The data to display on this page
2774	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
2775	 *  @memberof DataTable#oApi
2776	 */
2777	function _fnAjaxUpdateDraw ( settings, json )
2778	{
2779		// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2780		// Support both
2781		var compat = function ( old, modern ) {
2782			return json[old] !== undefined ? json[old] : json[modern];
2783		};
2784	
2785		var data = _fnAjaxDataSrc( settings, json );
2786		var draw            = compat( 'sEcho',                'draw' );
2787		var recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );
2788		var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2789	
2790		if ( draw ) {
2791			// Protect against out of sequence returns
2792			if ( draw*1 < settings.iDraw ) {
2793				return;
2794			}
2795			settings.iDraw = draw * 1;
2796		}
2797	
2798		_fnClearTable( settings );
2799		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
2800		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2801	
2802		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2803			_fnAddData( settings, data[i] );
2804		}
2805		settings.aiDisplay = settings.aiDisplayMaster.slice();
2806	
2807		settings.bAjaxDataGet = false;
2808		_fnDraw( settings );
2809	
2810		if ( ! settings._bInitComplete ) {
2811			_fnInitComplete( settings, json );
2812		}
2813	
2814		settings.bAjaxDataGet = true;
2815		_fnProcessingDisplay( settings, false );
2816	}
2817	
2818	
2819	/**
2820	 * Get the data from the JSON data source to use for drawing a table. Using
2821	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2822	 * source object, or from a processing function.
2823	 *  @param {object} oSettings dataTables settings object
2824	 *  @param  {object} json Data source object / array from the server
2825	 *  @return {array} Array of data to use
2826	 */
2827	function _fnAjaxDataSrc ( oSettings, json )
2828	{
2829		var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2830			oSettings.ajax.dataSrc :
2831			oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2832	
2833		// Compatibility with 1.9-. In order to read from aaData, check if the
2834		// default has been changed, if not, check for aaData
2835		if ( dataSrc === 'data' ) {
2836			return json.aaData || json[dataSrc];
2837		}
2838	
2839		return dataSrc !== "" ?
2840			_fnGetObjectDataFn( dataSrc )( json ) :
2841			json;
2842	}
2843	
2844	/**
2845	 * Generate the node required for filtering text
2846	 *  @returns {node} Filter control element
2847	 *  @param {object} oSettings dataTables settings object
2848	 *  @memberof DataTable#oApi
2849	 */
2850	function _fnFeatureHtmlFilter ( settings )
2851	{
2852		var classes = settings.oClasses;
2853		var tableId = settings.sTableId;
2854		var language = settings.oLanguage;
2855		var previousSearch = settings.oPreviousSearch;
2856		var features = settings.aanFeatures;
2857		var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2858	
2859		var str = language.sSearch;
2860		str = str.match(/_INPUT_/) ?
2861			str.replace('_INPUT_', input) :
2862			str+input;
2863	
2864		var filter = $('<div/>', {
2865				'id': ! features.f ? tableId+'_filter' : null,
2866				'class': classes.sFilter
2867			} )
2868			.append( $('<label/>' ).append( str ) );
2869	
2870		var searchFn = function() {
2871			/* Update all other filter input elements for the new display */
2872			var n = features.f;
2873			var val = !this.value ? "" : this.value; // mental IE8 fix :-(
2874	
2875			/* Now do the filter */
2876			if ( val != previousSearch.sSearch ) {
2877				_fnFilterComplete( settings, {
2878					"sSearch": val,
2879					"bRegex": previousSearch.bRegex,
2880					"bSmart": previousSearch.bSmart ,
2881					"bCaseInsensitive": previousSearch.bCaseInsensitive
2882				} );
2883	
2884				// Need to redraw, without resorting
2885				settings._iDisplayStart = 0;
2886				_fnDraw( settings );
2887			}
2888		};
2889	
2890		var searchDelay = settings.searchDelay !== null ?
2891			settings.searchDelay :
2892			_fnDataSource( settings ) === 'ssp' ?
2893				400 :
2894				0;
2895	
2896		var jqFilter = $('input', filter)
2897			.val( previousSearch.sSearch )
2898			.attr( 'placeholder', language.sSearchPlaceholder )
2899			.bind(
2900				'keyup.DT search.DT input.DT paste.DT cut.DT',
2901				searchDelay ?
2902					_fnThrottle( searchFn, searchDelay ) :
2903					searchFn
2904			)
2905			.bind( 'keypress.DT', function(e) {
2906				/* Prevent form submission */
2907				if ( e.keyCode == 13 ) {
2908					return false;
2909				}
2910			} )
2911			.attr('aria-controls', tableId);
2912	
2913		// Update the input elements whenever the table is filtered
2914		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2915			if ( settings === s ) {
2916				// IE9 throws an 'unknown error' if document.activeElement is used
2917				// inside an iframe or frame...
2918				try {
2919					if ( jqFilter[0] !== document.activeElement ) {
2920						jqFilter.val( previousSearch.sSearch );
2921					}
2922				}
2923				catch ( e ) {}
2924			}
2925		} );
2926	
2927		return filter[0];
2928	}
2929	
2930	
2931	/**
2932	 * Filter the table using both the global filter and column based filtering
2933	 *  @param {object} oSettings dataTables settings object
2934	 *  @param {object} oSearch search information
2935	 *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2936	 *  @memberof DataTable#oApi
2937	 */
2938	function _fnFilterComplete ( oSettings, oInput, iForce )
2939	{
2940		var oPrevSearch = oSettings.oPreviousSearch;
2941		var aoPrevSearch = oSettings.aoPreSearchCols;
2942		var fnSaveFilter = function ( oFilter ) {
2943			/* Save the filtering values */
2944			oPrevSearch.sSearch = oFilter.sSearch;
2945			oPrevSearch.bRegex = oFilter.bRegex;
2946			oPrevSearch.bSmart = oFilter.bSmart;
2947			oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2948		};
2949		var fnRegex = function ( o ) {
2950			// Backwards compatibility with the bEscapeRegex option
2951			return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2952		};
2953	
2954		// Resolve any column types that are unknown due to addition or invalidation
2955		// @todo As per sort - can this be moved into an event handler?
2956		_fnColumnTypes( oSettings );
2957	
2958		/* In server-side processing all filtering is done by the server, so no point hanging around here */
2959		if ( _fnDataSource( oSettings ) != 'ssp' )
2960		{
2961			/* Global filter */
2962			_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2963			fnSaveFilter( oInput );
2964	
2965			/* Now do the individual column filter */
2966			for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2967			{
2968				_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2969					aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2970			}
2971	
2972			/* Custom filtering */
2973			_fnFilterCustom( oSettings );
2974		}
2975		else
2976		{
2977			fnSaveFilter( oInput );
2978		}
2979	
2980		/* Tell the draw function we have been filtering */
2981		oSettings.bFiltered = true;
2982		_fnCallbackFire( oSettings, null, 'search', [oSettings] );
2983	}
2984	
2985	
2986	/**
2987	 * Apply custom filtering functions
2988	 *  @param {object} oSettings dataTables settings object
2989	 *  @memberof DataTable#oApi
2990	 */
2991	function _fnFilterCustom( settings )
2992	{
2993		var filters = DataTable.ext.search;
2994		var displayRows = settings.aiDisplay;
2995		var row, rowIdx;
2996	
2997		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2998			var rows = [];
2999	
3000			// Loop over each row and see if it should be included
3001			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
3002				rowIdx = displayRows[ j ];
3003				row = settings.aoData[ rowIdx ];
3004	
3005				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
3006					rows.push( rowIdx );
3007				}
3008			}
3009	
3010			// So the array reference doesn't break set the results into the
3011			// existing array
3012			displayRows.length = 0;
3013			$.merge( displayRows, rows );
3014		}
3015	}
3016	
3017	
3018	/**
3019	 * Filter the table on a per-column basis
3020	 *  @param {object} oSettings dataTables settings object
3021	 *  @param {string} sInput string to filter on
3022	 *  @param {int} iColumn column to filter
3023	 *  @param {bool} bRegex treat search string as a regular expression or not
3024	 *  @param {bool} bSmart use smart filtering or not
3025	 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
3026	 *  @memberof DataTable#oApi
3027	 */
3028	function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
3029	{
3030		if ( searchStr === '' ) {
3031			return;
3032		}
3033	
3034		var data;
3035		var display = settings.aiDisplay;
3036		var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
3037	
3038		for ( var i=display.length-1 ; i>=0 ; i-- ) {
3039			data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
3040	
3041			if ( ! rpSearch.test( data ) ) {
3042				display.splice( i, 1 );
3043			}
3044		}
3045	}
3046	
3047	
3048	/**
3049	 * Filter the data table based on user input and draw the table
3050	 *  @param {object} settings dataTables settings object
3051	 *  @param {string} input string to filter on
3052	 *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
3053	 *  @param {bool} regex treat as a regular expression or not
3054	 *  @param {bool} smart perform smart filtering or not
3055	 *  @param {bool} caseInsensitive Do case insenstive matching or not
3056	 *  @memberof DataTable#oApi
3057	 */
3058	function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
3059	{
3060		var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
3061		var prevSearch = settings.oPreviousSearch.sSearch;
3062		var displayMaster = settings.aiDisplayMaster;
3063		var display, invalidated, i;
3064	
3065		// Need to take account of custom filtering functions - always filter
3066		if ( DataTable.ext.search.length !== 0 ) {
3067			force = true;
3068		}
3069	
3070		// Check if any of the rows were invalidated
3071		invalidated = _fnFilterData( settings );
3072	
3073		// If the input is blank - we just want the full data set
3074		if ( input.length <= 0 ) {
3075			settings.aiDisplay = displayMaster.slice();
3076		}
3077		else {
3078			// New search - start from the master array
3079			if ( invalidated ||
3080				 force ||
3081				 prevSearch.length > input.length ||
3082				 input.indexOf(prevSearch) !== 0 ||
3083				 settings.bSorted // On resort, the display master needs to be
3084				                  // re-filtered since indexes will have changed
3085			) {
3086				settings.aiDisplay = displayMaster.slice();
3087			}
3088	
3089			// Search the display array
3090			display = settings.aiDisplay;
3091	
3092			for ( i=display.length-1 ; i>=0 ; i-- ) {
3093				if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
3094					display.splice( i, 1 );
3095				}
3096			}
3097		}
3098	}
3099	
3100	
3101	/**
3102	 * Build a regular expression object suitable for searching a table
3103	 *  @param {string} sSearch string to search for
3104	 *  @param {bool} bRegex treat as a regular expression or not
3105	 *  @param {bool} bSmart perform smart filtering or not
3106	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
3107	 *  @returns {RegExp} constructed object
3108	 *  @memberof DataTable#oApi
3109	 */
3110	function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
3111	{
3112		search = regex ?
3113			search :
3114			_fnEscapeRegex( search );
3115		
3116		if ( smart ) {
3117			/* For smart filtering we want to allow the search to work regardless of
3118			 * word order. We also want double quoted text to be preserved, so word
3119			 * order is important - a la google. So this is what we want to
3120			 * generate:
3121			 * 
3122			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
3123			 */
3124			var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
3125				if ( word.charAt(0) === '"' ) {
3126					var m = word.match( /^"(.*)"$/ );
3127					word = m ? m[1] : word;
3128				}
3129	
3130				return word.replace('"', '');
3131			} );
3132	
3133			search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
3134		}
3135	
3136		return new RegExp( search, caseInsensitive ? 'i' : '' );
3137	}
3138	
3139	
3140	/**
3141	 * Escape a string such that it can be used in a regular expression
3142	 *  @param {string} sVal string to escape
3143	 *  @returns {string} escaped string
3144	 *  @memberof DataTable#oApi
3145	 */
3146	function _fnEscapeRegex ( sVal )
3147	{
3148		return sVal.replace( _re_escape_regex, '\\$1' );
3149	}
3150	
3151	
3152	
3153	var __filter_div = $('<div>')[0];
3154	var __filter_div_textContent = __filter_div.textContent !== undefined;
3155	
3156	// Update the filtering data for each row if needed (by invalidation or first run)
3157	function _fnFilterData ( settings )
3158	{
3159		var columns = settings.aoColumns;
3160		var column;
3161		var i, j, ien, jen, filterData, cellData, row;
3162		var fomatters = DataTable.ext.type.search;
3163		var wasInvalidated = false;
3164	
3165		for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
3166			row = settings.aoData[i];
3167	
3168			if ( ! row._aFilterData ) {
3169				filterData = [];
3170	
3171				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
3172					column = columns[j];
3173	
3174					if ( column.bSearchable ) {
3175						cellData = _fnGetCellData( settings, i, j, 'filter' );
3176	
3177						if ( fomatters[ column.sType ] ) {
3178							cellData = fomatters[ column.sType ]( cellData );
3179						}
3180	
3181						// Search in DataTables 1.10 is string based. In 1.11 this
3182						// should be altered to also allow strict type checking.
3183						if ( cellData === null ) {
3184							cellData = '';
3185						}
3186	
3187						if ( typeof cellData !== 'string' && cellData.toString ) {
3188							cellData = cellData.toString();
3189						}
3190					}
3191					else {
3192						cellData = '';
3193					}
3194	
3195					// If it looks like there is an HTML entity in the string,
3196					// attempt to decode it so sorting works as expected. Note that
3197					// we could use a single line of jQuery to do this, but the DOM
3198					// method used here is much faster http://jsperf.com/html-decode
3199					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
3200						__filter_div.innerHTML = cellData;
3201						cellData = __filter_div_textContent ?
3202							__filter_div.textContent :
3203							__filter_div.innerText;
3204					}
3205	
3206					if ( cellData.replace ) {
3207						cellData = cellData.replace(/[\r\n]/g, '');
3208					}
3209	
3210					filterData.push( cellData );
3211				}
3212	
3213				row._aFilterData = filterData;
3214				row._sFilterRow = filterData.join('  ');
3215				wasInvalidated = true;
3216			}
3217		}
3218	
3219		return wasInvalidated;
3220	}
3221	
3222	
3223	/**
3224	 * Convert from the internal Hungarian notation to camelCase for external
3225	 * interaction
3226	 *  @param {object} obj Object to convert
3227	 *  @returns {object} Inverted object
3228	 *  @memberof DataTable#oApi
3229	 */
3230	function _fnSearchToCamel ( obj )
3231	{
3232		return {
3233			search:          obj.sSearch,
3234			smart:           obj.bSmart,
3235			regex:           obj.bRegex,
3236			caseInsensitive: obj.bCaseInsensitive
3237		};
3238	}
3239	
3240	
3241	
3242	/**
3243	 * Convert from camelCase notation to the internal Hungarian. We could use the
3244	 * Hungarian convert function here, but this is cleaner
3245	 *  @param {object} obj Object to convert
3246	 *  @returns {object} Inverted object
3247	 *  @memberof DataTable#oApi
3248	 */
3249	function _fnSearchToHung ( obj )
3250	{
3251		return {
3252			sSearch:          obj.search,
3253			bSmart:           obj.smart,
3254			bRegex:           obj.regex,
3255			bCaseInsensitive: obj.caseInsensitive
3256		};
3257	}
3258	
3259	/**
3260	 * Generate the node required for the info display
3261	 *  @param {object} oSettings dataTables settings object
3262	 *  @returns {node} Information element
3263	 *  @memberof DataTable#oApi
3264	 */
3265	function _fnFeatureHtmlInfo ( settings )
3266	{
3267		var
3268			tid = settings.sTableId,
3269			nodes = settings.aanFeatures.i,
3270			n = $('<div/>', {
3271				'class': settings.oClasses.sInfo,
3272				'id': ! nodes ? tid+'_info' : null
3273			} );
3274	
3275		if ( ! nodes ) {
3276			// Update display on each draw
3277			settings.aoDrawCallback.push( {
3278				"fn": _fnUpdateInfo,
3279				"sName": "information"
3280			} );
3281	
3282			n
3283				.attr( 'role', 'status' )
3284				.attr( 'aria-live', 'polite' );
3285	
3286			// Table is described by our info div
3287			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3288		}
3289	
3290		return n[0];
3291	}
3292	
3293	
3294	/**
3295	 * Update the information elements in the display
3296	 *  @param {object} settings dataTables settings object
3297	 *  @memberof DataTable#oApi
3298	 */
3299	function _fnUpdateInfo ( settings )
3300	{
3301		/* Show information about the table */
3302		var nodes = settings.aanFeatures.i;
3303		if ( nodes.length === 0 ) {
3304			return;
3305		}
3306	
3307		var
3308			lang  = settings.oLanguage,
3309			start = settings._iDisplayStart+1,
3310			end   = settings.fnDisplayEnd(),
3311			max   = settings.fnRecordsTotal(),
3312			total = settings.fnRecordsDisplay(),
3313			out   = total ?
3314				lang.sInfo :
3315				lang.sInfoEmpty;
3316	
3317		if ( total !== max ) {
3318			/* Record set after filtering */
3319			out += ' ' + lang.sInfoFiltered;
3320		}
3321	
3322		// Convert the macros
3323		out += lang.sInfoPostFix;
3324		out = _fnInfoMacros( settings, out );
3325	
3326		var callback = lang.fnInfoCallback;
3327		if ( callback !== null ) {
3328			out = callback.call( settings.oInstance,
3329				settings, start, end, max, total, out
3330			);
3331		}
3332	
3333		$(nodes).html( out );
3334	}
3335	
3336	
3337	function _fnInfoMacros ( settings, str )
3338	{
3339		// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3340		// internally
3341		var
3342			formatter  = settings.fnFormatNumber,
3343			start      = settings._iDisplayStart+1,
3344			len        = settings._iDisplayLength,
3345			vis        = settings.fnRecordsDisplay(),
3346			all        = len === -1;
3347	
3348		return str.
3349			replace(/_START_/g, formatter.call( settings, start ) ).
3350			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
3351			replace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).
3352			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3353			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3354			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3355	}
3356	
3357	
3358	
3359	/**
3360	 * Draw the table for the first time, adding all required features
3361	 *  @param {object} settings dataTables settings object
3362	 *  @memberof DataTable#oApi
3363	 */
3364	function _fnInitialise ( settings )
3365	{
3366		var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3367		var columns = settings.aoColumns, column;
3368		var features = settings.oFeatures;
3369		var deferLoading = settings.bDeferLoading; // value modified by the draw
3370	
3371		/* Ensure that the table data is fully initialised */
3372		if ( ! settings.bInitialised ) {
3373			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3374			return;
3375		}
3376	
3377		/* Show the display HTML options */
3378		_fnAddOptionsHtml( settings );
3379	
3380		/* Build and draw the header / footer for the table */
3381		_fnBuildHead( settings );
3382		_fnDrawHead( settings, settings.aoHeader );
3383		_fnDrawHead( settings, settings.aoFooter );
3384	
3385		/* Okay to show that something is going on now */
3386		_fnProcessingDisplay( settings, true );
3387	
3388		/* Calculate sizes for columns */
3389		if ( features.bAutoWidth ) {
3390			_fnCalculateColumnWidths( settings );
3391		}
3392	
3393		for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3394			column = columns[i];
3395	
3396			if ( column.sWidth ) {
3397				column.nTh.style.width = _fnStringToCss( column.sWidth );
3398			}
3399		}
3400	
3401		_fnCallbackFire( settings, null, 'preInit', [settings] );
3402	
3403		// If there is default sorting required - let's do it. The sort function
3404		// will do the drawing for us. Otherwise we draw the table regardless of the
3405		// Ajax source - this allows the table to look initialised for Ajax sourcing
3406		// data (show 'loading' message possibly)
3407		_fnReDraw( settings );
3408	
3409		// Server-side processing init complete is done by _fnAjaxUpdateDraw
3410		var dataSrc = _fnDataSource( settings );
3411		if ( dataSrc != 'ssp' || deferLoading ) {
3412			// if there is an ajax source load the data
3413			if ( dataSrc == 'ajax' ) {
3414				_fnBuildAjax( settings, [], function(json) {
3415					var aData = _fnAjaxDataSrc( settings, json );
3416	
3417					// Got the data - add it to the table
3418					for ( i=0 ; i<aData.length ; i++ ) {
3419						_fnAddData( settings, aData[i] );
3420					}
3421	
3422					// Reset the init display for cookie saving. We've already done
3423					// a filter, and therefore cleared it before. So we need to make
3424					// it appear 'fresh'
3425					settings.iInitDisplayStart = iAjaxStart;
3426	
3427					_fnReDraw( settings );
3428	
3429					_fnProcessingDisplay( settings, false );
3430					_fnInitComplete( settings, json );
3431				}, settings );
3432			}
3433			else {
3434				_fnProcessingDisplay( settings, false );
3435				_fnInitComplete( settings );
3436			}
3437		}
3438	}
3439	
3440	
3441	/**
3442	 * Draw the table for the first time, adding all required features
3443	 *  @param {object} oSettings dataTables settings object
3444	 *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
3445	 *    with client-side processing (optional)
3446	 *  @memberof DataTable#oApi
3447	 */
3448	function _fnInitComplete ( settings, json )
3449	{
3450		settings._bInitComplete = true;
3451	
3452		// When data was added after the initialisation (data or Ajax) we need to
3453		// calculate the column sizing
3454		if ( json || settings.oInit.aaData ) {
3455			_fnAdjustColumnSizing( settings );
3456		}
3457	
3458		_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
3459		_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3460	}
3461	
3462	
3463	function _fnLengthChange ( settings, val )
3464	{
3465		var len = parseInt( val, 10 );
3466		settings._iDisplayLength = len;
3467	
3468		_fnLengthOverflow( settings );
3469	
3470		// Fire length change event
3471		_fnCallbackFire( settings, null, 'length', [settings, len] );
3472	}
3473	
3474	
3475	/**
3476	 * Generate the node required for user display length changing
3477	 *  @param {object} settings dataTables settings object
3478	 *  @returns {node} Display length feature node
3479	 *  @memberof DataTable#oApi
3480	 */
3481	function _fnFeatureHtmlLength ( settings )
3482	{
3483		var
3484			classes  = settings.oClasses,
3485			tableId  = settings.sTableId,
3486			menu     = settings.aLengthMenu,
3487			d2       = $.isArray( menu[0] ),
3488			lengths  = d2 ? menu[0] : menu,
3489			language = d2 ? menu[1] : menu;
3490	
3491		var select = $('<select/>', {
3492			'name':          tableId+'_length',
3493			'aria-controls': tableId,
3494			'class':         classes.sLengthSelect
3495		} );
3496	
3497		for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3498			select[0][ i ] = new Option( language[i], lengths[i] );
3499		}
3500	
3501		var div = $('<div><label/></div>').addClass( classes.sLength );
3502		if ( ! settings.aanFeatures.l ) {
3503			div[0].id = tableId+'_length';
3504		}
3505	
3506		div.children().append(
3507			settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3508		);
3509	
3510		// Can't use `select` variable as user might provide their own and the
3511		// reference is broken by the use of outerHTML
3512		$('select', div)
3513			.val( settings._iDisplayLength )
3514			.bind( 'change.DT', function(e) {
3515				_fnLengthChange( settings, $(this).val() );
3516				_fnDraw( settings );
3517			} );
3518	
3519		// Update node value whenever anything changes the table's length
3520		$(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3521			if ( settings === s ) {
3522				$('select', div).val( len );
3523			}
3524		} );
3525	
3526		return div[0];
3527	}
3528	
3529	
3530	
3531	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3532	 * Note that most of the paging logic is done in
3533	 * DataTable.ext.pager
3534	 */
3535	
3536	/**
3537	 * Generate the node required for default pagination
3538	 *  @param {object} oSettings dataTables settings object
3539	 *  @returns {node} Pagination feature node
3540	 *  @memberof DataTable#oApi
3541	 */
3542	function _fnFeatureHtmlPaginate ( settings )
3543	{
3544		var
3545			type   = settings.sPaginationType,
3546			plugin = DataTable.ext.pager[ type ],
3547			modern = typeof plugin === 'function',
3548			redraw = function( settings ) {
3549				_fnDraw( settings );
3550			},
3551			node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3552			features = settings.aanFeatures;
3553	
3554		if ( ! modern ) {
3555			plugin.fnInit( settings, node, redraw );
3556		}
3557	
3558		/* Add a draw callback for the pagination on first instance, to update the paging display */
3559		if ( ! features.p )
3560		{
3561			node.id = settings.sTableId+'_paginate';
3562	
3563			settings.aoDrawCallback.push( {
3564				"fn": function( settings ) {
3565					if ( modern ) {
3566						var
3567							start      = settings._iDisplayStart,
3568							len        = settings._iDisplayLength,
3569							visRecords = settings.fnRecordsDisplay(),
3570							all        = len === -1,
3571							page = all ? 0 : Math.ceil( start / len ),
3572							pages = all ? 1 : Math.ceil( visRecords / len ),
3573							buttons = plugin(page, pages),
3574							i, ien;
3575	
3576						for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3577							_fnRenderer( settings, 'pageButton' )(
3578								settings, features.p[i], i, buttons, page, pages
3579							);
3580						}
3581					}
3582					else {
3583						plugin.fnUpdate( settings, redraw );
3584					}
3585				},
3586				"sName": "pagination"
3587			} );
3588		}
3589	
3590		return node;
3591	}
3592	
3593	
3594	/**
3595	 * Alter the display settings to change the page
3596	 *  @param {object} settings DataTables settings object
3597	 *  @param {string|int} action Paging action to take: "first", "previous",
3598	 *    "next" or "last" or page number to jump to (integer)
3599	 *  @param [bool] redraw Automatically draw the update or not
3600	 *  @returns {bool} true page has changed, false - no change
3601	 *  @memberof DataTable#oApi
3602	 */
3603	function _fnPageChange ( settings, action, redraw )
3604	{
3605		var
3606			start     = settings._iDisplayStart,
3607			len       = settings._iDisplayLength,
3608			records   = settings.fnRecordsDisplay();
3609	
3610		if ( records === 0 || len === -1 )
3611		{
3612			start = 0;
3613		}
3614		else if ( typeof action === "number" )
3615		{
3616			start = action * len;
3617	
3618			if ( start > records )
3619			{
3620				start = 0;
3621			}
3622		}
3623		else if ( action == "first" )
3624		{
3625			start = 0;
3626		}
3627		else if ( action == "previous" )
3628		{
3629			start = len >= 0 ?
3630				start - len :
3631				0;
3632	
3633			if ( start < 0 )
3634			{
3635			  start = 0;
3636			}
3637		}
3638		else if ( action == "next" )
3639		{
3640			if ( start + len < records )
3641			{
3642				start += len;
3643			}
3644		}
3645		else if ( action == "last" )
3646		{
3647			start = Math.floor( (records-1) / len) * len;
3648		}
3649		else
3650		{
3651			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3652		}
3653	
3654		var changed = settings._iDisplayStart !== start;
3655		settings._iDisplayStart = start;
3656	
3657		if ( changed ) {
3658			_fnCallbackFire( settings, null, 'page', [settings] );
3659	
3660			if ( redraw ) {
3661				_fnDraw( settings );
3662			}
3663		}
3664	
3665		return changed;
3666	}
3667	
3668	
3669	
3670	/**
3671	 * Generate the node required for the processing node
3672	 *  @param {object} settings dataTables settings object
3673	 *  @returns {node} Processing element
3674	 *  @memberof DataTable#oApi
3675	 */
3676	function _fnFeatureHtmlProcessing ( settings )
3677	{
3678		return $('<div/>', {
3679				'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3680				'class': settings.oClasses.sProcessing
3681			} )
3682			.html( settings.oLanguage.sProcessing )
3683			.insertBefore( settings.nTable )[0];
3684	}
3685	
3686	
3687	/**
3688	 * Display or hide the processing indicator
3689	 *  @param {object} settings dataTables settings object
3690	 *  @param {bool} show Show the processing indicator (true) or not (false)
3691	 *  @memberof DataTable#oApi
3692	 */
3693	function _fnProcessingDisplay ( settings, show )
3694	{
3695		if ( settings.oFeatures.bProcessing ) {
3696			$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3697		}
3698	
3699		_fnCallbackFire( settings, null, 'processing', [settings, show] );
3700	}
3701	
3702	/**
3703	 * Add any control elements for the table - specifically scrolling
3704	 *  @param {object} settings dataTables settings object
3705	 *  @returns {node} Node to add to the DOM
3706	 *  @memberof DataTable#oApi
3707	 */
3708	function _fnFeatureHtmlTable ( settings )
3709	{
3710		var table = $(settings.nTable);
3711	
3712		// Add the ARIA grid role to the table
3713		table.attr( 'role', 'grid' );
3714	
3715		// Scrolling from here on in
3716		var scroll = settings.oScroll;
3717	
3718		if ( scroll.sX === '' && scroll.sY === '' ) {
3719			return settings.nTable;
3720		}
3721	
3722		var scrollX = scroll.sX;
3723		var scrollY = scroll.sY;
3724		var classes = settings.oClasses;
3725		var caption = table.children('caption');
3726		var captionSide = caption.length ? caption[0]._captionSide : null;
3727		var headerClone = $( table[0].cloneNode(false) );
3728		var footerClone = $( table[0].cloneNode(false) );
3729		var footer = table.children('tfoot');
3730		var _div = '<div/>';
3731		var size = function ( s ) {
3732			return !s ? null : _fnStringToCss( s );
3733		};
3734	
3735		if ( ! footer.length ) {
3736			footer = null;
3737		}
3738	
3739		/*
3740		 * The HTML structure that we want to generate in this function is:
3741		 *  div - scroller
3742		 *    div - scroll head
3743		 *      div - scroll head inner
3744		 *        table - scroll head table
3745		 *          thead - thead
3746		 *    div - scroll body
3747		 *      table - table (master table)
3748		 *        thead - thead clone for sizing
3749		 *        tbody - tbody
3750		 *    div - scroll foot
3751		 *      div - scroll foot inner
3752		 *        table - scroll foot table
3753		 *          tfoot - tfoot
3754		 */
3755		var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3756			.append(
3757				$(_div, { 'class': classes.sScrollHead } )
3758					.css( {
3759						overflow: 'hidden',
3760						position: 'relative',
3761						border: 0,
3762						width: scrollX ? size(scrollX) : '100%'
3763					} )
3764					.append(
3765						$(_div, { 'class': classes.sScrollHeadInner } )
3766							.css( {
3767								'box-sizing': 'content-box',
3768								width: scroll.sXInner || '100%'
3769							} )
3770							.append(
3771								headerClone
3772									.removeAttr('id')
3773									.css( 'margin-left', 0 )
3774									.append( captionSide === 'top' ? caption : null )
3775									.append(
3776										table.children('thead')
3777									)
3778							)
3779					)
3780			)
3781			.append(
3782				$(_div, { 'class': classes.sScrollBody } )
3783					.css( {
3784						position: 'relative',
3785						overflow: 'auto',
3786						width: size( scrollX )
3787					} )
3788					.append( table )
3789			);
3790	
3791		if ( footer ) {
3792			scroller.append(
3793				$(_div, { 'class': classes.sScrollFoot } )
3794					.css( {
3795						overflow: 'hidden',
3796						border: 0,
3797						width: scrollX ? size(scrollX) : '100%'
3798					} )
3799					.append(
3800						$(_div, { 'class': classes.sScrollFootInner } )
3801							.append(
3802								footerClone
3803									.removeAttr('id')
3804									.css( 'margin-left', 0 )
3805									.append( captionSide === 'bottom' ? caption : null )
3806									.append(
3807										table.children('tfoot')
3808									)
3809							)
3810					)
3811			);
3812		}
3813	
3814		var children = scroller.children();
3815		var scrollHead = children[0];
3816		var scrollBody = children[1];
3817		var scrollFoot = footer ? children[2] : null;
3818	
3819		// When the body is scrolled, then we also want to scroll the headers
3820		if ( scrollX ) {
3821			$(scrollBody).on( 'scroll.DT', function (e) {
3822				var scrollLeft = this.scrollLeft;
3823	
3824				scrollHead.scrollLeft = scrollLeft;
3825	
3826				if ( footer ) {
3827					scrollFoot.scrollLeft = scrollLeft;
3828				}
3829			} );
3830		}
3831	
3832		$(scrollBody).css(
3833			scrollY && scroll.bCollapse ? 'max-height' : 'height', 
3834			scrollY
3835		);
3836	
3837		settings.nScrollHead = scrollHead;
3838		settings.nScrollBody = scrollBody;
3839		settings.nScrollFoot = scrollFoot;
3840	
3841		// On redraw - align columns
3842		settings.aoDrawCallback.push( {
3843			"fn": _fnScrollDraw,
3844			"sName": "scrolling"
3845		} );
3846	
3847		return scroller[0];
3848	}
3849	
3850	
3851	
3852	/**
3853	 * Update the header, footer and body tables for resizing - i.e. column
3854	 * alignment.
3855	 *
3856	 * Welcome to the most horrible function DataTables. The process that this
3857	 * function follows is basically:
3858	 *   1. Re-create the table inside the scrolling div
3859	 *   2. Take live measurements from the DOM
3860	 *   3. Apply the measurements to align the columns
3861	 *   4. Clean up
3862	 *
3863	 *  @param {object} settings dataTables settings object
3864	 *  @memberof DataTable#oApi
3865	 */
3866	function _fnScrollDraw ( settings )
3867	{
3868		// Given that this is such a monster function, a lot of variables are use
3869		// to try and keep the minimised size as small as possible
3870		var
3871			scroll         = settings.oScroll,
3872			scrollX        = scroll.sX,
3873			scrollXInner   = scroll.sXInner,
3874			scrollY        = scroll.sY,
3875			barWidth       = scroll.iBarWidth,
3876			divHeader      = $(settings.nScrollHead),
3877			divHeaderStyle = divHeader[0].style,
3878			divHeaderInner = divHeader.children('div'),
3879			divHeaderInnerStyle = divHeaderInner[0].style,
3880			divHeaderTable = divHeaderInner.children('table'),
3881			divBodyEl      = settings.nScrollBody,
3882			divBody        = $(divBodyEl),
3883			divBodyStyle   = divBodyEl.style,
3884			divFooter      = $(settings.nScrollFoot),
3885			divFooterInner = divFooter.children('div'),
3886			divFooterTable = divFooterInner.children('table'),
3887			header         = $(settings.nTHead),
3888			table          = $(settings.nTable),
3889			tableEl        = table[0],
3890			tableStyle     = tableEl.style,
3891			footer         = settings.nTFoot ? $(settings.nTFoot) : null,
3892			browser        = settings.oBrowser,
3893			ie67           = browser.bScrollOversize,
3894			dtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),
3895			headerTrgEls, footerTrgEls,
3896			headerSrcEls, footerSrcEls,
3897			headerCopy, footerCopy,
3898			headerWidths=[], footerWidths=[],
3899			headerContent=[], footerContent=[],
3900			idx, correction, sanityWidth,
3901			zeroOut = function(nSizer) {
3902				var style = nSizer.style;
3903				style.paddingTop = "0";
3904				style.paddingBottom = "0";
3905				style.borderTopWidth = "0";
3906				style.borderBottomWidth = "0";
3907				style.height = 0;
3908			};
3909	
3910		// If the scrollbar visibility has changed from the last draw, we need to
3911		// adjust the column sizes as the table width will have changed to account
3912		// for the scrollbar
3913		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
3914		
3915		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
3916			settings.scrollBarVis = scrollBarVis;
3917			_fnAdjustColumnSizing( settings );
3918			return; // adjust column sizing will call this function again
3919		}
3920		else {
3921			settings.scrollBarVis = scrollBarVis;
3922		}
3923	
3924		/*
3925		 * 1. Re-create the table inside the scrolling div
3926		 */
3927	
3928		// Remove the old minimised thead and tfoot elements in the inner table
3929		table.children('thead, tfoot').remove();
3930	
3931		if ( footer ) {
3932			footerCopy = footer.clone().prependTo( table );
3933			footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3934			footerSrcEls = footerCopy.find('tr');
3935		}
3936	
3937		// Clone the current header and footer elements and then place it into the inner table
3938		headerCopy = header.clone().prependTo( table );
3939		headerTrgEls = header.find('tr'); // original header is in its own table
3940		headerSrcEls = headerCopy.find('tr');
3941		headerCopy.find('th, td').removeAttr('tabindex');
3942	
3943	
3944		/*
3945		 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3946		 */
3947	
3948		// Remove old sizing and apply the calculated column widths
3949		// Get the unique column headers in the newly created (cloned) header. We want to apply the
3950		// calculated sizes to this header
3951		if ( ! scrollX )
3952		{
3953			divBodyStyle.width = '100%';
3954			divHeader[0].style.width = '100%';
3955		}
3956	
3957		$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3958			idx = _fnVisibleToColumnIndex( settings, i );
3959			el.style.width = settings.aoColumns[idx].sWidth;
3960		} );
3961	
3962		if ( footer ) {
3963			_fnApplyToChildren( function(n) {
3964				n.style.width = "";
3965			}, footerSrcEls );
3966		}
3967	
3968		// Size the table as a whole
3969		sanityWidth = table.outerWidth();
3970		if ( scrollX === "" ) {
3971			// No x scrolling
3972			tableStyle.width = "100%";
3973	
3974			// IE7 will make the width of the table when 100% include the scrollbar
3975			// - which is shouldn't. When there is a scrollbar we need to take this
3976			// into account.
3977			if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3978				divBody.css('overflow-y') == "scroll")
3979			) {
3980				tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3981			}
3982	
3983			// Recalculate the sanity width
3984			sanityWidth = table.outerWidth();
3985		}
3986		else if ( scrollXInner !== "" ) {
3987			// legacy x scroll inner has been given - use it
3988			tableStyle.width = _fnStringToCss(scrollXInner);
3989	
3990			// Recalculate the sanity width
3991			sanityWidth = table.outerWidth();
3992		}
3993	
3994		// Hidden header should have zero height, so remove padding and borders. Then
3995		// set the width based on the real headers
3996	
3997		// Apply all styles in one pass
3998		_fnApplyToChildren( zeroOut, headerSrcEls );
3999	
4000		// Read all widths in next pass
4001		_fnApplyToChildren( function(nSizer) {
4002			headerContent.push( nSizer.innerHTML );
4003			headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
4004		}, headerSrcEls );
4005	
4006		// Apply all widths in final pass
4007		_fnApplyToChildren( function(nToSize, i) {
4008			// Only apply widths to the DataTables detected header cells - this
4009			// prevents complex headers from having contradictory sizes applied
4010			if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
4011				nToSize.style.width = headerWidths[i];
4012			}
4013		}, headerTrgEls );
4014	
4015		$(headerSrcEls).height(0);
4016	
4017		/* Same again with the footer if we have one */
4018		if ( footer )
4019		{
4020			_fnApplyToChildren( zeroOut, footerSrcEls );
4021	
4022			_fnApplyToChildren( function(nSizer) {
4023				footerContent.push( nSizer.innerHTML );
4024				footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
4025			}, footerSrcEls );
4026	
4027			_fnApplyToChildren( function(nToSize, i) {
4028				nToSize.style.width = footerWidths[i];
4029			}, footerTrgEls );
4030	
4031			$(footerSrcEls).height(0);
4032		}
4033	
4034	
4035		/*
4036		 * 3. Apply the measurements
4037		 */
4038	
4039		// "Hide" the header and footer that we used for the sizing. We need to keep
4040		// the content of the cell so that the width applied to the header and body
4041		// both match, but we want to hide it completely. We want to also fix their
4042		// width to what they currently are
4043		_fnApplyToChildren( function(nSizer, i) {
4044			nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
4045			nSizer.style.width = headerWidths[i];
4046		}, headerSrcEls );
4047	
4048		if ( footer )
4049		{
4050			_fnApplyToChildren( function(nSizer, i) {
4051				nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
4052				nSizer.style.width = footerWidths[i];
4053			}, footerSrcEls );
4054		}
4055	
4056		// Sanity check that the table is of a sensible width. If not then we are going to get
4057		// misalignment - try to prevent this by not allowing the table to shrink below its min width
4058		if ( table.outerWidth() < sanityWidth )
4059		{
4060			// The min width depends upon if we have a vertical scrollbar visible or not */
4061			correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
4062				divBody.css('overflow-y') == "scroll")) ?
4063					sanityWidth+barWidth :
4064					sanityWidth;
4065	
4066			// IE6/7 are a law unto themselves...
4067			if ( ie67 && (divBodyEl.scrollHeight >
4068				divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
4069			) {
4070				tableStyle.width = _fnStringToCss( correction-barWidth );
4071			}
4072	
4073			// And give the user a warning that we've stopped the table getting too small
4074			if ( scrollX === "" || scrollXInner !== "" ) {
4075				_fnLog( settings, 1, 'Possible column misalignment', 6 );
4076			}
4077		}
4078		else
4079		{
4080			correction = '100%';
4081		}
4082	
4083		// Apply to the container elements
4084		divBodyStyle.width = _fnStringToCss( correction );
4085		divHeaderStyle.width = _fnStringToCss( correction );
4086	
4087		if ( footer ) {
4088			settings.nScrollFoot.style.width = _fnStringToCss( correction );
4089		}
4090	
4091	
4092		/*
4093		 * 4. Clean up
4094		 */
4095		if ( ! scrollY ) {
4096			/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
4097			 * the scrollbar height from the visible display, rather than adding it on. We need to
4098			 * set the height in order to sort this. Don't want to do it in any other browsers.
4099			 */
4100			if ( ie67 ) {
4101				divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
4102			}
4103		}
4104	
4105		/* Finally set the width's of the header and footer tables */
4106		var iOuterWidth = table.outerWidth();
4107		divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
4108		divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
4109	
4110		// Figure out if there are scrollbar present - if so then we need a the header and footer to
4111		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
4112		var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
4113		var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
4114		divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
4115	
4116		if ( footer ) {
4117			divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
4118			divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
4119			divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
4120		}
4121	
4122		// Correct DOM ordering for colgroup - comes before the thead
4123		table.children('colgroup').insertBefore( table.children('thead') );
4124	
4125		/* Adjust the position of the header in case we loose the y-scrollbar */
4126		divBody.scroll();
4127	
4128		// If sorting or filtering has occurred, jump the scrolling back to the top
4129		// only if we aren't holding the position
4130		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
4131			divBodyEl.scrollTop = 0;
4132		}
4133	}
4134	
4135	
4136	
4137	/**
4138	 * Apply a given function to the display child nodes of an element array (typically
4139	 * TD children of TR rows
4140	 *  @param {function} fn Method to apply to the objects
4141	 *  @param array {nodes} an1 List of elements to look through for display children
4142	 *  @param array {nodes} an2 Another list (identical structure to the first) - optional
4143	 *  @memberof DataTable#oApi
4144	 */
4145	function _fnApplyToChildren( fn, an1, an2 )
4146	{
4147		var index=0, i=0, iLen=an1.length;
4148		var nNode1, nNode2;
4149	
4150		while ( i < iLen ) {
4151			nNode1 = an1[i].firstChild;
4152			nNode2 = an2 ? an2[i].firstChild : null;
4153	
4154			while ( nNode1 ) {
4155				if ( nNode1.nodeType === 1 ) {
4156					if ( an2 ) {
4157						fn( nNode1, nNode2, index );
4158					}
4159					else {
4160						fn( nNode1, index );
4161					}
4162	
4163					index++;
4164				}
4165	
4166				nNode1 = nNode1.nextSibling;
4167				nNode2 = an2 ? nNode2.nextSibling : null;
4168			}
4169	
4170			i++;
4171		}
4172	}
4173	
4174	
4175	
4176	var __re_html_remove = /<.*?>/g;
4177	
4178	
4179	/**
4180	 * Calculate the width of columns for the table
4181	 *  @param {object} oSettings dataTables settings object
4182	 *  @memberof DataTable#oApi
4183	 */
4184	function _fnCalculateColumnWidths ( oSettings )
4185	{
4186		var
4187			table = oSettings.nTable,
4188			columns = oSettings.aoColumns,
4189			scroll = oSettings.oScroll,
4190			scrollY = scroll.sY,
4191			scrollX = scroll.sX,
4192			scrollXInner = scroll.sXInner,
4193			columnCount = columns.length,
4194			visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4195			headerCells = $('th', oSettings.nTHead),
4196			tableWidthAttr = table.getAttribute('width'), // from DOM element
4197			tableContainer = table.parentNode,
4198			userInputs = false,
4199			i, column, columnIdx, width, outerWidth,
4200			browser = oSettings.oBrowser,
4201			ie67 = browser.bScrollOversize;
4202	
4203		var styleWidth = table.style.width;
4204		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
4205			tableWidthAttr = styleWidth;
4206		}
4207	
4208		/* Convert any user input sizes into pixel sizes */
4209		for ( i=0 ; i<visibleColumns.length ; i++ ) {
4210			column = columns[ visibleColumns[i] ];
4211	
4212			if ( column.sWidth !== null ) {
4213				column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4214	
4215				userInputs = true;
4216			}
4217		}
4218	
4219		/* If the number of columns in the DOM equals the number that we have to
4220		 * process in DataTables, then we can use the offsets that are created by
4221		 * the web- browser. No custom sizes can be set in order for this to happen,
4222		 * nor scrolling used
4223		 */
4224		if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
4225		     columnCount == _fnVisbleColumns( oSettings ) &&
4226		     columnCount == headerCells.length
4227		) {
4228			for ( i=0 ; i<columnCount ; i++ ) {
4229				var colIdx = _fnVisibleToColumnIndex( oSettings, i );
4230	
4231				if ( colIdx !== null ) {
4232					columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4233				}
4234			}
4235		}
4236		else
4237		{
4238			// Otherwise construct a single row, worst case, table with the widest
4239			// node in the data, assign any user defined widths, then insert it into
4240			// the DOM and allow the browser to do all the hard work of calculating
4241			// table widths
4242			var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4243				.css( 'visibility', 'hidden' )
4244				.removeAttr( 'id' );
4245	
4246			// Clean up the table body
4247			tmpTable.find('tbody tr').remove();
4248			var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
4249	
4250			// Clone the table header and footer - we can't use the header / footer
4251			// from the cloned table, since if scrolling is active, the table's
4252			// real header and footer are contained in different table tags
4253			tmpTable.find('thead, tfoot').remove();
4254			tmpTable
4255				.append( $(oSettings.nTHead).clone() )
4256				.append( $(oSettings.nTFoot).clone() );
4257	
4258			// Remove any assigned widths from the footer (from scrolling)
4259			tmpTable.find('tfoot th, tfoot td').css('width', '');
4260	
4261			// Apply custom sizing to the cloned header
4262			headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4263	
4264			for ( i=0 ; i<visibleColumns.length ; i++ ) {
4265				column = columns[ visibleColumns[i] ];
4266	
4267				headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4268					_fnStringToCss( column.sWidthOrig ) :
4269					'';
4270	
4271				// For scrollX we need to force the column width otherwise the
4272				// browser will collapse it. If this width is smaller than the
4273				// width the column requires, then it will have no effect
4274				if ( column.sWidthOrig && scrollX ) {
4275					$( headerCells[i] ).append( $('<div/>').css( {
4276						width: column.sWidthOrig,
4277						margin: 0,
4278						padding: 0,
4279						border: 0,
4280						height: 1
4281					} ) );
4282				}
4283			}
4284	
4285			// Find the widest cell for each column and put it into the table
4286			if ( oSettings.aoData.length ) {
4287				for ( i=0 ; i<visibleColumns.length ; i++ ) {
4288					columnIdx = visibleColumns[i];
4289					column = columns[ columnIdx ];
4290	
4291					$( _fnGetWidestNode( oSettings, columnIdx ) )
4292						.clone( false )
4293						.append( column.sContentPadding )
4294						.appendTo( tr );
4295				}
4296			}
4297	
4298			// Tidy the temporary table - remove name attributes so there aren't
4299			// duplicated in the dom (radio elements for example)
4300			$('[name]', tmpTable).removeAttr('name');
4301	
4302			// Table has been built, attach to the document so we can work with it.
4303			// A holding element is used, positioned at the top of the container
4304			// with minimal height, so it has no effect on if the container scrolls
4305			// or not. Otherwise it might trigger scrolling when it actually isn't
4306			// needed
4307			var holder = $('<div/>').css( scrollX || scrollY ?
4308					{
4309						position: 'absolute',
4310						top: 0,
4311						left: 0,
4312						height: 1,
4313						right: 0,
4314						overflow: 'hidden'
4315					} :
4316					{}
4317				)
4318				.append( tmpTable )
4319				.appendTo( tableContainer );
4320	
4321			// When scrolling (X or Y) we want to set the width of the table as 
4322			// appropriate. However, when not scrolling leave the table width as it
4323			// is. This results in slightly different, but I think correct behaviour
4324			if ( scrollX && scrollXInner ) {
4325				tmpTable.width( scrollXInner );
4326			}
4327			else if ( scrollX ) {
4328				tmpTable.css( 'width', 'auto' );
4329				tmpTable.removeAttr('width');
4330	
4331				// If there is no width attribute or style, then allow the table to
4332				// collapse
4333				if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
4334					tmpTable.width( tableContainer.clientWidth );
4335				}
4336			}
4337			else if ( scrollY ) {
4338				tmpTable.width( tableContainer.clientWidth );
4339			}
4340			else if ( tableWidthAttr ) {
4341				tmpTable.width( tableWidthAttr );
4342			}
4343	
4344			// Get the width of each column in the constructed table - we need to
4345			// know the inner width (so it can be assigned to the other table's
4346			// cells) and the outer width so we can calculate the full width of the
4347			// table. This is safe since DataTables requires a unique cell for each
4348			// column, but if ever a header can span multiple columns, this will
4349			// need to be modified.
4350			var total = 0;
4351			for ( i=0 ; i<visibleColumns.length ; i++ ) {
4352				var cell = $(headerCells[i]);
4353				var border = cell.outerWidth() - cell.width();
4354	
4355				// Use getBounding... where possible (not IE8-) because it can give
4356				// sub-pixel accuracy, which we then want to round up!
4357				var bounding = browser.bBounding ?
4358					Math.ceil( headerCells[i].getBoundingClientRect().width ) :
4359					cell.outerWidth();
4360	
4361				// Total is tracked to remove any sub-pixel errors as the outerWidth
4362				// of the table might not equal the total given here (IE!).
4363				total += bounding;
4364	
4365				// Width for each column to use
4366				columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
4367			}
4368	
4369			table.style.width = _fnStringToCss( total );
4370	
4371			// Finished with the table - ditch it
4372			holder.remove();
4373		}
4374	
4375		// If there is a width attr, we want to attach an event listener which
4376		// allows the table sizing to automatically adjust when the window is
4377		// resized. Use the width attr rather than CSS, since we can't know if the
4378		// CSS is a relative value or absolute - DOM read is always px.
4379		if ( tableWidthAttr ) {
4380			table.style.width = _fnStringToCss( tableWidthAttr );
4381		}
4382	
4383		if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4384			var bindResize = function () {
4385				$(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4386					_fnAdjustColumnSizing( oSettings );
4387				} ) );
4388			};
4389	
4390			// IE6/7 will crash if we bind a resize event handler on page load.
4391			// To be removed in 1.11 which drops IE6/7 support
4392			if ( ie67 ) {
4393				setTimeout( bindResize, 1000 );
4394			}
4395			else {
4396				bindResize();
4397			}
4398	
4399			oSettings._reszEvt = true;
4400		}
4401	}
4402	
4403	
4404	/**
4405	 * Throttle the calls to a function. Arguments and context are maintained for
4406	 * the throttled function
4407	 *  @param {function} fn Function to be called
4408	 *  @param {int} [freq=200] call frequency in mS
4409	 *  @returns {function} wrapped function
4410	 *  @memberof DataTable#oApi
4411	 */
4412	function _fnThrottle( fn, freq ) {
4413		var
4414			frequency = freq !== undefined ? freq : 200,
4415			last,
4416			timer;
4417	
4418		return function () {
4419			var
4420				that = this,
4421				now  = +new Date(),
4422				args = arguments;
4423	
4424			if ( last && now < last + frequency ) {
4425				clearTimeout( timer );
4426	
4427				timer = setTimeout( function () {
4428					last = undefined;
4429					fn.apply( that, args );
4430				}, frequency );
4431			}
4432			else {
4433				last = now;
4434				fn.apply( that, args );
4435			}
4436		};
4437	}
4438	
4439	
4440	/**
4441	 * Convert a CSS unit width to pixels (e.g. 2em)
4442	 *  @param {string} width width to be converted
4443	 *  @param {node} parent parent to get the with for (required for relative widths) - optional
4444	 *  @returns {int} width in pixels
4445	 *  @memberof DataTable#oApi
4446	 */
4447	function _fnConvertToWidth ( width, parent )
4448	{
4449		if ( ! width ) {
4450			return 0;
4451		}
4452	
4453		var n = $('<div/>')
4454			.css( 'width', _fnStringToCss( width ) )
4455			.appendTo( parent || document.body );
4456	
4457		var val = n[0].offsetWidth;
4458		n.remove();
4459	
4460		return val;
4461	}
4462	
4463	
4464	/**
4465	 * Get the widest node
4466	 *  @param {object} settings dataTables settings object
4467	 *  @param {int} colIdx column of interest
4468	 *  @returns {node} widest table node
4469	 *  @memberof DataTable#oApi
4470	 */
4471	function _fnGetWidestNode( settings, colIdx )
4472	{
4473		var idx = _fnGetMaxLenString( settings, colIdx );
4474		if ( idx < 0 ) {
4475			return null;
4476		}
4477	
4478		var data = settings.aoData[ idx ];
4479		return ! data.nTr ? // Might not have been created when deferred rendering
4480			$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4481			data.anCells[ colIdx ];
4482	}
4483	
4484	
4485	/**
4486	 * Get the maximum strlen for each data column
4487	 *  @param {object} settings dataTables settings object
4488	 *  @param {int} colIdx column of interest
4489	 *  @returns {string} max string length for each column
4490	 *  @memberof DataTable#oApi
4491	 */
4492	function _fnGetMaxLenString( settings, colIdx )
4493	{
4494		var s, max=-1, maxIdx = -1;
4495	
4496		for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4497			s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4498			s = s.replace( __re_html_remove, '' );
4499			s = s.replace( /&nbsp;/g, ' ' );
4500	
4501			if ( s.length > max ) {
4502				max = s.length;
4503				maxIdx = i;
4504			}
4505		}
4506	
4507		return maxIdx;
4508	}
4509	
4510	
4511	/**
4512	 * Append a CSS unit (only if required) to a string
4513	 *  @param {string} value to css-ify
4514	 *  @returns {string} value with css unit
4515	 *  @memberof DataTable#oApi
4516	 */
4517	function _fnStringToCss( s )
4518	{
4519		if ( s === null ) {
4520			return '0px';
4521		}
4522	
4523		if ( typeof s == 'number' ) {
4524			return s < 0 ?
4525				'0px' :
4526				s+'px';
4527		}
4528	
4529		// Check it has a unit character already
4530		return s.match(/\d$/) ?
4531			s+'px' :
4532			s;
4533	}
4534	
4535	
4536	
4537	function _fnSortFlatten ( settings )
4538	{
4539		var
4540			i, iLen, k, kLen,
4541			aSort = [],
4542			aiOrig = [],
4543			aoColumns = settings.aoColumns,
4544			aDataSort, iCol, sType, srcCol,
4545			fixed = settings.aaSortingFixed,
4546			fixedObj = $.isPlainObject( fixed ),
4547			nestedSort = [],
4548			add = function ( a ) {
4549				if ( a.length && ! $.isArray( a[0] ) ) {
4550					// 1D array
4551					nestedSort.push( a );
4552				}
4553				else {
4554					// 2D array
4555					$.merge( nestedSort, a );
4556				}
4557			};
4558	
4559		// Build the sort array, with pre-fix and post-fix options if they have been
4560		// specified
4561		if ( $.isArray( fixed ) ) {
4562			add( fixed );
4563		}
4564	
4565		if ( fixedObj && fixed.pre ) {
4566			add( fixed.pre );
4567		}
4568	
4569		add( settings.aaSorting );
4570	
4571		if (fixedObj && fixed.post ) {
4572			add( fixed.post );
4573		}
4574	
4575		for ( i=0 ; i<nestedSort.length ; i++ )
4576		{
4577			srcCol = nestedSort[i][0];
4578			aDataSort = aoColumns[ srcCol ].aDataSort;
4579	
4580			for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4581			{
4582				iCol = aDataSort[k];
4583				sType = aoColumns[ iCol ].sType || 'string';
4584	
4585				if ( nestedSort[i]._idx === undefined ) {
4586					nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4587				}
4588	
4589				aSort.push( {
4590					src:       srcCol,
4591					col:       iCol,
4592					dir:       nestedSort[i][1],
4593					index:     nestedSort[i]._idx,
4594					type:      sType,
4595					formatter: DataTable.ext.type.order[ sType+"-pre" ]
4596				} );
4597			}
4598		}
4599	
4600		return aSort;
4601	}
4602	
4603	/**
4604	 * Change the order of the table
4605	 *  @param {object} oSettings dataTables settings object
4606	 *  @memberof DataTable#oApi
4607	 *  @todo This really needs split up!
4608	 */
4609	function _fnSort ( oSettings )
4610	{
4611		var
4612			i, ien, iLen, j, jLen, k, kLen,
4613			sDataType, nTh,
4614			aiOrig = [],
4615			oExtSort = DataTable.ext.type.order,
4616			aoData = oSettings.aoData,
4617			aoColumns = oSettings.aoColumns,
4618			aDataSort, data, iCol, sType, oSort,
4619			formatters = 0,
4620			sortCol,
4621			displayMaster = oSettings.aiDisplayMaster,
4622			aSort;
4623	
4624		// Resolve any column types that are unknown due to addition or invalidation
4625		// @todo Can this be moved into a 'data-ready' handler which is called when
4626		//   data is going to be used in the table?
4627		_fnColumnTypes( oSettings );
4628	
4629		aSort = _fnSortFlatten( oSettings );
4630	
4631		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4632			sortCol = aSort[i];
4633	
4634			// Track if we can use the fast sort algorithm
4635			if ( sortCol.formatter ) {
4636				formatters++;
4637			}
4638	
4639			// Load the data needed for the sort, for each cell
4640			_fnSortData( oSettings, sortCol.col );
4641		}
4642	
4643		/* No sorting required if server-side or no sorting array */
4644		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4645		{
4646			// Create a value - key array of the current row positions such that we can use their
4647			// current position during the sort, if values match, in order to perform stable sorting
4648			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4649				aiOrig[ displayMaster[i] ] = i;
4650			}
4651	
4652			/* Do the sort - here we want multi-column sorting based on a given data source (column)
4653			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4654			 * follow on it's own, but this is what we want (example two column sorting):
4655			 *  fnLocalSorting = function(a,b){
4656			 *    var iTest;
4657			 *    iTest = oSort['string-asc']('data11', 'data12');
4658			 *      if (iTest !== 0)
4659			 *        return iTest;
4660			 *    iTest = oSort['numeric-desc']('data21', 'data22');
4661			 *    if (iTest !== 0)
4662			 *      return iTest;
4663			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4664			 *  }
4665			 * Basically we have a test for each sorting column, if the data in that column is equal,
4666			 * test the next column. If all columns match, then we use a numeric sort on the row
4667			 * positions in the original data array to provide a stable sort.
4668			 *
4669			 * Note - I know it seems excessive to have two sorting methods, but the first is around
4670			 * 15% faster, so the second is only maintained for backwards compatibility with sorting
4671			 * methods which do not have a pre-sort formatting function.
4672			 */
4673			if ( formatters === aSort.length ) {
4674				// All sort types have formatting functions
4675				displayMaster.sort( function ( a, b ) {
4676					var
4677						x, y, k, test, sort,
4678						len=aSort.length,
4679						dataA = aoData[a]._aSortData,
4680						dataB = aoData[b]._aSortData;
4681	
4682					for ( k=0 ; k<len ; k++ ) {
4683						sort = aSort[k];
4684	
4685						x = dataA[ sort.col ];
4686						y = dataB[ sort.col ];
4687	
4688						test = x<y ? -1 : x>y ? 1 : 0;
4689						if ( test !== 0 ) {
4690							return sort.dir === 'asc' ? test : -test;
4691						}
4692					}
4693	
4694					x = aiOrig[a];
4695					y = aiOrig[b];
4696					return x<y ? -1 : x>y ? 1 : 0;
4697				} );
4698			}
4699			else {
4700				// Depreciated - remove in 1.11 (providing a plug-in option)
4701				// Not all sort types have formatting methods, so we have to call their sorting
4702				// methods.
4703				displayMaster.sort( function ( a, b ) {
4704					var
4705						x, y, k, l, test, sort, fn,
4706						len=aSort.length,
4707						dataA = aoData[a]._aSortData,
4708						dataB = aoData[b]._aSortData;
4709	
4710					for ( k=0 ; k<len ; k++ ) {
4711						sort = aSort[k];
4712	
4713						x = dataA[ sort.col ];
4714						y = dataB[ sort.col ];
4715	
4716						fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4717						test = fn( x, y );
4718						if ( test !== 0 ) {
4719							return test;
4720						}
4721					}
4722	
4723					x = aiOrig[a];
4724					y = aiOrig[b];
4725					return x<y ? -1 : x>y ? 1 : 0;
4726				} );
4727			}
4728		}
4729	
4730		/* Tell the draw function that we have sorted the data */
4731		oSettings.bSorted = true;
4732	}
4733	
4734	
4735	function _fnSortAria ( settings )
4736	{
4737		var label;
4738		var nextSort;
4739		var columns = settings.aoColumns;
4740		var aSort = _fnSortFlatten( settings );
4741		var oAria = settings.oLanguage.oAria;
4742	
4743		// ARIA attributes - need to loop all columns, to update all (removing old
4744		// attributes as needed)
4745		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4746		{
4747			var col = columns[i];
4748			var asSorting = col.asSorting;
4749			var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4750			var th = col.nTh;
4751	
4752			// IE7 is throwing an error when setting these properties with jQuery's
4753			// attr() and removeAttr() methods...
4754			th.removeAttribute('aria-sort');
4755	
4756			/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4757			if ( col.bSortable ) {
4758				if ( aSort.length > 0 && aSort[0].col == i ) {
4759					th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4760					nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4761				}
4762				else {
4763					nextSort = asSorting[0];
4764				}
4765	
4766				label = sTitle + ( nextSort === "asc" ?
4767					oAria.sSortAscending :
4768					oAria.sSortDescending
4769				);
4770			}
4771			else {
4772				label = sTitle;
4773			}
4774	
4775			th.setAttribute('aria-label', label);
4776		}
4777	}
4778	
4779	
4780	/**
4781	 * Function to run on user sort request
4782	 *  @param {object} settings dataTables settings object
4783	 *  @param {node} attachTo node to attach the handler to
4784	 *  @param {int} colIdx column sorting index
4785	 *  @param {boolean} [append=false] Append the requested sort to the existing
4786	 *    sort if true (i.e. multi-column sort)
4787	 *  @param {function} [callback] callback function
4788	 *  @memberof DataTable#oApi
4789	 */
4790	function _fnSortListener ( settings, colIdx, append, callback )
4791	{
4792		var col = settings.aoColumns[ colIdx ];
4793		var sorting = settings.aaSorting;
4794		var asSorting = col.asSorting;
4795		var nextSortIdx;
4796		var next = function ( a, overflow ) {
4797			var idx = a._idx;
4798			if ( idx === undefined ) {
4799				idx = $.inArray( a[1], asSorting );
4800			}
4801	
4802			return idx+1 < asSorting.length ?
4803				idx+1 :
4804				overflow ?
4805					null :
4806					0;
4807		};
4808	
4809		// Convert to 2D array if needed
4810		if ( typeof sorting[0] === 'number' ) {
4811			sorting = settings.aaSorting = [ sorting ];
4812		}
4813	
4814		// If appending the sort then we are multi-column sorting
4815		if ( append && settings.oFeatures.bSortMulti ) {
4816			// Are we already doing some kind of sort on this column?
4817			var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4818	
4819			if ( sortIdx !== -1 ) {
4820				// Yes, modify the sort
4821				nextSortIdx = next( sorting[sortIdx], true );
4822	
4823				if ( nextSortIdx === null && sorting.length === 1 ) {
4824					nextSortIdx = 0; // can't remove sorting completely
4825				}
4826	
4827				if ( nextSortIdx === null ) {
4828					sorting.splice( sortIdx, 1 );
4829				}
4830				else {
4831					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4832					sorting[sortIdx]._idx = nextSortIdx;
4833				}
4834			}
4835			else {
4836				// No sort on this column yet
4837				sorting.push( [ colIdx, asSorting[0], 0 ] );
4838				sorting[sorting.length-1]._idx = 0;
4839			}
4840		}
4841		else if ( sorting.length && sorting[0][0] == colIdx ) {
4842			// Single column - already sorting on this column, modify the sort
4843			nextSortIdx = next( sorting[0] );
4844	
4845			sorting.length = 1;
4846			sorting[0][1] = asSorting[ nextSortIdx ];
4847			sorting[0]._idx = nextSortIdx;
4848		}
4849		else {
4850			// Single column - sort only on this column
4851			sorting.length = 0;
4852			sorting.push( [ colIdx, asSorting[0] ] );
4853			sorting[0]._idx = 0;
4854		}
4855	
4856		// Run the sort by calling a full redraw
4857		_fnReDraw( settings );
4858	
4859		// callback used for async user interaction
4860		if ( typeof callback == 'function' ) {
4861			callback( settings );
4862		}
4863	}
4864	
4865	
4866	/**
4867	 * Attach a sort handler (click) to a node
4868	 *  @param {object} settings dataTables settings object
4869	 *  @param {node} attachTo node to attach the handler to
4870	 *  @param {int} colIdx column sorting index
4871	 *  @param {function} [callback] callback function
4872	 *  @memberof DataTable#oApi
4873	 */
4874	function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4875	{
4876		var col = settings.aoColumns[ colIdx ];
4877	
4878		_fnBindAction( attachTo, {}, function (e) {
4879			/* If the column is not sortable - don't to anything */
4880			if ( col.bSortable === false ) {
4881				return;
4882			}
4883	
4884			// If processing is enabled use a timeout to allow the processing
4885			// display to be shown - otherwise to it synchronously
4886			if ( settings.oFeatures.bProcessing ) {
4887				_fnProcessingDisplay( settings, true );
4888	
4889				setTimeout( function() {
4890					_fnSortListener( settings, colIdx, e.shiftKey, callback );
4891	
4892					// In server-side processing, the draw callback will remove the
4893					// processing display
4894					if ( _fnDataSource( settings ) !== 'ssp' ) {
4895						_fnProcessingDisplay( settings, false );
4896					}
4897				}, 0 );
4898			}
4899			else {
4900				_fnSortListener( settings, colIdx, e.shiftKey, callback );
4901			}
4902		} );
4903	}
4904	
4905	
4906	/**
4907	 * Set the sorting classes on table's body, Note: it is safe to call this function
4908	 * when bSort and bSortClasses are false
4909	 *  @param {object} oSettings dataTables settings object
4910	 *  @memberof DataTable#oApi
4911	 */
4912	function _fnSortingClasses( settings )
4913	{
4914		var oldSort = settings.aLastSort;
4915		var sortClass = settings.oClasses.sSortColumn;
4916		var sort = _fnSortFlatten( settings );
4917		var features = settings.oFeatures;
4918		var i, ien, colIdx;
4919	
4920		if ( features.bSort && features.bSortClasses ) {
4921			// Remove old sorting classes
4922			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4923				colIdx = oldSort[i].src;
4924	
4925				// Remove column sorting
4926				$( _pluck( settings.aoData, 'anCells', colIdx ) )
4927					.removeClass( sortClass + (i<2 ? i+1 : 3) );
4928			}
4929	
4930			// Add new column sorting
4931			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4932				colIdx = sort[i].src;
4933	
4934				$( _pluck( settings.aoData, 'anCells', colIdx ) )
4935					.addClass( sortClass + (i<2 ? i+1 : 3) );
4936			}
4937		}
4938	
4939		settings.aLastSort = sort;
4940	}
4941	
4942	
4943	// Get the data to sort a column, be it from cache, fresh (populating the
4944	// cache), or from a sort formatter
4945	function _fnSortData( settings, idx )
4946	{
4947		// Custom sorting function - provided by the sort data type
4948		var column = settings.aoColumns[ idx ];
4949		var customSort = DataTable.ext.order[ column.sSortDataType ];
4950		var customData;
4951	
4952		if ( customSort ) {
4953			customData = customSort.call( settings.oInstance, settings, idx,
4954				_fnColumnIndexToVisible( settings, idx )
4955			);
4956		}
4957	
4958		// Use / populate cache
4959		var row, cellData;
4960		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4961	
4962		for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4963			row = settings.aoData[i];
4964	
4965			if ( ! row._aSortData ) {
4966				row._aSortData = [];
4967			}
4968	
4969			if ( ! row._aSortData[idx] || customSort ) {
4970				cellData = customSort ?
4971					customData[i] : // If there was a custom sort function, use data from there
4972					_fnGetCellData( settings, i, idx, 'sort' );
4973	
4974				row._aSortData[ idx ] = formatter ?
4975					formatter( cellData ) :
4976					cellData;
4977			}
4978		}
4979	}
4980	
4981	
4982	
4983	/**
4984	 * Save the state of a table
4985	 *  @param {object} oSettings dataTables settings object
4986	 *  @memberof DataTable#oApi
4987	 */
4988	function _fnSaveState ( settings )
4989	{
4990		if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4991		{
4992			return;
4993		}
4994	
4995		/* Store the interesting variables */
4996		var state = {
4997			time:    +new Date(),
4998			start:   settings._iDisplayStart,
4999			length:  settings._iDisplayLength,
5000			order:   $.extend( true, [], settings.aaSorting ),
5001			search:  _fnSearchToCamel( settings.oPreviousSearch ),
5002			columns: $.map( settings.aoColumns, function ( col, i ) {
5003				return {
5004					visible: col.bVisible,
5005					search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
5006				};
5007			} )
5008		};
5009	
5010		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
5011	
5012		settings.oSavedState = state;
5013		settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
5014	}
5015	
5016	
5017	/**
5018	 * Attempt to load a saved table state
5019	 *  @param {object} oSettings dataTables settings object
5020	 *  @param {object} oInit DataTables init object so we can override settings
5021	 *  @memberof DataTable#oApi
5022	 */
5023	function _fnLoadState ( settings, oInit )
5024	{
5025		var i, ien;
5026		var columns = settings.aoColumns;
5027	
5028		if ( ! settings.oFeatures.bStateSave ) {
5029			return;
5030		}
5031	
5032		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
5033		if ( ! state || ! state.time ) {
5034			return;
5035		}
5036	
5037		/* Allow custom and plug-in manipulation functions to alter the saved data set and
5038		 * cancelling of loading by returning false
5039		 */
5040		var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
5041		if ( $.inArray( false, abStateLoad ) !== -1 ) {
5042			return;
5043		}
5044	
5045		/* Reject old data */
5046		var duration = settings.iStateDuration;
5047		if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
5048			return;
5049		}
5050	
5051		// Number of columns have changed - all bets are off, no restore of settings
5052		if ( columns.length !== state.columns.length ) {
5053			return;
5054		}
5055	
5056		// Store the saved state so it might be accessed at any time
5057		settings.oLoadedState = $.extend( true, {}, state );
5058	
5059		// Restore key features - todo - for 1.11 this needs to be done by
5060		// subscribed events
5061		if ( state.start !== undefined ) {
5062			settings._iDisplayStart    = state.start;
5063			settings.iInitDisplayStart = state.start;
5064		}
5065		if ( state.length !== undefined ) {
5066			settings._iDisplayLength   = state.length;
5067		}
5068	
5069		// Order
5070		if ( state.order !== undefined ) {
5071			settings.aaSorting = [];
5072			$.each( state.order, function ( i, col ) {
5073				settings.aaSorting.push( col[0] >= columns.length ?
5074					[ 0, col[1] ] :
5075					col
5076				);
5077			} );
5078		}
5079	
5080		// Search
5081		if ( state.search !== undefined ) {
5082			$.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
5083		}
5084	
5085		// Columns
5086		for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
5087			var col = state.columns[i];
5088	
5089			// Visibility
5090			if ( col.visible !== undefined ) {
5091				columns[i].bVisible = col.visible;
5092			}
5093	
5094			// Search
5095			if ( col.search !== undefined ) {
5096				$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
5097			}
5098		}
5099	
5100		_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
5101	}
5102	
5103	
5104	/**
5105	 * Return the settings object for a particular table
5106	 *  @param {node} table table we are using as a dataTable
5107	 *  @returns {object} Settings object - or null if not found
5108	 *  @memberof DataTable#oApi
5109	 */
5110	function _fnSettingsFromNode ( table )
5111	{
5112		var settings = DataTable.settings;
5113		var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
5114	
5115		return idx !== -1 ?
5116			settings[ idx ] :
5117			null;
5118	}
5119	
5120	
5121	/**
5122	 * Log an error message
5123	 *  @param {object} settings dataTables settings object
5124	 *  @param {int} level log error messages, or display them to the user
5125	 *  @param {string} msg error message
5126	 *  @param {int} tn Technical note id to get more information about the error.
5127	 *  @memberof DataTable#oApi
5128	 */
5129	function _fnLog( settings, level, msg, tn )
5130	{
5131		msg = 'DataTables warning: '+
5132			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
5133	
5134		if ( tn ) {
5135			msg += '. For more information about this error, please see '+
5136			'http://datatables.net/tn/'+tn;
5137		}
5138	
5139		if ( ! level  ) {
5140			// Backwards compatibility pre 1.10
5141			var ext = DataTable.ext;
5142			var type = ext.sErrMode || ext.errMode;
5143	
5144			if ( settings ) {
5145				_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
5146			}
5147	
5148			if ( type == 'alert' ) {
5149				alert( msg );
5150			}
5151			else if ( type == 'throw' ) {
5152				throw new Error(msg);
5153			}
5154			else if ( typeof type == 'function' ) {
5155				type( settings, tn, msg );
5156			}
5157		}
5158		else if ( window.console && console.log ) {
5159			console.log( msg );
5160		}
5161	}
5162	
5163	
5164	/**
5165	 * See if a property is defined on one object, if so assign it to the other object
5166	 *  @param {object} ret target object
5167	 *  @param {object} src source object
5168	 *  @param {string} name property
5169	 *  @param {string} [mappedName] name to map too - optional, name used if not given
5170	 *  @memberof DataTable#oApi
5171	 */
5172	function _fnMap( ret, src, name, mappedName )
5173	{
5174		if ( $.isArray( name ) ) {
5175			$.each( name, function (i, val) {
5176				if ( $.isArray( val ) ) {
5177					_fnMap( ret, src, val[0], val[1] );
5178				}
5179				else {
5180					_fnMap( ret, src, val );
5181				}
5182			} );
5183	
5184			return;
5185		}
5186	
5187		if ( mappedName === undefined ) {
5188			mappedName = name;
5189		}
5190	
5191		if ( src[name] !== undefined ) {
5192			ret[mappedName] = src[name];
5193		}
5194	}
5195	
5196	
5197	/**
5198	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
5199	 * shallow copy arrays. The reason we need to do this, is that we don't want to
5200	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
5201	 * able to override them, but we do want to deep copy arrays.
5202	 *  @param {object} out Object to extend
5203	 *  @param {object} extender Object from which the properties will be applied to
5204	 *      out
5205	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
5206	 *      independent copy with the exception of the `data` or `aaData` parameters
5207	 *      if they are present. This is so you can pass in a collection to
5208	 *      DataTables and have that used as your data source without breaking the
5209	 *      references
5210	 *  @returns {object} out Reference, just for convenience - out === the return.
5211	 *  @memberof DataTable#oApi
5212	 *  @todo This doesn't take account of arrays inside the deep copied objects.
5213	 */
5214	function _fnExtend( out, extender, breakRefs )
5215	{
5216		var val;
5217	
5218		for ( var prop in extender ) {
5219			if ( extender.hasOwnProperty(prop) ) {
5220				val = extender[prop];
5221	
5222				if ( $.isPlainObject( val ) ) {
5223					if ( ! $.isPlainObject( out[prop] ) ) {
5224						out[prop] = {};
5225					}
5226					$.extend( true, out[prop], val );
5227				}
5228				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5229					out[prop] = val.slice();
5230				}
5231				else {
5232					out[prop] = val;
5233				}
5234			}
5235		}
5236	
5237		return out;
5238	}
5239	
5240	
5241	/**
5242	 * Bind an event handers to allow a click or return key to activate the callback.
5243	 * This is good for accessibility since a return on the keyboard will have the
5244	 * same effect as a click, if the element has focus.
5245	 *  @param {element} n Element to bind the action to
5246	 *  @param {object} oData Data object to pass to the triggered function
5247	 *  @param {function} fn Callback function for when the event is triggered
5248	 *  @memberof DataTable#oApi
5249	 */
5250	function _fnBindAction( n, oData, fn )
5251	{
5252		$(n)
5253			.bind( 'click.DT', oData, function (e) {
5254					n.blur(); // Remove focus outline for mouse users
5255					fn(e);
5256				} )
5257			.bind( 'keypress.DT', oData, function (e){
5258					if ( e.which === 13 ) {
5259						e.preventDefault();
5260						fn(e);
5261					}
5262				} )
5263			.bind( 'selectstart.DT', function () {
5264					/* Take the brutal approach to cancelling text selection */
5265					return false;
5266				} );
5267	}
5268	
5269	
5270	/**
5271	 * Register a callback function. Easily allows a callback function to be added to
5272	 * an array store of callback functions that can then all be called together.
5273	 *  @param {object} oSettings dataTables settings object
5274	 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
5275	 *  @param {function} fn Function to be called back
5276	 *  @param {string} sName Identifying name for the callback (i.e. a label)
5277	 *  @memberof DataTable#oApi
5278	 */
5279	function _fnCallbackReg( oSettings, sStore, fn, sName )
5280	{
5281		if ( fn )
5282		{
5283			oSettings[sStore].push( {
5284				"fn": fn,
5285				"sName": sName
5286			} );
5287		}
5288	}
5289	
5290	
5291	/**
5292	 * Fire callback functions and trigger events. Note that the loop over the
5293	 * callback array store is done backwards! Further note that you do not want to
5294	 * fire off triggers in time sensitive applications (for example cell creation)
5295	 * as its slow.
5296	 *  @param {object} settings dataTables settings object
5297	 *  @param {string} callbackArr Name of the array storage for the callbacks in
5298	 *      oSettings
5299	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
5300	 *      null no trigger is fired
5301	 *  @param {array} args Array of arguments to pass to the callback function /
5302	 *      trigger
5303	 *  @memberof DataTable#oApi
5304	 */
5305	function _fnCallbackFire( settings, callbackArr, eventName, args )
5306	{
5307		var ret = [];
5308	
5309		if ( callbackArr ) {
5310			ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5311				return val.fn.apply( settings.oInstance, args );
5312			} );
5313		}
5314	
5315		if ( eventName !== null ) {
5316			var e = $.Event( eventName+'.dt' );
5317	
5318			$(settings.nTable).trigger( e, args );
5319	
5320			ret.push( e.result );
5321		}
5322	
5323		return ret;
5324	}
5325	
5326	
5327	function _fnLengthOverflow ( settings )
5328	{
5329		var
5330			start = settings._iDisplayStart,
5331			end = settings.fnDisplayEnd(),
5332			len = settings._iDisplayLength;
5333	
5334		/* If we have space to show extra rows (backing up from the end point - then do so */
5335		if ( start >= end )
5336		{
5337			start = end - len;
5338		}
5339	
5340		// Keep the start record on the current page
5341		start -= (start % len);
5342	
5343		if ( len === -1 || start < 0 )
5344		{
5345			start = 0;
5346		}
5347	
5348		settings._iDisplayStart = start;
5349	}
5350	
5351	
5352	function _fnRenderer( settings, type )
5353	{
5354		var renderer = settings.renderer;
5355		var host = DataTable.ext.renderer[type];
5356	
5357		if ( $.isPlainObject( renderer ) && renderer[type] ) {
5358			// Specific renderer for this type. If available use it, otherwise use
5359			// the default.
5360			return host[renderer[type]] || host._;
5361		}
5362		else if ( typeof renderer === 'string' ) {
5363			// Common renderer - if there is one available for this type use it,
5364			// otherwise use the default
5365			return host[renderer] || host._;
5366		}
5367	
5368		// Use the default
5369		return host._;
5370	}
5371	
5372	
5373	/**
5374	 * Detect the data source being used for the table. Used to simplify the code
5375	 * a little (ajax) and to make it compress a little smaller.
5376	 *
5377	 *  @param {object} settings dataTables settings object
5378	 *  @returns {string} Data source
5379	 *  @memberof DataTable#oApi
5380	 */
5381	function _fnDataSource ( settings )
5382	{
5383		if ( settings.oFeatures.bServerSide ) {
5384			return 'ssp';
5385		}
5386		else if ( settings.ajax || settings.sAjaxSource ) {
5387			return 'ajax';
5388		}
5389		return 'dom';
5390	}
5391	
5392
5393	DataTable = function( options )
5394	{
5395		/**
5396		 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5397		 * return the resulting jQuery object.
5398		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5399		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
5400		 *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5401		 *    criterion ("applied") or all TR elements (i.e. no filter).
5402		 *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5403		 *    Can be either 'current', whereby the current sorting of the table is used, or
5404		 *    'original' whereby the original order the data was read into the table is used.
5405		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5406		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
5407		 *    'current' and filter is 'applied', regardless of what they might be given as.
5408		 *  @returns {object} jQuery object, filtered by the given selector.
5409		 *  @dtopt API
5410		 *  @deprecated Since v1.10
5411		 *
5412		 *  @example
5413		 *    $(document).ready(function() {
5414		 *      var oTable = $('#example').dataTable();
5415		 *
5416		 *      // Highlight every second row
5417		 *      oTable.$('tr:odd').css('backgroundColor', 'blue');
5418		 *    } );
5419		 *
5420		 *  @example
5421		 *    $(document).ready(function() {
5422		 *      var oTable = $('#example').dataTable();
5423		 *
5424		 *      // Filter to rows with 'Webkit' in them, add a background colour and then
5425		 *      // remove the filter, thus highlighting the 'Webkit' rows only.
5426		 *      oTable.fnFilter('Webkit');
5427		 *      oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5428		 *      oTable.fnFilter('');
5429		 *    } );
5430		 */
5431		this.$ = function ( sSelector, oOpts )
5432		{
5433			return this.api(true).$( sSelector, oOpts );
5434		};
5435		
5436		
5437		/**
5438		 * Almost identical to $ in operation, but in this case returns the data for the matched
5439		 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5440		 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5441		 * rows are found, the data returned is the original data array/object that was used to
5442		 * create the row (or a generated array if from a DOM source).
5443		 *
5444		 * This method is often useful in-combination with $ where both functions are given the
5445		 * same parameters and the array indexes will match identically.
5446		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5447		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
5448		 *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
5449		 *    criterion ("applied") or all elements (i.e. no filter).
5450		 *  @param {string} [oOpts.order=current] Order of the data in the processed array.
5451		 *    Can be either 'current', whereby the current sorting of the table is used, or
5452		 *    'original' whereby the original order the data was read into the table is used.
5453		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5454		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
5455		 *    'current' and filter is 'applied', regardless of what they might be given as.
5456		 *  @returns {array} Data for the matched elements. If any elements, as a result of the
5457		 *    selector, were not TR, TD or TH elements in the DataTable, they will have a null
5458		 *    entry in the array.
5459		 *  @dtopt API
5460		 *  @deprecated Since v1.10
5461		 *
5462		 *  @example
5463		 *    $(document).ready(function() {
5464		 *      var oTable = $('#example').dataTable();
5465		 *
5466		 *      // Get the data from the first row in the table
5467		 *      var data = oTable._('tr:first');
5468		 *
5469		 *      // Do something useful with the data
5470		 *      alert( "First cell is: "+data[0] );
5471		 *    } );
5472		 *
5473		 *  @example
5474		 *    $(document).ready(function() {
5475		 *      var oTable = $('#example').dataTable();
5476		 *
5477		 *      // Filter to 'Webkit' and get all data for
5478		 *      oTable.fnFilter('Webkit');
5479		 *      var data = oTable._('tr', {"search": "applied"});
5480		 *
5481		 *      // Do something with the data
5482		 *      alert( data.length+" rows matched the search" );
5483		 *    } );
5484		 */
5485		this._ = function ( sSelector, oOpts )
5486		{
5487			return this.api(true).rows( sSelector, oOpts ).data();
5488		};
5489		
5490		
5491		/**
5492		 * Create a DataTables Api instance, with the currently selected tables for
5493		 * the Api's context.
5494		 * @param {boolean} [traditional=false] Set the API instance's context to be
5495		 *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5496		 *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5497		 *   or if all tables captured in the jQuery object should be used.
5498		 * @return {DataTables.Api}
5499		 */
5500		this.api = function ( traditional )
5501		{
5502			return traditional ?
5503				new _Api(
5504					_fnSettingsFromNode( this[ _ext.iApiIndex ] )
5505				) :
5506				new _Api( this );
5507		};
5508		
5509		
5510		/**
5511		 * Add a single new row or multiple rows of data to the table. Please note
5512		 * that this is suitable for client-side processing only - if you are using
5513		 * server-side processing (i.e. "bServerSide": true), then to add data, you
5514		 * must add it to the data source, i.e. the server-side, through an Ajax call.
5515		 *  @param {array|object} data The data to be added to the table. This can be:
5516		 *    <ul>
5517		 *      <li>1D array of data - add a single row with the data provided</li>
5518		 *      <li>2D array of arrays - add multiple rows in a single call</li>
5519		 *      <li>object - data object when using <i>mData</i></li>
5520		 *      <li>array of objects - multiple data objects when using <i>mData</i></li>
5521		 *    </ul>
5522		 *  @param {bool} [redraw=true] redraw the table or not
5523		 *  @returns {array} An array of integers, representing the list of indexes in
5524		 *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5525		 *    the table.
5526		 *  @dtopt API
5527		 *  @deprecated Since v1.10
5528		 *
5529		 *  @example
5530		 *    // Global var for counter
5531		 *    var giCount = 2;
5532		 *
5533		 *    $(document).ready(function() {
5534		 *      $('#example').dataTable();
5535		 *    } );
5536		 *
5537		 *    function fnClickAddRow() {
5538		 *      $('#example').dataTable().fnAddData( [
5539		 *        giCount+".1",
5540		 *        giCount+".2",
5541		 *        giCount+".3",
5542		 *        giCount+".4" ]
5543		 *      );
5544		 *
5545		 *      giCount++;
5546		 *    }
5547		 */
5548		this.fnAddData = function( data, redraw )
5549		{
5550			var api = this.api( true );
5551		
5552			/* Check if we want to add multiple rows or not */
5553			var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5554				api.rows.add( data ) :
5555				api.row.add( data );
5556		
5557			if ( redraw === undefined || redraw ) {
5558				api.draw();
5559			}
5560		
5561			return rows.flatten().toArray();
5562		};
5563		
5564		
5565		/**
5566		 * This function will make DataTables recalculate the column sizes, based on the data
5567		 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5568		 * through the sWidth parameter). This can be useful when the width of the table's
5569		 * parent element changes (for example a window resize).
5570		 *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5571		 *  @dtopt API
5572		 *  @deprecated Since v1.10
5573		 *
5574		 *  @example
5575		 *    $(document).ready(function() {
5576		 *      var oTable = $('#example').dataTable( {
5577		 *        "sScrollY": "200px",
5578		 *        "bPaginate": false
5579		 *      } );
5580		 *
5581		 *      $(window).bind('resize', function () {
5582		 *        oTable.fnAdjustColumnSizing();
5583		 *      } );
5584		 *    } );
5585		 */
5586		this.fnAdjustColumnSizing = function ( bRedraw )
5587		{
5588			var api = this.api( true ).columns.adjust();
5589			var settings = api.settings()[0];
5590			var scroll = settings.oScroll;
5591		
5592			if ( bRedraw === undefined || bRedraw ) {
5593				api.draw( false );
5594			}
5595			else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5596				/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5597				_fnScrollDraw( settings );
5598			}
5599		};
5600		
5601		
5602		/**
5603		 * Quickly and simply clear a table
5604		 *  @param {bool} [bRedraw=true] redraw the table or not
5605		 *  @dtopt API
5606		 *  @deprecated Since v1.10
5607		 *
5608		 *  @example
5609		 *    $(document).ready(function() {
5610		 *      var oTable = $('#example').dataTable();
5611		 *
5612		 *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5613		 *      oTable.fnClearTable();
5614		 *    } );
5615		 */
5616		this.fnClearTable = function( bRedraw )
5617		{
5618			var api = this.api( true ).clear();
5619		
5620			if ( bRedraw === undefined || bRedraw ) {
5621				api.draw();
5622			}
5623		};
5624		
5625		
5626		/**
5627		 * The exact opposite of 'opening' a row, this function will close any rows which
5628		 * are currently 'open'.
5629		 *  @param {node} nTr the table row to 'close'
5630		 *  @returns {int} 0 on success, or 1 if failed (can't find the row)
5631		 *  @dtopt API
5632		 *  @deprecated Since v1.10
5633		 *
5634		 *  @example
5635		 *    $(document).ready(function() {
5636		 *      var oTable;
5637		 *
5638		 *      // 'open' an information row when a row is clicked on
5639		 *      $('#example tbody tr').click( function () {
5640		 *        if ( oTable.fnIsOpen(this) ) {
5641		 *          oTable.fnClose( this );
5642		 *        } else {
5643		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5644		 *        }
5645		 *      } );
5646		 *
5647		 *      oTable = $('#example').dataTable();
5648		 *    } );
5649		 */
5650		this.fnClose = function( nTr )
5651		{
5652			this.api( true ).row( nTr ).child.hide();
5653		};
5654		
5655		
5656		/**
5657		 * Remove a row for the table
5658		 *  @param {mixed} target The index of the row from aoData to be deleted, or
5659		 *    the TR element you want to delete
5660		 *  @param {function|null} [callBack] Callback function
5661		 *  @param {bool} [redraw=true] Redraw the table or not
5662		 *  @returns {array} The row that was deleted
5663		 *  @dtopt API
5664		 *  @deprecated Since v1.10
5665		 *
5666		 *  @example
5667		 *    $(document).ready(function() {
5668		 *      var oTable = $('#example').dataTable();
5669		 *
5670		 *      // Immediately remove the first row
5671		 *      oTable.fnDeleteRow( 0 );
5672		 *    } );
5673		 */
5674		this.fnDeleteRow = function( target, callback, redraw )
5675		{
5676			var api = this.api( true );
5677			var rows = api.rows( target );
5678			var settings = rows.settings()[0];
5679			var data = settings.aoData[ rows[0][0] ];
5680		
5681			rows.remove();
5682		
5683			if ( callback ) {
5684				callback.call( this, settings, data );
5685			}
5686		
5687			if ( redraw === undefined || redraw ) {
5688				api.draw();
5689			}
5690		
5691			return data;
5692		};
5693		
5694		
5695		/**
5696		 * Restore the table to it's original state in the DOM by removing all of DataTables
5697		 * enhancements, alterations to the DOM structure of the table and event listeners.
5698		 *  @param {boolean} [remove=false] Completely remove the table from the DOM
5699		 *  @dtopt API
5700		 *  @deprecated Since v1.10
5701		 *
5702		 *  @example
5703		 *    $(document).ready(function() {
5704		 *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
5705		 *      var oTable = $('#example').dataTable();
5706		 *      oTable.fnDestroy();
5707		 *    } );
5708		 */
5709		this.fnDestroy = function ( remove )
5710		{
5711			this.api( true ).destroy( remove );
5712		};
5713		
5714		
5715		/**
5716		 * Redraw the table
5717		 *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5718		 *  @dtopt API
5719		 *  @deprecated Since v1.10
5720		 *
5721		 *  @example
5722		 *    $(document).ready(function() {
5723		 *      var oTable = $('#example').dataTable();
5724		 *
5725		 *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5726		 *      oTable.fnDraw();
5727		 *    } );
5728		 */
5729		this.fnDraw = function( complete )
5730		{
5731			// Note that this isn't an exact match to the old call to _fnDraw - it takes
5732			// into account the new data, but can hold position.
5733			this.api( true ).draw( complete );
5734		};
5735		
5736		
5737		/**
5738		 * Filter the input based on data
5739		 *  @param {string} sInput String to filter the table on
5740		 *  @param {int|null} [iColumn] Column to limit filtering to
5741		 *  @param {bool} [bRegex=false] Treat as regular expression or not
5742		 *  @param {bool} [bSmart=true] Perform smart filtering or not
5743		 *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5744		 *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5745		 *  @dtopt API
5746		 *  @deprecated Since v1.10
5747		 *
5748		 *  @example
5749		 *    $(document).ready(function() {
5750		 *      var oTable = $('#example').dataTable();
5751		 *
5752		 *      // Sometime later - filter...
5753		 *      oTable.fnFilter( 'test string' );
5754		 *    } );
5755		 */
5756		this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5757		{
5758			var api = this.api( true );
5759		
5760			if ( iColumn === null || iColumn === undefined ) {
5761				api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5762			}
5763			else {
5764				api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5765			}
5766		
5767			api.draw();
5768		};
5769		
5770		
5771		/**
5772		 * Get the data for the whole table, an individual row or an individual cell based on the
5773		 * provided parameters.
5774		 *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5775		 *    a TR node then the data source for the whole row will be returned. If given as a
5776		 *    TD/TH cell node then iCol will be automatically calculated and the data for the
5777		 *    cell returned. If given as an integer, then this is treated as the aoData internal
5778		 *    data index for the row (see fnGetPosition) and the data for that row used.
5779		 *  @param {int} [col] Optional column index that you want the data of.
5780		 *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
5781		 *    returned. If mRow is defined, just data for that row, and is iCol is
5782		 *    defined, only data for the designated cell is returned.
5783		 *  @dtopt API
5784		 *  @deprecated Since v1.10
5785		 *
5786		 *  @example
5787		 *    // Row data
5788		 *    $(document).ready(function() {
5789		 *      oTable = $('#example').dataTable();
5790		 *
5791		 *      oTable.$('tr').click( function () {
5792		 *        var data = oTable.fnGetData( this );
5793		 *        // ... do something with the array / object of data for the row
5794		 *      } );
5795		 *    } );
5796		 *
5797		 *  @example
5798		 *    // Individual cell data
5799		 *    $(document).ready(function() {
5800		 *      oTable = $('#example').dataTable();
5801		 *
5802		 *      oTable.$('td').click( function () {
5803		 *        var sData = oTable.fnGetData( this );
5804		 *        alert( 'The cell clicked on had the value of '+sData );
5805		 *      } );
5806		 *    } );
5807		 */
5808		this.fnGetData = function( src, col )
5809		{
5810			var api = this.api( true );
5811		
5812			if ( src !== undefined ) {
5813				var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5814		
5815				return col !== undefined || type == 'td' || type == 'th' ?
5816					api.cell( src, col ).data() :
5817					api.row( src ).data() || null;
5818			}
5819		
5820			return api.data().toArray();
5821		};
5822		
5823		
5824		/**
5825		 * Get an array of the TR nodes that are used in the table's body. Note that you will
5826		 * typically want to use the '$' API method in preference to this as it is more
5827		 * flexible.
5828		 *  @param {int} [iRow] Optional row index for the TR element you want
5829		 *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
5830		 *    in the table's body, or iRow is defined, just the TR element requested.
5831		 *  @dtopt API
5832		 *  @deprecated Since v1.10
5833		 *
5834		 *  @example
5835		 *    $(document).ready(function() {
5836		 *      var oTable = $('#example').dataTable();
5837		 *
5838		 *      // Get the nodes from the table
5839		 *      var nNodes = oTable.fnGetNodes( );
5840		 *    } );
5841		 */
5842		this.fnGetNodes = function( iRow )
5843		{
5844			var api = this.api( true );
5845		
5846			return iRow !== undefined ?
5847				api.row( iRow ).node() :
5848				api.rows().nodes().flatten().toArray();
5849		};
5850		
5851		
5852		/**
5853		 * Get the array indexes of a particular cell from it's DOM element
5854		 * and column index including hidden columns
5855		 *  @param {node} node this can either be a TR, TD or TH in the table's body
5856		 *  @returns {int} If nNode is given as a TR, then a single index is returned, or
5857		 *    if given as a cell, an array of [row index, column index (visible),
5858		 *    column index (all)] is given.
5859		 *  @dtopt API
5860		 *  @deprecated Since v1.10
5861		 *
5862		 *  @example
5863		 *    $(document).ready(function() {
5864		 *      $('#example tbody td').click( function () {
5865		 *        // Get the position of the current data from the node
5866		 *        var aPos = oTable.fnGetPosition( this );
5867		 *
5868		 *        // Get the data array for this row
5869		 *        var aData = oTable.fnGetData( aPos[0] );
5870		 *
5871		 *        // Update the data array and return the value
5872		 *        aData[ aPos[1] ] = 'clicked';
5873		 *        this.innerHTML = 'clicked';
5874		 *      } );
5875		 *
5876		 *      // Init DataTables
5877		 *      oTable = $('#example').dataTable();
5878		 *    } );
5879		 */
5880		this.fnGetPosition = function( node )
5881		{
5882			var api = this.api( true );
5883			var nodeName = node.nodeName.toUpperCase();
5884		
5885			if ( nodeName == 'TR' ) {
5886				return api.row( node ).index();
5887			}
5888			else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5889				var cell = api.cell( node ).index();
5890		
5891				return [
5892					cell.row,
5893					cell.columnVisible,
5894					cell.column
5895				];
5896			}
5897			return null;
5898		};
5899		
5900		
5901		/**
5902		 * Check to see if a row is 'open' or not.
5903		 *  @param {node} nTr the table row to check
5904		 *  @returns {boolean} true if the row is currently open, false otherwise
5905		 *  @dtopt API
5906		 *  @deprecated Since v1.10
5907		 *
5908		 *  @example
5909		 *    $(document).ready(function() {
5910		 *      var oTable;
5911		 *
5912		 *      // 'open' an information row when a row is clicked on
5913		 *      $('#example tbody tr').click( function () {
5914		 *        if ( oTable.fnIsOpen(this) ) {
5915		 *          oTable.fnClose( this );
5916		 *        } else {
5917		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5918		 *        }
5919		 *      } );
5920		 *
5921		 *      oTable = $('#example').dataTable();
5922		 *    } );
5923		 */
5924		this.fnIsOpen = function( nTr )
5925		{
5926			return this.api( true ).row( nTr ).child.isShown();
5927		};
5928		
5929		
5930		/**
5931		 * This function will place a new row directly after a row which is currently
5932		 * on display on the page, with the HTML contents that is passed into the
5933		 * function. This can be used, for example, to ask for confirmation that a
5934		 * particular record should be deleted.
5935		 *  @param {node} nTr The table row to 'open'
5936		 *  @param {string|node|jQuery} mHtml The HTML to put into the row
5937		 *  @param {string} sClass Class to give the new TD cell
5938		 *  @returns {node} The row opened. Note that if the table row passed in as the
5939		 *    first parameter, is not found in the table, this method will silently
5940		 *    return.
5941		 *  @dtopt API
5942		 *  @deprecated Since v1.10
5943		 *
5944		 *  @example
5945		 *    $(document).ready(function() {
5946		 *      var oTable;
5947		 *
5948		 *      // 'open' an information row when a row is clicked on
5949		 *      $('#example tbody tr').click( function () {
5950		 *        if ( oTable.fnIsOpen(this) ) {
5951		 *          oTable.fnClose( this );
5952		 *        } else {
5953		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5954		 *        }
5955		 *      } );
5956		 *
5957		 *      oTable = $('#example').dataTable();
5958		 *    } );
5959		 */
5960		this.fnOpen = function( nTr, mHtml, sClass )
5961		{
5962			return this.api( true )
5963				.row( nTr )
5964				.child( mHtml, sClass )
5965				.show()
5966				.child()[0];
5967		};
5968		
5969		
5970		/**
5971		 * Change the pagination - provides the internal logic for pagination in a simple API
5972		 * function. With this function you can have a DataTables table go to the next,
5973		 * previous, first or last pages.
5974		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5975		 *    or page number to jump to (integer), note that page 0 is the first page.
5976		 *  @param {bool} [bRedraw=true] Redraw the table or not
5977		 *  @dtopt API
5978		 *  @deprecated Since v1.10
5979		 *
5980		 *  @example
5981		 *    $(document).ready(function() {
5982		 *      var oTable = $('#example').dataTable();
5983		 *      oTable.fnPageChange( 'next' );
5984		 *    } );
5985		 */
5986		this.fnPageChange = function ( mAction, bRedraw )
5987		{
5988			var api = this.api( true ).page( mAction );
5989		
5990			if ( bRedraw === undefined || bRedraw ) {
5991				api.draw(false);
5992			}
5993		};
5994		
5995		
5996		/**
5997		 * Show a particular column
5998		 *  @param {int} iCol The column whose display should be changed
5999		 *  @param {bool} bShow Show (true) or hide (false) the column
6000		 *  @param {bool} [bRedraw=true] Redraw the table or not
6001		 *  @dtopt API
6002		 *  @deprecated Since v1.10
6003		 *
6004		 *  @example
6005		 *    $(document).ready(function() {
6006		 *      var oTable = $('#example').dataTable();
6007		 *
6008		 *      // Hide the second column after initialisation
6009		 *      oTable.fnSetColumnVis( 1, false );
6010		 *    } );
6011		 */
6012		this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
6013		{
6014			var api = this.api( true ).column( iCol ).visible( bShow );
6015		
6016			if ( bRedraw === undefined || bRedraw ) {
6017				api.columns.adjust().draw();
6018			}
6019		};
6020		
6021		
6022		/**
6023		 * Get the settings for a particular table for external manipulation
6024		 *  @returns {object} DataTables settings object. See
6025		 *    {@link DataTable.models.oSettings}
6026		 *  @dtopt API
6027		 *  @deprecated Since v1.10
6028		 *
6029		 *  @example
6030		 *    $(document).ready(function() {
6031		 *      var oTable = $('#example').dataTable();
6032		 *      var oSettings = oTable.fnSettings();
6033		 *
6034		 *      // Show an example parameter from the settings
6035		 *      alert( oSettings._iDisplayStart );
6036		 *    } );
6037		 */
6038		this.fnSettings = function()
6039		{
6040			return _fnSettingsFromNode( this[_ext.iApiIndex] );
6041		};
6042		
6043		
6044		/**
6045		 * Sort the table by a particular column
6046		 *  @param {int} iCol the data index to sort on. Note that this will not match the
6047		 *    'display index' if you have hidden data entries
6048		 *  @dtopt API
6049		 *  @deprecated Since v1.10
6050		 *
6051		 *  @example
6052		 *    $(document).ready(function() {
6053		 *      var oTable = $('#example').dataTable();
6054		 *
6055		 *      // Sort immediately with columns 0 and 1
6056		 *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
6057		 *    } );
6058		 */
6059		this.fnSort = function( aaSort )
6060		{
6061			this.api( true ).order( aaSort ).draw();
6062		};
6063		
6064		
6065		/**
6066		 * Attach a sort listener to an element for a given column
6067		 *  @param {node} nNode the element to attach the sort listener to
6068		 *  @param {int} iColumn the column that a click on this node will sort on
6069		 *  @param {function} [fnCallback] callback function when sort is run
6070		 *  @dtopt API
6071		 *  @deprecated Since v1.10
6072		 *
6073		 *  @example
6074		 *    $(document).ready(function() {
6075		 *      var oTable = $('#example').dataTable();
6076		 *
6077		 *      // Sort on column 1, when 'sorter' is clicked on
6078		 *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
6079		 *    } );
6080		 */
6081		this.fnSortListener = function( nNode, iColumn, fnCallback )
6082		{
6083			this.api( true ).order.listener( nNode, iColumn, fnCallback );
6084		};
6085		
6086		
6087		/**
6088		 * Update a table cell or row - this method will accept either a single value to
6089		 * update the cell with, an array of values with one element for each column or
6090		 * an object in the same format as the original data source. The function is
6091		 * self-referencing in order to make the multi column updates easier.
6092		 *  @param {object|array|string} mData Data to update the cell/row with
6093		 *  @param {node|int} mRow TR element you want to update or the aoData index
6094		 *  @param {int} [iColumn] The column to update, give as null or undefined to
6095		 *    update a whole row.
6096		 *  @param {bool} [bRedraw=true] Redraw the table or not
6097		 *  @param {bool} [bAction=true] Perform pre-draw actions or not
6098		 *  @returns {int} 0 on success, 1 on error
6099		 *  @dtopt API
6100		 *  @deprecated Since v1.10
6101		 *
6102		 *  @example
6103		 *    $(document).ready(function() {
6104		 *      var oTable = $('#example').dataTable();
6105		 *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
6106		 *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
6107		 *    } );
6108		 */
6109		this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
6110		{
6111			var api = this.api( true );
6112		
6113			if ( iColumn === undefined || iColumn === null ) {
6114				api.row( mRow ).data( mData );
6115			}
6116			else {
6117				api.cell( mRow, iColumn ).data( mData );
6118			}
6119		
6120			if ( bAction === undefined || bAction ) {
6121				api.columns.adjust();
6122			}
6123		
6124			if ( bRedraw === undefined || bRedraw ) {
6125				api.draw();
6126			}
6127			return 0;
6128		};
6129		
6130		
6131		/**
6132		 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6133		 * to ensure compatibility.
6134		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6135		 *    formats "X" and "X.Y" are also acceptable.
6136		 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
6137		 *    version, or false if this version of DataTales is not suitable
6138		 *  @method
6139		 *  @dtopt API
6140		 *  @deprecated Since v1.10
6141		 *
6142		 *  @example
6143		 *    $(document).ready(function() {
6144		 *      var oTable = $('#example').dataTable();
6145		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
6146		 *    } );
6147		 */
6148		this.fnVersionCheck = _ext.fnVersionCheck;
6149		
6150
6151		var _that = this;
6152		var emptyInit = options === undefined;
6153		var len = this.length;
6154
6155		if ( emptyInit ) {
6156			options = {};
6157		}
6158
6159		this.oApi = this.internal = _ext.internal;
6160
6161		// Extend with old style plug-in API methods
6162		for ( var fn in DataTable.ext.internal ) {
6163			if ( fn ) {
6164				this[fn] = _fnExternApiFunc(fn);
6165			}
6166		}
6167
6168		this.each(function() {
6169			// For each initialisation we want to give it a clean initialisation
6170			// object that can be bashed around
6171			var o = {};
6172			var oInit = len > 1 ? // optimisation for single table case
6173				_fnExtend( o, options, true ) :
6174				options;
6175
6176			/*global oInit,_that,emptyInit*/
6177			var i=0, iLen, j, jLen, k, kLen;
6178			var sId = this.getAttribute( 'id' );
6179			var bInitHandedOff = false;
6180			var defaults = DataTable.defaults;
6181			var $this = $(this);
6182			
6183			
6184			/* Sanity check */
6185			if ( this.nodeName.toLowerCase() != 'table' )
6186			{
6187				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6188				return;
6189			}
6190			
6191			/* Backwards compatibility for the defaults */
6192			_fnCompatOpts( defaults );
6193			_fnCompatCols( defaults.column );
6194			
6195			/* Convert the camel-case defaults to Hungarian */
6196			_fnCamelToHungarian( defaults, defaults, true );
6197			_fnCamelToHungarian( defaults.column, defaults.column, true );
6198			
6199			/* Setting up the initialisation object */
6200			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
6201			
6202			
6203			
6204			/* Check to see if we are re-initialising a table */
6205			var allSettings = DataTable.settings;
6206			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6207			{
6208				var s = allSettings[i];
6209			
6210				/* Base check on table node */
6211				if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
6212				{
6213					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6214					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6215			
6216					if ( emptyInit || bRetrieve )
6217					{
6218						return s.oInstance;
6219					}
6220					else if ( bDestroy )
6221					{
6222						s.oInstance.fnDestroy();
6223						break;
6224					}
6225					else
6226					{
6227						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
6228						return;
6229					}
6230				}
6231			
6232				/* If the element we are initialising has the same ID as a table which was previously
6233				 * initialised, but the table nodes don't match (from before) then we destroy the old
6234				 * instance by simply deleting it. This is under the assumption that the table has been
6235				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6236				 */
6237				if ( s.sTableId == this.id )
6238				{
6239					allSettings.splice( i, 1 );
6240					break;
6241				}
6242			}
6243			
6244			/* Ensure the table has an ID - required for accessibility */
6245			if ( sId === null || sId === "" )
6246			{
6247				sId = "DataTables_Table_"+(DataTable.ext._unique++);
6248				this.id = sId;
6249			}
6250			
6251			/* Create the settings object for this table and set some of the default parameters */
6252			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6253				"sDestroyWidth": $this[0].style.width,
6254				"sInstance":     sId,
6255				"sTableId":      sId
6256			} );
6257			oSettings.nTable = this;
6258			oSettings.oApi   = _that.internal;
6259			oSettings.oInit  = oInit;
6260			
6261			allSettings.push( oSettings );
6262			
6263			// Need to add the instance after the instance after the settings object has been added
6264			// to the settings array, so we can self reference the table instance if more than one
6265			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
6266			
6267			// Backwards compatibility, before we apply all the defaults
6268			_fnCompatOpts( oInit );
6269			
6270			if ( oInit.oLanguage )
6271			{
6272				_fnLanguageCompat( oInit.oLanguage );
6273			}
6274			
6275			// If the length menu is given, but the init display length is not, use the length menu
6276			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6277			{
6278				oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6279					oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6280			}
6281			
6282			// Apply the defaults and init options to make a single init object will all
6283			// options defined from defaults and instance options.
6284			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6285			
6286			
6287			// Map the initialisation options onto the settings object
6288			_fnMap( oSettings.oFeatures, oInit, [
6289				"bPaginate",
6290				"bLengthChange",
6291				"bFilter",
6292				"bSort",
6293				"bSortMulti",
6294				"bInfo",
6295				"bProcessing",
6296				"bAutoWidth",
6297				"bSortClasses",
6298				"bServerSide",
6299				"bDeferRender"
6300			] );
6301			_fnMap( oSettings, oInit, [
6302				"asStripeClasses",
6303				"ajax",
6304				"fnServerData",
6305				"fnFormatNumber",
6306				"sServerMethod",
6307				"aaSorting",
6308				"aaSortingFixed",
6309				"aLengthMenu",
6310				"sPaginationType",
6311				"sAjaxSource",
6312				"sAjaxDataProp",
6313				"iStateDuration",
6314				"sDom",
6315				"bSortCellsTop",
6316				"iTabIndex",
6317				"fnStateLoadCallback",
6318				"fnStateSaveCallback",
6319				"renderer",
6320				"searchDelay",
6321				"rowId",
6322				[ "iCookieDuration", "iStateDuration" ], // backwards compat
6323				[ "oSearch", "oPreviousSearch" ],
6324				[ "aoSearchCols", "aoPreSearchCols" ],
6325				[ "iDisplayLength", "_iDisplayLength" ],
6326				[ "bJQueryUI", "bJUI" ]
6327			] );
6328			_fnMap( oSettings.oScroll, oInit, [
6329				[ "sScrollX", "sX" ],
6330				[ "sScrollXInner", "sXInner" ],
6331				[ "sScrollY", "sY" ],
6332				[ "bScrollCollapse", "bCollapse" ]
6333			] );
6334			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6335			
6336			/* Callback functions which are array driven */
6337			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
6338			_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
6339			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
6340			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
6341			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
6342			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
6343			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
6344			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
6345			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
6346			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
6347			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
6348			
6349			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
6350			
6351			/* Browser support detection */
6352			_fnBrowserDetect( oSettings );
6353			
6354			var oClasses = oSettings.oClasses;
6355			
6356			// @todo Remove in 1.11
6357			if ( oInit.bJQueryUI )
6358			{
6359				/* Use the JUI classes object for display. You could clone the oStdClasses object if
6360				 * you want to have multiple tables with multiple independent classes
6361				 */
6362				$.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6363			
6364				if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6365				{
6366					/* Set the DOM to use a layout suitable for jQuery UI's theming */
6367					oSettings.sDom = '<"H"lfr>t<"F"ip>';
6368				}
6369			
6370				if ( ! oSettings.renderer ) {
6371					oSettings.renderer = 'jqueryui';
6372				}
6373				else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6374					oSettings.renderer.header = 'jqueryui';
6375				}
6376			}
6377			else
6378			{
6379				$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6380			}
6381			$this.addClass( oClasses.sTable );
6382			
6383			
6384			if ( oSettings.iInitDisplayStart === undefined )
6385			{
6386				/* Display start point, taking into account the save saving */
6387				oSettings.iInitDisplayStart = oInit.iDisplayStart;
6388				oSettings._iDisplayStart = oInit.iDisplayStart;
6389			}
6390			
6391			if ( oInit.iDeferLoading !== null )
6392			{
6393				oSettings.bDeferLoading = true;
6394				var tmp = $.isArray( oInit.iDeferLoading );
6395				oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6396				oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6397			}
6398			
6399			/* Language definitions */
6400			var oLanguage = oSettings.oLanguage;
6401			$.extend( true, oLanguage, oInit.oLanguage );
6402			
6403			if ( oLanguage.sUrl !== "" )
6404			{
6405				/* Get the language definitions from a file - because this Ajax call makes the language
6406				 * get async to the remainder of this function we use bInitHandedOff to indicate that
6407				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6408				 */
6409				$.ajax( {
6410					dataType: 'json',
6411					url: oLanguage.sUrl,
6412					success: function ( json ) {
6413						_fnLanguageCompat( json );
6414						_fnCamelToHungarian( defaults.oLanguage, json );
6415						$.extend( true, oLanguage, json );
6416						_fnInitialise( oSettings );
6417					},
6418					error: function () {
6419						// Error occurred loading language file, continue on as best we can
6420						_fnInitialise( oSettings );
6421					}
6422				} );
6423				bInitHandedOff = true;
6424			}
6425			
6426			/*
6427			 * Stripes
6428			 */
6429			if ( oInit.asStripeClasses === null )
6430			{
6431				oSettings.asStripeClasses =[
6432					oClasses.sStripeOdd,
6433					oClasses.sStripeEven
6434				];
6435			}
6436			
6437			/* Remove row stripe classes if they are already on the table row */
6438			var stripeClasses = oSettings.asStripeClasses;
6439			var rowOne = $this.children('tbody').find('tr').eq(0);
6440			if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6441				return rowOne.hasClass(el);
6442			} ) ) !== -1 ) {
6443				$('tbody tr', this).removeClass( stripeClasses.join(' ') );
6444				oSettings.asDestroyStripes = stripeClasses.slice();
6445			}
6446			
6447			/*
6448			 * Columns
6449			 * See if we should load columns automatically or use defined ones
6450			 */
6451			var anThs = [];
6452			var aoColumnsInit;
6453			var nThead = this.getElementsByTagName('thead');
6454			if ( nThead.length !== 0 )
6455			{
6456				_fnDetectHeader( oSettings.aoHeader, nThead[0] );
6457				anThs = _fnGetUniqueThs( oSettings );
6458			}
6459			
6460			/* If not given a column array, generate one with nulls */
6461			if ( oInit.aoColumns === null )
6462			{
6463				aoColumnsInit = [];
6464				for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6465				{
6466					aoColumnsInit.push( null );
6467				}
6468			}
6469			else
6470			{
6471				aoColumnsInit = oInit.aoColumns;
6472			}
6473			
6474			/* Add the columns */
6475			for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6476			{
6477				_fnAddColumn( oSettings, anThs ? anThs[i] : null );
6478			}
6479			
6480			/* Apply the column definitions */
6481			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6482				_fnColumnOptions( oSettings, iCol, oDef );
6483			} );
6484			
6485			/* HTML5 attribute detection - build an mData object automatically if the
6486			 * attributes are found
6487			 */
6488			if ( rowOne.length ) {
6489				var a = function ( cell, name ) {
6490					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
6491				};
6492			
6493				$( rowOne[0] ).children('th, td').each( function (i, cell) {
6494					var col = oSettings.aoColumns[i];
6495			
6496					if ( col.mData === i ) {
6497						var sort = a( cell, 'sort' ) || a( cell, 'order' );
6498						var filter = a( cell, 'filter' ) || a( cell, 'search' );
6499			
6500						if ( sort !== null || filter !== null ) {
6501							col.mData = {
6502								_:      i+'.display',
6503								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
6504								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
6505								filter: filter !== null ? i+'.@data-'+filter : undefined
6506							};
6507			
6508							_fnColumnOptions( oSettings, i );
6509						}
6510					}
6511				} );
6512			}
6513			
6514			var features = oSettings.oFeatures;
6515			
6516			/* Must be done after everything which can be overridden by the state saving! */
6517			if ( oInit.bStateSave )
6518			{
6519				features.bStateSave = true;
6520				_fnLoadState( oSettings, oInit );
6521				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6522			}
6523			
6524			
6525			/*
6526			 * Sorting
6527			 * @todo For modularisation (1.11) this needs to do into a sort start up handler
6528			 */
6529			
6530			// If aaSorting is not defined, then we use the first indicator in asSorting
6531			// in case that has been altered, so the default sort reflects that option
6532			if ( oInit.aaSorting === undefined )
6533			{
6534				var sorting = oSettings.aaSorting;
6535				for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6536				{
6537					sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6538				}
6539			}
6540			
6541			/* Do a first pass on the sorting classes (allows any size changes to be taken into
6542			 * account, and also will apply sorting disabled classes if disabled
6543			 */
6544			_fnSortingClasses( oSettings );
6545			
6546			if ( features.bSort )
6547			{
6548				_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6549					if ( oSettings.bSorted ) {
6550						var aSort = _fnSortFlatten( oSettings );
6551						var sortedColumns = {};
6552			
6553						$.each( aSort, function (i, val) {
6554							sortedColumns[ val.src ] = val.dir;
6555						} );
6556			
6557						_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6558						_fnSortAria( oSettings );
6559					}
6560				} );
6561			}
6562			
6563			_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6564				if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6565					_fnSortingClasses( oSettings );
6566				}
6567			}, 'sc' );
6568			
6569			
6570			/*
6571			 * Final init
6572			 * Cache the header, body and footer as required, creating them if needed
6573			 */
6574			
6575			// Work around for Webkit bug 83867 - store the caption-side before removing from doc
6576			var captions = $this.children('caption').each( function () {
6577				this._captionSide = $this.css('caption-side');
6578			} );
6579			
6580			var thead = $this.children('thead');
6581			if ( thead.length === 0 )
6582			{
6583				thead = $('<thead/>').appendTo(this);
6584			}
6585			oSettings.nTHead = thead[0];
6586			
6587			var tbody = $this.children('tbody');
6588			if ( tbody.length === 0 )
6589			{
6590				tbody = $('<tbody/>').appendTo(this);
6591			}
6592			oSettings.nTBody = tbody[0];
6593			
6594			var tfoot = $this.children('tfoot');
6595			if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6596			{
6597				// If we are a scrolling table, and no footer has been given, then we need to create
6598				// a tfoot element for the caption element to be appended to
6599				tfoot = $('<tfoot/>').appendTo(this);
6600			}
6601			
6602			if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6603				$this.addClass( oClasses.sNoFooter );
6604			}
6605			else if ( tfoot.length > 0 ) {
6606				oSettings.nTFoot = tfoot[0];
6607				_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6608			}
6609			
6610			/* Check if there is data passing into the constructor */
6611			if ( oInit.aaData )
6612			{
6613				for ( i=0 ; i<oInit.aaData.length ; i++ )
6614				{
6615					_fnAddData( oSettings, oInit.aaData[ i ] );
6616				}
6617			}
6618			else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6619			{
6620				/* Grab the data from the page - only do this when deferred loading or no Ajax
6621				 * source since there is no point in reading the DOM data if we are then going
6622				 * to replace it with Ajax data
6623				 */
6624				_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6625			}
6626			
6627			/* Copy the data index array */
6628			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6629			
6630			/* Initialisation complete - table can be drawn */
6631			oSettings.bInitialised = true;
6632			
6633			/* Check if we need to initialise the table (it might not have been handed off to the
6634			 * language processor)
6635			 */
6636			if ( bInitHandedOff === false )
6637			{
6638				_fnInitialise( oSettings );
6639			}
6640		} );
6641		_that = null;
6642		return this;
6643	};
6644
6645	
6646	
6647	/**
6648	 * Computed structure of the DataTables API, defined by the options passed to
6649	 * `DataTable.Api.register()` when building the API.
6650	 *
6651	 * The structure is built in order to speed creation and extension of the Api
6652	 * objects since the extensions are effectively pre-parsed.
6653	 *
6654	 * The array is an array of objects with the following structure, where this
6655	 * base array represents the Api prototype base:
6656	 *
6657	 *     [
6658	 *       {
6659	 *         name:      'data'                -- string   - Property name
6660	 *         val:       function () {},       -- function - Api method (or undefined if just an object
6661	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6662	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6663	 *       },
6664	 *       {
6665	 *         name:     'row'
6666	 *         val:       {},
6667	 *         methodExt: [ ... ],
6668	 *         propExt:   [
6669	 *           {
6670	 *             name:      'data'
6671	 *             val:       function () {},
6672	 *             methodExt: [ ... ],
6673	 *             propExt:   [ ... ]
6674	 *           },
6675	 *           ...
6676	 *         ]
6677	 *       }
6678	 *     ]
6679	 *
6680	 * @type {Array}
6681	 * @ignore
6682	 */
6683	var __apiStruct = [];
6684	
6685	
6686	/**
6687	 * `Array.prototype` reference.
6688	 *
6689	 * @type object
6690	 * @ignore
6691	 */
6692	var __arrayProto = Array.prototype;
6693	
6694	
6695	/**
6696	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6697	 * take several different forms for ease of use.
6698	 *
6699	 * Each of the input parameter types will be converted to a DataTables settings
6700	 * object where possible.
6701	 *
6702	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6703	 *   of:
6704	 *
6705	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6706	 *     with be found and used.
6707	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6708	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6709	 *   * `object` - DataTables settings object
6710	 *   * `DataTables.Api` - API instance
6711	 * @return {array|null} Matching DataTables settings objects. `null` or
6712	 *   `undefined` is returned if no matching DataTable is found.
6713	 * @ignore
6714	 */
6715	var _toSettings = function ( mixed )
6716	{
6717		var idx, jq;
6718		var settings = DataTable.settings;
6719		var tables = $.map( settings, function (el, i) {
6720			return el.nTable;
6721		} );
6722	
6723		if ( ! mixed ) {
6724			return [];
6725		}
6726		else if ( mixed.nTable && mixed.oApi ) {
6727			// DataTables settings object
6728			return [ mixed ];
6729		}
6730		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6731			// Table node
6732			idx = $.inArray( mixed, tables );
6733			return idx !== -1 ? [ settings[idx] ] : null;
6734		}
6735		else if ( mixed && typeof mixed.settings === 'function' ) {
6736			return mixed.settings().toArray();
6737		}
6738		else if ( typeof mixed === 'string' ) {
6739			// jQuery selector
6740			jq = $(mixed);
6741		}
6742		else if ( mixed instanceof $ ) {
6743			// jQuery object (also DataTables instance)
6744			jq = mixed;
6745		}
6746	
6747		if ( jq ) {
6748			return jq.map( function(i) {
6749				idx = $.inArray( this, tables );
6750				return idx !== -1 ? settings[idx] : null;
6751			} ).toArray();
6752		}
6753	};
6754	
6755	
6756	/**
6757	 * DataTables API class - used to control and interface with  one or more
6758	 * DataTables enhanced tables.
6759	 *
6760	 * The API class is heavily based on jQuery, presenting a chainable interface
6761	 * that you can use to interact with tables. Each instance of the API class has
6762	 * a "context" - i.e. the tables that it will operate on. This could be a single
6763	 * table, all tables on a page or a sub-set thereof.
6764	 *
6765	 * Additionally the API is designed to allow you to easily work with the data in
6766	 * the tables, retrieving and manipulating it as required. This is done by
6767	 * presenting the API class as an array like interface. The contents of the
6768	 * array depend upon the actions requested by each method (for example
6769	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6770	 * return an array of objects or arrays depending upon your table's
6771	 * configuration). The API object has a number of array like methods (`push`,
6772	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6773	 * `unique` etc) to assist your working with the data held in a table.
6774	 *
6775	 * Most methods (those which return an Api instance) are chainable, which means
6776	 * the return from a method call also has all of the methods available that the
6777	 * top level object had. For example, these two calls are equivalent:
6778	 *
6779	 *     // Not chained
6780	 *     api.row.add( {...} );
6781	 *     api.draw();
6782	 *
6783	 *     // Chained
6784	 *     api.row.add( {...} ).draw();
6785	 *
6786	 * @class DataTable.Api
6787	 * @param {array|object|string|jQuery} context DataTable identifier. This is
6788	 *   used to define which DataTables enhanced tables this API will operate on.
6789	 *   Can be one of:
6790	 *
6791	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
6792	 *     with be found and used.
6793	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
6794	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
6795	 *   * `object` - DataTables settings object
6796	 * @param {array} [data] Data to initialise the Api instance with.
6797	 *
6798	 * @example
6799	 *   // Direct initialisation during DataTables construction
6800	 *   var api = $('#example').DataTable();
6801	 *
6802	 * @example
6803	 *   // Initialisation using a DataTables jQuery object
6804	 *   var api = $('#example').dataTable().api();
6805	 *
6806	 * @example
6807	 *   // Initialisation as a constructor
6808	 *   var api = new $.fn.DataTable.Api( 'table.dataTable' );
6809	 */
6810	_Api = function ( context, data )
6811	{
6812		if ( ! (this instanceof _Api) ) {
6813			return new _Api( context, data );
6814		}
6815	
6816		var settings = [];
6817		var ctxSettings = function ( o ) {
6818			var a = _toSettings( o );
6819			if ( a ) {
6820				settings = settings.concat( a );
6821			}
6822		};
6823	
6824		if ( $.isArray( context ) ) {
6825			for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6826				ctxSettings( context[i] );
6827			}
6828		}
6829		else {
6830			ctxSettings( context );
6831		}
6832	
6833		// Remove duplicates
6834		this.context = _unique( settings );
6835	
6836		// Initial data
6837		if ( data ) {
6838			$.merge( this, data );
6839		}
6840	
6841		// selector
6842		this.selector = {
6843			rows: null,
6844			cols: null,
6845			opts: null
6846		};
6847	
6848		_Api.extend( this, this, __apiStruct );
6849	};
6850	
6851	DataTable.Api = _Api;
6852	
6853	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6854	// isPlainObject.
6855	$.extend( _Api.prototype, {
6856		any: function ()
6857		{
6858			return this.count() !== 0;
6859		},
6860	
6861	
6862		concat:  __arrayProto.concat,
6863	
6864	
6865		context: [], // array of table settings objects
6866	
6867	
6868		count: function ()
6869		{
6870			return this.flatten().length;
6871		},
6872	
6873	
6874		each: function ( fn )
6875		{
6876			for ( var i=0, ien=this.length ; i<ien; i++ ) {
6877				fn.call( this, this[i], i, this );
6878			}
6879	
6880			return this;
6881		},
6882	
6883	
6884		eq: function ( idx )
6885		{
6886			var ctx = this.context;
6887	
6888			return ctx.length > idx ?
6889				new _Api( ctx[idx], this[idx] ) :
6890				null;
6891		},
6892	
6893	
6894		filter: function ( fn )
6895		{
6896			var a = [];
6897	
6898			if ( __arrayProto.filter ) {
6899				a = __arrayProto.filter.call( this, fn, this );
6900			}
6901			else {
6902				// Compatibility for browsers without EMCA-252-5 (JS 1.6)
6903				for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6904					if ( fn.call( this, this[i], i, this ) ) {
6905						a.push( this[i] );
6906					}
6907				}
6908			}
6909	
6910			return new _Api( this.context, a );
6911		},
6912	
6913	
6914		flatten: function ()
6915		{
6916			var a = [];
6917			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6918		},
6919	
6920	
6921		join:    __arrayProto.join,
6922	
6923	
6924		indexOf: __arrayProto.indexOf || function (obj, start)
6925		{
6926			for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6927				if ( this[i] === obj ) {
6928					return i;
6929				}
6930			}
6931			return -1;
6932		},
6933	
6934		iterator: function ( flatten, type, fn, alwaysNew ) {
6935			var
6936				a = [], ret,
6937				i, ien, j, jen,
6938				context = this.context,
6939				rows, items, item,
6940				selector = this.selector;
6941	
6942			// Argument shifting
6943			if ( typeof flatten === 'string' ) {
6944				alwaysNew = fn;
6945				fn = type;
6946				type = flatten;
6947				flatten = false;
6948			}
6949	
6950			for ( i=0, ien=context.length ; i<ien ; i++ ) {
6951				var apiInst = new _Api( context[i] );
6952	
6953				if ( type === 'table' ) {
6954					ret = fn.call( apiInst, context[i], i );
6955	
6956					if ( ret !== undefined ) {
6957						a.push( ret );
6958					}
6959				}
6960				else if ( type === 'columns' || type === 'rows' ) {
6961					// this has same length as context - one entry for each table
6962					ret = fn.call( apiInst, context[i], this[i], i );
6963	
6964					if ( ret !== undefined ) {
6965						a.push( ret );
6966					}
6967				}
6968				else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6969					// columns and rows share the same structure.
6970					// 'this' is an array of column indexes for each context
6971					items = this[i];
6972	
6973					if ( type === 'column-rows' ) {
6974						rows = _selector_row_indexes( context[i], selector.opts );
6975					}
6976	
6977					for ( j=0, jen=items.length ; j<jen ; j++ ) {
6978						item = items[j];
6979	
6980						if ( type === 'cell' ) {
6981							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6982						}
6983						else {
6984							ret = fn.call( apiInst, context[i], item, i, j, rows );
6985						}
6986	
6987						if ( ret !== undefined ) {
6988							a.push( ret );
6989						}
6990					}
6991				}
6992			}
6993	
6994			if ( a.length || alwaysNew ) {
6995				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6996				var apiSelector = api.selector;
6997				apiSelector.rows = selector.rows;
6998				apiSelector.cols = selector.cols;
6999				apiSelector.opts = selector.opts;
7000				return api;
7001			}
7002			return this;
7003		},
7004	
7005	
7006		lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7007		{
7008			// Bit cheeky...
7009			return this.indexOf.apply( this.toArray.reverse(), arguments );
7010		},
7011	
7012	
7013		length:  0,
7014	
7015	
7016		map: function ( fn )
7017		{
7018			var a = [];
7019	
7020			if ( __arrayProto.map ) {
7021				a = __arrayProto.map.call( this, fn, this );
7022			}
7023			else {
7024				// Compatibility for browsers without EMCA-252-5 (JS 1.6)
7025				for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7026					a.push( fn.call( this, this[i], i ) );
7027				}
7028			}
7029	
7030			return new _Api( this.context, a );
7031		},
7032	
7033	
7034		pluck: function ( prop )
7035		{
7036			return this.map( function ( el ) {
7037				return el[ prop ];
7038			} );
7039		},
7040	
7041		pop:     __arrayProto.pop,
7042	
7043	
7044		push:    __arrayProto.push,
7045	
7046	
7047		// Does not return an API instance
7048		reduce: __arrayProto.reduce || function ( fn, init )
7049		{
7050			return _fnReduce( this, fn, init, 0, this.length, 1 );
7051		},
7052	
7053	
7054		reduceRight: __arrayProto.reduceRight || function ( fn, init )
7055		{
7056			return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7057		},
7058	
7059	
7060		reverse: __arrayProto.reverse,
7061	
7062	
7063		// Object with rows, columns and opts
7064		selector: null,
7065	
7066	
7067		shift:   __arrayProto.shift,
7068	
7069	
7070		sort:    __arrayProto.sort, // ? name - order?
7071	
7072	
7073		splice:  __arrayProto.splice,
7074	
7075	
7076		toArray: function ()
7077		{
7078			return __arrayProto.slice.call( this );
7079		},
7080	
7081	
7082		to$: function ()
7083		{
7084			return $( this );
7085		},
7086	
7087	
7088		toJQuery: function ()
7089		{
7090			return $( this );
7091		},
7092	
7093	
7094		unique: function ()
7095		{
7096			return new _Api( this.context, _unique(this) );
7097		},
7098	
7099	
7100		unshift: __arrayProto.unshift
7101	} );
7102	
7103	
7104	_Api.extend = function ( scope, obj, ext )
7105	{
7106		// Only extend API instances and static properties of the API
7107		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7108			return;
7109		}
7110	
7111		var
7112			i, ien,
7113			j, jen,
7114			struct, inner,
7115			methodScoping = function ( scope, fn, struc ) {
7116				return function () {
7117					var ret = fn.apply( scope, arguments );
7118	
7119					// Method extension
7120					_Api.extend( ret, ret, struc.methodExt );
7121					return ret;
7122				};
7123			};
7124	
7125		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7126			struct = ext[i];
7127	
7128			// Value
7129			obj[ struct.name ] = typeof struct.val === 'function' ?
7130				methodScoping( scope, struct.val, struct ) :
7131				$.isPlainObject( struct.val ) ?
7132					{} :
7133					struct.val;
7134	
7135			obj[ struct.name ].__dt_wrapper = true;
7136	
7137			// Property extension
7138			_Api.extend( scope, obj[ struct.name ], struct.propExt );
7139		}
7140	};
7141	
7142	
7143	// @todo - Is there need for an augment function?
7144	// _Api.augment = function ( inst, name )
7145	// {
7146	// 	// Find src object in the structure from the name
7147	// 	var parts = name.split('.');
7148	
7149	// 	_Api.extend( inst, obj );
7150	// };
7151	
7152	
7153	//     [
7154	//       {
7155	//         name:      'data'                -- string   - Property name
7156	//         val:       function () {},       -- function - Api method (or undefined if just an object
7157	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
7158	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
7159	//       },
7160	//       {
7161	//         name:     'row'
7162	//         val:       {},
7163	//         methodExt: [ ... ],
7164	//         propExt:   [
7165	//           {
7166	//             name:      'data'
7167	//             val:       function () {},
7168	//             methodExt: [ ... ],
7169	//             propExt:   [ ... ]
7170	//           },
7171	//           ...
7172	//         ]
7173	//       }
7174	//     ]
7175	
7176	_Api.register = _api_register = function ( name, val )
7177	{
7178		if ( $.isArray( name ) ) {
7179			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7180				_Api.register( name[j], val );
7181			}
7182			return;
7183		}
7184	
7185		var
7186			i, ien,
7187			heir = name.split('.'),
7188			struct = __apiStruct,
7189			key, method;
7190	
7191		var find = function ( src, name ) {
7192			for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7193				if ( src[i].name === name ) {
7194					return src[i];
7195				}
7196			}
7197			return null;
7198		};
7199	
7200		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7201			method = heir[i].indexOf('()') !== -1;
7202			key = method ?
7203				heir[i].replace('()', '') :
7204				heir[i];
7205	
7206			var src = find( struct, key );
7207			if ( ! src ) {
7208				src = {
7209					name:      key,
7210					val:       {},
7211					methodExt: [],
7212					propExt:   []
7213				};
7214				struct.push( src );
7215			}
7216	
7217			if ( i === ien-1 ) {
7218				src.val = val;
7219			}
7220			else {
7221				struct = method ?
7222					src.methodExt :
7223					src.propExt;
7224			}
7225		}
7226	};
7227	
7228	
7229	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7230		_Api.register( pluralName, val );
7231	
7232		_Api.register( singularName, function () {
7233			var ret = val.apply( this, arguments );
7234	
7235			if ( ret === this ) {
7236				// Returned item is the API instance that was passed in, return it
7237				return this;
7238			}
7239			else if ( ret instanceof _Api ) {
7240				// New API instance returned, want the value from the first item
7241				// in the returned array for the singular result.
7242				return ret.length ?
7243					$.isArray( ret[0] ) ?
7244						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7245						ret[0] :
7246					undefined;
7247			}
7248	
7249			// Non-API return - just fire it back
7250			return ret;
7251		} );
7252	};
7253	
7254	
7255	/**
7256	 * Selector for HTML tables. Apply the given selector to the give array of
7257	 * DataTables settings objects.
7258	 *
7259	 * @param {string|integer} [selector] jQuery selector string or integer
7260	 * @param  {array} Array of DataTables settings objects to be filtered
7261	 * @return {array}
7262	 * @ignore
7263	 */
7264	var __table_selector = function ( selector, a )
7265	{
7266		// Integer is used to pick out a table by index
7267		if ( typeof selector === 'number' ) {
7268			return [ a[ selector ] ];
7269		}
7270	
7271		// Perform a jQuery selector on the table nodes
7272		var nodes = $.map( a, function (el, i) {
7273			return el.nTable;
7274		} );
7275	
7276		return $(nodes)
7277			.filter( selector )
7278			.map( function (i) {
7279				// Need to translate back from the table node to the settings
7280				var idx = $.inArray( this, nodes );
7281				return a[ idx ];
7282			} )
7283			.toArray();
7284	};
7285	
7286	
7287	
7288	/**
7289	 * Context selector for the API's context (i.e. the tables the API instance
7290	 * refers to.
7291	 *
7292	 * @name    DataTable.Api#tables
7293	 * @param {string|integer} [selector] Selector to pick which tables the iterator
7294	 *   should operate on. If not given, all tables in the current context are
7295	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7296	 *   select multiple tables or as an integer to select a single table.
7297	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7298	 */
7299	_api_register( 'tables()', function ( selector ) {
7300		// A new instance is created if there was a selector specified
7301		return selector ?
7302			new _Api( __table_selector( selector, this.context ) ) :
7303			this;
7304	} );
7305	
7306	
7307	_api_register( 'table()', function ( selector ) {
7308		var tables = this.tables( selector );
7309		var ctx = tables.context;
7310	
7311		// Truncate to the first matched table
7312		return ctx.length ?
7313			new _Api( ctx[0] ) :
7314			tables;
7315	} );
7316	
7317	
7318	_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7319		return this.iterator( 'table', function ( ctx ) {
7320			return ctx.nTable;
7321		}, 1 );
7322	} );
7323	
7324	
7325	_api_registerPlural( 'tables().body()', 'table().body()' , function () {
7326		return this.iterator( 'table', function ( ctx ) {
7327			return ctx.nTBody;
7328		}, 1 );
7329	} );
7330	
7331	
7332	_api_registerPlural( 'tables().header()', 'table().header()' , function () {
7333		return this.iterator( 'table', function ( ctx ) {
7334			return ctx.nTHead;
7335		}, 1 );
7336	} );
7337	
7338	
7339	_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7340		return this.iterator( 'table', function ( ctx ) {
7341			return ctx.nTFoot;
7342		}, 1 );
7343	} );
7344	
7345	
7346	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7347		return this.iterator( 'table', function ( ctx ) {
7348			return ctx.nTableWrapper;
7349		}, 1 );
7350	} );
7351	
7352	
7353	
7354	/**
7355	 * Redraw the tables in the current context.
7356	 */
7357	_api_register( 'draw()', function ( paging ) {
7358		return this.iterator( 'table', function ( settings ) {
7359			if ( paging === 'page' ) {
7360				_fnDraw( settings );
7361			}
7362			else {
7363				if ( typeof paging === 'string' ) {
7364					paging = paging === 'full-hold' ?
7365						false :
7366						true;
7367				}
7368	
7369				_fnReDraw( settings, paging===false );
7370			}
7371		} );
7372	} );
7373	
7374	
7375	
7376	/**
7377	 * Get the current page index.
7378	 *
7379	 * @return {integer} Current page index (zero based)
7380	 *//**
7381	 * Set the current page.
7382	 *
7383	 * Note that if you attempt to show a page which does not exist, DataTables will
7384	 * not throw an error, but rather reset the paging.
7385	 *
7386	 * @param {integer|string} action The paging action to take. This can be one of:
7387	 *  * `integer` - The page index to jump to
7388	 *  * `string` - An action to take:
7389	 *    * `first` - Jump to first page.
7390	 *    * `next` - Jump to the next page
7391	 *    * `previous` - Jump to previous page
7392	 *    * `last` - Jump to the last page.
7393	 * @returns {DataTables.Api} this
7394	 */
7395	_api_register( 'page()', function ( action ) {
7396		if ( action === undefined ) {
7397			return this.page.info().page; // not an expensive call
7398		}
7399	
7400		// else, have an action to take on all tables
7401		return this.iterator( 'table', function ( settings ) {
7402			_fnPageChange( settings, action );
7403		} );
7404	} );
7405	
7406	
7407	/**
7408	 * Paging information for the first table in the current context.
7409	 *
7410	 * If you require paging information for another table, use the `table()` method
7411	 * with a suitable selector.
7412	 *
7413	 * @return {object} Object with the following properties set:
7414	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7415	 *  * `pages` - Total number of pages
7416	 *  * `start` - Display index for the first record shown on the current page
7417	 *  * `end` - Display index for the last record shown on the current page
7418	 *  * `length` - Display length (number of records). Note that generally `start
7419	 *    + length = end`, but this is not always true, for example if there are
7420	 *    only 2 records to show on the final page, with a length of 10.
7421	 *  * `recordsTotal` - Full data set length
7422	 *  * `recordsDisplay` - Data set length once the current filtering criterion
7423	 *    are applied.
7424	 */
7425	_api_register( 'page.info()', function ( action ) {
7426		if ( this.context.length === 0 ) {
7427			return undefined;
7428		}
7429	
7430		var
7431			settings   = this.context[0],
7432			start      = settings._iDisplayStart,
7433			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7434			visRecords = settings.fnRecordsDisplay(),
7435			all        = len === -1;
7436	
7437		return {
7438			"page":           all ? 0 : Math.floor( start / len ),
7439			"pages":          all ? 1 : Math.ceil( visRecords / len ),
7440			"start":          start,
7441			"end":            settings.fnDisplayEnd(),
7442			"length":         len,
7443			"recordsTotal":   settings.fnRecordsTotal(),
7444			"recordsDisplay": visRecords,
7445			"serverSide":     _fnDataSource( settings ) === 'ssp'
7446		};
7447	} );
7448	
7449	
7450	/**
7451	 * Get the current page length.
7452	 *
7453	 * @return {integer} Current page length. Note `-1` indicates that all records
7454	 *   are to be shown.
7455	 *//**
7456	 * Set the current page length.
7457	 *
7458	 * @param {integer} Page length to set. Use `-1` to show all records.
7459	 * @returns {DataTables.Api} this
7460	 */
7461	_api_register( 'page.len()', function ( len ) {
7462		// Note that we can't call this function 'length()' because `length`
7463		// is a Javascript property of functions which defines how many arguments
7464		// the function expects.
7465		if ( len === undefined ) {
7466			return this.context.length !== 0 ?
7467				this.context[0]._iDisplayLength :
7468				undefined;
7469		}
7470	
7471		// else, set the page length
7472		return this.iterator( 'table', function ( settings ) {
7473			_fnLengthChange( settings, len );
7474		} );
7475	} );
7476	
7477	
7478	
7479	var __reload = function ( settings, holdPosition, callback ) {
7480		// Use the draw event to trigger a callback
7481		if ( callback ) {
7482			var api = new _Api( settings );
7483	
7484			api.one( 'draw', function () {
7485				callback( api.ajax.json() );
7486			} );
7487		}
7488	
7489		if ( _fnDataSource( settings ) == 'ssp' ) {
7490			_fnReDraw( settings, holdPosition );
7491		}
7492		else {
7493			_fnProcessingDisplay( settings, true );
7494	
7495			// Cancel an existing request
7496			var xhr = settings.jqXHR;
7497			if ( xhr && xhr.readyState !== 4 ) {
7498				xhr.abort();
7499			}
7500	
7501			// Trigger xhr
7502			_fnBuildAjax( settings, [], function( json ) {
7503				_fnClearTable( settings );
7504	
7505				var data = _fnAjaxDataSrc( settings, json );
7506				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7507					_fnAddData( settings, data[i] );
7508				}
7509	
7510				_fnReDraw( settings, holdPosition );
7511				_fnProcessingDisplay( settings, false );
7512			} );
7513		}
7514	};
7515	
7516	
7517	/**
7518	 * Get the JSON response from the last Ajax request that DataTables made to the
7519	 * server. Note that this returns the JSON from the first table in the current
7520	 * context.
7521	 *
7522	 * @return {object} JSON received from the server.
7523	 */
7524	_api_register( 'ajax.json()', function () {
7525		var ctx = this.context;
7526	
7527		if ( ctx.length > 0 ) {
7528			return ctx[0].json;
7529		}
7530	
7531		// else return undefined;
7532	} );
7533	
7534	
7535	/**
7536	 * Get the data submitted in the last Ajax request
7537	 */
7538	_api_register( 'ajax.params()', function () {
7539		var ctx = this.context;
7540	
7541		if ( ctx.length > 0 ) {
7542			return ctx[0].oAjaxData;
7543		}
7544	
7545		// else return undefined;
7546	} );
7547	
7548	
7549	/**
7550	 * Reload tables from the Ajax data source. Note that this function will
7551	 * automatically re-draw the table when the remote data has been loaded.
7552	 *
7553	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7554	 *   position. A full re-sort and re-filter is performed when this method is
7555	 *   called, which is why the pagination reset is the default action.
7556	 * @returns {DataTables.Api} this
7557	 */
7558	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7559		return this.iterator( 'table', function (settings) {
7560			__reload( settings, resetPaging===false, callback );
7561		} );
7562	} );
7563	
7564	
7565	/**
7566	 * Get the current Ajax URL. Note that this returns the URL from the first
7567	 * table in the current context.
7568	 *
7569	 * @return {string} Current Ajax source URL
7570	 *//**
7571	 * Set the Ajax URL. Note that this will set the URL for all tables in the
7572	 * current context.
7573	 *
7574	 * @param {string} url URL to set.
7575	 * @returns {DataTables.Api} this
7576	 */
7577	_api_register( 'ajax.url()', function ( url ) {
7578		var ctx = this.context;
7579	
7580		if ( url === undefined ) {
7581			// get
7582			if ( ctx.length === 0 ) {
7583				return undefined;
7584			}
7585			ctx = ctx[0];
7586	
7587			return ctx.ajax ?
7588				$.isPlainObject( ctx.ajax ) ?
7589					ctx.ajax.url :
7590					ctx.ajax :
7591				ctx.sAjaxSource;
7592		}
7593	
7594		// set
7595		return this.iterator( 'table', function ( settings ) {
7596			if ( $.isPlainObject( settings.ajax ) ) {
7597				settings.ajax.url = url;
7598			}
7599			else {
7600				settings.ajax = url;
7601			}
7602			// No need to consider sAjaxSource here since DataTables gives priority
7603			// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7604			// value of `sAjaxSource` redundant.
7605		} );
7606	} );
7607	
7608	
7609	/**
7610	 * Load data from the newly set Ajax URL. Note that this method is only
7611	 * available when `ajax.url()` is used to set a URL. Additionally, this method
7612	 * has the same effect as calling `ajax.reload()` but is provided for
7613	 * convenience when setting a new URL. Like `ajax.reload()` it will
7614	 * automatically redraw the table once the remote data has been loaded.
7615	 *
7616	 * @returns {DataTables.Api} this
7617	 */
7618	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7619		// Same as a reload, but makes sense to present it for easy access after a
7620		// url change
7621		return this.iterator( 'table', function ( ctx ) {
7622			__reload( ctx, resetPaging===false, callback );
7623		} );
7624	} );
7625	
7626	
7627	
7628	
7629	var _selector_run = function ( type, selector, selectFn, settings, opts )
7630	{
7631		var
7632			out = [], res,
7633			a, i, ien, j, jen,
7634			selectorType = typeof selector;
7635	
7636		// Can't just check for isArray here, as an API or jQuery instance might be
7637		// given with their array like look
7638		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7639			selector = [ selector ];
7640		}
7641	
7642		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7643			a = selector[i] && selector[i].split ?
7644				selector[i].split(',') :
7645				[ selector[i] ];
7646	
7647			for ( j=0, jen=a.length ; j<jen ; j++ ) {
7648				res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7649	
7650				if ( res && res.length ) {
7651					out = out.concat( res );
7652				}
7653			}
7654		}
7655	
7656		// selector extensions
7657		var ext = _ext.selector[ type ];
7658		if ( ext.length ) {
7659			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7660				out = ext[i]( settings, opts, out );
7661			}
7662		}
7663	
7664		return _unique( out );
7665	};
7666	
7667	
7668	var _selector_opts = function ( opts )
7669	{
7670		if ( ! opts ) {
7671			opts = {};
7672		}
7673	
7674		// Backwards compatibility for 1.9- which used the terminology filter rather
7675		// than search
7676		if ( opts.filter && opts.search === undefined ) {
7677			opts.search = opts.filter;
7678		}
7679	
7680		return $.extend( {
7681			search: 'none',
7682			order: 'current',
7683			page: 'all'
7684		}, opts );
7685	};
7686	
7687	
7688	var _selector_first = function ( inst )
7689	{
7690		// Reduce the API instance to the first item found
7691		for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7692			if ( inst[i].length > 0 ) {
7693				// Assign the first element to the first item in the instance
7694				// and truncate the instance and context
7695				inst[0] = inst[i];
7696				inst[0].length = 1;
7697				inst.length = 1;
7698				inst.context = [ inst.context[i] ];
7699	
7700				return inst;
7701			}
7702		}
7703	
7704		// Not found - return an empty instance
7705		inst.length = 0;
7706		return inst;
7707	};
7708	
7709	
7710	var _selector_row_indexes = function ( settings, opts )
7711	{
7712		var
7713			i, ien, tmp, a=[],
7714			displayFiltered = settings.aiDisplay,
7715			displayMaster = settings.aiDisplayMaster;
7716	
7717		var
7718			search = opts.search,  // none, applied, removed
7719			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7720			page   = opts.page;    // all, current
7721	
7722		if ( _fnDataSource( settings ) == 'ssp' ) {
7723			// In server-side processing mode, most options are irrelevant since
7724			// rows not shown don't exist and the index order is the applied order
7725			// Removed is a special case - for consistency just return an empty
7726			// array
7727			return search === 'removed' ?
7728				[] :
7729				_range( 0, displayMaster.length );
7730		}
7731		else if ( page == 'current' ) {
7732			// Current page implies that order=current and fitler=applied, since it is
7733			// fairly senseless otherwise, regardless of what order and search actually
7734			// are
7735			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7736				a.push( displayFiltered[i] );
7737			}
7738		}
7739		else if ( order == 'current' || order == 'applied' ) {
7740			a = search == 'none' ?
7741				displayMaster.slice() :                      // no search
7742				search == 'applied' ?
7743					displayFiltered.slice() :                // applied search
7744					$.map( displayMaster, function (el, i) { // removed search
7745						return $.inArray( el, displayFiltered ) === -1 ? el : null;
7746					} );
7747		}
7748		else if ( order == 'index' || order == 'original' ) {
7749			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7750				if ( search == 'none' ) {
7751					a.push( i );
7752				}
7753				else { // applied | removed
7754					tmp = $.inArray( i, displayFiltered );
7755	
7756					if ((tmp === -1 && search == 'removed') ||
7757						(tmp >= 0   && search == 'applied') )
7758					{
7759						a.push( i );
7760					}
7761				}
7762			}
7763		}
7764	
7765		return a;
7766	};
7767	
7768	
7769	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7770	 * Rows
7771	 *
7772	 * {}          - no selector - use all available rows
7773	 * {integer}   - row aoData index
7774	 * {node}      - TR node
7775	 * {string}    - jQuery selector to apply to the TR elements
7776	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
7777	 *
7778	 */
7779	
7780	
7781	var __row_selector = function ( settings, selector, opts )
7782	{
7783		var run = function ( sel ) {
7784			var selInt = _intVal( sel );
7785			var i, ien;
7786	
7787			// Short cut - selector is a number and no options provided (default is
7788			// all records, so no need to check if the index is in there, since it
7789			// must be - dev error if the index doesn't exist).
7790			if ( selInt !== null && ! opts ) {
7791				return [ selInt ];
7792			}
7793	
7794			var rows = _selector_row_indexes( settings, opts );
7795	
7796			if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7797				// Selector - integer
7798				return [ selInt ];
7799			}
7800			else if ( ! sel ) {
7801				// Selector - none
7802				return rows;
7803			}
7804	
7805			// Selector - function
7806			if ( typeof sel === 'function' ) {
7807				return $.map( rows, function (idx) {
7808					var row = settings.aoData[ idx ];
7809					return sel( idx, row._aData, row.nTr ) ? idx : null;
7810				} );
7811			}
7812	
7813			// Get nodes in the order from the `rows` array with null values removed
7814			var nodes = _removeEmpty(
7815				_pluck_order( settings.aoData, rows, 'nTr' )
7816			);
7817	
7818			// Selector - node
7819			if ( sel.nodeName ) {
7820				if ( sel._DT_RowIndex !== undefined ) {
7821					return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
7822				}
7823				else if ( sel._DT_CellIndex ) {
7824					return [ sel._DT_CellIndex.row ];
7825				}
7826				else {
7827					var host = $(sel).closest('*[data-dt-row]');
7828					return host.length ?
7829						[ host.data('dt-row') ] :
7830						[];
7831				}
7832			}
7833	
7834			// ID selector. Want to always be able to select rows by id, regardless
7835			// of if the tr element has been created or not, so can't rely upon
7836			// jQuery here - hence a custom implementation. This does not match
7837			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7838			// but to select it using a CSS selector engine (like Sizzle or
7839			// querySelect) it would need to need to be escaped for some characters.
7840			// DataTables simplifies this for row selectors since you can select
7841			// only a row. A # indicates an id any anything that follows is the id -
7842			// unescaped.
7843			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7844				// get row index from id
7845				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7846				if ( rowObj !== undefined ) {
7847					return [ rowObj.idx ];
7848				}
7849	
7850				// need to fall through to jQuery in case there is DOM id that
7851				// matches
7852			}
7853	
7854			// Selector - jQuery selector string, array of nodes or jQuery object/
7855			// As jQuery's .filter() allows jQuery objects to be passed in filter,
7856			// it also allows arrays, so this will cope with all three options
7857			return $(nodes)
7858				.filter( sel )
7859				.map( function () {
7860					return this._DT_RowIndex;
7861				} )
7862				.toArray();
7863		};
7864	
7865		return _selector_run( 'row', selector, run, settings, opts );
7866	};
7867	
7868	
7869	_api_register( 'rows()', function ( selector, opts ) {
7870		// argument shifting
7871		if ( selector === undefined ) {
7872			selector = '';
7873		}
7874		else if ( $.isPlainObject( selector ) ) {
7875			opts = selector;
7876			selector = '';
7877		}
7878	
7879		opts = _selector_opts( opts );
7880	
7881		var inst = this.iterator( 'table', function ( settings ) {
7882			return __row_selector( settings, selector, opts );
7883		}, 1 );
7884	
7885		// Want argument shifting here and in __row_selector?
7886		inst.selector.rows = selector;
7887		inst.selector.opts = opts;
7888	
7889		return inst;
7890	} );
7891	
7892	_api_register( 'rows().nodes()', function () {
7893		return this.iterator( 'row', function ( settings, row ) {
7894			return settings.aoData[ row ].nTr || undefined;
7895		}, 1 );
7896	} );
7897	
7898	_api_register( 'rows().data()', function () {
7899		return this.iterator( true, 'rows', function ( settings, rows ) {
7900			return _pluck_order( settings.aoData, rows, '_aData' );
7901		}, 1 );
7902	} );
7903	
7904	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7905		return this.iterator( 'row', function ( settings, row ) {
7906			var r = settings.aoData[ row ];
7907			return type === 'search' ? r._aFilterData : r._aSortData;
7908		}, 1 );
7909	} );
7910	
7911	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7912		return this.iterator( 'row', function ( settings, row ) {
7913			_fnInvalidate( settings, row, src );
7914		} );
7915	} );
7916	
7917	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7918		return this.iterator( 'row', function ( settings, row ) {
7919			return row;
7920		}, 1 );
7921	} );
7922	
7923	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7924		var a = [];
7925		var context = this.context;
7926	
7927		// `iterator` will drop undefined values, but in this case we want them
7928		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7929			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7930				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7931				a.push( (hash === true ? '#' : '' )+ id );
7932			}
7933		}
7934	
7935		return new _Api( context, a );
7936	} );
7937	
7938	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7939		var that = this;
7940	
7941		this.iterator( 'row', function ( settings, row, thatIdx ) {
7942			var data = settings.aoData;
7943			var rowData = data[ row ];
7944			var i, ien, j, jen;
7945			var loopRow, loopCells;
7946	
7947			data.splice( row, 1 );
7948	
7949			// Update the cached indexes
7950			for ( i=0, ien=data.length ; i<ien ; i++ ) {
7951				loopRow = data[i];
7952				loopCells = loopRow.anCells;
7953	
7954				// Rows
7955				if ( loopRow.nTr !== null ) {
7956					loopRow.nTr._DT_RowIndex = i;
7957				}
7958	
7959				// Cells
7960				if ( loopCells !== null ) {
7961					for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
7962						loopCells[j]._DT_CellIndex.row = i;
7963					}
7964				}
7965			}
7966	
7967			// Delete from the display arrays
7968			_fnDeleteIndex( settings.aiDisplayMaster, row );
7969			_fnDeleteIndex( settings.aiDisplay, row );
7970			_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7971	
7972			// Check for an 'overflow' they case for displaying the table
7973			_fnLengthOverflow( settings );
7974	
7975			// Remove the row's ID reference if there is one
7976			var id = settings.rowIdFn( rowData._aData );
7977			if ( id !== undefined ) {
7978				delete settings.aIds[ id ];
7979			}
7980		} );
7981	
7982		this.iterator( 'table', function ( settings ) {
7983			for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7984				settings.aoData[i].idx = i;
7985			}
7986		} );
7987	
7988		return this;
7989	} );
7990	
7991	
7992	_api_register( 'rows.add()', function ( rows ) {
7993		var newRows = this.iterator( 'table', function ( settings ) {
7994				var row, i, ien;
7995				var out = [];
7996	
7997				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7998					row = rows[i];
7999	
8000					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8001						out.push( _fnAddTr( settings, row )[0] );
8002					}
8003					else {
8004						out.push( _fnAddData( settings, row ) );
8005					}
8006				}
8007	
8008				return out;
8009			}, 1 );
8010	
8011		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
8012		var modRows = this.rows( -1 );
8013		modRows.pop();
8014		$.merge( modRows, newRows );
8015	
8016		return modRows;
8017	} );
8018	
8019	
8020	
8021	
8022	
8023	/**
8024	 *
8025	 */
8026	_api_register( 'row()', function ( selector, opts ) {
8027		return _selector_first( this.rows( selector, opts ) );
8028	} );
8029	
8030	
8031	_api_register( 'row().data()', function ( data ) {
8032		var ctx = this.context;
8033	
8034		if ( data === undefined ) {
8035			// Get
8036			return ctx.length && this.length ?
8037				ctx[0].aoData[ this[0] ]._aData :
8038				undefined;
8039		}
8040	
8041		// Set
8042		ctx[0].aoData[ this[0] ]._aData = data;
8043	
8044		// Automatically invalidate
8045		_fnInvalidate( ctx[0], this[0], 'data' );
8046	
8047		return this;
8048	} );
8049	
8050	
8051	_api_register( 'row().node()', function () {
8052		var ctx = this.context;
8053	
8054		return ctx.length && this.length ?
8055			ctx[0].aoData[ this[0] ].nTr || null :
8056			null;
8057	} );
8058	
8059	
8060	_api_register( 'row.add()', function ( row ) {
8061		// Allow a jQuery object to be passed in - only a single row is added from
8062		// it though - the first element in the set
8063		if ( row instanceof $ && row.length ) {
8064			row = row[0];
8065		}
8066	
8067		var rows = this.iterator( 'table', function ( settings ) {
8068			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8069				return _fnAddTr( settings, row )[0];
8070			}
8071			return _fnAddData( settings, row );
8072		} );
8073	
8074		// Return an Api.rows() extended instance, with the newly added row selected
8075		return this.row( rows[0] );
8076	} );
8077	
8078	
8079	
8080	var __details_add = function ( ctx, row, data, klass )
8081	{
8082		// Convert to array of TR elements
8083		var rows = [];
8084		var addRow = function ( r, k ) {
8085			// Recursion to allow for arrays of jQuery objects
8086			if ( $.isArray( r ) || r instanceof $ ) {
8087				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8088					addRow( r[i], k );
8089				}
8090				return;
8091			}
8092	
8093			// If we get a TR element, then just add it directly - up to the dev
8094			// to add the correct number of columns etc
8095			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8096				rows.push( r );
8097			}
8098			else {
8099				// Otherwise create a row with a wrapper
8100				var created = $('<tr><td/></tr>').addClass( k );
8101				$('td', created)
8102					.addClass( k )
8103					.html( r )
8104					[0].colSpan = _fnVisbleColumns( ctx );
8105	
8106				rows.push( created[0] );
8107			}
8108		};
8109	
8110		addRow( data, klass );
8111	
8112		if ( row._details ) {
8113			row._details.remove();
8114		}
8115	
8116		row._details = $(rows);
8117	
8118		// If the children were already shown, that state should be retained
8119		if ( row._detailsShow ) {
8120			row._details.insertAfter( row.nTr );
8121		}
8122	};
8123	
8124	
8125	var __details_remove = function ( api, idx )
8126	{
8127		var ctx = api.context;
8128	
8129		if ( ctx.length ) {
8130			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8131	
8132			if ( row && row._details ) {
8133				row._details.remove();
8134	
8135				row._detailsShow = undefined;
8136				row._details = undefined;
8137			}
8138		}
8139	};
8140	
8141	
8142	var __details_display = function ( api, show ) {
8143		var ctx = api.context;
8144	
8145		if ( ctx.length && api.length ) {
8146			var row = ctx[0].aoData[ api[0] ];
8147	
8148			if ( row._details ) {
8149				row._detailsShow = show;
8150	
8151				if ( show ) {
8152					row._details.insertAfter( row.nTr );
8153				}
8154				else {
8155					row._details.detach();
8156				}
8157	
8158				__details_events( ctx[0] );
8159			}
8160		}
8161	};
8162	
8163	
8164	var __details_events = function ( settings )
8165	{
8166		var api = new _Api( settings );
8167		var namespace = '.dt.DT_details';
8168		var drawEvent = 'draw'+namespace;
8169		var colvisEvent = 'column-visibility'+namespace;
8170		var destroyEvent = 'destroy'+namespace;
8171		var data = settings.aoData;
8172	
8173		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8174	
8175		if ( _pluck( data, '_details' ).length > 0 ) {
8176			// On each draw, insert the required elements into the document
8177			api.on( drawEvent, function ( e, ctx ) {
8178				if ( settings !== ctx ) {
8179					return;
8180				}
8181	
8182				api.rows( {page:'current'} ).eq(0).each( function (idx) {
8183					// Internal data grab
8184					var row = data[ idx ];
8185	
8186					if ( row._detailsShow ) {
8187						row._details.insertAfter( row.nTr );
8188					}
8189				} );
8190			} );
8191	
8192			// Column visibility change - update the colspan
8193			api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8194				if ( settings !== ctx ) {
8195					return;
8196				}
8197	
8198				// Update the colspan for the details rows (note, only if it already has
8199				// a colspan)
8200				var row, visible = _fnVisbleColumns( ctx );
8201	
8202				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8203					row = data[i];
8204	
8205					if ( row._details ) {
8206						row._details.children('td[colspan]').attr('colspan', visible );
8207					}
8208				}
8209			} );
8210	
8211			// Table destroyed - nuke any child rows
8212			api.on( destroyEvent, function ( e, ctx ) {
8213				if ( settings !== ctx ) {
8214					return;
8215				}
8216	
8217				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8218					if ( data[i]._details ) {
8219						__details_remove( api, i );
8220					}
8221				}
8222			} );
8223		}
8224	};
8225	
8226	// Strings for the method names to help minification
8227	var _emp = '';
8228	var _child_obj = _emp+'row().child';
8229	var _child_mth = _child_obj+'()';
8230	
8231	// data can be:
8232	//  tr
8233	//  string
8234	//  jQuery or array of any of the above
8235	_api_register( _child_mth, function ( data, klass ) {
8236		var ctx = this.context;
8237	
8238		if ( data === undefined ) {
8239			// get
8240			return ctx.length && this.length ?
8241				ctx[0].aoData[ this[0] ]._details :
8242				undefined;
8243		}
8244		else if ( data === true ) {
8245			// show
8246			this.child.show();
8247		}
8248		else if ( data === false ) {
8249			// remove
8250			__details_remove( this );
8251		}
8252		else if ( ctx.length && this.length ) {
8253			// set
8254			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8255		}
8256	
8257		return this;
8258	} );
8259	
8260	
8261	_api_register( [
8262		_child_obj+'.show()',
8263		_child_mth+'.show()' // only when `child()` was called with parameters (without
8264	], function ( show ) {   // it returns an object and this method is not executed)
8265		__details_display( this, true );
8266		return this;
8267	} );
8268	
8269	
8270	_api_register( [
8271		_child_obj+'.hide()',
8272		_child_mth+'.hide()' // only when `child()` was called with parameters (without
8273	], function () {         // it returns an object and this method is not executed)
8274		__details_display( this, false );
8275		return this;
8276	} );
8277	
8278	
8279	_api_register( [
8280		_child_obj+'.remove()',
8281		_child_mth+'.remove()' // only when `child()` was called with parameters (without
8282	], function () {           // it returns an object and this method is not executed)
8283		__details_remove( this );
8284		return this;
8285	} );
8286	
8287	
8288	_api_register( _child_obj+'.isShown()', function () {
8289		var ctx = this.context;
8290	
8291		if ( ctx.length && this.length ) {
8292			// _detailsShown as false or undefined will fall through to return false
8293			return ctx[0].aoData[ this[0] ]._detailsShow || false;
8294		}
8295		return false;
8296	} );
8297	
8298	
8299	
8300	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8301	 * Columns
8302	 *
8303	 * {integer}           - column index (>=0 count from left, <0 count from right)
8304	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8305	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8306	 * "{string}:name"     - column name
8307	 * "{string}"          - jQuery selector on column header nodes
8308	 *
8309	 */
8310	
8311	// can be an array of these items, comma separated list, or an array of comma
8312	// separated lists
8313	
8314	var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8315	
8316	
8317	// r1 and r2 are redundant - but it means that the parameters match for the
8318	// iterator callback in columns().data()
8319	var __columnData = function ( settings, column, r1, r2, rows ) {
8320		var a = [];
8321		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8322			a.push( _fnGetCellData( settings, rows[row], column ) );
8323		}
8324		return a;
8325	};
8326	
8327	
8328	var __column_selector = function ( settings, selector, opts )
8329	{
8330		var
8331			columns = settings.aoColumns,
8332			names = _pluck( columns, 'sName' ),
8333			nodes = _pluck( columns, 'nTh' );
8334	
8335		var run = function ( s ) {
8336			var selInt = _intVal( s );
8337	
8338			// Selector - all
8339			if ( s === '' ) {
8340				return _range( columns.length );
8341			}
8342			
8343			// Selector - index
8344			if ( selInt !== null ) {
8345				return [ selInt >= 0 ?
8346					selInt : // Count from left
8347					columns.length + selInt // Count from right (+ because its a negative value)
8348				];
8349			}
8350			
8351			// Selector = function
8352			if ( typeof s === 'function' ) {
8353				var rows = _selector_row_indexes( settings, opts );
8354	
8355				return $.map( columns, function (col, idx) {
8356					return s(
8357							idx,
8358							__columnData( settings, idx, 0, 0, rows ),
8359							nodes[ idx ]
8360						) ? idx : null;
8361				} );
8362			}
8363	
8364			// jQuery or string selector
8365			var match = typeof s === 'string' ?
8366				s.match( __re_column_selector ) :
8367				'';
8368	
8369			if ( match ) {
8370				switch( match[2] ) {
8371					case 'visIdx':
8372					case 'visible':
8373						var idx = parseInt( match[1], 10 );
8374						// Visible index given, convert to column index
8375						if ( idx < 0 ) {
8376							// Counting from the right
8377							var visColumns = $.map( columns, function (col,i) {
8378								return col.bVisible ? i : null;
8379							} );
8380							return [ visColumns[ visColumns.length + idx ] ];
8381						}
8382						// Counting from the left
8383						return [ _fnVisibleToColumnIndex( settings, idx ) ];
8384	
8385					case 'name':
8386						// match by name. `names` is column index complete and in order
8387						return $.map( names, function (name, i) {
8388							return name === match[1] ? i : null;
8389						} );
8390	
8391					default:
8392						return [];
8393				}
8394			}
8395	
8396			// Cell in the table body
8397			if ( s.nodeName && s._DT_CellIndex ) {
8398				return [ s._DT_CellIndex.column ];
8399			}
8400	
8401			// jQuery selector on the TH elements for the columns
8402			var jqResult = $( nodes )
8403				.filter( s )
8404				.map( function () {
8405					return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8406				} )
8407				.toArray();
8408	
8409			if ( jqResult.length || ! s.nodeName ) {
8410				return jqResult;
8411			}
8412	
8413			// Otherwise a node which might have a `dt-column` data attribute, or be
8414			// a child or such an element
8415			var host = $(s).closest('*[data-dt-column]');
8416			return host.length ?
8417				[ host.data('dt-column') ] :
8418				[];
8419		};
8420	
8421		return _selector_run( 'column', selector, run, settings, opts );
8422	};
8423	
8424	
8425	var __setColumnVis = function ( settings, column, vis, recalc ) {
8426		var
8427			cols = settings.aoColumns,
8428			col  = cols[ column ],
8429			data = settings.aoData,
8430			row, cells, i, ien, tr;
8431	
8432		// Get
8433		if ( vis === undefined ) {
8434			return col.bVisible;
8435		}
8436	
8437		// Set
8438		// No change
8439		if ( col.bVisible === vis ) {
8440			return;
8441		}
8442	
8443		if ( vis ) {
8444			// Insert column
8445			// Need to decide if we should use appendChild or insertBefore
8446			var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8447	
8448			for ( i=0, ien=data.length ; i<ien ; i++ ) {
8449				tr = data[i].nTr;
8450				cells = data[i].anCells;
8451	
8452				if ( tr ) {
8453					// insertBefore can act like appendChild if 2nd arg is null
8454					tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8455				}
8456			}
8457		}
8458		else {
8459			// Remove column
8460			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
8461		}
8462	
8463		// Common actions
8464		col.bVisible = vis;
8465		_fnDrawHead( settings, settings.aoHeader );
8466		_fnDrawHead( settings, settings.aoFooter );
8467	
8468		if ( recalc === undefined || recalc ) {
8469			// Automatically adjust column sizing
8470			_fnAdjustColumnSizing( settings );
8471		}
8472	
8473		_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, recalc] );
8474	
8475		_fnSaveState( settings );
8476	};
8477	
8478	
8479	_api_register( 'columns()', function ( selector, opts ) {
8480		// argument shifting
8481		if ( selector === undefined ) {
8482			selector = '';
8483		}
8484		else if ( $.isPlainObject( selector ) ) {
8485			opts = selector;
8486			selector = '';
8487		}
8488	
8489		opts = _selector_opts( opts );
8490	
8491		var inst = this.iterator( 'table', function ( settings ) {
8492			return __column_selector( settings, selector, opts );
8493		}, 1 );
8494	
8495		// Want argument shifting here and in _row_selector?
8496		inst.selector.cols = selector;
8497		inst.selector.opts = opts;
8498	
8499		return inst;
8500	} );
8501	
8502	_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8503		return this.iterator( 'column', function ( settings, column ) {
8504			return settings.aoColumns[column].nTh;
8505		}, 1 );
8506	} );
8507	
8508	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8509		return this.iterator( 'column', function ( settings, column ) {
8510			return settings.aoColumns[column].nTf;
8511		}, 1 );
8512	} );
8513	
8514	_api_registerPlural( 'columns().data()', 'column().data()', function () {
8515		return this.iterator( 'column-rows', __columnData, 1 );
8516	} );
8517	
8518	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8519		return this.iterator( 'column', function ( settings, column ) {
8520			return settings.aoColumns[column].mData;
8521		}, 1 );
8522	} );
8523	
8524	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8525		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8526			return _pluck_order( settings.aoData, rows,
8527				type === 'search' ? '_aFilterData' : '_aSortData', column
8528			);
8529		}, 1 );
8530	} );
8531	
8532	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8533		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8534			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8535		}, 1 );
8536	} );
8537	
8538	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8539		return this.iterator( 'column', function ( settings, column ) {
8540			if ( vis === undefined ) {
8541				return settings.aoColumns[ column ].bVisible;
8542			} // else
8543			__setColumnVis( settings, column, vis, calc );
8544		} );
8545	} );
8546	
8547	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8548		return this.iterator( 'column', function ( settings, column ) {
8549			return type === 'visible' ?
8550				_fnColumnIndexToVisible( settings, column ) :
8551				column;
8552		}, 1 );
8553	} );
8554	
8555	_api_register( 'columns.adjust()', function () {
8556		return this.iterator( 'table', function ( settings ) {
8557			_fnAdjustColumnSizing( settings );
8558		}, 1 );
8559	} );
8560	
8561	_api_register( 'column.index()', function ( type, idx ) {
8562		if ( this.context.length !== 0 ) {
8563			var ctx = this.context[0];
8564	
8565			if ( type === 'fromVisible' || type === 'toData' ) {
8566				return _fnVisibleToColumnIndex( ctx, idx );
8567			}
8568			else if ( type === 'fromData' || type === 'toVisible' ) {
8569				return _fnColumnIndexToVisible( ctx, idx );
8570			}
8571		}
8572	} );
8573	
8574	_api_register( 'column()', function ( selector, opts ) {
8575		return _selector_first( this.columns( selector, opts ) );
8576	} );
8577	
8578	
8579	
8580	
8581	var __cell_selector = function ( settings, selector, opts )
8582	{
8583		var data = settings.aoData;
8584		var rows = _selector_row_indexes( settings, opts );
8585		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8586		var allCells = $( [].concat.apply([], cells) );
8587		var row;
8588		var columns = settings.aoColumns.length;
8589		var a, i, ien, j, o, host;
8590	
8591		var run = function ( s ) {
8592			var fnSelector = typeof s === 'function';
8593	
8594			if ( s === null || s === undefined || fnSelector ) {
8595				// All cells and function selectors
8596				a = [];
8597	
8598				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8599					row = rows[i];
8600	
8601					for ( j=0 ; j<columns ; j++ ) {
8602						o = {
8603							row: row,
8604							column: j
8605						};
8606	
8607						if ( fnSelector ) {
8608							// Selector - function
8609							host = data[ row ];
8610	
8611							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8612								a.push( o );
8613							}
8614						}
8615						else {
8616							// Selector - all
8617							a.push( o );
8618						}
8619					}
8620				}
8621	
8622				return a;
8623			}
8624			
8625			// Selector - index
8626			if ( $.isPlainObject( s ) ) {
8627				return [s];
8628			}
8629	
8630			// Selector - jQuery filtered cells
8631			var jqResult = allCells
8632				.filter( s )
8633				.map( function (i, el) {
8634					return { // use a new object, in case someone changes the values
8635						row:    el._DT_CellIndex.row,
8636						column: el._DT_CellIndex.column
8637	 				};
8638				} )
8639				.toArray();
8640	
8641			if ( jqResult.length || ! s.nodeName ) {
8642				return jqResult;
8643			}
8644	
8645			// Otherwise the selector is a node, and there is one last option - the
8646			// element might be a child of an element which has dt-row and dt-column
8647			// data attributes
8648			host = $(s).closest('*[data-dt-row]');
8649			return host.length ?
8650				[ {
8651					row: host.data('dt-row'),
8652					column: host.data('dt-column')
8653				} ] :
8654				[];
8655		};
8656	
8657		return _selector_run( 'cell', selector, run, settings, opts );
8658	};
8659	
8660	
8661	
8662	
8663	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8664		// Argument shifting
8665		if ( $.isPlainObject( rowSelector ) ) {
8666			// Indexes
8667			if ( rowSelector.row === undefined ) {
8668				// Selector options in first parameter
8669				opts = rowSelector;
8670				rowSelector = null;
8671			}
8672			else {
8673				// Cell index objects in first parameter
8674				opts = columnSelector;
8675				columnSelector = null;
8676			}
8677		}
8678		if ( $.isPlainObject( columnSelector ) ) {
8679			opts = columnSelector;
8680			columnSelector = null;
8681		}
8682	
8683		// Cell selector
8684		if ( columnSelector === null || columnSelector === undefined ) {
8685			return this.iterator( 'table', function ( settings ) {
8686				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8687			} );
8688		}
8689	
8690		// Row + column selector
8691		var columns = this.columns( columnSelector, opts );
8692		var rows = this.rows( rowSelector, opts );
8693		var a, i, ien, j, jen;
8694	
8695		var cells = this.iterator( 'table', function ( settings, idx ) {
8696			a = [];
8697	
8698			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8699				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8700					a.push( {
8701						row:    rows[idx][i],
8702						column: columns[idx][j]
8703					} );
8704				}
8705			}
8706	
8707			return a;
8708		}, 1 );
8709	
8710		$.extend( cells.selector, {
8711			cols: columnSelector,
8712			rows: rowSelector,
8713			opts: opts
8714		} );
8715	
8716		return cells;
8717	} );
8718	
8719	
8720	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8721		return this.iterator( 'cell', function ( settings, row, column ) {
8722			var data = settings.aoData[ row ];
8723	
8724			return data && data.anCells ?
8725				data.anCells[ column ] :
8726				undefined;
8727		}, 1 );
8728	} );
8729	
8730	
8731	_api_register( 'cells().data()', function () {
8732		return this.iterator( 'cell', function ( settings, row, column ) {
8733			return _fnGetCellData( settings, row, column );
8734		}, 1 );
8735	} );
8736	
8737	
8738	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8739		type = type === 'search' ? '_aFilterData' : '_aSortData';
8740	
8741		return this.iterator( 'cell', function ( settings, row, column ) {
8742			return settings.aoData[ row ][ type ][ column ];
8743		}, 1 );
8744	} );
8745	
8746	
8747	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8748		return this.iterator( 'cell', function ( settings, row, column ) {
8749			return _fnGetCellData( settings, row, column, type );
8750		}, 1 );
8751	} );
8752	
8753	
8754	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8755		return this.iterator( 'cell', function ( settings, row, column ) {
8756			return {
8757				row: row,
8758				column: column,
8759				columnVisible: _fnColumnIndexToVisible( settings, column )
8760			};
8761		}, 1 );
8762	} );
8763	
8764	
8765	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8766		return this.iterator( 'cell', function ( settings, row, column ) {
8767			_fnInvalidate( settings, row, src, column );
8768		} );
8769	} );
8770	
8771	
8772	
8773	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8774		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8775	} );
8776	
8777	
8778	_api_register( 'cell().data()', function ( data ) {
8779		var ctx = this.context;
8780		var cell = this[0];
8781	
8782		if ( data === undefined ) {
8783			// Get
8784			return ctx.length && cell.length ?
8785				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8786				undefined;
8787		}
8788	
8789		// Set
8790		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8791		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8792	
8793		return this;
8794	} );
8795	
8796	
8797	
8798	/**
8799	 * Get current ordering (sorting) that has been applied to the table.
8800	 *
8801	 * @returns {array} 2D array containing the sorting information for the first
8802	 *   table in the current context. Each element in the parent array represents
8803	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
8804	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8805	 *   the column index that the sorting condition applies to, the second is the
8806	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
8807	 *   index of the sorting order from the `column.sorting` initialisation array.
8808	 *//**
8809	 * Set the ordering for the table.
8810	 *
8811	 * @param {integer} order Column index to sort upon.
8812	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8813	 * @returns {DataTables.Api} this
8814	 *//**
8815	 * Set the ordering for the table.
8816	 *
8817	 * @param {array} order 1D array of sorting information to be applied.
8818	 * @param {array} [...] Optional additional sorting conditions
8819	 * @returns {DataTables.Api} this
8820	 *//**
8821	 * Set the ordering for the table.
8822	 *
8823	 * @param {array} order 2D array of sorting information to be applied.
8824	 * @returns {DataTables.Api} this
8825	 */
8826	_api_register( 'order()', function ( order, dir ) {
8827		var ctx = this.context;
8828	
8829		if ( order === undefined ) {
8830			// get
8831			return ctx.length !== 0 ?
8832				ctx[0].aaSorting :
8833				undefined;
8834		}
8835	
8836		// set
8837		if ( typeof order === 'number' ) {
8838			// Simple column / direction passed in
8839			order = [ [ order, dir ] ];
8840		}
8841		else if ( ! $.isArray( order[0] ) ) {
8842			// Arguments passed in (list of 1D arrays)
8843			order = Array.prototype.slice.call( arguments );
8844		}
8845		// otherwise a 2D array was passed in
8846	
8847		return this.iterator( 'table', function ( settings ) {
8848			settings.aaSorting = order.slice();
8849		} );
8850	} );
8851	
8852	
8853	/**
8854	 * Attach a sort listener to an element for a given column
8855	 *
8856	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8857	 *   listener to. This can take the form of a single DOM node, a jQuery
8858	 *   collection of nodes or a jQuery selector which will identify the node(s).
8859	 * @param {integer} column the column that a click on this node will sort on
8860	 * @param {function} [callback] callback function when sort is run
8861	 * @returns {DataTables.Api} this
8862	 */
8863	_api_register( 'order.listener()', function ( node, column, callback ) {
8864		return this.iterator( 'table', function ( settings ) {
8865			_fnSortAttachListener( settings, node, column, callback );
8866		} );
8867	} );
8868	
8869	
8870	_api_register( 'order.fixed()', function ( set ) {
8871		if ( ! set ) {
8872			var ctx = this.context;
8873			var fixed = ctx.length ?
8874				ctx[0].aaSortingFixed :
8875				undefined;
8876	
8877			return $.isArray( fixed ) ?
8878				{ pre: fixed } :
8879				fixed;
8880		}
8881	
8882		return this.iterator( 'table', function ( settings ) {
8883			settings.aaSortingFixed = $.extend( true, {}, set );
8884		} );
8885	} );
8886	
8887	
8888	// Order by the selected column(s)
8889	_api_register( [
8890		'columns().order()',
8891		'column().order()'
8892	], function ( dir ) {
8893		var that = this;
8894	
8895		return this.iterator( 'table', function ( settings, i ) {
8896			var sort = [];
8897	
8898			$.each( that[i], function (j, col) {
8899				sort.push( [ col, dir ] );
8900			} );
8901	
8902			settings.aaSorting = sort;
8903		} );
8904	} );
8905	
8906	
8907	
8908	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8909		var ctx = this.context;
8910	
8911		if ( input === undefined ) {
8912			// get
8913			return ctx.length !== 0 ?
8914				ctx[0].oPreviousSearch.sSearch :
8915				undefined;
8916		}
8917	
8918		// set
8919		return this.iterator( 'table', function ( settings ) {
8920			if ( ! settings.oFeatures.bFilter ) {
8921				return;
8922			}
8923	
8924			_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8925				"sSearch": input+"",
8926				"bRegex":  regex === null ? false : regex,
8927				"bSmart":  smart === null ? true  : smart,
8928				"bCaseInsensitive": caseInsen === null ? true : caseInsen
8929			} ), 1 );
8930		} );
8931	} );
8932	
8933	
8934	_api_registerPlural(
8935		'columns().search()',
8936		'column().search()',
8937		function ( input, regex, smart, caseInsen ) {
8938			return this.iterator( 'column', function ( settings, column ) {
8939				var preSearch = settings.aoPreSearchCols;
8940	
8941				if ( input === undefined ) {
8942					// get
8943					return preSearch[ column ].sSearch;
8944				}
8945	
8946				// set
8947				if ( ! settings.oFeatures.bFilter ) {
8948					return;
8949				}
8950	
8951				$.extend( preSearch[ column ], {
8952					"sSearch": input+"",
8953					"bRegex":  regex === null ? false : regex,
8954					"bSmart":  smart === null ? true  : smart,
8955					"bCaseInsensitive": caseInsen === null ? true : caseInsen
8956				} );
8957	
8958				_fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8959			} );
8960		}
8961	);
8962	
8963	/*
8964	 * State API methods
8965	 */
8966	
8967	_api_register( 'state()', function () {
8968		return this.context.length ?
8969			this.context[0].oSavedState :
8970			null;
8971	} );
8972	
8973	
8974	_api_register( 'state.clear()', function () {
8975		return this.iterator( 'table', function ( settings ) {
8976			// Save an empty object
8977			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8978		} );
8979	} );
8980	
8981	
8982	_api_register( 'state.loaded()', function () {
8983		return this.context.length ?
8984			this.context[0].oLoadedState :
8985			null;
8986	} );
8987	
8988	
8989	_api_register( 'state.save()', function () {
8990		return this.iterator( 'table', function ( settings ) {
8991			_fnSaveState( settings );
8992		} );
8993	} );
8994	
8995	
8996	
8997	/**
8998	 * Provide a common method for plug-ins to check the version of DataTables being
8999	 * used, in order to ensure compatibility.
9000	 *
9001	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
9002	 *    Note that the formats "X" and "X.Y" are also acceptable.
9003	 *  @returns {boolean} true if this version of DataTables is greater or equal to
9004	 *    the required version, or false if this version of DataTales is not
9005	 *    suitable
9006	 *  @static
9007	 *  @dtopt API-Static
9008	 *
9009	 *  @example
9010	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9011	 */
9012	DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9013	{
9014		var aThis = DataTable.version.split('.');
9015		var aThat = version.split('.');
9016		var iThis, iThat;
9017	
9018		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9019			iThis = parseInt( aThis[i], 10 ) || 0;
9020			iThat = parseInt( aThat[i], 10 ) || 0;
9021	
9022			// Parts are the same, keep comparing
9023			if (iThis === iThat) {
9024				continue;
9025			}
9026	
9027			// Parts are different, return immediately
9028			return iThis > iThat;
9029		}
9030	
9031		return true;
9032	};
9033	
9034	
9035	/**
9036	 * Check if a `<table>` node is a DataTable table already or not.
9037	 *
9038	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9039	 *      selector for the table to test. Note that if more than more than one
9040	 *      table is passed on, only the first will be checked
9041	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
9042	 *  @static
9043	 *  @dtopt API-Static
9044	 *
9045	 *  @example
9046	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9047	 *      $('#example').dataTable();
9048	 *    }
9049	 */
9050	DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9051	{
9052		var t = $(table).get(0);
9053		var is = false;
9054	
9055		$.each( DataTable.settings, function (i, o) {
9056			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9057			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9058	
9059			if ( o.nTable === t || head === t || foot === t ) {
9060				is = true;
9061			}
9062		} );
9063	
9064		return is;
9065	};
9066	
9067	
9068	/**
9069	 * Get all DataTable tables that have been initialised - optionally you can
9070	 * select to get only currently visible tables.
9071	 *
9072	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9073	 *    or visible tables only.
9074	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9075	 *    DataTables
9076	 *  @static
9077	 *  @dtopt API-Static
9078	 *
9079	 *  @example
9080	 *    $.each( $.fn.dataTable.tables(true), function () {
9081	 *      $(table).DataTable().columns.adjust();
9082	 *    } );
9083	 */
9084	DataTable.tables = DataTable.fnTables = function ( visible )
9085	{
9086		var api = false;
9087	
9088		if ( $.isPlainObject( visible ) ) {
9089			api = visible.api;
9090			visible = visible.visible;
9091		}
9092	
9093		var a = $.map( DataTable.settings, function (o) {
9094			if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9095				return o.nTable;
9096			}
9097		} );
9098	
9099		return api ?
9100			new _Api( a ) :
9101			a;
9102	};
9103	
9104	
9105	/**
9106	 * DataTables utility methods
9107	 * 
9108	 * This namespace provides helper methods that DataTables uses internally to
9109	 * create a DataTable, but which are not exclusively used only for DataTables.
9110	 * These methods can be used by extension authors to save the duplication of
9111	 * code.
9112	 *
9113	 *  @namespace
9114	 */
9115	DataTable.util = {
9116		/**
9117		 * Throttle the calls to a function. Arguments and context are maintained
9118		 * for the throttled function.
9119		 *
9120		 * @param {function} fn Function to be called
9121		 * @param {integer} freq Call frequency in mS
9122		 * @return {function} Wrapped function
9123		 */
9124		throttle: _fnThrottle,
9125	
9126	
9127		/**
9128		 * Escape a string such that it can be used in a regular expression
9129		 *
9130		 *  @param {string} sVal string to escape
9131		 *  @returns {string} escaped string
9132		 */
9133		escapeRegex: _fnEscapeRegex
9134	};
9135	
9136	
9137	/**
9138	 * Convert from camel case parameters to Hungarian notation. This is made public
9139	 * for the extensions to provide the same ability as DataTables core to accept
9140	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9141	 * parameters.
9142	 *
9143	 *  @param {object} src The model object which holds all parameters that can be
9144	 *    mapped.
9145	 *  @param {object} user The object to convert from camel case to Hungarian.
9146	 *  @param {boolean} force When set to `true`, properties which already have a
9147	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
9148	 *    won't be.
9149	 */
9150	DataTable.camelToHungarian = _fnCamelToHungarian;
9151	
9152	
9153	
9154	/**
9155	 *
9156	 */
9157	_api_register( '$()', function ( selector, opts ) {
9158		var
9159			rows   = this.rows( opts ).nodes(), // Get all rows
9160			jqRows = $(rows);
9161	
9162		return $( [].concat(
9163			jqRows.filter( selector ).toArray(),
9164			jqRows.find( selector ).toArray()
9165		) );
9166	} );
9167	
9168	
9169	// jQuery functions to operate on the tables
9170	$.each( [ 'on', 'one', 'off' ], function (i, key) {
9171		_api_register( key+'()', function ( /* event, handler */ ) {
9172			var args = Array.prototype.slice.call(arguments);
9173	
9174			// Add the `dt` namespace automatically if it isn't already present
9175			if ( ! args[0].match(/\.dt\b/) ) {
9176				args[0] += '.dt';
9177			}
9178	
9179			var inst = $( this.tables().nodes() );
9180			inst[key].apply( inst, args );
9181			return this;
9182		} );
9183	} );
9184	
9185	
9186	_api_register( 'clear()', function () {
9187		return this.iterator( 'table', function ( settings ) {
9188			_fnClearTable( settings );
9189		} );
9190	} );
9191	
9192	
9193	_api_register( 'settings()', function () {
9194		return new _Api( this.context, this.context );
9195	} );
9196	
9197	
9198	_api_register( 'init()', function () {
9199		var ctx = this.context;
9200		return ctx.length ? ctx[0].oInit : null;
9201	} );
9202	
9203	
9204	_api_register( 'data()', function () {
9205		return this.iterator( 'table', function ( settings ) {
9206			return _pluck( settings.aoData, '_aData' );
9207		} ).flatten();
9208	} );
9209	
9210	
9211	_api_register( 'destroy()', function ( remove ) {
9212		remove = remove || false;
9213	
9214		return this.iterator( 'table', function ( settings ) {
9215			var orig      = settings.nTableWrapper.parentNode;
9216			var classes   = settings.oClasses;
9217			var table     = settings.nTable;
9218			var tbody     = settings.nTBody;
9219			var thead     = settings.nTHead;
9220			var tfoot     = settings.nTFoot;
9221			var jqTable   = $(table);
9222			var jqTbody   = $(tbody);
9223			var jqWrapper = $(settings.nTableWrapper);
9224			var rows      = $.map( settings.aoData, function (r) { return r.nTr; } );
9225			var i, ien;
9226	
9227			// Flag to note that the table is currently being destroyed - no action
9228			// should be taken
9229			settings.bDestroying = true;
9230	
9231			// Fire off the destroy callbacks for plug-ins etc
9232			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9233	
9234			// If not being removed from the document, make all columns visible
9235			if ( ! remove ) {
9236				new _Api( settings ).columns().visible( true );
9237			}
9238	
9239			// Blitz all `DT` namespaced events (these are internal events, the
9240			// lowercase, `dt` events are user subscribed and they are responsible
9241			// for removing them
9242			jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
9243			$(window).unbind('.DT-'+settings.sInstance);
9244	
9245			// When scrolling we had to break the table up - restore it
9246			if ( table != thead.parentNode ) {
9247				jqTable.children('thead').detach();
9248				jqTable.append( thead );
9249			}
9250	
9251			if ( tfoot && table != tfoot.parentNode ) {
9252				jqTable.children('tfoot').detach();
9253				jqTable.append( tfoot );
9254			}
9255	
9256			settings.aaSorting = [];
9257			settings.aaSortingFixed = [];
9258			_fnSortingClasses( settings );
9259	
9260			$( rows ).removeClass( settings.asStripeClasses.join(' ') );
9261	
9262			$('th, td', thead).removeClass( classes.sSortable+' '+
9263				classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9264			);
9265	
9266			if ( settings.bJUI ) {
9267				$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
9268				$('th, td', thead).each( function () {
9269					var wrapper = $('div.'+classes.sSortJUIWrapper, this);
9270					$(this).append( wrapper.contents() );
9271					wrapper.detach();
9272				} );
9273			}
9274	
9275			// Add the TR elements back into the table in their original order
9276			jqTbody.children().detach();
9277			jqTbody.append( rows );
9278	
9279			// Remove the DataTables generated nodes, events and classes
9280			var removedMethod = remove ? 'remove' : 'detach';
9281			jqTable[ removedMethod ]();
9282			jqWrapper[ removedMethod ]();
9283	
9284			// If we need to reattach the table to the document
9285			if ( ! remove && orig ) {
9286				// insertBefore acts like appendChild if !arg[1]
9287				orig.insertBefore( table, settings.nTableReinsertBefore );
9288	
9289				// Restore the width of the original table - was read from the style property,
9290				// so we can restore directly to that
9291				jqTable
9292					.css( 'width', settings.sDestroyWidth )
9293					.removeClass( classes.sTable );
9294	
9295				// If the were originally stripe classes - then we add them back here.
9296				// Note this is not fool proof (for example if not all rows had stripe
9297				// classes - but it's a good effort without getting carried away
9298				ien = settings.asDestroyStripes.length;
9299	
9300				if ( ien ) {
9301					jqTbody.children().each( function (i) {
9302						$(this).addClass( settings.asDestroyStripes[i % ien] );
9303					} );
9304				}
9305			}
9306	
9307			/* Remove the settings object from the settings array */
9308			var idx = $.inArray( settings, DataTable.settings );
9309			if ( idx !== -1 ) {
9310				DataTable.settings.splice( idx, 1 );
9311			}
9312		} );
9313	} );
9314	
9315	
9316	// Add the `every()` method for rows, columns and cells in a compact form
9317	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9318		_api_register( type+'s().every()', function ( fn ) {
9319			var opts = this.selector.opts;
9320			var api = this;
9321	
9322			return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9323				// Rows and columns:
9324				//  arg1 - index
9325				//  arg2 - table counter
9326				//  arg3 - loop counter
9327				//  arg4 - undefined
9328				// Cells:
9329				//  arg1 - row index
9330				//  arg2 - column index
9331				//  arg3 - table counter
9332				//  arg4 - loop counter
9333				fn.call(
9334					api[ type ](
9335						arg1,
9336						type==='cell' ? arg2 : opts,
9337						type==='cell' ? opts : undefined
9338					),
9339					arg1, arg2, arg3, arg4
9340				);
9341			} );
9342		} );
9343	} );
9344	
9345	
9346	// i18n method for extensions to be able to use the language object from the
9347	// DataTable
9348	_api_register( 'i18n()', function ( token, def, plural ) {
9349		var ctx = this.context[0];
9350		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9351	
9352		if ( resolved === undefined ) {
9353			resolved = def;
9354		}
9355	
9356		if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9357			resolved = resolved[ plural ] !== undefined ?
9358				resolved[ plural ] :
9359				resolved._;
9360		}
9361	
9362		return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9363	} );
9364
9365	/**
9366	 * Version string for plug-ins to check compatibility. Allowed format is
9367	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9368	 * only for non-release builds. See http://semver.org/ for more information.
9369	 *  @member
9370	 *  @type string
9371	 *  @default Version number
9372	 */
9373	DataTable.version = "1.10.11";
9374
9375	/**
9376	 * Private data store, containing all of the settings objects that are
9377	 * created for the tables on a given page.
9378	 *
9379	 * Note that the `DataTable.settings` object is aliased to
9380	 * `jQuery.fn.dataTableExt` through which it may be accessed and
9381	 * manipulated, or `jQuery.fn.dataTable.settings`.
9382	 *  @member
9383	 *  @type array
9384	 *  @default []
9385	 *  @private
9386	 */
9387	DataTable.settings = [];
9388
9389	/**
9390	 * Object models container, for the various models that DataTables has
9391	 * available to it. These models define the objects that are used to hold
9392	 * the active state and configuration of the table.
9393	 *  @namespace
9394	 */
9395	DataTable.models = {};
9396	
9397	
9398	
9399	/**
9400	 * Template object for the way in which DataTables holds information about
9401	 * search information for the global filter and individual column filters.
9402	 *  @namespace
9403	 */
9404	DataTable.models.oSearch = {
9405		/**
9406		 * Flag to indicate if the filtering should be case insensitive or not
9407		 *  @type boolean
9408		 *  @default true
9409		 */
9410		"bCaseInsensitive": true,
9411	
9412		/**
9413		 * Applied search term
9414		 *  @type string
9415		 *  @default <i>Empty string</i>
9416		 */
9417		"sSearch": "",
9418	
9419		/**
9420		 * Flag to indicate if the search term should be interpreted as a
9421		 * regular expression (true) or not (false) and therefore and special
9422		 * regex characters escaped.
9423		 *  @type boolean
9424		 *  @default false
9425		 */
9426		"bRegex": false,
9427	
9428		/**
9429		 * Flag to indicate if DataTables is to use its smart filtering or not.
9430		 *  @type boolean
9431		 *  @default true
9432		 */
9433		"bSmart": true
9434	};
9435	
9436	
9437	
9438	
9439	/**
9440	 * Template object for the way in which DataTables holds information about
9441	 * each individual row. This is the object format used for the settings
9442	 * aoData array.
9443	 *  @namespace
9444	 */
9445	DataTable.models.oRow = {
9446		/**
9447		 * TR element for the row
9448		 *  @type node
9449		 *  @default null
9450		 */
9451		"nTr": null,
9452	
9453		/**
9454		 * Array of TD elements for each row. This is null until the row has been
9455		 * created.
9456		 *  @type array nodes
9457		 *  @default []
9458		 */
9459		"anCells": null,
9460	
9461		/**
9462		 * Data object from the original data source for the row. This is either
9463		 * an array if using the traditional form of DataTables, or an object if
9464		 * using mData options. The exact type will depend on the passed in
9465		 * data from the data source, or will be an array if using DOM a data
9466		 * source.
9467		 *  @type array|object
9468		 *  @default []
9469		 */
9470		"_aData": [],
9471	
9472		/**
9473		 * Sorting data cache - this array is ostensibly the same length as the
9474		 * number of columns (although each index is generated only as it is
9475		 * needed), and holds the data that is used for sorting each column in the
9476		 * row. We do this cache generation at the start of the sort in order that
9477		 * the formatting of the sort data need be done only once for each cell
9478		 * per sort. This array should not be read from or written to by anything
9479		 * other than the master sorting methods.
9480		 *  @type array
9481		 *  @default null
9482		 *  @private
9483		 */
9484		"_aSortData": null,
9485	
9486		/**
9487		 * Per cell filtering data cache. As per the sort data cache, used to
9488		 * increase the performance of the filtering in DataTables
9489		 *  @type array
9490		 *  @default null
9491		 *  @private
9492		 */
9493		"_aFilterData": null,
9494	
9495		/**
9496		 * Filtering data cache. This is the same as the cell filtering cache, but
9497		 * in this case a string rather than an array. This is easily computed with
9498		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9499		 * needed on every search (memory traded for performance)
9500		 *  @type array
9501		 *  @default null
9502		 *  @private
9503		 */
9504		"_sFilterRow": null,
9505	
9506		/**
9507		 * Cache of the class name that DataTables has applied to the row, so we
9508		 * can quickly look at this variable rather than needing to do a DOM check
9509		 * on className for the nTr property.
9510		 *  @type string
9511		 *  @default <i>Empty string</i>
9512		 *  @private
9513		 */
9514		"_sRowStripe": "",
9515	
9516		/**
9517		 * Denote if the original data source was from the DOM, or the data source
9518		 * object. This is used for invalidating data, so DataTables can
9519		 * automatically read data from the original source, unless uninstructed
9520		 * otherwise.
9521		 *  @type string
9522		 *  @default null
9523		 *  @private
9524		 */
9525		"src": null,
9526	
9527		/**
9528		 * Index in the aoData array. This saves an indexOf lookup when we have the
9529		 * object, but want to know the index
9530		 *  @type integer
9531		 *  @default -1
9532		 *  @private
9533		 */
9534		"idx": -1
9535	};
9536	
9537	
9538	/**
9539	 * Template object for the column information object in DataTables. This object
9540	 * is held in the settings aoColumns array and contains all the information that
9541	 * DataTables needs about each individual column.
9542	 *
9543	 * Note that this object is related to {@link DataTable.defaults.column}
9544	 * but this one is the internal data store for DataTables's cache of columns.
9545	 * It should NOT be manipulated outside of DataTables. Any configuration should
9546	 * be done through the initialisation options.
9547	 *  @namespace
9548	 */
9549	DataTable.models.oColumn = {
9550		/**
9551		 * Column index. This could be worked out on-the-fly with $.inArray, but it
9552		 * is faster to just hold it as a variable
9553		 *  @type integer
9554		 *  @default null
9555		 */
9556		"idx": null,
9557	
9558		/**
9559		 * A list of the columns that sorting should occur on when this column
9560		 * is sorted. That this property is an array allows multi-column s
9560orting
9561		 * to be defined for a column (for example first name / last name columns
9562		 * would benefit from this). The values are integers pointing to the
9563		 * columns to be sorted on (typically it will be a single integer pointing
9564		 * at itself, but that doesn't need to be the case).
9565		 *  @type array
9566		 */
9567		"aDataSort": null,
9568	
9569		/**
9570		 * Define the sorting directions that are applied to the column, in sequence
9571		 * as the column is repeatedly sorted upon - i.e. the first value is used
9572		 * as the sorting direction when the column if first sorted (clicked on).
9573		 * Sort it again (click again) and it will move on to the next index.
9574		 * Repeat until loop.
9575		 *  @type array
9576		 */
9577		"asSorting": null,
9578	
9579		/**
9580		 * Flag to indicate if the column is searchable, and thus should be included
9581		 * in the filtering or not.
9582		 *  @type boolean
9583		 */
9584		"bSearchable": null,
9585	
9586		/**
9587		 * Flag to indicate if the column is sortable or not.
9588		 *  @type boolean
9589		 */
9590		"bSortable": null,
9591	
9592		/**
9593		 * Flag to indicate if the column is currently visible in the table or not
9594		 *  @type boolean
9595		 */
9596		"bVisible": null,
9597	
9598		/**
9599		 * Store for manual type assignment using the `column.type` option. This
9600		 * is held in store so we can manipulate the column's `sType` property.
9601		 *  @type string
9602		 *  @default null
9603		 *  @private
9604		 */
9605		"_sManualType": null,
9606	
9607		/**
9608		 * Flag to indicate if HTML5 data attributes should be used as the data
9609		 * source for filtering or sorting. True is either are.
9610		 *  @type boolean
9611		 *  @default false
9612		 *  @private
9613		 */
9614		"_bAttrSrc": false,
9615	
9616		/**
9617		 * Developer definable function that is called whenever a cell is created (Ajax source,
9618		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9619		 * allowing you to modify the DOM element (add background colour for example) when the
9620		 * element is available.
9621		 *  @type function
9622		 *  @param {element} nTd The TD node that has been created
9623		 *  @param {*} sData The Data for the cell
9624		 *  @param {array|object} oData The data for the whole row
9625		 *  @param {int} iRow The row index for the aoData data store
9626		 *  @default null
9627		 */
9628		"fnCreatedCell": null,
9629	
9630		/**
9631		 * Function to get data from a cell in a column. You should <b>never</b>
9632		 * access data directly through _aData internally in DataTables - always use
9633		 * the method attached to this property. It allows mData to function as
9634		 * required. This function is automatically assigned by the column
9635		 * initialisation method
9636		 *  @type function
9637		 *  @param {array|object} oData The data array/object for the array
9638		 *    (i.e. aoData[]._aData)
9639		 *  @param {string} sSpecific The specific data type you want to get -
9640		 *    'display', 'type' 'filter' 'sort'
9641		 *  @returns {*} The data for the cell from the given row's data
9642		 *  @default null
9643		 */
9644		"fnGetData": null,
9645	
9646		/**
9647		 * Function to set data for a cell in the column. You should <b>never</b>
9648		 * set the data directly to _aData internally in DataTables - always use
9649		 * this method. It allows mData to function as required. This function
9650		 * is automatically assigned by the column initialisation method
9651		 *  @type function
9652		 *  @param {array|object} oData The data array/object for the array
9653		 *    (i.e. aoData[]._aData)
9654		 *  @param {*} sValue Value to set
9655		 *  @default null
9656		 */
9657		"fnSetData": null,
9658	
9659		/**
9660		 * Property to read the value for the cells in the column from the data
9661		 * source array / object. If null, then the default content is used, if a
9662		 * function is given then the return from the function is used.
9663		 *  @type function|int|string|null
9664		 *  @default null
9665		 */
9666		"mData": null,
9667	
9668		/**
9669		 * Partner property to mData which is used (only when defined) to get
9670		 * the data - i.e. it is basically the same as mData, but without the
9671		 * 'set' option, and also the data fed to it is the result from mData.
9672		 * This is the rendering method to match the data method of mData.
9673		 *  @type function|int|string|null
9674		 *  @default null
9675		 */
9676		"mRender": null,
9677	
9678		/**
9679		 * Unique header TH/TD element for this column - this is what the sorting
9680		 * listener is attached to (if sorting is enabled.)
9681		 *  @type node
9682		 *  @default null
9683		 */
9684		"nTh": null,
9685	
9686		/**
9687		 * Unique footer TH/TD element for this column (if there is one). Not used
9688		 * in DataTables as such, but can be used for plug-ins to reference the
9689		 * footer for each column.
9690		 *  @type node
9691		 *  @default null
9692		 */
9693		"nTf": null,
9694	
9695		/**
9696		 * The class to apply to all TD elements in the table's TBODY for the column
9697		 *  @type string
9698		 *  @default null
9699		 */
9700		"sClass": null,
9701	
9702		/**
9703		 * When DataTables calculates the column widths to assign to each column,
9704		 * it finds the longest string in each column and then constructs a
9705		 * temporary table and reads the widths from that. The problem with this
9706		 * is that "mmm" is much wider then "iiii", but the latter is a longer
9707		 * string - thus the calculation can go wrong (doing it properly and putting
9708		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9709		 * a "work around" we provide this option. It will append its value to the
9710		 * text that is found to be the longest string for the column - i.e. padding.
9711		 *  @type string
9712		 */
9713		"sContentPadding": null,
9714	
9715		/**
9716		 * Allows a default value to be given for a column's data, and will be used
9717		 * whenever a null data source is encountered (this can be because mData
9718		 * is set to null, or because the data source itself is null).
9719		 *  @type string
9720		 *  @default null
9721		 */
9722		"sDefaultContent": null,
9723	
9724		/**
9725		 * Name for the column, allowing reference to the column by name as well as
9726		 * by index (needs a lookup to work by name).
9727		 *  @type string
9728		 */
9729		"sName": null,
9730	
9731		/**
9732		 * Custom sorting data type - defines which of the available plug-ins in
9733		 * afnSortData the custom sorting will use - if any is defined.
9734		 *  @type string
9735		 *  @default std
9736		 */
9737		"sSortDataType": 'std',
9738	
9739		/**
9740		 * Class to be applied to the header element when sorting on this column
9741		 *  @type string
9742		 *  @default null
9743		 */
9744		"sSortingClass": null,
9745	
9746		/**
9747		 * Class to be applied to the header element when sorting on this column -
9748		 * when jQuery UI theming is used.
9749		 *  @type string
9750		 *  @default null
9751		 */
9752		"sSortingClassJUI": null,
9753	
9754		/**
9755		 * Title of the column - what is seen in the TH element (nTh).
9756		 *  @type string
9757		 */
9758		"sTitle": null,
9759	
9760		/**
9761		 * Column sorting and filtering type
9762		 *  @type string
9763		 *  @default null
9764		 */
9765		"sType": null,
9766	
9767		/**
9768		 * Width of the column
9769		 *  @type string
9770		 *  @default null
9771		 */
9772		"sWidth": null,
9773	
9774		/**
9775		 * Width of the column when it was first "encountered"
9776		 *  @type string
9777		 *  @default null
9778		 */
9779		"sWidthOrig": null
9780	};
9781	
9782	
9783	/*
9784	 * Developer note: The properties of the object below are given in Hungarian
9785	 * notation, that was used as the interface for DataTables prior to v1.10, however
9786	 * from v1.10 onwards the primary interface is camel case. In order to avoid
9787	 * breaking backwards compatibility utterly with this change, the Hungarian
9788	 * version is still, internally the primary interface, but is is not documented
9789	 * - hence the @name tags in each doc comment. This allows a Javascript function
9790	 * to create a map from Hungarian notation to camel case (going the other direction
9791	 * would require each property to be listed, which would at around 3K to the size
9792	 * of DataTables, while this method is about a 0.5K hit.
9793	 *
9794	 * Ultimately this does pave the way for Hungarian notation to be dropped
9795	 * completely, but that is a massive amount of work and will break current
9796	 * installs (therefore is on-hold until v2).
9797	 */
9798	
9799	/**
9800	 * Initialisation options that can be given to DataTables at initialisation
9801	 * time.
9802	 *  @namespace
9803	 */
9804	DataTable.defaults = {
9805		/**
9806		 * An array of data to use for the table, passed in at initialisation which
9807		 * will be used in preference to any data which is already in the DOM. This is
9808		 * particularly useful for constructing tables purely in Javascript, for
9809		 * example with a custom Ajax call.
9810		 *  @type array
9811		 *  @default null
9812		 *
9813		 *  @dtopt Option
9814		 *  @name DataTable.defaults.data
9815		 *
9816		 *  @example
9817		 *    // Using a 2D array data source
9818		 *    $(document).ready( function () {
9819		 *      $('#example').dataTable( {
9820		 *        "data": [
9821		 *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9822		 *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9823		 *        ],
9824		 *        "columns": [
9825		 *          { "title": "Engine" },
9826		 *          { "title": "Browser" },
9827		 *          { "title": "Platform" },
9828		 *          { "title": "Version" },
9829		 *          { "title": "Grade" }
9830		 *        ]
9831		 *      } );
9832		 *    } );
9833		 *
9834		 *  @example
9835		 *    // Using an array of objects as a data source (`data`)
9836		 *    $(document).ready( function () {
9837		 *      $('#example').dataTable( {
9838		 *        "data": [
9839		 *          {
9840		 *            "engine":   "Trident",
9841		 *            "browser":  "Internet Explorer 4.0",
9842		 *            "platform": "Win 95+",
9843		 *            "version":  4,
9844		 *            "grade":    "X"
9845		 *          },
9846		 *          {
9847		 *            "engine":   "Trident",
9848		 *            "browser":  "Internet Explorer 5.0",
9849		 *            "platform": "Win 95+",
9850		 *            "version":  5,
9851		 *            "grade":    "C"
9852		 *          }
9853		 *        ],
9854		 *        "columns": [
9855		 *          { "title": "Engine",   "data": "engine" },
9856		 *          { "title": "Browser",  "data": "browser" },
9857		 *          { "title": "Platform", "data": "platform" },
9858		 *          { "title": "Version",  "data": "version" },
9859		 *          { "title": "Grade",    "data": "grade" }
9860		 *        ]
9861		 *      } );
9862		 *    } );
9863		 */
9864		"aaData": null,
9865	
9866	
9867		/**
9868		 * If ordering is enabled, then DataTables will perform a first pass sort on
9869		 * initialisation. You can define which column(s) the sort is performed
9870		 * upon, and the sorting direction, with this variable. The `sorting` array
9871		 * should contain an array for each column to be sorted initially containing
9872		 * the column's index and a direction string ('asc' or 'desc').
9873		 *  @type array
9874		 *  @default [[0,'asc']]
9875		 *
9876		 *  @dtopt Option
9877		 *  @name DataTable.defaults.order
9878		 *
9879		 *  @example
9880		 *    // Sort by 3rd column first, and then 4th column
9881		 *    $(document).ready( function() {
9882		 *      $('#example').dataTable( {
9883		 *        "order": [[2,'asc'], [3,'desc']]
9884		 *      } );
9885		 *    } );
9886		 *
9887		 *    // No initial sorting
9888		 *    $(document).ready( function() {
9889		 *      $('#example').dataTable( {
9890		 *        "order": []
9891		 *      } );
9892		 *    } );
9893		 */
9894		"aaSorting": [[0,'asc']],
9895	
9896	
9897		/**
9898		 * This parameter is basically identical to the `sorting` parameter, but
9899		 * cannot be overridden by user interaction with the table. What this means
9900		 * is that you could have a column (visible or hidden) which the sorting
9901		 * will always be forced on first - any sorting after that (from the user)
9902		 * will then be performed as required. This can be useful for grouping rows
9903		 * together.
9904		 *  @type array
9905		 *  @default null
9906		 *
9907		 *  @dtopt Option
9908		 *  @name DataTable.defaults.orderFixed
9909		 *
9910		 *  @example
9911		 *    $(document).ready( function() {
9912		 *      $('#example').dataTable( {
9913		 *        "orderFixed": [[0,'asc']]
9914		 *      } );
9915		 *    } )
9916		 */
9917		"aaSortingFixed": [],
9918	
9919	
9920		/**
9921		 * DataTables can be instructed to load data to display in the table from a
9922		 * Ajax source. This option defines how that Ajax call is made and where to.
9923		 *
9924		 * The `ajax` property has three different modes of operation, depending on
9925		 * how it is defined. These are:
9926		 *
9927		 * * `string` - Set the URL from where the data should be loaded from.
9928		 * * `object` - Define properties for `jQuery.ajax`.
9929		 * * `function` - Custom data get function
9930		 *
9931		 * `string`
9932		 * --------
9933		 *
9934		 * As a string, the `ajax` property simply defines the URL from which
9935		 * DataTables will load data.
9936		 *
9937		 * `object`
9938		 * --------
9939		 *
9940		 * As an object, the parameters in the object are passed to
9941		 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9942		 * of the Ajax request. DataTables has a number of default parameters which
9943		 * you can override using this option. Please refer to the jQuery
9944		 * documentation for a full description of the options available, although
9945		 * the following parameters provide additional options in DataTables or
9946		 * require special consideration:
9947		 *
9948		 * * `data` - As with jQuery, `data` can be provided as an object, but it
9949		 *   can also be used as a function to manipulate the data DataTables sends
9950		 *   to the server. The function takes a single parameter, an object of
9951		 *   parameters with the values that DataTables has readied for sending. An
9952		 *   object may be returned which will be merged into the DataTables
9953		 *   defaults, or you can add the items to the object that was passed in and
9954		 *   not return anything from the function. This supersedes `fnServerParams`
9955		 *   from DataTables 1.9-.
9956		 *
9957		 * * `dataSrc` - By default DataTables will look for the property `data` (or
9958		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
9959		 *   from an Ajax source or for server-side processing - this parameter
9960		 *   allows that property to be changed. You can use Javascript dotted
9961		 *   object notation to get a data source for multiple levels of nesting, or
9962		 *   it my be used as a function. As a function it takes a single parameter,
9963		 *   the JSON returned from the server, which can be manipulated as
9964		 *   required, with the returned value being that used by DataTables as the
9965		 *   data source for the table. This supersedes `sAjaxDataProp` from
9966		 *   DataTables 1.9-.
9967		 *
9968		 * * `success` - Should not be overridden it is used internally in
9969		 *   DataTables. To manipulate / transform the data returned by the server
9970		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
9971		 *
9972		 * `function`
9973		 * ----------
9974		 *
9975		 * As a function, making the Ajax call is left up to yourself allowing
9976		 * complete control of the Ajax request. Indeed, if desired, a method other
9977		 * than Ajax could be used to obtain the required data, such as Web storage
9978		 * or an AIR database.
9979		 *
9980		 * The function is given four parameters and no return is required. The
9981		 * parameters are:
9982		 *
9983		 * 1. _object_ - Data to send to the server
9984		 * 2. _function_ - Callback function that must be executed when the required
9985		 *    data has been obtained. That data should be passed into the callback
9986		 *    as the only parameter
9987		 * 3. _object_ - DataTables settings object for the table
9988		 *
9989		 * Note that this supersedes `fnServerData` from DataTables 1.9-.
9990		 *
9991		 *  @type string|object|function
9992		 *  @default null
9993		 *
9994		 *  @dtopt Option
9995		 *  @name DataTable.defaults.ajax
9996		 *  @since 1.10.0
9997		 *
9998		 * @example
9999		 *   // Get JSON data from a file via Ajax.
10000		 *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10001		 *   $('#example').dataTable( {
10002		 *     "ajax": "data.json"
10003		 *   } );
10004		 *
10005		 * @example
10006		 *   // Get JSON data from a file via Ajax, using `dataSrc` to change
10007		 *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10008		 *   $('#example').dataTable( {
10009		 *     "ajax": {
10010		 *       "url": "data.json",
10011		 *       "dataSrc": "tableData"
10012		 *     }
10013		 *   } );
10014		 *
10015		 * @example
10016		 *   // Get JSON data from a file via Ajax, using `dataSrc` to read data
10017		 *   // from a plain array rather than an array in an object
10018		 *   $('#example').dataTable( {
10019		 *     "ajax": {
10020		 *       "url": "data.json",
10021		 *       "dataSrc": ""
10022		 *     }
10023		 *   } );
10024		 *
10025		 * @example
10026		 *   // Manipulate the data returned from the server - add a link to data
10027		 *   // (note this can, should, be done using `render` for the column - this
10028		 *   // is just a simple example of how the data can be manipulated).
10029		 *   $('#example').dataTable( {
10030		 *     "ajax": {
10031		 *       "url": "data.json",
10032		 *       "dataSrc": function ( json ) {
10033		 *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10034		 *           json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10035		 *         }
10036		 *         return json;
10037		 *       }
10038		 *     }
10039		 *   } );
10040		 *
10041		 * @example
10042		 *   // Add data to the request
10043		 *   $('#example').dataTable( {
10044		 *     "ajax": {
10045		 *       "url": "data.json",
10046		 *       "data": function ( d ) {
10047		 *         return {
10048		 *           "extra_search": $('#extra').val()
10049		 *         };
10050		 *       }
10051		 *     }
10052		 *   } );
10053		 *
10054		 * @example
10055		 *   // Send request as POST
10056		 *   $('#example').dataTable( {
10057		 *     "ajax": {
10058		 *       "url": "data.json",
10059		 *       "type": "POST"
10060		 *     }
10061		 *   } );
10062		 *
10063		 * @example
10064		 *   // Get the data from localStorage (could interface with a form for
10065		 *   // adding, editing and removing rows).
10066		 *   $('#example').dataTable( {
10067		 *     "ajax": function (data, callback, settings) {
10068		 *       callback(
10069		 *         JSON.parse( localStorage.getItem('dataTablesData') )
10070		 *       );
10071		 *     }
10072		 *   } );
10073		 */
10074		"ajax": null,
10075	
10076	
10077		/**
10078		 * This parameter allows you to readily specify the entries in the length drop
10079		 * down menu that DataTables shows when pagination is enabled. It can be
10080		 * either a 1D array of options which will be used for both the displayed
10081		 * option and the value, or a 2D array which will use the array in the first
10082		 * position as the value, and the array in the second position as the
10083		 * displayed options (useful for language strings such as 'All').
10084		 *
10085		 * Note that the `pageLength` property will be automatically set to the
10086		 * first value given in this array, unless `pageLength` is also provided.
10087		 *  @type array
10088		 *  @default [ 10, 25, 50, 100 ]
10089		 *
10090		 *  @dtopt Option
10091		 *  @name DataTable.defaults.lengthMenu
10092		 *
10093		 *  @example
10094		 *    $(document).ready( function() {
10095		 *      $('#example').dataTable( {
10096		 *        "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10097		 *      } );
10098		 *    } );
10099		 */
10100		"aLengthMenu": [ 10, 25, 50, 100 ],
10101	
10102	
10103		/**
10104		 * The `columns` option in the initialisation parameter allows you to define
10105		 * details about the way individual columns behave. For a full list of
10106		 * column options that can be set, please see
10107		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10108		 * define your columns, you must have an entry in the array for every single
10109		 * column that you have in your table (these can be null if you don't which
10110		 * to specify any options).
10111		 *  @member
10112		 *
10113		 *  @name DataTable.defaults.column
10114		 */
10115		"aoColumns": null,
10116	
10117		/**
10118		 * Very similar to `columns`, `columnDefs` allows you to target a specific
10119		 * column, multiple columns, or all columns, using the `targets` property of
10120		 * each object in the array. This allows great flexibility when creating
10121		 * tables, as the `columnDefs` arrays can be of any length, targeting the
10122		 * columns you specifically want. `columnDefs` may use any of the column
10123		 * options available: {@link DataTable.defaults.column}, but it _must_
10124		 * have `targets` defined in each object in the array. Values in the `targets`
10125		 * array may be:
10126		 *   <ul>
10127		 *     <li>
10127a string - class name will be matched on the TH for the column</li>
10128		 *     <li>0 or a positive integer - column index counting from the left</li>
10129		 *     <li>a negative integer - column index counting from the right</li>
10130		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10131		 *   </ul>
10132		 *  @member
10133		 *
10134		 *  @name DataTable.defaults.columnDefs
10135		 */
10136		"aoColumnDefs": null,
10137	
10138	
10139		/**
10140		 * Basically the same as `search`, this parameter defines the individual column
10141		 * filtering state at initialisation time. The array must be of the same size
10142		 * as the number of columns, and each element be an object with the parameters
10143		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10144		 * accepted and the default will be used.
10145		 *  @type array
10146		 *  @default []
10147		 *
10148		 *  @dtopt Option
10149		 *  @name DataTable.defaults.searchCols
10150		 *
10151		 *  @example
10152		 *    $(document).ready( function() {
10153		 *      $('#example').dataTable( {
10154		 *        "searchCols": [
10155		 *          null,
10156		 *          { "search": "My filter" },
10157		 *          null,
10158		 *          { "search": "^[0-9]", "escapeRegex": false }
10159		 *        ]
10160		 *      } );
10161		 *    } )
10162		 */
10163		"aoSearchCols": [],
10164	
10165	
10166		/**
10167		 * An array of CSS classes that should be applied to displayed rows. This
10168		 * array may be of any length, and DataTables will apply each class
10169		 * sequentially, looping when required.
10170		 *  @type array
10171		 *  @default null <i>
10171Will take the values determined by the `oClasses.stripe*`
10172		 *    options</i>
10173		 *
10174		 *  @dtopt Option
10175		 *  @name DataTable.defaults.stripeClasses
10176		 *
10177		 *  @example
10178		 *    $(document).ready( function() {
10179		 *      $('#example').dataTable( {
10180		 *        "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10181		 *      } );
10182		 *    } )
10183		 */
10184		"asStripeClasses": null,
10185	
10186	
10187		/**
10188		 * Enable or disable automatic column width calculation. This can be disabled
10189		 * as an optimisation (it takes some time to calculate the widths) if the
10190		 * tables widths are passed in using `columns`.
10191		 *  @type boolean
10192		 *  @default true
10193		 *
10194		 *  @dtopt Features
10195		 *  @name DataTable.defaults.autoWidth
10196		 *
10197		 *  @example
10198		 *    $(document).ready( function () {
10199		 *      $('#example').dataTable( {
10200		 *        "autoWidth": false
10201		 *      } );
10202		 *    } );
10203		 */
10204		"bAutoWidth": true,
10205	
10206	
10207		/**
10208		 * Deferred rendering can provide DataTables with a huge speed boost when you
10209		 * are using an Ajax or JS data source for the table. This option, when set to
10210		 * true, will cause DataTables to defer the creation of the table elements for
10211		 * each row until they are needed for a draw - saving a significant amount of
10212		 * time.
10213		 *  @type boolean
10214		 *  @default false
10215		 *
10216		 *  @dtopt Features
10217		 *  @name DataTable.defaults.deferRender
10218		 *
10219		 *  @example
10220		 *    $(document).ready( function() {
10221		 *      $('#example').dataTable( {
10222		 *        "ajax": "sources/arrays.txt",
10223		 *        "deferRender": true
10224		 *      } );
10225		 *    } );
10226		 */
10227		"bDeferRender": false,
10228	
10229	
10230		/**
10231		 * Replace a DataTable which matches the given selector and replace it with
10232		 * one which has the properties of the new initialisation object passed. If no
10233		 * table matches the selector, then the new DataTable will be constructed as
10234		 * per normal.
10235		 *  @type boolean
10236		 *  @default false
10237		 *
10238		 *  @dtopt Options
10239		 *  @name DataTable.defaults.destroy
10240		 *
10241		 *  @example
10242		 *    $(document).ready( function() {
10243		 *      $('#example').dataTable( {
10244		 *        "srollY": "200px",
10245		 *        "paginate": false
10246		 *      } );
10247		 *
10248		 *      // Some time later....
10249		 *      $('#example').dataTable( {
10250		 *        "filter": false,
10251		 *        "destroy": true
10252		 *      } );
10253		 *    } );
10254		 */
10255		"bDestroy": false,
10256	
10257	
10258		/**
10259		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10260		 * that it allows the end user to input multiple words (space separated) and
10261		 * will match a row containing those words, even if not in the order that was
10262		 * specified (this allow matching across multiple columns). Note that if you
10263		 * wish to use filtering in DataTables this must remain 'true' - to remove the
10264		 * default filtering input box and retain filtering abilities, please use
10265		 * {@link DataTable.defaults.dom}.
10266		 *  @type boolean
10267		 *  @default true
10268		 *
10269		 *  @dtopt Features
10270		 *  @name DataTable.defaults.searching
10271		 *
10272		 *  @example
10273		 *    $(document).ready( function () {
10274		 *      $('#example').dataTable( {
10275		 *        "searching": false
10276		 *      } );
10277		 *    } );
10278		 */
10279		"bFilter": true,
10280	
10281	
10282		/**
10283		 * Enable or disable the table information display. This shows information
10284		 * about the data that is currently visible on the page, including information
10285		 * about filtered data if that action is being performed.
10286		 *  @type boolean
10287		 *  @default true
10288		 *
10289		 *  @dtopt Features
10290		 *  @name DataTable.defaults.info
10291		 *
10292		 *  @example
10293		 *    $(document).ready( function () {
10294		 *      $('#example').dataTable( {
10295		 *        "info": false
10296		 *      } );
10297		 *    } );
10298		 */
10299		"bInfo": true,
10300	
10301	
10302		/**
10303		 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
10304		 * slightly different and additional mark-up from what DataTables has
10305		 * traditionally used).
10306		 *  @type boolean
10307		 *  @default false
10308		 *
10309		 *  @dtopt Features
10310		 *  @name DataTable.defaults.jQueryUI
10311		 *
10312		 *  @example
10313		 *    $(document).ready( function() {
10314		 *      $('#example').dataTable( {
10315		 *        "jQueryUI": true
10316		 *      } );
10317		 *    } );
10318		 */
10319		"bJQueryUI": false,
10320	
10321	
10322		/**
10323		 * Allows the end user to select the size of a formatted page from a select
10324		 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10325		 *  @type boolean
10326		 *  @default true
10327		 *
10328		 *  @dtopt Features
10329		 *  @name DataTable.defaults.lengthChange
10330		 *
10331		 *  @example
10332		 *    $(document).ready( function () {
10333		 *      $('#example').dataTable( {
10334		 *        "lengthChange": false
10335		 *      } );
10336		 *    } );
10337		 */
10338		"bLengthChange": true,
10339	
10340	
10341		/**
10342		 * Enable or disable pagination.
10343		 *  @type boolean
10344		 *  @default true
10345		 *
10346		 *  @dtopt Features
10347		 *  @name DataTable.defaults.paging
10348		 *
10349		 *  @example
10350		 *    $(document).ready( function () {
10351		 *      $('#example').dataTable( {
10352		 *        "paging": false
10353		 *      } );
10354		 *    } );
10355		 */
10356		"bPaginate": true,
10357	
10358	
10359		/**
10360		 * Enable or disable the display of a 'processing' indicator when the table is
10361		 * being processed (e.g. a sort). This is particularly useful for tables with
10362		 * large amounts of data where it can take a noticeable amount of time to sort
10363		 * the entries.
10364		 *  @type boolean
10365		 *  @default false
10366		 *
10367		 *  @dtopt Features
10368		 *  @name DataTable.defaults.processing
10369		 *
10370		 *  @example
10371		 *    $(document).ready( function () {
10372		 *      $('#example').dataTable( {
10373		 *        "processing": true
10374		 *      } );
10375		 *    } );
10376		 */
10377		"bProcessing": false,
10378	
10379	
10380		/**
10381		 * Retrieve the DataTables object for the given selector. Note that if the
10382		 * table has already been initialised, this parameter will cause DataTables
10383		 * to simply return the object that has already been set up - it will not take
10384		 * account of any changes you might have made to the initialisation object
10385		 * passed to DataTables (setting this parameter to true is an acknowledgement
10386		 * that you understand this). `destroy` can be used to reinitialise a table if
10387		 * you need.
10388		 *  @type boolean
10389		 *  @default false
10390		 *
10391		 *  @dtopt Options
10392		 *  @name DataTable.defaults.retrieve
10393		 *
10394		 *  @example
10395		 *    $(document).ready( function() {
10396		 *      initTable();
10397		 *      tableActions();
10398		 *    } );
10399		 *
10400		 *    function initTable ()
10401		 *    {
10402		 *      return $('#example').dataTable( {
10403		 *        "scrollY": "200px",
10404		 *        "paginate": false,
10405		 *        "retrieve": true
10406		 *      } );
10407		 *    }
10408		 *
10409		 *    function tableActions ()
10410		 *    {
10411		 *      var table = initTable();
10412		 *      // perform API operations with oTable
10413		 *    }
10414		 */
10415		"bRetrieve": false,
10416	
10417	
10418		/**
10419		 * When vertical (y) scrolling is enabled, DataTables will force the height of
10420		 * the table's viewport to the given height at all times (useful for layout).
10421		 * However, this can look odd when filtering data down to a small data set,
10422		 * and the footer is left "floating" further down. This parameter (when
10423		 * enabled) will cause DataTables to collapse the table's viewport down when
10424		 * the result set will fit within the given Y height.
10425		 *  @type boolean
10426		 *  @default false
10427		 *
10428		 *  @dtopt Options
10429		 *  @name DataTable.defaults.scrollCollapse
10430		 *
10431		 *  @example
10432		 *    $(document).ready( function() {
10433		 *      $('#example').dataTable( {
10434		 *        "scrollY": "200",
10435		 *        "scrollCollapse": true
10436		 *      } );
10437		 *    } );
10438		 */
10439		"bScrollCollapse": false,
10440	
10441	
10442		/**
10443		 * Configure DataTables to use server-side processing. Note that the
10444		 * `ajax` parameter must also be given in order to give DataTables a
10445		 * source to obtain the required data for each draw.
10446		 *  @type boolean
10447		 *  @default false
10448		 *
10449		 *  @dtopt Features
10450		 *  @dtopt Server-side
10451		 *  @name DataTable.defaults.serverSide
10452		 *
10453		 *  @example
10454		 *    $(document).ready( function () {
10455		 *      $('#example').dataTable( {
10456		 *        "serverSide": true,
10457		 *        "ajax": "xhr.php"
10458		 *      } );
10459		 *    } );
10460		 */
10461		"bServerSide": false,
10462	
10463	
10464		/**
10465		 * Enable or disable sorting of columns. Sorting of individual columns can be
10466		 * disabled by the `sortable` option for each column.
10467		 *  @type boolean
10468		 *  @default true
10469		 *
10470		 *  @dtopt Features
10471		 *  @name DataTable.defaults.ordering
10472		 *
10473		 *  @example
10474		 *    $(document).ready( function () {
10475		 *      $('#example').dataTable( {
10476		 *        "ordering": false
10477		 *      } );
10478		 *    } );
10479		 */
10480		"bSort": true,
10481	
10482	
10483		/**
10484		 * Enable or display DataTables' ability to sort multiple columns at the
10485		 * same time (activated by shift-click by the user).
10486		 *  @type boolean
10487		 *  @default true
10488		 *
10489		 *  @dtopt Options
10490		 *  @name DataTable.defaults.orderMulti
10491		 *
10492		 *  @example
10493		 *    // Disable multiple column sorting ability
10494		 *    $(document).ready( function () {
10495		 *      $('#example').dataTable( {
10496		 *        "orderMulti": false
10497		 *      } );
10498		 *    } );
10499		 */
10500		"bSortMulti": true,
10501	
10502	
10503		/**
10504		 * Allows control over whether DataTables should use the top (true) unique
10505		 * cell that is found for a single column, or the bottom (false - default).
10506		 * This is useful when using complex headers.
10507		 *  @type boolean
10508		 *  @default false
10509		 *
10510		 *  @dtopt Options
10511		 *  @name DataTable.defaults.orderCellsTop
10512		 *
10513		 *  @example
10514		 *    $(document).ready( function() {
10515		 *      $('#example').dataTable( {
10516		 *        "orderCellsTop": true
10517		 *      } );
10518		 *    } );
10519		 */
10520		"bSortCellsTop": false,
10521	
10522	
10523		/**
10524		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10525		 * `sorting\_3` to the columns which are currently being sorted on. This is
10526		 * presented as a feature switch as it can increase processing time (while
10527		 * classes are removed and added) so for large data sets you might want to
10528		 * turn this off.
10529		 *  @type boolean
10530		 *  @default true
10531		 *
10532		 *  @dtopt Features
10533		 *  @name DataTable.defaults.orderClasses
10534		 *
10535		 *  @example
10536		 *    $(document).ready( function () {
10537		 *      $('#example').dataTable( {
10538		 *        "orderClasses": false
10539		 *      } );
10540		 *    } );
10541		 */
10542		"bSortClasses": true,
10543	
10544	
10545		/**
10546		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10547		 * used to save table display information such as pagination information,
10548		 * display length, filtering and sorting. As such when the end user reloads
10549		 * the page the display display will match what thy had previously set up.
10550		 *
10551		 * Due to the use of `localStorage` the default state saving is not supported
10552		 * in IE6 or 7. If state saving is required in those browsers, use
10553		 * `stateSaveCallback` to provide a storage solution such as cookies.
10554		 *  @type boolean
10555		 *  @default false
10556		 *
10557		 *  @dtopt Features
10558		 *  @name DataTable.defaults.stateSave
10559		 *
10560		 *  @example
10561		 *    $(document).ready( function () {
10562		 *      $('#example').dataTable( {
10563		 *        "stateSave": true
10564		 *      } );
10565		 *    } );
10566		 */
10567		"bStateSave": false,
10568	
10569	
10570		/**
10571		 * This function is called when a TR element is created (and all TD child
10572		 * elements have been inserted), or registered if using a DOM source, allowing
10573		 * manipulation of the TR element (adding classes etc).
10574		 *  @type function
10575		 *  @param {node} row "TR" element for the current row
10576		 *  @param {array} data Raw data array for this row
10577		 *  @param {int} dataIndex The index of this row in the internal aoData array
10578		 *
10579		 *  @dtopt Callbacks
10580		 *  @name DataTable.defaults.createdRow
10581		 *
10582		 *  @example
10583		 *    $(document).ready( function() {
10584		 *      $('#example').dataTable( {
10585		 *        "createdRow": function( row, data, dataIndex ) {
10586		 *          // Bold the grade for all 'A' grade browsers
10587		 *          if ( data[4] == "A" )
10588		 *          {
10589		 *            $('td:eq(4)', row).html( '<b>A</b>' );
10590		 *          }
10591		 *        }
10592		 *      } );
10593		 *    } );
10594		 */
10595		"fnCreatedRow": null,
10596	
10597	
10598		/**
10599		 * This function is called on every 'draw' event, and allows you to
10600		 * dynamically modify any aspect you want about the created DOM.
10601		 *  @type function
10602		 *  @param {object} settings DataTables settings object
10603		 *
10604		 *  @dtopt Callbacks
10605		 *  @name DataTable.defaults.drawCallback
10606		 *
10607		 *  @example
10608		 *    $(document).ready( function() {
10609		 *      $('#example').dataTable( {
10610		 *        "drawCallback": function( settings ) {
10611		 *          alert( 'DataTables has redrawn the table' );
10612		 *        }
10613		 *      } );
10614		 *    } );
10615		 */
10616		"fnDrawCallback": null,
10617	
10618	
10619		/**
10620		 * Identical to fnHeaderCallback() but for the table footer this function
10621		 * allows you to modify the table footer on every 'draw' event.
10622		 *  @type function
10623		 *  @param {node} foot "TR" element for the footer
10624		 *  @param {array} data Full table data (as derived from the original HTML)
10625		 *  @param {int} start Index for the current display starting point in the
10626		 *    display array
10627		 *  @param {int} end Index for the current display ending point in the
10628		 *    display array
10629		 *  @param {array int} display Index array to translate the visual position
10630		 *    to the full data array
10631		 *
10632		 *  @dtopt Callbacks
10633		 *  @name DataTable.defaults.footerCallback
10634		 *
10635		 *  @example
10636		 *    $(document).ready( function() {
10637		 *      $('#example').dataTable( {
10638		 *        "footerCallback": function( tfoot, data, start, end, display ) {
10639		 *          tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10640		 *        }
10641		 *      } );
10642		 *    } )
10643		 */
10644		"fnFooterCallback": null,
10645	
10646	
10647		/**
10648		 * When rendering large numbers in the information element for the table
10649		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10650		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10651		 * rendered as "1,000,000") to help readability for the end user. This
10652		 * function will override the default method DataTables uses.
10653		 *  @type function
10654		 *  @member
10655		 *  @param {int} toFormat number to be formatted
10656		 *  @returns {string} formatted string for DataTables to show the number
10657		 *
10658		 *  @dtopt Callbacks
10659		 *  @name DataTable.defaults.formatNumber
10660		 *
10661		 *  @example
10662		 *    // Format a number using a single quote for the separator (note that
10663		 *    // this can also be done with the language.thousands option)
10664		 *    $(document).ready( function() {
10665		 *      $('#example').dataTable( {
10666		 *        "formatNumber": function ( toFormat ) {
10667		 *          return toFormat.toString().replace(
10668		 *            /\B(?=(\d{3})+(?!\d))/g, "'"
10669		 *          );
10670		 *        };
10671		 *      } );
10672		 *    } );
10673		 */
10674		"fnFormatNumber": function ( toFormat ) {
10675			return toFormat.toString().replace(
10676				/\B(?=(\d{3})+(?!\d))/g,
10677				this.oLanguage.sThousands
10678			);
10679		},
10680	
10681	
10682		/**
10683		 * This function is called on every 'draw' event, and allows you to
10684		 * dynamically modify the header row. This can be used to calculate and
10685		 * display useful information about the table.
10686		 *  @type function
10687		 *  @param {node} head "TR" element for the header
10688		 *  @param {array} data Full table data (as derived from the original HTML)
10689		 *  @param {int} start Index for the current display starting point in the
10690		 *    display array
10691		 *  @param {int} end Index for the current display ending point in the
10692		 *    display array
10693		 *  @param {array int} display Index array to translate the visual position
10694		 *    to the full data array
10695		 *
10696		 *  @dtopt Callbacks
10697		 *  @name DataTable.defaults.headerCallback
10698		 *
10699		 *  @example
10700		 *    $(document).ready( function() {
10701		 *      $('#example').dataTable( {
10702		 *        "fheaderCallback": function( head, data, start, end, display ) {
10703		 *          head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10704		 *        }
10705		 *      } );
10706		 *    } )
10707		 */
10708		"fnHeaderCallback": null,
10709	
10710	
10711		/**
10712		 * The information element can be used to convey information about the current
10713		 * state of the table. Although the internationalisation options presented by
10714		 * DataTables are quite capable of dealing with most customisations, there may
10715		 * be times where you wish to customise the string further. This callback
10716		 * allows you to do exactly that.
10717		 *  @type function
10718		 *  @param {object} oSettings DataTables settings object
10719		 *  @param {int} start Starting position in data for the draw
10720		 *  @param {int} end End position in data for the draw
10721		 *  @param {int} max Total number of rows in the table (regardless of
10722		 *    filtering)
10723		 *  @param {int} total Total number of rows in the data set, after filtering
10724		 *  @param {string} pre The string that DataTables has formatted using it's
10725		 *    own rules
10726		 *  @returns {string} The string to be displayed in the information element.
10727		 *
10728		 *  @dtopt Callbacks
10729		 *  @name DataTable.defaults.infoCallback
10730		 *
10731		 *  @example
10732		 *    $('#example').dataTable( {
10733		 *      "infoCallback": function( settings, start, end, max, total, pre ) {
10734		 *        return start +" to "+ end;
10735		 *      }
10736		 *    } );
10737		 */
10738		"fnInfoCallback": null,
10739	
10740	
10741		/**
10742		 * Called when the table has been initialised. Normally DataTables will
10743		 * initialise sequentially and there will be no need for this function,
10744		 * however, this does not hold true when using external language information
10745		 * since that is obtained using an async XHR call.
10746		 *  @type function
10747		 *  @param {object} settings DataTables settings object
10748		 *  @param {object} json The JSON object request from the server - only
10749		 *    present if client-side Ajax sourced data is used
10750		 *
10751		 *  @dtopt Callbacks
10752		 *  @name DataTable.defaults.initComplete
10753		 *
10754		 *  @example
10755		 *    $(document).ready( function() {
10756		 *      $('#example').dataTable( {
10757		 *        "initComplete": function(settings, json) {
10758		 *          alert( 'DataTables has finished its initialisation.' );
10759		 *        }
10760		 *      } );
10761		 *    } )
10762		 */
10763		"fnInitComplete": null,
10764	
10765	
10766		/**
10767		 * Called at the very start of each table draw and can be used to cancel the
10768		 * draw by returning false, any other return (including undefined) results in
10769		 * the full draw occurring).
10770		 *  @type function
10771		 *  @param {object} settings DataTables settings object
10772		 *  @returns {boolean} False will cancel the draw, anything else (including no
10773		 *    return) will allow it to complete.
10774		 *
10775		 *  @dtopt Callbacks
10776		 *  @name DataTable.defaults.preDrawCallback
10777		 *
10778		 *  @example
10779		 *    $(document).ready( function() {
10780		 *      $('#example').dataTable( {
10781		 *        "preDrawCallback": function( settings ) {
10782		 *          if ( $('#test').val() == 1 ) {
10783		 *            return false;
10784		 *          }
10785		 *        }
10786		 *      } );
10787		 *    } );
10788		 */
10789		"fnPreDrawCallback": null,
10790	
10791	
10792		/**
10793		 * This function allows you to 'post process' each row after it have been
10794		 * generated for each table draw, but before it is rendered on screen. This
10795		 * function might be used for setting the row class name etc.
10796		 *  @type function
10797		 *  @param {node} row "TR" element for the current row
10798		 *  @param {array} data Raw data array for this row
10799		 *  @param {int} displayIndex The display index for the current table draw
10800		 *  @param {int} displayIndexFull The index of the data in the full list of
10801		 *    rows (after filtering)
10802		 *
10803		 *  @dtopt Callbacks
10804		 *  @name DataTable.defaults.rowCallback
10805		 *
10806		 *  @example
10807		 *    $(document).ready( function() {
10808		 *      $('#example').dataTable( {
10809		 *        "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10810		 *          // Bold the grade for all 'A' grade browsers
10811		 *          if ( data[4] == "A" ) {
10812		 *            $('td:eq(4)', row).html( '<b>A</b>' );
10813		 *          }
10814		 *        }
10815		 *      } );
10816		 *    } );
10817		 */
10818		"fnRowCallback": null,
10819	
10820	
10821		/**
10822		 * __Deprecated__ The functionality provided by this parameter has now been
10823		 * superseded by that provided through `ajax`, which should be used instead.
10824		 *
10825		 * This parameter allows you to override the default function which obtains
10826		 * the data from the server so something more suitable for your application.
10827		 * For example you could use POST data, or pull information from a Gears or
10828		 * AIR database.
10829		 *  @type function
10830		 *  @member
10831		 *  @param {string} source HTTP source to obtain the data from (`ajax`)
10832		 *  @param {array} data A key/value pair object containing the data to send
10833		 *    to the server
10834		 *  @param {function} callback to be called on completion of the data get
10835		 *    process that will draw the data on the page.
10836		 *  @param {object} settings DataTables settings object
10837		 *
10838		 *  @dtopt Callbacks
10839		 *  @dtopt Server-side
10840		 *  @name DataTable.defaults.serverData
10841		 *
10842		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
10843		 */
10844		"fnServerData": null,
10845	
10846	
10847		/**
10848		 * __Deprecated__ The functionality provided by this parameter has now been
10849		 * superseded by that provided through `ajax`, which should be used instead.
10850		 *
10851		 *  It is often useful to send extra data to the server when making an Ajax
10852		 * request - for example custom filtering information, and this callback
10853		 * function makes it trivial to send extra information to the server. The
10854		 * passed in parameter is the data set that has been constructed by
10855		 * DataTables, and you can add to this or modify it as you require.
10856		 *  @type function
10857		 *  @param {array} data Data array (array of objects which are name/value
10858		 *    pairs) that has been constructed by DataTables and will be sent to the
10859		 *    server. In the case of Ajax sourced data with server-side processing
10860		 *    this will be an empty array, for server-side processing there will be a
10861		 *    significant number of parameters!
10862		 *  @returns {undefined} Ensure that you modify the data array passed in,
10863		 *    as this is passed by reference.
10864		 *
10865		 *  @dtopt Callbacks
10866		 *  @dtopt Server-side
10867		 *  @name DataTable.defaults.serverParams
10868		 *
10869		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
10870		 */
10871		"fnServerParams": null,
10872	
10873	
10874		/**
10875		 * Load the table state. With this function you can define from where, and how, the
10876		 * state of a table is loaded. By default DataTables will load from `localStorage`
10877		 * but you might wish to use a server-side database or cookies.
10878		 *  @type function
10879		 *  @member
10880		 *  @param {object} settings DataTables settings object
10881		 *  @return {object} The DataTables state object to be loaded
10882		 *
10883		 *  @dtopt Callbacks
10884		 *  @name DataTable.defaults.stateLoadCallback
10885		 *
10886		 *  @example
10887		 *    $(document).ready( function() {
10888		 *      $('#example').dataTable( {
10889		 *        "stateSave": true,
10890		 *        "stateLoadCallback": function (settings) {
10891		 *          var o;
10892		 *
10893		 *          // Send an Ajax request to the server to get the data. Note that
10894		 *          // this is a synchronous request.
10895		 *          $.ajax( {
10896		 *            "url": "/state_load",
10897		 *            "async": false,
10898		 *            "dataType": "json",
10899		 *            "success": function (json) {
10900		 *              o = json;
10901		 *            }
10902		 *          } );
10903		 *
10904		 *          return o;
10905		 *        }
10906		 *      } );
10907		 *    } );
10908		 */
10909		"fnStateLoadCallback": function ( settings ) {
10910			try {
10911				return JSON.parse(
10912					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10913						'DataTables_'+settings.sInstance+'_'+location.pathname
10914					)
10915				);
10916			} catch (e) {}
10917		},
10918	
10919	
10920		/**
10921		 * Callback which allows modification of the saved state prior to loading that state.
10922		 * This callback is called when the table is loading state from the stored data, but
10923		 * prior to the settings object being modified by the saved state. Note that for
10924		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10925		 * a plug-in.
10926		 *  @type function
10927		 *  @param {object} settings DataTables settings object
10928		 *  @param {object} data The state object that is to be loaded
10929		 *
10930		 *  @dtopt Callbacks
10931		 *  @name DataTable.defaults.stateLoadParams
10932		 *
10933		 *  @example
10934		 *    // Remove a saved filter, so filtering is never loaded
10935		 *    $(document).ready( function() {
10936		 *      $('#example').dataTable( {
10937		 *        "stateSave": true,
10938		 *        "stateLoadParams": function (settings, data) {
10939		 *          data.oSearch.sSearch = "";
10940		 *        }
10941		 *      } );
10942		 *    } );
10943		 *
10944		 *  @example
10945		 *    // Disallow state loading by returning false
10946		 *    $(document).ready( function() {
10947		 *      $('#example').dataTable( {
10948		 *        "stateSave": true,
10949		 *        "stateLoadParams": function (settings, data) {
10950		 *          return false;
10951		 *        }
10952		 *      } );
10953		 *    } );
10954		 */
10955		"fnStateLoadParams": null,
10956	
10957	
10958		/**
10959		 * Callback that is called when the state has been loaded from the state saving method
10960		 * and the DataTables settings object has been modified as a result of the loaded state.
10961		 *  @type function
10962		 *  @param {object} settings DataTables settings object
10963		 *  @param {object} data The state object that was loaded
10964		 *
10965		 *  @dtopt Callbacks
10966		 *  @name DataTable.defaults.stateLoaded
10967		 *
10968		 *  @example
10969		 *    // Show an alert with the filtering value that was saved
10970		 *    $(document).ready( function() {
10971		 *      $('#example').dataTable( {
10972		 *        "stateSave": true,
10973		 *        "stateLoaded": function (settings, data) {
10974		 *          alert( 'Saved filter was: '+data.oSearch.sSearch );
10975		 *        }
10976		 *      } );
10977		 *    } );
10978		 */
10979		"fnStateLoaded": null,
10980	
10981	
10982		/**
10983		 * Save the table state. This function allows you to define where and how the state
10984		 * information for the table is stored By default DataTables will use `localStorage`
10985		 * but you might wish to use a server-side database or cookies.
10986		 *  @type function
10987		 *  @member
10988		 *  @param {object} settings DataTables settings object
10989		 *  @param {object} data The state object to be saved
10990		 *
10991		 *  @dtopt Callbacks
10992		 *  @name DataTable.defaults.stateSaveCallback
10993		 *
10994		 *  @example
10995		 *    $(document).ready( function() {
10996		 *      $('#example').dataTable( {
10997		 *        "stateSave": true,
10998		 *        "stateSaveCallback": function (settings, data) {
10999		 *          // Send an Ajax request to the server with the state object
11000		 *          $.ajax( {
11001		 *            "url": "/state_save",
11002		 *            "data": data,
11003		 *            "dataType": "json",
11004		 *            "method": "POST"
11005		 *            "success": function () {}
11006		 *          } );
11007		 *        }
11008		 *      } );
11009		 *    } );
11010		 */
11011		"fnStateSaveCallback": function ( settings, data ) {
11012			try {
11013				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11014					'DataTables_'+settings.sInstance+'_'+location.pathname,
11015					JSON.stringify( data )
11016				);
11017			} catch (e) {}
11018		},
11019	
11020	
11021		/**
11022		 * Callback which allows modification of the state to be saved. Called when the table
11023		 * has changed state a new state save is required. This method allows modification of
11024		 * the state saving object prior to actually doing the save, including addition or
11025		 * other state properties or modification. Note that for plug-in authors, you should
11026		 * use the `stateSaveParams` event to save parameters for a plug-in.
11027		 *  @type function
11028		 *  @param {object} settings DataTables settings object
11029		 *  @param {object} data The state object to be saved
11030		 *
11031		 *  @dtopt Callbacks
11032		 *  @name DataTable.defaults.stateSaveParams
11033		 *
11034		 *  @example
11035		 *    // Remove a saved filter, so filtering is never saved
11036		 *    $(document).ready( function() {
11037		 *      $('#example').dataTable( {
11038		 *        "stateSave": true,
11039		 *        "stateSaveParams": function (settings, data) {
11040		 *          data.oSearch.sSearch = "";
11041		 *        }
11042		 *      } );
11043		 *    } );
11044		 */
11045		"fnStateSaveParams": null,
11046	
11047	
11048		/**
11049		 * Duration for which the saved state information is considered valid. After this period
11050		 * has elapsed the state will be returned to the default.
11051		 * Value is given in seconds.
11052		 *  @type int
11053		 *  @default 7200 <i>(2 hours)</i>
11054		 *
11055		 *  @dtopt Options
11056		 *  @name DataTable.defaults.stateDuration
11057		 *
11058		 *  @example
11059		 *    $(document).ready( function() {
11060		 *      $('#example').dataTable( {
11061		 *        "stateDuration": 60*60*24; // 1 day
11062		 *      } );
11063		 *    } )
11064		 */
11065		"iStateDuration": 7200,
11066	
11067	
11068		/**
11069		 * When enabled DataTables will not make a request to the server for the first
11070		 * page draw - rather it will use the data already on the page (no sorting etc
11071		 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11072		 * is used to indicate that deferred loading is required, but it is also used
11073		 * to tell DataTables how many records there are in the full table (allowing
11074		 * the information element and pagination to be displayed correctly). In the case
11075		 * where a filtering is applied to the table on initial load, this can be
11076		 * indicated by giving the parameter as an array, where the first element is
11077		 * the number of records available after filtering and the second element is the
11078		 * number of records without filtering (allowing the table information element
11079		 * to be shown correctly).
11080		 *  @type int | array
11081		 *  @default null
11082		 *
11083		 *  @dtopt Options
11084		 *  @name DataTable.defaults.deferLoading
11085		 *
11086		 *  @example
11087		 *    // 57 records available in the table, no filtering applied
11088		 *    $(document).ready( function() {
11089		 *      $('#example').dataTable( {
11090		 *        "serverSide": true,
11091		 *        "ajax": "scripts/server_processing.php",
11092		 *        "deferLoading": 57
11093		 *      } );
11094		 *    } );
11095		 *
11096		 *  @example
11097		 *    // 57 records after filtering, 100 without filtering (an initial filter applied)
11098		 *    $(document).ready( function() {
11099		 *      $('#example').dataTable( {
11100		 *        "serverSide": true,
11101		 *        "ajax": "scripts/server_processing.php",
11102		 *        "deferLoading": [ 57, 100 ],
11103		 *        "search": {
11104		 *          "search": "my_filter"
11105		 *        }
11106		 *      } );
11107		 *    } );
11108		 */
11109		"iDeferLoading": null,
11110	
11111	
11112		/**
11113		 * Number of rows to display on a single page when using pagination. If
11114		 * feature enabled (`lengthChange`) then the end user will be able to override
11115		 * this to a custom setting using a pop-up menu.
11116		 *  @type int
11117		 *  @default 10
11118		 *
11119		 *  @dtopt Options
11120		 *  @name DataTable.defaults.pageLength
11121		 *
11122		 *  @example
11123		 *    $(document).ready( function() {
11124		 *      $('#example').dataTable( {
11125		 *        "pageLength": 50
11126		 *      } );
11127		 *    } )
11128		 */
11129		"iDisplayLength": 10,
11130	
11131	
11132		/**
11133		 * Define the starting point for data display when using DataTables with
11134		 * pagination. Note that this parameter is the number of records, rather than
11135		 * the page number, so if you have 10 records per page and want to start on
11136		 * the third page, it should be "20".
11137		 *  @type int
11138		 *  @default 0
11139		 *
11140		 *  @dtopt Options
11141		 *  @name DataTable.defaults.displayStart
11142		 *
11143		 *  @example
11144		 *    $(document).ready( function() {
11145		 *      $('#example').dataTable( {
11146		 *        "displayStart": 20
11147		 *      } );
11148		 *    } )
11149		 */
11150		"iDisplayStart": 0,
11151	
11152	
11153		/**
11154		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
11155		 * and filtering) by adding a `tabindex` attribute to the required elements. This
11156		 * allows you to tab through the controls and press the enter key to activate them.
11157		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
11158		 * You can overrule this using this parameter if you wish. Use a value of -1 to
11159		 * disable built-in keyboard navigation.
11160		 *  @type int
11161		 *  @default 0
11162		 *
11163		 *  @dtopt Options
11164		 *  @name DataTable.defaults.tabIndex
11165		 *
11166		 *  @example
11167		 *    $(document).ready( function() {
11168		 *      $('#example').dataTable( {
11169		 *        "tabIndex": 1
11170		 *      } );
11171		 *    } );
11172		 */
11173		"iTabIndex": 0,
11174	
11175	
11176		/**
11177		 * Classes that DataTables assigns to the various components and features
11178		 * that it adds to the HTML table. This allows classes to be configured
11179		 * during initialisation in addition to through the static
11180		 * {@link DataTable.ext.oStdClasses} object).
11181		 *  @namespace
11182		 *  @name DataTable.defaults.classes
11183		 */
11184		"oClasses": {},
11185	
11186	
11187		/**
11188		 * All strings that DataTables uses in the user interface that it creates
11189		 * are defined in this object, allowing you to modified them individually or
11190		 * completely replace them all as required.
11191		 *  @namespace
11192		 *  @name DataTable.defaults.language
11193		 */
11194		"oLanguage": {
11195			/**
11196			 * Strings that are used for WAI-ARIA labels and controls only (these are not
11197			 * actually visible on the page, but will be read by screenreaders, and thus
11198			 * must be internationalised as well).
11199			 *  @namespace
11200			 *  @name DataTable.defaults.language.aria
11201			 */
11202			"oAria": {
11203				/**
11204				 * ARIA label that is added to the table headers when the column may be
11205				 * sorted ascending by activing the column (click or return when focu
11205sed).
11206				 * Note that the column header is prefixed to this string.
11207				 *  @type string
11208				 *  @default : activate to sort column ascending
11209				 *
11210				 *  @dtopt Language
11211				 *  @name DataTable.defaults.language.aria.sortAscending
11212				 *
11213				 *  @example
11214				 *    $(document).ready( function() {
11215				 *      $('#example').dataTable( {
11216				 *        "language": {
11217				 *          "aria": {
11218				 *            "sortAscending": " - click/return to sort ascending"
11219				 *          }
11220				 *        }
11221				 *      } );
11222				 *    } );
11223				 */
11224				"sSortAscending": ": activate to sort column ascending",
11225	
11226				/**
11227				 * ARIA label that is added to the table headers when the column may be
11228				 * sorted descending by activing the column (click or return when focused).
11229				 * Note that the column header is prefixed to this string.
11230				 *  @type string
11231				 *  @default : activate to sort column ascending
11232				 *
11233				 *  @dtopt Language
11234				 *  @name DataTable.defaults.language.aria.sortDescending
11235				 *
11236				 *  @example
11237				 *    $(document).ready( function() {
11238				 *      $('#example').dataTable( {
11239				 *        "language": {
11240				 *          "aria": {
11241				 *            "sortDescending": " - click/return to sort descending"
11242				 *          }
11243				 *        }
11244				 *      } );
11245				 *    } );
11246				 */
11247				"sSortDescending": ": activate to sort column descending"
11248			},
11249	
11250			/**
11251			 * Pagination string used by DataTables for the built-in pagination
11252			 * control types.
11253			 *  @namespace
11254			 *  @name DataTable.defaults.language.paginate
11255			 */
11256			"oPaginate": {
11257				/**
11258				 * Text to use when using the 'full_numbers' type of pagination for the
11259				 * button to take the user to the first page.
11260				 *  @type string
11261				 *  @default First
11262				 *
11263				 *  @dtopt Language
11264				 *  @name DataTable.defaults.language.paginate.first
11265				 *
11266				 *  @example
11267				 *    $(document).ready( function() {
11268				 *      $('#example').dataTable( {
11269				 *        "language": {
11270				 *          "paginate": {
11271				 *            "first": "First page"
11272				 *          }
11273				 *        }
11274				 *      } );
11275				 *    } );
11276				 */
11277				"sFirst": "First",
11278	
11279	
11280				/**
11281				 * Text to use when using the 'full_numbers' type of pagination for the
11282				 * button to take the user to the last page.
11283				 *  @type string
11284				 *  @default Last
11285				 *
11286				 *  @dtopt Language
11287				 *  @name DataTable.defaults.language.paginate.last
11288				 *
11289				 *  @example
11290				 *    $(document).ready( function() {
11291				 *      $('#example').dataTable( {
11292				 *        "language": {
11293				 *          "paginate": {
11294				 *            "last": "Last page"
11295				 *          }
11296				 *        }
11297				 *      } );
11298				 *    } );
11299				 */
11300				"sLast": "Last",
11301	
11302	
11303				/**
11304				 * Text to use for the 'next' pagination button (to take the user to the
11305				 * next page).
11306				 *  @type string
11307				 *  @default Next
11308				 *
11309				 *  @dtopt Language
11310				 *  @name DataTable.defaults.language.paginate.next
11311				 *
11312				 *  @example
11313				 *    $(document).ready( function() {
11314				 *      $('#example').dataTable( {
11315				 *        "language": {
11316				 *          "paginate": {
11317				 *            "next": "Next page"
11318				 *          }
11319				 *        }
11320				 *      } );
11321				 *    } );
11322				 */
11323				"sNext": "Next",
11324	
11325	
11326				/**
11327				 * Text to use for the 'previous' pagination button (to take the user to
11328				 * the previous page).
11329				 *  @type string
11330				 *  @default Previous
11331				 *
11332				 *  @dtopt Language
11333				 *  @name DataTable.defaults.language.paginate.previous
11334				 *
11335				 *  @example
11336				 *    $(document).ready( function() {
11337				 *      $('#example').dataTable( {
11338				 *        "language": {
11339				 *          "paginate": {
11340				 *            "previous": "Previous page"
11341				 *          }
11342				 *        }
11343				 *      } );
11344				 *    } );
11345				 */
11346				"sPrevious": "Previous"
11347			},
11348	
11349			/**
11350			 * This string is shown in preference to `zeroRecords` when the table is
11351			 * empty of data (regardless of filtering). Note that this is an optional
11352			 * parameter - if it is not given, the value of `zeroRecords` will be used
11353			 * instead (either the default or given value).
11354			 *  @type string
11355			 *  @default No data available in table
11356			 *
11357			 *  @dtopt Language
11358			 *  @name DataTable.defaults.language.emptyTable
11359			 *
11360			 *  @example
11361			 *    $(document).ready( function() {
11362			 *      $('#example').dataTable( {
11363			 *        "language": {
11364			 *          "emptyTable": "No data available in table"
11365			 *        }
11366			 *      } );
11367			 *    } );
11368			 */
11369			"sEmptyTable": "No data available in table",
11370	
11371	
11372			/**
11373			 * This string gives information to the end user about the information
11374			 * that is current on display on the page. The following tokens can be
11375			 * used in the string and will be dynamically replaced as the table
11376			 * display updates. This tokens can be placed anywhere in the string, or
11377			 * removed as needed by the language requires:
11378			 *
11379			 * * `\_START\_` - Display index of the first record on the current page
11380			 * * `\_END\_` - Display index of the last record on the current page
11381			 * * `\_TOTAL\_` - Number of records in the table after filtering
11382			 * * `\_MAX\_` - Number of records in the table without filtering
11383			 * * `\_PAGE\_` - Current page number
11384			 * * `\_PAGES\_` - Total number of pages of data in the table
11385			 *
11386			 *  @type string
11387			 *  @default Showing _START_ to _END_ of _TOTAL_ entries
11388			 *
11389			 *  @dtopt Language
11390			 *  @name DataTable.defaults.language.info
11391			 *
11392			 *  @example
11393			 *    $(document).ready( function() {
11394			 *      $('#example').dataTable( {
11395			 *        "language": {
11396			 *          "info": "Showing page _PAGE_ of _PAGES_"
11397			 *        }
11398			 *      } );
11399			 *    } );
11400			 */
11401			"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11402	
11403	
11404			/**
11405			 * Display information string for when the table is empty. Typically the
11406			 * format of this string should match `info`.
11407			 *  @type string
11408			 *  @default Showing 0 to 0 of 0 entries
11409			 *
11410			 *  @dtopt Language
11411			 *  @name DataTable.defaults.language.infoEmpty
11412			 *
11413			 *  @example
11414			 *    $(document).ready( function() {
11415			 *      $('#example').dataTable( {
11416			 *        "language": {
11417			 *          "infoEmpty": "No entries to show"
11418			 *        }
11419			 *      } );
11420			 *    } );
11421			 */
11422			"sInfoEmpty": "Showing 0 to 0 of 0 entries",
11423	
11424	
11425			/**
11426			 * When a user filters the information in a table, this string is appended
11427			 * to the information (`info`) to give an idea of how strong the filtering
11428			 * is. The variable _MAX_ is dynamically updated.
11429			 *  @type string
11430			 *  @default (filtered from _MAX_ total entries)
11431			 *
11432			 *  @dtopt Language
11433			 *  @name DataTable.defaults.language.infoFiltered
11434			 *
11435			 *  @example
11436			 *    $(document).ready( function() {
11437			 *      $('#example').dataTable( {
11438			 *        "language": {
11439			 *          "infoFiltered": " - filtering from _MAX_ records"
11440			 *        }
11441			 *      } );
11442			 *    } );
11443			 */
11444			"sInfoFiltered": "(filtered from _MAX_ total entries)",
11445	
11446	
11447			/**
11448			 * If can be useful to append extra information to the info string at times,
11449			 * and this variable does exactly that. This information will be appended to
11450			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11451			 * being used) at all times.
11452			 *  @type string
11453			 *  @default <i>Empty string</i>
11454			 *
11455			 *  @dtopt Language
11456			 *  @name DataTable.defaults.language.infoPostFix
11457			 *
11458			 *  @example
11459			 *    $(document).ready( function() {
11460			 *      $('#example').dataTable( {
11461			 *        "language": {
11462			 *          "infoPostFix": "All records shown are derived from real information."
11463			 *        }
11464			 *      } );
11465			 *    } );
11466			 */
11467			"sInfoPostFix": "",
11468	
11469	
11470			/**
11471			 * This decimal place operator is a little different from the other
11472			 * language options since DataTables doesn't output floating point
11473			 * numbers, so it won't ever use this for display of a number. Rather,
11474			 * what this parameter does is modify the sort methods of the table so
11475			 * that numbers which are in a format which has a character other than
11476			 * a period (`.`) as a decimal place will be sorted numerically.
11477			 *
11478			 * Note that numbers with different decimal places cannot be shown in
11479			 * the same table and still be sortable, the table must be consistent.
11480			 * However, multiple different tables on the page can use different
11481			 * decimal place characters.
11482			 *  @type string
11483			 *  @default 
11484			 *
11485			 *  @dtopt Language
11486			 *  @name DataTable.defaults.language.decimal
11487			 *
11488			 *  @example
11489			 *    $(document).ready( function() {
11490			 *      $('#example').dataTable( {
11491			 *        "language": {
11492			 *          "decimal": ","
11493			 *          "thousands": "."
11494			 *        }
11495			 *      } );
11496			 *    } );
11497			 */
11498			"sDecimal": "",
11499	
11500	
11501			/**
11502			 * DataTables has a build in number formatter (`formatNumber`) which is
11503			 * used to format large numbers that are used in the table information.
11504			 * By default a comma is used, but this can be trivially changed to any
11505			 * character you wish with this parameter.
11506			 *  @type string
11507			 *  @default ,
11508			 *
11509			 *  @dtopt Language
11510			 *  @name DataTable.defaults.language.thousands
11511			 *
11512			 *  @example
11513			 *    $(document).ready( function() {
11514			 *      $('#example').dataTable( {
11515			 *        "language": {
11516			 *          "thousands": "'"
11517			 *        }
11518			 *      } );
11519			 *    } );
11520			 */
11521			"sThousands": ",",
11522	
11523	
11524			/**
11525			 * Detail the action that will be taken when the drop down menu for the
11526			 * pagination length option is changed. The '_MENU_' variable is replaced
11527			 * with a default select list of 10, 25, 50 and 100, and can be replaced
11528			 * with a custom select box if required.
11529			 *  @type string
11530			 *  @default Show _MENU_ entries
11531			 *
11532			 *  @dtopt Language
11533			 *  @name DataTable.defaults.language.lengthMenu
11534			 *
11535			 *  @example
11536			 *    // Language change only
11537			 *    $(document).ready( function() {
11538			 *      $('#example').dataTable( {
11539			 *        "language": {
11540			 *          "lengthMenu": "Display _MENU_ records"
11541			 *        }
11542			 *      } );
11543			 *    } );
11544			 *
11545			 *  @example
11546			 *    // Language and options change
11547			 *    $(document).ready( function() {
11548			 *      $('#example').dataTable( {
11549			 *        "language": {
11550			 *          "lengthMenu": 'Display <select>'+
11551			 *            '<option value="10">10</option>'+
11552			 *            '<option value="20">20</option>'+
11553			 *            '<option value="30">30</option>'+
11554			 *            '<option value="40">40</option>'+
11555			 *            '<option value="50">50</option>'+
11556			 *            '<option value="-1">All</option>'+
11557			 *            '</select> records'
11558			 *        }
11559			 *      } );
11560			 *    } );
11561			 */
11562			"sLengthMenu": "Show _MENU_ entries",
11563	
11564	
11565			/**
11566			 * When using Ajax sourced data and during the first draw when DataTables is
11567			 * gathering the data, this message is shown in an empty row in the table to
11568			 * indicate to the end user the the data is being loaded. Note that this
11569			 * parameter is not used when loading data by server-side processing, just
11570			 * Ajax sourced data with client-side processing.
11571			 *  @type string
11572			 *  @default Loading...
11573			 *
11574			 *  @dtopt Language
11575			 *  @name DataTable.defaults.language.loadingRecords
11576			 *
11577			 *  @example
11578			 *    $(document).ready( function() {
11579			 *      $('#example').dataTable( {
11580			 *        "language": {
11581			 *          "loadingRecords": "Please wait - loading..."
11582			 *        }
11583			 *      } );
11584			 *    } );
11585			 */
11586			"sLoadingRecords": "Loading...",
11587	
11588	
11589			/**
11590			 * Text which is displayed when the table is processing a user action
11591			 * (usually a sort command or similar).
11592			 *  @type string
11593			 *  @default Processing...
11594			 *
11595			 *  @dtopt Language
11596			 *  @name DataTable.defaults.language.processing
11597			 *
11598			 *  @example
11599			 *    $(document).ready( function() {
11600			 *      $('#example').dataTable( {
11601			 *        "language": {
11602			 *          "processing": "DataTables is currently busy"
11603			 *        }
11604			 *      } );
11605			 *    } );
11606			 */
11607			"sProcessing": "Processing...",
11608	
11609	
11610			/**
11611			 * Details the actions that will be taken when the user types into the
11612			 * filtering input text box. The variable "_INPUT_", if used in the string,
11613			 * is replaced with the HTML text box for the filtering input allowing
11614			 * control over where it appears in the string. If "_INPUT_" is not given
11615			 * then the input box is appended to the string automatically.
11616			 *  @type string
11617			 *  @default Search:
11618			 *
11619			 *  @dtopt Language
11620			 *  @name DataTable.defaults.language.search
11621			 *
11622			 *  @example
11623			 *    // Input text box will be appended at the end automatically
11624			 *    $(document).ready( function() {
11625			 *      $('#example').dataTable( {
11626			 *        "language": {
11627			 *          "search": "Filter records:"
11628			 *        }
11629			 *      } );
11630			 *    } );
11631			 *
11632			 *  @example
11633			 *    // Specify where the filter should appear
11634			 *    $(document).ready( function() {
11635			 *      $('#example').dataTable( {
11636			 *        "language": {
11637			 *          "search": "Apply filter _INPUT_ to table"
11638			 *        }
11639			 *      } );
11640			 *    } );
11641			 */
11642			"sSearch": "Search:",
11643	
11644	
11645			/**
11646			 * Assign a `placeholder` attribute to the search `input` element
11647			 *  @type string
11648			 *  @default 
11649			 *
11650			 *  @dtopt Language
11651			 *  @name DataTable.defaults.language.searchPlaceholder
11652			 */
11653			"sSearchPlaceholder": "",
11654	
11655	
11656			/**
11657			 * All of the language information can be stored in a file on the
11658			 * server-side, which DataTables will look up if this parameter is passed.
11659			 * It must store the URL of the language file, which is in a JSON format,
11660			 * and the object has the same properties as the oLanguage object in the
11661			 * initialiser object (i.e. the above parameters). Please refer to one of
11662			 * the example language files to see how this works in action.
11663			 *  @type string
11664			 *  @default <i>Empty string - i.e. disabled</i>
11665			 *
11666			 *  @dtopt Language
11667			 *  @name DataTable.defaults.language.url
11668			 *
11669			 *  @example
11670			 *    $(document).ready( function() {
11671			 *      $('#example').dataTable( {
11672			 *        "language": {
11673			 *          "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11674			 *        }
11675			 *      } );
11676			 *    } );
11677			 */
11678			"sUrl": "",
11679	
11680	
11681			/**
11682			 * Text shown inside the table records when the is no information to be
11683			 * displayed after filtering. `emptyTable` is shown when there is simply no
11684			 * information in the table at all (regardless of filtering).
11685			 *  @type string
11686			 *  @default No matching records found
11687			 *
11688			 *  @dtopt Language
11689			 *  @name DataTable.defaults.language.zeroRecords
11690			 *
11691			 *  @example
11692			 *    $(document).ready( function() {
11693			 *      $('#example').dataTable( {
11694			 *        "language": {
11695			 *          "zeroRecords": "No records to display"
11696			 *        }
11697			 *      } );
11698			 *    } );
11699			 */
11700			"sZeroRecords": "No matching records found"
11701		},
11702	
11703	
11704		/**
11705		 * This parameter allows you to have define the global filtering state at
11706		 * initialisation time. As an object the `search` parameter must be
11707		 * defined, but all other parameters are optional. When `regex` is true,
11708		 * the search string will be treated as a regular expression, when false
11709		 * (default) it will be treated as a straight string. When `smart`
11710		 * DataTables will use it's smart filtering methods (to word match at
11711		 * any point in the data), when false this will not be done.
11712		 *  @namespace
11713		 *  @extends DataTable.models.oSearch
11714		 *
11715		 *  @dtopt Options
11716		 *  @name DataTable.defaults.search
11717		 *
11718		 *  @example
11719		 *    $(document).ready( function() {
11720		 *      $('#example').dataTable( {
11721		 *        "search": {"search": "Initial search"}
11722		 *      } );
11723		 *    } )
11724		 */
11725		"oSearch": $.extend( {}, DataTable.models.oSearch ),
11726	
11727	
11728		/**
11729		 * __Deprecated__ The functionality provided by this parameter has now been
11730		 * superseded by that provided through `ajax`, which should be used instead.
11731		 *
11732		 * By default DataTables will look for the property `data` (or `aaData` for
11733		 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11734		 * source or for server-side processing - this parameter allows that
11735		 * property to be changed. You can use Javascript dotted object notation to
11736		 * get a data source for multiple levels of nesting.
11737		 *  @type string
11738		 *  @default data
11739		 *
11740		 *  @dtopt Options
11741		 *  @dtopt Server-side
11742		 *  @name DataTable.defaults.ajaxDataProp
11743		 *
11744		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
11745		 */
11746		"sAjaxDataProp": "data",
11747	
11748	
11749		/**
11750		 * __Deprecated__ The functionality provided by this parameter has now been
11751		 * superseded by that provided through `ajax`, which should be used instead.
11752		 *
11753		 * You can instruct DataTables to load data from an external
11754		 * source using this parameter (use aData if you want to pass data in you
11755		 * already have). Simply provide a url a JSON object can be obtained from.
11756		 *  @type string
11757		 *  @default null
11758		 *
11759		 *  @dtopt Options
11760		 *  @dtopt Server-side
11761		 *  @name DataTable.defaults.ajaxSource
11762		 *
11763		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
11764		 */
11765		"sAjaxSource": null,
11766	
11767	
11768		/**
11769		 * This initialisation variable allows you to specify exactly where in the
11770		 * DOM you want DataTables to inject the various controls it adds to the page
11771		 * (for example you might want the pagination controls at the top of the
11772		 * table). DIV elements (with or without a custom class) can also be added to
11773		 * aid styling. The follow syntax is used:
11774		 *   <ul>
11775		 *     <li>The following options are allowed:
11776		 *       <ul>
11777		 *         <li>'l' - Length changing</li>
11778		 *         <li>'f' - Filtering input</li>
11779		 *         <li>'t' - The table!</li>
11780		 *         <li>'i' - Information</li>
11781		 *         <li>'p' - Pagination</li>
11782		 *         <li>'r' - pRocessing</li>
11783		 *       </ul>
11784		 *     </li>
11785		 *     <li>The following constants are allowed:
11786		 *       <ul>
11787		 *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11788		 *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11789		 *       </ul>
11790		 *     </li>
11791		 *     <li>The following syntax is expected:
11792		 *       <ul>
11793		 *         <li>'&lt;' and '&gt;' - div elements</li>
11794		 *         <li>'&lt;"class" and '&gt;' - div with a class</li>
11795		 *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11796		 *       </ul>
11797		 *     </li>
11798		 *     <li>Examples:
11799		 *       <ul>
11800		 *         <li>'&lt;"wrapper"flipt&gt;'</li>
11801		 *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11802		 *       </ul>
11803		 *     </li>
11804		 *   </ul>
11805		 *  @type string
11806		 *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11807		 *    <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11808		 *
11809		 *  @dtopt Options
11810		 *  @name DataTable.defaults.dom
11811		 *
11812		 *  @example
11813		 *    $(document).ready( function() {
11814		 *      $('#example').dataTable( {
11815		 *        "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11816		 *      } );
11817		 *    } );
11818		 */
11819		"sDom": "lfrtip",
11820	
11821	
11822		/**
11823		 * Search delay option. This will throttle full table searches that use the
11824		 * DataTables provided search input element (it does not effect calls to
11825		 * `dt-api search()`, providing a delay before the search is made.
11826		 *  @type integer
11827		 *  @default 0
11828		 *
11829		 *  @dtopt Options
11830		 *  @name DataTable.defaults.searchDelay
11831		 *
11832		 *  @example
11833		 *    $(document).ready( function() {
11834		 *      $('#example').dataTable( {
11835		 *        "searchDelay": 200
11836		 *      } );
11837		 *    } )
11838		 */
11839		"searchDelay": null,
11840	
11841	
11842		/**
11843		 * DataTables features four different built-in options for the buttons to
11844		 * display for pagination control:
11845		 *
11846		 * * `simple` - 'Previous' and 'Next' buttons only
11847		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11848		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11849		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11850		 *   page numbers
11851		 *  
11852		 * Further methods can be added using {@link DataTable.ext.oPagination}.
11853		 *  @type string
11854		 *  @default simple_numbers
11855		 *
11856		 *  @dtopt Options
11857		 *  @name DataTable.defaults.pagingType
11858		 *
11859		 *  @example
11860		 *    $(document).ready( function() {
11861		 *      $('#example').dataTable( {
11862		 *        "pagingType": "full_numbers"
11863		 *      } );
11864		 *    } )
11865		 */
11866		"sPaginationType": "simple_numbers",
11867	
11868	
11869		/**
11870		 * Enable horizontal scrolling. When a table is too wide to fit into a
11871		 * certain layout, or you have a large number of columns in the table, you
11872		 * can enable x-scrolling to show the table in a viewport, which can be
11873		 * scrolled. This property can be `true` which will allow the table to
11874		 * scroll horizontally when needed, or any CSS unit, or a number (in which
11875		 * case it will be treated as a pixel measurement). Setting as simply `true`
11876		 * is recommended.
11877		 *  @type boolean|string
11878		 *  @default <i>blank string - i.e. disabled</i>
11879		 *
11880		 *  @dtopt Features
11881		 *  @name DataTable.defaults.scrollX
11882		 *
11883		 *  @example
11884		 *    $(document).ready( function() {
11885		 *      $('#example').dataTable( {
11886		 *        "scrollX": true,
11887		 *        "scrollCollapse": true
11888		 *      } );
11889		 *    } );
11890		 */
11891		"sScrollX": "",
11892	
11893	
11894		/**
11895		 * This property can be used to force a DataTable to use more width than it
11896		 * might otherwise do when x-scrolling is enabled. For example if you have a
11897		 * table which requires to be well spaced, this parameter is useful for
11898		 * "over-sizing" the table, and thus forcing scrolling. This property can by
11899		 * any CSS unit, or a number (in which case it will be treated as a pixel
11900		 * measurement).
11901		 *  @type string
11902		 *  @default <i>blank string - i.e. disabled</i>
11903		 *
11904		 *  @dtopt Options
11905		 *  @name DataTable.defaults.scrollXInner
11906		 *
11907		 *  @example
11908		 *    $(document).ready( function() {
11909		 *      $('#example').dataTable( {
11910		 *        "scrollX": "100%",
11911		 *        "scrollXInner": "110%"
11912		 *      } );
11913		 *    } );
11914		 */
11915		"sScrollXInner": "",
11916	
11917	
11918		/**
11919		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11920		 * to the given height, and enable scrolling for any data which overflows the
11921		 * current viewport. This can be used as an alternative to paging to display
11922		 * a lot of data in a small area (although paging and scrolling can both be
11923		 * enabled at the same time). This property can be any CSS unit, or a number
11924		 * (in which case it will be treated as a pixel measurement).
11925		 *  @type string
11926		 *  @default <i>blank string - i.e. disabled</i>
11927		 *
11928		 *  @dtopt Features
11929		 *  @name DataTable.defaults.scrollY
11930		 *
11931		 *  @example
11932		 *    $(document).ready( function() {
11933		 *      $('#example').dataTable( {
11934		 *        "scrollY": "200px",
11935		 *        "paginate": false
11936		 *      } );
11937		 *    } );
11938		 */
11939		"sScrollY": "",
11940	
11941	
11942		/**
11943		 * __Deprecated__ The functionality provided by this parameter has now been
11944		 * superseded by that provided through `ajax`, which should be used instead.
11945		 *
11946		 * Set the HTTP method that is used to make the Ajax call for server-side
11947		 * processing or Ajax sourced data.
11948		 *  @type string
11949		 *  @default GET
11950		 *
11951		 *  @dtopt Options
11952		 *  @dtopt Server-side
11953		 *  @name DataTable.defaults.serverMethod
11954		 *
11955		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
11956		 */
11957		"sServerMethod": "GET",
11958	
11959	
11960		/**
11961		 * DataTables makes use of renderers when displaying HTML elements for
11962		 * a table. These renderers can be added or modified by plug-ins to
11963		 * generate suitable mark-up for a site. For example the Bootstrap
11964		 * integration plug-in for DataTables uses a paging button renderer to
11965		 * display pagination buttons in the mark-up required by Bootstrap.
11966		 *
11967		 * For further information about the renderers available see
11968		 * DataTable.ext.renderer
11969		 *  @type string|object
11970		 *  @default null
11971		 *
11972		 *  @name DataTable.defaults.renderer
11973		 *
11974		 */
11975		"renderer": null,
11976	
11977	
11978		/**
11979		 * Set the data property name that DataTables should use to get a row's id
11980		 * to set as the `id` property in the node.
11981		 *  @type string
11982		 *  @default DT_RowId
11983		 *
11984		 *  @name DataTable.defaults.rowId
11985		 */
11986		"rowId": "DT_RowId"
11987	};
11988	
11989	_fnHungarianMap( DataTable.defaults );
11990	
11991	
11992	
11993	/*
11994	 * Developer note - See note in model.defaults.js about the use of Hungarian
11995	 * notation and camel case.
11996	 */
11997	
11998	/**
11999	 * Column options that can be given to DataTables at initialisation time.
12000	 *  @namespace
12001	 */
12002	DataTable.defaults.column = {
12003		/**
12004		 * Define which column(s) an order will occur on for this column. This
12005		 * allows a column's ordering to take multiple columns into account when
12006		 * doing a sort or use the data from a different column. For example first
12007		 * name / last name columns make sense to do a multi-column sort over the
12008		 * two columns.
12009		 *  @type array|int
12010		 *  @default null <i>Takes the value of the column index automatically</i>
12011		 *
12012		 *  @name DataTable.defaults.column.orderData
12013		 *  @dtopt Columns
12014		 *
12015		 *  @example
12016		 *    // Using `columnDefs`
12017		 *    $(document).ready( function() {
12018		 *      $('#example').dataTable( {
12019		 *        "columnDefs": [
12020		 *          { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12021		 *          { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12022		 *          { "orderData": 2, "targets": [ 2 ] }
12023		 *        ]
12024		 *      } );
12025		 *    } );
12026		 *
12027		 *  @example
12028		 *    // Using `columns`
12029		 *    $(document).ready( function() {
12030		 *      $('#example').dataTable( {
12031		 *        "columns": [
12032		 *          { "orderData": [ 0, 1 ] },
12033		 *          { "orderData": [ 1, 0 ] },
12034		 *          { "orderData": 2 },
12035		 *          null,
12036		 *          null
12037		 *        ]
12038		 *      } );
12039		 *    } );
12040		 */
12041		"aDataSort": null,
12042		"iDataSort": -1,
12043	
12044	
12045		/**
12046		 * You can control the default ordering direction, and even alter the
12047		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12048		 * using this parameter.
12049		 *  @type array
12050		 *  @default [ 'asc', 'desc' ]
12051		 *
12052		 *  @name DataTable.defaults.column.orderSequence
12053		 *  @dtopt Columns
12054		 *
12055		 *  @example
12056		 *    // Using `columnDefs`
12057		 *    $(document).ready( function() {
12058		 *      $('#example').dataTable( {
12059		 *        "columnDefs": [
12060		 *          { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12061		 *          { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12062		 *          { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12063		 *        ]
12064		 *      } );
12065		 *    } );
12066		 *
12067		 *  @example
12068		 *    // Using `columns`
12069		 *    $(document).ready( function() {
12070		 *      $('#example').dataTable( {
12071		 *        "columns": [
12072		 *          null,
12073		 *          { "orderSequence": [ "asc" ] },
12074		 *          { "orderSequence": [ "desc", "asc", "asc" ] },
12075		 *          { "orderSequence": [ "desc" ] },
12076		 *          null
12077		 *        ]
12078		 *      } );
12079		 *    } );
12080		 */
12081		"asSorting": [ 'asc', 'desc' ],
12082	
12083	
12084		/**
12085		 * Enable or disable filtering on the data in this column.
12086		 *  @type boolean
12087		 *  @default true
12088		 *
12089		 *  @name DataTable.defaults.column.searchable
12090		 *  @dtopt Columns
12091		 *
12092		 *  @example
12093		 *    // Using `columnDefs`
12094		 *    $(document).ready( function() {
12095		 *      $('#example').dataTable( {
12096		 *        "columnDefs": [
12097		 *          { "searchable": false, "targets": [ 0 ] }
12098		 *        ] } );
12099		 *    } );
12100		 *
12101		 *  @example
12102		 *    // Using `columns`
12103		 *    $(document).ready( function() {
12104		 *      $('#example').dataTable( {
12105		 *        "columns": [
12106		 *          { "searchable": false },
12107		 *          null,
12108		 *          null,
12109		 *          null,
12110		 *          null
12111		 *        ] } );
12112		 *    } );
12113		 */
12114		"bSearchable": true,
12115	
12116	
12117		/**
12118		 * Enable or disable ordering on this column.
12119		 *  @type boolean
12120		 *  @default true
12121		 *
12122		 *  @name DataTable.defaults.column.orderable
12123		 *  @dtopt Columns
12124		 *
12125		 *  @example
12126		 *    // Using `columnDefs`
12127		 *    $(document).ready( function() {
12128		 *      $('#example').dataTable( {
12129		 *        "columnDefs": [
12130		 *          { "orderable": false, "targets": [ 0 ] }
12131		 *        ] } );
12132		 *    } );
12133		 *
12134		 *  @example
12135		 *    // Using `columns`
12136		 *    $(document).ready( function() {
12137		 *      $('#example').dataTable( {
12138		 *        "columns": [
12139		 *          { "orderable": false },
12140		 *          null,
12141		 *          null,
12142		 *          null,
12143		 *          null
12144		 *        ] } );
12145		 *    } );
12146		 */
12147		"bSortable": true,
12148	
12149	
12150		/**
12151		 * Enable or disable the display of this column.
12152		 *  @type boolean
12153		 *  @default true
12154		 *
12155		 *  @name DataTable.defaults.column.visible
12156		 *  @dtopt Columns
12157		 *
12158		 *  @example
12159		 *    // Using `columnDefs`
12160		 *    $(document).ready( function() {
12161		 *      $('#example').dataTable( {
12162		 *        "columnDefs": [
12163		 *          { "visible": false, "targets": [ 0 ] }
12164		 *        ] } );
12165		 *    } );
12166		 *
12167		 *  @example
12168		 *    // Using `columns`
12169		 *    $(document).ready( function() {
12170		 *      $('#example').dataTable( {
12171		 *        "columns": [
12172		 *          { "visible": false },
12173		 *          null,
12174		 *          null,
12175		 *          null,
12176		 *          null
12177		 *        ] } );
12178		 *    } );
12179		 */
12180		"bVisible": true,
12181	
12182	
12183		/**
12184		 * Developer definable function that is called whenever a cell is created (Ajax source,
12185		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12186		 * allowing you to modify the DOM element (add background colour for example) when the
12187		 * element is available.
12188		 *  @type function
12189		 *  @param {element} td The TD node that has been created
12190		 *  @param {*} cellData The Data for the cell
12191		 *  @param {array|object} rowData The data for the whole row
12192		 *  @param {int} row The row index for the aoData data store
12193		 *  @param {int} col The column index for aoColumns
12194		 *
12195		 *  @name DataTable.defaults.column.createdCell
12196		 *  @dtopt Columns
12197		 *
12198		 *  @example
12199		 *    $(document).ready( function() {
12200		 *      $('#example').dataTable( {
12201		 *        "columnDefs": [ {
12202		 *          "targets": [3],
12203		 *          "createdCell": function (td, cellData, rowData, row, c
12203ol) {
12204		 *            if ( cellData == "1.7" ) {
12205		 *              $(td).css('color', 'blue')
12206		 *            }
12207		 *          }
12208		 *        } ]
12209		 *      });
12210		 *    } );
12211		 */
12212		"fnCreatedCell": null,
12213	
12214	
12215		/**
12216		 * This parameter has been replaced by `data` in DataTables to ensure naming
12217		 * consistency. `dataProp` can still be used, as there is backwards
12218		 * compatibility in DataTables for this option, but it is strongly
12219		 * recommended that you use `data` in preference to `dataProp`.
12220		 *  @name DataTable.defaults.column.dataProp
12221		 */
12222	
12223	
12224		/**
12225		 * This property can be used to read data from any data source property,
12226		 * including deeply nested objects / properties. `data` can be given in a
12227		 * number of different ways which effect its behaviour:
12228		 *
12229		 * * `integer` - treated as an array index for the data source. This is the
12230		 *   default that DataTables uses (incrementally increased for each column).
12231		 * * `string` - read an object property from the data source. There are
12232		 *   three 'special' options that can be used in the string to alter how
12233		 *   DataTables reads the data from the source object:
12234		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
12235		 *      Javascript to read from nested objects, so to can the options
12236		 *      specified in `data`. For example: `browser.version` or
12237		 *      `browser.name`. If your object parameter name contains a period, use
12238		 *      `\\` to escape it - i.e. `first\\.name`.
12239		 *    * `[]` - Array notation. DataTables can automatically combine data
12240		 *      from and array source, joining the data with the characters provided
12241		 *      between the two brackets. For example: `name[, ]` would provide a
12242		 *      comma-space separated list from the source array. If no characters
12243		 *      are provided between the brackets, the original array source is
12244		 *      returned.
12245		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
12246		 *      execute a function of the name given. For example: `browser()` for a
12247		 *      simple function on the data source, `browser.version()` for a
12248		 *      function in a nested property or even `browser().version` to get an
12249		 *      object property if the function called returns an object. Note that
12250		 *      function notation is recommended for use in `render` rather than
12251		 *      `data` as it is much simpler to use as a renderer.
12252		 * * `null` - use the original data source for the row rather than plucking
12253		 *   data directly from it. This action has effects on two other
12254		 *   initialisation options:
12255		 *    * `defaultContent` - When null is given as the `data` option and
12256		 *      `defaultContent` is specified for the column, the value defined by
12257		 *      `defaultContent` will be used for the cell.
12258		 *    * `render` - When null is used for the `data` option and the `render`
12259		 *      option is specified for the column, the whole data source for the
12260		 *      row is used for the renderer.
12261		 * * `function` - the function given will be executed whenever DataTables
12262		 *   needs to set or get the data for a cell in the column. The function
12263		 *   takes three parameters:
12264		 *    * Parameters:
12265		 *      * `{array|object}` The data source for the row
12266		 *      * `{string}` The type call data requested - this will be 'set' when
12267		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
12268		 *        when gathering data. Note that when `undefined` is given for the
12269		 *        type DataTables expects to get the raw data for the object back<
12270		 *      * `{*}` Data to set when the second parameter is 'set'.
12271		 *    * Return:
12272		 *      * The return value from the function is not required when 'set' is
12273		 *        the type of call, but otherwise the return is what will be used
12274		 *        for the data requested.
12275		 *
12276		 * Note that `data` is a getter and setter option. If you just require
12277		 * formatting of data for output, you will likely want to use `render` which
12278		 * is simply a getter and thus simpler to use.
12279		 *
12280		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12281		 * name change reflects the flexibility of this property and is consistent
12282		 * with the naming of mRender. If 'mDataProp' is given, then it will still
12283		 * be used by DataTables, as it automatically maps the old name to the new
12284		 * if required.
12285		 *
12286		 *  @type string|int|function|null
12287		 *  @default null <i>Use automatically calculated column index</i>
12288		 *
12289		 *  @name DataTable.defaults.column.data
12290		 *  @dtopt Columns
12291		 *
12292		 *  @example
12293		 *    // Read table data from objects
12294		 *    // JSON structure for each row:
12295		 *    //   {
12296		 *    //      "engine": {value},
12297		 *    //      "browser": {value},
12298		 *    //      "platform": {value},
12299		 *    //      "version": {value},
12300		 *    //      "grade": {value}
12301		 *    //   }
12302		 *    $(document).ready( function() {
12303		 *      $('#example').dataTable( {
12304		 *        "ajaxSource": "sources/objects.txt",
12305		 *        "columns": [
12306		 *          { "data": "engine" },
12307		 *          { "data": "browser" },
12308		 *          { "data": "platform" },
12309		 *          { "data": "version" },
12310		 *          { "data": "grade" }
12311		 *        ]
12312		 *      } );
12313		 *    } );
12314		 *
12315		 *  @example
12316		 *    // Read information from deeply nested objects
12317		 *    // JSON structure for each row:
12318		 *    //   {
12319		 *    //      "engine": {value},
12320		 *    //      "browser": {value},
12321		 *    //      "platform": {
12322		 *    //         "inner": {value}
12323		 *    //      },
12324		 *    //      "details": [
12325		 *    //         {value}, {value}
12326		 *    //      ]
12327		 *    //   }
12328		 *    $(document).ready( function() {
12329		 *      $('#example').dataTable( {
12330		 *        "ajaxSource": "sources/deep.txt",
12331		 *        "columns": [
12332		 *          { "data": "engine" },
12333		 *          { "data": "browser" },
12334		 *          { "data": "platform.inner" },
12335		 *          { "data": "platform.details.0" },
12336		 *          { "data": "platform.details.1" }
12337		 *        ]
12338		 *      } );
12339		 *    } );
12340		 *
12341		 *  @example
12342		 *    // Using `data` as a function to provide different information for
12343		 *    // sorting, filtering and display. In this case, currency (price)
12344		 *    $(document).ready( function() {
12345		 *      $('#example').dataTable( {
12346		 *        "columnDefs": [ {
12347		 *          "targets": [ 0 ],
12348		 *          "data": function ( source, type, val ) {
12349		 *            if (type === 'set') {
12350		 *              source.price = val;
12351		 *              // Store the computed dislay and filter values for efficiency
12352		 *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
12353		 *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12354		 *              return;
12355		 *            }
12356		 *            else if (type === 'display') {
12357		 *              return source.price_display;
12358		 *            }
12359		 *            else if (type === 'filter') {
12360		 *              return source.price_filter;
12361		 *            }
12362		 *            // 'sort', 'type' and undefined all just use the integer
12363		 *            return source.price;
12364		 *          }
12365		 *        } ]
12366		 *      } );
12367		 *    } );
12368		 *
12369		 *  @example
12370		 *    // Using default content
12371		 *    $(document).ready( function() {
12372		 *      $('#example').dataTable( {
12373		 *        "columnDefs": [ {
12374		 *          "targets": [ 0 ],
12375		 *          "data": null,
12376		 *          "defaultContent": "Click to edit"
12377		 *        } ]
12378		 *      } );
12379		 *    } );
12380		 *
12381		 *  @example
12382		 *    // Using array notation - outputting a list from an array
12383		 *    $(document).ready( function() {
12384		 *      $('#example').dataTable( {
12385		 *        "columnDefs": [ {
12386		 *          "targets": [ 0 ],
12387		 *          "data": "name[, ]"
12388		 *        } ]
12389		 *      } );
12390		 *    } );
12391		 *
12392		 */
12393		"mData": null,
12394	
12395	
12396		/**
12397		 * This property is the rendering partner to `data` and it is suggested that
12398		 * when you want to manipulate data for display (including filtering,
12399		 * sorting etc) without altering the underlying data for the table, use this
12400		 * property. `render` can be considered to be the the read only companion to
12401		 * `data` which is read / write (then as such more complex). Like `data`
12402		 * this option can be given in a number of different ways to effect its
12403		 * behaviour:
12404		 *
12405		 * * `integer` - treated as an array index for the data source. This is the
12406		 *   default that DataTables uses (incrementally increased for each column).
12407		 * * `string` - read an object property from the data source. There are
12408		 *   three 'special' options that can be used in the string to alter how
12409		 *   DataTables reads the data from the source object:
12410		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
12411		 *      Javascript to read from nested objects, so to can the options
12412		 *      specified in `data`. For example: `browser.version` or
12413		 *      `browser.name`. If your object parameter name contains a period, use
12414		 *      `\\` to escape it - i.e. `first\\.name`.
12415		 *    * `[]` - Array notation. DataTables can automatically combine data
12416		 *      from and array source, joining the data with the characters provided
12417		 *      between the two brackets. For example: `name[, ]` would provide a
12418		 *      comma-space separated list from the source array. If no characters
12419		 *      are provided between the brackets, the original array source is
12420		 *      returned.
12421		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
12422		 *      execute a function of the name given. For example: `browser()` for a
12423		 *      simple function on the data source, `browser.version()` for a
12424		 *      function in a nested property or even `browser().version` to get an
12425		 *      object property if the function called returns an object.
12426		 * * `object` - use different data for the different data types requested by
12427		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
12428		 *   of the object is the data type the property refers to and the value can
12429		 *   defined using an integer, string or function using the same rules as
12430		 *   `render` normally does. Note that an `_` option _must_ be specified.
12431		 *   This is the default value to use if you haven't specified a value for
12432		 *   the data type requested by DataTables.
12433		 * * `function` - the function given will be executed whenever DataTables
12434		 *   needs to set or get the data for a cell in the column. The function
12435		 *   takes three parameters:
12436		 *    * Parameters:
12437		 *      * {array|object} The data source for the row (based on `data`)
12438		 *      * {string} The type call data requested - this will be 'filter',
12439		 *        'display', 'type' or 'sort'.
12440		 *      * {array|object} The full data source for the row (not based on
12441		 *        `data`)
12442		 *    * Return:
12443		 *      * The return value from the function is what will be used for the
12444		 *        data requested.
12445		 *
12446		 *  @type string|int|function|object|null
12447		 *  @default null Use the data source value.
12448		 *
12449		 *  @name DataTable.defaults.column.render
12450		 *  @dtopt Columns
12451		 *
12452		 *  @example
12453		 *    // Create a comma separated list from an array of objects
12454		 *    $(document).ready( function() {
12455		 *      $('#example').dataTable( {
12456		 *        "ajaxSource": "sources/deep.txt",
12457		 *        "columns": [
12458		 *          { "data": "engine" },
12459		 *          { "data": "browser" },
12460		 *          {
12461		 *            "data": "platform",
12462		 *            "render": "[, ].name"
12463		 *          }
12464		 *        ]
12465		 *      } );
12466		 *    } );
12467		 *
12468		 *  @example
12469		 *    // Execute a function to obtain data
12470		 *    $(document).ready( function() {
12471		 *      $('#example').dataTable( {
12472		 *        "columnDefs": [ {
12473		 *          "targets": [ 0 ],
12474		 *          "data": null, // Use the full data source object for the renderer's source
12475		 *          "render": "browserName()"
12476		 *        } ]
12477		 *      } );
12478		 *    } );
12479		 *
12480		 *  @example
12481		 *    // As an object, extracting different data for the different types
12482		 *    // This would be used with a data source such as:
12483		 *    //   { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12484		 *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12485		 *    // (which has both forms) is used for filtering for if a user inputs either format, while
12486		 *    // the formatted phone number is the one that is shown in the table.
12487		 *    $(document).ready( function() {
12488		 *      $('#example').dataTable( {
12489		 *        "columnDefs": [ {
12490		 *          "targets": [ 0 ],
12491		 *          "data": null, // Use the full data source object for the renderer's source
12492		 *          "render": {
12493		 *            "_": "phone",
12494		 *            "filter": "phone_filter",
12495		 *            "display": "phone_display"
12496		 *          }
12497		 *        } ]
12498		 *      } );
12499		 *    } );
12500		 *
12501		 *  @example
12502		 *    // Use as a function to create a link from the data source
12503		 *    $(document).ready( function() {
12504		 *      $('#example').dataTable( {
12505		 *        "columnDefs": [ {
12506		 *          "targets": [ 0 ],
12507		 *          "data": "download_link",
12508		 *          "render": function ( data, type, full ) {
12509		 *            return '<a href="'+data+'">Download</a>';
12510		 *          }
12511		 *        } ]
12512		 *      } );
12513		 *    } );
12514		 */
12515		"mRender": null,
12516	
12517	
12518		/**
12519		 * Change the cell type created for the column - either TD cells or TH cells. This
12520		 * can be useful as TH cells have semantic meaning in the table body, allowing them
12521		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12522		 *  @type string
12523		 *  @default td
12524		 *
12525		 *  @name DataTable.defaults.column.cellType
12526		 *  @dtopt Columns
12527		 *
12528		 *  @example
12529		 *    // Make the first column use TH cells
12530		 *    $(document).ready( function() {
12531		 *      $('#example').dataTable( {
12532		 *        "columnDefs": [ {
12533		 *          "targets": [ 0 ],
12534		 *          "cellType": "th"
12535		 *        } ]
12536		 *      } );
12537		 *    } );
12538		 */
12539		"sCellType": "td",
12540	
12541	
12542		/**
12543		 * Class to give to each cell in this column.
12544		 *  @type string
12545		 *  @default <i>Empty string</i>
12546		 *
12547		 *  @name DataTable.defaults.column.class
12548		 *  @dtopt Columns
12549		 *
12550		 *  @example
12551		 *    // Using `columnDefs`
12552		 *    $(document).ready( function() {
12553		 *      $('#example').dataTable( {
12554		 *        "columnDefs": [
12555		 *          { "class": "my_class", "targets": [ 0 ] }
12556		 *        ]
12557		 *      } );
12558		 *    } );
12559		 *
12560		 *  @example
12561		 *    // Using `columns`
12562		 *    $(document).ready( function() {
12563		 *      $('#example').dataTable( {
12564		 *        "columns": [
12565		 *          { "class": "my_class" },
12566		 *          null,
12567		 *          null,
12568		 *          null,
12569		 *          null
12570		 *        ]
12571		 *      } );
12572		 *    } );
12573		 */
12574		"sClass": "",
12575	
12576		/**
12577		 * When DataTables calculates the column widths to assign to each column,
12578		 * it finds the longest string in each column and then constructs a
12579		 * temporary table and reads the widths from that. The problem with this
12580		 * is that "mmm" is much wider then "iiii", but the latter is a longer
12581		 * string - thus the calculation can go wrong (doing it properly and putting
12582		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12583		 * a "work around" we provide this option. It will append its value to the
12584		 * text that is found to be the longest string for the column - i.e. padding.
12585		 * Generally you shouldn't need this!
12586		 *  @type string
12587		 *  @default <i>Empty string<i>
12588		 *
12589		 *  @name DataTable.defaults.column.contentPadding
12590		 *  @dtopt Columns
12591		 *
12592		 *  @example
12593		 *    // Using `columns`
12594		 *    $(document).ready( function() {
12595		 *      $('#example').dataTable( {
12596		 *        "columns": [
12597		 *          null,
12598		 *          null,
12599		 *          null,
12600		 *          {
12601		 *            "contentPadding": "mmm"
12602		 *          }
12603		 *        ]
12604		 *      } );
12605		 *    } );
12606		 */
12607		"sContentPadding": "",
12608	
12609	
12610		/**
12611		 * Allows a default value to be given for a column's data, and will be used
12612		 * whenever a null data source is encountered (this can be because `data`
12613		 * is set to null, or because the data source itself is null).
12614		 *  @type string
12615		 *  @default null
12616		 *
12617		 *  @name DataTable.defaults.column.defaultContent
12618		 *  @dtopt Columns
12619		 *
12620		 *  @example
12621		 *    // Using `columnDefs`
12622		 *    $(document).ready( function() {
12623		 *      $('#example').dataTable( {
12624		 *        "columnDefs": [
12625		 *          {
12626		 *            "data": null,
12627		 *            "defaultContent": "Edit",
12628		 *            "targets": [ -1 ]
12629		 *          }
12630		 *        ]
12631		 *      } );
12632		 *    } );
12633		 *
12634		 *  @example
12635		 *    // Using `columns`
12636		 *    $(document).ready( function() {
12637		 *      $('#example').dataTable( {
12638		 *        "columns": [
12639		 *          null,
12640		 *          null,
12641		 *          null,
12642		 *          {
12643		 *            "data": null,
12644		 *            "defaultContent": "Edit"
12645		 *          }
12646		 *        ]
12647		 *      } );
12648		 *    } );
12649		 */
12650		"sDefaultContent": null,
12651	
12652	
12653		/**
12654		 * This parameter is only used in DataTables' server-side processing. It can
12655		 * be exceptionally useful to know what columns are being displayed on the
12656		 * client side, and to map these to database fields. When defined, the names
12657		 * also allow DataTables to reorder information from the server if it comes
12658		 * back in an unexpected order (i.e. if you switch your columns around on the
12659		 * client-side, your server-side code does not also need updating).
12660		 *  @type string
12661		 *  @default <i>Empty string</i>
12662		 *
12663		 *  @name DataTable.defaults.column.name
12664		 *  @dtopt Columns
12665		 *
12666		 *  @example
12667		 *    // Using `columnDefs`
12668		 *    $(document).ready( function() {
12669		 *      $('#example').dataTable( {
12670		 *        "columnDefs": [
12671		 *          { "name": "engine", "targets": [ 0 ] },
12672		 *          { "name": "browser", "targets": [ 1 ] },
12673		 *          { "name": "platform", "targets": [ 2 ] },
12674		 *          { "name": "version", "targets": [ 3 ] },
12675		 *          { "name": "grade", "targets": [ 4 ] }
12676		 *        ]
12677		 *      } );
12678		 *    } );
12679		 *
12680		 *  @example
12681		 *    // Using `columns`
12682		 *    $(document).ready( function() {
12683		 *      $('#example').dataTable( {
12684		 *        "columns": [
12685		 *          { "name": "engine" },
12686		 *          { "name": "browser" },
12687		 *          { "name": "platform" },
12688		 *          { "name": "version" },
12689		 *          { "name": "grade" }
12690		 *        ]
12691		 *      } );
12692		 *    } );
12693		 */
12694		"sName": "",
12695	
12696	
12697		/**
12698		 * Defines a data source type for the ordering which can be used to read
12699		 * real-time information from the table (updating the internally cached
12700		 * version) prior to ordering. This allows ordering to occur on user
12701		 * editable elements such as form inputs.
12702		 *  @type string
12703		 *  @default std
12704		 *
12705		 *  @name DataTable.defaults.column.orderDataType
12706		 *  @dtopt Columns
12707		 *
12708		 *  @example
12709		 *    // Using `columnDefs`
12710		 *    $(document).ready( function() {
12711		 *      $('#example').dataTable( {
12712		 *        "columnDefs": [
12713		 *          { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12714		 *          { "type": "numeric", "targets": [ 3 ] },
12715		 *          { "orderDataType": "dom-select", "targets": [ 4 ] },
12716		 *          { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12717		 *        ]
12718		 *      } );
12719		 *    } );
12720		 *
12721		 *  @example
12722		 *    // Using `columns`
12723		 *    $(document).ready( function() {
12724		 *      $('#example').dataTable( {
12725		 *        "columns": [
12726		 *          null,
12727		 *          null,
12728		 *          { "orderDataType": "dom-text" },
12729		 *          { "orderDataType": "dom-text", "type": "numeric" },
12730		 *          { "orderDataType": "dom-select" },
12731		 *          { "orderDataType": "dom-checkbox" }
12732		 *        ]
12733		 *      } );
12734		 *    } );
12735		 */
12736		"sSortDataType": "std",
12737	
12738	
12739		/**
12740		 * The title of this column.
12741		 *  @type string
12742		 *  @default null <i>Derived from the 'TH' value for this column in the
12743		 *    original HTML table.</i>
12744		 *
12745		 *  @name DataTable.defaults.column.title
12746		 *  @dtopt Columns
12747		 *
12748		 *  @example
12749		 *    // Using `columnDefs`
12750		 *    $(document).ready( function() {
12751		 *      $('#example').dataTable( {
12752		 *        "columnDefs": [
12753		 *          { "title": "My column title", "targets": [ 0 ] }
12754		 *        ]
12755		 *      } );
12756		 *    } );
12757		 *
12758		 *  @example
12759		 *    // Using `columns`
12760		 *    $(document).ready( function() {
12761		 *      $('#example').dataTable( {
12762		 *        "columns": [
12763		 *          { "title": "My column title" },
12764		 *          null,
12765		 *          null,
12766		 *          null,
12767		 *          null
12768		 *        ]
12769		 *      } );
12770		 *    } );
12771		 */
12772		"sTitle": null,
12773	
12774	
12775		/**
12776		 * The type allows you to specify how the data for this column will be
12777		 * ordered. Four types (string, numeric, date and html (which will strip
12778		 * HTML tags before ordering)) are currently available. Note that only date
12779		 * formats understood by Javascript's Date() object will be accepted as type
12780		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12781		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12782		 * through plug-ins.
12783		 *  @type string
12784		 *  @default null <i>Auto-detected from raw data</i>
12785		 *
12786		 *  @name DataTable.defaults.column.type
12787		 *  @dtopt Columns
12788		 *
12789		 *  @example
12790		 *    // Using `columnDefs`
12791		 *    $(document).ready( function() {
12792		 *      $('#example').dataTable( {
12793		 *        "columnDefs": [
12794		 *          { "type": "html", "targets": [ 0 ] }
12795		 *        ]
12796		 *      } );
12797		 *    } );
12798		 *
12799		 *  @example
12800		 *    // Using `columns`
12801		 *    $(document).ready( function() {
12802		 *      $('#example').dataTable( {
12803		 *        "columns": [
12804		 *          { "type": "html" },
12805		 *          null,
12806		 *          null,
12807		 *          null,
12808		 *          null
12809		 *        ]
12810		 *      } );
12811		 *    } );
12812		 */
12813		"sType": null,
12814	
12815	
12816		/**
12817		 * Defining the width of the column, this parameter may take any CSS value
12818		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12819		 * been given a specific width through this interface ensuring that the table
12820		 * remains readable.
12821		 *  @type string
12822		 *  @default null <i>Automatic</i>
12823		 *
12824		 *  @name DataTable.defaults.column.width
12825		 *  @dtopt Columns
12826		 *
12827		 *  @example
12828		 *    // Using `columnDefs`
12829		 *    $(document).ready( function() {
12830		 *      $('#example').dataTable( {
12831		 *        "columnDefs": [
12832		 *          { "width": "20%", "targets": [ 0 ] }
12833		 *        ]
12834		 *      } );
12835		 *    } );
12836		 *
12837		 *  @example
12838		 *    // Using `columns`
12839		 *    $(document).ready( function() {
12840		 *      $('#example').dataTable( {
12841		 *        "columns": [
12842		 *          { "width": "20%" },
12843		 *          null,
12844		 *          null,
12845		 *          null,
12846		 *          null
12847		 *        ]
12848		 *      } );
12849		 *    } );
12850		 */
12851		"sWidth": null
12852	};
12853	
12854	_fnHungarianMap( DataTable.defaults.column );
12855	
12856	
12857	
12858	/**
12859	 * DataTables settings object - this holds all the information needed for a
12860	 * given table, including configuration, data and current application of the
12861	 * table options. DataTables does not have a single instance for each DataTable
12862	 * with the settings attached to that instance, but rather instances of the
12863	 * DataTable "class" are created on-the-fly as needed (typically by a
12864	 * $().dataTable() call) and the settings object is then applied to that
12865	 * instance.
12866	 *
12867	 * Note that this object is related to {@link DataTable.defaults} but this
12868	 * one is the internal data store for DataTables's cache of columns. It should
12869	 * NOT be manipulated outside of DataTables. Any configuration should be done
12870	 * through the initialisation options.
12871	 *  @namespace
12872	 *  @todo Really should attach the settings object to individual instances so we
12873	 *    don't need to create new instances on each $().dataTable() call (if the
12874	 *    table already exists). It would also save passing oSettings around and
12875	 *    into every single function. However, this is a very significant
12876	 *    architecture change for DataTables and will almost certainly break
12877	 *    backwards compatibility with older installations. This is something that
12878	 *    will be done in 2.0.
12879	 */
12880	DataTable.models.oSettings = {
12881		/**
12882		 * Primary features of DataTables and their enablement state.
12883		 *  @namespace
12884		 */
12885		"oFeatures": {
12886	
12887			/**
12888			 * Flag to say if DataTables should automatically try to calculate the
12889			 * optimum table and columns widths (true) or not (false).
12890			 * Note that this parameter will be set by the initialisation routine. To
12891			 * set a default use {@link DataTable.defaults}.
12892			 *  @type boolean
12893			 */
12894			"bAutoWidth": null,
12895	
12896			/**
12897			 * Delay the creation of TR and TD elements until they are actually
12898			 * needed by a driven page draw. This can give a significant speed
12899			 * increase for Ajax source and Javascript source data, but makes no
12900			 * difference at all fro DOM and server-side processing tables.
12901			 * Note that this parameter will be set by the initialisation routine. To
12902			 * set a default use {@link DataTable.defaults}.
12903			 *  @type boolean
12904			 */
12905			"bDeferRender": null,
12906	
12907			/**
12908			 * Enable filtering on the table or not. Note that if this is disabled
12909			 * then there is no filtering at all on the table, including fnFilter.
12910			 * To just remove the filtering input use sDom and remove the 'f' option.
12911			 * Note that this parameter will be set by the initialisation routine. To
12912			 * set a default use {@link DataTable.defaults}.
12913			 *  @type boolean
12914			 */
12915			"bFilter": null,
12916	
12917			/**
12918			 * Table information element (the 'Showing x of y records' div) enable
12919			 * flag.
12920			 * Note that this parameter will be set by the initialisation routine. To
12921			 * set a default use {@link DataTable.defaults}.
12922			 *  @type boolean
12923			 */
12924			"bInfo": null,
12925	
12926			/**
12927			 * Present a user control allowing the end user to change the page size
12928			 * when pagination is enabled.
12929			 * Note that this parameter will be set by the initialisation routine. To
12930			 * set a default use {@link DataTable.defaults}.
12931			 *  @type boolean
12932			 */
12933			"bLengthChange": null,
12934	
12935			/**
12936			 * Pagination enabled or not. Note that if this is disabled then length
12937			 * changing must also be disabled.
12938			 * Note that this parameter will be set by the initialisation routine. To
12939			 * set a default use {@link DataTable.defaults}.
12940			 *  @type boolean
12941			 */
12942			"bPaginate": null,
12943	
12944			/**
12945			 * Processing indicator enable flag whenever DataTables is enacting a
12946			 * user request - typically an Ajax request for server-side processing.
12947			 * Note that this parameter will be set by the initialisation routine. To
12948			 * set a default use {@link DataTable.defaults}.
12949			 *  @type boolean
12950			 */
12951			"bProcessing": null,
12952	
12953			/**
12954			 * Server-side processing enabled flag - when enabled DataTables will
12955			 * get all data from the server for every draw - there is no filtering,
12956			 * sorting or paging done on the client-side.
12957			 * Note that this parameter will be set by the initialisation routine. To
12958			 * set a default use {@link DataTable.defaults}.
12959			 *  @type boolean
12960			 */
12961			"bServerSide": null,
12962	
12963			/**
12964			 * Sorting enablement flag.
12965			 * Note that this parameter will be set by the initialisation routine. To
12966			 * set a default use {@link DataTable.defaults}.
12967			 *  @type boolean
12968			 */
12969			"bSort": null,
12970	
12971			/**
12972			 * Multi-column sorting
12973			 * Note that this parameter will be set by the initialisation routine. To
12974			 * set a default use {@link DataTable.defaults}.
12975			 *  @type boolean
12976			 */
12977			"bSortMulti": null,
12978	
12979			/**
12980			 * Apply a class to the columns which are being sorted to provide a
12981			 * visual highlight or not. This can slow things down when enabled since
12982			 * there is a lot of DOM interaction.
12983			 * Note that this parameter will be set by the initialisation routine. To
12984			 * set a default use {@link DataTable.defaults}.
12985			 *  @type boolean
12986			 */
12987			"bSortClasses": null,
12988	
12989			/**
12990			 * State saving enablement flag.
12991			 * Note that this parameter will be set by the initialisation routine. To
12992			 * set a default use {@link DataTable.defaults}.
12993			 *  @type boolean
12994			 */
12995			"bStateSave": null
12996		},
12997	
12998	
12999		/**
13000		 * Scrolling settings for a table.
13001		 *  @namespace
13002		 */
13003		"oScroll": {
13004			/**
13005			 * When the table is shorter in height than sScrollY, collapse the
13006			 * table container down to the height of the table (when true).
13007			 * Note that this parameter will be set by the initialisation routine. To
13008			 * set a default use {@link DataTable.defaults}.
13009			 *  @type boolean
13010			 */
13011			"bCollapse": null,
13012	
13013			/**
13014			 * Width of the scrollbar for the web-browser's platform. Calculated
13015			 * during table initialisation.
13016			 *  @type int
13017			 *  @default 0
13018			 */
13019			"iBarWidth": 0,
13020	
13021			/**
13022			 * Viewport width for horizontal scrolling. Horizontal scrolling is
13023			 * disabled if an empty string.
13024			 * Note that this parameter will be set by the initialisation routine. To
13025			 * set a default use {@link DataTable.defaults}.
13026			 *  @type string
13027			 */
13028			"sX": null,
13029	
13030			/**
13031			 * Width to expand the table to when using x-scrolling. Typically you
13032			 * should not need to use this.
13033			 * Note that this parameter will be set by the initialisation routine. To
13034			 * set a default use {@link DataTable.defaults}.
13035			 *  @type string
13036			 *  @deprecated
13037			 */
13038			"sXInner": null,
13039	
13040			/**
13041			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
13042			 * if an empty string.
13043			 * Note that this parameter will be set by the initialisation routine. To
13044			 * set a default use {@link DataTable.defaults}.
13045			 *  @type string
13046			 */
13047			"sY": null
13048		},
13049	
13050		/**
13051		 * Language information for the table.
13052		 *  @namespace
13053		 *  @extends DataTable.defaults.oLanguage
13054		 */
13055		"oLanguage": {
13056			/**
13057			 * Information callback function. See
13058			 * {@link DataTable.defaults.fnInfoCallback}
13059			 *  @type function
13060			 *  @default null
13061			 */
13062			"fnInfoCallback": null
13063		},
13064	
13065		/**
13066		 * Browser support parameters
13067		 *  @namespace
13068		 */
13069		"oBrowser": {
13070			/**
13071			 * Indicate if the browser incorrectly calculates width:100% inside a
13072			 * scrolling element (IE6/7)
13073			 *  @type boolean
13074			 *  @default false
13075			 */
13076			"bScrollOversize": false,
13077	
13078			/**
13079			 * Determine if the vertical scrollbar is on the right or left of the
13080			 * scrolling container - needed for rtl language layout, although not
13081			 * all browsers move the scrollbar (Safari).
13082			 *  @type boolean
13083			 *  @default false
13084			 */
13085			"bScrollbarLeft": false,
13086	
13087			/**
13088			 * Flag for if `getBoundingClientRect` is fully supported or not
13089			 *  @type boolean
13090			 *  @default false
13091			 */
13092			"bBounding": false,
13093	
13094			/**
13095			 * Browser scrollbar width
13096			 *  @type integer
13097			 *  @default 0
13098			 */
13099			"barWidth": 0
13100		},
13101	
13102	
13103		"ajax": null,
13104	
13105	
13106		/**
13107		 * Array referencing the nodes which are used for the features. The
13108		 * parameters of this object match what is allowed by sDom - i.e.
13109		 *   <ul>
13110		 *     <li>'l' - Length changing</li>
13111		 *     <li>'f' - Filtering input</li>
13112		 *     <li>'t' - The table!</li>
13113		 *     <li>'i' - Information</li>
13114		 *     <li>'p' - Pagination</li>
13115		 *     <li>'r' - pRocessing</li>
13116		 *   </ul>
13117		 *  @type array
13118		 *  @default []
13119		 */
13120		"aanFeatures": [],
13121	
13122		/**
13123		 * Store data information - see {@link DataTable.models.oRow} for detailed
13124		 * information.
13125		 *  @type array
13126		 *  @default []
13127		 */
13128		"aoData": [],
13129	
13130		/**
13131		 * Array of indexes which are in the current display (after filtering etc)
13132		 *  @type array
13133		 *  @default []
13134		 */
13135		"aiDisplay": [],
13136	
13137		/**
13138		 * Array of indexes for display - no filtering
13139		 *  @type array
13140		 *  @default []
13141		 */
13142		"aiDisplayMaster": [],
13143	
13144		/**
13145		 * Map of row ids to data indexes
13146		 *  @type object
13147		 *  @default {}
13148		 */
13149		"aIds": {},
13150	
13151		/**
13152		 * Store information about each column that is in use
13153		 *  @type array
13154		 *  @default []
13155		 */
13156		"aoColumns": [],
13157	
13158		/**
13159		 * Store information about the table's header
13160		 *  @type array
13161		 *  @default []
13162		 */
13163		"aoHeader": [],
13164	
13165		/**
13166		 * Store information about the table's footer
13167		 *  @type array
13168		 *  @default []
13169		 */
13170		"aoFooter": [],
13171	
13172		/**
13173		 * Store the applied global search information in case we want to force a
13174		 * research or compare the old search to a new one.
13175		 * Note that this parameter will be set by the initialisation routine. To
13176		 * set a default use {@link DataTable.defaults}.
13177		 *  @namespace
13178		 *  @extends DataTable.models.oSearch
13179		 */
13180		"oPreviousSearch": {},
13181	
13182		/**
13183		 * Store the applied search for each column - see
13184		 * {@link DataTable.models.oSearch} for the format that is used for the
13185		 * filtering information for each column.
13186		 *  @type array
13187		 *  @default []
13188		 */
13189		"aoPreSearchCols": [],
13190	
13191		/**
13192		 * Sorting that is applied to the table. Note that the inner arrays are
13193		 * used in the following manner:
13194		 * <ul>
13195		 *   <li>Index 0 - column number</li>
13196		 *   <li>Index 1 - current sorting direction</li>
13197		 * </ul>
13198		 * Note that this parameter will be set by the initialisation routine. To
13199		 * set a default use {@link DataTable.defaults}.
13200		 *  @type array
13201		 *  @todo These inner arrays should really be objects
13202		 */
13203		"aaSorting": null,
13204	
13205		/**
13206		 * Sorting that is always applied to the table (i.e. prefixed in front of
13207		 * aaSorting).
13208		 * Note that this parameter will be set by the initialisation routine. To
13209		 * set a default use {@link DataTable.defaults}.
13210		 *  @type array
13211		 *  @default []
13212		 */
13213		"aaSortingFixed": [],
13214	
13215		/**
13216		 * Classes to use for the striping of a table.
13217		 * Note that this parameter will be set by the initialisation routine. To
13218		 * set a default use {@link DataTable.defaults}.
13219		 *  @type array
13220		 *  @default []
13221		 */
13222		"asStripeClasses": null,
13223	
13224		/**
13225		 * If restoring a table - we should restore its striping classes as well
13226		 *  @type array
13227		 *  @default []
13228		 */
13229		"asDestroyStripes": [],
13230	
13231		/**
13232		 * If restoring a table - we should restore its width
13233		 *  @type int
13234		 *  @default 0
13235		 */
13236		"sDestroyWidth": 0,
13237	
13238		/**
13239		 * Callback functions array for every time a row is inserted (i.e. on a draw).
13240		 *  @type array
13241		 *  @default []
13242		 */
13243		"aoRowCallback": [],
13244	
13245		/**
13246		 * Callback functions for the header on each draw.
13247		 *  @type array
13248		 *  @default []
13249		 */
13250		"aoHeaderCallback": [],
13251	
13252		/**
13253		 * Callback function for the footer on each draw.
13254		 *  @type array
13255		 *  @default []
13256		 */
13257		"aoFooterCallback": [],
13258	
13259		/**
13260		 * Array of callback functions for draw callback functions
13261		 *  @type array
13262		 *  @default []
13263		 */
13264		"aoDrawCallback": [],
13265	
13266		/**
13267		 * Array of callback functions for row created function
13268		 *  @type array
13269		 *  @default []
13270		 */
13271		"aoRowCreatedCallback": [],
13272	
13273		/**
13274		 * Callback functions for just before the table is redrawn. A return of
13275		 * false will be used to cancel the draw.
13276		 *  @type array
13277		 *  @default []
13278		 */
13279		"aoPreDrawCallback": [],
13280	
13281		/**
13282		 * Callback functions for when the table has been initialised.
13283		 *  @type array
13284		 *  @default []
13285		 */
13286		"aoInitComplete": [],
13287	
13288	
13289		/**
13290		 * Callbacks for modifying the settings to be stored for state saving, prior to
13291		 * saving state.
13292		 *  @type array
13293		 *  @default []
13294		 */
13295		"aoStateSaveParams": [],
13296	
13297		/**
13298		 * Callbacks for modifying the settings that have been stored for state saving
13299		 * prior to using the stored values to restore the state.
13300		 *  @type array
13301		 *  @default []
13302		 */
13303		"aoStateLoadParams": [],
13304	
13305		/**
13306		 * Callbacks for operating on the settings object once the saved state has been
13307		 * loaded
13308		 *  @type array
13309		 *  @default []
13310		 */
13311		"aoStateLoaded": [],
13312	
13313		/**
13314		 * Cache the table ID for quick access
13315		 *  @type string
13316		 *  @default <i>Empty string</i>
13317		 */
13318		"sTableId": "",
13319	
13320		/**
13321		 * The TABLE node for the main table
13322		 *  @type node
13323		 *  @default null
13324		 */
13325		"nTable": null,
13326	
13327		/**
13328		 * Permanent ref to the thead element
13329		 *  @type node
13330		 *  @default null
13331		 */
13332		"nTHead": null,
13333	
13334		/**
13335		 * Permanent ref to the tfoot element - if it exists
13336		 *  @type node
13337		 *  @default null
13338		 */
13339		"nTFoot": null,
13340	
13341		/**
13342		 * Permanent ref to the tbody element
13343		 *  @type node
13344		 *  @default null
13345		 */
13346		"nTBody": null,
13347	
13348		/**
13349		 * Cache the wrapper node (contains all DataTables controlled elements)
13350		 *  @type node
13351		 *  @default null
13352		 */
13353		"nTableWrapper": null,
13354	
13355		/**
13356		 * Indicate if when using server-side processing the loading of data
13357		 * should be deferred until the second draw.
13358		 * Note that this parameter will be set by the initialisation routine. To
13359		 * set a default use {@link DataTable.defaults}.
13360		 *  @type boolean
13361		 *  @default false
13362		 */
13363		"bDeferLoading": false,
13364	
13365		/**
13366		 * Indicate if all required information has been read in
13367		 *  @type boolean
13368		 *  @default false
13369		 */
13370		"bInitialised": false,
13371	
13372		/**
13373		 * Information about open rows. Each object in the array has the parameters
13374		 * 'nTr' and 'nParent'
13375		 *  @type array
13376		 *  @default []
13377		 */
13378		"aoOpenRows": [],
13379	
13380		/**
13381		 * Dictate the positioning of DataTables' control elements - see
13382		 * {@link DataTable.model.oInit.sDom}.
13383		 * Note that this parameter will be set by the initialisation routine. To
13384		 * set a default use {@link DataTable.defaults}.
13385		 *  @type string
13386		 *  @default null
13387		 */
13388		"sDom": null,
13389	
13390		/**
13391		 * Search delay (in mS)
13392		 *  @type integer
13393		 *  @default null
13394		 */
13395		"searchDelay": null,
13396	
13397		/**
13398		 * Which type of pagination should be used.
13399		 * Note that this parameter will be set by the initialisation routine. To
13400		 * set a default use {@link DataTable.defaults}.
13401		 *  @type string
13402		 *  @default two_button
13403		 */
13404		"sPaginationType": "two_button",
13405	
13406		/**
13407		 * The state duration (for `stateSave`) in seconds.
13408		 * Note that this parameter will be set by the initialisation routine. To
13409		 * set a default use {@link DataTable.defaults}.
13410		 *  @type int
13411		 *  @default 0
13412		 */
13413		"iStateDuration": 0,
13414	
13415		/**
13416		 * Array of callback functions for state saving. Each array element is an
13417		 * object with the following parameters:
13418		 *   <ul>
13419		 *     <li>function:fn - function to call. Takes two parameters, oSettings
13420		 *       and the JSON string to save that has been thus far created. Returns
13421		 *       a JSON string to be inserted into a json object
13422		 *       (i.e. '"param": [ 0, 1, 2]')</li>
13423		 *     <li>string:sName - name of callback</li>
13424		 *   </ul>
13425		 *  @type array
13426		 *  @default []
13427		 */
13428		"aoStateSave": [],
13429	
13430		/**
13431		 * Array of callback functions for state loading. Each array element is an
13432		 * object with the following parameters:
13433		 *   <ul>
13434		 *     <li>function:fn - function to call. Takes two parameters, oSettings
13435		 *       and the object stored. May return false to cancel state loading</li>
13436		 *     <li>string:sName - name of callback</li>
13437		 *   </ul>
13438		 *  @type array
13439		 *  @default []
13440		 */
13441		"aoStateLoad": [],
13442	
13443		/**
13444		 * State that was saved. Useful for back reference
13445		 *  @type object
13446		 *  @default null
13447		 */
13448		"oSavedState": null,
13449	
13450		/**
13451		 * State that was loaded. Useful for back reference
13452		 *  @type object
13453		 *  @default null
13454		 */
13455		"oLoadedState": null,
13456	
13457		/**
13458		 * Source url for AJAX data for the table.
13459		 * Note that this parameter will be set by the initialisation routine. To
13460		 * set a default use {@link DataTable.defaults}.
13461		 *  @type string
13462		 *  @default null
13463		 */
13464		"sAjaxSource": null,
13465	
13466		/**
13467		 * Property from a given object from which to read the table data from. This
13468		 * can be an empty string (when not server-side processing), in which case
13469		 * it is  assumed an an array is given directly.
13470		 * Note that this parameter will be set by the initialisation routine. To
13471		 * set a default use {@link DataTable.defaults}.
13472		 *  @type string
13473		 */
13474		"sAjaxDataProp": null,
13475	
13476		/**
13477		 * Note if draw should be blocked while getting data
13478		 *  @type boolean
13479		 *  @default true
13480		 */
13481		"bAjaxDataGet": true,
13482	
13483		/**
13484		 * The last jQuery XHR object that was used for server-side data gathering.
13485		 * This can be used for working with the XHR information in one of the
13486		 * callbacks
13487		 *  @type object
13488		 *  @default null
13489		 */
13490		"jqXHR": null,
13491	
13492		/**
13493		 * JSON returned from the server in the last Ajax request
13494		 *  @type object
13495		 *  @default undefined
13496		 */
13497		"json": undefined,
13498	
13499		/**
13500		 * Data submitted as part of the last Ajax request
13501		 *  @type object
13502		 *  @default undefined
13503		 */
13504		"oAjaxData": undefined,
13505	
13506		/**
13507		 * Function to get the server-side data.
13508		 * Note that this parameter will be set by the initialisation routine. To
13509		 * set a default use {@link DataTable.defaults}.
13510		 *  @type function
13511		 */
13512		"fnServerData": null,
13513	
13514		/**
13515		 * Functions which are called prior to sending an Ajax request so extra
13516		 * parameters can easily be sent to the server
13517		 *  @type array
13518		 *  @default []
13519		 */
13520		"aoServerParams": [],
13521	
13522		/**
13523		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13524		 * required).
13525		 * Note that this parameter will be set by the initialisation routine. To
13526		 * set a default use {@link DataTable.defaults}.
13527		 *  @type string
13528		 */
13529		"sServerMethod": null,
13530	
13531		/**
13532		 * Format numbers for display.
13533		 * Note that this parameter will be set by the initialisation routine. To
13534		 * set a default use {@link DataTable.defaults}.
13535		 *  @type function
13536		 */
13537		"fnFormatNumber": null,
13538	
13539		/**
13540		 * List of options that can be used for the user selectable length menu.
13541		 * Note that this parameter will be set by the initialisation routine. To
13542		 * set a default use {@link DataTable.defaults}.
13543		 *  @type array
13544		 *  @default []
13545		 */
13546		"aLengthMenu": null,
13547	
13548		/**
13549		 * Counter for the draws that the table does. Also used as a tracker for
13550		 * server-side processing
13551		 *  @type int
13552		 *  @default 0
13553		 */
13554		"iDraw": 0,
13555	
13556		/**
13557		 * Indicate if a redraw is being done - useful for Ajax
13558		 *  @type boolean
13559		 *  @default false
13560		 */
13561		"bDrawing": false,
13562	
13563		/**
13564		 * Draw index (iDraw) of the last error when parsing the returned data
13565		 *  @type int
13566		 *  @default -1
13567		 */
13568		"iDrawError": -1,
13569	
13570		/**
13571		 * Paging display length
13572		 *  @type int
13573		 *  @default 10
13574		 */
13575		"_iDisplayLength": 10,
13576	
13577		/**
13578		 * Paging start point - aiDisplay index
13579		 *  @type int
13580		 *  @default 0
13581		 */
13582		"_iDisplayStart": 0,
13583	
13584		/**
13585		 * Server-side processing - number of records in the result set
13586		 * (i.e. before filtering), Use fnRecordsTotal rather than
13587		 * this property to get the value of the number of records, regardless of
13588		 * the server-side processing setting.
13589		 *  @type int
13590		 *  @default 0
13591		 *  @private
13592		 */
13593		"_iRecordsTotal": 0,
13594	
13595		/**
13596		 * Server-side processing - number of records in the current display set
13597		 * (i.e. after filtering). Use fnRecordsDisplay rather than
13598		 * this property to get the value of the number of records, regardless of
13599		 * the server-side processing setting.
13600		 *  @type boolean
13601		 *  @default 0
13602		 *  @private
13603		 */
13604		"_iRecordsDisplay": 0,
13605	
13606		/**
13607		 * Flag to indicate if jQuery UI marking and classes should be used.
13608		 * Note that this parameter will be set by the initialisation routine. To
13609		 * set a default use {@link DataTable.defaults}.
13610		 *  @type boolean
13611		 */
13612		"bJUI": null,
13613	
13614		/**
13615		 * The classes to use for the table
13616		 *  @type object
13617		 *  @default {}
13618		 */
13619		"oClasses": {},
13620	
13621		/**
13622		 * Flag attached to the settings object so you can check in the draw
13623		 * callback if filtering has been done in the draw. Deprecated in favour of
13624		 * events.
13625		 *  @type boolean
13626		 *  @default false
13627		 *  @deprecated
13628		 */
13629		"bFiltered": false,
13630	
13631		/**
13632		 * Flag attached to the settings object so you can check in the draw
13633		 * callback if sorting has been done in the draw. Deprecated in favour of
13634		 * events.
13635		 *  @type boolean
13636		 *  @default false
13637		 *  @deprecated
13638		 */
13639		"bSorted": false,
13640	
13641		/**
13642		 * Indicate that if multiple rows are in the header and there is more than
13643		 * one unique cell per column, if the top one (true) or bottom one (false)
13644		 * should be used for sorting / title by DataTables.
13645		 * Note that this parameter will be set by the initialisation routine. To
13646		 * set a default use {@link DataTable.defaults}.
13647		 *  @type boolean
13648		 */
13649		"bSortCellsTop": null,
13650	
13651		/**
13652		 * Initialisation object that is used for the table
13653		 *  @type object
13654		 *  @default null
13655		 */
13656		"oInit": null,
13657	
13658		/**
13659		 * Destroy callback functions - for plug-ins to attach themselves to the
13660		 * destroy so they can clean up markup and events.
13661		 *  @type array
13662		 *  @default []
13663		 */
13664		"aoDestroyCallback": [],
13665	
13666	
13667		/**
13668		 * Get the number of records in the current record set, before filtering
13669		 *  @type function
13670		 */
13671		"fnRecordsTotal": function ()
13672		{
13673			return _fnDataSource( this ) == 'ssp' ?
13674				this._iRecordsTotal * 1 :
13675				this.aiDisplayMaster.length;
13676		},
13677	
13678		/**
13679		 * Get the number of records in the current record set, after filtering
13680		 *  @type function
13681		 */
13682		"fnRecordsDisplay": function ()
13683		{
13684			return _fnDataSource( this ) == 'ssp' ?
13685				this._iRecordsDisplay * 1 :
13686				this.aiDisplay.length;
13687		},
13688	
13689		/**
13690		 * Get the display end point - aiDisplay index
13691		 *  @type function
13692		 */
13693		"fnDisplayEnd": function ()
13694		{
13695			var
13696				len      = this._iDisplayLength,
13697				start    = this._iDisplayStart,
13698				calc     = start + len,
13699				records  = this.aiDisplay.length,
13700				features = this.oFeatures,
13701				paginate = features.bPaginate;
13702	
13703			if ( features.bServerSide ) {
13704				return paginate === false || len === -1 ?
13705					start + records :
13706					Math.min( start+len, this._iRecordsDisplay );
13707			}
13708			else {
13709				return ! paginate || calc>records || len===-1 ?
13710					records :
13711					calc;
13712			}
13713		},
13714	
13715		/**
13716		 * The DataTables object for this table
13717		 *  @type object
13718		 *  @default null
13719		 */
13720		"oInstance": null,
13721	
13722		/**
13723		 * Unique identifier for each instance of the DataTables object. If there
13724		 * is an ID on the table node, then it takes that value, otherwise an
13725		 * incrementing internal counter is used.
13726		 *  @type string
13727		 *  @default null
13728		 */
13729		"sInstance": null,
13730	
13731		/**
13732		 * tabindex attribute value that is added to DataTables control elements, allowing
13733		 * keyboard navigation of the table and its controls.
13734		 */
13735		"iTabIndex": 0,
13736	
13737		/**
13738		 * DIV container for the footer scrolling table if scrolling
13739		 */
13740		"nScrollHead": null,
13741	
13742		/**
13743		 * DIV container for the footer scrolling table if scrolling
13744		 */
13745		"nScrollFoot": null,
13746	
13747		/**
13748		 * Last applied sort
13749		 *  @type array
13750		 *  @default []
13751		 */
13752		"aLastSort": [],
13753	
13754		/**
13755		 * Stored plug-in instances
13756		 *  @type object
13757		 *  @default {}
13758		 */
13759		"oPlugins": {},
13760	
13761		/**
13762		 * Function used to get a row's id from the row's data
13763		 *  @type function
13764		 *  @default null
13765		 */
13766		"rowIdFn": null,
13767	
13768		/**
13769		 * Data location where to store a row's id
13770		 *  @type string
13771		 *  @default null
13772		 */
13773		"rowId": null
13774	};
13775
13776	/**
13777	 * Extension object for DataTables that is used to provide all extension
13778	 * options.
13779	 *
13780	 * Note that the `DataTable.ext` object is available through
13781	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13782	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13783	 *  @namespace
13784	 *  @extends DataTable.models.ext
13785	 */
13786	
13787	
13788	/**
13789	 * DataTables extensions
13790	 * 
13791	 * This namespace acts as a collection area for plug-ins that can be used to
13792	 * extend DataTables capabilities. Indeed many of the build in methods
13793	 * use this method to provide their own capabilities (sorting methods for
13794	 * example).
13795	 *
13796	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13797	 * reasons
13798	 *
13799	 *  @namespace
13800	 */
13801	DataTable.ext = _ext = {
13802		/**
13803		 * Buttons. For use with the Buttons extension for DataTables. This is
13804		 * defined here so other extensions can define buttons regardless of load
13805		 * order. It is _not_ used by DataTables core.
13806		 *
13807		 *  @type object
13808		 *  @default {}
13809		 */
13810		buttons: {},
13811	
13812	
13813		/**
13814		 * Element class names
13815		 *
13816		 *  @type object
13817		 *  @default {}
13818		 */
13819		classes: {},
13820	
13821	
13822		/**
13823		 * DataTables build type (expanded by the download builder)
13824		 *
13825		 *  @type string
13826		 */
13827		build:"dt/dt-1.10.11,af-2.1.1,b-1.1.2,b-html5-1.1.2,fh-3.1.1",
13828	
13829	
13830		/**
13831		 * Error reporting.
13832		 * 
13833		 * How should DataTables report an error. Can take the value 'alert',
13834		 * 'throw', 'none' or a function.
13835		 *
13836		 *  @type string|function
13837		 *  @default alert
13838		 */
13839		errMode: "alert",
13840	
13841	
13842		/**
13843		 * Feature plug-ins.
13844		 * 
13845		 * This is an array of objects which describe the feature plug-ins that are
13846		 * available to DataTables. These feature plug-ins are then available for
13847		 * use through the `dom` initialisation option.
13848		 * 
13849		 * Each feature plug-in is described by an object which must have the
13850		 * following properties:
13851		 * 
13852		 * * `fnInit` - function that is used to initialise the plug-in,
13853		 * * `cFeature` - a character so the feature can be enabled by the `dom`
13854		 *   instillation option. This is case sensitive.
13855		 *
13856		 * The `fnInit` function has the following input parameters:
13857		 *
13858		 * 1. `{object}` DataTables settings object: see
13859		 *    {@link DataTable.models.oSettings}
13860		 *
13861		 * And the following return is expected:
13862		 * 
13863		 * * {node|null} The element which contains your feature. Note that the
13864		 *   return may also be void if your plug-in does not require to inject any
13865		 *   DOM elements into DataTables control (`dom`) - for example this might
13866		 *   be useful when developing a plug-in which allows table control via
13867		 *   keyboard entry
13868		 *
13869		 *  @type array
13870		 *
13871		 *  @example
13872		 *    $.fn.dataTable.ext.features.push( {
13873		 *      "fnInit": function( oSettings ) {
13874		 *        return new TableTools( { "oDTSettings": oSettings } );
13875		 *      },
13876		 *      "cFeature": "T"
13877		 *    } );
13878		 */
13879		feature: [],
13880	
13881	
13882		/**
13883		 * Row searching.
13884		 * 
13885		 * This method of searching is complimentary to the default type based
13886		 * searching, and a lot more comprehensive as it allows you complete control
13887		 * over the searching logic. Each element in this array is a function
13888		 * (parameters described below) that is called for every row in the table,
13889		 * and your logic decides if it should be included in the searching data set
13890		 * or not.
13891		 *
13892		 * Searching functions have the following input parameters:
13893		 *
13894		 * 1. `{object}` DataTables settings object: see
13895		 *    {@link DataTable.models.oSettings}
13896		 * 2. `{array|object}` Data for the row to be processed (same as the
13897		 *    original format that was passed in as the data source, or an array
13898		 *    from a DOM data source
13899		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13900		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
13901		 *
13902		 * And the following return is expected:
13903		 *
13904		 * * {boolean} Include the row in the searched result set (true) or not
13905		 *   (false)
13906		 *
13907		 * Note that as with the main search ability in DataTables, technically this
13908		 * is "filtering", since it is subtractive. However, for consistency in
13909		 * naming we call it searching here.
13910		 *
13911		 *  @type array
13912		 *  @default []
13913		 *
13914		 *  @example
13915		 *    // The following example shows custom search being applied to the
13916		 *    // fourth column (i.e. the data[3] index) based on two input values
13917		 *    // from the end-user, matching the data in a certain range.
13918		 *    $.fn.dataTable.ext.search.push(
13919		 *      function( settings, data, dataIndex ) {
13920		 *        var min = document.getElementById('min').value * 1;
13921		 *        var max = document.getElementById('max').value * 1;
13922		 *        var version = data[3] == "-" ? 0 : data[3]*1;
13923		 *
13924		 *        if ( min == "" && max == "" ) {
13925		 *          return true;
13926		 *        }
13927		 *        else if ( min == "" && version < max ) {
13928		 *          return true;
13929		 *        }
13930		 *        else if ( min < version && "" == max ) {
13931		 *          return true;
13932		 *        }
13933		 *        else if ( min < version && version < max ) {
13934		 *          return true;
13935		 *        }
13936		 *        return false;
13937		 *      }
13938		 *    );
13939		 */
13940		search: [],
13941	
13942	
13943		/**
13944		 * Selector extensions
13945		 *
13946		 * The `selector` option can be used to extend the options available for the
13947		 * selector modifier options (`selector-modifier` object data type) that
13948		 * each of the three built in selector types offer (row, column and cell +
13949		 * their plural counterparts). For example the Select extension uses this
13950		 * mechanism to provide an option to select only rows, columns and cells
13951		 * that have been marked as selected by the end user (`{selected: true}`),
13952		 * which can be used in conjunction with the existing built in selector
13953		 * options.
13954		 *
13955		 * Each property is an array to which functions can be pushed. The functions
13956		 * take three attributes:
13957		 *
13958		 * * Settings object for the host table
13959		 * * Options object (`selector-modifier` object type)
13960		 * * Array of selected item indexes
13961		 *
13962		 * The return is an array of the resulting item indexes after the custom
13963		 * selector has been applied.
13964		 *
13965		 *  @type object
13966		 */
13967		selector: {
13968			cell: [],
13969			column: [],
13970			row: []
13971		},
13972	
13973	
13974		/**
13975		 * Internal functions, exposed for used in plug-ins.
13976		 * 
13977		 * Please note that you should not need to use the internal methods for
13978		 * anything other than a plug-in (and even then, try to avoid if possible).
13979		 * The internal function may change between releases.
13980		 *
13981		 *  @type object
13982		 *  @default {}
13983		 */
13984		internal: {},
13985	
13986	
13987		/**
13988		 * Legacy configuration options. Enable and disable legacy options that
13989		 * are available in DataTables.
13990		 *
13991		 *  @type object
13992		 */
13993		legacy: {
13994			/**
13995			 * Enable / disable DataTables 1.9 compatible server-side processing
13996			 * requests
13997			 *
13998			 *  @type boolean
13999			 *  @default null
14000			 */
14001			ajax: null
14002		},
14003	
14004	
14005		/**
14006		 * Pagination plug-in methods.
14007		 * 
14008		 * Each entry in this object is a function and defines which buttons should
14009		 * be shown by the pagination rendering method that is used for the table:
14010		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14011		 * buttons are displayed in the document, while the functions here tell it
14012		 * what buttons to display. This is done by returning an array of button
14013		 * descriptions (what each button will do).
14014		 *
14015		 * Pagination types (the four built in options and any additional plug-in
14016		 * options defined here) can be used through the `paginationType`
14017		 * initialisation parameter.
14018		 *
14019		 * The functions defined take two parameters:
14020		 *
14021		 * 1. `{int} page` The current page index
14022		 * 2. `{int} pages` The number of pages in the table
14023		 *
14024		 * Each function is expected to return an array where each element of the
14025		 * array can be one of:
14026		 *
14027		 * * `first` - Jump to first page when activated
14028		 * * `last` - Jump to last page when activated
14029		 * * `previous` - Show previous page when activated
14030		 * * `next` - Show next page when activated
14031		 * * `{int}` - Show page of the index given
14032		 * * `{array}` - A nested array containing the above elements to add a
14033		 *   containing 'DIV' element (might be useful for styling).
14034		 *
14035		 * Note that DataTables v1.9- used this object slightly differently whereby
14036		 * an object with two functions would be defined for each plug-in. That
14037		 * ability is still supported by DataTables 1.10+ to provide backwards
14038		 * compatibility, but this option of use is now decremented and no longer
14039		 * documented in DataTables 1.10+.
14040		 *
14041		 *  @type object
14042		 *  @default {}
14043		 *
14044		 *  @example
14045		 *    // Show previous, next and current page buttons only
14046		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14047		 *      return [ 'previous', page, 'next' ];
14048		 *    };
14049		 */
14050		pager: {},
14051	
14052	
14053		renderer: {
14054			pageButton: {},
14055			header: {}
14056		},
14057	
14058	
14059		/**
14060		 * Ordering plug-ins - custom data source
14061		 * 
14062		 * The extension options for ordering of data available here is complimentary
14063		 * to the default type based ordering that DataTables typically uses. It
14064		 * allows much greater control over the the data that is being used to
14065		 * order a column, but is necessarily therefore more complex.
14066		 * 
14067		 * This type of ordering is useful if you want to do ordering based on data
14068		 * live from the DOM (for example the contents of an 'input' element) rather
14069		 * than just the static string that DataTables knows of.
14070		 * 
14071		 * The way these plug-ins work is that you create an array of the values you
14072		 * wish to be ordering for the column in question and then return that
14073		 * array. The data in the array much be in the index order of the rows in
14074		 * the table (not the currently ordering order!). Which order data gathering
14075		 * function is run here depends on the `dt-init columns.orderDataType`
14076		 * parameter that is used for the column (if any).
14077		 *
14078		 * The functions defined take two parameters:
14079		 *
14080		 * 1. `{object}` DataTables settings object: see
14081		 *    {@link DataTable.models.oSettings}
14082		 * 2. `{int}` Target column index
14083		 *
14084		 * Each function is expected to return an array:
14085		 *
14086		 * * `{array}` Data for the column to be ordering upon
14087		 *
14088		 *  @type array
14089		 *
14090		 *  @example
14091		 *    // Ordering using `input` node values
14092		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
14093		 *    {
14094		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14095		 *        return $('input', td).val();
14096		 *      } );
14097		 *    }
14098		 */
14099		order: {},
14100	
14101	
14102		/**
14103		 * Type based plug-ins.
14104		 *
14105		 * Each column in DataTables has a type assigned to it, either by automatic
14106		 * detection or by direct assignment using the `type` option for the column.
14107		 * The type of a column will effect how it is ordering and search (plug-ins
14108		 * can also make use of the column type if required).
14109		 *
14110		 * @namespace
14111		 */
14112		type: {
14113			/**
14114			 * Type detection functions.
14115			 *
14116			 * The functions defined in this object are used to automatically detect
14117			 * a column's type, making initialisation of DataTables super easy, even
14118			 * when complex data is in the table.
14119			 *
14120			 * The functions defined take two parameters:
14121			 *
14122		     *  1. `{*}` Data from the column cell to be analysed
14123		     *  2. `{settings}` DataTables settings object. This can be used to
14124		     *     perform context specific type detection - for example detection
14125		     *     based on language settings such as using a comma for a decimal
14126		     *     place. Generally speaking the options from the settings will not
14127		     *     be required
14128			 *
14129			 * Each function is expected to return:
14130			 *
14131			 * * `{string|null}` Data type detected, or null if unknown (and thus
14132			 *   pass it on to the other type detection functions.
14133			 *
14134			 *  @type array
14135			 *
14136			 *  @example
14137			 *    // Currency type detection plug-in:
14138			 *    $.fn.dataTable.ext.type.detect.push(
14139			 *      function ( data, settings ) {
14140			 *        // Check the numeric part
14141			 *        if ( ! $.isNumeric( data.substring(1) ) ) {
14142			 *          return null;
14143			 *        }
14144			 *
14145			 *        // Check prefixed by currency
14146			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14147			 *          return 'currency';
14148			 *        }
14149			 *        return null;
14150			 *      }
14151			 *    );
14152			 */
14153			detect: [],
14154	
14155	
14156			/**
14157			 * Type based search formatting.
14158			 *
14159			 * The type based searching functions can be used to pre-format the
14160			 * data to be search on. For example, it can be used to strip HTML
14161			 * tags or to de-format telephone numbers for numeric only searching.
14162			 *
14163			 * Note that is a search is not defined for a column of a given type,
14164			 * no search formatting will be performed.
14165			 * 
14166			 * Pre-processing of searching data plug-ins - When you assign the sType
14167			 * for a column (or have it automatically detected for you by DataTables
14168			 * or a type detection plug-in), you will typically be using this for
14169			 * custom sorting, but it can also be used to provide custom searching
14170			 * by allowing you to pre-processing the data and returning the data in
14171			 * the format that should be searched upon. This is done by adding
14172			 * functions this object with a parameter name which matches the sType
14173			 * for that target column. This is the corollary of <i>afnSortData</i>
14174			 * for searching data.
14175			 *
14176			 * The functions defined take a single parameter:
14177			 *
14178		     *  1. `{*}` Data from the column cell to be prepared for searching
14179			 *
14180			 * Each function is expected to return:
14181			 *
14182			 * * `{string|null}` Formatted string that will be used for the searching.
14183			 *
14184			 *  @type object
14185			 *  @default {}
14186			 *
14187			 *  @example
14188			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14189			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14190			 *    }
14191			 */
14192			search: {},
14193	
14194	
14195			/**
14196			 * Type based ordering.
14197			 *
14198			 * The column type tells DataTables what ordering to apply to the table
14199			 * when a column is sorted upon. The order for each type that is defined,
14200			 * is defined by the functions available in this object.
14201			 *
14202			 * Each ordering option can be described by three properties added to
14203			 * this object:
14204			 *
14205			 * * `{type}-pre` - Pre-formatting function
14206			 * * `{type}-asc` - Ascending order function
14207			 * * `{type}-desc` - Descending order function
14208			 *
14209			 * All three can be used together, only `{type}-pre` or only
14210			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
14211			 * that only `{type}-pre` is used, as this provides the optimal
14212			 * implementation in terms of speed, although the others are provided
14213			 * for compatibility with existing Javascript sort functions.
14214			 *
14215			 * `{type}-pre`: Functions defined take a single parameter:
14216			 *
14217		     *  1. `{*}` Data from the column cell to be prepared for ordering
14218			 *
14219			 * And return:
14220			 *
14221			 * * `{*}` Data to be sorted upon
14222			 *
14223			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14224			 * functions, taking two parameters:
14225			 *
14226		     *  1. `{*}` Data to compare to the second parameter
14227		     *  2. `{*}` Data to compare to the first parameter
14228			 *
14229			 * And returning:
14230			 *
14231			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14232			 *   than the second parameter, ===0 if the two parameters are equal and
14233			 *   >0 if the first parameter should be sorted height than the second
14234			 *   parameter.
14235			 * 
14236			 *  @type object
14237			 *  @default {}
14238			 *
14239			 *  @example
14240			 *    // Numeric ordering of formatted numbers with a pre-formatter
14241			 *    $.extend( $.fn.dataTable.ext.type.order, {
14242			 *      "string-pre": function(x) {
14243			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14244			 *        return parseFloat( a );
14245			 *      }
14246			 *    } );
14247			 *
14248			 *  @example
14249			 *    // Case-sensitive string ordering, with no pre-formatting method
14250			 *    $.extend( $.fn.dataTable.ext.order, {
14251			 *      "string-case-asc": function(x,y) {
14252			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14253			 *      },
14254			 *      "string-case-desc": function(x,y) {
14255			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14256			 *      }
14257			 *    } );
14258			 */
14259			order: {}
14260		},
14261	
14262		/**
14263		 * Unique DataTables instance counter
14264		 *
14265		 * @type int
14266		 * @private
14267		 */
14268		_unique: 0,
14269	
14270	
14271		//
14272		// Depreciated
14273		// The following properties are retained for backwards compatiblity only.
14274		// The should not be used in new projects and will be removed in a future
14275		// version
14276		//
14277	
14278		/**
14279		 * Version check function.
14280		 *  @type function
14281		 *  @depreciated Since 1.10
14282		 */
14283		fnVersionCheck: DataTable.fnVersionCheck,
14284	
14285	
14286		/**
14287		 * Index for what 'this' index API functions should use
14288		 *  @type int
14289		 *  @deprecated Since v1.10
14290		 */
14291		iApiIndex: 0,
14292	
14293	
14294		/**
14295		 * jQuery UI class container
14296		 *  @type object
14297		 *  @deprecated Since v1.10
14298		 */
14299		oJUIClasses: {},
14300	
14301	
14302		/**
14303		 * Software version
14304		 *  @type string
14305		 *  @deprecated Since v1.10
14306		 */
14307		sVersion: DataTable.version
14308	};
14309	
14310	
14311	//
14312	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14313	//
14314	$.extend( _ext, {
14315		afnFiltering: _ext.search,
14316		aTypes:       _ext.type.detect,
14317		ofnSearch:    _ext.type.search,
14318		oSort:        _ext.type.order,
14319		afnSortData:  _ext.order,
14320		aoFeatures:   _ext.feature,
14321		oApi:         _ext.internal,
14322		oStdClasses:  _ext.classes,
14323		oPagination:  _ext.pager
14324	} );
14325	
14326	
14327	$.extend( DataTable.ext.classes, {
14328		"sTable": "dataTable",
14329		"sNoFooter": "no-footer",
14330	
14331		/* Paging buttons */
14332		"sPageButton": "paginate_button",
14333		"sPageButtonActive": "current",
14334		"sPageButtonDisabled": "disabled",
14335	
14336		/* Striping classes */
14337		"sStripeOdd": "odd",
14338		"sStripeEven": "even",
14339	
14340		/* Empty row */
14341		"sRowEmpty": "dataTables_empty",
14342	
14343		/* Features */
14344		"sWrapper": "dataTables_wrapper",
14345		"sFilter": "dataTables_filter",
14346		"sInfo": "dataTables_info",
14347		"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14348		"sLength": "dataTables_length",
14349		"sProcessing": "dataTables_processing",
14350	
14351		/* Sorting */
14352		"sSortAsc": "sorting_asc",
14353		"sSortDesc": "sorting_desc",
14354		"sSortable": "sorting", /* Sortable in both directions */
14355		"sSortableAsc": "sorting_asc_disabled",
14356		"sSortableDesc": "sorting_desc_disabled",
14357		"sSortableNone": "sorting_disabled",
14358		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14359	
14360		/* Filtering */
14361		"sFilterInput": "",
14362	
14363		/* Page length */
14364		"sLengthSelect": "",
14365	
14366		/* Scrolling */
14367		"sScrollWrapper": "dataTables_scroll",
14368		"sScrollHead": "dataTables_scrollHead",
14369		"sScrollHeadInner": "dataTables_scrollHeadInner",
14370		"sScrollBody": "dataTables_scrollBody",
14371		"sScrollFoot": "dataTables_scrollFoot",
14372		"sScrollFootInner": "dataTables_scrollFootInner",
14373	
14374		/* Misc */
14375		"sHeaderTH": "",
14376		"sFooterTH": "",
14377	
14378		// Deprecated
14379		"sSortJUIAsc": "",
14380		"sSortJUIDesc": "",
14381		"sSortJUI": "",
14382		"sSortJUIAscAllowed": "",
14383		"sSortJUIDescAllowed": "",
14384		"sSortJUIWrapper": "",
14385		"sSortIcon": "",
14386		"sJUIHeader": "",
14387		"sJUIFooter": ""
14388	} );
14389	
14390	
14391	(function() {
14392	
14393	// Reused strings for better compression. Closure compiler appears to have a
14394	// weird edge case where it is trying to expand strings rather than use the
14395	// variable version. This results in about 200 bytes being added, for very
14396	// little preference benefit since it this run on script load only.
14397	var _empty = '';
14398	_empty = '';
14399	
14400	var _stateDefault = _empty + 'ui-state-default';
14401	var _sortIcon     = _empty + 'css_right ui-icon ui-icon-';
14402	var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
14403	
14404	$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
14405		/* Full numbers paging buttons */
14406		"sPageButton":         "fg-button ui-button "+_stateDefault,
14407		"sPageButtonActive":   "ui-state-disabled",
14408		"sPageButtonDisabled": "ui-state-disabled",
14409	
14410		/* Features */
14411		"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
14412			"ui-buttonset-multi paging_", /* Note that the type is postfixed */
14413	
14414		/* Sorting */
14415		"sSortAsc":            _stateDefault+" sorting_asc",
14416		"sSortDesc":           _stateDefault+" sorting_desc",
14417		"sSortable":           _stateDefault+" sorting",
14418		"sSortableAsc":        _stateDefault+" sorting_asc_disabled",
14419		"sSortableDesc":       _stateDefault+" sorting_desc_disabled",
14420		"sSortableNone":       _stateDefault+" sorting_disabled",
14421		"sSortJUIAsc":         _sortIcon+"triangle-1-n",
14422		"sSortJUIDesc":        _sortIcon+"triangle-1-s",
14423		"sSortJUI":            _sortIcon+"carat-2-n-s",
14424		"sSortJUIAscAllowed":  _sortIcon+"carat-1-n",
14425		"sSortJUIDescAllowed": _sortIcon+"carat-1-s",
14426		"sSortJUIWrapper":     "DataTables_sort_wrapper",
14427		"sSortIcon":           "DataTables_sort_icon",
14428	
14429		/* Scrolling */
14430		"sScrollHead": "dataTables_scrollHead "+_stateDefault,
14431		"sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
14432	
14433		/* Misc */
14434		"sHeaderTH":  _stateDefault,
14435		"sFooterTH":  _stateDefault,
14436		"sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
14437		"sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
14438	} );
14439	
14440	}());
14441	
14442	
14443	
14444	var extPagination = DataTable.ext.pager;
14445	
14446	function _numbers ( page, pages ) {
14447		var
14448			numbers = [],
14449			buttons = extPagination.numbers_length,
14450			half = Math.floor( buttons / 2 ),
14451			i = 1;
14452	
14453		if ( pages <= buttons ) {
14454			numbers = _range( 0, pages );
14455		}
14456		else if ( page <= half ) {
14457			numbers = _range( 0, buttons-2 );
14458			numbers.push( 'ellipsis' );
14459			numbers.push( pages-1 );
14460		}
14461		else if ( page >= pages - 1 - half ) {
14462			numbers = _range( pages-(buttons-2), pages );
14463			numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14464			numbers.splice( 0, 0, 0 );
14465		}
14466		else {
14467			numbers = _range( page-half+2, page+half-1 );
14468			numbers.push( 'ellipsis' );
14469			numbers.push( pages-1 );
14470			numbers.splice( 0, 0, 'ellipsis' );
14471			numbers.splice( 0, 0, 0 );
14472		}
14473	
14474		numbers.DT_el = 'span';
14475		return numbers;
14476	}
14477	
14478	
14479	$.extend( extPagination, {
14480		simple: function ( page, pages ) {
14481			return [ 'previous', 'next' ];
14482		},
14483	
14484		full: function ( page, pages ) {
14485			return [  'first', 'previous', 'next', 'last' ];
14486		},
14487	
14488		numbers: function ( page, pages ) {
14489			return [ _numbers(page, pages) ];
14490		},
14491	
14492		simple_numbers: function ( page, pages ) {
14493			return [ 'previous', _numbers(page, pages), 'next' ];
14494		},
14495	
14496		full_numbers: function ( page, pages ) {
14497			return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14498		},
14499	
14500		// For testing and plug-ins to use
14501		_numbers: _numbers,
14502	
14503		// Number of number buttons (including ellipsis) to show. _Must be odd!_
14504		numbers_length: 7
14505	} );
14506	
14507	
14508	$.extend( true, DataTable.ext.renderer, {
14509		pageButton: {
14510			_: function ( settings, host, idx, buttons, page, pages ) {
14511				var classes = settings.oClasses;
14512				var lang = settings.oLanguage.oPaginate;
14513				var aria = settings.oLanguage.oAria.paginate || {};
14514				var btnDisplay, btnClass, counter=0;
14515	
14516				var attach = function( container, buttons ) {
14517					var i, ien, node, button;
14518					var clickHandler = function ( e ) {
14519						_fnPageChange( settings, e.data.action, true );
14520					};
14521	
14522					for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14523						button = buttons[i];
14524	
14525						if ( $.isArray( button ) ) {
14526							var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14527								.appendTo( container );
14528							attach( inner, button );
14529						}
14530						else {
14531							btnDisplay = null;
14532							btnClass = '';
14533	
14534							switch ( button ) {
14535								case 'ellipsis':
14536									container.append('<span class="ellipsis">&#x2026;
14536</span>');
14537									break;
14538	
14539								case 'first':
14540									btnDisplay = lang.sFirst;
14541									btnClass = button + (page > 0 ?
14542										'' : ' '+classes.sPageButtonDisabled);
14543									break;
14544	
14545								case 'previous':
14546									btnDisplay = lang.sPrevious;
14547									btnClass = button + (page > 0 ?
14548										'' : ' '+classes.sPageButtonDisabled);
14549									break;
14550	
14551								case 'next':
14552									btnDisplay = lang.sNext;
14553									btnClass = button + (page < pages-1 ?
14554										'' : ' '+classes.sPageButtonDisabled);
14555									break;
14556	
14557								case 'last':
14558									btnDisplay = lang.sLast;
14559									btnClass = button + (page < pages-1 ?
14560										'' : ' '+classes.sPageButtonDisabled);
14561									break;
14562	
14563								default:
14564									btnDisplay = button + 1;
14565									btnClass = page === button ?
14566										classes.sPageButtonActive : '';
14567									break;
14568							}
14569	
14570							if ( btnDisplay !== null ) {
14571								node = $('<a>', {
14572										'class': classes.sPageButton+' '+btnClass,
14573										'aria-controls': settings.sTableId,
14574										'aria-label': aria[ button ],
14575										'data-dt-idx': counter,
14576										'tabindex': settings.iTabIndex,
14577										'id': idx === 0 && typeof button === 'string' ?
14578											settings.sTableId +'_'+ button :
14579											null
14580									} )
14581									.html( btnDisplay )
14582									.appendTo( container );
14583	
14584								_fnBindAction(
14585									node, {action: button}, clickHandler
14586								);
14587	
14588								counter++;
14589							}
14590						}
14591					}
14592				};
14593	
14594				// IE9 throws an 'unknown error' if document.activeElement is used
14595				// inside an iframe or frame. Try / catch the error. Not good for
14596				// accessibility, but neither are frames.
14597				var activeEl;
14598	
14599				try {
14600					// Because this approach is destroying and recreating the paging
14601					// elements, focus is lost on the select button which is bad for
14602					// accessibility. So we want to restore focus once the draw has
14603					// completed
14604					activeEl = $(host).find(document.activeElement).data('dt-idx');
14605				}
14606				catch (e) {}
14607	
14608				attach( $(host).empty(), buttons );
14609	
14610				if ( activeEl ) {
14611					$(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14612				}
14613			}
14614		}
14615	} );
14616	
14617	
14618	
14619	// Built in type detection. See model.ext.aTypes for information about
14620	// what is required from this methods.
14621	$.extend( DataTable.ext.type.detect, [
14622		// Plain numbers - first since V8 detects some plain numbers as dates
14623		// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14624		function ( d, settings )
14625		{
14626			var decimal = settings.oLanguage.sDecimal;
14627			return _isNumber( d, decimal ) ? 'num'+decimal : null;
14628		},
14629	
14630		// Dates (only those recognised by the browser's Date.parse)
14631		function ( d, settings )
14632		{
14633			// V8 will remove any unknown characters at the start and end of the
14634			// expression, leading to false matches such as `$245.12` or `10%` being
14635			// a valid date. See forum thread 18941 for detail.
14636			if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14637				return null;
14638			}
14639			var parsed = Date.parse(d);
14640			return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14641		},
14642	
14643		// Formatted numbers
14644		function ( d, settings )
14645		{
14646			var decimal = settings.oLanguage.sDecimal;
14647			return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14648		},
14649	
14650		// HTML numeric
14651		function ( d, settings )
14652		{
14653			var decimal = settings.oLanguage.sDecimal;
14654			return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14655		},
14656	
14657		// HTML numeric, formatted
14658		function ( d, settings )
14659		{
14660			var decimal = settings.oLanguage.sDecimal;
14661			return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14662		},
14663	
14664		// HTML (this is strict checking - there must be html)
14665		function ( d, settings )
14666		{
14667			return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14668				'html' : null;
14669		}
14670	] );
14671	
14672	
14673	
14674	// Filter formatting functions. See model.ext.ofnSearch for information about
14675	// what is required from these methods.
14676	// 
14677	// Note that additional search methods are added for the html numbers and
14678	// html formatted numbers by `_addNumericSort()` when we know what the decimal
14679	// place is
14680	
14681	
14682	$.extend( DataTable.ext.type.search, {
14683		html: function ( data ) {
14684			return _empty(data) ?
14685				data :
14686				typeof data === 'string' ?
14687					data
14688						.replace( _re_new_lines, " " )
14689						.replace( _re_html, "" ) :
14690					'';
14691		},
14692	
14693		string: function ( data ) {
14694			return _empty(data) ?
14695				data :
14696				typeof data === 'string' ?
14697					data.replace( _re_new_lines, " " ) :
14698					data;
14699		}
14700	} );
14701	
14702	
14703	
14704	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14705		if ( d !== 0 && (!d || d === '-') ) {
14706			return -Infinity;
14707		}
14708	
14709		// If a decimal place other than `.` is used, it needs to be given to the
14710		// function so we can detect it and replace with a `.` which is the only
14711		// decimal place Javascript recognises - it is not locale aware.
14712		if ( decimalPlace ) {
14713			d = _numToDecimal( d, decimalPlace );
14714		}
14715	
14716		if ( d.replace ) {
14717			if ( re1 ) {
14718				d = d.replace( re1, '' );
14719			}
14720	
14721			if ( re2 ) {
14722				d = d.replace( re2, '' );
14723			}
14724		}
14725	
14726		return d * 1;
14727	};
14728	
14729	
14730	// Add the numeric 'deformatting' functions for sorting and search. This is done
14731	// in a function to provide an easy ability for the language options to add
14732	// additional methods if a non-period decimal place is used.
14733	function _addNumericSort ( decimalPlace ) {
14734		$.each(
14735			{
14736				// Plain numbers
14737				"num": function ( d ) {
14738					return __numericReplace( d, decimalPlace );
14739				},
14740	
14741				// Formatted numbers
14742				"num-fmt": function ( d ) {
14743					return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14744				},
14745	
14746				// HTML numeric
14747				"html-num": function ( d ) {
14748					return __numericReplace( d, decimalPlace, _re_html );
14749				},
14750	
14751				// HTML numeric, formatted
14752				"html-num-fmt": function ( d ) {
14753					return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14754				}
14755			},
14756			function ( key, fn ) {
14757				// Add the ordering method
14758				_ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14759	
14760				// For HTML types add a search formatter that will strip the HTML
14761				if ( key.match(/^html\-/) ) {
14762					_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14763				}
14764			}
14765		);
14766	}
14767	
14768	
14769	// Default sort methods
14770	$.extend( _ext.type.order, {
14771		// Dates
14772		"date-pre": function ( d ) {
14773			return Date.parse( d ) || 0;
14774		},
14775	
14776		// html
14777		"html-pre": function ( a ) {
14778			return _empty(a) ?
14779				'' :
14780				a.replace ?
14781					a.replace( /<.*?>/g, "" ).toLowerCase() :
14782					a+'';
14783		},
14784	
14785		// string
14786		"string-pre": function ( a ) {
14787			// This is a little complex, but faster than always calling toString,
14788			// http://jsperf.com/tostring-v-check
14789			return _empty(a) ?
14790				'' :
14791				typeof a === 'string' ?
14792					a.toLowerCase() :
14793					! a.toString ?
14794						'' :
14795						a.toString();
14796		},
14797	
14798		// string-asc and -desc are retained only for compatibility with the old
14799		// sort methods
14800		"string-asc": function ( x, y ) {
14801			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14802		},
14803	
14804		"string-desc": function ( x, y ) {
14805			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14806		}
14807	} );
14808	
14809	
14810	// Numeric sorting types - order doesn't matter here
14811	_addNumericSort( '' );
14812	
14813	
14814	$.extend( true, DataTable.ext.renderer, {
14815		header: {
14816			_: function ( settings, cell, column, classes ) {
14817				// No additional mark-up required
14818				// Attach a sort listener to update on sort - note that using the
14819				// `DT` namespace will allow the event to be removed automatically
14820				// on destroy, while the `dt` namespaced event is the one we are
14821				// listening for
14822				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14823					if ( settings !== ctx ) { // need to check this this is the host
14824						return;               // table, not a nested one
14825					}
14826	
14827					var colIdx = column.idx;
14828	
14829					cell
14830						.removeClass(
14831							column.sSortingClass +' '+
14832							classes.sSortAsc +' '+
14833							classes.sSortDesc
14834						)
14835						.addClass( columns[ colIdx ] == 'asc' ?
14836							classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14837								classes.sSortDesc :
14838								column.sSortingClass
14839						);
14840				} );
14841			},
14842	
14843			jqueryui: function ( settings, cell, column, classes ) {
14844				$('<div/>')
14845					.addClass( classes.sSortJUIWrapper )
14846					.append( cell.contents() )
14847					.append( $('<span/>')
14848						.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14849					)
14850					.appendTo( cell );
14851	
14852				// Attach a sort listener to update on sort
14853				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14854					if ( settings !== ctx ) {
14855						return;
14856					}
14857	
14858					var colIdx = column.idx;
14859	
14860					cell
14861						.removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14862						.addClass( columns[ colIdx ] == 'asc' ?
14863							classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14864								classes.sSortDesc :
14865								column.sSortingClass
14866						);
14867	
14868					cell
14869						.find( 'span.'+classes.sSortIcon )
14870						.removeClass(
14871							classes.sSortJUIAsc +" "+
14872							classes.sSortJUIDesc +" "+
14873							classes.sSortJUI +" "+
14874							classes.sSortJUIAscAllowed +" "+
14875							classes.sSortJUIDescAllowed
14876						)
14877						.addClass( columns[ colIdx ] == 'asc' ?
14878							classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14879								classes.sSortJUIDesc :
14880								column.sSortingClassJUI
14881						);
14882				} );
14883			}
14884		}
14885	} );
14886	
14887	/*
14888	 * Public helper functions. These aren't used internally by DataTables, or
14889	 * called by any of the options passed into DataTables, but they can be used
14890	 * externally by developers working with DataTables. They are helper functions
14891	 * to make working with DataTables a little bit easier.
14892	 */
14893	
14894	var __htmlEscapeEntities = function ( d ) {
14895		return typeof d === 'string' ?
14896			d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14897			d;
14898	};
14899	
14900	/**
14901	 * Helpers for `columns.render`.
14902	 *
14903	 * The options defined here can be used with the `columns.render` initialisation
14904	 * option to provide a display renderer. The following functions are defined:
14905	 *
14906	 * * `number` - Will format numeric data (defined by `columns.data`) for
14907	 *   display, retaining the original unformatted data for sorting and filtering.
14908	 *   It takes 5 parameters:
14909	 *   * `string` - Thousands grouping separator
14910	 *   * `string` - Decimal point indicator
14911	 *   * `integer` - Number of decimal points to show
14912	 *   * `string` (optional) - Prefix.
14913	 *   * `string` (optional) - Postfix (/suffix).
14914	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14915	 *   parameters.
14916	 *
14917	 * @example
14918	 *   // Column definition using the number renderer
14919	 *   {
14920	 *     data: "salary",
14921	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14922	 *   }
14923	 *
14924	 * @namespace
14925	 */
14926	DataTable.render = {
14927		number: function ( thousands, decimal, precision, prefix, postfix ) {
14928			return {
14929				display: function ( d ) {
14930					if ( typeof d !== 'number' && typeof d !== 'string' ) {
14931						return d;
14932					}
14933	
14934					var negative = d < 0 ? '-' : '';
14935					var flo = parseFloat( d );
14936	
14937					// If NaN then there isn't much formatting that we can do - just
14938					// return immediately, escaping any HTML (this was supposed to
14939					// be a number after all)
14940					if ( isNaN( flo ) ) {
14941						return __htmlEscapeEntities( d );
14942					}
14943	
14944					d = Math.abs( flo );
14945	
14946					var intPart = parseInt( d, 10 );
14947					var floatPart = precision ?
14948						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14949						'';
14950	
14951					return negative + (prefix||'') +
14952						intPart.toString().replace(
14953							/\B(?=(\d{3})+(?!\d))/g, thousands
14954						) +
14955						floatPart +
14956						(postfix||'');
14957				}
14958			};
14959		},
14960	
14961		text: function () {
14962			return {
14963				display: __htmlEscapeEntities
14964			};
14965		}
14966	};
14967	
14968	
14969	/*
14970	 * This is really a good bit rubbish this method of exposing the internal methods
14971	 * publicly... - To be fixed in 2.0 using methods on the prototype
14972	 */
14973	
14974	
14975	/**
14976	 * Create a wrapper function for exporting an internal functions to an external API.
14977	 *  @param {string} fn API function name
14978	 *  @returns {function} wrapped function
14979	 *  @memberof DataTable#internal
14980	 */
14981	function _fnExternApiFunc (fn)
14982	{
14983		return function() {
14984			var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14985				Array.prototype.slice.call(arguments)
14986			);
14987			return DataTable.ext.internal[fn].apply( this, args );
14988		};
14989	}
14990	
14991	
14992	/**
14993	 * Reference to internal functions for use by plug-in developers. Note that
14994	 * these methods are references to internal functions and are considered to be
14995	 * private. If you use these methods, be aware that they are liable to change
14996	 * between versions.
14997	 *  @namespace
14998	 */
14999	$.extend( DataTable.ext.internal, {
15000		_fnExternApiFunc: _fnExternApiFunc,
15001		_fnBuildAjax: _fnBuildAjax,
15002		_fnAjaxUpdate: _fnAjaxUpdate,
15003		_fnAjaxParameters: _fnAjaxParameters,
15004		_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
15005		_fnAjaxDataSrc: _fnAjaxDataSrc,
15006		_fnAddColumn: _fnAddColumn,
15007		_fnColumnOptions: _fnColumnOptions,
15008		_fnAdjustColumnSizing: _fnAdjustColumnSizing,
15009		_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
15010		_fnColumnIndexToVisible: _fnColumnIndexToVisible,
15011		_fnVisbleColumns: _fnVisbleColumns,
15012		_fnGetColumns: _fnGetColumns,
15013		_fnColumnTypes: _fnColumnTypes,
15014		_fnApplyColumnDefs: _fnApplyColumnDefs,
15015		_fnHungarianMap: _fnHungarianMap,
15016		_fnCamelToHungarian: _fnCamelToHungarian,
15017		_fnLanguageCompat: _fnLanguageCompat,
15018		_fnBrowserDetect: _fnBrowserDetect,
15019		_fnAddData: _fnAddData,
15020		_fnAddTr: _fnAddTr,
15021		_fnNodeToDataIndex: _fnNodeToDataIndex,
15022		_fnNodeToColumnIndex: _fnNodeToColumnIndex,
15023		_fnGetCellData: _fnGetCellData,
15024		_fnSetCellData: _fnSetCellData,
15025		_fnSplitObjNotation: _fnSplitObjNotation,
15026		_fnGetObjectDataFn: _fnGetObjectDataFn,
15027		_fnSetObjectDataFn: _fnSetObjectDataFn,
15028		_fnGetDataMaster: _fnGetDataMaster,
15029		_fnClearTable: _fnClearTable,
15030		_fnDeleteIndex: _fnDeleteIndex,
15031		_fnInvalidate: _fnInvalidate,
15032		_fnGetRowElements: _fnGetRowElements,
15033		_fnCreateTr: _fnCreateTr,
15034		_fnBuildHead: _fnBuildHead,
15035		_fnDrawHead: _fnDrawHead,
15036		_fnDraw: _fnDraw,
15037		_fnReDraw: _fnReDraw,
15038		_fnAddOptionsHtml: _fnAddOptionsHtml,
15039		_fnDetectHeader: _fnDetectHeader,
15040		_fnGetUniqueThs: _fnGetUniqueThs,
15041		_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15042		_fnFilterComplete: _fnFilterComplete,
15043		_fnFilterCustom: _fnFilterCustom,
15044		_fnFilterColumn: _fnFilterColumn,
15045		_fnFilter: _fnFilter,
15046		_fnFilterCreateSearch: _fnFilterCreateSearch,
15047		_fnEscapeRegex: _fnEscapeRegex,
15048		_fnFilterData: _fnFilterData,
15049		_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15050		_fnUpdateInfo: _fnUpdateInfo,
15051		_fnInfoMacros: _fnInfoMacros,
15052		_fnInitialise: _fnInitialise,
15053		_fnInitComplete: _fnInitComplete,
15054		_fnLengthChange: _fnLengthChange,
15055		_fnFeatureHtmlLength: _fnFeatureHtmlLength,
15056		_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15057		_fnPageChange: _fnPageChange,
15058		_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15059		_fnProcessingDisplay: _fnProcessingDisplay,
15060		_fnFeatureHtmlTable: _fnFeatureHtmlTable,
15061		_fnScrollDraw: _fnScrollDraw,
15062		_fnApplyToChildren: _fnApplyToChildren,
15063		_fnCalculateColumnWidths: _fnCalculateColumnWidths,
15064		_fnThrottle: _fnThrottle,
15065		_fnConvertToWidth: _fnConvertToWidth,
15066		_fnGetWidestNode: _fnGetWidestNode,
15067		_fnGetMaxLenString: _fnGetMaxLenString,
15068		_fnStringToCss: _fnStringToCss,
15069		_fnSortFlatten: _fnSortFlatten,
15070		_fnSort: _fnSort,
15071		_fnSortAria: _fnSortAria,
15072		_fnSortListener: _fnSortListener,
15073		_fnSortAttachListener: _fnSortAttachListener,
15074		_fnSortingClasses: _fnSortingClasses,
15075		_fnSortData: _fnSortData,
15076		_fnSaveState: _fnSaveState,
15077		_fnLoadState: _fnLoadState,
15078		_fnSettingsFromNode: _fnSettingsFromNode,
15079		_fnLog: _fnLog,
15080		_fnMap: _fnMap,
15081		_fnBindAction: _fnBindAction,
15082		_fnCallbackReg: _fnCallbackReg,
15083		_fnCallbackFire: _fnCallbackFire,
15084		_fnLengthOverflow: _fnLengthOverflow,
15085		_fnRenderer: _fnRenderer,
15086		_fnDataSource: _fnDataSource,
15087		_fnRowAttributes: _fnRowAttributes,
15088		_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15089		                                // in 1.10, so this dead-end function is
15090		                                // added to prevent errors
15091	} );
15092	
15093
15094	// jQuery access
15095	$.fn.dataTable = DataTable;
15096
15097	// Provide access to the host jQuery object (circular reference)
15098	DataTable.$ = $;
15099
15100	// Legacy aliases
15101	$.fn.dataTableSettings = DataTable.settings;
15102	$.fn.dataTableExt = DataTable.ext;
15103
15104	// With a capital `D` we return a DataTables API instance rather than a
15105	// jQuery object
15106	$.fn.DataTable = function ( opts ) {
15107		return $(this).dataTable( opts ).api();
15108	};
15109
15110	// All properties that are available to $.fn.dataTable should also be
15111	// available on $.fn.DataTable
15112	$.each( DataTable, function ( prop, val ) {
15113		$.fn.DataTable[ prop ] = val;
15114	} );
15115
15116
15117	// Information about events fired by DataTables - for documentation.
15118	/**
15119	 * Draw event, fired whenever the table is redrawn on the page, at the same
15120	 * point as fnDrawCallback. This may be useful for binding events or
15121	 * performing calculations when the table is altered at all.
15122	 *  @name DataTable#draw.dt
15123	 *  @event
15124	 *  @param {event} e jQuery event object
15125	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15126	 */
15127
15128	/**
15129	 * Search event, fired when the searching applied to the table (using the
15130	 * built-in global search, or column filters) is altered.
15131	 *  @name DataTable#search.dt
15132	 *  @event
15133	 *  @param {event} e jQuery event object
15134	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15135	 */
15136
15137	/**
15138	 * Page change event, fired when the paging of the table is altered.
15139	 *  @name DataTable#page.dt
15140	 *  @event
15141	 *  @param {event} e jQuery event object
15142	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15143	 */
15144
15145	/**
15146	 * Order event, fired when the ordering applied to the table is altered.
15147	 *  @name DataTable#order.dt
15148	 *  @event
15149	 *  @param {event} e jQuery event object
15150	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15151	 */
15152
15153	/**
15154	 * DataTables initialisation complete event, fired when the table is fully
15155	 * drawn, including Ajax data loaded, if Ajax data is required.
15156	 *  @name DataTable#init.dt
15157	 *  @event
15158	 *  @param {event} e jQuery event object
15159	 *  @param {object} oSettings DataTables settings object
15160	 *  @param {object} json The JSON object request from the server - only
15161	 *    present if client-side Ajax sourced data is used</li></ol>
15162	 */
15163
15164	/**
15165	 * State save event, fired when the table has changed state a new state save
15166	 * is required. This event allows modification of the state saving object
15167	 * prior to actually doing the save, including addition or other state
15168	 * properties (for plug-ins) or modification of a DataTables core property.
15169	 *  @name DataTable#stateSaveParams.dt
15170	 *  @event
15171	 *  @param {event} e jQuery event object
15172	 *  @param {object} oSettings DataTables settings object
15173	 *  @param {object} json The state information to be saved
15174	 */
15175
15176	/**
15177	 * State load event, fired when the table is loading state from the stored
15178	 * data, but prior to the settings object being modified by the saved state
15179	 * - allowing modification of the saved state is required or loading of
15180	 * state for a plug-in.
15181	 *  @name DataTable#stateLoadParams.dt
15182	 *  @event
15183	 *  @param {event} e jQuery event object
15184	 *  @param {object} oSettings DataTables settings object
15185	 *  @param {object} json The saved state information
15186	 */
15187
15188	/**
15189	 * State loaded event, fired when state has been loaded from stored data and
15190	 * the settings object has been modified by the loaded data.
15191	 *  @name DataTable#stateLoaded.dt
15192	 *  @event
15193	 *  @param {event} e jQuery event object
15194	 *  @param {object} oSettings DataTables settings object
15195	 *  @param {object} json The saved state information
15196	 */
15197
15198	/**
15199	 * Processing event, fired when DataTables is doing some kind of processing
15200	 * (be it, order, searcg or anything else). It can be used to indicate to
15201	 * the end user that there is something happening, or that something has
15202	 * finished.
15203	 *  @name DataTable#processing.dt
15204	 *  @event
15205	 *  @param {event} e jQuery event object
15206	 *  @param {object} oSettings DataTables settings object
15207	 *  @param {boolean} bShow Flag for if DataTables is doing processing or not
15208	 */
15209
15210	/**
15211	 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15212	 * request to made to the server for new data. This event is called before
15213	 * DataTables processed the returned data, so it can also be used to pre-
15214	 * process the data returned from th
15214e server, if needed.
15215	 *
15216	 * Note that this trigger is called in `fnServerData`, if you override
15217	 * `fnServerData` and which to use this event, you need to trigger it in you
15218	 * success function.
15219	 *  @name DataTable#xhr.dt
15220	 *  @event
15221	 *  @param {event} e jQuery event object
15222	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15223	 *  @param {object} json JSON returned from the server
15224	 *
15225	 *  @example
15226	 *     // Use a custom property returned from the server in another DOM element
15227	 *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15228	 *       $('#status').html( json.status );
15229	 *     } );
15230	 *
15231	 *  @example
15232	 *     // Pre-process the data returned from the server
15233	 *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15234	 *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15235	 *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15236	 *       }
15237	 *       // Note no return - manipulate the data directly in the JSON object.
15238	 *     } );
15239	 */
15240
15241	/**
15242	 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15243	 * or passing the bDestroy:true parameter in the initialisation object. This
15244	 * can be used to remove bound events, added DOM nodes, etc.
15245	 *  @name DataTable#destroy.dt
15246	 *  @event
15247	 *  @param {event} e jQuery event object
15248	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15249	 */
15250
15251	/**
15252	 * Page length change event, fired when number of records to show on each
15253	 * page (the length) is changed.
15254	 *  @name DataTable#length.dt
15255	 *  @event
15256	 *  @param {event} e jQuery event object
15257	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15258	 *  @param {integer} len New length
15259	 */
15260
15261	/**
15262	 * Column sizing has changed.
15263	 *  @name DataTable#column-sizing.dt
15264	 *  @event
15265	 *  @param {event} e jQuery event object
15266	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15267	 */
15268
15269	/**
15270	 * Column visibility has changed.
15271	 *  @name DataTable#column-visibility.dt
15272	 *  @event
15273	 *  @param {event} e jQuery event object
15274	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15275	 *  @param {int} column Column index
15276	 *  @param {bool} vis `false` if column now hidden, or `true` if visible
15277	 */
15278
15279	return $.fn.dataTable;
15280}));
15281
15282
15283/*! AutoFill 2.1.1
15284 * ©2008-2015 SpryMedia Ltd - datatables.net/license
15285 */
15286
15287/**
15288 * @summary     AutoFill
15289 * @description Add Excel like click and drag auto-fill options to DataTables
15290 * @version     2.1.1
15291 * @file        dataTables.autoFill.js
15292 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
15293 * @contact     www.sprymedia.co.uk/contact
15294 * @copyright   Copyright 2010-2015 SpryMedia Ltd.
15295 *
15296 * This source file is free software, available under the following license:
15297 *   MIT license - http://datatables.net/license/mit
15298 *
15299 * This source file is distributed in the hope that it will be useful, but
15300 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15301 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
15302 *
15303 * For details please refer to: http://www.datatables.net
15304 */
15305(function( factory ){
15306	if ( typeof define === 'function' && define.amd ) {
15307		// AMD
15308		define( ['jquery', 'datatables.net'], function ( $ ) {
15309			return factory( $, window, document );
15310		} );
15311	}
15312	else if ( typeof exports === 'object' ) {
15313		// CommonJS
15314		module.exports = function (root, $) {
15315			if ( ! root ) {
15316				root = window;
15317			}
15318
15319			if ( ! $ || ! $.fn.dataTable ) {
15320				$ = require('datatables.net')(root, $).$;
15321			}
15322
15323			return factory( $, root, root.document );
15324		};
15325	}
15326	else {
15327		// Browser
15328		factory( jQuery, window, document );
15329	}
15330}(function( $, window, document, undefined ) {
15331'use strict';
15332var DataTable = $.fn.dataTable;
15333
15334
15335var _instance = 0;
15336
15337/** 
15338 * AutoFill provides Excel like auto-fill features for a DataTable
15339 *
15340 * @class AutoFill
15341 * @constructor
15342 * @param {object} oTD DataTables settings object
15343 * @param {object} oConfig Configuration object for AutoFill
15344 */
15345var AutoFill = function( dt, opts )
15346{
15347	if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
15348		throw( "Warning: AutoFill requires DataTables 1.10.8 or greater");
15349	}
15350
15351	// User and defaults configuration object
15352	this.c = $.extend( true, {},
15353		DataTable.defaults.autoFill,
15354		AutoFill.defaults,
15355		opts
15356	);
15357
15358	/**
15359	 * @namespace Settings object which contains customisable information for AutoFill instance
15360	 */
15361	this.s = {
15362		/** @type {DataTable.Api} DataTables' API instance */
15363		dt: new DataTable.Api( dt ),
15364
15365		/** @type {String} Unique namespace for events attached to the document */
15366		namespace: '.autoFill'+(_instance++),
15367
15368		/** @type {Object} Cached dimension information for use in the mouse move event handler */
15369		scroll: {},
15370
15371		/** @type {integer} Interval object used for smooth scrolling */
15372		scrollInterval: null,
15373
15374		handle: {
15375			height: 0,
15376			width: 0
15377		}
15378	};
15379
15380
15381	/**
15382	 * @namespace Common and useful DOM elements for the class instance
15383	 */
15384	this.dom = {
15385		/** @type {jQuery} AutoFill handle */
15386		handle: $('<div class="dt-autofill-handle"/>'),
15387
15388		/**
15389		 * @type {Object} Selected cells outline - Need to use 4 elements,
15390		 *   otherwise the mouse over if you back into the selected rectangle
15391		 *   will be over that element, rather than the cells!
15392		 */
15393		select: {
15394			top:    $('<div class="dt-autofill-select top"/>'),
15395			right:  $('<div class="dt-autofill-select right"/>'),
15396			bottom: $('<div class="dt-autofill-select bottom"/>'),
15397			left:   $('<div class="dt-autofill-select left"/>')
15398		},
15399
15400		/** @type {jQuery} Fill type chooser background */
15401		background: $('<div class="dt-autofill-background"/>'),
15402
15403		/** @type {jQuery} Fill type chooser */
15404		list: $('<div class="dt-autofill-list">'+this.s.dt.i18n('autoFill.info', '')+'<ul/></div>'),
15405
15406		/** @type {jQuery} DataTables scrolling container */
15407		dtScroll: null,
15408
15409		/** @type {jQuery} Offset parent element */
15410		offsetParent: null
15411	};
15412
15413
15414	/* Constructor logic */
15415	this._constructor();
15416};
15417
15418
15419
15420$.extend( AutoFill.prototype, {
15421	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15422	 * Constructor
15423	 */
15424
15425	/**
15426	 * Initialise the RowReorder instance
15427	 *
15428	 * @private
15429	 */
15430	_constructor: function ()
15431	{
15432		var that = this;
15433		var dt = this.s.dt;
15434		var dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container());
15435
15436		if ( dtScroll.length ) {
15437			this.dom.dtScroll = dtScroll;
15438
15439			// Need to scroll container to be the offset parent
15440			if ( dtScroll.css('position') === 'static' ) {
15441				dtScroll.css( 'position', 'relative' );
15442			}
15443		}
15444
15445		this._focusListener();
15446
15447		this.dom.handle.on( 'mousedown', function (e) {
15448			that._mousedown( e );
15449			return false;
15450		} );
15451
15452		dt.on( 'destroy.autoFill', function () {
15453			dt.off( '.autoFill' );
15454			$(dt.table().body()).off( that.s.namespace );
15455			$(document.body).off( that.s.namespace );
15456		} );
15457	},
15458
15459
15460	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15461	 * Private methods
15462	 */
15463
15464	/**
15465	 * Display the AutoFill drag handle by appending it to a table cell. This
15466	 * is the opposite of the _detach method.
15467	 *
15468	 * @param  {node} node TD/TH cell to insert the handle into
15469	 * @private
15470	 */
15471	_attach: function ( node )
15472	{
15473		var dt = this.s.dt;
15474		var idx = dt.cell( node ).index();
15475		var handle = this.dom.handle;
15476		var handleDim = this.s.handle;
15477		var dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container() );
15478
15479		if ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) {
15480			this._detach();
15481			return;
15482		}
15483
15484		if ( ! this.dom.offsetParent ) {
15485			this.dom.offsetParent = $(node).offsetParent();
15486		}
15487
15488		if ( ! handleDim.height || ! handleDim.width ) {
15489			// Append to document so we can get its size. Not expecting it to
15490			// change during the life time of the page
15491			handle.appendTo( 'body' );
15492			handleDim.height = handle.outerHeight();
15493			handleDim.width = handle.outerWidth();
15494		}
15495
15496		var offset = $(node).position();
15497
15498		this.dom.attachedTo = node;
15499		handle
15500			.css( {
15501				top: offset.top + node.offsetHeight - handleDim.height + dtScroll.scrollTop(),
15502				left: offset.left + node.offsetWidth - handleDim.width + dtScroll.
15502scrollLeft()
15503			} )
15504			.appendTo( this.dom.offsetParent );
15505	},
15506
15507
15508	/**
15509	 * Determine can the fill type should be. This can be automatic, or ask the
15510	 * end user.
15511	 *
15512	 * @param {array} cells Information about the selected cells from the key
15513	 *     up function
15514	 * @private
15515	 */
15516	_actionSelector: function ( cells )
15517	{
15518		var that = this;
15519		var dt = this.s.dt;
15520		var actions = AutoFill.actions;
15521		var available = [];
15522
15523		// "Ask" each plug-in if it wants to handle this data
15524		$.each( actions, function ( key, action ) {
15525			if ( action.available( dt, cells ) ) {
15526				available.push( key );
15527			}
15528		} );
15529
15530		if ( available.length === 1 && this.c.alwaysAsk === false ) {
15531			// Only one action available - enact it immediately
15532			var result = actions[ available[0] ].execute( dt, cells );
15533			this._update( result, cells );
15534		}
15535		else {
15536			// Multiple actions available - ask the end user what they want to do
15537			var list = this.dom.list.children('ul').empty();
15538
15539			// Add a cancel option
15540			available.push( 'cancel' );
15541
15542			$.each( available, function ( i, name ) {
15543				list.append( $('<li/>')
15544					.append(
15545						'<div class="dt-autofill-question">'+
15546							actions[ name ].option( dt, cells )+
15547						'<div>'
15548					)
15549					.append( $('<div class="dt-autofill-button">' )
15550						.append( $('<button class="'+AutoFill.classes.btn+'">'+dt.i18n('autoFill.button', '&gt;')+'</button>')
15551							.on( 'click', function () {
15552								var result = actions[ name ].execute(
15553									dt, cells, $(this).closest('li')
15554								);
15555								that._update( result, cells );
15556
15557								that.dom.background.remove();
15558								that.dom.list.remove();
15559							} )
15560						)
15561					)
15562				);
15563			} );
15564
15565			this.dom.background.appendTo( 'body' );
15566			this.dom.list.appendTo( 'body' );
15567
15568			this.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 );
15569		}
15570	},
15571
15572
15573	/**
15574	 * Remove the AutoFill handle from the document
15575	 *
15576	 * @private
15577	 */
15578	_detach: function ()
15579	{
15580		this.dom.attachedTo = null;
15581		this.dom.handle.detach();
15582	},
15583
15584
15585	/**
15586	 * Draw the selection outline by calculating the range between the start
15587	 * and end cells, then placing the highlighting elements to draw a rectangle
15588	 *
15589	 * @param  {node}   target End cell
15590	 * @param  {object} e      Originating event
15591	 * @private
15592	 */
15593	_drawSelection: function ( target, e )
15594	{
15595		// Calculate boundary for start cell to this one
15596		var dt = this.s.dt;
15597		var start = this.s.start;
15598		var startCell = $(this.dom.start);
15599		var endCell = $(target);
15600		var end = {
15601			row: dt.rows( { page: 'current' } ).nodes().indexOf( endCell.parent()[0] ),
15602			column: endCell.index()
15603		};
15604
15605		// Be sure that is a DataTables controlled cell
15606		if ( ! dt.cell( endCell ).any() ) {
15607			return;
15608		}
15609
15610		// if target is not in the columns available - do nothing
15611		if ( dt.columns( this.c.columns ).indexes().indexOf( end.column ) === -1 ) {
15612			return;
15613		}
15614
15615		this.s.end = end;
15616
15617		var top, bottom, left, right, height, width;
15618
15619		top    = start.row    < end.row    ? startCell : endCell;
15620		bottom = start.row    < end.row    ? endCell   : startCell;
15621		left   = start.column < end.column ? startCell : endCell;
15622		right  = start.column < end.column ? endCell   : startCell;
15623
15624		top    = top.position().top;
15625		left   = left.position().left;
15626		height = bottom.position().top + bottom.outerHeight() - top;
15627		width  = right.position().left + right.outerWidth() - left;
15628
15629		var dtScroll = this.dom.dtScroll;
15630		if ( dtScroll ) {
15631			top += dtScroll.scrollTop();
15632			left += dtScroll.scrollLeft();
15633		}
15634
15635		var select = this.dom.select;
15636		select.top.css( {
15637			top: top,
15638			left: left,
15639			width: width
15640		} );
15641
15642		select.left.css( {
15643			top: top,
15644			left: left,
15645			height: height
15646		} );
15647
15648		select.bottom.css( {
15649			top: top + height,
15650			left: left,
15651			width: width
15652		} );
15653
15654		select.right.css( {
15655			top: top,
15656			left: left + width,
15657			height: height
15658		} );
15659	},
15660
15661
15662	/**
15663	 * Use the Editor API to perform an update based on the new data for the
15664	 * cells
15665	 *
15666	 * @param {array} cells Information about the selected cells from the key
15667	 *     up function
15668	 * @private
15669	 */
15670	_editor: function ( cells )
15671	{
15672		var dt = this.s.dt;
15673		var editor = this.c.editor;
15674
15675		if ( ! editor ) {
15676			return;
15677		}
15678
15679		// Build the object structure for Editor's multi-row editing
15680		var idValues = {};
15681		var nodes = [];
15682		var fields = editor.fields();
15683
15684		for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
15685			for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
15686				var cell = cells[i][j];
15687
15688				// Determine the field name for the cell being edited
15689				var col = dt.settings()[0].aoColumns[ cell.index.column ];
15690				var fieldName = col.editField;
15691
15692				if ( fieldName === undefined ) {
15693					var dataSrc = col.mData;
15694
15695					// dataSrc is the `field.data` property, but we need to set
15696					// using the field name, so we need to translate from the
15697					// data to the name
15698					for ( var k=0, ken=fields.length ; k<ken ; k++ ) {
15699						var field = editor.field( fields[k] );
15700
15701						if ( field.dataSrc() === dataSrc ) {
15702							fieldName = field.name();
15703							break;
15704						}
15705					}
15706				}
15707
15708				if ( ! fieldName ) {
15709					throw 'Could not automatically determine field data. '+
15710						'Please see https://datatables.net/tn/11';
15711				}
15712
15713				if ( ! idValues[ fieldName ] ) {
15714					idValues[ fieldName ] = {};
15715				}
15716
15717				var id = dt.row( cell.index.row ).id();
15718				idValues[ fieldName ][ id ] = cell.set;
15719
15720				// Keep a list of cells so we can activate the bubble editing
15721				// with them
15722				nodes.push( cell.index );
15723			}
15724		}
15725
15726		// Perform the edit using bubble editing as it allows us to specify
15727		// the cells to be edited, rather than using full rows
15728		editor
15729			.bubble( nodes, false )
15730			.multiSet( idValues )
15731			.submit();
15732	},
15733
15734
15735	/**
15736	 * Emit an event on the DataTable for listeners
15737	 *
15738	 * @param  {string} name Event name
15739	 * @param  {array} args Event arguments
15740	 * @private
15741	 */
15742	_emitEvent: function ( name, args )
15743	{
15744		this.s.dt.iterator( 'table', function ( ctx, i ) {
15745			$(ctx.nTable).triggerHandler( name+'.dt', args );
15746		} );
15747	},
15748
15749
15750	/**
15751	 * Attach suitable listeners (based on the configuration) that will attach
15752	 * and detach the AutoFill handle in the document.
15753	 *
15754	 * @private
15755	 */
15756	_focusListener: function ()
15757	{
15758		var that = this;
15759		var dt = this.s.dt;
15760		var namespace = this.s.namespace;
15761		var focus = this.c.focus !== null ?
15762			this.c.focus :
15763			dt.settings()[0].keytable ?
15764				'focus' :
15765				'hover';
15766
15767		// All event listeners attached here are removed in the `destroy`
15768		// callback in the constructor
15769		if ( focus === 'focus' ) {
15770			dt
15771				.on( 'key-focus.autoFill', function ( e, dt, cell ) {
15772					that._attach( cell.node() );
15773				} )
15774				.on( 'key-blur.autoFill', function ( e, dt, cell ) {
15775					that._detach();
15776				} );
15777		}
15778		else if ( focus === 'click' ) {
15779			$(dt.table().body()).on( 'click'+namespace, 'td, th', function (e) {
15780				that._attach( this );
15781			} );
15782
15783			$(document.body).on( 'click'+namespace, function (e) {
15784				if ( ! $(e.target).parents().filter( dt.table().body() ).length ) {
15785					that._detach();
15786				}
15787			} );
15788		}
15789		else {
15790			$(dt.table().body())
15791				.on( 'mouseenter'+namespace, 'td, th', function (e) {
15792					that._attach( this );
15793				} )
15794				.on( 'mouseleave'+namespace, function (e) {
15795					if ( $(e.relatedTarget).hasClass('dt-autofill-handle') ) {
15796						return;
15797					}
15798
15799					that._detach();
15800				} );
15801		}
15802	},
15803
15804
15805	/**
15806	 * Start mouse drag - selects the start cell
15807	 *
15808	 * @param  {object} e Mouse down event
15809	 * @private
15810	 */
15811	_mousedown: function ( e )
15812	{
15813		var that = this;
15814		var dt = this.s.dt;
15815
15816		this.dom.start = this.dom.attachedTo;
15817		this.s.start = {
15818			row: dt.rows( { page: 'current' } ).nodes().indexOf( $(this.dom.start).parent()[0] ),
15819			column: $(this.dom.start).index()
15820		};
15821
15822		$(document.body)
15823			.on( 'mousemove.autoFill', function (e) {
15824				that._mousemove( e );
15825			} )
15826			.on( 'mouseup.autoFill', function (e) {
15827				that._mouseup( e );
15828			} );
15829
15830		var select = this.dom.select;
15831		var offsetParent = $(this.s.dt.table().body()).offsetParent();
15832		select.top.appendTo( offsetParent );
15833		select.left.appendTo( offsetParent );
15834		select.right.appendTo( offsetParent );
15835		select.bottom.appendTo( offsetParent );
15836
15837		this._drawSelection( this.dom.start, e );
15838
15839		this.dom.handle.css( 'display', 'none' );
15840
15841		// Cache scrolling information so mouse move doesn't need to read.
15842		// This assumes that the window and DT scroller will not change size
15843		// during an AutoFill drag, which I think is a fair assumption
15844		var scrollWrapper = this.dom.dtScroll;
15845		this.s.scroll = {
15846			windowHeight: $(window).height(),
15847			windowWidth:  $(window).width(),
15848			dtTop:        scrollWrapper ? scrollWrapper.offset().top : null,
15849			dtLeft:       scrollWrapper ? scrollWrapper.offset().left : null,
15850			dtHeight:     scrollWrapper ? scrollWrapper.outerHeight() : null,
15851			dtWidth:      scrollWrapper ? scrollWrapper.outerWidth() : null
15852		};
15853	},
15854
15855
15856	/**
15857	 * Mouse drag - selects the end cell and update the selection display for
15858	 * the end user
15859	 *
15860	 * @param  {object} e Mouse move event
15861	 * @private
15862	 */
15863	_mousemove: function ( e )
15864	{	
15865		var that = this;
15866		var dt = this.s.dt;
15867		var name = e.target.nodeName.toLowerCase();
15868		if ( name !== 'td' && name !== 'th' ) {
15869			return;
15870		}
15871
15872		this._drawSelection( e.target, e );
15873		this._shiftScroll( e );
15874	},
15875
15876
15877	/**
15878	 * End mouse drag - perform the update actions
15879	 *
15880	 * @param  {object} e Mouse up event
15881	 * @private
15882	 */
15883	_mouseup: function ( e )
15884	{
15885		$(document.body).off( '.autoFill' );
15886
15887		var dt = this.s.dt;
15888		var select = this.dom.select;
15889		select.top.remove();
15890		select.left.remove();
15891		select.right.remove();
15892		select.bottom.remove();
15893
15894		this.dom.handle.css( 'display', 'block' );
15895
15896		// Display complete - now do something useful with the selection!
15897		var start = this.s.start;
15898		var end = this.s.end;
15899
15900		// Haven't selected multiple cells, so nothing to do
15901		if ( start.row === end.row && start.column === end.column ) {
15902			return;
15903		}
15904
15905		// Build a matrix representation of the selected rows
15906		var rows       = this._range( start.row, end.row );
15907		var columns    = this._range( start.column, end.column );
15908		var selected   = [];
15909		var dtSettings = dt.settings()[0];
15910		var dtColumns  = dtSettings.aoColumns;
15911
15912		// Can't use Array.prototype.map as IE8 doesn't support it
15913		// Can't use $.map as jQuery flattens 2D arrays
15914		// Need to use a good old fashioned for loop
15915		for ( var rowIdx=0 ; rowIdx<rows.length ; rowIdx++ ) {
15916			selected.push(
15917				$.map( columns, function (column) {
15918					var cell = dt.cell( ':eq('+rows[rowIdx]+')', column+':visible', {page:'current'} );
15919					var data = cell.data();
15920					var cellIndex = cell.index();
15921					var editField = dtColumns[ cellIndex.column ].editField;
15922
15923					if ( editField !== undefined ) {
15924						data = dtSettings.oApi._fnGetObjectDataFn( editField )( dt.row( cellIndex.row ).data() );
15925					}
15926
15927					return {
15928						cell:  cell,
15929						data:  data,
15930						label: cell.data(),
15931						index: cellIndex
15932					};
15933				} )
15934			);
15935		}
15936
15937		this._actionSelector( selected );
15938		
15939		// Stop shiftScroll
15940		clearInterval( this.s.scrollInterval );
15941		this.s.scrollInterval = null;
15942	},
15943
15944
15945	/**
15946	 * Create an array with a range of numbers defined by the start and end
15947	 * parameters passed in (inclusive!).
15948	 * 
15949	 * @param  {integer} start Start
15950	 * @param  {integer} end   End
15951	 * @private
15952	 */
15953	_range: function ( start, end )
15954	{
15955		var out = [];
15956		var i;
15957
15958		if ( start <= end ) {
15959			for ( i=start ; i<=end ; i++ ) {
15960				out.push( i );
15961			}
15962		}
15963		else {
15964			for ( i=start ; i>=end ; i-- ) {
15965				out.push( i );
15966			}
15967		}
15968
15969		return out;
15970	},
15971
15972
15973	/**
15974	 * Move the window and DataTables scrolling during a drag to scroll new
15975	 * content into view. This is done by proximity to the edge of the scrolling
15976	 * container of the mouse - for example near the top edge of the window
15977	 * should scroll up. This is a little complicated as there are two elements
15978	 * that can be scrolled - the window and the DataTables scrolling view port
15979	 * (if scrollX and / or scrollY is enabled).
15980	 *
15981	 * @param  {object} e Mouse move event object
15982	 * @private
15983	 */
15984	_shiftScroll: function ( e )
15985	{
15986		var that = this;
15987		var dt = this.s.dt;
15988		var scroll = this.s.scroll;
15989		var runInterval = false;
15990		var scrollSpeed = 5;
15991		var buffer = 65;
15992		var
15993			windowY = e.pageY - document.body.scrollTop,
15994			windowX = e.pageX - document.body.scrollLeft,
15995			windowVert, windowHoriz,
15996			dtVert, dtHoriz;
15997
15998		// Window calculations - based on the mouse position in the window,
15999		// regardless of scrolling
16000		if ( windowY < buffer ) {
16001			windowVert = scrollSpeed * -1;
16002		}
16003		else if ( windowY > scroll.windowHeight - buffer ) {
16004			windowVert = scrollSpeed;
16005		}
16006
16007		if ( windowX < buffer ) {
16008			windowHoriz = scrollSpeed * -1;
16009		}
16010		else if ( windowX > scroll.windowWidth - buffer ) {
16011			windowHoriz = scrollSpeed;
16012		}
16013
16014		// DataTables scrolling calculations - based on the table's position in
16015		// the document and the mouse position on the page
16016		if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {
16017			dtVert = scrollSpeed * -1;
16018		}
16019		else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {
16020			dtVert = scrollSpeed;
16021		}
16022
16023		if ( scroll.dtLeft !== null && e.pageX < scroll.dtLeft + buffer ) {
16024			dtHoriz = scrollSpeed * -1;
16025		}
16026		else if ( scroll.dtLeft !== null && e.pageX > scroll.dtLeft + scroll.dtWidth - buffer ) {
16027			dtHoriz = scrollSpeed;
16028		}
16029
16030		// This is where it gets interesting. We want to continue scrolling
16031		// without requiring a mouse move, so we need an interval to be
16032		// triggered. The interval should continue until it is no longer needed,
16033		// but it must also use the latest scroll commands (for example consider
16034		// that the mouse might move from scrolling up to scrolling left, all
16035		// with the same interval running. We use the `scroll` object to "pass"
16036		// this information to the interval. Can't use local variables as they
16037		// wouldn't be the ones that are used by an already existing interval!
16038		if ( windowVert || windowHoriz || dtVert || dtHoriz ) {
16039			scroll.windowVert = windowVert;
16040			scroll.windowHoriz = windowHoriz;
16041			scroll.dtVert = dtVert;
16042			scroll.dtHoriz = dtHoriz;
16043			runInterval = true;
16044		}
16045		else if ( this.s.scrollInterval ) {
16046			// Don't need to scroll - remove any existing timer
16047			clearInterval( this.s.scrollInterval );
16048			this.s.scrollInterval = null;
16049		}
16050
16051		// If we need to run the interval to scroll and there is no existing
16052		// interval (if there is an existing one, it will continue to run)
16053		if ( ! this.s.scrollInterval && runInterval ) {
16054			this.s.scrollInterval = setInterval( function () {
16055				// Don't need to worry about setting scroll <0 or beyond the
16056				// scroll bound as the browser will just reject that.
16057				if ( scroll.windowVert ) {
16058					document.body.scrollTop += scroll.windowVert;
16059				}
16060				if ( scroll.windowHoriz ) {
16061					document.body.scrollLeft += scroll.windowHoriz;
16062				}
16063
16064				// DataTables scrolling
16065				if ( scroll.dtVert || scroll.dtHoriz ) {
16066					var scroller = that.dom.dtScroll[0];
16067
16068					if ( scroll.dtVert ) {
16069						scroller.scrollTop += scroll.dtVert;
16070					}
16071					if ( scroll.dtHoriz ) {
16072						scroller.scrollLeft += scroll.dtHoriz;
16073					}
16074				}
16075			}, 20 );
16076		}
16077	},
16078
16079
16080	/**
16081	 * Update the DataTable after the user has selected what they want to do
16082	 *
16083	 * @param  {false|undefined} result Return from the `execute` method - can
16084	 *   be false internally to do nothing. This is not documented for plug
16084-ins
16085	 *   and is used only by the cancel option.
16086	 * @param {array} cells Information about the selected cells from the key
16087	 *     up function, argumented with the set values
16088	 * @private
16089	 */
16090	_update: function ( result, cells )
16091	{
16092		// Do nothing on `false` return from an execute function
16093		if ( result === false ) {
16094			return;
16095		}
16096
16097		var dt = this.s.dt;
16098		var cell;
16099
16100		// Potentially allow modifications to the cells matrix
16101		this._emitEvent( 'preAutoFill', [ dt, cells ] );
16102
16103		this._editor( cells );
16104
16105		// Automatic updates are not performed if `update` is null and the
16106		// `editor` parameter is passed in - the reason being that Editor will
16107		// update the data once submitted
16108		var update = this.c.update !== null ?
16109			this.c.update :
16110			this.c.editor ?
16111				false :
16112				true;
16113
16114		if ( update ) {
16115			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16116				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16117					cell = cells[i][j];
16118
16119					cell.cell.data( cell.set );
16120				}
16121			}
16122
16123			dt.draw(false);
16124		}
16125
16126		this._emitEvent( 'autoFill', [ dt, cells ] );
16127	}
16128} );
16129
16130
16131/**
16132 * AutoFill actions. The options here determine how AutoFill will fill the data
16133 * in the table when the user has selected a range of cells. Please see the
16134 * documentation on the DataTables site for full details on how to create plug-
16135 * ins.
16136 *
16137 * @type {Object}
16138 */
16139AutoFill.actions = {
16140	increment: {
16141		available: function ( dt, cells ) {
16142			return $.isNumeric( cells[0][0].label );
16143		},
16144
16145		option: function ( dt, cells ) {
16146			return dt.i18n(
16147				'autoFill.increment',
16148				'Increment / decrement each cell by: <input type="number" value="1">'
16149			);
16150		},
16151
16152		execute: function ( dt, cells, node ) {
16153			var value = cells[0][0].data * 1;
16154			var increment = $('input', node).val() * 1;
16155
16156			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16157				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16158					cells[i][j].set = value;
16159
16160					value += increment;
16161				}
16162			}
16163		}
16164	},
16165
16166	fill: {
16167		available: function ( dt, cells ) {
16168			return true;
16169		},
16170
16171		option: function ( dt, cells ) {
16172			return dt.i18n('autoFill.fill', 'Fill all cells with <i>'+cells[0][0].label+'</i>' );
16173		},
16174
16175		execute: function ( dt, cells, node ) {
16176			var value = cells[0][0].data;
16177
16178			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16179				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16180					cells[i][j].set = value;
16181				}
16182			}
16183		}
16184	},
16185
16186	fillHorizontal: {
16187		available: function ( dt, cells ) {
16188			return cells.length > 1 && cells[0].length > 1;
16189		},
16190
16191		option: function ( dt, cells ) {
16192			return dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' );
16193		},
16194
16195		execute: function ( dt, cells, node ) {
16196			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16197				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16198					cells[i][j].set = cells[i][0].data;
16199				}
16200			}
16201		}
16202	},
16203
16204	fillVertical: {
16205		available: function ( dt, cells ) {
16206			return cells.length > 1 && cells[0].length > 1;
16207		},
16208
16209		option: function ( dt, cells ) {
16210			return dt.i18n('autoFill.fillVertical', 'Fill cells vertically' );
16211		},
16212
16213		execute: function ( dt, cells, node ) {
16214			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16215				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16216					cells[i][j].set = cells[0][j].data;
16217				}
16218			}
16219		}
16220	},
16221
16222	// Special type that does not make itself available, but is added
16223	// automatically by AutoFill if a multi-choice list is shown. This allows
16224	// sensible code reuse
16225	cancel: {
16226		available: function () {
16227			return false;
16228		},
16229
16230		option: function ( dt ) {
16231			return dt.i18n('autoFill.cancel', 'Cancel' );
16232		},
16233
16234		execute: function () {
16235			return false;
16236		}
16237	}
16238};
16239
16240
16241/**
16242 * AutoFill version
16243 * 
16244 * @static
16245 * @type      String
16246 */
16247AutoFill.version = '2.1.1';
16248
16249
16250/**
16251 * AutoFill defaults
16252 * 
16253 * @namespace
16254 */
16255AutoFill.defaults = {
16256	/** @type {Boolean} Ask user what they want to do, even for a single option */
16257	alwaysAsk: false,
16258
16259	/** @type {string|null} What will trigger a focus */
16260	focus: null, // focus, click, hover
16261
16262	/** @type {column-selector} Columns to provide auto fill for */
16263	columns: '', // all
16264
16265	/** @type {boolean|null} Update the cells after a drag */
16266	update: null, // false is editor given, true otherwise
16267
16268	/** @type {DataTable.Editor} Editor instance for automatic submission */
16269	editor: null
16270};
16271
16272
16273/**
16274 * Classes used by AutoFill that are configurable
16275 * 
16276 * @namespace
16277 */
16278AutoFill.classes = {
16279	/** @type {String} Class used by the selection button */
16280	btn: 'btn'
16281};
16282
16283
16284// Attach a listener to the document which listens for DataTables initialisation
16285// events so we can automatically initialise
16286$(document).on( 'preInit.dt.autofill', function (e, settings, json) {
16287	if ( e.namespace !== 'dt' ) {
16288		return;
16289	}
16290
16291	var init = settings.oInit.autoFill;
16292	var defaults = DataTable.defaults.autoFill;
16293
16294	if ( init || defaults ) {
16295		var opts = $.extend( {}, init, defaults );
16296
16297		if ( init !== false ) {
16298			new AutoFill( settings, opts  );
16299		}
16300	}
16301} );
16302
16303
16304// Alias for access
16305DataTable.AutoFill = AutoFill;
16306DataTable.AutoFill = AutoFill;
16307
16308
16309return AutoFill;
16310}));
16311
16312
16313/*! Buttons for DataTables 1.1.2
16314 * ©2015 SpryMedia Ltd - datatables.net/license
16315 */
16316
16317(function( factory ){
16318	if ( typeof define === 'function' && define.amd ) {
16319		// AMD
16320		define( ['jquery', 'datatables.net'], function ( $ ) {
16321			return factory( $, window, document );
16322		} );
16323	}
16324	else if ( typeof exports === 'object' ) {
16325		// CommonJS
16326		module.exports = function (root, $) {
16327			if ( ! root ) {
16328				root = window;
16329			}
16330
16331			if ( ! $ || ! $.fn.dataTable ) {
16332				$ = require('datatables.net')(root, $).$;
16333			}
16334
16335			return factory( $, root, root.document );
16336		};
16337	}
16338	else {
16339		// Browser
16340		factory( jQuery, window, document );
16341	}
16342}(function( $, window, document, undefined ) {
16343'use strict';
16344var DataTable = $.fn.dataTable;
16345
16346
16347// Used for namespacing events added to the document by each instance, so they
16348// can be removed on destroy
16349var _instCounter = 0;
16350
16351// Button namespacing counter for namespacing events on individual buttons
16352var _buttonCounter = 0;
16353
16354var _dtButtons = DataTable.ext.buttons;
16355
16356/**
16357 * [Buttons description]
16358 * @param {[type]}
16359 * @param {[type]}
16360 */
16361var Buttons = function( dt, config )
16362{
16363	// Allow a boolean true for defaults
16364	if ( config === true ) {
16365		config = {};
16366	}
16367
16368	// For easy configuration of buttons an array can be given
16369	if ( $.isArray( config ) ) {
16370		config = { buttons: config };
16371	}
16372
16373	this.c = $.extend( true, {}, Buttons.defaults, config );
16374
16375	// Don't want a deep copy for the buttons
16376	if ( config.buttons ) {
16377		this.c.buttons = config.buttons;
16378	}
16379
16380	this.s = {
16381		dt: new DataTable.Api( dt ),
16382		buttons: [],
16383		subButtons: [],
16384		listenKeys: '',
16385		namespace: 'dtb'+(_instCounter++)
16386	};
16387
16388	this.dom = {
16389		container: $('<'+this.c.dom.container.tag+'/>')
16390			.addClass( this.c.dom.container.className )
16391	};
16392
16393	this._constructor();
16394};
16395
16396
16397$.extend( Buttons.prototype, {
16398	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16399	 * Public methods
16400	 */
16401
16402	/**
16403	 * Get the action of a button
16404	 * @param  {int|string} Button index
16405	 * @return {function}
16406	 *//**
16407	 * Set the action of a button
16408	 * @param  {int|string} Button index
16409	 * @param  {function} Function to set
16410	 * @return {Buttons} Self for chaining
16411	 */
16412	action: function ( idx, action )
16413	{
16414		var button = this._indexToButton( idx ).conf;
16415		var dt = this.s.dt;
16416
16417		if ( action === undefined ) {
16418			return button.action;
16419		}
16420
16421		button.action = action;
16422
16423		return this;
16424	},
16425
16426	/**
16427	 * Add an active class to the button to make to look active or get current
16428	 * active state.
16429	 * @param  {int|string} Button index
16430	 * @param  {boolean} [flag] Enable / disable flag
16431	 * @return {Buttons} Self for chaining or boolean for getter
16432	 */
16433	active: function ( idx, flag ) {
16434		var button = this._indexToButton( idx );
16435		var klass = this.c.dom.button.active;
16436
16437		if ( flag === undefined ) {
16438			return button.node.hasClass( klass );
16439		}
16440
16441		button.node.toggleClass( klass, flag === undefined ? true : flag );
16442
16443		return this;
16444	},
16445
16446	/**
16447	 * Add a new button
16448	 * @param {int|string} Button index for where to insert the button
16449	 * @param {object} Button configuration object, base string name or function
16450	 * @return {Buttons} Self for chaining
16451	 */
16452	add: function ( idx, config )
16453	{
16454		if ( typeof idx === 'string' && idx.indexOf('-') !== -1 ) {
16455			var idxs = idx.split('-');
16456			this.c.buttons[idxs[0]*1].buttons.splice( idxs[1]*1, 0, config );
16457		}
16458		else {
16459			this.c.buttons.splice( idx*1, 0, config );
16460		}
16461
16462		this.dom.container.empty();
16463		this._buildButtons( this.c.buttons );
16464
16465		return this;
16466	},
16467
16468	/**
16469	 * Get the container node for the buttons
16470	 * @return {jQuery} Buttons node
16471	 */
16472	container: function ()
16473	{
16474		return this.dom.container;
16475	},
16476
16477	/**
16478	 * Disable a button
16479	 * @param  {int|string} Button index
16480	 * @return {Buttons} Self for chaining
16481	 */
16482	disable: function ( idx ) {
16483		var button = this._indexToButton( idx );
16484		button.node.addClass( this.c.dom.button.disabled );
16485
16486		return this;
16487	},
16488
16489	/**
16490	 * Destroy the instance, cleaning up event handlers and removing DOM
16491	 * elements
16492	 * @return {Buttons} Self for chaining
16493	 */
16494	destroy: function ()
16495	{
16496		// Key event listener
16497		$('body').off( 'keyup.'+this.s.namespace );
16498
16499		// Individual button destroy (so they can remove their own events if
16500		// needed
16501		var buttons = this.s.buttons;
16502		var subButtons = this.s.subButtons;
16503		var i, ien, j, jen;
16504		
16505		for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
16506			this.removePrep( i );
16507
16508			for ( j=0, jen=subButtons[i].length ; j<jen ; j++ ) {
16509				this.removePrep( i+'-'+j );
16510			}
16511		}
16512
16513		this.removeCommit();
16514
16515		// Container
16516		this.dom.container.remove();
16517
16518		// Remove from the settings object collection
16519		var buttonInsts = this.s.dt.settings()[0];
16520
16521		for ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {
16522			if ( buttonInsts.inst === this ) {
16523				buttonInsts.splice( i, 1 );
16524				break;
16525			}
16526		}
16527
16528		return this;
16529	},
16530
16531	/**
16532	 * Enable / disable a button
16533	 * @param  {int|string} Button index
16534	 * @param  {boolean} [flag=true] Enable / disable flag
16535	 * @return {Buttons} Self for chaining
16536	 */
16537	enable: function ( idx, flag )
16538	{
16539		if ( flag === false ) {
16540			return this.disable( idx );
16541		}
16542
16543		var button = this._indexToButton( idx );
16544		button.node.removeClass( this.c.dom.button.disabled );
16545
16546		return this;
16547	},
16548
16549	/**
16550	 * Get the instance name for the button set selector
16551	 * @return {string} Instance name
16552	 */
16553	name: function ()
16554	{
16555		return this.c.name;
16556	},
16557
16558	/**
16559	 * Get a button's node
16560	 * @param  {int|string} Button index
16561	 * @return {jQuery} Button element
16562	 */
16563	node: function ( idx )
16564	{
16565		var button = this._indexToButton( idx );
16566		return button.node;
16567	},
16568
16569	/**
16570	 * Tidy up any buttons that have been scheduled for removal. This is
16571	 * required so multiple buttons can be removed without upsetting the button
16572	 * indexes while removing them.
16573	 * @param  {int|string} Button index
16574	 * @return {Buttons} Self for chaining
16575	 */
16576	removeCommit: function ()
16577	{
16578		var buttons = this.s.buttons;
16579		var subButtons = this.s.subButtons;
16580		var i, ien, j;
16581
16582		for ( i=buttons.length-1 ; i>=0 ; i-- ) {
16583			if ( buttons[i] === null ) {
16584				buttons.splice( i, 1 );
16585				subButtons.splice( i, 1 );
16586				this.c.buttons.splice( i, 1 );
16587			}
16588		}
16589
16590		for ( i=0, ien=subButtons.length ; i<ien ; i++ ) {
16591			for ( j=subButtons[i].length-1 ; j>=0 ; j-- ) {
16592				if ( subButtons[i][j] === null ) {
16593					subButtons[i].splice( j, 1 );
16594					this.c.buttons[i].buttons.splice( j, 1 );
16595				}
16596			}
16597		}
16598
16599		return this;
16600	},
16601
16602	/**
16603	 * Scheduled a button for removal. This is required so multiple buttons can
16604	 * be removed without upsetting the button indexes while removing them.
16605	 * @return {Buttons} Self for chaining
16606	 */
16607	removePrep: function ( idx )
16608	{
16609		var button;
16610		var dt = this.s.dt;
16611
16612		if ( typeof idx === 'number' || idx.indexOf('-') === -1 ) {
16613			// Top level button
16614			button = this.s.buttons[ idx*1 ];
16615
16616			if ( button.conf.destroy ) {
16617				button.conf.destroy.call( dt.button(idx), dt, button, button.conf );
16618			}
16619
16620			button.node.remove();
16621			this._removeKey( button.conf );
16622			this.s.buttons[ idx*1 ] = null;
16623		}
16624		else {
16625			// Collection button
16626			var idxs = idx.split('-');
16627			button = this.s.subButtons[ idxs[0]*1 ][ idxs[1]*1 ];
16628
16629			if ( button.conf.destroy ) {
16630				button.conf.destroy.call( dt.button(idx), dt, button, button.conf );
16631			}
16632
16633			button.node.remove();
16634			this._removeKey( button.conf );
16635			this.s.subButtons[ idxs[0]*1 ][ idxs[1]*1 ] = null;
16636		}
16637
16638		return this;
16639	},
16640
16641	/**
16642	 * Get the text for a button
16643	 * @param  {int|string} Button index
16644	 * @return {string} Button text
16645	 *//**
16646	 * Set the text for a button
16647	 * @param  {int|string|function} Button index
16648	 * @param  {string} Text
16649	 * @return {Buttons} Self for chaining
16650	 */
16651	text: function ( idx, label )
16652	{
16653		var button = this._indexToButton( idx );
16654		var buttonLiner = this.c.dom.collection.buttonLiner;
16655		var linerTag = typeof idx === 'string' && idx.indexOf( '-' ) !== -1 && buttonLiner && buttonLiner.tag ?
16656			buttonLiner.tag :
16657			this.c.dom.buttonLiner.tag;
16658		var dt = this.s.dt;
16659		var text = function ( opt ) {
16660			return typeof opt === 'function' ?
16661				opt( dt, button.node, button.conf ) :
16662				opt;
16663		};
16664
16665		if ( label === undefined ) {
16666			return text( button.conf.text );
16667		}
16668
16669		button.conf.text = label;
16670
16671		if ( linerTag ) {
16672			button.node.children( linerTag ).html( text(label) );
16673		}
16674		else {
16675			button.node.html( text(label) );
16676		}
16677
16678		return this;
16679	},
16680
16681	/**
16682	 * Calculate button index from a node
16683	 * @param  {node} Button node (_not_ a jQuery object)
16684	 * @return {string} Index. Undefined if not found
16685	 */
16686	toIndex: function ( node )
16687	{
16688		var i, ien, j, jen;
16689		var buttons = this.s.buttons;
16690		var subButtons = this.s.subButtons;
16691
16692		// Loop the main buttons first
16693		for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
16694			if ( buttons[i].node[0] === node ) {
16695				return i+'';
16696			}
16697		}
16698
16699		// Then the sub-buttons
16700		for ( i=0, ien=subButtons.length ; i<ien ; i++ ) {
16701			for ( j=0, jen=subButtons[i].length ; j<jen ; j++ ) {
16702				if ( subButtons[i][j].node[0] === node ) {
16703					return i+'-'+j;
16704				}
16705			}
16706		}
16707	},
16708
16709
16710	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16711	 * Constructor
16712	 */
16713
16714	/**
16715	 * Buttons constructor
16716	 * @private
16717	 */
16718	_constructor: function ()
16719	{
16720		var that = this;
16721		var dt = this.s.dt;
16722		var dtSettings = dt.settings()[0];
16723
16724		if ( ! dtSettings._buttons ) {
16725			dtSettings._buttons = [];
16726		}
16727
16728		dtSettings._buttons.push( {
16729			inst: this,
16730			name: this.c.name
16731		} );
16732
16733		this._buildButtons( this.c.buttons );
16734
16735		dt.on( 'destroy', function () {
16736			that.destroy();
16737		} );
16738
16739		// Global key event binding to listen for button keys
16740		$('body').on( 'keyup.'+this.s.namespace, function ( e ) {
16741			if ( ! document.activeElement || document.activeElement === document.body ) {
16742				// SUse a string of characters for fast lookup of if we need to
16743				// handle this
16744				var character = String.fromCharCode(e.keyCode).toLowerCase();
16745
16746				if ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {
16747					that._keypress( character, e );
16748				}
16749			}
16750		} );
16751	},
16752
16753
16754	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16755	 * Private methods
16756	 */
16757
16758	/**
16759	 * Add a new button to the key press listener
16760	 * @param {object} Resolved button configuration object
16761	 * @private
16762	 */
16763	_addKey: function ( conf )
16764	{
16765		if ( conf.key ) {
16766			this.s.listenKeys += $.isPlainObject( conf.key ) ?
16767				conf.key.key :
16768				conf.key;
16769		}
16770	},
16771
16772	/**
16773	 * Create buttons from an array of buttons
16774	 * @param  {array} Buttons to create
16775	 * @param  {jQuery} Container node into which the created button should be
16776	 *   inserted.
16777	 * @param  {int} Counter for sub-buttons to be stored in a collection
16778	 * @private
16779	 */
16780	_buildButtons: function ( buttons, container, collectionCounter )
16781	{
16782		var dt = this.s.dt;
16783		var buttonCounter = 0;
16784
16785		if ( ! container ) {
16786			container = this.dom.container;
16787			this.s.buttons = [];
16788			this.s.subButtons = [];
16789		}
16790
16791		for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
16792			var conf = this._resolveExtends( buttons[i] );
16793
16794			if ( ! conf ) {
16795				continue;
16796			}
16797
16798			// If the configuration is an array, then expand the buttons at this
16799			// point
16800			if ( $.isArray( conf ) ) {
16801				this._buildButtons( conf, container, collectionCounter );
16802				continue;
16803			}
16804
16805			var button = this._buildButton(
16806				conf,
16807				collectionCounter!==undefined ? true : false
16808			);
16809
16810			if ( ! button ) {
16811				continue;
16812			}
16813
16814			var buttonNode = button.node;
16815			container.append( button.inserter );
16816
16817			if ( collectionCounter === undefined ) {
16818				this.s.buttons.push( {
16819					node:     buttonNode,
16820					conf:     conf,
16821					inserter: button.inserter
16822				} );
16823				this.s.subButtons.push( [] );
16824			}
16825			else {
16826				this.s.subButtons[ collectionCounter ].push( {
16827					node:     buttonNode,
16828					conf:     conf,
16829					inserter: button.inserter
16830				} );
16831			}
16832
16833			if ( conf.buttons ) {
16834				var collectionDom = this.c.dom.collection;
16835				conf._collection = $('<'+collectionDom.tag+'/>')
16836					.addClass( collectionDom.className );
16837
16838				this._buildButtons( conf.buttons, conf._collection, buttonCounter );
16839			}
16840
16841			// init call is made here, rather than buildButton as it needs to
16842			// have been added to the buttons / subButtons array first
16843			if ( conf.init ) {
16844				conf.init.call( dt.button( buttonNode ), dt, buttonNode, conf );
16845			}
16846
16847			buttonCounter++;
16848		}
16849	},
16850
16851	/**
16852	 * Create an individual button
16853	 * @param  {object} config            Resolved button configuration
16854	 * @param  {boolean} collectionButton `true` if a collection button
16855	 * @return {jQuery} Created button node (jQuery)
16856	 * @private
16857	 */
16858	_buildButton: function ( config, collectionButton )
16859	{
16860		var that = this;
16861		var buttonDom = this.c.dom.button;
16862		var linerDom = this.c.dom.buttonLiner;
16863		var collectionDom = this.c.dom.collection;
16864		var dt = this.s.dt;
16865		var text = function ( opt ) {
16866			return typeof opt === 'function' ?
16867				opt( dt, button, config ) :
16868				opt;
16869		};
16870
16871		if ( collectionButton && collectionDom.button ) {
16872			buttonDom = collectionDom.button;
16873		}
16874
16875		if ( collectionButton && collectionDom.buttonLiner ) {
16876			linerDom = collectionDom.buttonLiner;
16877		}
16878
16879		// Make sure that the button is available based on whatever requirements
16880		// it has. For example, Flash buttons require Flash
16881		if ( config.available && ! config.available( dt, config ) ) {
16882			return false;
16883		}
16884
16885		var action = function ( e, dt, button, config ) {
16886			config.action.call( dt.button( button ), e, dt, button, config );
16887
16888			$(dt.table().node()).triggerHandler( 'buttons-action.dt', [
16889				dt.button( button ), dt, button, config 
16890			] );
16891		};
16892
16893		var button = $('<'+buttonDom.tag+'/>')
16894			.addClass( buttonDom.className )
16895			.attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )
16896			.attr( 'aria-controls', this.s.dt.table().node().id )
16897			.on( 'click.dtb', function (e) {
16898				e.preventDefault();
16899
16900				if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
16901					action( e, dt, button, config );
16902				}
16903
16904				button.blur();
16905			} )
16906			.on( 'keyup.dtb', function (e) {
16907				if ( e.keyCode === 13 ) {
16908					if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
16909						action( e, dt, button, config );
16910					}
16911				}
16912			} );
16913
16914		if ( linerDom.tag ) {
16915			button.append(
16916				$('<'+linerDom.tag+'/>')
16917					.html( text( config.text ) )
16918					.addClass( linerDom.className )
16919			);
16920		}
16921		else {
16922			button.html( text( config.text ) );
16923		}
16924
16925		if ( config.enabled === false ) {
16926			button.addClass( buttonDom.disabled );
16927		}
16928
16929		if ( config.className ) {
16930			button.addClass( config.className );
16931		}
16932
16933		if ( config.titleAttr ) {
16934			button.attr( 'title', config.titleAttr );
16935		}
16936
16937		if ( ! config.namespace ) {
16938			config.namespace = '.dt-button-'+(_buttonCounter++);
16939		}
16940
16941		var buttonContainer = this.c.dom.buttonContainer;
16942		var inserter;
16943		if ( buttonContainer && buttonContainer.tag ) {
16944			inserter = $('<'+buttonContainer.tag+'/>')
16945				.addClass( buttonContainer.className )
16946				.append( button );
16947		}
16948		else {
16949			inserter = button;
16950		}
16951
16952		this._addKey( config );
16953
16954		return {
16955			node: button,
16956			inserter: inserter
16957		};
16958	},
16959
16960	/**
16961	 * Get a button's host information from a button index
16962	 * @param  {int|string} Button index
16963	 * @return {object} Button information - object contains `node` and `conf`
16964	 *   properties
16965	 * @private
16966	 */
16967	_indexToButton: function ( idx )
16968	{
16969		if ( typeof idx === 'number' || idx.indexOf('-') === -1 ) {
16970			return this.s.buttons[ idx*1 ];
16971		}
16972
16973		var idxs = idx.split('-');
16974		return this.s.subButtons[ idxs[0]*1 ][ idxs[1]*1 ];
16975	},
16976
16977	/**
16978	 * Handle a key press - determine if any button's key configured matches
16979	 * what was typed and trigger the action if so.
16980	 * @param  {string} The character pressed
16981	 * @param  {object} Key event that triggered this call
16982	 * @private
16983	 */
16984	_keypress: function ( character, e )
16985	{
16986		var i, ien, j, jen;
16987		var buttons = this.s.buttons;
16988		var subButtons = this.s.subButtons;
16989		var run = function ( conf, node ) {
16990			if ( ! conf.key ) {
16991				return;
16992			}
16993
16994			if ( conf.key === character ) {
16995				node.click();
16996			}
16997			else if ( $.isPlainObject( conf.key ) ) {
16998				if ( conf.key.key !== character ) {
16999					return;
17000				}
17001
17002				if ( conf.key.shiftKey && ! e.shiftKey ) {
17003					return;
17004				}
17005
17006				if ( conf.key.altKey && ! e.altKey ) {
17007					return;
17008				}
17009
17010				if ( conf.key.ctrlKey && ! e.ctrlKey ) {
17011					return;
17012				}
17013
17014				if ( conf.key.metaKey && ! e.metaKey ) {
17015					return;
17016				}
17017
17018				// Made it this far - it is good
17019				node.click();
17020			}
17021		};
17022
17023		// Loop the main buttons first
17024		for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
17025			run( buttons[i].conf, buttons[i].node );
17026		}
17027
17028		// Then the sub-buttons
17029		for ( i=0, ien=subButtons.length ; i<ien ; i++ ) {
17030			for ( j=0, jen=subButtons[i].length ; j<jen ; j++ ) {
17031				run( subButtons[i][j].conf, subButtons[i][j].node );
17032			}
17033		}
17034	},
17035
17036	/**
17037	 * Remove a key from the key listener for this instance (to be used when a
17038	 * button is removed)
17039	 * @param  {object} Button configuration
17040	 */
17041	_removeKey: function ( conf )
17042	{
17043		if ( conf.key ) {
17044			var character = $.isPlainObject( conf.key ) ?
17045				conf.key.key :
17046				conf.key;
17047
17048			// Remove only one character, as multiple buttons could have the
17049			// same listening key
17050			var a = this.s.listenKeys.split('');
17051			var idx = $.inArray( character, a );
17052			a.splice( idx, 1 );
17053			this.s.listenKeys = a.join('');
17054		}
17055	},
17056
17057	/**
17058	 * Resolve a button configuration
17059	 * @param  {string|function|object} Button config to resolve
17060	 * @return {object} Button configuration
17061	 */
17062	_resolveExtends: function ( conf )
17063	{
17064		var dt = this.s.dt;
17065		var i, ien;
17066		var toConfObject = function ( base ) {
17067			var loop = 0;
17068
17069			// Loop until we have resolved to a button configuration, or an
17070			// array of button configurations (which will be iterated
17071			// separately)
17072			while ( ! $.isPlainObject(base) && ! $.isArray(base) ) {
17073				if ( base === undefined ) {
17074					return;
17075				}
17076
17077				if ( typeof base === 'function' ) {
17078					base = base( dt, conf );
17079
17080					if ( ! base ) {
17081						return false;
17082					}
17083				}
17084				else if ( typeof base === 'string' ) {
17085					if ( ! _dtButtons[ base ] ) {
17086						throw 'Unknown button type: '+base;
17087					}
17088
17089					base = _dtButtons[ base ];
17090				}
17091
17092				loop++;
17093				if ( loop > 30 ) {
17094					// Protect against misconfiguration killing the browser
17095					throw 'Buttons: Too many iterations';
17096				}
17097			}
17098
17099			return $.isArray( base ) ?
17100				base :
17101				$.extend( {}, base );
17102		};
17103
17104		conf = toConfObject( conf );
17105
17106		while ( conf && conf.extend ) {
17107			// Use `toConfObject` in case the button definition being extended
17108			// is itself a string or a function
17109			if ( ! _dtButtons[ conf.extend ] ) {
17110				throw 'Cannot extend unknown button type: '+conf.extend;
17111			}
17112
17113			var objArray = toConfObject( _dtButtons[ conf.extend ] );
17114			if ( $.isArray( objArray ) ) {
17115				return objArray;
17116			}
17117			else if ( ! objArray ) {
17118				// This is a little brutal as it might be possible to have a
17119				// valid button without the extend, but if there is no extend
17120				// then the host button would be acting in an undefined state
17121				return false;
17122			}
17123
17124			// Stash the current class name
17125			var originalClassName = objArray.className;
17126
17127			conf = $.extend( {}, objArray, conf );
17128
17129			// The extend will have overwritten the original class name if the
17130			// `conf` object also assigned a class, but we want to concatenate
17131			// them so they are list that is combined from all extended buttons
17132			if ( originalClassName && conf.className !== originalClassName ) {
17133				conf.className = originalClassName+' '+conf.className;
17134			}
17135
17136			// Buttons to be added to a collection  -gives the ability to define
17137			// if buttons should be added to the start or end of a collection
17138			var postfixButtons = conf.postfixButtons;
17139			if ( postfixButtons ) {
17140				if ( ! conf.buttons ) {
17141					conf.buttons = [];
17142				}
17143
17144				for ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {
17145					conf.buttons.push( postfixButtons[i] );
17146				}
17147
17148				conf.postfixButtons = null;
17149			}
17150
17151			var prefixButtons = conf.prefixButtons;
17152			if ( prefixButtons ) {
17153				if ( ! conf.buttons ) {
17154					conf.buttons = [];
17155				}
17156
17157				for ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {
17158					conf.buttons.splice( i, 0, prefixButtons[i] );
17159				}
17160
17161				conf.prefixButtons = null;
17162			}
17163
17164			// Although we want the `conf` object to overwrite almost all of
17165			// the properties of the object being extended, the `extend`
17166			// property should come from the object being extended
17167			conf.extend = objArray.extend;
17168		}
17169
17170		return conf;
17171	}
17172} );
17173
17174
17175
17176/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17177 * Statics
17178 */
17179
17180/**
17181 * Show / hide a background layer behind a collection
17182 * @param  {boolean} Flag to indicate if the background should be shown or
17183 *   hidden 
17184 * @param  {string} Class to assign to the background
17185 * @static
17186 */
17187Buttons.background = function ( show, className, fade ) {
17188	if ( fade === undefined ) {
17189		fade = 400;
17190	}
17191
17192	if ( show ) {
17193		$('<div/>')
17194			.addClass( className )
17195			.css( 'display', 'none' )
17196			.appendTo( 'body' )
17197			.fadeIn( fade );
17198	}
17199	else {
17200		$('body > div.'+className)
17201			.fadeOut( fade, function () {
17202				$(this).remove();
17203			} );
17204	}
17205};
17206
17207/**
17208 * Instance selector - select Buttons instances based on an instance selector
17209 * value from the buttons assigned to a DataTable. This is only useful if
17210 * multiple instances are attached to a DataTable.
17211 * @param  {string|int|array} Instance selector - see `instance-selector`
17212 *   documentation on the DataTables site
17213 * @param  {array} Button instance array that was attached to the DataTables
17214 *   settings object
17215 * @return {array} Buttons instances
17216 * @static
17217 */
17218Buttons.instanceSelector = function ( group, buttons )
17219{
17220	if ( ! group ) {
17221		return $.map( buttons, function ( v ) {
17222			return v.inst;
17223		} );
17224	}
17225
17226	var ret = [];
17227	var names = $.map( buttons, function ( v ) {
17228		return v.name;
17229	} );
17230
17231	// Flatten the group selector into an array of single options
17232	var process = function ( input ) {
17233		if ( $.isArray( input ) ) {
17234			for ( var i=0, ien=input.length ; i<ien ; i++ ) {
17235				process( input[i] );
17236			}
17237			return;
17238		}
17239
17240		if ( typeof input === 'string' ) {
17241			if ( input.indexOf( ',' ) !== -1 ) {
17242				// String selector, list of names
17243				process( input.split(',') );
17244			}
17245			else {
17246				// String selector individual name
17247				var idx = $.inArray( $.trim(input), names );
17248
17249				if ( idx !== -1 ) {
17250					ret.push( buttons[ idx ].inst );
17251				}
17252			}
17253		}
17254		else if ( typeof input === 'number' ) {
17255			// Index selector
17256			ret.push( buttons[ input ].inst );
17257		}
17258	};
17259	
17260	process( group );
17261
17262	return ret;
17263};
17264
17265/**
17266 * Button selector - select one or more buttons from a selector input so some
17267 * operation can be performed on them.
17268 * @param  {array} Button instances array that the selector should operate on
17269 * @param  {string|int|node|jQuery|array} Button selector - see
17270 *   `button-selector` documentation on the DataTables site
17271 * @return {array} Array of objects containing `inst` and `idx` properties of
17272 *   the selected buttons so you know which instance each button belongs to.
17273 * @static
17274 */
17275Buttons.buttonSelector = function ( insts, selector )
17276{
17277	var ret = [];
17278	var run = function ( selector, inst ) {
17279		var i, ien, j, jen;
17280		var buttons = [];
17281
17282		$.each( inst.s.buttons, function (i, v) {
17283			if ( v !== null ) {
17284				buttons.push( {
17285					node: v.node[0],
17286					name: v.conf.name
17287				} );
17288			}
17289		} );
17290
17291		$.each( inst.s.subButtons, function (i, v) {
17292			$.each( v, function (j, w) {
17293				if ( w !== null ) {
17294					buttons.push( {
17295						node: w.node[0],
17296						name: w.conf.name
17297					} );
17298				}
17299			} );
17300		} );
17301
17302		var nodes = $.map( buttons, function (v) {
17303			return v.node;
17304		} );
17305
17306		if ( $.isArray( selector ) || selector instanceof $ ) {
17307			for ( i=0, ien=selector.length ; i<ien ; i++ ) {
17308				run( selector[i], inst );
17309			}
17310			return;
17311		}
17312
17313		if ( selector === null || selector === undefined || selector === '*' ) {
17314			// Select all
17315			for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
17316				ret.push( {
17317					inst: inst,
17318					idx: inst.toIndex( buttons[i].node )
17319				} );
17320			}
17321		}
17322		else if ( typeof selector === 'number' ) {
17323			// Main button index selector
17324			ret.push( {
17325				inst: inst,
17326				idx: selector
17327			} );
17328		}
17329		else if ( typeof selector === 'string' ) {
17330			if ( selector.indexOf( ',' ) !== -1 ) {
17331				// Split
17332				var a = selector.split(',');
17333
17334				for ( i=0, ien=a.length ; i<ien ; i++ ) {
17335					run( $.trim(a[i]), inst );
17336				}
17337			}
17338			else if ( selector.match( /^\d+(\-\d+)?$/ ) ) {
17339				// Sub-button index selector
17340				ret.push( {
17341					inst: inst,
17342					idx: selector
17343				} );
17344			}
17345			else if ( selector.indexOf( ':name' ) !== -1 ) {
17346				// Button name selector
17347				var name = selector.replace( ':name', '' );
17348
17349				for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
17350					if ( buttons[i].name === name ) {
17351						ret.push( {
17352							inst: inst,
17353							idx: inst.toIndex( buttons[i].node )
17354						} );
17355					}
17356				}
17357			}
17358			else {
17359				// jQuery selector on the nodes
17360				$( nodes ).filter( selector ).each( function () {
17361					ret.push( {
17362						inst: inst,
17363						idx: inst.toIndex( this )
17364					} );
17365				} );
17366			}
17367		}
17368		else if ( typeof selector === 'object' && selector.nodeName ) {
17369			// Node selector
17370			var idx = $.inArray( selector, nodes );
17371
17372			if ( idx !== -1 ) {
17373				ret.push( {
17374					inst: inst,
17375					idx: inst.toIndex( nodes[ idx ] )
17376				} );
17377			}
17378		}
17379	};
17380
17381
17382	for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
17383		var inst = insts[i];
17384
17385		run( selector, inst );
17386	}
17387
17388	return ret;
17389};
17390
17391
17392/**
17393 * Buttons defaults. For full documentation, please refer to the docs/option
17394 * directory or the DataTables site.
17395 * @type {Object}
17396 * @static
17397 */
17398Buttons.defaults = {
17399	buttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],
17400	name: 'main',
17401	tabIndex: 0,
17402	dom: {
17403		container: {
17404			tag: 'div',
17405			className: 'dt-buttons'
17406		},
17407		collection: {
17408			tag: 'div',
17409			className: 'dt-button-collection'
17410		},
17411		button: {
17412			tag: 'a',
17413			className: 'dt-button',
17414			active: 'active',
17415			disabled: 'disabled'
17416		},
17417		buttonLiner: {
17418			tag: 'span',
17419			className: ''
17420		}
17421	}
17422};
17423
17424/**
17425 * Version information
17426 * @type {string}
17427 * @static
17428 */
17429Buttons.version = '1.1.2';
17430
17431
17432$.extend( _dtButtons, {
17433	collection: {
17434		text: function ( dt, button, config ) {
17435			return dt.i18n( 'buttons.collection', 'Collection' );
17436		},
17437		className: 'buttons-collection',
17438		action: function ( e, dt, button, config ) {
17439			var background;
17440			var host = button;
17441			var hostOffset = host.offset();
17442			var tableContainer = $( dt.table().container() );
17443			var multiLevel = false;
17444
17445			// Remove any old collection
17446			if ( $('div.dt-button-background').length ) {
17447				multiLevel = $('div.dt-button-collection').offset();
17448				$(document).trigger( 'click.dtb-collection' );
17449			}
17450
17451			config._collection
17452				.addClass( config.collectionLayout )
17453				.css( 'display', 'none' )
17454				.appendTo( 'body' )
17455				.fadeIn( config.fade );
17456
17457			var position = config._collection.css( 'position' );
17458
17459			if ( multiLevel && position === 'absolute' ) {
17460				config._collection.css( {
17461					top: multiLevel.top + 5, // magic numbers for a little offset
17462					left: multiLevel.left + 5
17463				} );
17464			}
17465			else if ( position === 'absolute' ) {
17466				config._collection.css( {
17467					top: hostOffset.top + host.outerHeight(),
17468					left: hostOffset.left
17469				} );
17470
17471				var listRight = hostOffset.left + config._collection.outerWidth();
17472				var tableRight = tableContainer.offset().left + tableContainer.width();
17473				if ( listRight > tableRight ) {
17474					config._collection.css( 'left', hostOffset.left - ( listRight - tableRight ) );
17475				}
17476			}
17477			else {
17478				// Fix position - centre on screen
17479				var top = config._collection.height() / 2;
17480				if ( top > $(window).height() / 2 ) {
17481					top = $(window).height() / 2;
17482				}
17483
17484				config._collection.css( 'marginTop', top*-1 );
17485			}
17486
17487			if ( config.background ) {
17488				Buttons.background( true, config.backgroundClassName, config.fade );
17489			}
17490
17491			// Need to break the 'thread' for the collection button being
17492			// activated by a click - it would also trigger this event
17493			setTimeout( function () {
17494				// This is bonkers, but if we don't have a click listener on the
17495				// background element, iOS Safari will ignore the body click
17496				// listener below. An empty function here is all that is
17497				// required to make it work...
17498				$('div.dt-button-background').on( 'click.dtb-collection', function () {} );
17499
17500				$('body').on( 'click.dtb-collection', function (e) {
17501					if ( ! $(e.target).parents().andSelf().filter( config._collection ).length ) {
17502						config._collection
17503							.fadeOut( config.fade, function () {
17504								config._collection.detach();
17505							} );
17506
17507						$('div.dt-button-background').off( 'click.dtb-collection' );
17508						Buttons.background( false, config.backgroundClassName, config.fade );
17509
17510						$('body').off( 'click.dtb-collection' );
17511						dt.off( 'buttons-action.b-internal' );
17512					}
17513				} );
17514			}, 10 );
17515
17516			if ( config.autoClose ) {
17517				dt.on( 'buttons-action.b-internal', function () {
17518					$('div.dt-button-background').click();
17519				} );
17520			}
17521		},
17522		background: true,
17523		collectionLayout: '',
17524		backgroundClassName: 'dt-button-background',
17525		autoClose: false,
17526		fade: 400
17527	},
17528	copy: function ( dt, conf ) {
17529		if ( _dtButtons.copyHtml5 ) {
17530			return 'copyHtml5';
17531		}
17532		if ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) {
17533			return 'copyFlash';
17534		}
17535	},
17536	csv: function ( dt, conf ) {
17537		// Common option that will use the HTML5 or Flash export buttons
17538		if ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {
17539			return 'csvHtml5';
17540		}
17541		if ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) {
17542			return 'csvFlash';
17543		}
17544	},
17545	excel: function ( dt, conf ) {
17546		// Common option that will use the HTML5 or Flash export buttons
17547		if ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {
17548			return 'excelHtml5';
17549		}
17550		if ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) {
17551			return 'excelFlash';
17552		}
17553	},
17554	pdf: function ( dt, conf ) {
17555		// Common option that will use the HTML5 or Flash export buttons
17556		if ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {
17557			return 'pdfHtml5';
17558		}
17559		if ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) {
17560			return 'pdfFlash';
17561		}
17562	},
17563	pageLength: function ( dt, conf ) {
17564		var lengthMenu = dt.settings()[0].aLengthMenu;
17565		var vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu;
17566		var lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu;
17567		var text = function ( dt ) {
17568			return dt.i18n( 'buttons.pageLength', {
17569				"-1": 'Show all rows',
17570				_:    'Show %d rows'
17571			}, dt.page.len() );
17572		};
17573
17574		return {
17575			extend: 'collection',
17576			text: text,
17577			className: 'buttons-page-length',
17578			autoClose: true,
17579			buttons: $.map( vals, function ( val, i ) {
17580				return {
17581					text: lang[i],
17582					action: function ( e, dt, button, conf ) {
17583						dt.page.len( val ).draw();
17584					},
17585					init: function ( dt, node, conf ) {
17586						var that = this;
17587						var fn = function () {
17588							that.active( dt.page.len() === val );
17589						};
17590
17591						dt.on( 'length.dt'+conf.namespace, fn );
17592						fn();
17593					},
17594					destroy: function ( dt, node, conf ) {
17595						dt.off( 'length.dt'+conf.namespace );
17596					}
17597				};
17598			} ),
17599			init: function ( dt, node, conf ) {
17600				var that = this;
17601				dt.on( 'length.dt'+conf.namespace, function () {
17602					that.text( text( dt ) );
17603				} );
17604			},
17605			destroy: function ( dt, node, conf ) {
17606				dt.off( 'length.dt'+conf.namespace );
17607			}
17608		};
17609	}
17610} );
17611
17612
17613/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17614 * DataTables API
17615 *
17616 * For complete documentation, please refer to the docs/api directory or the
17617 * DataTables site
17618 */
17619
17620// Buttons group and individual button selector
17621DataTable.Api.register( 'buttons()', function ( group, selector ) {
17622	// Argument shifting
17623	if ( selector === undefined ) {
17624		selector = group;
17625		group = undefined;
17626	}
17627
17628	return this.iterator( true, 'table', function ( ctx ) {
17629		if ( ctx._buttons ) {
17630			return Buttons.buttonSelector(
17631				Buttons.instanceSelector( group, ctx._buttons ),
17632				selector
17633			);
17634		}
17635	}, true );
17636} );
17637
17638// Individual button selector
17639DataTable.Api.register( 'button()', function ( group, selector ) {
17640	// just run buttons() and truncate
17641	var buttons = this.buttons( group, selector );
17642
17643	if ( buttons.length > 1 ) {
17644		buttons.splice( 1, buttons.length );
17645	}
17646
17647	return buttons;
17648} );
17649
17650// Active buttons
17651DataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) {
17652	if ( flag === undefined ) {
17653		return this.map( function ( set ) {
17654			 return set.inst.active( set.idx );
17655		} );
17656	}
17657
17658	return this.each( function ( set ) {
17659		set.inst.active( set.idx, flag );
17660	} );
17661} );
17662
17663// Get / set button action
17664DataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {
17665	if ( action === undefined ) {
17666		return this.map( function ( set ) {
17667			 return set.inst.action( set.idx );
17668		} );
17669	}
17670
17671	return this.each( function ( set ) {
17672		set.inst.action( set.idx, action );
17673	} );
17674} );
17675
17676// Enable / disable buttons
17677DataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {
17678	return this.each( function ( set ) {
17679		set.inst.enable( set.idx, flag );
17680	} );
17681} );
17682
17683// Disable buttons
17684DataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {
17685	return this.each( function ( set ) {
17686		set.inst.disable( set.idx );
17687	} );
17688} );
17689
17690// Get button nodes
17691DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {
17692	var jq = $();
17693
17694	// jQuery will automatically reduce duplicates to a single entry
17695	$( this.each( function ( set ) {
17696		jq = jq.add( set.inst.node( set.idx ) );
17697	} ) );
17698
17699	return jq;
17700} );
17701
17702// Get / set button text (i.e. the button labels)
17703DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {
17704	if ( label === undefined ) {
17705		return this.map( function ( set ) {
17706			 return set.inst.text( set.idx );
17707		} );
17708	}
17709
17710	return this.each( function ( set ) {
17711		set.inst.text( set.idx, label );
17712	} );
17713} );
17714
17715// Trigger a button's action
17716DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {
17717	return this.each( function ( set ) {
17718		set.inst.node( set.idx ).trigger( 'click' );
17719	} );
17720} );
17721
17722// Get the container elements for the button sets selected
17723DataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () {
17724	var jq = $();
17725
17726	// jQuery will automatically reduce duplicates to a single entry
17727	$( this.each( function ( set ) {
17728		jq = jq.add( set.inst.container() );
17729	} ) );
17730
17731	return jq;
17732} );
17733
17734// Add a new button
17735DataTable.Api.register( 'button().add()', function ( idx, conf ) {
17736	if ( this.length === 1 ) {
17737		this[0].inst.add( idx, conf );
17738	}
17739
17740	return this.button( idx );
17741} );
17742
17743// Destroy the button sets selected
17744DataTable.Api.register( 'buttons().destroy()', function ( idx ) {
17745	this.pluck( 'inst' ).unique().each( function ( inst ) {
17746		inst.destroy();
17747	} );
17748
17749	return this;
17750} );
17751
17752// Remove a button
17753DataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {
17754	// Need to split into prep and commit so the indexes remain constant during the remove
17755	this.each( function ( set ) {
17756		set.inst.removePrep( set.idx );
17757	} );
17758
17759	this.pluck( 'inst' ).unique().each( function ( inst ) {
17760		inst.removeCommit();
17761	} );
17762
17763	return this;
17764} );
17765
17766// Information box that can be used by buttons
17767var _infoTimer;
17768DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
17769	var that = this;
17770
17771	if ( title === false ) {
17772		$('#datatables_buttons_info').fadeOut( function () {
17773			$(this).remove();
17774		} );
17775		clearTimeout( _infoTimer );
17776		_infoTimer = null;
17777
17778		return this;
17779	}
17780
17781	if ( _infoTimer ) {
17782		clearTimeout( _infoTimer );
17783	}
17784
17785	if ( $('#datatables_buttons_info').length ) {
17786		$('#datatables_buttons_info').remove();
17787	}
17788
17789	title = title ? '<h2>'+title+'</h2>' : '';
17790
17791	$('<div id="datatables_buttons_info" class="dt-button-info"/>')
17792		.html( title )
17793		.append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )
17794		.css( 'display', 'none' )
17795		.appendTo( 'body' )
17796		.fadeIn();
17797
17798	if ( time !== undefined && time !== 0 ) {
17799		_infoTimer = setTimeout( function () {
17800			that.buttons.info( false );
17801		}, time );
17802	}
17803
17804	return this;
17805} );
17806
17807// Get data from the table for export - this is common to a number of plug-in
17808// buttons so it is included in the Buttons core library
17809DataTable.Api.register( 'buttons.exportData()', function ( options ) {
17810	if ( this.context.length ) {
17811		return _exportData( new DataTable.Api( this.context[0] ), options );
17812	}
17813} );
17814
17815
17816var _exportTextarea = $('<textarea/>')[0];
17817var _exportData = function ( dt, inOpts )
17818{
17819	var config = $.extend( true, {}, {
17820		rows:           null,
17821		columns:        '',
17822		modifier:       {
17823			search: 'applied',
17824			order:  'applied'
17825		},
17826		orthogonal:     'display',
17827		stripHtml:      true,
17828		stripNewlines:  true,
17829		decodeEntities: true,
17830		trim:           true,
17831		format:         {
17832			header: function ( d ) {
17833				return strip( d );
17834			},
17835			footer: function ( d ) {
17836				return strip( d );
17837			},
17838			body: function ( d ) {
17839				return strip( d );
17840			}
17841		}
17842	}, inOpts );
17843
17844	var strip = function ( str ) {
17845		if ( typeof str !== 'string' ) {
17846			return str;
17847		}
17848
17849		if ( config.stripHtml ) {
17850			str = str.replace( /<.*?>/g, '' );
17851		}
17852
17853		if ( config.trim ) {
17854			str = str.replace( /^\s+|\s+$/g, '' );
17855		}
17856
17857		if ( config.stripNewlines ) {
17858			str = str.replace( /\n/g, ' ' );
17859		}
17860
17861		if ( config.decodeEntities ) {
17862			_exportTextarea.innerHTML = str;
17863			str = _exportTextarea.value;
17864		}
17865
17866		return str;
17867	};
17868
17869
17870	var header = dt.columns( config.columns ).indexes().map( function (idx, i) {
17871		return config.format.header( dt.column( idx ).header().innerHTML, idx );
17872	} ).toArray();
17873
17874	var footer = dt.table().footer() ?
17875		dt.columns( config.columns ).indexes().map( function (idx, i) {
17876			var el = dt.column( idx ).footer();
17877			return config.format.footer( el ? el.innerHTML : '', idx );
17878		} ).toArray() :
17879		null;
17880
17881	var rowIndexes = dt.rows( config.rows, config.modifier ).indexes().toArray();
17882	var cells = dt
17883		.cells( rowIndexes, config.columns )
17884		.render( config.orthogonal )
17885		.toArray();
17886	var columns = header.length;
17887	var rows = columns > 0 ? cells.length / columns : 0;
17888	var body = new Array( rows );
17889	var cellCounter = 0;
17890
17891	for ( var i=0, ien=rows ; i<ien ; i++ ) {
17892		var row = new Array( columns );
17893
17894		for ( var j=0 ; j<columns ; j++ ) {
17895			row[j] = config.format.body( cells[ cellCounter ], j, i );
17896			cellCounter++;
17897		}
17898
17899		body[i] = row;
17900	}
17901
17902	return {
17903		header: header,
17904		footer: footer,
17905		body:   body
17906	};
17907};
17908
17909
17910/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17911 * DataTables interface
17912 */
17913
17914// Attach to DataTables objects for global access
17915$.fn.dataTable.Buttons = Buttons;
17916$.fn.DataTable.Buttons = Buttons;
17917
17918
17919
17920// DataTables creation - check if the buttons have been defined for this table,
17921// they will have been if the `B` option was used in `dom`, otherwise we should
17922// create the buttons instance here so they can be inserted into the document
17923// using the API. Listen for `init` for compatibility with pre 1.10.10, but to
17924// be removed in future.
17925$(document).on( 'init.dt plugin-init.dt', function (e, settings, json) {
17926	if ( e.namespace !== 'dt' ) {
17927		return;
17928	}
17929
17930	var opts = settings.oInit.buttons || DataTable.defaults.buttons;
17931
17932	if ( opts && ! settings._buttons ) {
17933		new Buttons( settings, opts ).container();
17934	}
17935} );
17936
17937// DataTables `dom` feature option
17938DataTable.ext.feature.push( {
17939	fnInit: function( settings ) {
17940		var api = new DataTable.Api( settings );
17941		var opts = api.init().buttons || DataTable.defaults.buttons;
17942
17943		return new Buttons( api, opts ).container();
17944	},
17945	cFeature: "B"
17946} );
17947
17948
17949return Buttons;
17950}));
17951
17952
17953/*!
17954 * HTML5 export buttons for Buttons and DataTables.
17955 * 2015 SpryMedia Ltd - datatables.net/license
17956 *
17957 * FileSaver.js (2015-05-07.2) - MIT license
17958 * Copyright © 2015 Eli Grey - http://eligrey.com
17959 */
17960
17961(function( factory ){
17962	if ( typeof define === 'function' && define.amd ) {
17963		// AMD
17964		define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
17965			return factory( $, window, document );
17966		} );
17967	}
17968	else if ( typeof exports === 'object' ) {
17969		// CommonJS
17970		module.exports = function (root, $) {
17971			if ( ! root ) {
17972				root = window;
17973			}
17974
17975			if ( ! $ || ! $.fn.dataTable ) {
17976				$ = require('datatables.net')(root, $).$;
17977			}
17978
17979			if ( ! $.fn.dataTable.Buttons ) {
17980				require('datatables.net-buttons')(root, $);
17981			}
17982
17983			return factory( $, root, root.document );
17984		};
17985	}
17986	else {
17987		// Browser
17988		factory( jQuery, window, document );
17989	}
17990}(function( $, window, document, undefined ) {
17991'use strict';
17992var DataTable = $.fn.dataTable;
17993
17994
17995/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17996 * FileSaver.js dependency
17997 */
17998
17999/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
18000
18001var _saveAs = (function(view) {
18002	// IE <10 is explicitly unsupported
18003	if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
18004		return;
18005	}
18006	var
18007		  doc = view.document
18008		  // only get URL when necessary in case Blob.js hasn't overridden it yet
18009		, get_URL = function() {
18010			return view.URL || view.webkitURL || view;
18011		}
18012		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
18013		, can_use_save_link = "download" in save_link
18014		, click = function(node) {
18015			var event = doc.createEvent("MouseEvents");
18016			event.initMouseEvent(
18017				"click", true, false, view, 0, 0, 0, 0, 0
18018				, false, false, false, false, 0, null
18019			);
18020			node.dispatchEvent(event);
18021		}
18022		, webkit_req_fs = view.webkitRequestFileSystem
18023		, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
18024		, throw_outside = function(ex) {
18025			(view.setImmediate || view.setTimeout)(function() {
18026				throw ex;
18027			}, 0);
18028		}
18029		, force_saveable_type = "application/octet-stream"
18030		, fs_min_size = 0
18031		// See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
18032		// https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
18033		// for the reasoning behind the timeout and revocation flow
18034		, arbitrary_revoke_timeout = 500 // in ms
18035		, revoke = function(file) {
18036			var revoker = function() {
18037				if (typeof file === "string") { // file is an object URL
18038					get_URL().revokeObjectURL(file);
18039				} else { // file is a File
18040					file.remove();
18041				}
18042			};
18043			if (view.chrome) {
18044				revoker();
18045			} else {
18046				setTimeout(revoker, arbitrary_revoke_timeout);
18047			}
18048		}
18049		, dispatch = function(filesaver, event_types, event) {
18050			event_types = [].concat(event_types);
18051			var i = event_types.length;
18052			while (i--) {
18053				var listener = filesaver["on" + event_types[i]];
18054				if (typeof listener === "function") {
18055					try {
18056						listener.call(filesaver, event || filesaver);
18057					} catch (ex) {
18058						throw_outside(ex);
18059					}
18060				}
18061			}
18062		}
18063		, auto_bom = function(blob) {
18064			// prepend BOM for UTF-8 XML and text/* types (including HTML)
18065			if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
18066				return new Blob(["\ufeff", blob], {type: blob.type});
18067			}
18068			return blob;
18069		}
18070		, FileSaver = function(blob, name) {
18071			blob = auto_bom(blob);
18072			// First try a.download, then web filesystem, then object URLs
18073			var
18074				  filesaver = this
18075				, type = blob.type
18076				, blob_changed = false
18077				, object_url
18078				, target_view
18079				, dispatch_all = function() {
18080					dispatch(filesaver, "writestart progress write writeend".split(" "));
18081				}
18082				// on any filesys errors revert to saving with object URLs
18083				, fs_error = function() {
18084					// don't create more object URLs than needed
18085					if (blob_changed || !object_url) {
18086						object_url = get_URL().createObjectURL(blob);
18087					}
18088					if (target_view) {
18089						target_view.location.href = object_url;
18090					} else {
18091						var new_tab = view.open(object_url, "_blank");
18092						if (new_tab === undefined && typeof safari !== "undefined") {
18093							//Apple do not allow window.open, see http://bit.ly/1kZffRI
18094							view.location.href = object_url;
18095						}
18096					}
18097					filesaver.readyState = filesaver.DONE;
18098					dispatch_all();
18099					revoke(object_url);
18100				}
18101				, abortable = function(func) {
18102					return function() {
18103						if (filesaver.readyState !== filesaver.DONE) {
18104							return func.apply(this, arguments);
18105						}
18106					};
18107				}
18108				, create_if_not_found = {create: true, exclusive: false}
18109				, slice
18110			;
18111			filesaver.readyState = filesaver.INIT;
18112			if (!name) {
18113				name = "download";
18114			}
18115			if (can_use_save_link) {
18116				object_url = get_URL().createObjectURL(blob);
18117				save_link.href = object_url;
18118				save_link.download = name;
18119				click(save_link);
18120				filesaver.readyState = filesaver.DONE;
18121				dispatch_all();
18122				revoke(object_url);
18123				return;
18124			}
18125			// Object and web filesystem URLs have a problem saving in Google Chrome when
18126			// viewed in a tab, so I force save with application/octet-stream
18127			// http://code.google.com/p/chromium/issues/detail?id=91158
18128			// Update: Google errantly closed 91158, I submitted it again:
18129			// https://code.google.com/p/chromium/issues/detail?id=389642
18130			if (view.chrome && type && type !== force_saveable_type) {
18131				slice = blob.slice || blob.webkitSlice;
18132				blob = slice.call(blob, 0, blob.size, force_saveable_type);
18133				blob_changed = true;
18134			}
18135			// Since I can't be sure that the guessed media type will trigger a download
18136			// in WebKit, I append .download to the filename.
18137			// https://bugs.webkit.org/show_bug.cgi?id=65440
18138			if (webkit_req_fs && name !== "download") {
18139				name += ".download";
18140			}
18141			if (type === force_saveable_type || webkit_req_fs) {
18142				target_view = view;
18143			}
18144			if (!req_fs) {
18145				fs_error();
18146				return;
18147			}
18148			fs_min_size += blob.size;
18149			req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
18150				fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
18151					var save = function() {
18152						dir.getFile(name, create_if_not_found, abortable(function(file) {
18153							file.createWriter(abortable(function(writer) {
18154								writer.onwriteend = function(event) {
18155									target_view.location.href = file.toURL();
18156									filesaver.readyState = filesaver.DONE;
18157									dispatch(filesaver, "writeend", event);
18158									revoke(file);
18159								};
18160								writer.onerror = function() {
18161									var error = writer.error;
18162									if (error.code !== error.ABORT_ERR) {
18163										fs_error();
18164									}
18165								};
18166								"writestart progress write abort".split(" ").forEach(function(event) {
18167									writer["on" + event] = filesaver["on" + event];
18168								});
18169								writer.write(blob);
18170								filesaver.abort = function() {
18171									writer.abort();
18172									filesaver.readyState = filesaver.DONE;
18173								};
18174								filesaver.readyState = filesaver.WRITING;
18175							}), fs_error);
18176						}), fs_error);
18177					};
18178					dir.getFile(name, {create: false}, abortable(function(file) {
18179						// delete file if it already exists
18180						file.remove();
18181						save();
18182					}), abortable(function(ex) {
18183						if (ex.code === ex.NOT_FOUND_ERR) {
18184							save();
18185						} else {
18186							fs_error();
18187						}
18188					}));
18189				}), fs_error);
18190			}), fs_error);
18191		}
18192		, FS_proto = FileSaver.prototype
18193		, saveAs = function(blob, name) {
18194			return new FileSaver(blob, name);
18195		}
18196	;
18197	// IE 10+ (native saveAs)
18198	if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
18199		return function(blob, name) {
18200			return navigator.msSaveOrOpenBlob(auto_bom(blob), name);
18201		};
18202	}
18203
18204	FS_proto.abort = function() {
18205		var filesaver = this;
18206		filesaver.readyState = filesaver.DONE;
18207		dispatch(filesaver, "abort");
18208	};
18209	FS_proto.readyState = FS_proto.INIT = 0;
18210	FS_proto.WRITING = 1;
18211	FS_proto.DONE = 2;
18212
18213	FS_proto.error =
18214	FS_proto.onwritestart =
18215	FS_proto.onprogress =
18216	FS_proto.onwrite =
18217	FS_proto.onabort =
18218	FS_proto.onerror =
18219	FS_proto.onwriteend =
18220		null;
18221
18222	return saveAs;
18223}(window));
18224
18225
18226
18227/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18228 * Local (private) functions
18229 */
18230
18231/**
18232 * Get the file name for an exported file.
18233 *
18234 * @param {object}  config       Button configuration
18235 * @param {boolean} incExtension Include the file name extension
18236 */
18237var _filename = function ( config, incExtension )
18238{
18239	// Backwards compatibility
18240	var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined ?
18241		config.title :
18242		config.filename;
18243
18244	if ( typeof filename === 'function' ) {
18245		filename = filename();
18246	}
18247
18248	if ( filename.indexOf( '*' ) !== -1 ) {
18249		filename = filename.replace( '*', $('title').text() );
18250	}
18251
18252	// Strip characters which the OS will object to
18253	filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
18254
18255	return incExtension === undefined || incExtension === true ?
18256		filename+config.extension :
18257		filename;
18258};
18259
18260/**
18261 * Get the sheet name for Excel exports.
18262 *
18263 * @param {object}  config       Button configuration
18264 */
18265var _sheetname = function ( config )
18266{
18267	var sheetName = 'Sheet1';
18268
18269	if ( config.sheetName ) {
18270		sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, '');
18271	}
18272
18273	return sheetName;	
18274};
18275
18276/**
18277 * Get the title for an exported file.
18278 *
18279 * @param {object}  config  Button configuration
18280 */
18281var _title = function ( config )
18282{
18283	var title = config.title;
18284
18285	if ( typeof title === 'function' ) {
18286		title = title();
18287	}
18288
18289	return title.indexOf( '*' ) !== -1 ?
18290		title.replace( '*', $('title').text() ) :
18291		title;
18292};
18293
18294/**
18295 * Get the newline character(s)
18296 *
18297 * @param {object}  config Button configuration
18298 * @return {string}        Newline character
18299 */
18300var _newLine = function ( config )
18301{
18302	return config.newline ?
18303		config.newline :
18304		navigator.userAgent.match(/Windows/) ?
18305			'\r\n' :
18306			'\n';
18307};
18308
18309/**
18310 * Combine the data from the `buttons.exportData` method into a string that
18311 * will be used in the export file.
18312 *
18313 * @param  {DataTable.Api} dt     DataTables API instance
18314 * @param  {object}        config Button configuration
18315 * @return {object}               The data to export
18316 */
18317var _exportData = function ( dt, config )
18318{
18319	var newLine = _newLine( config );
18320	var data = dt.buttons.exportData( config.exportOptions );
18321	var boundary = config.fieldBoundary;
18322	var separator = config.fieldSeparator;
18323	var reBoundary = new RegExp( boundary, 'g' );
18324	var escapeChar = config.escapeChar !== undefined ?
18325		config.escapeChar :
18326		'\\';
18327	var join = function ( a ) {
18328		var s = '';
18329
18330		// If there is a field boundary, then we might need to escape it in
18331		// the source data
18332		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
18333			if ( i > 0 ) {
18334				s += separator;
18335			}
18336
18337			s += boundary ?
18338				boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :
18339				a[i];
18340		}
18341
18342		return s;
18343	};
18344
18345	var header = config.header ? join( data.header )+newLine : '';
18346	var footer = config.footer && data.footer ? newLine+join( data.footer ) : '';
18347	var body = [];
18348
18349	for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
18350		body.push( join( data.body[i] ) );
18351	}
18352
18353	return {
18354		str: header + body.join( newLine ) + footer,
18355		rows: body.length
18356	};
18357};
18358
18359/**
18360 * Safari's data: support for creating and downloading files is really poor, so
18361 * various options need to be disabled in it. See
18362 * https://bugs.webkit.org/show_bug.cgi?id=102914
18363 * 
18364 * @return {Boolean} `true` if Safari
18365 */
18366var _isSafari = function ()
18367{
18368	return navigator.userAgent.indexOf('Safari') !== -1 &&
18369		navigator.userAgent.indexOf('Chrome') === -1 &&
18370		navigator.userAgent.indexOf('Opera') === -1;
18371};
18372
18373
18374// Excel - Pre-defined strings to build a minimal XLSX file
18375var excelStrings = {
18376	"_rels/.rels": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
18377<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\
18378	<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>\
18379</Relationships>',
18380
18381	"xl/_rels/workbook.xml.rels": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
18382<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\
18383	<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>\
18384</Relationships>',
18385
18386	"[Content_Types].xml": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
18387<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">\
18388	<Default Extension="xml" ContentType="application/xml"/>\
18389	<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>\
18390	<Default Extension="jpeg" ContentType="image/jpeg"/>\
18391	<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>\
18392	<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>\
18393</Types>',
18394
18395	"xl/workbook.xml": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
18396<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">\
18397	<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/>\
18398	<workbookPr showInkAnnotation="0" autoCompressPictures="0"/>\
18399	<bookViews>\
18400		<workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/>\
18401	</bookViews>\
18402	<sheets>\
18403		<sheet name="__SHEET_NAME__" sheetId="1" r:id="rId1"/>\
18404	</sheets>\
18405</workbook>',
18406
18407	"xl/worksheets/sheet1.xml": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
18408<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">\
18409	<sheetData>\
18410		__DATA__\
18411	</sheetData>\
18412</worksheet>'
18413};
18414
18415
18416
18417/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18418 * Buttons
18419 */
18420
18421//
18422// Copy to clipboard
18423//
18424DataTable.ext.buttons.copyHtml5 = {
18425	className: 'buttons-copy buttons-html5',
18426
18427	text: function ( dt ) {
18428		return dt.i18n( 'buttons.copy', 'Copy' );
18429	},
18430
18431	action: function ( e, dt, button, config ) {
18432		var exportData = _exportData( dt, config );
18433		var output = exportData.str;
18434		var hiddenDiv = $('<div/>')
18435			.css( {
18436				height: 1,
18437				width: 1,
18438				overflow: 'hidden',
18439				position: 'fixed',
18440				top: 0,
18441				left: 0
18442			} );
18443
18444		if ( config.customize ) {
18445			output = config.customize( output, config );
18446		}
18447
18448		var textarea = $('<textarea readonly/>')
18449			.val( output )
18450			.appendTo( hiddenDiv );
18451
18452		// For browsers that support the copy execCommand, try to use it
18453		if ( document.queryCommandSupported('copy') ) {
18454			hiddenDiv.appendTo( dt.table().container() );
18455			textarea[0].focus();
18456			textarea[0].select();
18457
18458			try {
18459				document.execCommand( 'copy' );
18460				hiddenDiv.remove();
18461
18462				dt.buttons.info(
18463					dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
18464					dt.i18n( 'buttons.copySuccess', {
18465							1: "Copied one row to clipboard",
18466							_: "Copied %d rows to clipboard"
18467						}, exportData.rows ),
18468					2000
18469				);
18470
18471				return;
18472			}
18473			catch (t) {}
18474		}
18475
18476		// Otherwise we show the text box and instruct the user to use it
18477		var message = $('<span>'+dt.i18n( 'buttons.copyKeys',
18478				'Press <i>ctrl</i> or <i>\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+
18479				'To cancel, click this message or press escape.' )+'</span>'
18480			)
18481			.append( hiddenDiv );
18482
18483		dt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );
18484
18485		// Select the text so when the user activates their system clipboard
18486		// it will copy that text
18487		textarea[0].focus();
18488		textarea[0].select();
18489
18490		// Event to hide the message when the user is done
18491		var container = $(message).closest('.dt-button-info');
18492		var close = function () {
18493			container.off( 'click.buttons-copy' );
18494			$(document).off( '.buttons-copy' );
18495			dt.buttons.info( false );
18496		};
18497
18498		container.on( 'click.buttons-copy', close );
18499		$(document)
18500			.on( 'keydown.buttons-copy', function (e) {
18501				if ( e.keyCode === 27 ) { // esc
18502					close();
18503				}
18504			} )
18505			.on( 'copy.buttons-copy cut.buttons-copy', function () {
18506				close();
18507			} );
18508	},
18509
18510	exportOptions: {},
18511
18512	fieldSeparator: '\t',
18513
18514	fieldBoundary: '',
18515
18516	header: true,
18517
18518	footer: false
18519};
18520
18521//
18522// CSV export
18523//
18524DataTable.ext.buttons.csvHtml5 = {
18525	className: 'buttons-csv buttons-html5',
18526
18527	available: function () {
18528		return window.FileReader !== undefined && window.Blob;
18529	},
18530
18531	text: function ( dt ) {
18532		return dt.i18n( 'buttons.csv', 'CSV' );
18533	},
18534
18535	action: function ( e, dt, button, config ) {
18536		// Set the text
18537		var newLine = _newLine( config );
18538		var output = _exportData( dt, config ).str;
18539		var charset = config.charset;
18540
18541		if ( config.customize ) {
18542			output = config.customize( output, config );
18543		}
18544
18545		if ( charset !== false ) {
18546			if ( ! charset ) {
18547				charset = document.characterSet || document.charset;
18548			}
18549
18550			if ( charset ) {
18551				charset = ';charset='+charset;
18552			}
18553		}
18554		else {
18555			charset = '';
18556		}
18557
18558		_saveAs(
18559			new Blob( [output], {type: 'text/csv'+charset} ),
18560			_filename( config )
18561		);
18562	},
18563
18564	filename: '*',
18565
18566	extension: '.csv',
18567
18568	exportOptions: {},
18569
18570	fieldSeparator: ',',
18571
18572	fieldBoundary: '"',
18573
18574	escapeChar: '"',
18575
18576	charset: null,
18577
18578	header: true,
18579
18580	footer: false
18581};
18582
18583//
18584// Excel (xlsx) export
18585//
18586DataTable.ext.buttons.excelHtml5 = {
18587	className: 'buttons-excel buttons-html5',
18588
18589	available: function () {
18590		return window.FileReader !== undefined && window.JSZip !== undefined && ! _isSafari();
18591	},
18592
18593	text: function ( dt ) {
18594		return dt.i18n( 'buttons.excel', 'Excel' );
18595	},
18596
18597	action: function ( e, dt, button, config ) {
18598		// Set the text
18599		var xml = '';
18600		var data = dt.buttons.exportData( config.exportOptions );
18601		var addRow = function ( row ) {
18602			var cells = [];
18603
18604			for ( var i=0, ien=row.length ; i<ien ; i++ ) {
18605				if ( row[i] === null || row[i] === undefined ) {
18606					row[i] = '';
18607				}
18608
18609				// Don't match numbers with leading zeros or a negative anywhere
18610				// but the start
18611				cells.push( typeof row[i] === 'number' || (row[i].match && $.trim(row[i]).match(/^-?\d+(\.\d+)?$/) && row[i].charAt(0) !== '0') ?
18612					'<c t="n"><v>'+row[i]+'</v></c>' :
18613					'<c t="inlineStr"><is><t>'+(
18614						! row[i].replace ?
18615							row[i] :
18616							row[i]
18617								.replace(/&(?!amp;)/g, '&amp;')
18618								.replace(/</g, '&lt;')
18619								.replace(/>/g, '&gt;')
18620								.replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, ''))+ // remove control characters
18621					'</t></is></c>'                                                      // they are not valid in XML
18622				);
18623			}
18624
18625			return '<row>'+cells.join('')+'</row>';
18626		};
18627
18628		if ( config.header ) {
18629			xml += addRow( data.header );
18630		}
18631
18632		for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
18633			xml += addRow( data.body[i] );
18634		}
18635
18636		if ( config.footer ) {
18637			xml += addRow( data.footer );
18638		}
18639
18640		var zip           = new window.JSZip();
18641		var _rels         = zip.folder("_rels");
18642		var xl            = zip.folder("xl");
18643		var xl_rels       = zip.folder("xl/_rels");
18644		var xl_worksheets = zip.folder("xl/worksheets");
18645
18646		zip.file(           '[Content_Types].xml', excelStrings['[Content_Types].xml'] );
18647		_rels.file(         '.rels',               excelStrings['_rels/.rels'] );
18648		xl.file(            'workbook.xml',        excelStrings['xl/workbook.xml'].replace( '__SHEET_NAME__', _sheetname( config ) ) );
18649		xl_rels.file(       'workbook.xml.rels',   excelStrings['xl/_rels/workbook.xml.rels'] );
18650		xl_worksheets.file( 'sheet1.xml',          excelStrings['xl/worksheets/sheet1.xml'].replace( '__DATA__', xml ) );
18651
18652		_saveAs(
18653			zip.generate( {type:"blob", mimeType:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'} ),
18654			_filename( config )
18655		);
18656	},
18657
18658	filename: '*',
18659
18660	extension: '.xlsx',
18661
18662	exportOptions: {},
18663
18664	header: true,
18665
18666	footer: false
18667};
18668
18669//
18670// PDF export - using pdfMake - http://pdfmake.org
18671//
18672DataTable.ext.buttons.pdfHtml5 = {
18673	className: 'buttons-pdf buttons-html5',
18674
18675	available: function () {
18676		return window.FileReader !== undefined && window.pdfMake;
18677	},
18678
18679	text: function ( dt ) {
18680		return dt.i18n( 'buttons.pdf', 'PDF' );
18681	},
18682
18683	action: function ( e, dt, button, config ) {
18684		var newLine = _newLine( config );
18685		var data = dt.buttons.exportData( config.exportOptions );
18686		var rows = [];
18687
18688		if ( config.header ) {
18689			rows.push( $.map( data.header, function ( d ) {
18690				return {
18691					text: typeof d === 'string' ? d : d+'',
18692					style: 'tableHeader'
18693				};
18694			} ) );
18695		}
18696
18697		for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
18698			rows.push( $.map( data.body[i], function ( d ) {
18699				return {
18700					text: typeof d === 'string' ? d : d+'',
18701					style: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'
18702				};
18703			} ) );
18704		}
18705
18706		if ( config.footer ) {
18707			rows.push( $.map( data.footer, function ( d ) {
18708				return {
18709					text: typeof d === 'string' ? d : d+'',
18710					style: 'tableFooter'
18711				};
18712			} ) );
18713		}
18714
18715		var doc = {
18716			pageSize: config.pageSize,
18717			pageOrientation: config.orientation,
18718			content: [
18719				{
18720					table: {
18721						headerRows: 1,
18722						body: rows
18723					},
18724					layout: 'noBorders'
18725				}
18726			],
18727			styles: {
18728				tableHeader: {
18729					bold: true,
18730					fontSize: 11,
18731					color: 'white',
18732					fillColor: '#2d4154',
18733					alignment: 'center'
18734				},
18735				tableBodyEven: {},
18736				tableBodyOdd: {
18737					fillColor: '#f3f3f3'
18738				},
18739				tableFooter: {
18740					bold: true,
18741					fontSize: 11,
18742					color: 'white',
18743					fillColor: '#2d4154'
18744				},
18745				title: {
18746					alignment: 'center',
18747					fontSize: 15
18748				},
18749				message: {}
18750			},
18751			defaultStyle: {
18752				fontSize: 10
18753			}
18754		};
18755
18756		if ( config.message ) {
18757			doc.content.unshift( {
18758				text: config.message,
18759				style: 'message',
18760				margin: [ 0, 0, 0, 12 ]
18761			} );
18762		}
18763
18764		if ( config.title ) {
18765			doc.content.unshift( {
18766				text: _title( config, false ),
18767				style: 'title',
18768				margin: [ 0, 0, 0, 12 ]
18769			} );
18770		}
18771
18772		if ( config.customize ) {
18773			config.customize( doc, config );
18774		}
18775
18776		var pdf = window.pdfMake.createPdf( doc );
18777
18778		if ( config.download === 'open' && ! _isSafari() ) {
18779			pdf.open();
18780		}
18781		else {
18782			pdf.getBuffer( function (buffer) {
18783				var blob = new Blob( [buffer], {type:'application/pdf'} );
18784
18785				_saveAs( blob, _filename( config ) );
18786			} );
18787		}
18788	},
18789
18790	title: '*',
18791
18792	filename: '*',
18793
18794	extension: '.pdf',
18795
18796	exportOptions: {},
18797
18798	orientation: 'portrait',
18799
18800	pageSize: 'A4',
18801
18802	header: true,
18803
18804	footer: false,
18805
18806	message: null,
18807
18808	customize: null,
18809
18810	download: 'download'
18811};
18812
18813
18814return DataTable.Buttons;
18815}));
18816
18817
18818/*! FixedHeader 3.1.1
18819 * ©2009-2016 SpryMedia Ltd - datatables.net/license
18820 */
18821
18822/**
18823 * @summary     FixedHeader
18824 * @description Fix a table's header or footer, so it is always visible while
18825 *              scrolling
18826 * @version     3.1.1
18827 * @file        dataTables.fixedHeader.js
18828 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
18829 * @contact     www.sprymedia.co.uk/contact
18830 * @copyright   Copyright 2009-2016 SpryMedia Ltd.
18831 *
18832 * This source file is free software, available under the following license:
18833 *   MIT license - http://datatables.net/license/mit
18834 *
18835 * This source file is distributed in the hope that it will be useful, but
18836 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18837 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
18838 *
18839 * For details please refer to: http://www.datatables.net
18840 */
18841
18842(function( factory ){
18843	if ( typeof define === 'function' && define.amd ) {
18844		// AMD
18845		define( ['jquery', 'datatables.net'], function ( $ ) {
18846			return factory( $, window, document );
18847		} );
18848	}
18849	else if ( typeof exports === 'object' ) {
18850		// CommonJS
18851		module.exports = function (root, $) {
18852			if ( ! root ) {
18853				root = window;
18854			}
18855
18856			if ( ! $ || ! $.fn.dataTable ) {
18857				$ = require('datatables.net')(root, $).$;
18858			}
18859
18860			return factory( $, root, root.document );
18861		};
18862	}
18863	else {
18864		// Browser
18865		factory( jQuery, window, document );
18866	}
18867}(function( $, window, document, undefined ) {
18868'use strict';
18869var DataTable = $.fn.dataTable;
18870
18871
18872var _instCounter = 0;
18873
18874var FixedHeader = function ( dt, config ) {
18875	// Sanity check - you just know it will happen
18876	if ( ! (this instanceof FixedHeader) ) {
18877		throw "FixedHeader must be initialised with the 'new' keyword.";
18878	}
18879
18880	// Allow a boolean true for defaults
18881	if ( config === true ) {
18882		config = {};
18883	}
18884
18885	dt = new DataTable.Api( dt );
18886
18887	this.c = $.extend( true, {}, FixedHeader.defaults, config );
18888
18889	this.s = {
18890		dt: dt,
18891		position: {
18892			theadTop: 0,
18893			tbodyTop: 0,
18894			tfootTop: 0,
18895			tfootBottom: 0,
18896			width: 0,
18897			left: 0,
18898			tfootHeight: 0,
18899			theadHeight: 0,
18900			windowHeight: $(window).height(),
18901			visible: true
18902		},
18903		headerMode: null,
18904		footerMode: null,
18905		autoWidth: dt.settings()[0].oFeatures.bAutoWidth,
18906		namespace: '.dtfc'+(_instCounter++),
18907		scrollLeft: {
18908			header: -1,
18909			footer: -1
18910		},
18911		enable: true
18912	};
18913
18914	this.dom = {
18915		floatingHeader: null,
18916		thead: $(dt.table().header()),
18917		tbody: $(dt.table().body()),
18918		tfoot: $(dt.table().footer()),
18919		header: {
18920			host: null,
18921			floating: null,
18922			placeholder: null
18923		},
18924		footer: {
18925			host: null,
18926			floating: null,
18927			placeholder: null
18928		}
18929	};
18930
18931	this.dom.header.host = this.dom.thead.parent();
18932	this.dom.footer.host = this.dom.tfoot.parent();
18933
18934	var dtSettings = dt.settings()[0];
18935	if ( dtSettings._fixedHeader ) {
18936		throw "FixedHeader already initialised on table "+dtSettings.nTable.id;
18937	}
18938
18939	dtSettings._fixedHeader = this;
18940
18941	this._constructor();
18942};
18943
18944
18945/*
18946 * Variable: FixedHeader
18947 * Purpose:  Prototype for FixedHeader
18948 * Scope:    global
18949 */
18950$.extend( FixedHeader.prototype, {
18951	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18952	 * API methods
18953	 */
18954	
18955	/**
18956	 * Enable / disable the fixed elements
18957	 *
18958	 * @param  {boolean} enable `true` to enable, `false` to disable
18959	 */
18960	enable: function ( enable )
18961	{
18962		this.s.enable = enable;
18963
18964		if ( this.c.header ) {
18965			this._modeChange( 'in-place', 'header', true );
18966		}
18967
18968		if ( this.c.footer && this.dom.tfoot.length ) {
18969			this._modeChange( 'in-place', 'footer', true );
18970		}
18971
18972		this.update();
18973	},
18974	
18975	/**
18976	 * Set header offset 
18977	 *
18978	 * @param  {int} new value for headerOffset
18979	 */
18980	headerOffset: function ( offset )
18981	{
18982		if ( offset !== undefined ) {
18983			this.c.headerOffset = offset;
18984			this.update();
18985		}
18986
18987		return this.c.headerOffset;
18988	},
18989	
18990	/**
18991	 * Set footer offset
18992	 *
18993	 * @param  {int} new value for footerOffset
18994	 */
18995	footerOffset: function ( offset )
18996	{
18997		if ( offset !== undefined ) {
18998			this.c.footerOffset = offset;
18999			this.update();
19000		}
19001
19002		return this.c.footerOffset;
19003	},
19004
19005	
19006	/**
19007	 * Recalculate the position of the fixed elements and force them into place
19008	 */
19009	update: function ()
19010	{
19011		this._positions();
19012		this._scroll( true );
19013	},
19014
19015
19016	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19017	 * Constructor
19018	 */
19019	
19020	/**
19021	 * FixedHeader constructor - adding the required event listeners and
19022	 * simple initialisation
19023	 *
19024	 * @private
19025	 */
19026	_constructor: function ()
19027	{
19028		var that = this;
19029		var dt = this.s.dt;
19030
19031		$(window)
19032			.on( 'scroll'+this.s.namespace, function () {
19033				that._scroll();
19034			} )
19035			.on( 'resize'+this.s.namespace, function () {
19036				that.s.position.windowHeight = $(window).height();
19037				that.update();
19038			} );
19039
19040		dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc', function () {
19041			that.update();
19042		} );
19043
19044		dt.on( 'destroy.dtfc', function () {
19045			dt.off( '.dtfc' );
19046			$(window).off( that.s.namespace );
19047		} );
19048
19049		this._positions();
19050		this._scroll();
19051	},
19052
19053
19054	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19055	 * Private methods
19056	 */
19057
19058	/**
19059	 * Clone a fixed item to act as a place holder for the original element
19060	 * which is moved into a clone of the table element, and moved around the
19061	 * document to give the fixed effect.
19062	 *
19063	 * @param  {string}  item  'header' or 'footer'
19064	 * @param  {boolean} force Force the clone to happen, or allow automatic
19065	 *   decision (reuse existing if available)
19066	 * @private
19067	 */
19068	_clone: function ( item, force )
19069	{
19070		var dt = this.s.dt;
19071		var itemDom = this.dom[ item ];
19072		var itemElement = item === 'header' ?
19073			this.dom.thead :
19074			this.dom.tfoot;
19075
19076		if ( ! force && itemDom.floating ) {
19077			// existing floating element - reuse it
19078			itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );
19079		}
19080		else {
19081			if ( itemDom.floating ) {
19082				itemDom.placeholder.remove();
19083				this._unsize( item );
19084				itemDom.floating.children().detach();
19085				itemDom.floating.remove();
19086			}
19087
19088			itemDom.floating = $( dt.table().node().cloneNode( false ) )
19089				.css( 'table-layout', 'fixed' )
19090				.removeAttr( 'id' )
19091				.append( itemElement )
19092				.appendTo( 'body' );
19093
19094			// Insert a fake thead/tfoot into the DataTable to stop it jumping around
19095			itemDom.placeholder = itemElement.clone( false );
19096			itemDom.host.prepend( itemDom.placeholder );
19097
19098			// Clone widths
19099			this._matchWidths( itemDom.placeholder, itemDom.floating );
19100		}
19101	},
19102
19103	/**
19104	 * Copy widths from the cells in one element to another. This is required
19105	 * for the footer as the footer in the main table takes its sizes from the
19106	 * header columns. That isn't present in the footer so to have it still
19107	 * align correctly, the sizes need to be copied over. It is also required
19108	 * for the header when auto width is not enabled
19109	 *
19110	 * @param  {jQuery}
19110 from Copy widths from
19111	 * @param  {jQuery} to   Copy widths to
19112	 * @private
19113	 */
19114	_matchWidths: function ( from, to ) {
19115		var get = function ( name ) {
19116			return $(name, from)
19117				.map( function () {
19118					return $(this).width();
19119				} ).toArray();
19120		};
19121
19122		var set = function ( name, toWidths ) {
19123			$(name, to).each( function ( i ) {
19124				$(this).css( {
19125					width: toWidths[i],
19126					minWidth: toWidths[i]
19127				} );
19128			} );
19129		};
19130
19131		var thWidths = get( 'th' );
19132		var tdWidths = get( 'td' );
19133
19134		set( 'th', thWidths );
19135		set( 'td', tdWidths );
19136	},
19137
19138	/**
19139	 * Remove assigned widths from the cells in an element. This is required
19140	 * when inserting the footer back into the main table so the size is defined
19141	 * by the header columns and also when auto width is disabled in the
19142	 * DataTable.
19143	 *
19144	 * @param  {string} item The `header` or `footer`
19145	 * @private
19146	 */
19147	_unsize: function ( item ) {
19148		var el = this.dom[ item ].floating;
19149
19150		if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {
19151			$('th, td', el).css( {
19152				width: '',
19153				minWidth: ''
19154			} );
19155		}
19156		else if ( el && item === 'header' ) {
19157			$('th, td', el).css( 'min-width', '' );
19158		}
19159	},
19160
19161	/**
19162	 * Reposition the floating elements to take account of horizontal page
19163	 * scroll
19164	 *
19165	 * @param  {string} item       The `header` or `footer`
19166	 * @param  {int}    scrollLeft Document scrollLeft
19167	 * @private
19168	 */
19169	_horizontal: function ( item, scrollLeft )
19170	{
19171		var itemDom = this.dom[ item ];
19172		var position = this.s.position;
19173		var lastScrollLeft = this.s.scrollLeft;
19174
19175		if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {
19176			itemDom.floating.css( 'left', position.left - scrollLeft );
19177
19178			lastScrollLeft[ item ] = scrollLeft;
19179		}
19180	},
19181
19182	/**
19183	 * Change from one display mode to another. Each fixed item can be in one
19184	 * of:
19185	 *
19186	 * * `in-place` - In the main DataTable
19187	 * * `in` - Floating over the DataTable
19188	 * * `below` - (Header only) Fixed to the bottom of the table body
19189	 * * `above` - (Footer only) Fixed to the top of the table body
19190	 * 
19191	 * @param  {string}  mode        Mode that the item should be shown in
19192	 * @param  {string}  item        'header' or 'footer'
19193	 * @param  {boolean} forceChange Force a redraw of the mode, even if already
19194	 *     in that mode.
19195	 * @private
19196	 */
19197	_modeChange: function ( mode, item, forceChange )
19198	{
19199		var dt = this.s.dt;
19200		var itemDom = this.dom[ item ];
19201		var position = this.s.position;
19202
19203		if ( mode === 'in-place' ) {
19204			// Insert the header back into the table's real header
19205			if ( itemDom.placeholder ) {
19206				itemDom.placeholder.remove();
19207				itemDom.placeholder = null;
19208			}
19209
19210			this._unsize( item );
19211
19212			if ( item === 'header' ) {
19213				itemDom.host.prepend( this.dom.thead );
19214			}
19215			else {
19216				itemDom.host.append( this.dom.tfoot );
19217			}
19218
19219			if ( itemDom.floating ) {
19220				itemDom.floating.remove();
19221				itemDom.floating = null;
19222			}
19223		}
19224		else if ( mode === 'in' ) {
19225			// Remove the header from the read header and insert into a fixed
19226			// positioned floating table clone
19227			this._clone( item, forceChange );
19228
19229			itemDom.floating
19230				.addClass( 'fixedHeader-floating' )
19231				.css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )
19232				.css( 'left', position.left+'px' )
19233				.css( 'width', position.width+'px' );
19234
19235			if ( item === 'footer' ) {
19236				itemDom.floating.css( 'top', '' );
19237			}
19238		}
19239		else if ( mode === 'below' ) { // only used for the header
19240			// Fix the position of the floating header at base of the table body
19241			this._clone( item, forceChange );
19242
19243			itemDom.floating
19244				.addClass( 'fixedHeader-locked' )
19245				.css( 'top', position.tfootTop - position.theadHeight )
19246				.css( 'left', position.left+'px' )
19247				.css( 'width', position.width+'px' );
19248		}
19249		else if ( mode === 'above' ) { // only used for the footer
19250			// Fix the position of the floating footer at top of the table body
19251			this._clone( item, forceChange );
19252
19253			itemDom.floating
19254				.addClass( 'fixedHeader-locked' )
19255				.css( 'top', position.tbodyTop )
19256				.css( 'left', position.left+'px' )
19257				.css( 'width', position.width+'px' );
19258		}
19259
19260		this.s.scrollLeft.header = -1;
19261		this.s.scrollLeft.footer = -1;
19262		this.s[item+'Mode'] = mode;
19263	},
19264
19265	/**
19266	 * Cache the positional information that is required for the mode
19267	 * calculations that FixedHeader performs.
19268	 *
19269	 * @private
19270	 */
19271	_positions: function ()
19272	{
19273		var dt = this.s.dt;
19274		var table = dt.table();
19275		var position = this.s.position;
19276		var dom = this.dom;
19277		var tableNode = $(table.node());
19278
19279		// Need to use the header and footer that are in the main table,
19280		// regardless of if they are clones, since they hold the positions we
19281		// want to measure from
19282		var thead = tableNode.children('thead');
19283		var tfoot = tableNode.children('tfoot');
19284		var tbody = dom.tbody;
19285
19286		position.visible = tableNode.is(':visible');
19287		position.width = tableNode.outerWidth();
19288		position.left = tableNode.offset().left;
19289		position.theadTop = thead.offset().top;
19290		position.tbodyTop = tbody.offset().top;
19291		position.theadHeight = position.tbodyTop - position.theadTop;
19292
19293		if ( tfoot.length ) {
19294			position.tfootTop = tfoot.offset().top;
19295			position.tfootBottom = position.tfootTop + tfoot.outerHeight();
19296			position.tfootHeight = position.tfootBottom - position.tfootTop;
19297		}
19298		else {
19299			position.tfootTop = position.tbodyTop + tbody.outerHeight();
19300			position.tfootBottom = position.tfootTop;
19301			position.tfootHeight = position.tfootTop;
19302		}
19303	},
19304
19305
19306	/**
19307	 * Mode calculation - determine what mode the fixed items should be placed
19308	 * into.
19309	 *
19310	 * @param  {boolean} forceChange Force a redraw of the mode, even if already
19311	 *     in that mode.
19312	 * @private
19313	 */
19314	_scroll: function ( forceChange )
19315	{
19316		var windowTop = $(document).scrollTop();
19317		var windowLeft = $(document).scrollLeft();
19318		var position = this.s.position;
19319		var headerMode, footerMode;
19320
19321		if ( ! this.s.enable ) {
19322			return;
19323		}
19324
19325		if ( this.c.header ) {
19326			if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {
19327				headerMode = 'in-place';
19328			}
19329			else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {
19330				headerMode = 'in';
19331			}
19332			else {
19333				headerMode = 'below';
19334			}
19335
19336			if ( forceChange || headerMode !== this.s.headerMode ) {
19337				this._modeChange( headerMode, 'header', forceChange );
19338			}
19339
19340			this._horizontal( 'header', windowLeft );
19341		}
19342
19343		if ( this.c.footer && this.dom.tfoot.length ) {
19344			if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {
19345				footerMode = 'in-place';
19346			}
19347			else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {
19348				footerMode = 'in';
19349			}
19350			else {
19351				footerMode = 'above';
19352			}
19353
19354			if ( forceChange || footerMode !== this.s.footerMode ) {
19355				this._modeChange( footerMode, 'footer', forceChange );
19356			}
19357
19358			this._horizontal( 'footer', windowLeft );
19359		}
19360	}
19361} );
19362
19363
19364/**
19365 * Version
19366 * @type {String}
19367 * @static
19368 */
19369FixedHeader.version = "3.1.1";
19370
19371/**
19372 * Defaults
19373 * @type {Object}
19374 * @static
19375 */
19376FixedHeader.defaults = {
19377	header: true,
19378	footer: false,
19379	headerOffset: 0,
19380	footerOffset: 0
19381};
19382
19383
19384/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19385 * DataTables interfaces
19386 */
19387
19388// Attach for constructor access
19389$.fn.dataTable.FixedHeader = FixedHeader;
19390$.fn.DataTable.FixedHeader = FixedHeader;
19391
19392
19393// DataTables creation - check if the FixedHeader option has been defined on the
19394// table and if so, initialise
19395$(document).on( 'init.dt.dtfh', function (e, settings, json) {
19396	if ( e.namespace !== 'dt' ) {
19397		return;
19398	}
19399
19400	var init = settings.oInit.fixedHeader;
19401	var defaults = DataTable.defaults.fixedHeader;
19402
19403	if ( (init || defaults) && ! settings._fixedHeader ) {
19404		var opts = $.extend( {}, defaults, init );
19405
19406		if ( init !== false ) {
19407			new FixedHeader( settings, opts );
19408		}
19409	}
19410} );
19411
19412// DataTables API methods
19413DataTable.Api.register( 'fixedHeader()', function () {} );
19414
19415DataTable.Api.register( 'fixedHeader.adjust()', function () {
19416	return this.iterator( 'table', function ( ctx ) {
19417		var fh = ctx._fixedHeader;
19418
19419		if ( fh ) {
19420			fh.update();
19421		}
19422	} );
19423} );
19424
19425DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {
19426	return this.iterator( 'table', function ( ctx ) {
19427		var fh = ctx._fixedHeader;
19428
19429		if ( fh ) {
19430			fh.enable( flag !== undefined ? flag : true );
19431		}
19432	} );
19433} );
19434
19435DataTable.Api.register( 'fixedHeader.disable()', function ( ) {
19436	return this.iterator( 'table', function ( ctx ) {
19437		var fh = ctx._fixedHeader;
19438
19439		if ( fh ) {
19440			fh.enable( false );
19441		}
19442	} );
19443} );
19444
19445$.each( ['header', 'footer'], function ( i, el ) {
19446	DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {
19447		var ctx = this.context;
19448
19449		if ( offset === undefined ) {
19450			return ctx.length && ctx[0]._fixedHeader ?
19451				ctx[0]._fixedHeader[el +'Offset']() :
19452				undefined;
19453		}
19454
19455		return this.iterator( 'table', function ( ctx ) {
19456			var fh = ctx._fixedHeader;
19457
19458			if ( fh ) {
19459				fh[ el +'Offset' ]( offset );
19460			}
19461		} );
19462	} );
19463} );
19464
19465
19466return FixedHeader;
19467}));
19468
19469

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.