PageSourceSearch

https://www.extenc.com/modules/metidatatable/lib/datatables.js?v=7717f27557944e175e7628aef560f964

js extenc.com collected 2026-10-10 02:36:40 UTC 1,021,955 bytes, 34,905 lines download raw bytes

vendor: 16,509 bytes, lines 1-518
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/#bs/jszip-2.5.0/dt-1.10.18/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/cr-1.5.0/fh-3.1.4/r-2.2.2/rg-1.1.0/sc-1.5.0/sl-1.2.6
8 *
9 * Included libraries:
10 *   JSZip 2.5.0, DataTables 1.10.18, Buttons 1.5.4, Column visibility 1.5.4, HTML5 export 1.5.4, ColReorder 1.5.0, FixedHeader 3.1.4, Responsive 2.2.2, RowGroup 1.1.0, Scroller 1.5.0, Select 1.2.6
11 */
12
13/*!
14
15JSZip - A Javascript class for generating and reading zip files
16<http://stuartk.com/jszip>
17
18(c) 2009-2014 Stuart Knightley <stuart [at] stuartk.com>
19Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown.
20
21JSZip uses the library pako released under the MIT license :
22https://github.com/nodeca/pako/blob/master/LICENSE
23*/
24!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.JSZip=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
25'use strict';
26// private property
27var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
28
29
30// public method for encoding
31exports.encode = function(input, utf8) {
32    var output = "";
33    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
34    var i = 0;
35
36    while (i < input.length) {
37
38        chr1 = input.charCodeAt(i++);
39        chr2 = input.charCodeAt(i++);
40        chr3 = input.charCodeAt(i++);
41
42        enc1 = chr1 >> 2;
43        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
44        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
45        enc4 = chr3 & 63;
46
47        if (isNaN(chr2)) {
48            enc3 = enc4 = 64;
49        }
50        else if (isNaN(chr3)) {
51            enc4 = 64;
52        }
53
54        output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
55
56    }
57
58    return output;
59};
60
61// public method for decoding
62exports.decode = function(input, utf8) {
63    var output = "";
64    var chr1, chr2, chr3;
65    var enc1, enc2, enc3, enc4;
66    var i = 0;
67
68    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
69
70    while (i < input.length) {
71
72        enc1 = _keyStr.indexOf(input.charAt(i++));
73        enc2 = _keyStr.indexOf(input.charAt(i++));
74        enc3 = _keyStr.indexOf(input.charAt(i++));
75        enc4 = _keyStr.indexOf(input.charAt(i++));
76
77        chr1 = (enc1 << 2) | (enc2 >> 4);
78        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
79        chr3 = ((enc3 & 3) << 6) | enc4;
80
81        output = output + String.fromCharCode(chr1);
82
83        if (enc3 != 64) {
84            output = output + String.fromCharCode(chr2);
85        }
86        if (enc4 != 64) {
87            output = output + String.fromCharCode(chr3);
88        }
89
90    }
91
92    return output;
93
94};
95
96},{}],2:[function(_dereq_,module,exports){
97'use strict';
98function CompressedObject() {
99    this.compressedSize = 0;
100    this.uncompressedSize = 0;
101    this.crc32 = 0;
102    this.compressionMethod = null;
103    this.compressedContent = null;
104}
105
106CompressedObject.prototype = {
107    /**
108     * Return the decompressed content in an unspecified format.
109     * The format will depend on the decompressor.
110     * @return {Object} the decompressed content.
111     */
112    getContent: function() {
113        return null; // see implementation
114    },
115    /**
116     * Return the compressed content in an unspecified format.
117     * The format will depend on the compressed conten source.
118     * @return {Object} the compressed content.
119     */
120    getCompressedContent: function() {
121        return null; // see implementation
122    }
123};
124module.exports = CompressedObject;
125
126},{}],3:[function(_dereq_,module,exports){
127'use strict';
128exports.STORE = {
129    magic: "\x00\x00",
130    compress: function(content, compressionOptions) {
131        return content; // no compression
132    },
133    uncompress: function(content) {
134        return content; // no compression
135    },
136    compressInputType: null,
137    uncompressInputType: null
138};
139exports.DEFLATE = _dereq_('./flate');
140
141},{"./flate":8}],4:[function(_dereq_,module,exports){
142'use strict';
143
144var utils = _dereq_('./utils');
145
146var table = [
147    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
148    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
149    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
150    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
151    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
152    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
153    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
154    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
155    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
156    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
157    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
158    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
159    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
160    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
161    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
162    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
163    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
164    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
165    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
166    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
167    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
168    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
169    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
170    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
171    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
172    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
173    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
174    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
175    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
176    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
177    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
178    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
179    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
180    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
181    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
182    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
183    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
184    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
185    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
186    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
187    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
188    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
189    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
190    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
191    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
192    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
193    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
194    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
195    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
196    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
197    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
198    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
199    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
200    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
201    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
202    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
203    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
204    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
205    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
206    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
207    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
208    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
209    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
210    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
211];
212
213/**
214 *
215 *  Javascript crc32
216 *  http://www.webtoolkit.info/
217 *
218 */
219module.exports = function crc32(input, crc) {
220    if (typeof input === "undefined" || !input.length) {
221        return 0;
222    }
223
224    var isArray = utils.getTypeOf(input) !== "string";
225
226    if (typeof(crc) == "undefined") {
227        crc = 0;
228    }
229    var x = 0;
230    var y = 0;
231    var b = 0;
232
233    crc = crc ^ (-1);
234    for (var i = 0, iTop = input.length; i < iTop; i++) {
235        b = isArray ? input[i] : input.charCodeAt(i);
236        y = (crc ^ b) & 0xFF;
237        x = table[y];
238        crc = (crc >>> 8) ^ x;
239    }
240
241    return crc ^ (-1);
242};
243// vim: set shiftwidth=4 softtabstop=4:
244
245},{"./utils":21}],5:[function(_dereq_,module,exports){
246'use strict';
247var utils = _dereq_('./utils');
248
249function DataReader(data) {
250    this.data = null; // type : see implementation
251    this.length = 0;
252    this.index = 0;
253}
254DataReader.prototype = {
255    /**
256     * Check that the offset will not go too far.
257     * @param {string} offset the additional offset to check.
258     * @throws {Error} an Error if the offset is out of bounds.
259     */
260    checkOffset: function(offset) {
261        this.checkIndex(this.index + offset);
262    },
263    /**
264     * Check that the specifed index will not be too far.
265     * @param {string} newIndex the index to check.
266     * @throws {Error} an Error if the index is out of bounds.
267     */
268    checkIndex: function(newIndex) {
269        if (this.length < newIndex || newIndex < 0) {
270            throw new Error("End of data reached (data length = " + this.length + ", asked index = " + (newIndex) + "). Corrupted zip ?");
271        }
272    },
273    /**
274     * Change the index.
275     * @param {number} newIndex The new index.
276     * @throws {Error} if the new index is out of the data.
277     */
278    setIndex: function(newIndex) {
279        this.checkIndex(newIndex);
280        this.index = newIndex;
281    },
282    /**
283     * Skip the next n bytes.
284     * @param {number} n the number of bytes to skip.
285     * @throws {Error} if the new index is out of the data.
286     */
287    skip: function(n) {
288        this.setIndex(this.index + n);
289    },
290    /**
291     * Get the byte at the specified index.
292     * @param {number} i the index to use.
293     * @return {number} a byte.
294     */
295    byteAt: function(i) {
296        // see implementations
297    },
298    /**
299     * Get the next number with a given byte size.
300     * @param {number} size the number of bytes to read.
301     * @return {number} the corresponding number.
302     */
303    readInt: function(size) {
304        var result = 0,
305            i;
306        this.checkOffset(size);
307        for (i = this.index + size - 1; i >= this.index; i--) {
308            result = (result << 8) + this.byteAt(i);
309        }
310        this.index += size;
311        return result;
312    },
313    /**
314     * Get the next string with a given byte size.
315     * @param {number} size the number of bytes to read.
316     * @return {string} the corresponding string.
317     */
318    readString: function(size) {
319        return utils.transformTo("string", this.readData(size));
320    },
321    /**
322     * Get raw data without conversion, <size> bytes.
323     * @param {number} size the number of bytes to read.
324     * @return {Object} the raw data, implementation specific.
325     */
326    readData: function(size) {
327        // see implementations
328    },
329    /**
330     * Find the last occurence of a zip signature (4 bytes).
331     * @param {string} sig the signature to find.
332     * @return {number} the index of the last occurence, -1 if not found.
333     */
334    lastIndexOfSignature: function(sig) {
335        // see implementations
336    },
337    /**
338     * Get the next date.
339     * @return {Date} the date.
340     */
341    readDate: function() {
342        var dostime = this.readInt(4);
343        return new Date(
344        ((dostime >> 25) & 0x7f) + 1980, // year
345        ((dostime >> 21) & 0x0f) - 1, // month
346        (dostime >> 16) & 0x1f, // day
347        (dostime >> 11) & 0x1f, // hour
348        (dostime >> 5) & 0x3f, // minute
349        (dostime & 0x1f) << 1); // second
350    }
351};
352module.exports = DataReader;
353
354},{"./utils":21}],6:[function(_dereq_,module,exports){
355'use strict';
356exports.base64 = false;
357exports.binary = false;
358exports.dir = false;
359exports.createFolders = false;
360exports.date = null;
361exports.compression = null;
362exports.compressionOptions = null;
363exports.comment = null;
364exports.unixPermissions = null;
365exports.dosPermissions = null;
366
367},{}],7:[function(_dereq_,module,exports){
368'use strict';
369var utils = _dereq_('./utils');
370
371/**
372 * @deprecated
373 * This function will be removed in a future version without replacement.
374 */
375exports.string2binary = function(str) {
376    return utils.string2binary(str);
377};
378
379/**
380 * @deprecated
381 * This function will be removed in a future version without replacement.
382 */
383exports.string2Uint8Array = function(str) {
384    return utils.transformTo("uint8array", str);
385};
386
387/**
388 * @deprecated
389 * This function will be removed in a future version without replacement.
390 */
391exports.uint8Array2String = function(array) {
392    return utils.transformTo("string", array);
393};
394
395/**
396 * @deprecated
397 * This function will be removed in a future version without replacement.
398 */
399exports.string2Blob = function(str) {
400    var buffer = utils.transformTo("arraybuffer", str);
401    return utils.arrayBuffer2Blob(buffer);
402};
403
404/**
405 * @deprecated
406 * This function will be removed in a future version without replacement.
407 */
408exports.arrayBuffer2Blob = function(buffer) {
409    return utils.arrayBuffer2Blob(buffer);
410};
411
412/**
413 * @deprecated
414 * This function will be removed in a future version without replacement.
415 */
416exports.transformTo = function(outputType, input) {
417    return utils.transformTo(outputType, input);
418};
419
420/**
421 * @deprecated
422 * This function will be removed in a future version without replacement.
423 */
424exports.getTypeOf = function(input) {
425    return utils.getTypeOf(input);
426};
427
428/**
429 * @deprecated
430 * This function will be removed in a future version without replacement.
431 */
432exports.checkSupport = function(type) {
433    return utils.checkSupport(type);
434};
435
436/**
437 * @deprecated
438 * This value will be removed in a future version without replacement.
439 */
440exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS;
441
442/**
443 * @deprecated
444 * This value will be removed in a future version without replacement.
445 */
446exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS;
447
448
449/**
450 * @deprecated
451 * This function will be removed in a future version without replacement.
452 */
453exports.pretty = function(str) {
454    return utils.pretty(str);
455};
456
457/**
458 * @deprecated
459 * This function will be removed in a future version without replacement.
460 */
461exports.findCompression = function(compressionMethod) {
462    return utils.findCompression(compressionMethod);
463};
464
465/**
466 * @deprecated
467 * This function will be removed in a future version without replacement.
468 */
469exports.isRegExp = function (object) {
470    return utils.isRegExp(object);
471};
472
473
474},{"./utils":21}],8:[function(_dereq_,module,exports){
475'use strict';
476var USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined');
477
478var pako = _dereq_("pako");
479exports.uncompressInputType = USE_TYPEDARRAY ? "uint8array" : "array";
480exports.compressInputType = USE_TYPEDARRAY ? "uint8array" : "array";
481
482exports.magic = "\x08\x00";
483exports.compress = function(input, compressionOptions) {
484    return pako.deflateRaw(input, {
485        level : compressionOptions.level || -1 // default compression
486    });
487};
488exports.uncompress =  function(input) {
489    return pako.inflateRaw(input);
490};
491
492},{"pako":24}],9:[function(_dereq_,module,exports){
493'use strict';
494
495var base64 = _dereq_('./base64');
496
497/**
498Usage:
499   zip = new JSZip();
500   zip.file("hello.txt", "Hello, World!").file("tempfile", "nothing");
501   zip.folder("images").file("smile.gif", base64Data, {base64: true});
502   zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")});
503   zip.remove("tempfile");
504
505   base64zip = zip.generate();
506
507**/
508
509/**
510 * Representation a of zip file in js
511 * @constructor
512 * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional).
513 * @param {Object=} options the options for creating this objects (optional).
514 */
515function JSZip(data, options) {
516    // if this constructor is used without `new`, it adds `new` before itself:
517    if(!(this instanceof JSZip)) return new JSZip(data, options);
518
vendor: 3,309 bytes, lines 519-639
519    // object containing the files :
520    // {
521    //   "folder/" : {...},
522    //   "folder/data.txt" : {...}
523    // }
524    this.files = {};
525
526    this.comment = null;
527
528    // Where we are in the hierarchy
529    this.root = "";
530    if (data) {
531        this.load(data, options);
532    }
533    this.clone = function() {
534        var newObj = new JSZip();
535        for (var i in this) {
536            if (typeof this[i] !== "function") {
537                newObj[i] = this[i];
538            }
539        }
540        return newObj;
541    };
542}
543JSZip.prototype = _dereq_('./object');
544JSZip.prototype.load = _dereq_('./load');
545JSZip.support = _dereq_('./support');
546JSZip.defaults = _dereq_('./defaults');
547
548/**
549 * @deprecated
550 * This namespace will be removed in a future version without replacement.
551 */
552JSZip.utils = _dereq_('./deprecatedPublicUtils');
553
554JSZip.base64 = {
555    /**
556     * @deprecated
557     * This method will be removed in a future version without replacement.
558     */
559    encode : function(input) {
560        return base64.encode(input);
561    },
562    /**
563     * @deprecated
564     * This method will be removed in a future version without replacement.
565     */
566    decode : function(input) {
567        return base64.decode(input);
568    }
569};
570JSZip.compressions = _dereq_('./compressions');
571module.exports = JSZip;
572
573},{"./base64":1,"./compressions":3,"./defaults":6,"./deprecatedPublicUtils":7,"./load":10,"./object":13,"./support":17}],10:[function(_dereq_,module,exports){
574'use strict';
575var base64 = _dereq_('./base64');
576var ZipEntries = _dereq_('./zipEntries');
577module.exports = function(data, options) {
578    var files, zipEntries, i, input;
579    options = options || {};
580    if (options.base64) {
581        data = base64.decode(data);
582    }
583
584    zipEntries = new ZipEntries(data, options);
585    files = zipEntries.files;
586    for (i = 0; i < files.length; i++) {
587        input = files[i];
588        this.file(input.fileName, input.decompressed, {
589            binary: true,
590            optimizedBinaryString: true,
591            date: input.date,
592            dir: input.dir,
593            comment : input.fileComment.length ? input.fileComment : null,
594            unixPermissions : input.unixPermissions,
595            dosPermissions : input.dosPermissions,
596            createFolders: options.createFolders
597        });
598    }
599    if (zipEntries.zipComment.length) {
600        this.comment = zipEntries.zipComment;
601    }
602
603    return this;
604};
605
606},{"./base64":1,"./zipEntries":22}],11:[function(_dereq_,module,exports){
607(function (Buffer){
608'use strict';
609module.exports = function(data, encoding){
610    return new Buffer(data, encoding);
611};
612module.exports.test = function(b){
613    return Buffer.isBuffer(b);
614};
615
616}).call(this,(typeof Buffer !== "undefined" ? Buffer : undefined))
617},{}],12:[function(_dereq_,module,exports){
618'use strict';
619var Uint8ArrayReader = _dereq_('./uint8ArrayReader');
620
621function NodeBufferReader(data) {
622    this.data = data;
623    this.length = this.data.length;
624    this.index = 0;
625}
626NodeBufferReader.prototype = new Uint8ArrayReader();
627
628/**
629 * @see DataReader.readData
630 */
631NodeBufferReader.prototype.readData = function(size) {
632    this.checkOffset(size);
633    var result = this.data.slice(this.index, this.index + size);
634    this.index += size;
635    return result;
636};
637module.exports = NodeBufferReader;
638
639},{"./uint8ArrayReader":18}],13
vendor: 5,595 bytes, lines 639-816
639:[function(_dereq_,module,exports){
640'use strict';
641var support = _dereq_('./support');
642var utils = _dereq_('./utils');
643var crc32 = _dereq_('./crc32');
644var signature = _dereq_('./signature');
645var defaults = _dereq_('./defaults');
646var base64 = _dereq_('./base64');
647var compressions = _dereq_('./compressions');
648var CompressedObject = _dereq_('./compressedObject');
649var nodeBuffer = _dereq_('./nodeBuffer');
650var utf8 = _dereq_('./utf8');
651var StringWriter = _dereq_('./stringWriter');
652var Uint8ArrayWriter = _dereq_('./uint8ArrayWriter');
653
654/**
655 * Returns the raw data of a ZipObject, decompress the content if necessary.
656 * @param {ZipObject} file the file to use.
657 * @return {String|ArrayBuffer|Uint8Array|Buffer} the data.
658 */
659var getRawData = function(file) {
660    if (file._data instanceof CompressedObject) {
661        file._data = file._data.getContent();
662        file.options.binary = true;
663        file.options.base64 = false;
664
665        if (utils.getTypeOf(file._data) === "uint8array") {
666            var copy = file._data;
667            // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array.
668            // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file).
669            file._data = new Uint8Array(copy.length);
670            // with an empty Uint8Array, Opera fails with a "Offset larger than array size"
671            if (copy.length !== 0) {
672                file._data.set(copy, 0);
673            }
674        }
675    }
676    return file._data;
677};
678
679/**
680 * Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it.
681 * @param {ZipObject} file the file to use.
682 * @return {String|ArrayBuffer|Uint8Array|Buffer} the data.
683 */
684var getBinaryData = function(file) {
685    var result = getRawData(file),
686        type = utils.getTypeOf(result);
687    if (type === "string") {
688        if (!file.options.binary) {
689            // unicode text !
690            // unicode string => binary string is a painful process, check if we can avoid it.
691            if (support.nodebuffer) {
692                return nodeBuffer(result, "utf-8");
693            }
694        }
695        return file.asBinary();
696    }
697    return result;
698};
699
700/**
701 * Transform this._data into a string.
702 * @param {function} filter a function String -> String, applied if not null on the result.
703 * @return {String} the string representing this._data.
704 */
705var dataToString = function(asUTF8) {
706    var result = getRawData(this);
707    if (result === null || typeof result === "undefined") {
708        return "";
709    }
710    // if the data is a base64 string, we decode it before checking the encoding !
711    if (this.options.base64) {
712        result = base64.decode(result);
713    }
714    if (asUTF8 && this.options.binary) {
715        // JSZip.prototype.utf8decode supports arrays as input
716        // skip to array => string step, utf8decode will do it.
717        result = out.utf8decode(result);
718    }
719    else {
720        // no utf8 transformation, do the array => string step.
721        result = utils.transformTo("string", result);
722    }
723
724    if (!asUTF8 && !this.options.binary) {
725        result = utils.transformTo("string", out.utf8encode(result));
726    }
727    return result;
728};
729/**
730 * A simple object representing a file in the zip file.
731 * @constructor
732 * @param {string} name the name of the file
733 * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data
734 * @param {Object} options the options of the file
735 */
736var ZipObject = function(name, data, options) {
737    this.name = name;
738    this.dir = options.dir;
739    this.date = options.date;
740    this.comment = options.comment;
741    this.unixPermissions = options.unixPermissions;
742    this.dosPermissions = options.dosPermissions;
743
744    this._data = data;
745    this.options = options;
746
747    /*
748     * This object contains initial values for dir and date.
749     * With them, we can check if the user changed the deprecated metadata in
750     * `ZipObject#options` or not.
751     */
752    this._initialMetadata = {
753      dir : options.dir,
754      date : options.date
755    };
756};
757
758ZipObject.prototype = {
759    /**
760     * Return the content as UTF8 string.
761     * @return {string} the UTF8 string.
762     */
763    asText: function() {
764        return dataToString.call(this, true);
765    },
766    /**
767     * Returns the binary content.
768     * @return {string} the content as binary.
769     */
770    asBinary: function() {
771        return dataToString.call(this, false);
772    },
773    /**
774     * Returns the content as a nodejs Buffer.
775     * @return {Buffer} the content as a Buffer.
776     */
777    asNodeBuffer: function() {
778        var result = getBinaryData(this);
779        return utils.transformTo("nodebuffer", result);
780    },
781    /**
782     * Returns the content as an Uint8Array.
783     * @return {Uint8Array} the content as an Uint8Array.
784     */
785    asUint8Array: function() {
786        var result = getBinaryData(this);
787        return utils.transformTo("uint8array", result);
788    },
789    /**
790     * Returns the content as an ArrayBuffer.
791     * @return {ArrayBuffer} the content as an ArrayBufer.
792     */
793    asArrayBuffer: function() {
794        return this.asUint8Array().buffer;
795    }
796};
797
798/**
799 * Transform an integer into a string in hexadecimal.
800 * @private
801 * @param {number} dec the number to convert.
802 * @param {number} bytes the number of bytes to generate.
803 * @returns {string} the result.
804 */
805var decToHex = function(dec, bytes) {
806    var hex = "",
807        i;
808    for (i = 0; i < bytes; i++) {
809        hex += String.fromCharCode(dec & 0xff);
810        dec = dec >>> 8;
811    }
812    return hex;
813};
814
815/**
816 * 
vendor: 23,128 bytes, lines 816-1488
816Merge the objects passed as parameters into a new one.
817 * @private
818 * @param {...Object} var_args All objects to merge.
819 * @return {Object} a new object with the data of the others.
820 */
821var extend = function() {
822    var result = {}, i, attr;
823    for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers
824        for (attr in arguments[i]) {
825            if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === "undefined") {
826                result[attr] = arguments[i][attr];
827            }
828        }
829    }
830    return result;
831};
832
833/**
834 * Transforms the (incomplete) options from the user into the complete
835 * set of options to create a file.
836 * @private
837 * @param {Object} o the options from the user.
838 * @return {Object} the complete set of options.
839 */
840var prepareFileAttrs = function(o) {
841    o = o || {};
842    if (o.base64 === true && (o.binary === null || o.binary === undefined)) {
843        o.binary = true;
844    }
845    o = extend(o, defaults);
846    o.date = o.date || new Date();
847    if (o.compression !== null) o.compression = o.compression.toUpperCase();
848
849    return o;
850};
851
852/**
853 * Add a file in the current folder.
854 * @private
855 * @param {string} name the name of the file
856 * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file
857 * @param {Object} o the options of the file
858 * @return {Object} the new file.
859 */
860var fileAdd = function(name, data, o) {
861    // be sure sub folders exist
862    var dataType = utils.getTypeOf(data),
863        parent;
864
865    o = prepareFileAttrs(o);
866
867    if (typeof o.unixPermissions === "string") {
868        o.unixPermissions = parseInt(o.unixPermissions, 8);
869    }
870
871    // UNX_IFDIR  0040000 see zipinfo.c
872    if (o.unixPermissions && (o.unixPermissions & 0x4000)) {
873        o.dir = true;
874    }
875    // Bit 4    Directory
876    if (o.dosPermissions && (o.dosPermissions & 0x0010)) {
877        o.dir = true;
878    }
879
880    if (o.dir) {
881        name = forceTrailingSlash(name);
882    }
883
884    if (o.createFolders && (parent = parentFolder(name))) {
885        folderAdd.call(this, parent, true);
886    }
887
888    if (o.dir || data === null || typeof data === "undefined") {
889        o.base64 = false;
890        o.binary = false;
891        data = null;
892        dataType = null;
893    }
894    else if (dataType === "string") {
895        if (o.binary && !o.base64) {
896            // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask
897            if (o.optimizedBinaryString !== true) {
898                // this is a string, not in a base64 format.
899                // Be sure that this is a correct "binary string"
900                data = utils.string2binary(data);
901            }
902        }
903    }
904    else { // arraybuffer, uint8array, ...
905        o.base64 = false;
906        o.binary = true;
907
908        if (!dataType && !(data instanceof CompressedObject)) {
909            throw new Error("The data of '" + name + "' is in an unsupported format !");
910        }
911
912        // special case : it's way easier to work with Uint8Array than with ArrayBuffer
913        if (dataType === "arraybuffer") {
914            data = utils.transformTo("uint8array", data);
915        }
916    }
917
918    var object = new ZipObject(name, data, o);
919    this.files[name] = object;
920    return object;
921};
922
923/**
924 * Find the parent folder of the path.
925 * @private
926 * @param {string} path the path to use
927 * @return {string} the parent folder, or ""
928 */
929var parentFolder = function (path) {
930    if (path.slice(-1) == '/') {
931        path = path.substring(0, path.length - 1);
932    }
933    var lastSlash = path.lastIndexOf('/');
934    return (lastSlash > 0) ? path.substring(0, lastSlash) : "";
935};
936
937
938/**
939 * Returns the path with a slash at the end.
940 * @private
941 * @param {String} path the path to check.
942 * @return {String} the path with a trailing slash.
943 */
944var forceTrailingSlash = function(path) {
945    // Check the name ends with a /
946    if (path.slice(-1) != "/") {
947        path += "/"; // IE doesn't like substr(-1)
948    }
949    return path;
950};
951/**
952 * Add a (sub) folder in the current folder.
953 * @private
954 * @param {string} name the folder's name
955 * @param {boolean=} [createFolders] If true, automatically create sub
956 *  folders. Defaults to false.
957 * @return {Object} the new folder.
958 */
959var folderAdd = function(name, createFolders) {
960    createFolders = (typeof createFolders !== 'undefined') ? createFolders : false;
961
962    name = forceTrailingSlash(name);
963
964    // Does this folder already exist?
965    if (!this.files[name]) {
966        fileAdd.call(this, name, null, {
967            dir: true,
968            createFolders: createFolders
969        });
970    }
971    return this.files[name];
972};
973
974/**
975 * Generate a JSZip.CompressedObject for a given zipOject.
976 * @param {ZipObject} file the object to read.
977 * @param {JSZip.compression} compression the compression to use.
978 * @param {Object} compressionOptions the options to use when compressing.
979 * @return {JSZip.CompressedObject} the compressed result.
980 */
981var generateCompressedObjectFrom = function(file, compression, compressionOptions) {
982    var result = new CompressedObject(),
983        content;
984
985    // the data has not been decompressed, we might reuse things !
986    if (file._data instanceof CompressedObject) {
987        result.uncompressedSize = file._data.uncompressedSize;
988        result.crc32 = file._data.crc32;
989
990        if (result.uncompressedSize === 0 || file.dir) {
991            compression = compressions['STORE'];
992            result.compressedContent = "";
993            result.crc32 = 0;
994        }
995        else if (file._data.compressionMethod === compression.magic) {
996            result.compressedContent = file._data.getCompressedContent();
997        }
998        else {
999            content = file._data.getContent();
1000            // need to decompress / recompress
1001            result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions);
1002        }
1003    }
1004    else {
1005        // have uncompressed data
1006        content = getBinaryData(file);
1007        if (!content || content.length === 0 || file.dir) {
1008            compression = compressions['STORE'];
1009            content = "";
1010        }
1011        result.uncompressedSize = content.length;
1012        result.crc32 = crc32(content);
1013        result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions);
1014    }
1015
1016    result.compressedSize = result.compressedContent.length;
1017    result.compressionMethod = compression.magic;
1018
1019    return result;
1020};
1021
1022
1023
1024
1025/**
1026 * Generate the UNIX part of the external file attributes.
1027 * @param {Object} unixPermissions the unix permissions or null.
1028 * @param {Boolean} isDir true if the entry is a directory, false otherwise.
1029 * @return {Number} a 32 bit integer.
1030 *
1031 * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute :
1032 *
1033 * TTTTsstrwxrwxrwx0000000000ADVSHR
1034 * ^^^^____________________________ file type, see zipinfo.c (UNX_*)
1035 *     ^^^_________________________ setuid, setgid, sticky
1036 *        ^^^^^^^^^________________ permissions
1037 *                 ^^^^^^^^^^______ not used ?
1038 *                           ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only
1039 */
1040var generateUnixExternalFileAttr = function (unixPermissions, isDir) {
1041
1042    var result = unixPermissions;
1043    if (!unixPermissions) {
1044        // I can't use octal values in strict mode, hence the hexa.
1045        //  040775 => 0x41fd
1046        // 0100664 => 0x81b4
1047        result = isDir ? 0x41fd : 0x81b4;
1048    }
1049
1050    return (result & 0xFFFF) << 16;
1051};
1052
1053/**
1054 * Generate the DOS part of the external file attributes.
1055 * @param {Object} dosPermissions the dos permissions or null.
1056 * @param {Boolean} isDir true if the entry is a directory, false otherwise.
1057 * @return {Number} a 32 bit integer.
1058 *
1059 * Bit 0     Read-Only
1060 * Bit 1     Hidden
1061 * Bit 2     System
1062 * Bit 3     Volume Label
1063 * Bit 4     Directory
1064 * Bit 5     Archive
1065 */
1066var generateDosExternalFileAttr = function (dosPermissions, isDir) {
1067
1068    // the dir flag is already set for compatibility
1069
1070    return (dosPermissions || 0)  & 0x3F;
1071};
1072
1073/**
1074 * Generate the various parts used in the construction of the final zip file.
1075 * @param {string} name the file name.
1076 * @param {ZipObject} file the file content.
1077 * @param {JSZip.CompressedObject} compressedObject the compressed object.
1078 * @param {number} offset the current offset from the start of the zip file.
1079 * @param {String} platform let's pretend we are this platform (change platform dependents fields)
1080 * @return {object} the zip parts.
1081 */
1082var generateZipParts = function(name, file, compressedObject, offset, platform) {
1083    var data = compressedObject.compressedContent,
1084        utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)),
1085        comment = file.comment || "",
1086        utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)),
1087        useUTF8ForFileName = utfEncodedFileName.length !== file.name.length,
1088        useUTF8ForComment = utfEncodedComment.length !== comment.length,
1089        o = file.options,
1090        dosTime,
1091        dosDate,
1092        extraFields = "",
1093        unicodePathExtraField = "",
1094        unicodeCommentExtraField = "",
1095        dir, date;
1096
1097
1098    // handle the deprecated options.dir
1099    if (file._initialMetadata.dir !== file.dir) {
1100        dir = file.dir;
1101    } else {
1102        dir = o.dir;
1103    }
1104
1105    // handle the deprecated options.date
1106    if(file._initialMetadata.date !== file.date) {
1107        date = file.date;
1108    } else {
1109        date = o.date;
1110    }
1111
1112    var extFileAttr = 0;
1113    var versionMadeBy = 0;
1114    if (dir) {
1115        // dos or unix, we set the dos dir flag
1116        extFileAttr |= 0x00010;
1117    }
1118    if(platform === "UNIX") {
1119        versionMadeBy = 0x031E; // UNIX, version 3.0
1120        extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir);
1121    } else { // DOS or other, fallback to DOS
1122        versionMadeBy = 0x0014; // DOS, version 2.0
1123        extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir);
1124    }
1125
1126    // date
1127    // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html
1128    // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html
1129    // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
1130
1131    dosTime = date.getHours();
1132    dosTime = dosTime << 6;
1133    dosTime = dosTime | date.getMinutes();
1134    dosTime = dosTime << 5;
1135    dosTime = dosTime | date.getSeconds() / 2;
1136
1137    dosDate = date.getFullYear() - 1980;
1138    dosDate = dosDate << 4;
1139    dosDate = dosDate | (date.getMonth() + 1);
1140    dosDate = dosDate << 5;
1141    dosDate = dosDate | date.getDate();
1142
1143    if (useUTF8ForFileName) {
1144        // set the unicode path extra field. unzip needs at least one extra
1145        // field to correctly handle unicode path, so using the path is as good
1146        // as any other information. This could improve the situation with
1147        // other archive managers too.
1148        // This field is usually used without the utf8 flag, with a non
1149        // unicode path in the header (winrar, winzip). This helps (a bit)
1150        // with the messy Windows' default compressed folders feature but
1151        // breaks on p7zip which doesn't seek the unicode path extra field.
1152        // So for now, UTF-8 everywhere !
1153        unicodePathExtraField =
1154            // Version
1155            decToHex(1, 1) +
1156            // NameCRC32
1157            decToHex(crc32(utfEncodedFileName), 4) +
1158            // UnicodeName
1159            utfEncodedFileName;
1160
1161        extraFields +=
1162            // Info-ZIP Unicode Path Extra Field
1163            "\x75\x70" +
1164            // size
1165            decToHex(unicodePathExtraField.length, 2) +
1166            // content
1167            unicodePathExtraField;
1168    }
1169
1170    if(useUTF8ForComment) {
1171
1172        unicodeCommentExtraField =
1173            // Version
1174            decToHex(1, 1) +
1175            // CommentCRC32
1176            decToHex(this.crc32(utfEncodedComment), 4) +
1177            // UnicodeName
1178            utfEncodedComment;
1179
1180        extraFields +=
1181            // Info-ZIP Unicode Path Extra Field
1182            "\x75\x63" +
1183            // size
1184            decToHex(unicodeCommentExtraField.length, 2) +
1185            // content
1186            unicodeCommentExtraField;
1187    }
1188
1189    var header = "";
1190
1191    // version needed to extract
1192    header += "\x0A\x00";
1193    // general purpose bit flag
1194    // set bit 11 if utf8
1195    header += (useUTF8ForFileName || useUTF8ForComment) ? "\x00\x08" : "\x00\x00";
1196    // compression method
1197    header += compressedObject.compressionMethod;
1198    // last mod file time
1199    header += decToHex(dosTime, 2);
1200    // last mod file date
1201    header += decToHex(dosDate, 2);
1202    // crc-32
1203    header += decToHex(compressedObject.crc32, 4);
1204    // compressed size
1205    header += decToHex(compressedObject.compressedSize, 4);
1206    // uncompressed size
1207    header += decToHex(compressedObject.uncompressedSize, 4);
1208    // file name length
1209    header += decToHex(utfEncodedFileName.length, 2);
1210    // extra field length
1211    header += decToHex(extraFields.length, 2);
1212
1213
1214    var fileRecord = signature.LOCAL_FILE_HEADER + header + utfEncodedFileName + extraFields;
1215
1216    var dirRecord = signature.CENTRAL_FILE_HEADER +
1217    // version made by (00: DOS)
1218    decToHex(versionMadeBy, 2) +
1219    // file header (common to file and central directory)
1220    header +
1221    // file comment length
1222    decToHex(utfEncodedComment.length, 2) +
1223    // disk number start
1224    "\x00\x00" +
1225    // internal file attributes TODO
1226    "\x00\x00" +
1227    // external file attributes
1228    decToHex(extFileAttr, 4) +
1229    // relative offset of local header
1230    decToHex(offset, 4) +
1231    // file name
1232    utfEncodedFileName +
1233    // extra field
1234    extraFields +
1235    // file comment
1236    utfEncodedComment;
1237
1238    return {
1239        fileRecord: fileRecord,
1240        dirRecord: dirRecord,
1241        compressedObject: compressedObject
1242    };
1243};
1244
1245
1246// return the actual prototype of JSZip
1247var out = {
1248    /**
1249     * Read an existing zip and merge the data in the current JSZip object.
1250     * The implementation is in jszip-load.js, don't forget to include it.
1251     * @param {String|ArrayBuffer|Uint8Array|Buffer} stream  The stream to load
1252     * @param {Object} options Options for loading the stream.
1253     *  options.base64 : is the stream in base64 ? default : false
1254     * @return {JSZip} the current JSZip object
1255     */
1256    load: function(stream, options) {
1257        throw new Error("Load method is not defined. Is the file jszip-load.js included ?");
1258    },
1259
1260    /**
1261     * Filter nested files/folders with the specified function.
1262     * @param {Function} search the predicate to use :
1263     * function (relativePath, file) {...}
1264     * It takes 2 arguments : the relative path and the file.
1265     * @return {Array} An array of matching elements.
1266     */
1267    filter: function(search) {
1268        var result = [],
1269            filename, relativePath, file, fileClone;
1270        for (filename in this.files) {
1271            if (!this.files.hasOwnProperty(filename)) {
1272                continue;
1273            }
1274            file = this.files[filename];
1275            // return a new object, don't let the user mess with our internal objects :)
1276            fileClone = new ZipObject(file.name, file._data, extend(file.options));
1277            relativePath = filename.slice(this.root.length, filename.length);
1278            if (filename.slice(0, this.root.length) === this.root && // the file is in the current root
1279            search(relativePath, fileClone)) { // and the file matches the function
1280                result.push(fileClone);
1281            }
1282        }
1283        return result;
1284    },
1285
1286    /**
1287     * Add a file to the zip file, or search a file.
1288     * @param   {string|RegExp} name The name of the file to add (if data is defined),
1289     * the name of the file to find (if no data) or a regex to match files.
1290     * @param   {String|ArrayBuffer|Uint8Array|Buffer} data  The file data, either raw or base64 encoded
1291     * @param   {Object} o     File options
1292     * @return  {JSZip|Object|Array} this JSZip object (when adding a file),
1293     * a file (when searching by string) or an array of files (when searching by regex).
1294     */
1295    file: function(name, data, o) {
1296        if (arguments.length === 1) {
1297            if (utils.isRegExp(name)) {
1298                var regexp = name;
1299                return this.filter(function(relativePath, file) {
1300                    return !file.dir && regexp.test(relativePath);
1301                });
1302            }
1303            else { // text
1304                return this.filter(function(relativePath, file) {
1305                    return !file.dir && relativePath === name;
1306                })[0] || null;
1307            }
1308        }
1309        else { // more than one argument : we have data !
1310            name = this.root + name;
1311            fileAdd.call(this, name, data, o);
1312        }
1313        return this;
1314    },
1315
1316    /**
1317     * Add a directory to the zip file, or search.
1318     * @param   {String|RegExp} arg The name of the directory to add, or a regex to search folders.
1319     * @return  {JSZip} an object with the new directory as the root, or an array containing matching folders.
1320     */
1321    folder: function(arg) {
1322        if (!arg) {
1323            return this;
1324        }
1325
1326        if (utils.isRegExp(arg)) {
1327            return this.filter(function(relativePath, file) {
1328                return file.dir && arg.test(relativePath);
1329            });
1330        }
1331
1332        // else, name is a new folder
1333        var name = this.root + arg;
1334        var newFolder = folderAdd.call(this, name);
1335
1336        // Allow chaining by returning a new object with this folder as the root
1337        var ret = this.clone();
1338        ret.root = newFolder.name;
1339        return ret;
1340    },
1341
1342    /**
1343     * Delete a file, or a directory and all sub-files, from the zip
1344     * @param {string} name the name of the file to delete
1345     * @return {JSZip} this JSZip object
1346     */
1347    remove: function(name) {
1348        name = this.root + name;
1349        var file = this.files[name];
1350        if (!file) {
1351            // Look for any folders
1352            if (name.slice(-1) != "/") {
1353                name += "/";
1354            }
1355            file = this.files[name];
1356        }
1357
1358        if (file && !file.dir) {
1359            // file
1360            delete this.files[name];
1361        } else {
1362            // maybe a folder, delete recursively
1363            var kids = this.filter(function(relativePath, file) {
1364                return file.name.slice(0, name.length) === name;
1365            });
1366            for (var i = 0; i < kids.length; i++) {
1367                delete this.files[kids[i].name];
1368            }
1369        }
1370
1371        return this;
1372    },
1373
1374    /**
1375     * Generate the complete zip file
1376     * @param {Object} options the options to generate the zip file :
1377     * - base64, (deprecated, use type instead) true to generate base64.
1378     * - compression, "STORE" by default.
1379     * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob.
1380     * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file
1381     */
1382    generate: function(options) {
1383        options = extend(options || {}, {
1384            base64: true,
1385            compression: "STORE",
1386            compressionOptions : null,
1387            type: "base64",
1388            platform: "DOS",
1389            comment: null,
1390            mimeType: 'application/zip'
1391        });
1392
1393        utils.checkSupport(options.type);
1394
1395        // accept nodejs `process.platform`
1396        if(
1397          options.platform === 'darwin' ||
1398          options.platform === 'freebsd' ||
1399          options.platform === 'linux' ||
1400          options.platform === 'sunos'
1401        ) {
1402          options.platform = "UNIX";
1403        }
1404        if (options.platform === 'win32') {
1405          options.platform = "DOS";
1406        }
1407
1408        var zipData = [],
1409            localDirLength = 0,
1410            centralDirLength = 0,
1411            writer, i,
1412            utfEncodedComment = utils.transformTo("string", this.utf8encode(options.comment || this.comment || ""));
1413
1414        // first, generate all the zip parts.
1415        for (var name in this.files) {
1416            if (!this.files.hasOwnProperty(name)) {
1417                continue;
1418            }
1419            var file = this.files[name];
1420
1421            var compressionName = file.options.compression || options.compression.toUpperCase();
1422            var compression = compressions[compressionName];
1423            if (!compression) {
1424                throw new Error(compressionName + " is not a valid compression method !");
1425            }
1426            var compressionOptions = file.options.compressionOptions || options.compressionOptions || {};
1427
1428            var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions);
1429
1430            var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform);
1431            localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize;
1432            centralDirLength += zipPart.dirRecord.length;
1433            zipData.push(zipPart);
1434        }
1435
1436        var dirEnd = "";
1437
1438        // end of central dir signature
1439        dirEnd = signature.CENTRAL_DIRECTORY_END +
1440        // number of this disk
1441        "\x00\x00" +
1442        // number of the disk with the start of the central directory
1443        "\x00\x00" +
1444        // total number of entries in the central directory on this disk
1445        decToHex(zipData.length, 2) +
1446        // total number of entries in the central directory
1447        decToHex(zipData.length, 2) +
1448        // size of the central directory   4 bytes
1449        decToHex(centralDirLength, 4) +
1450        // offset of start of central directory with respect to the starting disk number
1451        decToHex(localDirLength, 4) +
1452        // .ZIP file comment length
1453        decToHex(utfEncodedComment.length, 2) +
1454        // .ZIP file comment
1455        utfEncodedComment;
1456
1457
1458        // we have all the parts (and the total length)
1459        // time to create a writer !
1460        var typeName = options.type.toLowerCase();
1461        if(typeName==="uint8array"||typeName==="arraybuffer"||typeName==="blob"||typeName==="nodebuffer") {
1462            writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length);
1463        }else{
1464            writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length);
1465        }
1466
1467        for (i = 0; i < zipData.length; i++) {
1468            writer.append(zipData[i].fileRecord);
1469            writer.append(zipData[i].compressedObject.compressedContent);
1470        }
1471        for (i = 0; i < zipData.length; i++) {
1472            writer.append(zipData[i].dirRecord);
1473        }
1474
1475        writer.append(dirEnd);
1476
1477        var zip = writer.finalize();
1478
1479
1480
1481        switch(options.type.toLowerCase()) {
1482            // case "zip is an Uint8Array"
1483            case "uint8array" :
1484            case "arraybuffer" :
1485            case "nodebuffer" :
1486               return utils.transformTo(options.type.toLowerCase(), zip);
1487            case "blob" :
1488               return utils.arrayBuffer2Blob(utils.transformTo("arraybuffer", zip), options.mimeType
vendor: 13,868 bytes, lines 1488-1954
1488);
1489            // case "zip is a string"
1490            case "base64" :
1491               return (options.base64) ? base64.encode(zip) : zip;
1492            default : // case "string" :
1493               return zip;
1494         }
1495
1496    },
1497
1498    /**
1499     * @deprecated
1500     * This method will be removed in a future version without replacement.
1501     */
1502    crc32: function (input, crc) {
1503        return crc32(input, crc);
1504    },
1505
1506    /**
1507     * @deprecated
1508     * This method will be removed in a future version without replacement.
1509     */
1510    utf8encode: function (string) {
1511        return utils.transformTo("string", utf8.utf8encode(string));
1512    },
1513
1514    /**
1515     * @deprecated
1516     * This method will be removed in a future version without replacement.
1517     */
1518    utf8decode: function (input) {
1519        return utf8.utf8decode(input);
1520    }
1521};
1522module.exports = out;
1523
1524},{"./base64":1,"./compressedObject":2,"./compressions":3,"./crc32":4,"./defaults":6,"./nodeBuffer":11,"./signature":14,"./stringWriter":16,"./support":17,"./uint8ArrayWriter":19,"./utf8":20,"./utils":21}],14:[function(_dereq_,module,exports){
1525'use strict';
1526exports.LOCAL_FILE_HEADER = "PK\x03\x04";
1527exports.CENTRAL_FILE_HEADER = "PK\x01\x02";
1528exports.CENTRAL_DIRECTORY_END = "PK\x05\x06";
1529exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07";
1530exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06";
1531exports.DATA_DESCRIPTOR = "PK\x07\x08";
1532
1533},{}],15:[function(_dereq_,module,exports){
1534'use strict';
1535var DataReader = _dereq_('./dataReader');
1536var utils = _dereq_('./utils');
1537
1538function StringReader(data, optimizedBinaryString) {
1539    this.data = data;
1540    if (!optimizedBinaryString) {
1541        this.data = utils.string2binary(this.data);
1542    }
1543    this.length = this.data.length;
1544    this.index = 0;
1545}
1546StringReader.prototype = new DataReader();
1547/**
1548 * @see DataReader.byteAt
1549 */
1550StringReader.prototype.byteAt = function(i) {
1551    return this.data.charCodeAt(i);
1552};
1553/**
1554 * @see DataReader.lastIndexOfSignature
1555 */
1556StringReader.prototype.lastIndexOfSignature = function(sig) {
1557    return this.data.lastIndexOf(sig);
1558};
1559/**
1560 * @see DataReader.readData
1561 */
1562StringReader.prototype.readData = function(size) {
1563    this.checkOffset(size);
1564    // this will work because the constructor applied the "& 0xff" mask.
1565    var result = this.data.slice(this.index, this.index + size);
1566    this.index += size;
1567    return result;
1568};
1569module.exports = StringReader;
1570
1571},{"./dataReader":5,"./utils":21}],16:[function(_dereq_,module,exports){
1572'use strict';
1573
1574var utils = _dereq_('./utils');
1575
1576/**
1577 * An object to write any content to a string.
1578 * @constructor
1579 */
1580var StringWriter = function() {
1581    this.data = [];
1582};
1583StringWriter.prototype = {
1584    /**
1585     * Append any content to the current string.
1586     * @param {Object} input the content to add.
1587     */
1588    append: function(input) {
1589        input = utils.transformTo("string", input);
1590        this.data.push(input);
1591    },
1592    /**
1593     * Finalize the construction an return the result.
1594     * @return {string} the generated string.
1595     */
1596    finalize: function() {
1597        return this.data.join("");
1598    }
1599};
1600
1601module.exports = StringWriter;
1602
1603},{"./utils":21}],17:[function(_dereq_,module,exports){
1604(function (Buffer){
1605'use strict';
1606exports.base64 = true;
1607exports.array = true;
1608exports.string = true;
1609exports.arraybuffer = typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined";
1610// contains true if JSZip can read/generate nodejs Buffer, false otherwise.
1611// Browserify will provide a Buffer implementation for browsers, which is
1612// an augmented Uint8Array (i.e., can be used as either Buffer or U8).
1613exports.nodebuffer = typeof Buffer !== "undefined";
1614// contains true if JSZip can read/generate Uint8Array, false otherwise.
1615exports.uint8array = typeof Uint8Array !== "undefined";
1616
1617if (typeof ArrayBuffer === "undefined") {
1618    exports.blob = false;
1619}
1620else {
1621    var buffer = new ArrayBuffer(0);
1622    try {
1623        exports.blob = new Blob([buffer], {
1624            type: "application/zip"
1625        }).size === 0;
1626    }
1627    catch (e) {
1628        try {
1629            var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
1630            var builder = new Builder();
1631            builder.append(buffer);
1632            exports.blob = builder.getBlob('application/zip').size === 0;
1633        }
1634        catch (e) {
1635            exports.blob = false;
1636        }
1637    }
1638}
1639
1640}).call(this,(typeof Buffer !== "undefined" ? Buffer : undefined))
1641},{}],18:[function(_dereq_,module,exports){
1642'use strict';
1643var DataReader = _dereq_('./dataReader');
1644
1645function Uint8ArrayReader(data) {
1646    if (data) {
1647        this.data = data;
1648        this.length = this.data.length;
1649        this.index = 0;
1650    }
1651}
1652Uint8ArrayReader.prototype = new DataReader();
1653/**
1654 * @see DataReader.byteAt
1655 */
1656Uint8ArrayReader.prototype.byteAt = function(i) {
1657    return this.data[i];
1658};
1659/**
1660 * @see DataReader.lastIndexOfSignature
1661 */
1662Uint8ArrayReader.prototype.lastIndexOfSignature = function(sig) {
1663    var sig0 = sig.charCodeAt(0),
1664        sig1 = sig.charCodeAt(1),
1665        sig2 = sig.charCodeAt(2),
1666        sig3 = sig.charCodeAt(3);
1667    for (var i = this.length - 4; i >= 0; --i) {
1668        if (this.data[i] === sig0 && this.data[i + 1] === sig1 && this.data[i + 2] === sig2 && this.data[i + 3] === sig3) {
1669            return i;
1670        }
1671    }
1672
1673    return -1;
1674};
1675/**
1676 * @see DataReader.readData
1677 */
1678Uint8ArrayReader.prototype.readData = function(size) {
1679    this.checkOffset(size);
1680    if(size === 0) {
1681        // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of [].
1682        return new Uint8Array(0);
1683    }
1684    var result = this.data.subarray(this.index, this.index + size);
1685    this.index += size;
1686    return result;
1687};
1688module.exports = Uint8ArrayReader;
1689
1690},{"./dataReader":5}],19:[function(_dereq_,module,exports){
1691'use strict';
1692
1693var utils = _dereq_('./utils');
1694
1695/**
1696 * An object to write any content to an Uint8Array.
1697 * @constructor
1698 * @param {number} length The length of the array.
1699 */
1700var Uint8ArrayWriter = function(length) {
1701    this.data = new Uint8Array(length);
1702    this.index = 0;
1703};
1704Uint8ArrayWriter.prototype = {
1705    /**
1706     * Append any content to the current array.
1707     * @param {Object} input the content to add.
1708     */
1709    append: function(input) {
1710        if (input.length !== 0) {
1711            // with an empty Uint8Array, Opera fails with a "Offset larger than array size"
1712            input = utils.transformTo("uint8array", input);
1713            this.data.set(input, this.index);
1714            this.index += input.length;
1715        }
1716    },
1717    /**
1718     * Finalize the construction an return the result.
1719     * @return {Uint8Array} the generated array.
1720     */
1721    finalize: function() {
1722        return this.data;
1723    }
1724};
1725
1726module.exports = Uint8ArrayWriter;
1727
1728},{"./utils":21}],20:[function(_dereq_,module,exports){
1729'use strict';
1730
1731var utils = _dereq_('./utils');
1732var support = _dereq_('./support');
1733var nodeBuffer = _dereq_('./nodeBuffer');
1734
1735/**
1736 * The following functions come from pako, from pako/lib/utils/strings
1737 * released under the MIT license, see pako https://github.com/nodeca/pako/
1738 */
1739
1740// Table with utf8 lengths (calculated by first byte of sequence)
1741// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
1742// because max possible codepoint is 0x10ffff
1743var _utf8len = new Array(256);
1744for (var i=0; i<256; i++) {
1745  _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);
1746}
1747_utf8len[254]=_utf8len[254]=1; // Invalid sequence start
1748
1749// convert string to array (typed, when possible)
1750var string2buf = function (str) {
1751    var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
1752
1753    // count binary size
1754    for (m_pos = 0; m_pos < str_len; m_pos++) {
1755        c = str.charCodeAt(m_pos);
1756        if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
1757            c2 = str.charCodeAt(m_pos+1);
1758            if ((c2 & 0xfc00) === 0xdc00) {
1759                c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
1760                m_pos++;
1761            }
1762        }
1763        buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
1764    }
1765
1766    // allocate buffer
1767    if (support.uint8array) {
1768        buf = new Uint8Array(buf_len);
1769    } else {
1770        buf = new Array(buf_len);
1771    }
1772
1773    // convert
1774    for (i=0, m_pos = 0; i < buf_len; m_pos++) {
1775        c = str.charCodeAt(m_pos);
1776        if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
1777            c2 = str.charCodeAt(m_pos+1);
1778            if ((c2 & 0xfc00) === 0xdc00) {
1779                c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
1780                m_pos++;
1781            }
1782        }
1783        if (c < 0x80) {
1784            /* one byte */
1785            buf[i++] = c;
1786        } else if (c < 0x800) {
1787            /* two bytes */
1788            buf[i++] = 0xC0 | (c >>> 6);
1789            buf[i++] = 0x80 | (c & 0x3f);
1790        } else if (c < 0x10000) {
1791            /* three bytes */
1792            buf[i++] = 0xE0 | (c >>> 12);
1793            buf[i++] = 0x80 | (c >>> 6 & 0x3f);
1794            buf[i++] = 0x80 | (c & 0x3f);
1795        } else {
1796            /* four bytes */
1797            buf[i++] = 0xf0 | (c >>> 18);
1798            buf[i++] = 0x80 | (c >>> 12 & 0x3f);
1799            buf[i++] = 0x80 | (c >>> 6 & 0x3f);
1800            buf[i++] = 0x80 | (c & 0x3f);
1801        }
1802    }
1803
1804    return buf;
1805};
1806
1807// Calculate max possible position in utf8 buffer,
1808// that will not break sequence. If that's not possible
1809// - (very small limits) return max size as is.
1810//
1811// buf[] - utf8 bytes array
1812// max   - length limit (mandatory);
1813var utf8border = function(buf, max) {
1814    var pos;
1815
1816    max = max || buf.length;
1817    if (max > buf.length) { max = buf.length; }
1818
1819    // go back from last position, until start of sequence found
1820    pos = max-1;
1821    while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
1822
1823    // Fuckup - very small and broken sequence,
1824    // return max, because we should return something anyway.
1825    if (pos < 0) { return max; }
1826
1827    // If we came to start of buffer - that means vuffer is too small,
1828    // return max too.
1829    if (pos === 0) { return max; }
1830
1831    return (pos + _utf8len[buf[pos]] > max) ? pos : max;
1832};
1833
1834// convert array to string
1835var buf2string = function (buf) {
1836    var str, i, out, c, c_len;
1837    var len = buf.length;
1838
1839    // Reserve max possible length (2 words per char)
1840    // NB: by unknown reasons, Array is significantly faster for
1841    //     String.fromCharCode.apply than Uint16Array.
1842    var utf16buf = new Array(len*2);
1843
1844    for (out=0, i=0; i<len;) {
1845        c = buf[i++];
1846        // quick process ascii
1847        if (c < 0x80) { utf16buf[out++] = c; continue; }
1848
1849        c_len = _utf8len[c];
1850        // skip 5 & 6 byte codes
1851        if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }
1852
1853        // apply mask on first byte
1854        c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
1855        // join the rest
1856        while (c_len > 1 && i < len) {
1857            c = (c << 6) | (buf[i++] & 0x3f);
1858            c_len--;
1859        }
1860
1861        // terminated by end of string?
1862        if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
1863
1864        if (c < 0x10000) {
1865            utf16buf[out++] = c;
1866        } else {
1867            c -= 0x10000;
1868            utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
1869            utf16buf[out++] = 0xdc00 | (c & 0x3ff);
1870        }
1871    }
1872
1873    // shrinkBuf(utf16buf, out)
1874    if (utf16buf.length !== out) {
1875        if(utf16buf.subarray) {
1876            utf16buf = utf16buf.subarray(0, out);
1877        } else {
1878            utf16buf.length = out;
1879        }
1880    }
1881
1882    // return String.fromCharCode.apply(null, utf16buf);
1883    return utils.applyFromCharCode(utf16buf);
1884};
1885
1886
1887// That's all for the pako functions.
1888
1889
1890/**
1891 * Transform a javascript string into an array (typed if possible) of bytes,
1892 * UTF-8 encoded.
1893 * @param {String} str the string to encode
1894 * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string.
1895 */
1896exports.utf8encode = function utf8encode(str) {
1897    if (support.nodebuffer) {
1898        return nodeBuffer(str, "utf-8");
1899    }
1900
1901    return string2buf(str);
1902};
1903
1904
1905/**
1906 * Transform a bytes array (or a representation) representing an UTF-8 encoded
1907 * string into a javascript string.
1908 * @param {Array|Uint8Array|Buffer} buf the data de decode
1909 * @return {String} the decoded string.
1910 */
1911exports.utf8decode = function utf8decode(buf) {
1912    if (support.nodebuffer) {
1913        return utils.transformTo("nodebuffer", buf).toString("utf-8");
1914    }
1915
1916    buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf);
1917
1918    // return buf2string(buf);
1919    // Chrome prefers to work with "small" chunks of data
1920    // for the method buf2string.
1921    // Firefox and Chrome has their own shortcut, IE doesn't seem to really care.
1922    var result = [], k = 0, len = buf.length, chunk = 65536;
1923    while (k < len) {
1924        var nextBoundary = utf8border(buf, Math.min(k + chunk, len));
1925        if (support.uint8array) {
1926            result.push(buf2string(buf.subarray(k, nextBoundary)));
1927        } else {
1928            result.push(buf2string(buf.slice(k, nextBoundary)));
1929        }
1930        k = nextBoundary;
1931    }
1932    return result.join("");
1933
1934};
1935// vim: set shiftwidth=4 softtabstop=4:
1936
1937},{"./nodeBuffer":11,"./support":17,"./utils":21}],21:[function(_dereq_,module,exports){
1938'use strict';
1939var support = _dereq_('./support');
1940var compressions = _dereq_('./compressions');
1941var nodeBuffer = _dereq_('./nodeBuffer');
1942/**
1943 * Convert a string to a "binary string" : a string containing only char codes between 0 and 255.
1944 * @param {string} str the string to transform.
1945 * @return {String} the binary string.
1946 */
1947exports.string2binary = function(str) {
1948    var result = "";
1949    for (var i = 0; i < str.length; i++) {
1950        result += String.fromCharCode(str.charCodeAt(i) & 0xff);
1951    }
1952    return result;
1953};
1954exports.arrayBuffer2Blob = function(buffer
1954, mimeType) {
1955    exports.checkSupport("blob");
1956	mimeType = mimeType || 'application/zip';
1957
1958    try {
1959        // Blob constructor
1960        return new Blob([buffer], {
1961            type: mimeType
1962        });
1963    }
1964    catch (e) {
1965
1966        try {
1967            // deprecated, browser only, old way
1968            var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
1969            var builder = new Builder();
1970            builder.append(buffer);
1971            return builder.getBlob(mimeType
vendor: 13,328 bytes, lines 1971-2377
1971);
1972        }
1973        catch (e) {
1974
1975            // well, fuck ?!
1976            throw new Error("Bug : can't construct the Blob.");
1977        }
1978    }
1979
1980
1981};
1982/**
1983 * The identity function.
1984 * @param {Object} input the input.
1985 * @return {Object} the same input.
1986 */
1987function identity(input) {
1988    return input;
1989}
1990
1991/**
1992 * Fill in an array with a string.
1993 * @param {String} str the string to use.
1994 * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated).
1995 * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array.
1996 */
1997function stringToArrayLike(str, array) {
1998    for (var i = 0; i < str.length; ++i) {
1999        array[i] = str.charCodeAt(i) & 0xFF;
2000    }
2001    return array;
2002}
2003
2004/**
2005 * Transform an array-like object to a string.
2006 * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.
2007 * @return {String} the result.
2008 */
2009function arrayLikeToString(array) {
2010    // Performances notes :
2011    // --------------------
2012    // String.fromCharCode.apply(null, array) is the fastest, see
2013    // see http://jsperf.com/converting-a-uint8array-to-a-string/2
2014    // but the stack is limited (and we can get huge arrays !).
2015    //
2016    // result += String.fromCharCode(array[i]); generate too many strings !
2017    //
2018    // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2
2019    var chunk = 65536;
2020    var result = [],
2021        len = array.length,
2022        type = exports.getTypeOf(array),
2023        k = 0,
2024        canUseApply = true;
2025      try {
2026         switch(type) {
2027            case "uint8array":
2028               String.fromCharCode.apply(null, new Uint8Array(0));
2029               break;
2030            case "nodebuffer":
2031               String.fromCharCode.apply(null, nodeBuffer(0));
2032               break;
2033         }
2034      } catch(e) {
2035         canUseApply = false;
2036      }
2037
2038      // no apply : slow and painful algorithm
2039      // default browser on android 4.*
2040      if (!canUseApply) {
2041         var resultStr = "";
2042         for(var i = 0; i < array.length;i++) {
2043            resultStr += String.fromCharCode(array[i]);
2044         }
2045    return resultStr;
2046    }
2047    while (k < len && chunk > 1) {
2048        try {
2049            if (type === "array" || type === "nodebuffer") {
2050                result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len))));
2051            }
2052            else {
2053                result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len))));
2054            }
2055            k += chunk;
2056        }
2057        catch (e) {
2058            chunk = Math.floor(chunk / 2);
2059        }
2060    }
2061    return result.join("");
2062}
2063
2064exports.applyFromCharCode = arrayLikeToString;
2065
2066
2067/**
2068 * Copy the data from an array-like to an other array-like.
2069 * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array.
2070 * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated.
2071 * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array.
2072 */
2073function arrayLikeToArrayLike(arrayFrom, arrayTo) {
2074    for (var i = 0; i < arrayFrom.length; i++) {
2075        arrayTo[i] = arrayFrom[i];
2076    }
2077    return arrayTo;
2078}
2079
2080// a matrix containing functions to transform everything into everything.
2081var transform = {};
2082
2083// string to ?
2084transform["string"] = {
2085    "string": identity,
2086    "array": function(input) {
2087        return stringToArrayLike(input, new Array(input.length));
2088    },
2089    "arraybuffer": function(input) {
2090        return transform["string"]["uint8array"](input).buffer;
2091    },
2092    "uint8array": function(input) {
2093        return stringToArrayLike(input, new Uint8Array(input.length));
2094    },
2095    "nodebuffer": function(input) {
2096        return stringToArrayLike(input, nodeBuffer(input.length));
2097    }
2098};
2099
2100// array to ?
2101transform["array"] = {
2102    "string": arrayLikeToString,
2103    "array": identity,
2104    "arraybuffer": function(input) {
2105        return (new Uint8Array(input)).buffer;
2106    },
2107    "uint8array": function(input) {
2108        return new Uint8Array(input);
2109    },
2110    "nodebuffer": function(input) {
2111        return nodeBuffer(input);
2112    }
2113};
2114
2115// arraybuffer to ?
2116transform["arraybuffer"] = {
2117    "string": function(input) {
2118        return arrayLikeToString(new Uint8Array(input));
2119    },
2120    "array": function(input) {
2121        return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength));
2122    },
2123    "arraybuffer": identity,
2124    "uint8array": function(input) {
2125        return new Uint8Array(input);
2126    },
2127    "nodebuffer": function(input) {
2128        return nodeBuffer(new Uint8Array(input));
2129    }
2130};
2131
2132// uint8array to ?
2133transform["uint8array"] = {
2134    "string": arrayLikeToString,
2135    "array": function(input) {
2136        return arrayLikeToArrayLike(input, new Array(input.length));
2137    },
2138    "arraybuffer": function(input) {
2139        return input.buffer;
2140    },
2141    "uint8array": identity,
2142    "nodebuffer": function(input) {
2143        return nodeBuffer(input);
2144    }
2145};
2146
2147// nodebuffer to ?
2148transform["nodebuffer"] = {
2149    "string": arrayLikeToString,
2150    "array": function(input) {
2151        return arrayLikeToArrayLike(input, new Array(input.length));
2152    },
2153    "arraybuffer": function(input) {
2154        return transform["nodebuffer"]["uint8array"](input).buffer;
2155    },
2156    "uint8array": function(input) {
2157        return arrayLikeToArrayLike(input, new Uint8Array(input.length));
2158    },
2159    "nodebuffer": identity
2160};
2161
2162/**
2163 * Transform an input into any type.
2164 * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer.
2165 * If no output type is specified, the unmodified input will be returned.
2166 * @param {String} outputType the output type.
2167 * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert.
2168 * @throws {Error} an Error if the browser doesn't support the requested output type.
2169 */
2170exports.transformTo = function(outputType, input) {
2171    if (!input) {
2172        // undefined, null, etc
2173        // an empty string won't harm.
2174        input = "";
2175    }
2176    if (!outputType) {
2177        return input;
2178    }
2179    exports.checkSupport(outputType);
2180    var inputType = exports.getTypeOf(input);
2181    var result = transform[inputType][outputType](input);
2182    return result;
2183};
2184
2185/**
2186 * Return the type of the input.
2187 * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer.
2188 * @param {Object} input the input to identify.
2189 * @return {String} the (lowercase) type of the input.
2190 */
2191exports.getTypeOf = function(input) {
2192    if (typeof input === "string") {
2193        return "string";
2194    }
2195    if (Object.prototype.toString.call(input) === "[object Array]") {
2196        return "array";
2197    }
2198    if (support.nodebuffer && nodeBuffer.test(input)) {
2199        return "nodebuffer";
2200    }
2201    if (support.uint8array && input instanceof Uint8Array) {
2202        return "uint8array";
2203    }
2204    if (support.arraybuffer && input instanceof ArrayBuffer) {
2205        return "arraybuffer";
2206    }
2207};
2208
2209/**
2210 * Throw an exception if the type is not supported.
2211 * @param {String} type the type to check.
2212 * @throws {Error} an Error if the browser doesn't support the requested type.
2213 */
2214exports.checkSupport = function(type) {
2215    var supported = support[type.toLowerCase()];
2216    if (!supported) {
2217        throw new Error(type + " is not supported by this browser");
2218    }
2219};
2220exports.MAX_VALUE_16BITS = 65535;
2221exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1
2222
2223/**
2224 * Prettify a string read as binary.
2225 * @param {string} str the string to prettify.
2226 * @return {string} a pretty string.
2227 */
2228exports.pretty = function(str) {
2229    var res = '',
2230        code, i;
2231    for (i = 0; i < (str || "").length; i++) {
2232        code = str.charCodeAt(i);
2233        res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase();
2234    }
2235    return res;
2236};
2237
2238/**
2239 * Find a compression registered in JSZip.
2240 * @param {string} compressionMethod the method magic to find.
2241 * @return {Object|null} the JSZip compression object, null if none found.
2242 */
2243exports.findCompression = function(compressionMethod) {
2244    for (var method in compressions) {
2245        if (!compressions.hasOwnProperty(method)) {
2246            continue;
2247        }
2248        if (compressions[method].magic === compressionMethod) {
2249            return compressions[method];
2250        }
2251    }
2252    return null;
2253};
2254/**
2255* Cross-window, cross-Node-context regular expression detection
2256* @param  {Object}  object Anything
2257* @return {Boolean}        true if the object is a regular expression,
2258* false otherwise
2259*/
2260exports.isRegExp = function (object) {
2261    return Object.prototype.toString.call(object) === "[object RegExp]";
2262};
2263
2264
2265},{"./compressions":3,"./nodeBuffer":11,"./support":17}],22:[function(_dereq_,module,exports){
2266'use strict';
2267var StringReader = _dereq_('./stringReader');
2268var NodeBufferReader = _dereq_('./nodeBufferReader');
2269var Uint8ArrayReader = _dereq_('./uint8ArrayReader');
2270var utils = _dereq_('./utils');
2271var sig = _dereq_('./signature');
2272var ZipEntry = _dereq_('./zipEntry');
2273var support = _dereq_('./support');
2274var jszipProto = _dereq_('./object');
2275//  class ZipEntries {{{
2276/**
2277 * All the entries in the zip file.
2278 * @constructor
2279 * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load.
2280 * @param {Object} loadOptions Options for loading the stream.
2281 */
2282function ZipEntries(data, loadOptions) {
2283    this.files = [];
2284    this.loadOptions = loadOptions;
2285    if (data) {
2286        this.load(data);
2287    }
2288}
2289ZipEntries.prototype = {
2290    /**
2291     * Check that the reader is on the speficied signature.
2292     * @param {string} expectedSignature the expected signature.
2293     * @throws {Error} if it is an other signature.
2294     */
2295    checkSignature: function(expectedSignature) {
2296        var signature = this.reader.readString(4);
2297        if (signature !== expectedSignature) {
2298            throw new Error("Corrupted zip or bug : unexpected signature " + "(" + utils.pretty(signature) + ", expected " + utils.pretty(expectedSignature) + ")");
2299        }
2300    },
2301    /**
2302     * Read the end of the central directory.
2303     */
2304    readBlockEndOfCentral: function() {
2305        this.diskNumber = this.reader.readInt(2);
2306        this.diskWithCentralDirStart = this.reader.readInt(2);
2307        this.centralDirRecordsOnThisDisk = this.reader.readInt(2);
2308        this.centralDirRecords = this.reader.readInt(2);
2309        this.centralDirSize = this.reader.readInt(4);
2310        this.centralDirOffset = this.reader.readInt(4);
2311
2312        this.zipCommentLength = this.reader.readInt(2);
2313        // warning : the encoding depends of the system locale
2314        // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded.
2315        // On a windows machine, this field is encoded with the localized windows code page.
2316        this.zipComment = this.reader.readString(this.zipCommentLength);
2317        // To get consistent behavior with the generation part, we will assume that
2318        // this is utf8 encoded.
2319        this.zipComment = jszipProto.utf8decode(this.zipComment);
2320    },
2321    /**
2322     * Read the end of the Zip 64 central directory.
2323     * Not merged with the method readEndOfCentral :
2324     * The end of central can coexist with its Zip64 brother,
2325     * I don't want to read the wrong number of bytes !
2326     */
2327    readBlockZip64EndOfCentral: function() {
2328        this.zip64EndOfCentralSize = this.reader.readInt(8);
2329        this.versionMadeBy = this.reader.readString(2);
2330        this.versionNeeded = this.reader.readInt(2);
2331        this.diskNumber = this.reader.readInt(4);
2332        this.diskWithCentralDirStart = this.reader.readInt(4);
2333        this.centralDirRecordsOnThisDisk = this.reader.readInt(8);
2334        this.centralDirRecords = this.reader.readInt(8);
2335        this.centralDirSize = this.reader.readInt(8);
2336        this.centralDirOffset = this.reader.readInt(8);
2337
2338        this.zip64ExtensibleData = {};
2339        var extraDataSize = this.zip64EndOfCentralSize - 44,
2340            index = 0,
2341            extraFieldId,
2342            extraFieldLength,
2343            extraFieldValue;
2344        while (index < extraDataSize) {
2345            extraFieldId = this.reader.readInt(2);
2346            extraFieldLength = this.reader.readInt(4);
2347            extraFieldValue = this.reader.readString(extraFieldLength);
2348            this.zip64ExtensibleData[extraFieldId] = {
2349                id: extraFieldId,
2350                length: extraFieldLength,
2351                value: extraFieldValue
2352            };
2353        }
2354    },
2355    /**
2356     * Read the end of the Zip 64 central directory locator.
2357     */
2358    readBlockZip64EndOfCentralLocator: function() {
2359        this.diskWithZip64CentralDirStart = this.reader.readInt(4);
2360        this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8);
2361        this.disksCount = this.reader.readInt(4);
2362        if (this.disksCount > 1) {
2363            throw new Error("Multi-volumes zip are not supported");
2364        }
2365    },
2366    /**
2367     * Read the local files, based on the offset read in the central part.
2368     */
2369    readLocalFiles: function() {
2370        var i, file;
2371        for (i = 0; i < this.files.length; i++) {
2372            file = this.files[i];
2373            this.reader.setIndex(file.localHeaderOffset);
2374            this.checkSignature(sig.LOCAL_FILE_HEADER);
2375            file.readLocalPart(this.reader);
2376            file.handleUTF8();
2377        
2377    file.processAttributes();
2378        }
2379    },
2380    /**
2381     * Read the central directory.
2382     */
2383    readCentralDir: function() {
2384        var file;
2385
2386        this.reader.setIndex(this.centralDirOffset);
2387        while (this.reader.readString(4) === sig.CENTRAL_FILE_HEADER) {
2388            file = new ZipEntry({
2389                zip64: this.zip64
2390            }, this.loadOptions);
2391            file.readCentralPart(this.reader);
2392            this.files.push(file);
2393        }
2394    },
2395    /**
2396     * Read the end of central directory.
2397     */
2398    readEndOfCentral: function() {
2399        var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END);
2400        if (offset === -1) {
2401            // Check if the content is a truncated zip or complete garbage.
2402            // A "LOCAL_FILE_HEADER" is not required at the beginning (auto
2403            // extractible zip for example) but it can give a good hint.
2404            // If an ajax request was used without responseType, we will also
2405            // get unreadable data.
2406            var isGarbage = true;
2407            try {
2408                this.reader.setIndex(0);
2409                this.checkSignature(sig.LOCAL_FILE_HEADER);
2410                isGarbage = false;
vendor: 8,072 bytes, lines 2411-2587
2411            } catch (e) {}
2412
2413            if (isGarbage) {
2414                throw new Error("Can't find end of central directory : is this a zip file ? " +
2415                                "If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html");
2416            } else {
2417                throw new Error("Corrupted zip : can't find end of central directory");
2418            }
2419        }
2420        this.reader.setIndex(offset);
2421        this.checkSignature(sig.CENTRAL_DIRECTORY_END);
2422        this.readBlockEndOfCentral();
2423
2424
2425        /* extract from the zip spec :
2426            4)  If one of the fields in the end of central directory
2427                record is too small to hold required data, the field
2428                should be set to -1 (0xFFFF or 0xFFFFFFFF) and the
2429                ZIP64 format record should be created.
2430            5)  The end of central directory record and the
2431                Zip64 end of central directory locator record must
2432                reside on the same disk when splitting or spanning
2433                an archive.
2434         */
2435        if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) {
2436            this.zip64 = true;
2437
2438            /*
2439            Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from
2440            the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents
2441            all numbers as 64-bit double precision IEEE 754 floating point numbers.
2442            So, we have 53bits for integers and bitwise operations treat everything as 32bits.
2443            see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
2444            and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5
2445            */
2446
2447            // should look for a zip64 EOCD locator
2448            offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
2449            if (offset === -1) {
2450                throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator");
2451            }
2452            this.reader.setIndex(offset);
2453            this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
2454            this.readBlockZip64EndOfCentralLocator();
2455
2456            // now the zip64 EOCD record
2457            this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);
2458            this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);
2459            this.readBlockZip64EndOfCentral();
2460        }
2461    },
2462    prepareReader: function(data) {
2463        var type = utils.getTypeOf(data);
2464        if (type === "string" && !support.uint8array) {
2465            this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString);
2466        }
2467        else if (type === "nodebuffer") {
2468            this.reader = new NodeBufferReader(data);
2469        }
2470        else {
2471            this.reader = new Uint8ArrayReader(utils.transformTo("uint8array", data));
2472        }
2473    },
2474    /**
2475     * Read a zip file and create ZipEntries.
2476     * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file.
2477     */
2478    load: function(data) {
2479        this.prepareReader(data);
2480        this.readEndOfCentral();
2481        this.readCentralDir();
2482        this.readLocalFiles();
2483    }
2484};
2485// }}} end of ZipEntries
2486module.exports = ZipEntries;
2487
2488},{"./nodeBufferReader":12,"./object":13,"./signature":14,"./stringReader":15,"./support":17,"./uint8ArrayReader":18,"./utils":21,"./zipEntry":23}],23:[function(_dereq_,module,exports){
2489'use strict';
2490var StringReader = _dereq_('./stringReader');
2491var utils = _dereq_('./utils');
2492var CompressedObject = _dereq_('./compressedObject');
2493var jszipProto = _dereq_('./object');
2494
2495var MADE_BY_DOS = 0x00;
2496var MADE_BY_UNIX = 0x03;
2497
2498// class ZipEntry {{{
2499/**
2500 * An entry in the zip file.
2501 * @constructor
2502 * @param {Object} options Options of the current file.
2503 * @param {Object} loadOptions Options for loading the stream.
2504 */
2505function ZipEntry(options, loadOptions) {
2506    this.options = options;
2507    this.loadOptions = loadOptions;
2508}
2509ZipEntry.prototype = {
2510    /**
2511     * say if the file is encrypted.
2512     * @return {boolean} true if the file is encrypted, false otherwise.
2513     */
2514    isEncrypted: function() {
2515        // bit 1 is set
2516        return (this.bitFlag & 0x0001) === 0x0001;
2517    },
2518    /**
2519     * say if the file has utf-8 filename/comment.
2520     * @return {boolean} true if the filename/comment is in utf-8, false otherwise.
2521     */
2522    useUTF8: function() {
2523        // bit 11 is set
2524        return (this.bitFlag & 0x0800) === 0x0800;
2525    },
2526    /**
2527     * Prepare the function used to generate the compressed content from this ZipFile.
2528     * @param {DataReader} reader the reader to use.
2529     * @param {number} from the offset from where we should read the data.
2530     * @param {number} length the length of the data to read.
2531     * @return {Function} the callback to get the compressed content (the type depends of the DataReader class).
2532     */
2533    prepareCompressedContent: function(reader, from, length) {
2534        return function() {
2535            var previousIndex = reader.index;
2536            reader.setIndex(from);
2537            var compressedFileData = reader.readData(length);
2538            reader.setIndex(previousIndex);
2539
2540            return compressedFileData;
2541        };
2542    },
2543    /**
2544     * Prepare the function used to generate the uncompressed content from this ZipFile.
2545     * @param {DataReader} reader the reader to use.
2546     * @param {number} from the offset from where we should read the data.
2547     * @param {number} length the length of the data to read.
2548     * @param {JSZip.compression} compression the compression used on this file.
2549     * @param {number} uncompressedSize the uncompressed size to expect.
2550     * @return {Function} the callback to get the uncompressed content (the type depends of the DataReader class).
2551     */
2552    prepareContent: function(reader, from, length, compression, uncompressedSize) {
2553        return function() {
2554
2555            var compressedFileData = utils.transformTo(compression.uncompressInputType, this.getCompressedContent());
2556            var uncompressedFileData = compression.uncompress(compressedFileData);
2557
2558            if (uncompressedFileData.length !== uncompressedSize) {
2559                throw new Error("Bug : uncompressed data size mismatch");
2560            }
2561
2562            return uncompressedFileData;
2563        };
2564    },
2565    /**
2566     * Read the local part of a zip file and add the info in this object.
2567     * @param {DataReader} reader the reader to use.
2568     */
2569    readLocalPart: function(reader) {
2570        var compression, localExtraFieldsLength;
2571
2572        // we already know everything from the central dir !
2573        // If the central dir data are false, we are doomed.
2574        // On the bright side, the local part is scary  : zip64, data descriptors, both, etc.
2575        // The less data we get here, the more reliable this should be.
2576        // Let's skip the whole header and dash to the data !
2577        reader.skip(22);
2578        // in some zip created on windows, the filename stored in the central dir contains \ instead of /.
2579        // Strangely, the filename here is OK.
2580        // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes
2581        // or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators...
2582        // Search "unzip mismatching "local" filename continuing with "central" filename version" on
2583        // the internet.
2584        //
2585        // I think I see the logic here : the central directory is used to display
2586        // content and the local directory is used to extract the files. Mixing / and \
2587        // may be used to display \ to windows users and use / when extracting the files.
vendor: 4,164 bytes, lines 2588-2677
2588        // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394
2589        this.fileNameLength = reader.readInt(2);
2590        localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir
2591        this.fileName = reader.readString(this.fileNameLength);
2592        reader.skip(localExtraFieldsLength);
2593
2594        if (this.compressedSize == -1 || this.uncompressedSize == -1) {
2595            throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory " + "(compressedSize == -1 || uncompressedSize == -1)");
2596        }
2597
2598        compression = utils.findCompression(this.compressionMethod);
2599        if (compression === null) { // no compression found
2600            throw new Error("Corrupted zip : compression " + utils.pretty(this.compressionMethod) + " unknown (inner file : " + this.fileName + ")");
2601        }
2602        this.decompressed = new CompressedObject();
2603        this.decompressed.compressedSize = this.compressedSize;
2604        this.decompressed.uncompressedSize = this.uncompressedSize;
2605        this.decompressed.crc32 = this.crc32;
2606        this.decompressed.compressionMethod = this.compressionMethod;
2607        this.decompressed.getCompressedContent = this.prepareCompressedContent(reader, reader.index, this.compressedSize, compression);
2608        this.decompressed.getContent = this.prepareContent(reader, reader.index, this.compressedSize, compression, this.uncompressedSize);
2609
2610        // we need to compute the crc32...
2611        if (this.loadOptions.checkCRC32) {
2612            this.decompressed = utils.transformTo("string", this.decompressed.getContent());
2613            if (jszipProto.crc32(this.decompressed) !== this.crc32) {
2614                throw new Error("Corrupted zip : CRC32 mismatch");
2615            }
2616        }
2617    },
2618
2619    /**
2620     * Read the central part of a zip file and add the info in this object.
2621     * @param {DataReader} reader the reader to use.
2622     */
2623    readCentralPart: function(reader) {
2624        this.versionMadeBy = reader.readInt(2);
2625        this.versionNeeded = reader.readInt(2);
2626        this.bitFlag = reader.readInt(2);
2627        this.compressionMethod = reader.readString(2);
2628        this.date = reader.readDate();
2629        this.crc32 = reader.readInt(4);
2630        this.compressedSize = reader.readInt(4);
2631        this.uncompressedSize = reader.readInt(4);
2632        this.fileNameLength = reader.readInt(2);
2633        this.extraFieldsLength = reader.readInt(2);
2634        this.fileCommentLength = reader.readInt(2);
2635        this.diskNumberStart = reader.readInt(2);
2636        this.internalFileAttributes = reader.readInt(2);
2637        this.externalFileAttributes = reader.readInt(4);
2638        this.localHeaderOffset = reader.readInt(4);
2639
2640        if (this.isEncrypted()) {
2641            throw new Error("Encrypted zip are not supported");
2642        }
2643
2644        this.fileName = reader.readString(this.fileNameLength);
2645        this.readExtraFields(reader);
2646        this.parseZIP64ExtraField(reader);
2647        this.fileComment = reader.readString(this.fileCommentLength);
2648    },
2649
2650    /**
2651     * Parse the external file attributes and get the unix/dos permissions.
2652     */
2653    processAttributes: function () {
2654        this.unixPermissions = null;
2655        this.dosPermissions = null;
2656        var madeBy = this.versionMadeBy >> 8;
2657
2658        // Check if we have the DOS directory flag set.
2659        // We look for it in the DOS and UNIX permissions
2660        // but some unknown platform could set it as a compatibility flag.
2661        this.dir = this.externalFileAttributes & 0x0010 ? true : false;
2662
2663        if(madeBy === MADE_BY_DOS) {
2664            // first 6 bits (0 to 5)
2665            this.dosPermissions = this.externalFileAttributes & 0x3F;
2666        }
2667
2668        if(madeBy === MADE_BY_UNIX) {
2669            this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF;
2670            // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8);
2671        }
2672
2673        // fail safe : if the name ends with a / it probably means a folder
2674        if (!this.dir && this.fileName.slice(-1) === '/') {
2675            this.dir = true;
2676        }
2677    },
vendor: 77,279 bytes, lines 2678-5176
2678
2679    /**
2680     * Parse the ZIP64 extra field and merge the info in the current ZipEntry.
2681     * @param {DataReader} reader the reader to use.
2682     */
2683    parseZIP64ExtraField: function(reader) {
2684
2685        if (!this.extraFields[0x0001]) {
2686            return;
2687        }
2688
2689        // should be something, preparing the extra reader
2690        var extraReader = new StringReader(this.extraFields[0x0001].value);
2691
2692        // I really hope that these 64bits integer can fit in 32 bits integer, because js
2693        // won't let us have more.
2694        if (this.uncompressedSize === utils.MAX_VALUE_32BITS) {
2695            this.uncompressedSize = extraReader.readInt(8);
2696        }
2697        if (this.compressedSize === utils.MAX_VALUE_32BITS) {
2698            this.compressedSize = extraReader.readInt(8);
2699        }
2700        if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) {
2701            this.localHeaderOffset = extraReader.readInt(8);
2702        }
2703        if (this.diskNumberStart === utils.MAX_VALUE_32BITS) {
2704            this.diskNumberStart = extraReader.readInt(4);
2705        }
2706    },
2707    /**
2708     * Read the central part of a zip file and add the info in this object.
2709     * @param {DataReader} reader the reader to use.
2710     */
2711    readExtraFields: function(reader) {
2712        var start = reader.index,
2713            extraFieldId,
2714            extraFieldLength,
2715            extraFieldValue;
2716
2717        this.extraFields = this.extraFields || {};
2718
2719        while (reader.index < start + this.extraFieldsLength) {
2720            extraFieldId = reader.readInt(2);
2721            extraFieldLength = reader.readInt(2);
2722            extraFieldValue = reader.readString(extraFieldLength);
2723
2724            this.extraFields[extraFieldId] = {
2725                id: extraFieldId,
2726                length: extraFieldLength,
2727                value: extraFieldValue
2728            };
2729        }
2730    },
2731    /**
2732     * Apply an UTF8 transformation if needed.
2733     */
2734    handleUTF8: function() {
2735        if (this.useUTF8()) {
2736            this.fileName = jszipProto.utf8decode(this.fileName);
2737            this.fileComment = jszipProto.utf8decode(this.fileComment);
2738        } else {
2739            var upath = this.findExtraFieldUnicodePath();
2740            if (upath !== null) {
2741                this.fileName = upath;
2742            }
2743            var ucomment = this.findExtraFieldUnicodeComment();
2744            if (ucomment !== null) {
2745                this.fileComment = ucomment;
2746            }
2747        }
2748    },
2749
2750    /**
2751     * Find the unicode path declared in the extra field, if any.
2752     * @return {String} the unicode path, null otherwise.
2753     */
2754    findExtraFieldUnicodePath: function() {
2755        var upathField = this.extraFields[0x7075];
2756        if (upathField) {
2757            var extraReader = new StringReader(upathField.value);
2758
2759            // wrong version
2760            if (extraReader.readInt(1) !== 1) {
2761                return null;
2762            }
2763
2764            // the crc of the filename changed, this field is out of date.
2765            if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) {
2766                return null;
2767            }
2768
2769            return jszipProto.utf8decode(extraReader.readString(upathField.length - 5));
2770        }
2771        return null;
2772    },
2773
2774    /**
2775     * Find the unicode comment declared in the extra field, if any.
2776     * @return {String} the unicode comment, null otherwise.
2777     */
2778    findExtraFieldUnicodeComment: function() {
2779        var ucommentField = this.extraFields[0x6375];
2780        if (ucommentField) {
2781            var extraReader = new StringReader(ucommentField.value);
2782
2783            // wrong version
2784            if (extraReader.readInt(1) !== 1) {
2785                return null;
2786            }
2787
2788            // the crc of the comment changed, this field is out of date.
2789            if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) {
2790                return null;
2791            }
2792
2793            return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5));
2794        }
2795        return null;
2796    }
2797};
2798module.exports = ZipEntry;
2799
2800},{"./compressedObject":2,"./object":13,"./stringReader":15,"./utils":21}],24:[function(_dereq_,module,exports){
2801// Top level file is just a mixin of submodules & constants
2802'use strict';
2803
2804var assign    = _dereq_('./lib/utils/common').assign;
2805
2806var deflate   = _dereq_('./lib/deflate');
2807var inflate   = _dereq_('./lib/inflate');
2808var constants = _dereq_('./lib/zlib/constants');
2809
2810var pako = {};
2811
2812assign(pako, deflate, inflate, constants);
2813
2814module.exports = pako;
2815},{"./lib/deflate":25,"./lib/inflate":26,"./lib/utils/common":27,"./lib/zlib/constants":30}],25:[function(_dereq_,module,exports){
2816'use strict';
2817
2818
2819var zlib_deflate = _dereq_('./zlib/deflate.js');
2820var utils = _dereq_('./utils/common');
2821var strings = _dereq_('./utils/strings');
2822var msg = _dereq_('./zlib/messages');
2823var zstream = _dereq_('./zlib/zstream');
2824
2825
2826/* Public constants ==========================================================*/
2827/* ===========================================================================*/
2828
2829var Z_NO_FLUSH      = 0;
2830var Z_FINISH        = 4;
2831
2832var Z_OK            = 0;
2833var Z_STREAM_END    = 1;
2834
2835var Z_DEFAULT_COMPRESSION = -1;
2836
2837var Z_DEFAULT_STRATEGY    = 0;
2838
2839var Z_DEFLATED  = 8;
2840
2841/* ===========================================================================*/
2842
2843
2844/**
2845 * class Deflate
2846 *
2847 * Generic JS-style wrapper for zlib calls. If you don't need
2848 * streaming behaviour - use more simple functions: [[deflate]],
2849 * [[deflateRaw]] and [[gzip]].
2850 **/
2851
2852/* internal
2853 * Deflate.chunks -> Array
2854 *
2855 * Chunks of output data, if [[Deflate#onData]] not overriden.
2856 **/
2857
2858/**
2859 * Deflate.result -> Uint8Array|Array
2860 *
2861 * Compressed result, generated by default [[Deflate#onData]]
2862 * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
2863 * (call [[Deflate#push]] with `Z_FINISH` / `true` param).
2864 **/
2865
2866/**
2867 * Deflate.err -> Number
2868 *
2869 * Error code after deflate finished. 0 (Z_OK) on success.
2870 * You will not need it in real life, because deflate errors
2871 * are possible only on wrong options or bad `onData` / `onEnd`
2872 * custom handlers.
2873 **/
2874
2875/**
2876 * Deflate.msg -> String
2877 *
2878 * Error message, if [[Deflate.err]] != 0
2879 **/
2880
2881
2882/**
2883 * new Deflate(options)
2884 * - options (Object): zlib deflate options.
2885 *
2886 * Creates new deflator instance with specified params. Throws exception
2887 * on bad params. Supported options:
2888 *
2889 * - `level`
2890 * - `windowBits`
2891 * - `memLevel`
2892 * - `strategy`
2893 *
2894 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
2895 * for more information on these.
2896 *
2897 * Additional options, for internal needs:
2898 *
2899 * - `chunkSize` - size of generated data chunks (16K by default)
2900 * - `raw` (Boolean) - do raw deflate
2901 * - `gzip` (Boolean) - create gzip wrapper
2902 * - `to` (String) - if equal to 'string', then result will be "binary string"
2903 *    (each char code [0..255])
2904 * - `header` (Object) - custom header for gzip
2905 *   - `text` (Boolean) - true if compressed data believed to be text
2906 *   - `time` (Number) - modification time, unix timestamp
2907 *   - `os` (Number) - operation system code
2908 *   - `extra` (Array) - array of bytes with extra data (max 65536)
2909 *   - `name` (String) - file name (binary string)
2910 *   - `comment` (String) - comment (binary string)
2911 *   - `hcrc` (Boolean) - true if header crc should be added
2912 *
2913 * ##### Example:
2914 *
2915 * ```javascript
2916 * var pako = require('pako')
2917 *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
2918 *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
2919 *
2920 * var deflate = new pako.Deflate({ level: 3});
2921 *
2922 * deflate.push(chunk1, false);
2923 * deflate.push(chunk2, true);  // true -> last chunk
2924 *
2925 * if (deflate.err) { throw new Error(deflate.err); }
2926 *
2927 * console.log(deflate.result);
2928 * ```
2929 **/
2930var Deflate = function(options) {
2931
2932  this.options = utils.assign({
2933    level: Z_DEFAULT_COMPRESSION,
2934    method: Z_DEFLATED,
2935    chunkSize: 16384,
2936    windowBits: 15,
2937    memLevel: 8,
2938    strategy: Z_DEFAULT_STRATEGY,
2939    to: ''
2940  }, options || {});
2941
2942  var opt = this.options;
2943
2944  if (opt.raw && (opt.windowBits > 0)) {
2945    opt.windowBits = -opt.windowBits;
2946  }
2947
2948  else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
2949    opt.windowBits += 16;
2950  }
2951
2952  this.err    = 0;      // error code, if happens (0 = Z_OK)
2953  this.msg    = '';     // error message
2954  this.ended  = false;  // used to avoid multiple onEnd() calls
2955  this.chunks = [];     // chunks of compressed data
2956
2957  this.strm = new zstream();
2958  this.strm.avail_out = 0;
2959
2960  var status = zlib_deflate.deflateInit2(
2961    this.strm,
2962    opt.level,
2963    opt.method,
2964    opt.windowBits,
2965    opt.memLevel,
2966    opt.strategy
2967  );
2968
2969  if (status !== Z_OK) {
2970    throw new Error(msg[status]);
2971  }
2972
2973  if (opt.header) {
2974    zlib_deflate.deflateSetHeader(this.strm, opt.header);
2975  }
2976};
2977
2978/**
2979 * Deflate#push(data[, mode]) -> Boolean
2980 * - data (Uint8Array|Array|String): input data. Strings will be converted to
2981 *   utf8 byte sequence.
2982 * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
2983 *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
2984 *
2985 * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
2986 * new compressed chunks. Returns `true` on success. The last data block must have
2987 * mode Z_FINISH (or `true`). That flush internal pending buffers and call
2988 * [[Deflate#onEnd]].
2989 *
2990 * On fail call [[Deflate#onEnd]] with error code and return false.
2991 *
2992 * We strongly recommend to use `Uint8Array` on input for best speed (output
2993 * array format is detected automatically). Also, don't skip last param and always
2994 * use the same type in your code (boolean or number). That will improve JS speed.
2995 *
2996 * For regular `Array`-s make sure all elements are [0..255].
2997 *
2998 * ##### Example
2999 *
3000 * ```javascript
3001 * push(chunk, false); // push one of data chunks
3002 * ...
3003 * push(chunk, true);  // push last chunk
3004 * ```
3005 **/
3006Deflate.prototype.push = function(data, mode) {
3007  var strm = this.strm;
3008  var chunkSize = this.options.chunkSize;
3009  var status, _mode;
3010
3011  if (this.ended) { return false; }
3012
3013  _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
3014
3015  // Convert data if needed
3016  if (typeof data === 'string') {
3017    // If we need to compress text, change encoding to utf8.
3018    strm.input = strings.string2buf(data);
3019  } else {
3020    strm.input = data;
3021  }
3022
3023  strm.next_in = 0;
3024  strm.avail_in = strm.input.length;
3025
3026  do {
3027    if (strm.avail_out === 0) {
3028      strm.output = new utils.Buf8(chunkSize);
3029      strm.next_out = 0;
3030      strm.avail_out = chunkSize;
3031    }
3032    status = zlib_deflate.deflate(strm, _mode);    /* no bad return value */
3033
3034    if (status !== Z_STREAM_END && status !== Z_OK) {
3035      this.onEnd(status);
3036      this.ended = true;
3037      return false;
3038    }
3039    if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) {
3040      if (this.options.to === 'string') {
3041        this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
3042      } else {
3043        this.onData(utils.shrinkBuf(strm.output, strm.next_out));
3044      }
3045    }
3046  } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
3047
3048  // Finalize on the last chunk.
3049  if (_mode === Z_FINISH) {
3050    status = zlib_deflate.deflateEnd(this.strm);
3051    this.onEnd(status);
3052    this.ended = true;
3053    return status === Z_OK;
3054  }
3055
3056  return true;
3057};
3058
3059
3060/**
3061 * Deflate#onData(chunk) -> Void
3062 * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
3063 *   on js engine support. When string output requested, each chunk
3064 *   will be string.
3065 *
3066 * By default, stores data blocks in `chunks[]` property and glue
3067 * those in `onEnd`. Override this handler, if you need another behaviour.
3068 **/
3069Deflate.prototype.onData = function(chunk) {
3070  this.chunks.push(chunk);
3071};
3072
3073
3074/**
3075 * Deflate#onEnd(status) -> Void
3076 * - status (Number): deflate status. 0 (Z_OK) on success,
3077 *   other if not.
3078 *
3079 * Called once after you tell deflate that input stream complete
3080 * or error happenned. By default - join collected chunks,
3081 * free memory and fill `results` / `err` properties.
3082 **/
3083Deflate.prototype.onEnd = function(status) {
3084  // On success - join
3085  if (status === Z_OK) {
3086    if (this.options.to === 'string') {
3087      this.result = this.chunks.join('');
3088    } else {
3089      this.result = utils.flattenChunks(this.chunks);
3090    }
3091  }
3092  this.chunks = [];
3093  this.err = status;
3094  this.msg = this.strm.msg;
3095};
3096
3097
3098/**
3099 * deflate(data[, options]) -> Uint8Array|Array|String
3100 * - data (Uint8Array|Array|String): input data to compress.
3101 * - options (Object): zlib deflate options.
3102 *
3103 * Compress `data` with deflate alrorythm and `options`.
3104 *
3105 * Supported options are:
3106 *
3107 * - level
3108 * - windowBits
3109 * - memLevel
3110 * - strategy
3111 *
3112 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
3113 * for more information on these.
3114 *
3115 * Sugar (options):
3116 *
3117 * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
3118 *   negative windowBits implicitly.
3119 * - `to` (String) - if equal to 'string', then result will be "binary string"
3120 *    (each char code [0..255])
3121 *
3122 * ##### Example:
3123 *
3124 * ```javascript
3125 * var pako = require('pako')
3126 *   , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
3127 *
3128 * console.log(pako.deflate(data));
3129 * ```
3130 **/
3131function deflate(input, options) {
3132  var deflator = new Deflate(options);
3133
3134  deflator.push(input, true);
3135
3136  // That will never happens, if you don't cheat with options :)
3137  if (deflator.err) { throw deflator.msg; }
3138
3139  return deflator.result;
3140}
3141
3142
3143/**
3144 * deflateRaw(data[, options]) -> Uint8Array|Array|String
3145 * - data (Uint8Array|Array|String): input data to compress.
3146 * - options (Object): zlib deflate options.
3147 *
3148 * The same as [[deflate]], but creates raw data, without wrapper
3149 * (header and adler32 crc).
3150 **/
3151function deflateRaw(input, options) {
3152  options = options || {};
3153  options.raw = true;
3154  return deflate(input, options);
3155}
3156
3157
3158/**
3159 * gzip(data[, options]) -> Uint8Array|Array|String
3160 * - data (Uint8Array|Array|String): input data to compress.
3161 * - options (Object): zlib deflate options.
3162 *
3163 * The same as [[deflate]], but create gzip wrapper instead of
3164 * deflate one.
3165 **/
3166function gzip(input, options) {
3167  options = options || {};
3168  options.gzip = true;
3169  return deflate(input, options);
3170}
3171
3172
3173exports.Deflate = Deflate;
3174exports.deflate = deflate;
3175exports.deflateRaw = deflateRaw;
3176exports.gzip = gzip;
3177},{"./utils/common":27,"./utils/strings":28,"./zlib/deflate.js":32,"./zlib/messages":37,"./zlib/zstream":39}],26:[function(_dereq_,module,exports){
3178'use strict';
3179
3180
3181var zlib_inflate = _dereq_('./zlib/inflate.js');
3182var utils = _dereq_('./utils/common');
3183var strings = _dereq_('./utils/strings');
3184var c = _dereq_('./zlib/constants');
3185var msg = _dereq_('./zlib/messages');
3186var zstream = _dereq_('./zlib/zstream');
3187var gzheader = _dereq_('./zlib/gzheader');
3188
3189
3190/**
3191 * class Inflate
3192 *
3193 * Generic JS-style wrapper for zlib calls. If you don't need
3194 * streaming behaviour - use more simple functions: [[inflate]]
3195 * and [[inflateRaw]].
3196 **/
3197
3198/* internal
3199 * inflate.chunks -> Array
3200 *
3201 * Chunks of output data, if [[Inflate#onData]] not overriden.
3202 **/
3203
3204/**
3205 * Inflate.result -> Uint8Array|Array|String
3206 *
3207 * Uncompressed result, generated by default [[Inflate#onData]]
3208 * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
3209 * (call [[Inflate#push]] with `Z_FINISH` / `true` param).
3210 **/
3211
3212/**
3213 * Inflate.err -> Number
3214 *
3215 * Error code after inflate finished. 0 (Z_OK) on success.
3216 * Should be checked if broken data possible.
3217 **/
3218
3219/**
3220 * Inflate.msg -> String
3221 *
3222 * Error message, if [[Inflate.err]] != 0
3223 **/
3224
3225
3226/**
3227 * new Inflate(options)
3228 * - options (Object): zlib inflate options.
3229 *
3230 * Creates new inflator instance with specified params. Throws exception
3231 * on bad params. Supported options:
3232 *
3233 * - `windowBits`
3234 *
3235 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
3236 * for more information on these.
3237 *
3238 * Additional options, for internal needs:
3239 *
3240 * - `chunkSize` - size of generated data chunks (16K by default)
3241 * - `raw` (Boolean) - do raw inflate
3242 * - `to` (String) - if equal to 'string', then result will be converted
3243 *   from utf8 to utf16 (javascript) string. When string output requested,
3244 *   chunk length can differ from `chunkSize`, depending on content.
3245 *
3246 * By default, when no options set, autodetect deflate/gzip data format via
3247 * wrapper header.
3248 *
3249 * ##### Example:
3250 *
3251 * ```javascript
3252 * var pako = require('pako')
3253 *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
3254 *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
3255 *
3256 * var inflate = new pako.Inflate({ level: 3});
3257 *
3258 * inflate.push(chunk1, false);
3259 * inflate.push(chunk2, true);  // true -> last chunk
3260 *
3261 * if (inflate.err) { throw new Error(inflate.err); }
3262 *
3263 * console.log(inflate.result);
3264 * ```
3265 **/
3266var Inflate = function(options) {
3267
3268  this.options = utils.assign({
3269    chunkSize: 16384,
3270    windowBits: 0,
3271    to: ''
3272  }, options || {});
3273
3274  var opt = this.options;
3275
3276  // Force window size for `raw` data, if not set directly,
3277  // because we have no header for autodetect.
3278  if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
3279    opt.windowBits = -opt.windowBits;
3280    if (opt.windowBits === 0) { opt.windowBits = -15; }
3281  }
3282
3283  // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
3284  if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
3285      !(options && options.windowBits)) {
3286    opt.windowBits += 32;
3287  }
3288
3289  // Gzip header has no info about windows size, we can do autodetect only
3290  // for deflate. So, if window size not set, force it to max when gzip possible
3291  if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
3292    // bit 3 (16) -> gzipped data
3293    // bit 4 (32) -> autodetect gzip/deflate
3294    if ((opt.windowBits & 15) === 0) {
3295      opt.windowBits |= 15;
3296    }
3297  }
3298
3299  this.err    = 0;      // error code, if happens (0 = Z_OK)
3300  this.msg    = '';     // error message
3301  this.ended  = false;  // used to avoid multiple onEnd() calls
3302  this.chunks = [];     // chunks of compressed data
3303
3304  this.strm   = new zstream();
3305  this.strm.avail_out = 0;
3306
3307  var status  = zlib_inflate.inflateInit2(
3308    this.strm,
3309    opt.windowBits
3310  );
3311
3312  if (status !== c.Z_OK) {
3313    throw new Error(msg[status]);
3314  }
3315
3316  this.header = new gzheader();
3317
3318  zlib_inflate.inflateGetHeader(this.strm, this.header);
3319};
3320
3321/**
3322 * Inflate#push(data[, mode]) -> Boolean
3323 * - data (Uint8Array|Array|String): input data
3324 * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
3325 *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
3326 *
3327 * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
3328 * new output chunks. Returns `true` on success. The last data block must have
3329 * mode Z_FINISH (or `true`). That flush internal pending buffers and call
3330 * [[Inflate#onEnd]].
3331 *
3332 * On fail call [[Inflate#onEnd]] with error code and return false.
3333 *
3334 * We strongly recommend to use `Uint8Array` on input for best speed (output
3335 * format is detected automatically). Also, don't skip last param and always
3336 * use the same type in your code (boolean or number). That will improve JS speed.
3337 *
3338 * For regular `Array`-s make sure all elements are [0..255].
3339 *
3340 * ##### Example
3341 *
3342 * ```javascript
3343 * push(chunk, false); // push one of data chunks
3344 * ...
3345 * push(chunk, true);  // push last chunk
3346 * ```
3347 **/
3348Inflate.prototype.push = function(data, mode) {
3349  var strm = this.strm;
3350  var chunkSize = this.options.chunkSize;
3351  var status, _mode;
3352  var next_out_utf8, tail, utf8str;
3353
3354  if (this.ended) { return false; }
3355  _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);
3356
3357  // Convert data if needed
3358  if (typeof data === 'string') {
3359    // Only binary strings can be decompressed on practice
3360    strm.input = strings.binstring2buf(data);
3361  } else {
3362    strm.input = data;
3363  }
3364
3365  strm.next_in = 0;
3366  strm.avail_in = strm.input.length;
3367
3368  do {
3369    if (strm.avail_out === 0) {
3370      strm.output = new utils.Buf8(chunkSize);
3371      strm.next_out = 0;
3372      strm.avail_out = chunkSize;
3373    }
3374
3375    status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH);    /* no bad return value */
3376
3377    if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
3378      this.onEnd(status);
3379      this.ended = true;
3380      return false;
3381    }
3382
3383    if (strm.next_out) {
3384      if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) {
3385
3386        if (this.options.to === 'string') {
3387
3388          next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
3389
3390          tail = strm.next_out - next_out_utf8;
3391          utf8str = strings.buf2string(strm.output, next_out_utf8);
3392
3393          // move tail
3394          strm.next_out = tail;
3395          strm.avail_out = chunkSize - tail;
3396          if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }
3397
3398          this.onData(utf8str);
3399
3400        } else {
3401          this.onData(utils.shrinkBuf(strm.output, strm.next_out));
3402        }
3403      }
3404    }
3405  } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END);
3406
3407  if (status === c.Z_STREAM_END) {
3408    _mode = c.Z_FINISH;
3409  }
3410  // Finalize on the last chunk.
3411  if (_mode === c.Z_FINISH) {
3412    status = zlib_inflate.inflateEnd(this.strm);
3413    this.onEnd(status);
3414    this.ended = true;
3415    return status === c.Z_OK;
3416  }
3417
3418  return true;
3419};
3420
3421
3422/**
3423 * Inflate#onData(chunk) -> Void
3424 * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
3425 *   on js engine support. When string output requested, each chunk
3426 *   will be string.
3427 *
3428 * By default, stores data blocks in `chunks[]` property and glue
3429 * those in `onEnd`. Override this handler, if you need another behaviour.
3430 **/
3431Inflate.prototype.onData = function(chunk) {
3432  this.chunks.push(chunk);
3433};
3434
3435
3436/**
3437 * Inflate#onEnd(status) -> Void
3438 * - status (Number): inflate status. 0 (Z_OK) on success,
3439 *   other if not.
3440 *
3441 * Called once after you tell inflate that input stream complete
3442 * or error happenned. By default - join collected chunks,
3443 * free memory and fill `results` / `err` properties.
3444 **/
3445Inflate.prototype.onEnd = function(status) {
3446  // On success - join
3447  if (status === c.Z_OK) {
3448    if (this.options.to === 'string') {
3449      // Glue & convert here, until we teach pako to send
3450      // utf8 alligned strings to onData
3451      this.result = this.chunks.join('');
3452    } else {
3453      this.result = utils.flattenChunks(this.chunks);
3454    }
3455  }
3456  this.chunks = [];
3457  this.err = status;
3458  this.msg = this.strm.msg;
3459};
3460
3461
3462/**
3463 * inflate(data[, options]) -> Uint8Array|Array|String
3464 * - data (Uint8Array|Array|String): input data to decompress.
3465 * - options (Object): zlib inflate options.
3466 *
3467 * Decompress `data` with inflate/ungzip and `options`. Autodetect
3468 * format via wrapper header by default. That's why we don't provide
3469 * separate `ungzip` method.
3470 *
3471 * Supported options are:
3472 *
3473 * - windowBits
3474 *
3475 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
3476 * for more information.
3477 *
3478 * Sugar (options):
3479 *
3480 * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
3481 *   negative windowBits implicitly.
3482 * - `to` (String) - if equal to 'string', then result will be converted
3483 *   from utf8 to utf16 (javascript) string. When string output requested,
3484 *   chunk length can differ from `chunkSize`, depending on content.
3485 *
3486 *
3487 * ##### Example:
3488 *
3489 * ```javascript
3490 * var pako = require('pako')
3491 *   , input = pako.deflate([1,2,3,4,5,6,7,8,9])
3492 *   , output;
3493 *
3494 * try {
3495 *   output = pako.inflate(input);
3496 * } catch (err)
3497 *   console.log(err);
3498 * }
3499 * ```
3500 **/
3501function inflate(input, options) {
3502  var inflator = new Inflate(options);
3503
3504  inflator.push(input, true);
3505
3506  // That will never happens, if you don't cheat with options :)
3507  if (inflator.err) { throw inflator.msg; }
3508
3509  return inflator.result;
3510}
3511
3512
3513/**
3514 * inflateRaw(data[, options]) -> Uint8Array|Array|String
3515 * - data (Uint8Array|Array|String): input data to decompress.
3516 * - options (Object): zlib inflate options.
3517 *
3518 * The same as [[inflate]], but creates raw data, without wrapper
3519 * (header and adler32 crc).
3520 **/
3521function inflateRaw(input, options) {
3522  options = options || {};
3523  options.raw = true;
3524  return inflate(input, options);
3525}
3526
3527
3528/**
3529 * ungzip(data[, options]) -> Uint8Array|Array|String
3530 * - data (Uint8Array|Array|String): input data to decompress.
3531 * - options (Object): zlib inflate options.
3532 *
3533 * Just shortcut to [[inflate]], because it autodetects format
3534 * by header.content. Done for convenience.
3535 **/
3536
3537
3538exports.Inflate = Inflate;
3539exports.inflate = inflate;
3540exports.inflateRaw = inflateRaw;
3541exports.ungzip  = inflate;
3542
3543},{"./utils/common":27,"./utils/strings":28,"./zlib/constants":30,"./zlib/gzheader":33,"./zlib/inflate.js":35,"./zlib/messages":37,"./zlib/zstream":39}],27:[function(_dereq_,module,exports){
3544'use strict';
3545
3546
3547var TYPED_OK =  (typeof Uint8Array !== 'undefined') &&
3548                (typeof Uint16Array !== 'undefined') &&
3549                (typeof Int32Array !== 'undefined');
3550
3551
3552exports.assign = function (obj /*from1, from2, from3, ...*/) {
3553  var sources = Array.prototype.slice.call(arguments, 1);
3554  while (sources.length) {
3555    var source = sources.shift();
3556    if (!source) { continue; }
3557
3558    if (typeof(source) !== 'object') {
3559      throw new TypeError(source + 'must be non-object');
3560    }
3561
3562    for (var p in source) {
3563      if (source.hasOwnProperty(p)) {
3564        obj[p] = source[p];
3565      }
3566    }
3567  }
3568
3569  return obj;
3570};
3571
3572
3573// reduce buffer size, avoiding mem copy
3574exports.shrinkBuf = function (buf, size) {
3575  if (buf.length === size) { return buf; }
3576  if (buf.subarray) { return buf.subarray(0, size); }
3577  buf.length = size;
3578  return buf;
3579};
3580
3581
3582var fnTyped = {
3583  arraySet: function (dest, src, src_offs, len, dest_offs) {
3584    if (src.subarray && dest.subarray) {
3585      dest.set(src.subarray(src_offs, src_offs+len), dest_offs);
3586      return;
3587    }
3588    // Fallback to ordinary array
3589    for(var i=0; i<len; i++) {
3590      dest[dest_offs + i] = src[src_offs + i];
3591    }
3592  },
3593  // Join array of chunks to single array.
3594  flattenChunks: function(chunks) {
3595    var i, l, len, pos, chunk, result;
3596
3597    // calculate data length
3598    len = 0;
3599    for (i=0, l=chunks.length; i<l; i++) {
3600      len += chunks[i].length;
3601    }
3602
3603    // join chunks
3604    result = new Uint8Array(len);
3605    pos = 0;
3606    for (i=0, l=chunks.length; i<l; i++) {
3607      chunk = chunks[i];
3608      result.set(chunk, pos);
3609      pos += chunk.length;
3610    }
3611
3612    return result;
3613  }
3614};
3615
3616var fnUntyped = {
3617  arraySet: function (dest, src, src_offs, len, dest_offs) {
3618    for(var i=0; i<len; i++) {
3619      dest[dest_offs + i] = src[src_offs + i];
3620    }
3621  },
3622  // Join array of chunks to single array.
3623  flattenChunks: function(chunks) {
3624    return [].concat.apply([], chunks);
3625  }
3626};
3627
3628
3629// Enable/Disable typed arrays use, for testing
3630//
3631exports.setTyped = function (on) {
3632  if (on) {
3633    exports.Buf8  = Uint8Array;
3634    exports.Buf16 = Uint16Array;
3635    exports.Buf32 = Int32Array;
3636    exports.assign(exports, fnTyped);
3637  } else {
3638    exports.Buf8  = Array;
3639    exports.Buf16 = Array;
3640    exports.Buf32 = Array;
3641    exports.assign(exports, fnUntyped);
3642  }
3643};
3644
3645exports.setTyped(TYPED_OK);
3646},{}],28:[function(_dereq_,module,exports){
3647// String encode/decode helpers
3648'use strict';
3649
3650
3651var utils = _dereq_('./common');
3652
3653
3654// Quick check if we can use fast array to bin string conversion
3655//
3656// - apply(Array) can fail on Android 2.2
3657// - apply(Uint8Array) can fail on iOS 5.1 Safary
3658//
3659var STR_APPLY_OK = true;
3660var STR_APPLY_UIA_OK = true;
3661
3662try { String.fromCharCode.apply(null, [0]); } catch(__) { STR_APPLY_OK = false; }
3663try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch(__) { STR_APPLY_UIA_OK = false; }
3664
3665
3666// Table with utf8 lengths (calculated by first byte of sequence)
3667// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
3668// because max possible codepoint is 0x10ffff
3669var _utf8len = new utils.Buf8(256);
3670for (var i=0; i<256; i++) {
3671  _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);
3672}
3673_utf8len[254]=_utf8len[254]=1; // Invalid sequence start
3674
3675
3676// convert string to array (typed, when possible)
3677exports.string2buf = function (str) {
3678  var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
3679
3680  // count binary size
3681  for (m_pos = 0; m_pos < str_len; m_pos++) {
3682    c = str.charCodeAt(m_pos);
3683    if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
3684      c2 = str.charCodeAt(m_pos+1);
3685      if ((c2 & 0xfc00) === 0xdc00) {
3686        c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
3687        m_pos++;
3688      }
3689    }
3690    buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
3691  }
3692
3693  // allocate buffer
3694  buf = new utils.Buf8(buf_len);
3695
3696  // convert
3697  for (i=0, m_pos = 0; i < buf_len; m_pos++) {
3698    c = str.charCodeAt(m_pos);
3699    if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
3700      c2 = str.charCodeAt(m_pos+1);
3701      if ((c2 & 0xfc00) === 0xdc00) {
3702        c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
3703        m_pos++;
3704      }
3705    }
3706    if (c < 0x80) {
3707      /* one byte */
3708      buf[i++] = c;
3709    } else if (c < 0x800) {
3710      /* two bytes */
3711      buf[i++] = 0xC0 | (c >>> 6);
3712      buf[i++] = 0x80 | (c & 0x3f);
3713    } else if (c < 0x10000) {
3714      /* three bytes */
3715      buf[i++] = 0xE0 | (c >>> 12);
3716      buf[i++] = 0x80 | (c >>> 6 & 0x3f);
3717      buf[i++] = 0x80 | (c & 0x3f);
3718    } else {
3719      /* four bytes */
3720      buf[i++] = 0xf0 | (c >>> 18);
3721      buf[i++] = 0x80 | (c >>> 12 & 0x3f);
3722      buf[i++] = 0x80 | (c >>> 6 & 0x3f);
3723      buf[i++] = 0x80 | (c & 0x3f);
3724    }
3725  }
3726
3727  return buf;
3728};
3729
3730// Helper (used in 2 places)
3731function buf2binstring(buf, len) {
3732  // use fallback for big arrays to avoid stack overflow
3733  if (len < 65537) {
3734    if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {
3735      return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
3736    }
3737  }
3738
3739  var result = '';
3740  for(var i=0; i < len; i++) {
3741    result += String.fromCharCode(buf[i]);
3742  }
3743  return result;
3744}
3745
3746
3747// Convert byte array to binary string
3748exports.buf2binstring = function(buf) {
3749  return buf2binstring(buf, buf.length);
3750};
3751
3752
3753// Convert binary string (typed, when possible)
3754exports.binstring2buf = function(str) {
3755  var buf = new utils.Buf8(str.length);
3756  for(var i=0, len=buf.length; i < len; i++) {
3757    buf[i] = str.charCodeAt(i);
3758  }
3759  return buf;
3760};
3761
3762
3763// convert array to string
3764exports.buf2string = function (buf, max) {
3765  var i, out, c, c_len;
3766  var len = max || buf.length;
3767
3768  // Reserve max possible length (2 words per char)
3769  // NB: by unknown reasons, Array is significantly faster for
3770  //     String.fromCharCode.apply than Uint16Array.
3771  var utf16buf = new Array(len*2);
3772
3773  for (out=0, i=0; i<len;) {
3774    c = buf[i++];
3775    // quick process ascii
3776    if (c < 0x80) { utf16buf[out++] = c; continue; }
3777
3778    c_len = _utf8len[c];
3779    // skip 5 & 6 byte codes
3780    if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }
3781
3782    // apply mask on first byte
3783    c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
3784    // join the rest
3785    while (c_len > 1 && i < len) {
3786      c = (c << 6) | (buf[i++] & 0x3f);
3787      c_len--;
3788    }
3789
3790    // terminated by end of string?
3791    if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
3792
3793    if (c < 0x10000) {
3794      utf16buf[out++] = c;
3795    } else {
3796      c -= 0x10000;
3797      utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
3798      utf16buf[out++] = 0xdc00 | (c & 0x3ff);
3799    }
3800  }
3801
3802  return buf2binstring(utf16buf, out);
3803};
3804
3805
3806// Calculate max possible position in utf8 buffer,
3807// that will not break sequence. If that's not possible
3808// - (very small limits) return max size as is.
3809//
3810// buf[] - utf8 bytes array
3811// max   - length limit (mandatory);
3812exports.utf8border = function(buf, max) {
3813  var pos;
3814
3815  max = max || buf.length;
3816  if (max > buf.length) { max = buf.length; }
3817
3818  // go back from last position, until start of sequence found
3819  pos = max-1;
3820  while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
3821
3822  // Fuckup - very small and broken sequence,
3823  // return max, because we should return something anyway.
3824  if (pos < 0) { return max; }
3825
3826  // If we came to start of buffer - that means vuffer is too small,
3827  // return max too.
3828  if (pos === 0) { return max; }
3829
3830  return (pos + _utf8len[buf[pos]] > max) ? pos : max;
3831};
3832
3833},{"./common":27}],29:[function(_dereq_,module,exports){
3834'use strict';
3835
3836// Note: adler32 takes 12% for level 0 and 2% for level 6.
3837// It doesn't worth to make additional optimizationa as in original.
3838// Small size is preferable.
3839
3840function adler32(adler, buf, len, pos) {
3841  var s1 = (adler & 0xffff) |0
3842    , s2 = ((adler >>> 16) & 0xffff) |0
3843    , n = 0;
3844
3845  while (len !== 0) {
3846    // Set limit ~ twice less than 5552, to keep
3847    // s2 in 31-bits, because we force signed ints.
3848    // in other case %= will fail.
3849    n = len > 2000 ? 2000 : len;
3850    len -= n;
3851
3852    do {
3853      s1 = (s1 + buf[pos++]) |0;
3854      s2 = (s2 + s1) |0;
3855    } while (--n);
3856
3857    s1 %= 65521;
3858    s2 %= 65521;
3859  }
3860
3861  return (s1 | (s2 << 16)) |0;
3862}
3863
3864
3865module.exports = adler32;
3866},{}],30:[function(_dereq_,module,exports){
3867module.exports = {
3868
3869  /* Allowed flush values; see deflate() and inflate() below for details */
3870  Z_NO_FLUSH:         0,
3871  Z_PARTIAL_FLUSH:    1,
3872  Z_SYNC_FLUSH:       2,
3873  Z_FULL_FLUSH:       3,
3874  Z_FINISH:           4,
3875  Z_BLOCK:            5,
3876  Z_TREES:            6,
3877
3878  /* Return codes for the compression/decompression functions. Negative values
3879  * are errors, positive values are used for special but normal events.
3880  */
3881  Z_OK:               0,
3882  Z_STREAM_END:       1,
3883  Z_NEED_DICT:        2,
3884  Z_ERRNO:           -1,
3885  Z_STREAM_ERROR:    -2,
3886  Z_DATA_ERROR:      -3,
3887  //Z_MEM_ERROR:     -4,
3888  Z_BUF_ERROR:       -5,
3889  //Z_VERSION_ERROR: -6,
3890
3891  /* compression levels */
3892  Z_NO_COMPRESSION:         0,
3893  Z_BEST_SPEED:             1,
3894  Z_BEST_COMPRESSION:       9,
3895  Z_DEFAULT_COMPRESSION:   -1,
3896
3897
3898  Z_FILTERED:               1,
3899  Z_HUFFMAN_ONLY:           2,
3900  Z_RLE:                    3,
3901  Z_FIXED:                  4,
3902  Z_DEFAULT_STRATEGY:       0,
3903
3904  /* Possible values of the data_type field (though see inflate()) */
3905  Z_BINARY:                 0,
3906  Z_TEXT:                   1,
3907  //Z_ASCII:                1, // = Z_TEXT (deprecated)
3908  Z_UNKNOWN:                2,
3909
3910  /* The deflate compression method */
3911  Z_DEFLATED:               8
3912  //Z_NULL:                 null // Use -1 or null inline, depending on var type
3913};
3914},{}],31:[function(_dereq_,module,exports){
3915'use strict';
3916
3917// Note: we can't get significant speed boost here.
3918// So write code to minimize size - no pregenerated tables
3919// and array tools dependencies.
3920
3921
3922// Use ordinary array, since untyped makes no boost here
3923function makeTable() {
3924  var c, table = [];
3925
3926  for(var n =0; n < 256; n++){
3927    c = n;
3928    for(var k =0; k < 8; k++){
3929      c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
3930    }
3931    table[n] = c;
3932  }
3933
3934  return table;
3935}
3936
3937// Create table on load. Just 255 signed longs. Not a problem.
3938var crcTable = makeTable();
3939
3940
3941function crc32(crc, buf, len, pos) {
3942  var t = crcTable
3943    , end = pos + len;
3944
3945  crc = crc ^ (-1);
3946
3947  for (var i = pos; i < end; i++ ) {
3948    crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
3949  }
3950
3951  return (crc ^ (-1)); // >>> 0;
3952}
3953
3954
3955module.exports = crc32;
3956},{}],32:[function(_dereq_,module,exports){
3957'use strict';
3958
3959var utils   = _dereq_('../utils/common');
3960var trees   = _dereq_('./trees');
3961var adler32 = _dereq_('./adler32');
3962var crc32   = _dereq_('./crc32');
3963var msg   = _dereq_('./messages');
3964
3965/* Public constants ==========================================================*/
3966/* ===========================================================================*/
3967
3968
3969/* Allowed flush values; see deflate() and inflate() below for details */
3970var Z_NO_FLUSH      = 0;
3971var Z_PARTIAL_FLUSH = 1;
3972//var Z_SYNC_FLUSH    = 2;
3973var Z_FULL_FLUSH    = 3;
3974var Z_FINISH        = 4;
3975var Z_BLOCK         = 5;
3976//var Z_TREES         = 6;
3977
3978
3979/* Return codes for the compression/decompression functions. Negative values
3980 * are errors, positive values are used for special but normal events.
3981 */
3982var Z_OK            = 0;
3983var Z_STREAM_END    = 1;
3984//var Z_NEED_DICT     = 2;
3985//var Z_ERRNO         = -1;
3986var Z_STREAM_ERROR  = -2;
3987var Z_DATA_ERROR    = -3;
3988//var Z_MEM_ERROR     = -4;
3989var Z_BUF_ERROR     = -5;
3990//var Z_VERSION_ERROR = -6;
3991
3992
3993/* compression levels */
3994//var Z_NO_COMPRESSION      = 0;
3995//var Z_BEST_SPEED          = 1;
3996//var Z_BEST_COMPRESSION    = 9;
3997var Z_DEFAULT_COMPRESSION = -1;
3998
3999
4000var Z_FILTERED            = 1;
4001var Z_HUFFMAN_ONLY        = 2;
4002var Z_RLE                 = 3;
4003var Z_FIXED               = 4;
4004var Z_DEFAULT_STRATEGY    = 0;
4005
4006/* Possible values of the data_type field (though see inflate()) */
4007//var Z_BINARY              = 0;
4008//var Z_TEXT                = 1;
4009//var Z_ASCII               = 1; // = Z_TEXT
4010var Z_UNKNOWN             = 2;
4011
4012
4013/* The deflate compression method */
4014var Z_DEFLATED  = 8;
4015
4016/*============================================================================*/
4017
4018
4019var MAX_MEM_LEVEL = 9;
4020/* Maximum value for memLevel in deflateInit2 */
4021var MAX_WBITS = 15;
4022/* 32K LZ77 window */
4023var DEF_MEM_LEVEL = 8;
4024
4025
4026var LENGTH_CODES  = 29;
4027/* number of length codes, not counting the special END_BLOCK code */
4028var LITERALS      = 256;
4029/* number of literal bytes 0..255 */
4030var L_CODES       = LITERALS + 1 + LENGTH_CODES;
4031/* number of Literal or Length codes, including the END_BLOCK code */
4032var D_CODES       = 30;
4033/* number of distance codes */
4034var BL_CODES      = 19;
4035/* number of codes used to transfer the bit lengths */
4036var HEAP_SIZE     = 2*L_CODES + 1;
4037/* maximum heap size */
4038var MAX_BITS  = 15;
4039/* All codes must not exceed MAX_BITS bits */
4040
4041var MIN_MATCH = 3;
4042var MAX_MATCH = 258;
4043var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
4044
4045var PRESET_DICT = 0x20;
4046
4047var INIT_STATE = 42;
4048var EXTRA_STATE = 69;
4049var NAME_STATE = 73;
4050var COMMENT_STATE = 91;
4051var HCRC_STATE = 103;
4052var BUSY_STATE = 113;
4053var FINISH_STATE = 666;
4054
4055var BS_NEED_MORE      = 1; /* block not completed, need more input or more output */
4056var BS_BLOCK_DONE     = 2; /* block flush performed */
4057var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
4058var BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */
4059
4060var OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
4061
4062function err(strm, errorCode) {
4063  strm.msg = msg[errorCode];
4064  return errorCode;
4065}
4066
4067function rank(f) {
4068  return ((f) << 1) - ((f) > 4 ? 9 : 0);
4069}
4070
4071function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
4072
4073
4074/* =========================================================================
4075 * Flush as much pending output as possible. All deflate() output goes
4076 * through this function so some applications may wish to modify it
4077 * to avoid allocating a large strm->output buffer and copying into it.
4078 * (See also read_buf()).
4079 */
4080function flush_pending(strm) {
4081  var s = strm.state;
4082
4083  //_tr_flush_bits(s);
4084  var len = s.pending;
4085  if (len > strm.avail_out) {
4086    len = strm.avail_out;
4087  }
4088  if (len === 0) { return; }
4089
4090  utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
4091  strm.next_out += len;
4092  s.pending_out += len;
4093  strm.total_out += len;
4094  strm.avail_out -= len;
4095  s.pending -= len;
4096  if (s.pending === 0) {
4097    s.pending_out = 0;
4098  }
4099}
4100
4101
4102function flush_block_only (s, last) {
4103  trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
4104  s.block_start = s.strstart;
4105  flush_pending(s.strm);
4106}
4107
4108
4109function put_byte(s, b) {
4110  s.pending_buf[s.pending++] = b;
4111}
4112
4113
4114/* =========================================================================
4115 * Put a short in the pending buffer. The 16-bit value is put in MSB order.
4116 * IN assertion: the stream state is correct and there is enough room in
4117 * pending_buf.
4118 */
4119function putShortMSB(s, b) {
4120//  put_byte(s, (Byte)(b >> 8));
4121//  put_byte(s, (Byte)(b & 0xff));
4122  s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
4123  s.pending_buf[s.pending++] = b & 0xff;
4124}
4125
4126
4127/* ===========================================================================
4128 * Read a new buffer from the current input stream, update the adler32
4129 * and total number of bytes read.  All deflate() input goes through
4130 * this function so some applications may wish to modify it to avoid
4131 * allocating a large strm->input buffer and copying from it.
4132 * (See also flush_pending()).
4133 */
4134function read_buf(strm, buf, start, size) {
4135  var len = strm.avail_in;
4136
4137  if (len > size) { len = size; }
4138  if (len === 0) { return 0; }
4139
4140  strm.avail_in -= len;
4141
4142  utils.arraySet(buf, strm.input, strm.next_in, len, start);
4143  if (strm.state.wrap === 1) {
4144    strm.adler = adler32(strm.adler, buf, len, start);
4145  }
4146
4147  else if (strm.state.wrap === 2) {
4148    strm.adler = crc32(strm.adler, buf, len, start);
4149  }
4150
4151  strm.next_in += len;
4152  strm.total_in += len;
4153
4154  return len;
4155}
4156
4157
4158/* ===========================================================================
4159 * Set match_start to the longest match starting at the given string and
4160 * return its length. Matches shorter or equal to prev_length are discarded,
4161 * in which case the result is equal to prev_length and match_start is
4162 * garbage.
4163 * IN assertions: cur_match is the head of the hash chain for the current
4164 *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
4165 * OUT assertion: the match length is not greater than s->lookahead.
4166 */
4167function longest_match(s, cur_match) {
4168  var chain_length = s.max_chain_length;      /* max hash chain length */
4169  var scan = s.strstart; /* current string */
4170  var match;                       /* matched string */
4171  var len;                           /* length of current match */
4172  var best_len = s.prev_length;              /* best match length so far */
4173  var nice_match = s.nice_match;             /* stop if match long enough */
4174  var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
4175      s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
4176
4177  var _win = s.window; // shortcut
4178
4179  var wmask = s.w_mask;
4180  var prev  = s.prev;
4181
4182  /* Stop when cur_match becomes <= limit. To simplify the code,
4183   * we prevent matches with the string of window index 0.
4184   */
4185
4186  var strend = s.strstart + MAX_MATCH;
4187  var scan_end1  = _win[scan + best_len - 1];
4188  var scan_end   = _win[scan + best_len];
4189
4190  /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
4191   * It is easy to get rid of this optimization if necessary.
4192   */
4193  // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
4194
4195  /* Do not waste too much time if we already have a good match: */
4196  if (s.prev_length >= s.good_match) {
4197    chain_length >>= 2;
4198  }
4199  /* Do not look for matches beyond the end of the input. This is necessary
4200   * to make deflate deterministic.
4201   */
4202  if (nice_match > s.lookahead) { nice_match = s.lookahead; }
4203
4204  // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
4205
4206  do {
4207    // Assert(cur_match < s->strstart, "no future");
4208    match = cur_match;
4209
4210    /* Skip to next match if the match length cannot increase
4211     * or if the match length is less than 2.  Note that the checks below
4212     * for insufficient lookahead only occur occasionally for performance
4213     * reasons.  Therefore uninitialized memory will be accessed, and
4214     * conditional jumps will be made that depend on those values.
4215     * However the length of the match is limited to the lookahead, so
4216     * the output of deflate is not affected by the uninitialized values.
4217     */
4218
4219    if (_win[match + best_len]     !== scan_end  ||
4220        _win[match + best_len - 1] !== scan_end1 ||
4221        _win[match]                !== _win[scan] ||
4222        _win[++match]              !== _win[scan + 1]) {
4223      continue;
4224    }
4225
4226    /* The check at best_len-1 can be removed because it will be made
4227     * again later. (This heuristic is not always a win.)
4228     * It is not necessary to compare scan[2] and match[2] since they
4229     * are always equal when the other bytes match, given that
4230     * the hash keys are equal and that HASH_BITS >= 8.
4231     */
4232    scan += 2;
4233    match++;
4234    // Assert(*scan == *match, "match[2]?");
4235
4236    /* We check for insufficient lookahead only every 8th comparison;
4237     * the 256th check will be made at strstart+258.
4238     */
4239    do {
4240      /*jshint noempty:false*/
4241    } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
4242             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
4243             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
4244             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
4245             scan < strend);
4246
4247    // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
4248
4249    len = MAX_MATCH - (strend - scan);
4250    scan = strend - MAX_MATCH;
4251
4252    if (len > best_len) {
4253      s.match_start = cur_match;
4254      best_len = len;
4255      if (len >= nice_match) {
4256        break;
4257      }
4258      scan_end1  = _win[scan + best_len - 1];
4259      scan_end   = _win[scan + best_len];
4260    }
4261  } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
4262
4263  if (best_len <= s.lookahead) {
4264    return best_len;
4265  }
4266  return s.lookahead;
4267}
4268
4269
4270/* ===========================================================================
4271 * Fill the window when the lookahead becomes insufficient.
4272 * Updates strstart and lookahead.
4273 *
4274 * IN assertion: lookahead < MIN_LOOKAHEAD
4275 * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
4276 *    At least one byte has been read, or avail_in == 0; reads are
4277 *    performed for at least two bytes (required for the zip translate_eol
4278 *    option -- not supported here).
4279 */
4280function fill_window(s) {
4281  var _w_size = s.w_size;
4282  var p, n, m, more, str;
4283
4284  //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
4285
4286  do {
4287    more = s.window_size - s.lookahead - s.strstart;
4288
4289    // JS ints have 32 bit, block below not needed
4290    /* Deal with !@#$% 64K limit: */
4291    //if (sizeof(int) <= 2) {
4292    //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
4293    //        more = wsize;
4294    //
4295    //  } else if (more == (unsigned)(-1)) {
4296    //        /* Very unlikely, but possible on 16 bit machine if
4297    //         * strstart == 0 && lookahead == 1 (input done a byte at time)
4298    //         */
4299    //        more--;
4300    //    }
4301    //}
4302
4303
4304    /* If the window is almost full and there is insufficient lookahead,
4305     * move the upper half to the lower one to make room in the upper half.
4306     */
4307    if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
4308
4309      utils.arraySet(s.window, s.window, _w_size, _w_size, 0);
4310      s.match_start -= _w_size;
4311      s.strstart -= _w_size;
4312      /* we now have strstart >= MAX_DIST */
4313      s.block_start -= _w_size;
4314
4315      /* Slide the hash table (could be avoided with 32 bit values
4316       at the expense of memory usage). We slide even when level == 0
4317       to keep the hash table consistent if we switch back to level > 0
4318       later. (Using level 0 permanently is not an optimal usage of
4319       zlib, so we don't care about this pathological case.)
4320       */
4321
4322      n = s.hash_size;
4323      p = n;
4324      do {
4325        m = s.head[--p];
4326        s.head[p] = (m >= _w_size ? m - _w_size : 0);
4327      } while (--n);
4328
4329      n = _w_size;
4330      p = n;
4331      do {
4332        m = s.prev[--p];
4333        s.prev[p] = (m >= _w_size ? m - _w_size : 0);
4334        /* If n is not on any hash chain, prev[n] is garbage but
4335         * its value will never be used.
4336         */
4337      } while (--n);
4338
4339      more += _w_size;
4340    }
4341    if (s.strm.avail_in === 0) {
4342      break;
4343    }
4344
4345    /* If there was no sliding:
4346     *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
4347     *    more == window_size - lookahead - strstart
4348     * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
4349     * => more >= window_size - 2*WSIZE + 2
4350     * In the BIG_MEM or MMAP case (not yet supported),
4351     *   window_size == input_size + MIN_LOOKAHEAD  &&
4352     *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
4353     * Otherwise, window_size == 2*WSIZE so more >= 2.
4354     * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
4355     */
4356    //Assert(more >= 2, "more < 2");
4357    n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
4358    s.lookahead += n;
4359
4360    /* Initialize the hash value now that we have some input: */
4361    if (s.lookahead + s.insert >= MIN_MATCH) {
4362      str = s.strstart - s.insert;
4363      s.ins_h = s.window[str];
4364
4365      /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
4366      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;
4367//#if MIN_MATCH != 3
4368//        Call update_hash() MIN_MATCH-3 more times
4369//#endif
4370      while (s.insert) {
4371        /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
4372        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask;
4373
4374        s.prev[str & s.w_mask] = s.head[s.ins_h];
4375        s.head[s.ins_h] = str;
4376        str++;
4377        s.insert--;
4378        if (s.lookahead + s.insert < MIN_MATCH) {
4379          break;
4380        }
4381      }
4382    }
4383    /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
4384     * but this is not important since only literal bytes will be emitted.
4385     */
4386
4387  } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
4388
4389  /* If the WIN_INIT bytes after the end of the current data have never been
4390   * written, then zero those bytes in order to avoid memory check reports of
4391   * the use of uninitialized (or uninitialised as Julian writes) bytes by
4392   * the longest match routines.  Update the high water mark for the next
4393   * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
4394   * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
4395   */
4396//  if (s.high_water < s.window_size) {
4397//    var curr = s.strstart + s.lookahead;
4398//    var init = 0;
4399//
4400//    if (s.high_water < curr) {
4401//      /* Previous high water mark below current data -- zero WIN_INIT
4402//       * bytes or up to end of window, whichever is less.
4403//       */
4404//      init = s.window_size - curr;
4405//      if (init > WIN_INIT)
4406//        init = WIN_INIT;
4407//      zmemzero(s->window + curr, (unsigned)init);
4408//      s->high_water = curr + init;
4409//    }
4410//    else if (s->high_water < (ulg)curr + WIN_INIT) {
4411//      /* High water mark at or above current data, but below current data
4412//       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
4413//       * to end of window, whichever is less.
4414//       */
4415//      init = (ulg)curr + WIN_INIT - s->high_water;
4416//      if (init > s->window_size - s->high_water)
4417//        init = s->window_size - s->high_water;
4418//      zmemzero(s->window + s->high_water, (unsigned)init);
4419//      s->high_water += init;
4420//    }
4421//  }
4422//
4423//  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
4424//    "not enough room for search");
4425}
4426
4427/* ===========================================================================
4428 * Copy without compression as much as possible from the input stream, return
4429 * the current block state.
4430 * This function does not insert new strings in the dictionary since
4431 * uncompressible data is probably not useful. This function is used
4432 * only for the level=0 compression option.
4433 * NOTE: this function should be optimized to avoid extra copying from
4434 * window to pending_buf.
4435 */
4436function deflate_stored(s, flush) {
4437  /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
4438   * to pending_buf_size, and each stored block has a 5 byte header:
4439   */
4440  var max_block_size = 0xffff;
4441
4442  if (max_block_size > s.pending_buf_size - 5) {
4443    max_block_size = s.pending_buf_size - 5;
4444  }
4445
4446  /* Copy as much as possible from input to output: */
4447  for (;;) {
4448    /* Fill the window as much as possible: */
4449    if (s.lookahead <= 1) {
4450
4451      //Assert(s->strstart < s->w_size+MAX_DIST(s) ||
4452      //  s->block_start >= (long)s->w_size, "slide too late");
4453//      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
4454//        s.block_start >= s.w_size)) {
4455//        throw  new Error("slide too late");
4456//      }
4457
4458      fill_window(s);
4459      if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
4460        return BS_NEED_MORE;
4461      }
4462
4463      if (s.lookahead === 0) {
4464        break;
4465      }
4466      /* flush the current block */
4467    }
4468    //Assert(s->block_start >= 0L, "block gone");
4469//    if (s.block_start < 0) throw new Error("block gone");
4470
4471    s.strstart += s.lookahead;
4472    s.lookahead = 0;
4473
4474    /* Emit a stored block if pending_buf will be full: */
4475    var max_start = s.block_start + max_block_size;
4476
4477    if (s.strstart === 0 || s.strstart >= max_start) {
4478      /* strstart == 0 is possible when wraparound on 16-bit machine */
4479      s.lookahead = s.strstart - max_start;
4480      s.strstart = max_start;
4481      /*** FLUSH_BLOCK(s, 0); ***/
4482      flush_block_only(s, false);
4483      if (s.strm.avail_out === 0) {
4484        return BS_NEED_MORE;
4485      }
4486      /***/
4487
4488
4489    }
4490    /* Flush if we may have to slide, otherwise block_start may become
4491     * negative and the data will be gone:
4492     */
4493    if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
4494      /*** FLUSH_BLOCK(s, 0); ***/
4495      flush_block_only(s, false);
4496      if (s.strm.avail_out === 0) {
4497        return BS_NEED_MORE;
4498      }
4499      /***/
4500    }
4501  }
4502
4503  s.insert = 0;
4504
4505  if (flush === Z_FINISH) {
4506    /*** FLUSH_BLOCK(s, 1); ***/
4507    flush_block_only(s, true);
4508    if (s.strm.avail_out === 0) {
4509      return BS_FINISH_STARTED;
4510    }
4511    /***/
4512    return BS_FINISH_DONE;
4513  }
4514
4515  if (s.strstart > s.block_start) {
4516    /*** FLUSH_BLOCK(s, 0); ***/
4517    flush_block_only(s, false);
4518    if (s.strm.avail_out === 0) {
4519      return BS_NEED_MORE;
4520    }
4521    /***/
4522  }
4523
4524  return BS_NEED_MORE;
4525}
4526
4527/* ===========================================================================
4528 * Compress as much as possible from the input stream, return the current
4529 * block state.
4530 * This function does not perform lazy evaluation of matches and inserts
4531 * new strings in the dictionary only for unmatched strings or for short
4532 * matches. It is used only for the fast compression options.
4533 */
4534function deflate_fast(s, flush) {
4535  var hash_head;        /* head of the hash chain */
4536  var bflush;           /* set if current block must be flushed */
4537
4538  for (;;) {
4539    /* Make sure that we always have enough lookahead, except
4540     * at the end of the input file. We need MAX_MATCH bytes
4541     * for the next match, plus MIN_MATCH bytes to insert the
4542     * string following the next match.
4543     */
4544    if (s.lookahead < MIN_LOOKAHEAD) {
4545      fill_window(s);
4546      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
4547        return BS_NEED_MORE;
4548      }
4549      if (s.lookahead === 0) {
4550        break; /* flush the current block */
4551      }
4552    }
4553
4554    /* Insert the string window[strstart .. strstart+2] in the
4555     * dictionary, and set hash_head to the head of the hash chain:
4556     */
4557    hash_head = 0/*NIL*/;
4558    if (s.lookahead >= MIN_MATCH) {
4559      /*** INSERT_STRING(s, s.strstart, hash_head); ***/
4560      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
4561      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
4562      s.head[s.ins_h] = s.strstart;
4563      /***/
4564    }
4565
4566    /* Find the longest match, discarding those <= prev_length.
4567     * At this point we have always match_length < MIN_MATCH
4568     */
4569    if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
4570      /* To simplify the code, we prevent matches with the string
4571       * of window index 0 (in particular we have to avoid a match
4572       * of the string with itself at the start of the input file).
4573       */
4574      s.match_length = longest_match(s, hash_head);
4575      /* longest_match() sets match_start */
4576    }
4577    if (s.match_length >= MIN_MATCH) {
4578      // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
4579
4580      /*** _tr_tally_dist(s, s.strstart - s.match_start,
4581                     s.match_length - MIN_MATCH, bflush); ***/
4582      bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
4583
4584      s.lookahead -= s.match_length;
4585
4586      /* Insert new strings in the hash table only if the match length
4587       * is not too large. This saves time but degrades compression.
4588       */
4589      if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
4590        s.match_length--; /* string at strstart already in table */
4591        do {
4592          s.strstart++;
4593          /*** INSERT_STRING(s, s.strstart, hash_head); ***/
4594          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
4595          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
4596          s.head[s.ins_h] = s.strstart;
4597          /***/
4598          /* strstart never exceeds WSIZE-MAX_MATCH, so there are
4599           * always MIN_MATCH bytes ahead.
4600           */
4601        } while (--s.match_length !== 0);
4602        s.strstart++;
4603      } else
4604      {
4605        s.strstart += s.match_length;
4606        s.match_length = 0;
4607        s.ins_h = s.window[s.strstart];
4608        /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
4609        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;
4610
4611//#if MIN_MATCH != 3
4612//                Call UPDATE_HASH() MIN_MATCH-3 more times
4613//#endif
4614        /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
4615         * matter since it will be recomputed at next deflate call.
4616         */
4617      }
4618    } else {
4619      /* No match, output a literal byte */
4620      //Tracevv((stderr,"%c", s.window[s.strstart]));
4621      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
4622      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
4623
4624      s.lookahead--;
4625      s.strstart++;
4626    }
4627    if (bflush) {
4628      /*** FLUSH_BLOCK(s, 0); ***/
4629      flush_block_only(s, false);
4630      if (s.strm.avail_out === 0) {
4631        return BS_NEED_MORE;
4632      }
4633      /***/
4634    }
4635  }
4636  s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1);
4637  if (flush === Z_FINISH) {
4638    /*** FLUSH_BLOCK(s, 1); ***/
4639    flush_block_only(s, true);
4640    if (s.strm.avail_out === 0) {
4641      return BS_FINISH_STARTED;
4642    }
4643    /***/
4644    return BS_FINISH_DONE;
4645  }
4646  if (s.last_lit) {
4647    /*** FLUSH_BLOCK(s, 0); ***/
4648    flush_block_only(s, false);
4649    if (s.strm.avail_out === 0) {
4650      return BS_NEED_MORE;
4651    }
4652    /***/
4653  }
4654  return BS_BLOCK_DONE;
4655}
4656
4657/* ===========================================================================
4658 * Same as above, but achieves better compression. We use a lazy
4659 * evaluation for matches: a match is finally adopted only if there is
4660 * no better match at the next window position.
4661 */
4662function deflate_slow(s, flush) {
4663  var hash_head;          /* head of hash chain */
4664  var bflush;              /* set if current block must be flushed */
4665
4666  var max_insert;
4667
4668  /* Process the input block. */
4669  for (;;) {
4670    /* Make sure that we always have enough lookahead, except
4671     * at the end of the input file. We need MAX_MATCH bytes
4672     * for the next match, plus MIN_MATCH bytes to insert the
4673     * string following the next match.
4674     */
4675    if (s.lookahead < MIN_LOOKAHEAD) {
4676      fill_window(s);
4677      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
4678        return BS_NEED_MORE;
4679      }
4680      if (s.lookahead === 0) { break; } /* flush the current block */
4681    }
4682
4683    /* Insert the string window[strstart .. strstart+2] in the
4684     * dictionary, and set hash_head to the head of the hash chain:
4685     */
4686    hash_head = 0/*NIL*/;
4687    if (s.lookahead >= MIN_MATCH) {
4688      /*** INSERT_STRING(s, s.strstart, hash_head); ***/
4689      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
4690      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
4691      s.head[s.ins_h] = s.strstart;
4692      /***/
4693    }
4694
4695    /* Find the longest match, discarding those <= prev_length.
4696     */
4697    s.prev_length = s.match_length;
4698    s.prev_match = s.match_start;
4699    s.match_length = MIN_MATCH-1;
4700
4701    if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
4702        s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
4703      /* To simplify the code, we prevent matches with the string
4704       * of window index 0 (in particular we have to avoid a match
4705       * of the string with itself at the start of the input file).
4706       */
4707      s.match_length = longest_match(s, hash_head);
4708      /* longest_match() sets match_start */
4709
4710      if (s.match_length <= 5 &&
4711         (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
4712
4713        /* If prev_match is also MIN_MATCH, match_start is garbage
4714         * but we will ignore the current match anyway.
4715         */
4716        s.match_length = MIN_MATCH-1;
4717      }
4718    }
4719    /* If there was a match at the previous step and the current
4720     * match is not better, output the previous match:
4721     */
4722    if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
4723      max_insert = s.strstart + s.lookahead - MIN_MATCH;
4724      /* Do not insert strings in hash table beyond this. */
4725
4726      //check_match(s, s.strstart-1, s.prev_match, s.prev_length);
4727
4728      /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
4729                     s.prev_length - MIN_MATCH, bflush);***/
4730      bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH);
4731      /* Insert in hash table all strings up to the end of the match.
4732       * strstart-1 and strstart are already inserted. If there is not
4733       * enough lookahead, the last two strings are not inserted in
4734       * the hash table.
4735       */
4736      s.lookahead -= s.prev_length-1;
4737      s.prev_length -= 2;
4738      do {
4739        if (++s.strstart <= max_insert) {
4740          /*** INSERT_STRING(s, s.strstart, hash_head); ***/
4741          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
4742          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
4743          s.head[s.ins_h] = s.strstart;
4744          /***/
4745        }
4746      } while (--s.prev_length !== 0);
4747      s.match_available = 0;
4748      s.match_length = MIN_MATCH-1;
4749      s.strstart++;
4750
4751      if (bflush) {
4752        /*** FLUSH_BLOCK(s, 0); ***/
4753        flush_block_only(s, false);
4754        if (s.strm.avail_out === 0) {
4755          return BS_NEED_MORE;
4756        }
4757        /***/
4758      }
4759
4760    } else if (s.match_available) {
4761      /* If there was no match at the previous position, output a
4762       * single literal. If there was a match but the current match
4763       * is longer, truncate the previous match to a single literal.
4764       */
4765      //Tracevv((stderr,"%c", s->window[s->strstart-1]));
4766      /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
4767      bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);
4768
4769      if (bflush) {
4770        /*** FLUSH_BLOCK_ONLY(s, 0) ***/
4771        flush_block_only(s, false);
4772        /***/
4773      }
4774      s.strstart++;
4775      s.lookahead--;
4776      if (s.strm.avail_out === 0) {
4777        return BS_NEED_MORE;
4778      }
4779    } else {
4780      /* There is no previous match to compare with, wait for
4781       * the next step to decide.
4782       */
4783      s.match_available = 1;
4784      s.strstart++;
4785      s.lookahead--;
4786    }
4787  }
4788  //Assert (flush != Z_NO_FLUSH, "no flush?");
4789  if (s.match_available) {
4790    //Tracevv((stderr,"%c", s->window[s->strstart-1]));
4791    /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
4792    bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);
4793
4794    s.match_available = 0;
4795  }
4796  s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1;
4797  if (flush === Z_FINISH) {
4798    /*** FLUSH_BLOCK(s, 1); ***/
4799    flush_block_only(s, true);
4800    if (s.strm.avail_out === 0) {
4801      return BS_FINISH_STARTED;
4802    }
4803    /***/
4804    return BS_FINISH_DONE;
4805  }
4806  if (s.last_lit) {
4807    /*** FLUSH_BLOCK(s, 0); ***/
4808    flush_block_only(s, false);
4809    if (s.strm.avail_out === 0) {
4810      return BS_NEED_MORE;
4811    }
4812    /***/
4813  }
4814
4815  return BS_BLOCK_DONE;
4816}
4817
4818
4819/* ===========================================================================
4820 * For Z_RLE, simply look for runs of bytes, generate matches only of distance
4821 * one.  Do not maintain a hash table.  (It will be regenerated if this run of
4822 * deflate switches away from Z_RLE.)
4823 */
4824function deflate_rle(s, flush) {
4825  var bflush;            /* set if current block must be flushed */
4826  var prev;              /* byte at distance one to match */
4827  var scan, strend;      /* scan goes up to strend for length of run */
4828
4829  var _win = s.window;
4830
4831  for (;;) {
4832    /* Make sure that we always have enough lookahead, except
4833     * at the end of the input file. We need MAX_MATCH bytes
4834     * for the longest run, plus one for the unrolled loop.
4835     */
4836    if (s.lookahead <= MAX_MATCH) {
4837      fill_window(s);
4838      if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {
4839        return BS_NEED_MORE;
4840      }
4841      if (s.lookahead === 0) { break; } /* flush the current block */
4842    }
4843
4844    /* See how many times the previous byte repeats */
4845    s.match_length = 0;
4846    if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
4847      scan = s.strstart - 1;
4848      prev = _win[scan];
4849      if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
4850        strend = s.strstart + MAX_MATCH;
4851        do {
4852          /*jshint noempty:false*/
4853        } while (prev === _win[++scan] && prev === _win[++scan] &&
4854                 prev === _win[++scan] && prev === _win[++scan] &&
4855                 prev === _win[++scan] && prev === _win[++scan] &&
4856                 prev === _win[++scan] && prev === _win[++scan] &&
4857                 scan < strend);
4858        s.match_length = MAX_MATCH - (strend - scan);
4859        if (s.match_length > s.lookahead) {
4860          s.match_length = s.lookahead;
4861        }
4862      }
4863      //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
4864    }
4865
4866    /* Emit match if have run of MIN_MATCH or longer, else emit literal */
4867    if (s.match_length >= MIN_MATCH) {
4868      //check_match(s, s.strstart, s.strstart - 1, s.match_length);
4869
4870      /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
4871      bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);
4872
4873      s.lookahead -= s.match_length;
4874      s.strstart += s.match_length;
4875      s.match_length = 0;
4876    } else {
4877      /* No match, output a literal byte */
4878      //Tracevv((stderr,"%c", s->window[s->strstart]));
4879      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
4880      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
4881
4882      s.lookahead--;
4883      s.strstart++;
4884    }
4885    if (bflush) {
4886      /*** FLUSH_BLOCK(s, 0); ***/
4887      flush_block_only(s, false);
4888      if (s.strm.avail_out === 0) {
4889        return BS_NEED_MORE;
4890      }
4891      /***/
4892    }
4893  }
4894  s.insert = 0;
4895  if (flush === Z_FINISH) {
4896    /*** FLUSH_BLOCK(s, 1); ***/
4897    flush_block_only(s, true);
4898    if (s.strm.avail_out === 0) {
4899      return BS_FINISH_STARTED;
4900    }
4901    /***/
4902    return BS_FINISH_DONE;
4903  }
4904  if (s.last_lit) {
4905    /*** FLUSH_BLOCK(s, 0); ***/
4906    flush_block_only(s, false);
4907    if (s.strm.avail_out === 0) {
4908      return BS_NEED_MORE;
4909    }
4910    /***/
4911  }
4912  return BS_BLOCK_DONE;
4913}
4914
4915/* ===========================================================================
4916 * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
4917 * (It will be regenerated if this run of deflate switches away from Huffman.)
4918 */
4919function deflate_huff(s, flush) {
4920  var bflush;             /* set if current block must be flushed */
4921
4922  for (;;) {
4923    /* Make sure that we have a literal to write. */
4924    if (s.lookahead === 0) {
4925      fill_window(s);
4926      if (s.lookahead === 0) {
4927        if (flush === Z_NO_FLUSH) {
4928          return BS_NEED_MORE;
4929        }
4930        break;      /* flush the current block */
4931      }
4932    }
4933
4934    /* Output a literal byte */
4935    s.match_length = 0;
4936    //Tracevv((stderr,"%c", s->window[s->strstart]));
4937    /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
4938    bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
4939    s.lookahead--;
4940    s.strstart++;
4941    if (bflush) {
4942      /*** FLUSH_BLOCK(s, 0); ***/
4943      flush_block_only(s, false);
4944      if (s.strm.avail_out === 0) {
4945        return BS_NEED_MORE;
4946      }
4947      /***/
4948    }
4949  }
4950  s.insert = 0;
4951  if (flush === Z_FINISH) {
4952    /*** FLUSH_BLOCK(s, 1); ***/
4953    flush_block_only(s, true);
4954    if (s.strm.avail_out === 0) {
4955      return BS_FINISH_STARTED;
4956    }
4957    /***/
4958    return BS_FINISH_DONE;
4959  }
4960  if (s.last_lit) {
4961    /*** FLUSH_BLOCK(s, 0); ***/
4962    flush_block_only(s, false);
4963    if (s.strm.avail_out === 0) {
4964      return BS_NEED_MORE;
4965    }
4966    /***/
4967  }
4968  return BS_BLOCK_DONE;
4969}
4970
4971/* Values for max_lazy_match, good_match and max_chain_length, depending on
4972 * the desired pack level (0..9). The values given below have been tuned to
4973 * exclude worst case performance for pathological files. Better values may be
4974 * found for specific files.
4975 */
4976var Config = function (good_length, max_lazy, nice_length, max_chain, func) {
4977  this.good_length = good_length;
4978  this.max_lazy = max_lazy;
4979  this.nice_length = nice_length;
4980  this.max_chain = max_chain;
4981  this.func = func;
4982};
4983
4984var configuration_table;
4985
4986configuration_table = [
4987  /*      good lazy nice chain */
4988  new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */
4989  new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */
4990  new Config(4, 5, 16, 8, deflate_fast),           /* 2 */
4991  new Config(4, 6, 32, 32, deflate_fast),          /* 3 */
4992
4993  new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */
4994  new Config(8, 16, 32, 32, deflate_slow),         /* 5 */
4995  new Config(8, 16, 128, 128, deflate_slow),       /* 6 */
4996  new Config(8, 32, 128, 256, deflate_slow),       /* 7 */
4997  new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */
4998  new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */
4999];
5000
5001
5002/* ===========================================================================
5003 * Initialize the "longest match" routines for a new zlib stream
5004 */
5005function lm_init(s) {
5006  s.window_size = 2 * s.w_size;
5007
5008  /*** CLEAR_HASH(s); ***/
5009  zero(s.head); // Fill with NIL (= 0);
5010
5011  /* Set the default configuration parameters:
5012   */
5013  s.max_lazy_match = configuration_table[s.level].max_lazy;
5014  s.good_match = configuration_table[s.level].good_length;
5015  s.nice_match = configuration_table[s.level].nice_length;
5016  s.max_chain_length = configuration_table[s.level].max_chain;
5017
5018  s.strstart = 0;
5019  s.block_start = 0;
5020  s.lookahead = 0;
5021  s.insert = 0;
5022  s.match_length = s.prev_length = MIN_MATCH - 1;
5023  s.match_available = 0;
5024  s.ins_h = 0;
5025}
5026
5027
5028function DeflateState() {
5029  this.strm = null;            /* pointer back to this zlib stream */
5030  this.status = 0;            /* as the name implies */
5031  this.pending_buf = null;      /* output still pending */
5032  this.pending_buf_size = 0;  /* size of pending_buf */
5033  this.pending_out = 0;       /* next pending byte to output to the stream */
5034  this.pending = 0;           /* nb of bytes in the pending buffer */
5035  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
5036  this.gzhead = null;         /* gzip header information to write */
5037  this.gzindex = 0;           /* where in extra, name, or comment */
5038  this.method = Z_DEFLATED; /* can only be DEFLATED */
5039  this.last_flush = -1;   /* value of flush param for previous deflate call */
5040
5041  this.w_size = 0;  /* LZ77 window size (32K by default) */
5042  this.w_bits = 0;  /* log2(w_size)  (8..16) */
5043  this.w_mask = 0;  /* w_size - 1 */
5044
5045  this.window = null;
5046  /* Sliding window. Input bytes are read into the second half of the window,
5047   * and move to the first half later to keep a dictionary of at least wSize
5048   * bytes. With this organization, matches are limited to a distance of
5049   * wSize-MAX_MATCH bytes, but this ensures that IO is always
5050   * performed with a length multiple of the block size.
5051   */
5052
5053  this.window_size = 0;
5054  /* Actual size of window: 2*wSize, except when the user input buffer
5055   * is directly used as sliding window.
5056   */
5057
5058  this.prev = null;
5059  /* Link to older string with same hash index. To limit the size of this
5060   * array to 64K, this link is maintained only for the last 32K strings.
5061   * An index in this array is thus a window index modulo 32K.
5062   */
5063
5064  this.head = null;   /* Heads of the hash chains or NIL. */
5065
5066  this.ins_h = 0;       /* hash index of string to be inserted */
5067  this.hash_size = 0;   /* number of elements in hash table */
5068  this.hash_bits = 0;   /* log2(hash_size) */
5069  this.hash_mask = 0;   /* hash_size-1 */
5070
5071  this.hash_shift = 0;
5072  /* Number of bits by which ins_h must be shifted at each input
5073   * step. It must be such that after MIN_MATCH steps, the oldest
5074   * byte no longer takes part in the hash key, that is:
5075   *   hash_shift * MIN_MATCH >= hash_bits
5076   */
5077
5078  this.block_start = 0;
5079  /* Window position at the beginning of the current output block. Gets
5080   * negative when the window is moved backwards.
5081   */
5082
5083  this.match_length = 0;      /* length of best match */
5084  this.prev_match = 0;        /* previous match */
5085  this.match_available = 0;   /* set if previous match exists */
5086  this.strstart = 0;          /* start of string to insert */
5087  this.match_start = 0;       /* start of matching string */
5088  this.lookahead = 0;         /* number of valid bytes ahead in window */
5089
5090  this.prev_length = 0;
5091  /* Length of the best match at previous step. Matches not greater than this
5092   * are discarded. This is used in the lazy match evaluation.
5093   */
5094
5095  this.max_chain_length = 0;
5096  /* To speed up deflation, hash chains are never searched beyond this
5097   * length.  A higher limit improves compression ratio but degrades the
5098   * speed.
5099   */
5100
5101  this.max_lazy_match = 0;
5102  /* Attempt to find a better match only when the current match is strictly
5103   * smaller than this value. This mechanism is used only for compression
5104   * levels >= 4.
5105   */
5106  // That's alias to max_lazy_match, don't use directly
5107  //this.max_insert_length = 0;
5108  /* Insert new strings in the hash table only if the match length is not
5109   * greater than this length. This saves time but degrades compression.
5110   * max_insert_length is used only for compression levels <= 3.
5111   */
5112
5113  this.level = 0;     /* compression level (1..9) */
5114  this.strategy = 0;  /* favor or force Huffman coding*/
5115
5116  this.good_match = 0;
5117  /* Use a faster search when the previous match is longer than this */
5118
5119  this.nice_match = 0; /* Stop searching when current match exceeds this */
5120
5121              /* used by trees.c: */
5122
5123  /* Didn't use ct_data typedef below to suppress compiler warning */
5124
5125  // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
5126  // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
5127  // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
5128
5129  // Use flat array of DOUBLE size, with interleaved fata,
5130  // because JS does not support effective
5131  this.dyn_ltree  = new utils.Buf16(HEAP_SIZE * 2);
5132  this.dyn_dtree  = new utils.Buf16((2*D_CODES+1) * 2);
5133  this.bl_tree    = new utils.Buf16((2*BL_CODES+1) * 2);
5134  zero(this.dyn_ltree);
5135  zero(this.dyn_dtree);
5136  zero(this.bl_tree);
5137
5138  this.l_desc   = null;         /* desc. for literal tree */
5139  this.d_desc   = null;         /* desc. for distance tree */
5140  this.bl_desc  = null;         /* desc. for bit length tree */
5141
5142  //ush bl_count[MAX_BITS+1];
5143  this.bl_count = new utils.Buf16(MAX_BITS+1);
5144  /* number of codes at each bit length for an optimal tree */
5145
5146  //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
5147  this.heap = new utils.Buf16(2*L_CODES+1);  /* heap used to build the Huffman trees */
5148  zero(this.heap);
5149
5150  this.heap_len = 0;               /* number of elements in the heap */
5151  this.heap_max = 0;               /* element of largest frequency */
5152  /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
5153   * The same heap array is used to build all trees.
5154   */
5155
5156  this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1];
5157  zero(this.depth);
5158  /* Depth of each subtree used as tie breaker for trees of equal frequency
5159   */
5160
5161  this.l_buf = 0;          /* buffer index for literals or lengths */
5162
5163  this.lit_bufsize = 0;
5164  /* Size of match buffer for literals/lengths.  There are 4 reasons for
5165   * limiting lit_bufsize to 64K:
5166   *   - frequencies can be kept in 16 bit counters
5167   *   - if compression is not successful for the first block, all input
5168   *     data is still in the window so we can still emit a stored block even
5169   *     when input comes from standard input.  (This can also be done for
5170   *     all blocks if lit_bufsize is not greater than 32K.)
5171   *   - if compression is not successful for a file smaller than 64K, we can
5172   *     even emit a stored file instead of a stored block (saving 5 bytes).
5173   *     This is applicable only for zip (not gzip or zlib).
5174   *   - creating new Huffman trees less frequently may not provide fast
5175   *     adaptation to changes in the input data statistics. (Take for
5176   *     example a binary file with poorly compressible code followed by
vendor: 3,610 bytes, lines 5177-5317
5177   *     a highly compressible string table.) Smaller buffer sizes give
5178   *     fast adaptation but have of course the overhead of transmitting
5179   *     trees more frequently.
5180   *   - I can't count above 4
5181   */
5182
5183  this.last_lit = 0;      /* running index in l_buf */
5184
5185  this.d_buf = 0;
5186  /* Buffer index for distances. To simplify the code, d_buf and l_buf have
5187   * the same number of elements. To use different lengths, an extra flag
5188   * array would be necessary.
5189   */
5190
5191  this.opt_len = 0;       /* bit length of current block with optimal trees */
5192  this.static_len = 0;    /* bit length of current block with static trees */
5193  this.matches = 0;       /* number of string matches in current block */
5194  this.insert = 0;        /* bytes at end of window left to insert */
5195
5196
5197  this.bi_buf = 0;
5198  /* Output buffer. bits are inserted starting at the bottom (least
5199   * significant bits).
5200   */
5201  this.bi_valid = 0;
5202  /* Number of valid bits in bi_buf.  All bits above the last valid bit
5203   * are always zero.
5204   */
5205
5206  // Used for window memory init. We safely ignore it for JS. That makes
5207  // sense only for pointers and memory check tools.
5208  //this.high_water = 0;
5209  /* High water mark offset in window for initialized bytes -- bytes above
5210   * this are set to zero in order to avoid memory check warnings when
5211   * longest match routines access bytes past the input.  This is then
5212   * updated to the new high water mark.
5213   */
5214}
5215
5216
5217function deflateResetKeep(strm) {
5218  var s;
5219
5220  if (!strm || !strm.state) {
5221    return err(strm, Z_STREAM_ERROR);
5222  }
5223
5224  strm.total_in = strm.total_out = 0;
5225  strm.data_type = Z_UNKNOWN;
5226
5227  s = strm.state;
5228  s.pending = 0;
5229  s.pending_out = 0;
5230
5231  if (s.wrap < 0) {
5232    s.wrap = -s.wrap;
5233    /* was made negative by deflate(..., Z_FINISH); */
5234  }
5235  s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
5236  strm.adler = (s.wrap === 2) ?
5237    0  // crc32(0, Z_NULL, 0)
5238  :
5239    1; // adler32(0, Z_NULL, 0)
5240  s.last_flush = Z_NO_FLUSH;
5241  trees._tr_init(s);
5242  return Z_OK;
5243}
5244
5245
5246function deflateReset(strm) {
5247  var ret = deflateResetKeep(strm);
5248  if (ret === Z_OK) {
5249    lm_init(strm.state);
5250  }
5251  return ret;
5252}
5253
5254
5255function deflateSetHeader(strm, head) {
5256  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
5257  if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
5258  strm.state.gzhead = head;
5259  return Z_OK;
5260}
5261
5262
5263function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
5264  if (!strm) { // === Z_NULL
5265    return Z_STREAM_ERROR;
5266  }
5267  var wrap = 1;
5268
5269  if (level === Z_DEFAULT_COMPRESSION) {
5270    level = 6;
5271  }
5272
5273  if (windowBits < 0) { /* suppress zlib wrapper */
5274    wrap = 0;
5275    windowBits = -windowBits;
5276  }
5277
5278  else if (windowBits > 15) {
5279    wrap = 2;           /* write gzip wrapper instead */
5280    windowBits -= 16;
5281  }
5282
5283
5284  if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
5285    windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
5286    strategy < 0 || strategy > Z_FIXED) {
5287    return err(strm, Z_STREAM_ERROR);
5288  }
5289
5290
5291  if (windowBits === 8) {
5292    windowBits = 9;
5293  }
5294  /* until 256-byte window bug fixed */
5295
5296  var s = new DeflateState();
5297
5298  strm.state = s;
5299  s.strm = strm;
5300
5301  s.wrap = wrap;
5302  s.gzhead = null;
5303  s.w_bits = windowBits;
5304  s.w_size = 1 << s.w_bits;
5305  s.w_mask = s.w_size - 1;
5306
5307  s.hash_bits = memLevel + 7;
5308  s.hash_size = 1 << s.hash_bits;
5309  s.hash_mask = s.hash_size - 1;
5310  s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
5311
5312  s.window = new utils.Buf8(s.w_size * 2);
5313  s.head = new utils.Buf16(s.hash_size);
5314  s.prev = new utils.Buf16(s.w_size);
5315
5316  // Don't need mem init magic for JS.
5317  //s.high_water = 0;
vendor: 12,835 bytes, lines 5317-5742
5317  /* nothing written to s->window yet */
5318
5319  s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
5320
5321  s.pending_buf_size = s.lit_bufsize * 4;
5322  s.pending_buf = new utils.Buf8(s.pending_buf_size);
5323
5324  s.d_buf = s.lit_bufsize >> 1;
5325  s.l_buf = (1 + 2) * s.lit_bufsize;
5326
5327  s.level = level;
5328  s.strategy = strategy;
5329  s.method = method;
5330
5331  return deflateReset(strm);
5332}
5333
5334function deflateInit(strm, level) {
5335  return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
5336}
5337
5338
5339function deflate(strm, flush) {
5340  var old_flush, s;
5341  var beg, val; // for gzip header write only
5342
5343  if (!strm || !strm.state ||
5344    flush > Z_BLOCK || flush < 0) {
5345    return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
5346  }
5347
5348  s = strm.state;
5349
5350  if (!strm.output ||
5351      (!strm.input && strm.avail_in !== 0) ||
5352      (s.status === FINISH_STATE && flush !== Z_FINISH)) {
5353    return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
5354  }
5355
5356  s.strm = strm; /* just in case */
5357  old_flush = s.last_flush;
5358  s.last_flush = flush;
5359
5360  /* Write the header */
5361  if (s.status === INIT_STATE) {
5362
5363    if (s.wrap === 2) { // GZIP header
5364      strm.adler = 0;  //crc32(0L, Z_NULL, 0);
5365      put_byte(s, 31);
5366      put_byte(s, 139);
5367      put_byte(s, 8);
5368      if (!s.gzhead) { // s->gzhead == Z_NULL
5369        put_byte(s, 0);
5370        put_byte(s, 0);
5371        put_byte(s, 0);
5372        put_byte(s, 0);
5373        put_byte(s, 0);
5374        put_byte(s, s.level === 9 ? 2 :
5375                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
5376                     4 : 0));
5377        put_byte(s, OS_CODE);
5378        s.status = BUSY_STATE;
5379      }
5380      else {
5381        put_byte(s, (s.gzhead.text ? 1 : 0) +
5382                    (s.gzhead.hcrc ? 2 : 0) +
5383                    (!s.gzhead.extra ? 0 : 4) +
5384                    (!s.gzhead.name ? 0 : 8) +
5385                    (!s.gzhead.comment ? 0 : 16)
5386                );
5387        put_byte(s, s.gzhead.time & 0xff);
5388        put_byte(s, (s.gzhead.time >> 8) & 0xff);
5389        put_byte(s, (s.gzhead.time >> 16) & 0xff);
5390        put_byte(s, (s.gzhead.time >> 24) & 0xff);
5391        put_byte(s, s.level === 9 ? 2 :
5392                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
5393                     4 : 0));
5394        put_byte(s, s.gzhead.os & 0xff);
5395        if (s.gzhead.extra && s.gzhead.extra.length) {
5396          put_byte(s, s.gzhead.extra.length & 0xff);
5397          put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
5398        }
5399        if (s.gzhead.hcrc) {
5400          strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
5401        }
5402        s.gzindex = 0;
5403        s.status = EXTRA_STATE;
5404      }
5405    }
5406    else // DEFLATE header
5407    {
5408      var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
5409      var level_flags = -1;
5410
5411      if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
5412        level_flags = 0;
5413      } else if (s.level < 6) {
5414        level_flags = 1;
5415      } else if (s.level === 6) {
5416        level_flags = 2;
5417      } else {
5418        level_flags = 3;
5419      }
5420      header |= (level_flags << 6);
5421      if (s.strstart !== 0) { header |= PRESET_DICT; }
5422      header += 31 - (header % 31);
5423
5424      s.status = BUSY_STATE;
5425      putShortMSB(s, header);
5426
5427      /* Save the adler32 of the preset dictionary: */
5428      if (s.strstart !== 0) {
5429        putShortMSB(s, strm.adler >>> 16);
5430        putShortMSB(s, strm.adler & 0xffff);
5431      }
5432      strm.adler = 1; // adler32(0L, Z_NULL, 0);
5433    }
5434  }
5435
5436//#ifdef GZIP
5437  if (s.status === EXTRA_STATE) {
5438    if (s.gzhead.extra/* != Z_NULL*/) {
5439      beg = s.pending;  /* start of bytes to update crc */
5440
5441      while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
5442        if (s.pending === s.pending_buf_size) {
5443          if (s.gzhead.hcrc && s.pending > beg) {
5444            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
5445          }
5446          flush_pending(strm);
5447          beg = s.pending;
5448          if (s.pending === s.pending_buf_size) {
5449            break;
5450          }
5451        }
5452        put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
5453        s.gzindex++;
5454      }
5455      if (s.gzhead.hcrc && s.pending > beg) {
5456        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
5457      }
5458      if (s.gzindex === s.gzhead.extra.length) {
5459        s.gzindex = 0;
5460        s.status = NAME_STATE;
5461      }
5462    }
5463    else {
5464      s.status = NAME_STATE;
5465    }
5466  }
5467  if (s.status === NAME_STATE) {
5468    if (s.gzhead.name/* != Z_NULL*/) {
5469      beg = s.pending;  /* start of bytes to update crc */
5470      //int val;
5471
5472      do {
5473        if (s.pending === s.pending_buf_size) {
5474          if (s.gzhead.hcrc && s.pending > beg) {
5475            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
5476          }
5477          flush_pending(strm);
5478          beg = s.pending;
5479          if (s.pending === s.pending_buf_size) {
5480            val = 1;
5481            break;
5482          }
5483        }
5484        // JS specific: little magic to add zero terminator to end of string
5485        if (s.gzindex < s.gzhead.name.length) {
5486          val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
5487        } else {
5488          val = 0;
5489        }
5490        put_byte(s, val);
5491      } while (val !== 0);
5492
5493      if (s.gzhead.hcrc && s.pending > beg){
5494        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
5495      }
5496      if (val === 0) {
5497        s.gzindex = 0;
5498        s.status = COMMENT_STATE;
5499      }
5500    }
5501    else {
5502      s.status = COMMENT_STATE;
5503    }
5504  }
5505  if (s.status === COMMENT_STATE) {
5506    if (s.gzhead.comment/* != Z_NULL*/) {
5507      beg = s.pending;  /* start of bytes to update crc */
5508      //int val;
5509
5510      do {
5511        if (s.pending === s.pending_buf_size) {
5512          if (s.gzhead.hcrc && s.pending > beg) {
5513            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
5514          }
5515          flush_pending(strm);
5516          beg = s.pending;
5517          if (s.pending === s.pending_buf_size) {
5518            val = 1;
5519            break;
5520          }
5521        }
5522        // JS specific: little magic to add zero terminator to end of string
5523        if (s.gzindex < s.gzhead.comment.length) {
5524          val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
5525        } else {
5526          val = 0;
5527        }
5528        put_byte(s, val);
5529      } while (val !== 0);
5530
5531      if (s.gzhead.hcrc && s.pending > beg) {
5532        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
5533      }
5534      if (val === 0) {
5535        s.status = HCRC_STATE;
5536      }
5537    }
5538    else {
5539      s.status = HCRC_STATE;
5540    }
5541  }
5542  if (s.status === HCRC_STATE) {
5543    if (s.gzhead.hcrc) {
5544      if (s.pending + 2 > s.pending_buf_size) {
5545        flush_pending(strm);
5546      }
5547      if (s.pending + 2 <= s.pending_buf_size) {
5548        put_byte(s, strm.adler & 0xff);
5549        put_byte(s, (strm.adler >> 8) & 0xff);
5550        strm.adler = 0; //crc32(0L, Z_NULL, 0);
5551        s.status = BUSY_STATE;
5552      }
5553    }
5554    else {
5555      s.status = BUSY_STATE;
5556    }
5557  }
5558//#endif
5559
5560  /* Flush as much pending output as possible */
5561  if (s.pending !== 0) {
5562    flush_pending(strm);
5563    if (strm.avail_out === 0) {
5564      /* Since avail_out is 0, deflate will be called again with
5565       * more output space, but possibly with both pending and
5566       * avail_in equal to zero. There won't be anything to do,
5567       * but this is not an error situation so make sure we
5568       * return OK instead of BUF_ERROR at next call of deflate:
5569       */
5570      s.last_flush = -1;
5571      return Z_OK;
5572    }
5573
5574    /* Make sure there is something to do and avoid duplicate consecutive
5575     * flushes. For repeated and useless calls with Z_FINISH, we keep
5576     * returning Z_STREAM_END instead of Z_BUF_ERROR.
5577     */
5578  } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
5579    flush !== Z_FINISH) {
5580    return err(strm, Z_BUF_ERROR);
5581  }
5582
5583  /* User must not provide more input after the first FINISH: */
5584  if (s.status === FINISH_STATE && strm.avail_in !== 0) {
5585    return err(strm, Z_BUF_ERROR);
5586  }
5587
5588  /* Start a new block or continue the current one.
5589   */
5590  if (strm.avail_in !== 0 || s.lookahead !== 0 ||
5591    (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
5592    var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
5593      (s.strategy === Z_RLE ? deflate_rle(s, flush) :
5594        configuration_table[s.level].func(s, flush));
5595
5596    if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
5597      s.status = FINISH_STATE;
5598    }
5599    if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
5600      if (strm.avail_out === 0) {
5601        s.last_flush = -1;
5602        /* avoid BUF_ERROR next call, see above */
5603      }
5604      return Z_OK;
5605      /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
5606       * of deflate should use the same flush parameter to make sure
5607       * that the flush is complete. So we don't have to output an
5608       * empty block here, this will be done at next call. This also
5609       * ensures that for a very small output buffer, we emit at most
5610       * one empty block.
5611       */
5612    }
5613    if (bstate === BS_BLOCK_DONE) {
5614      if (flush === Z_PARTIAL_FLUSH) {
5615        trees._tr_align(s);
5616      }
5617      else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
5618
5619        trees._tr_stored_block(s, 0, 0, false);
5620        /* For a full flush, this empty block will be recognized
5621         * as a special marker by inflate_sync().
5622         */
5623        if (flush === Z_FULL_FLUSH) {
5624          /*** CLEAR_HASH(s); ***/             /* forget history */
5625          zero(s.head); // Fill with NIL (= 0);
5626
5627          if (s.lookahead === 0) {
5628            s.strstart = 0;
5629            s.block_start = 0;
5630            s.insert = 0;
5631          }
5632        }
5633      }
5634      flush_pending(strm);
5635      if (strm.avail_out === 0) {
5636        s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
5637        return Z_OK;
5638      }
5639    }
5640  }
5641  //Assert(strm->avail_out > 0, "bug2");
5642  //if (strm.avail_out <= 0) { throw new Error("bug2");}
5643
5644  if (flush !== Z_FINISH) { return Z_OK; }
5645  if (s.wrap <= 0) { return Z_STREAM_END; }
5646
5647  /* Write the trailer */
5648  if (s.wrap === 2) {
5649    put_byte(s, strm.adler & 0xff);
5650    put_byte(s, (strm.adler >> 8) & 0xff);
5651    put_byte(s, (strm.adler >> 16) & 0xff);
5652    put_byte(s, (strm.adler >> 24) & 0xff);
5653    put_byte(s, strm.total_in & 0xff);
5654    put_byte(s, (strm.total_in >> 8) & 0xff);
5655    put_byte(s, (strm.total_in >> 16) & 0xff);
5656    put_byte(s, (strm.total_in >> 24) & 0xff);
5657  }
5658  else
5659  {
5660    putShortMSB(s, strm.adler >>> 16);
5661    putShortMSB(s, strm.adler & 0xffff);
5662  }
5663
5664  flush_pending(strm);
5665  /* If avail_out is zero, the application will call deflate again
5666   * to flush the rest.
5667   */
5668  if (s.wrap > 0) { s.wrap = -s.wrap; }
5669  /* write the trailer only once! */
5670  return s.pending !== 0 ? Z_OK : Z_STREAM_END;
5671}
5672
5673function deflateEnd(strm) {
5674  var status;
5675
5676  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
5677    return Z_STREAM_ERROR;
5678  }
5679
5680  status = strm.state.status;
5681  if (status !== INIT_STATE &&
5682    status !== EXTRA_STATE &&
5683    status !== NAME_STATE &&
5684    status !== COMMENT_STATE &&
5685    status !== HCRC_STATE &&
5686    status !== BUSY_STATE &&
5687    status !== FINISH_STATE
5688  ) {
5689    return err(strm, Z_STREAM_ERROR);
5690  }
5691
5692  strm.state = null;
5693
5694  return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
5695}
5696
5697/* =========================================================================
5698 * Copy the source state to the destination state
5699 */
5700//function deflateCopy(dest, source) {
5701//
5702//}
5703
5704exports.deflateInit = deflateInit;
5705exports.deflateInit2 = deflateInit2;
5706exports.deflateReset = deflateReset;
5707exports.deflateResetKeep = deflateResetKeep;
5708exports.deflateSetHeader = deflateSetHeader;
5709exports.deflate = deflate;
5710exports.deflateEnd = deflateEnd;
5711exports.deflateInfo = 'pako deflate (from Nodeca project)';
5712
5713/* Not implemented
5714exports.deflateBound = deflateBound;
5715exports.deflateCopy = deflateCopy;
5716exports.deflateSetDictionary = deflateSetDictionary;
5717exports.deflateParams = deflateParams;
5718exports.deflatePending = deflatePending;
5719exports.deflatePrime = deflatePrime;
5720exports.deflateTune = deflateTune;
5721*/
5722},{"../utils/common":27,"./adler32":29,"./crc32":31,"./messages":37,"./trees":38}],33:[function(_dereq_,module,exports){
5723'use strict';
5724
5725
5726function GZheader() {
5727  /* true if compressed data believed to be text */
5728  this.text       = 0;
5729  /* modification time */
5730  this.time       = 0;
5731  /* extra flags (not used when writing a gzip file) */
5732  this.xflags     = 0;
5733  /* operating system */
5734  this.os         = 0;
5735  /* pointer to extra field or Z_NULL if none */
5736  this.extra      = null;
5737  /* extra field length (valid if extra != Z_NULL) */
5738  this.extra_len  = 0; // Actually, we don't need it in JS,
5739                       // but leave for few code modifications
5740
5741  //
5742  // Setup limits is not necessary because in js we should not preallocate memory
5742 
vendor: 110,633 bytes, lines 5742-9167
5742
5743  // for inflate use constant limit in 65536 bytes
5744  //
5745
5746  /* space at extra (only when reading header) */
5747  // this.extra_max  = 0;
5748  /* pointer to zero-terminated file name or Z_NULL */
5749  this.name       = '';
5750  /* space at name (only when reading header) */
5751  // this.name_max   = 0;
5752  /* pointer to zero-terminated comment or Z_NULL */
5753  this.comment    = '';
5754  /* space at comment (only when reading header) */
5755  // this.comm_max   = 0;
5756  /* true if there was or will be a header crc */
5757  this.hcrc       = 0;
5758  /* true when done reading gzip header (not used when writing a gzip file) */
5759  this.done       = false;
5760}
5761
5762module.exports = GZheader;
5763},{}],34:[function(_dereq_,module,exports){
5764'use strict';
5765
5766// See state defs from inflate.js
5767var BAD = 30;       /* got a data error -- remain here until reset */
5768var TYPE = 12;      /* i: waiting for type bits, including last-flag bit */
5769
5770/*
5771   Decode literal, length, and distance codes and write out the resulting
5772   literal and match bytes until either not enough input or output is
5773   available, an end-of-block is encountered, or a data error is encountered.
5774   When large enough input and output buffers are supplied to inflate(), for
5775   example, a 16K input buffer and a 64K output buffer, more than 95% of the
5776   inflate execution time is spent in this routine.
5777
5778   Entry assumptions:
5779
5780        state.mode === LEN
5781        strm.avail_in >= 6
5782        strm.avail_out >= 258
5783        start >= strm.avail_out
5784        state.bits < 8
5785
5786   On return, state.mode is one of:
5787
5788        LEN -- ran out of enough output space or enough available input
5789        TYPE -- reached end of block code, inflate() to interpret next block
5790        BAD -- error in block data
5791
5792   Notes:
5793
5794    - The maximum input bits used by a length/distance pair is 15 bits for the
5795      length code, 5 bits for the length extra, 15 bits for the distance code,
5796      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
5797      Therefore if strm.avail_in >= 6, then there is enough input to avoid
5798      checking for available input while decoding.
5799
5800    - The maximum bytes that a single length/distance pair can output is 258
5801      bytes, which is the maximum length that can be coded.  inflate_fast()
5802      requires strm.avail_out >= 258 for each loop to avoid checking for
5803      output space.
5804 */
5805module.exports = function inflate_fast(strm, start) {
5806  var state;
5807  var _in;                    /* local strm.input */
5808  var last;                   /* have enough input while in < last */
5809  var _out;                   /* local strm.output */
5810  var beg;                    /* inflate()'s initial strm.output */
5811  var end;                    /* while out < end, enough space available */
5812//#ifdef INFLATE_STRICT
5813  var dmax;                   /* maximum distance from zlib header */
5814//#endif
5815  var wsize;                  /* window size or zero if not using window */
5816  var whave;                  /* valid bytes in the window */
5817  var wnext;                  /* window write index */
5818  var window;                 /* allocated sliding window, if wsize != 0 */
5819  var hold;                   /* local strm.hold */
5820  var bits;                   /* local strm.bits */
5821  var lcode;                  /* local strm.lencode */
5822  var dcode;                  /* local strm.distcode */
5823  var lmask;                  /* mask for first level of length codes */
5824  var dmask;                  /* mask for first level of distance codes */
5825  var here;                   /* retrieved table entry */
5826  var op;                     /* code bits, operation, extra bits, or */
5827                              /*  window position, window bytes to copy */
5828  var len;                    /* match length, unused bytes */
5829  var dist;                   /* match distance */
5830  var from;                   /* where to copy match from */
5831  var from_source;
5832
5833
5834  var input, output; // JS specific, because we have no pointers
5835
5836  /* copy state to local variables */
5837  state = strm.state;
5838  //here = state.here;
5839  _in = strm.next_in;
5840  input = strm.input;
5841  last = _in + (strm.avail_in - 5);
5842  _out = strm.next_out;
5843  output = strm.output;
5844  beg = _out - (start - strm.avail_out);
5845  end = _out + (strm.avail_out - 257);
5846//#ifdef INFLATE_STRICT
5847  dmax = state.dmax;
5848//#endif
5849  wsize = state.wsize;
5850  whave = state.whave;
5851  wnext = state.wnext;
5852  window = state.window;
5853  hold = state.hold;
5854  bits = state.bits;
5855  lcode = state.lencode;
5856  dcode = state.distcode;
5857  lmask = (1 << state.lenbits) - 1;
5858  dmask = (1 << state.distbits) - 1;
5859
5860
5861  /* decode literals and length/distances until end-of-block or not enough
5862     input data or output space */
5863
5864  top:
5865  do {
5866    if (bits < 15) {
5867      hold += input[_in++] << bits;
5868      bits += 8;
5869      hold += input[_in++] << bits;
5870      bits += 8;
5871    }
5872
5873    here = lcode[hold & lmask];
5874
5875    dolen:
5876    for (;;) { // Goto emulation
5877      op = here >>> 24/*here.bits*/;
5878      hold >>>= op;
5879      bits -= op;
5880      op = (here >>> 16) & 0xff/*here.op*/;
5881      if (op === 0) {                          /* literal */
5882        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
5883        //        "inflate:         literal '%c'\n" :
5884        //        "inflate:         literal 0x%02x\n", here.val));
5885        output[_out++] = here & 0xffff/*here.val*/;
5886      }
5887      else if (op & 16) {                     /* length base */
5888        len = here & 0xffff/*here.val*/;
5889        op &= 15;                           /* number of extra bits */
5890        if (op) {
5891          if (bits < op) {
5892            hold += input[_in++] << bits;
5893            bits += 8;
5894          }
5895          len += hold & ((1 << op) - 1);
5896          hold >>>= op;
5897          bits -= op;
5898        }
5899        //Tracevv((stderr, "inflate:         length %u\n", len));
5900        if (bits < 15) {
5901          hold += input[_in++] << bits;
5902          bits += 8;
5903          hold += input[_in++] << bits;
5904          bits += 8;
5905        }
5906        here = dcode[hold & dmask];
5907
5908        dodist:
5909        for (;;) { // goto emulation
5910          op = here >>> 24/*here.bits*/;
5911          hold >>>= op;
5912          bits -= op;
5913          op = (here >>> 16) & 0xff/*here.op*/;
5914
5915          if (op & 16) {                      /* distance base */
5916            dist = here & 0xffff/*here.val*/;
5917            op &= 15;                       /* number of extra bits */
5918            if (bits < op) {
5919              hold += input[_in++] << bits;
5920              bits += 8;
5921              if (bits < op) {
5922                hold += input[_in++] << bits;
5923                bits += 8;
5924              }
5925            }
5926            dist += hold & ((1 << op) - 1);
5927//#ifdef INFLATE_STRICT
5928            if (dist > dmax) {
5929              strm.msg = 'invalid distance too far back';
5930              state.mode = BAD;
5931              break top;
5932            }
5933//#endif
5934            hold >>>= op;
5935            bits -= op;
5936            //Tracevv((stderr, "inflate:         distance %u\n", dist));
5937            op = _out - beg;                /* max distance in output */
5938            if (dist > op) {                /* see if copy from window */
5939              op = dist - op;               /* distance back in window */
5940              if (op > whave) {
5941                if (state.sane) {
5942                  strm.msg = 'invalid distance too far back';
5943                  state.mode = BAD;
5944                  break top;
5945                }
5946
5947// (!) This block is disabled in zlib defailts,
5948// don't enable it for binary compatibility
5949//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
5950//                if (len <= op - whave) {
5951//                  do {
5952//                    output[_out++] = 0;
5953//                  } while (--len);
5954//                  continue top;
5955//                }
5956//                len -= op - whave;
5957//                do {
5958//                  output[_out++] = 0;
5959//                } while (--op > whave);
5960//                if (op === 0) {
5961//                  from = _out - dist;
5962//                  do {
5963//                    output[_out++] = output[from++];
5964//                  } while (--len);
5965//                  continue top;
5966//                }
5967//#endif
5968              }
5969              from = 0; // window index
5970              from_source = window;
5971              if (wnext === 0) {           /* very common case */
5972                from += wsize - op;
5973                if (op < len) {         /* some from window */
5974                  len -= op;
5975                  do {
5976                    output[_out++] = window[from++];
5977                  } while (--op);
5978                  from = _out - dist;  /* rest from output */
5979                  from_source = output;
5980                }
5981              }
5982              else if (wnext < op) {      /* wrap around window */
5983                from += wsize + wnext - op;
5984                op -= wnext;
5985                if (op < len) {         /* some from end of window */
5986                  len -= op;
5987                  do {
5988                    output[_out++] = window[from++];
5989                  } while (--op);
5990                  from = 0;
5991                  if (wnext < len) {  /* some from start of window */
5992                    op = wnext;
5993                    len -= op;
5994                    do {
5995                      output[_out++] = window[from++];
5996                    } while (--op);
5997                    from = _out - dist;      /* rest from output */
5998                    from_source = output;
5999                  }
6000                }
6001              }
6002              else {                      /* contiguous in window */
6003                from += wnext - op;
6004                if (op < len) {         /* some from window */
6005                  len -= op;
6006                  do {
6007                    output[_out++] = window[from++];
6008                  } while (--op);
6009                  from = _out - dist;  /* rest from output */
6010                  from_source = output;
6011                }
6012              }
6013              while (len > 2) {
6014                output[_out++] = from_source[from++];
6015                output[_out++] = from_source[from++];
6016                output[_out++] = from_source[from++];
6017                len -= 3;
6018              }
6019              if (len) {
6020                output[_out++] = from_source[from++];
6021                if (len > 1) {
6022                  output[_out++] = from_source[from++];
6023                }
6024              }
6025            }
6026            else {
6027              from = _out - dist;          /* copy direct from output */
6028              do {                        /* minimum length is three */
6029                output[_out++] = output[from++];
6030                output[_out++] = output[from++];
6031                output[_out++] = output[from++];
6032                len -= 3;
6033              } while (len > 2);
6034              if (len) {
6035                output[_out++] = output[from++];
6036                if (len > 1) {
6037                  output[_out++] = output[from++];
6038                }
6039              }
6040            }
6041          }
6042          else if ((op & 64) === 0) {          /* 2nd level distance code */
6043            here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
6044            continue dodist;
6045          }
6046          else {
6047            strm.msg = 'invalid distance code';
6048            state.mode = BAD;
6049            break top;
6050          }
6051
6052          break; // need to emulate goto via "continue"
6053        }
6054      }
6055      else if ((op & 64) === 0) {              /* 2nd level length code */
6056        here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
6057        continue dolen;
6058      }
6059      else if (op & 32) {                     /* end-of-block */
6060        //Tracevv((stderr, "inflate:         end of block\n"));
6061        state.mode = TYPE;
6062        break top;
6063      }
6064      else {
6065        strm.msg = 'invalid literal/length code';
6066        state.mode = BAD;
6067        break top;
6068      }
6069
6070      break; // need to emulate goto via "continue"
6071    }
6072  } while (_in < last && _out < end);
6073
6074  /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
6075  len = bits >> 3;
6076  _in -= len;
6077  bits -= len << 3;
6078  hold &= (1 << bits) - 1;
6079
6080  /* update state and return */
6081  strm.next_in = _in;
6082  strm.next_out = _out;
6083  strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
6084  strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
6085  state.hold = hold;
6086  state.bits = bits;
6087  return;
6088};
6089
6090},{}],35:[function(_dereq_,module,exports){
6091'use strict';
6092
6093
6094var utils = _dereq_('../utils/common');
6095var adler32 = _dereq_('./adler32');
6096var crc32   = _dereq_('./crc32');
6097var inflate_fast = _dereq_('./inffast');
6098var inflate_table = _dereq_('./inftrees');
6099
6100var CODES = 0;
6101var LENS = 1;
6102var DISTS = 2;
6103
6104/* Public constants ==========================================================*/
6105/* ===========================================================================*/
6106
6107
6108/* Allowed flush values; see deflate() and inflate() below for details */
6109//var Z_NO_FLUSH      = 0;
6110//var Z_PARTIAL_FLUSH = 1;
6111//var Z_SYNC_FLUSH    = 2;
6112//var Z_FULL_FLUSH    = 3;
6113var Z_FINISH        = 4;
6114var Z_BLOCK         = 5;
6115var Z_TREES         = 6;
6116
6117
6118/* Return codes for the compression/decompression functions. Negative values
6119 * are errors, positive values are used for special but normal events.
6120 */
6121var Z_OK            = 0;
6122var Z_STREAM_END    = 1;
6123var Z_NEED_DICT     = 2;
6124//var Z_ERRNO         = -1;
6125var Z_STREAM_ERROR  = -2;
6126var Z_DATA_ERROR    = -3;
6127var Z_MEM_ERROR     = -4;
6128var Z_BUF_ERROR     = -5;
6129//var Z_VERSION_ERROR = -6;
6130
6131/* The deflate compression method */
6132var Z_DEFLATED  = 8;
6133
6134
6135/* STATES ====================================================================*/
6136/* ===========================================================================*/
6137
6138
6139var    HEAD = 1;       /* i: waiting for magic header */
6140var    FLAGS = 2;      /* i: waiting for method and flags (gzip) */
6141var    TIME = 3;       /* i: waiting for modification time (gzip) */
6142var    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */
6143var    EXLEN = 5;      /* i: waiting for extra length (gzip) */
6144var    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */
6145var    NAME = 7;       /* i: waiting for end of file name (gzip) */
6146var    COMMENT = 8;    /* i: waiting for end of comment (gzip) */
6147var    HCRC = 9;       /* i: waiting for header crc (gzip) */
6148var    DICTID = 10;    /* i: waiting for dictionary check value */
6149var    DICT = 11;      /* waiting for inflateSetDictionary() call */
6150var        TYPE = 12;      /* i: waiting for type bits, including last-flag bit */
6151var        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */
6152var        STORED = 14;    /* i: waiting for stored size (length and complement) */
6153var        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */
6154var        COPY = 16;      /* i/o: waiting for input or output to copy stored block */
6155var        TABLE = 17;     /* i: waiting for dynamic block table lengths */
6156var        LENLENS = 18;   /* i: waiting for code length code lengths */
6157var        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */
6158var            LEN_ = 20;      /* i: same as LEN below, but only first time in */
6159var            LEN = 21;       /* i: waiting for length/lit/eob code */
6160var            LENEXT = 22;    /* i: waiting for length extra bits */
6161var            DIST = 23;      /* i: waiting for distance code */
6162var            DISTEXT = 24;   /* i: waiting for distance extra bits */
6163var            MATCH = 25;     /* o: waiting for output space to copy string */
6164var            LIT = 26;       /* o: waiting for output space to write literal */
6165var    CHECK = 27;     /* i: waiting for 32-bit check value */
6166var    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */
6167var    DONE = 29;      /* finished check, done -- remain here until reset */
6168var    BAD = 30;       /* got a data error -- remain here until reset */
6169var    MEM = 31;       /* got an inflate() memory error -- remain here until reset */
6170var    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */
6171
6172/* ===========================================================================*/
6173
6174
6175
6176var ENOUGH_LENS = 852;
6177var ENOUGH_DISTS = 592;
6178//var ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);
6179
6180var MAX_WBITS = 15;
6181/* 32K LZ77 window */
6182var DEF_WBITS = MAX_WBITS;
6183
6184
6185function ZSWAP32(q) {
6186  return  (((q >>> 24) & 0xff) +
6187          ((q >>> 8) & 0xff00) +
6188          ((q & 0xff00) << 8) +
6189          ((q & 0xff) << 24));
6190}
6191
6192
6193function InflateState() {
6194  this.mode = 0;             /* current inflate mode */
6195  this.last = false;          /* true if processing last block */
6196  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
6197  this.havedict = false;      /* true if dictionary provided */
6198  this.flags = 0;             /* gzip header method and flags (0 if zlib) */
6199  this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */
6200  this.check = 0;             /* protected copy of check value */
6201  this.total = 0;             /* protected copy of output count */
6202  // TODO: may be {}
6203  this.head = null;           /* where to save gzip header information */
6204
6205  /* sliding window */
6206  this.wbits = 0;             /* log base 2 of requested window size */
6207  this.wsize = 0;             /* window size or zero if not using window */
6208  this.whave = 0;             /* valid bytes in the window */
6209  this.wnext = 0;             /* window write index */
6210  this.window = null;         /* allocated sliding window, if needed */
6211
6212  /* bit accumulator */
6213  this.hold = 0;              /* input bit accumulator */
6214  this.bits = 0;              /* number of bits in "in" */
6215
6216  /* for string and stored block copying */
6217  this.length = 0;            /* literal or length of data to copy */
6218  this.offset = 0;            /* distance back to copy string from */
6219
6220  /* for table and code decoding */
6221  this.extra = 0;             /* extra bits needed */
6222
6223  /* fixed and dynamic code tables */
6224  this.lencode = null;          /* starting table for length/literal codes */
6225  this.distcode = null;         /* starting table for distance codes */
6226  this.lenbits = 0;           /* index bits for lencode */
6227  this.distbits = 0;          /* index bits for distcode */
6228
6229  /* dynamic table building */
6230  this.ncode = 0;             /* number of code length code lengths */
6231  this.nlen = 0;              /* number of length code lengths */
6232  this.ndist = 0;             /* number of distance code lengths */
6233  this.have = 0;              /* number of code lengths in lens[] */
6234  this.next = null;              /* next available space in codes[] */
6235
6236  this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
6237  this.work = new utils.Buf16(288); /* work area for code table building */
6238
6239  /*
6240   because we don't have pointers in js, we use lencode and distcode directly
6241   as buffers so we don't need codes
6242  */
6243  //this.codes = new utils.Buf32(ENOUGH);       /* space for code tables */
6244  this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */
6245  this.distdyn = null;             /* dynamic table for distance codes (JS specific) */
6246  this.sane = 0;                   /* if false, allow invalid distance too far */
6247  this.back = 0;                   /* bits back of last unprocessed length/lit */
6248  this.was = 0;                    /* initial length of match */
6249}
6250
6251function inflateResetKeep(strm) {
6252  var state;
6253
6254  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
6255  state = strm.state;
6256  strm.total_in = strm.total_out = state.total = 0;
6257  strm.msg = ''; /*Z_NULL*/
6258  if (state.wrap) {       /* to support ill-conceived Java test suite */
6259    strm.adler = state.wrap & 1;
6260  }
6261  state.mode = HEAD;
6262  state.last = 0;
6263  state.havedict = 0;
6264  state.dmax = 32768;
6265  state.head = null/*Z_NULL*/;
6266  state.hold = 0;
6267  state.bits = 0;
6268  //state.lencode = state.distcode = state.next = state.codes;
6269  state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
6270  state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);
6271
6272  state.sane = 1;
6273  state.back = -1;
6274  //Tracev((stderr, "inflate: reset\n"));
6275  return Z_OK;
6276}
6277
6278function inflateReset(strm) {
6279  var state;
6280
6281  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
6282  state = strm.state;
6283  state.wsize = 0;
6284  state.whave = 0;
6285  state.wnext = 0;
6286  return inflateResetKeep(strm);
6287
6288}
6289
6290function inflateReset2(strm, windowBits) {
6291  var wrap;
6292  var state;
6293
6294  /* get the state */
6295  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
6296  state = strm.state;
6297
6298  /* extract wrap request from windowBits parameter */
6299  if (windowBits < 0) {
6300    wrap = 0;
6301    windowBits = -windowBits;
6302  }
6303  else {
6304    wrap = (windowBits >> 4) + 1;
6305    if (windowBits < 48) {
6306      windowBits &= 15;
6307    }
6308  }
6309
6310  /* set number of window bits, free window if different */
6311  if (windowBits && (windowBits < 8 || windowBits > 15)) {
6312    return Z_STREAM_ERROR;
6313  }
6314  if (state.window !== null && state.wbits !== windowBits) {
6315    state.window = null;
6316  }
6317
6318  /* update state and reset the rest of it */
6319  state.wrap = wrap;
6320  state.wbits = windowBits;
6321  return inflateReset(strm);
6322}
6323
6324function inflateInit2(strm, windowBits) {
6325  var ret;
6326  var state;
6327
6328  if (!strm) { return Z_STREAM_ERROR; }
6329  //strm.msg = Z_NULL;                 /* in case we return an error */
6330
6331  state = new InflateState();
6332
6333  //if (state === Z_NULL) return Z_MEM_ERROR;
6334  //Tracev((stderr, "inflate: allocated\n"));
6335  strm.state = state;
6336  state.window = null/*Z_NULL*/;
6337  ret = inflateReset2(strm, windowBits);
6338  if (ret !== Z_OK) {
6339    strm.state = null/*Z_NULL*/;
6340  }
6341  return ret;
6342}
6343
6344function inflateInit(strm) {
6345  return inflateInit2(strm, DEF_WBITS);
6346}
6347
6348
6349/*
6350 Return state with length and distance decoding tables and index sizes set to
6351 fixed code decoding.  Normally this returns fixed tables from inffixed.h.
6352 If BUILDFIXED is defined, then instead this routine builds the tables the
6353 first time it's called, and returns those tables the first time and
6354 thereafter.  This reduces the size of the code by about 2K bytes, in
6355 exchange for a little execution time.  However, BUILDFIXED should not be
6356 used for threaded applications, since the rewriting of the tables and virgin
6357 may not be thread-safe.
6358 */
6359var virgin = true;
6360
6361var lenfix, distfix; // We have no pointers in JS, so keep tables separate
6362
6363function fixedtables(state) {
6364  /* build fixed huffman tables if first call (may not be thread safe) */
6365  if (virgin) {
6366    var sym;
6367
6368    lenfix = new utils.Buf32(512);
6369    distfix = new utils.Buf32(32);
6370
6371    /* literal/length table */
6372    sym = 0;
6373    while (sym < 144) { state.lens[sym++] = 8; }
6374    while (sym < 256) { state.lens[sym++] = 9; }
6375    while (sym < 280) { state.lens[sym++] = 7; }
6376    while (sym < 288) { state.lens[sym++] = 8; }
6377
6378    inflate_table(LENS,  state.lens, 0, 288, lenfix,   0, state.work, {bits: 9});
6379
6380    /* distance table */
6381    sym = 0;
6382    while (sym < 32) { state.lens[sym++] = 5; }
6383
6384    inflate_table(DISTS, state.lens, 0, 32,   distfix, 0, state.work, {bits: 5});
6385
6386    /* do this just once */
6387    virgin = false;
6388  }
6389
6390  state.lencode = lenfix;
6391  state.lenbits = 9;
6392  state.distcode = distfix;
6393  state.distbits = 5;
6394}
6395
6396
6397/*
6398 Update the window with the last wsize (normally 32K) bytes written before
6399 returning.  If window does not exist yet, create it.  This is only called
6400 when a window is already in use, or when output has been written during this
6401 inflate call, but the end of the deflate stream has not been reached yet.
6402 It is also called to create a window for dictionary data when a dictionary
6403 is loaded.
6404
6405 Providing output buffers larger than 32K to inflate() should provide a speed
6406 advantage, since only the last 32K of output is copied to the sliding window
6407 upon return from inflate(), and since all distances after the first 32K of
6408 output will fall in the output data, making match copies simpler and faster.
6409 The advantage may be dependent on the size of the processor's data caches.
6410 */
6411function updatewindow(strm, src, end, copy) {
6412  var dist;
6413  var state = strm.state;
6414
6415  /* if it hasn't been done already, allocate space for the window */
6416  if (state.window === null) {
6417    state.wsize = 1 << state.wbits;
6418    state.wnext = 0;
6419    state.whave = 0;
6420
6421    state.window = new utils.Buf8(state.wsize);
6422  }
6423
6424  /* copy state->wsize or less output bytes into the circular window */
6425  if (copy >= state.wsize) {
6426    utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0);
6427    state.wnext = 0;
6428    state.whave = state.wsize;
6429  }
6430  else {
6431    dist = state.wsize - state.wnext;
6432    if (dist > copy) {
6433      dist = copy;
6434    }
6435    //zmemcpy(state->window + state->wnext, end - copy, dist);
6436    utils.arraySet(state.window,src, end - copy, dist, state.wnext);
6437    copy -= dist;
6438    if (copy) {
6439      //zmemcpy(state->window, end - copy, copy);
6440      utils.arraySet(state.window,src, end - copy, copy, 0);
6441      state.wnext = copy;
6442      state.whave = state.wsize;
6443    }
6444    else {
6445      state.wnext += dist;
6446      if (state.wnext === state.wsize) { state.wnext = 0; }
6447      if (state.whave < state.wsize) { state.whave += dist; }
6448    }
6449  }
6450  return 0;
6451}
6452
6453function inflate(strm, flush) {
6454  var state;
6455  var input, output;          // input/output buffers
6456  var next;                   /* next input INDEX */
6457  var put;                    /* next output INDEX */
6458  var have, left;             /* available input and output */
6459  var hold;                   /* bit buffer */
6460  var bits;                   /* bits in bit buffer */
6461  var _in, _out;              /* save starting available input and output */
6462  var copy;                   /* number of stored or match bytes to copy */
6463  var from;                   /* where to copy match bytes from */
6464  var from_source;
6465  var here = 0;               /* current decoding table entry */
6466  var here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
6467  //var last;                   /* parent table entry */
6468  var last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
6469  var len;                    /* length to copy for repeats, bits to drop */
6470  var ret;                    /* return code */
6471  var hbuf = new utils.Buf8(4);    /* buffer for gzip header crc calculation */
6472  var opts;
6473
6474  var n; // temporary var for NEED_BITS
6475
6476  var order = /* permutation of code lengths */
6477    [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
6478
6479
6480  if (!strm || !strm.state || !strm.output ||
6481      (!strm.input && strm.avail_in !== 0)) {
6482    return Z_STREAM_ERROR;
6483  }
6484
6485  state = strm.state;
6486  if (state.mode === TYPE) { state.mode = TYPEDO; }    /* skip check */
6487
6488
6489  //--- LOAD() ---
6490  put = strm.next_out;
6491  output = strm.output;
6492  left = strm.avail_out;
6493  next = strm.next_in;
6494  input = strm.input;
6495  have = strm.avail_in;
6496  hold = state.hold;
6497  bits = state.bits;
6498  //---
6499
6500  _in = have;
6501  _out = left;
6502  ret = Z_OK;
6503
6504  inf_leave: // goto emulation
6505  for (;;) {
6506    switch (state.mode) {
6507    case HEAD:
6508      if (state.wrap === 0) {
6509        state.mode = TYPEDO;
6510        break;
6511      }
6512      //=== NEEDBITS(16);
6513      while (bits < 16) {
6514        if (have === 0) { break inf_leave; }
6515        have--;
6516        hold += input[next++] << bits;
6517        bits += 8;
6518      }
6519      //===//
6520      if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */
6521        state.check = 0/*crc32(0L, Z_NULL, 0)*/;
6522        //=== CRC2(state.check, hold);
6523        hbuf[0] = hold & 0xff;
6524        hbuf[1] = (hold >>> 8) & 0xff;
6525        state.check = crc32(state.check, hbuf, 2, 0);
6526        //===//
6527
6528        //=== INITBITS();
6529        hold = 0;
6530        bits = 0;
6531        //===//
6532        state.mode = FLAGS;
6533        break;
6534      }
6535      state.flags = 0;           /* expect zlib header */
6536      if (state.head) {
6537        state.head.done = false;
6538      }
6539      if (!(state.wrap & 1) ||   /* check if zlib header allowed */
6540        (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
6541        strm.msg = 'incorrect header check';
6542        state.mode = BAD;
6543        break;
6544      }
6545      if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
6546        strm.msg = 'unknown compression method';
6547        state.mode = BAD;
6548        break;
6549      }
6550      //--- DROPBITS(4) ---//
6551      hold >>>= 4;
6552      bits -= 4;
6553      //---//
6554      len = (hold & 0x0f)/*BITS(4)*/ + 8;
6555      if (state.wbits === 0) {
6556        state.wbits = len;
6557      }
6558      else if (len > state.wbits) {
6559        strm.msg = 'invalid window size';
6560        state.mode = BAD;
6561        break;
6562      }
6563      state.dmax = 1 << len;
6564      //Tracev((stderr, "inflate:   zlib header ok\n"));
6565      strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
6566      state.mode = hold & 0x200 ? DICTID : TYPE;
6567      //=== INITBITS();
6568      hold = 0;
6569      bits = 0;
6570      //===//
6571      break;
6572    case FLAGS:
6573      //=== NEEDBITS(16); */
6574      while (bits < 16) {
6575        if (have === 0) { break inf_leave; }
6576        have--;
6577        hold += input[next++] << bits;
6578        bits += 8;
6579      }
6580      //===//
6581      state.flags = hold;
6582      if ((state.flags & 0xff) !== Z_DEFLATED) {
6583        strm.msg = 'unknown compression method';
6584        state.mode = BAD;
6585        break;
6586      }
6587      if (state.flags & 0xe000) {
6588        strm.msg = 'unknown header flags set';
6589        state.mode = BAD;
6590        break;
6591      }
6592      if (state.head) {
6593        state.head.text = ((hold >> 8) & 1);
6594      }
6595      if (state.flags & 0x0200) {
6596        //=== CRC2(state.check, hold);
6597        hbuf[0] = hold & 0xff;
6598        hbuf[1] = (hold >>> 8) & 0xff;
6599        state.check = crc32(state.check, hbuf, 2, 0);
6600        //===//
6601      }
6602      //=== INITBITS();
6603      hold = 0;
6604      bits = 0;
6605      //===//
6606      state.mode = TIME;
6607      /* falls through */
6608    case TIME:
6609      //=== NEEDBITS(32); */
6610      while (bits < 32) {
6611        if (have === 0) { break inf_leave; }
6612        have--;
6613        hold += input[next++] << bits;
6614        bits += 8;
6615      }
6616      //===//
6617      if (state.head) {
6618        state.head.time = hold;
6619      }
6620      if (state.flags & 0x0200) {
6621        //=== CRC4(state.check, hold)
6622        hbuf[0] = hold & 0xff;
6623        hbuf[1] = (hold >>> 8) & 0xff;
6624        hbuf[2] = (hold >>> 16) & 0xff;
6625        hbuf[3] = (hold >>> 24) & 0xff;
6626        state.check = crc32(state.check, hbuf, 4, 0);
6627        //===
6628      }
6629      //=== INITBITS();
6630      hold = 0;
6631      bits = 0;
6632      //===//
6633      state.mode = OS;
6634      /* falls through */
6635    case OS:
6636      //=== NEEDBITS(16); */
6637      while (bits < 16) {
6638        if (have === 0) { break inf_leave; }
6639        have--;
6640        hold += input[next++] << bits;
6641        bits += 8;
6642      }
6643      //===//
6644      if (state.head) {
6645        state.head.xflags = (hold & 0xff);
6646        state.head.os = (hold >> 8);
6647      }
6648      if (state.flags & 0x0200) {
6649        //=== CRC2(state.check, hold);
6650        hbuf[0] = hold & 0xff;
6651        hbuf[1] = (hold >>> 8) & 0xff;
6652        state.check = crc32(state.check, hbuf, 2, 0);
6653        //===//
6654      }
6655      //=== INITBITS();
6656      hold = 0;
6657      bits = 0;
6658      //===//
6659      state.mode = EXLEN;
6660      /* falls through */
6661    case EXLEN:
6662      if (state.flags & 0x0400) {
6663        //=== NEEDBITS(16); */
6664        while (bits < 16) {
6665          if (have === 0) { break inf_leave; }
6666          have--;
6667          hold += input[next++] << bits;
6668          bits += 8;
6669        }
6670        //===//
6671        state.length = hold;
6672        if (state.head) {
6673          state.head.extra_len = hold;
6674        }
6675        if (state.flags & 0x0200) {
6676          //=== CRC2(state.check, hold);
6677          hbuf[0] = hold & 0xff;
6678          hbuf[1] = (hold >>> 8) & 0xff;
6679          state.check = crc32(state.check, hbuf, 2, 0);
6680          //===//
6681        }
6682        //=== INITBITS();
6683        hold = 0;
6684        bits = 0;
6685        //===//
6686      }
6687      else if (state.head) {
6688        state.head.extra = null/*Z_NULL*/;
6689      }
6690      state.mode = EXTRA;
6691      /* falls through */
6692    case EXTRA:
6693      if (state.flags & 0x0400) {
6694        copy = state.length;
6695        if (copy > have) { copy = have; }
6696        if (copy) {
6697          if (state.head) {
6698            len = state.head.extra_len - state.length;
6699            if (!state.head.extra) {
6700              // Use untyped array for more conveniend processing later
6701              state.head.extra = new Array(state.head.extra_len);
6702            }
6703            utils.arraySet(
6704              state.head.extra,
6705              input,
6706              next,
6707              // extra field is limited to 65536 bytes
6708              // - no need for additional size check
6709              copy,
6710              /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
6711              len
6712            );
6713            //zmemcpy(state.head.extra + len, next,
6714            //        len + copy > state.head.extra_max ?
6715            //        state.head.extra_max - len : copy);
6716          }
6717          if (state.flags & 0x0200) {
6718            state.check = crc32(state.check, input, copy, next);
6719          }
6720          have -= copy;
6721          next += copy;
6722          state.length -= copy;
6723        }
6724        if (state.length) { break inf_leave; }
6725      }
6726      state.length = 0;
6727      state.mode = NAME;
6728      /* falls through */
6729    case NAME:
6730      if (state.flags & 0x0800) {
6731        if (have === 0) { break inf_leave; }
6732        copy = 0;
6733        do {
6734          // TODO: 2 or 1 bytes?
6735          len = input[next + copy++];
6736          /* use constant limit because in js we should not preallocate memory */
6737          if (state.head && len &&
6738              (state.length < 65536 /*state.head.name_max*/)) {
6739            state.head.name += String.fromCharCode(len);
6740          }
6741        } while (len && copy < have);
6742
6743        if (state.flags & 0x0200) {
6744          state.check = crc32(state.check, input, copy, next);
6745        }
6746        have -= copy;
6747        next += copy;
6748        if (len) { break inf_leave; }
6749      }
6750      else if (state.head) {
6751        state.head.name = null;
6752      }
6753      state.length = 0;
6754      state.mode = COMMENT;
6755      /* falls through */
6756    case COMMENT:
6757      if (state.flags & 0x1000) {
6758        if (have === 0) { break inf_leave; }
6759        copy = 0;
6760        do {
6761          len = input[next + copy++];
6762          /* use constant limit because in js we should not preallocate memory */
6763          if (state.head && len &&
6764              (state.length < 65536 /*state.head.comm_max*/)) {
6765            state.head.comment += String.fromCharCode(len);
6766          }
6767        } while (len && copy < have);
6768        if (state.flags & 0x0200) {
6769          state.check = crc32(state.check, input, copy, next);
6770        }
6771        have -= copy;
6772        next += copy;
6773        if (len) { break inf_leave; }
6774      }
6775      else if (state.head) {
6776        state.head.comment = null;
6777      }
6778      state.mode = HCRC;
6779      /* falls through */
6780    case HCRC:
6781      if (state.flags & 0x0200) {
6782        //=== NEEDBITS(16); */
6783        while (bits < 16) {
6784          if (have === 0) { break inf_leave; }
6785          have--;
6786          hold += input[next++] << bits;
6787          bits += 8;
6788        }
6789        //===//
6790        if (hold !== (state.check & 0xffff)) {
6791          strm.msg = 'header crc mismatch';
6792          state.mode = BAD;
6793          break;
6794        }
6795        //=== INITBITS();
6796        hold = 0;
6797        bits = 0;
6798        //===//
6799      }
6800      if (state.head) {
6801        state.head.hcrc = ((state.flags >> 9) & 1);
6802        state.head.done = true;
6803      }
6804      strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/;
6805      state.mode = TYPE;
6806      break;
6807    case DICTID:
6808      //=== NEEDBITS(32); */
6809      while (bits < 32) {
6810        if (have === 0) { break inf_leave; }
6811        have--;
6812        hold += input[next++] << bits;
6813        bits += 8;
6814      }
6815      //===//
6816      strm.adler = state.check = ZSWAP32(hold);
6817      //=== INITBITS();
6818      hold = 0;
6819      bits = 0;
6820      //===//
6821      state.mode = DICT;
6822      /* falls through */
6823    case DICT:
6824      if (state.havedict === 0) {
6825        //--- RESTORE() ---
6826        strm.next_out = put;
6827        strm.avail_out = left;
6828        strm.next_in = next;
6829        strm.avail_in = have;
6830        state.hold = hold;
6831        state.bits = bits;
6832        //---
6833        return Z_NEED_DICT;
6834      }
6835      strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
6836      state.mode = TYPE;
6837      /* falls through */
6838    case TYPE:
6839      if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
6840      /* falls through */
6841    case TYPEDO:
6842      if (state.last) {
6843        //--- BYTEBITS() ---//
6844        hold >>>= bits & 7;
6845        bits -= bits & 7;
6846        //---//
6847        state.mode = CHECK;
6848        break;
6849      }
6850      //=== NEEDBITS(3); */
6851      while (bits < 3) {
6852        if (have === 0) { break inf_leave; }
6853        have--;
6854        hold += input[next++] << bits;
6855        bits += 8;
6856      }
6857      //===//
6858      state.last = (hold & 0x01)/*BITS(1)*/;
6859      //--- DROPBITS(1) ---//
6860      hold >>>= 1;
6861      bits -= 1;
6862      //---//
6863
6864      switch ((hold & 0x03)/*BITS(2)*/) {
6865      case 0:                             /* stored block */
6866        //Tracev((stderr, "inflate:     stored block%s\n",
6867        //        state.last ? " (last)" : ""));
6868        state.mode = STORED;
6869        break;
6870      case 1:                             /* fixed block */
6871        fixedtables(state);
6872        //Tracev((stderr, "inflate:     fixed codes block%s\n",
6873        //        state.last ? " (last)" : ""));
6874        state.mode = LEN_;             /* decode codes */
6875        if (flush === Z_TREES) {
6876          //--- DROPBITS(2) ---//
6877          hold >>>= 2;
6878          bits -= 2;
6879          //---//
6880          break inf_leave;
6881        }
6882        break;
6883      case 2:                             /* dynamic block */
6884        //Tracev((stderr, "inflate:     dynamic codes block%s\n",
6885        //        state.last ? " (last)" : ""));
6886        state.mode = TABLE;
6887        break;
6888      case 3:
6889        strm.msg = 'invalid block type';
6890        state.mode = BAD;
6891      }
6892      //--- DROPBITS(2) ---//
6893      hold >>>= 2;
6894      bits -= 2;
6895      //---//
6896      break;
6897    case STORED:
6898      //--- BYTEBITS() ---// /* go to byte boundary */
6899      hold >>>= bits & 7;
6900      bits -= bits & 7;
6901      //---//
6902      //=== NEEDBITS(32); */
6903      while (bits < 32) {
6904        if (have === 0) { break inf_leave; }
6905        have--;
6906        hold += input[next++] << bits;
6907        bits += 8;
6908      }
6909      //===//
6910      if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
6911        strm.msg = 'invalid stored block lengths';
6912        state.mode = BAD;
6913        break;
6914      }
6915      state.length = hold & 0xffff;
6916      //Tracev((stderr, "inflate:       stored length %u\n",
6917      //        state.length));
6918      //=== INITBITS();
6919      hold = 0;
6920      bits = 0;
6921      //===//
6922      state.mode = COPY_;
6923      if (flush === Z_TREES) { break inf_leave; }
6924      /* falls through */
6925    case COPY_:
6926      state.mode = COPY;
6927      /* falls through */
6928    case COPY:
6929      copy = state.length;
6930      if (copy) {
6931        if (copy > have) { copy = have; }
6932        if (copy > left) { copy = left; }
6933        if (copy === 0) { break inf_leave; }
6934        //--- zmemcpy(put, next, copy); ---
6935        utils.arraySet(output, input, next, copy, put);
6936        //---//
6937        have -= copy;
6938        next += copy;
6939        left -= copy;
6940        put += copy;
6941        state.length -= copy;
6942        break;
6943      }
6944      //Tracev((stderr, "inflate:       stored end\n"));
6945      state.mode = TYPE;
6946      break;
6947    case TABLE:
6948      //=== NEEDBITS(14); */
6949      while (bits < 14) {
6950        if (have === 0) { break inf_leave; }
6951        have--;
6952        hold += input[next++] << bits;
6953        bits += 8;
6954      }
6955      //===//
6956      state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
6957      //--- DROPBITS(5) ---//
6958      hold >>>= 5;
6959      bits -= 5;
6960      //---//
6961      state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
6962      //--- DROPBITS(5) ---//
6963      hold >>>= 5;
6964      bits -= 5;
6965      //---//
6966      state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
6967      //--- DROPBITS(4) ---//
6968      hold >>>= 4;
6969      bits -= 4;
6970      //---//
6971//#ifndef PKZIP_BUG_WORKAROUND
6972      if (state.nlen > 286 || state.ndist > 30) {
6973        strm.msg = 'too many length or distance symbols';
6974        state.mode = BAD;
6975        break;
6976      }
6977//#endif
6978      //Tracev((stderr, "inflate:       table sizes ok\n"));
6979      state.have = 0;
6980      state.mode = LENLENS;
6981      /* falls through */
6982    case LENLENS:
6983      while (state.have < state.ncode) {
6984        //=== NEEDBITS(3);
6985        while (bits < 3) {
6986          if (have === 0) { break inf_leave; }
6987          have--;
6988          hold += input[next++] << bits;
6989          bits += 8;
6990        }
6991        //===//
6992        state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
6993        //--- DROPBITS(3) ---//
6994        hold >>>= 3;
6995        bits -= 3;
6996        //---//
6997      }
6998      while (state.have < 19) {
6999        state.lens[order[state.have++]] = 0;
7000      }
7001      // We have separate tables & no pointers. 2 commented lines below not needed.
7002      //state.next = state.codes;
7003      //state.lencode = state.next;
7004      // Switch to use dynamic table
7005      state.lencode = state.lendyn;
7006      state.lenbits = 7;
7007
7008      opts = {bits: state.lenbits};
7009      ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
7010      state.lenbits = opts.bits;
7011
7012      if (ret) {
7013        strm.msg = 'invalid code lengths set';
7014        state.mode = BAD;
7015        break;
7016      }
7017      //Tracev((stderr, "inflate:       code lengths ok\n"));
7018      state.have = 0;
7019      state.mode = CODELENS;
7020      /* falls through */
7021    case CODELENS:
7022      while (state.have < state.nlen + state.ndist) {
7023        for (;;) {
7024          here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
7025          here_bits = here >>> 24;
7026          here_op = (here >>> 16) & 0xff;
7027          here_val = here & 0xffff;
7028
7029          if ((here_bits) <= bits) { break; }
7030          //--- PULLBYTE() ---//
7031          if (have === 0) { break inf_leave; }
7032          have--;
7033          hold += input[next++] << bits;
7034          bits += 8;
7035          //---//
7036        }
7037        if (here_val < 16) {
7038          //--- DROPBITS(here.bits) ---//
7039          hold >>>= here_bits;
7040          bits -= here_bits;
7041          //---//
7042          state.lens[state.have++] = here_val;
7043        }
7044        else {
7045          if (here_val === 16) {
7046            //=== NEEDBITS(here.bits + 2);
7047            n = here_bits + 2;
7048            while (bits < n) {
7049              if (have === 0) { break inf_leave; }
7050              have--;
7051              hold += input[next++] << bits;
7052              bits += 8;
7053            }
7054            //===//
7055            //--- DROPBITS(here.bits) ---//
7056            hold >>>= here_bits;
7057            bits -= here_bits;
7058            //---//
7059            if (state.have === 0) {
7060              strm.msg = 'invalid bit length repeat';
7061              state.mode = BAD;
7062              break;
7063            }
7064            len = state.lens[state.have - 1];
7065            copy = 3 + (hold & 0x03);//BITS(2);
7066            //--- DROPBITS(2) ---//
7067            hold >>>= 2;
7068            bits -= 2;
7069            //---//
7070          }
7071          else if (here_val === 17) {
7072            //=== NEEDBITS(here.bits + 3);
7073            n = here_bits + 3;
7074            while (bits < n) {
7075              if (have === 0) { break inf_leave; }
7076              have--;
7077              hold += input[next++] << bits;
7078              bits += 8;
7079            }
7080            //===//
7081            //--- DROPBITS(here.bits) ---//
7082            hold >>>= here_bits;
7083            bits -= here_bits;
7084            //---//
7085            len = 0;
7086            copy = 3 + (hold & 0x07);//BITS(3);
7087            //--- DROPBITS(3) ---//
7088            hold >>>= 3;
7089            bits -= 3;
7090            //---//
7091          }
7092          else {
7093            //=== NEEDBITS(here.bits + 7);
7094            n = here_bits + 7;
7095            while (bits < n) {
7096              if (have === 0) { break inf_leave; }
7097              have--;
7098              hold += input[next++] << bits;
7099              bits += 8;
7100            }
7101            //===//
7102            //--- DROPBITS(here.bits) ---//
7103            hold >>>= here_bits;
7104            bits -= here_bits;
7105            //---//
7106            len = 0;
7107            copy = 11 + (hold & 0x7f);//BITS(7);
7108            //--- DROPBITS(7) ---//
7109            hold >>>= 7;
7110            bits -= 7;
7111            //---//
7112          }
7113          if (state.have + copy > state.nlen + state.ndist) {
7114            strm.msg = 'invalid bit length repeat';
7115            state.mode = BAD;
7116            break;
7117          }
7118          while (copy--) {
7119            state.lens[state.have++] = len;
7120          }
7121        }
7122      }
7123
7124      /* handle error breaks in while */
7125      if (state.mode === BAD) { break; }
7126
7127      /* check for end-of-block code (better have one) */
7128      if (state.lens[256] === 0) {
7129        strm.msg = 'invalid code -- missing end-of-block';
7130        state.mode = BAD;
7131        break;
7132      }
7133
7134      /* build code tables -- note: do not change the lenbits or distbits
7135         values here (9 and 6) without reading the comments in inftrees.h
7136         concerning the ENOUGH constants, which depend on those values */
7137      state.lenbits = 9;
7138
7139      opts = {bits: state.lenbits};
7140      ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
7141      // We have separate tables & no pointers. 2 commented lines below not needed.
7142      // state.next_index = opts.table_index;
7143      state.lenbits = opts.bits;
7144      // state.lencode = state.next;
7145
7146      if (ret) {
7147        strm.msg = 'invalid literal/lengths set';
7148        state.mode = BAD;
7149        break;
7150      }
7151
7152      state.distbits = 6;
7153      //state.distcode.copy(state.codes);
7154      // Switch to use dynamic table
7155      state.distcode = state.distdyn;
7156      opts = {bits: state.distbits};
7157      ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
7158      // We have separate tables & no pointers. 2 commented lines below not needed.
7159      // state.next_index = opts.table_index;
7160      state.distbits = opts.bits;
7161      // state.distcode = state.next;
7162
7163      if (ret) {
7164        strm.msg = 'invalid distances set';
7165        state.mode = BAD;
7166        break;
7167      }
7168      //Tracev((stderr, 'inflate:       codes ok\n'));
7169      state.mode = LEN_;
7170      if (flush === Z_TREES) { break inf_leave; }
7171      /* falls through */
7172    case LEN_:
7173      state.mode = LEN;
7174      /* falls through */
7175    case LEN:
7176      if (have >= 6 && left >= 258) {
7177        //--- RESTORE() ---
7178        strm.next_out = put;
7179        strm.avail_out = left;
7180        strm.next_in = next;
7181        strm.avail_in = have;
7182        state.hold = hold;
7183        state.bits = bits;
7184        //---
7185        inflate_fast(strm, _out);
7186        //--- LOAD() ---
7187        put = strm.next_out;
7188        output = strm.output;
7189        left = strm.avail_out;
7190        next = strm.next_in;
7191        input = strm.input;
7192        have = strm.avail_in;
7193        hold = state.hold;
7194        bits = state.bits;
7195        //---
7196
7197        if (state.mode === TYPE) {
7198          state.back = -1;
7199        }
7200        break;
7201      }
7202      state.back = 0;
7203      for (;;) {
7204        here = state.lencode[hold & ((1 << state.lenbits) -1)];  /*BITS(state.lenbits)*/
7205        here_bits = here >>> 24;
7206        here_op = (here >>> 16) & 0xff;
7207        here_val = here & 0xffff;
7208
7209        if (here_bits <= bits) { break; }
7210        //--- PULLBYTE() ---//
7211        if (have === 0) { break inf_leave; }
7212        have--;
7213        hold += input[next++] << bits;
7214        bits += 8;
7215        //---//
7216      }
7217      if (here_op && (here_op & 0xf0) === 0) {
7218        last_bits = here_bits;
7219        last_op = here_op;
7220        last_val = here_val;
7221        for (;;) {
7222          here = state.lencode[last_val +
7223                  ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
7224          here_bits = here >>> 24;
7225          here_op = (here >>> 16) & 0xff;
7226          here_val = here & 0xffff;
7227
7228          if ((last_bits + here_bits) <= bits) { break; }
7229          //--- PULLBYTE() ---//
7230          if (have === 0) { break inf_leave; }
7231          have--;
7232          hold += input[next++] << bits;
7233          bits += 8;
7234          //---//
7235        }
7236        //--- DROPBITS(last.bits) ---//
7237        hold >>>= last_bits;
7238        bits -= last_bits;
7239        //---//
7240        state.back += last_bits;
7241      }
7242      //--- DROPBITS(here.bits) ---//
7243      hold >>>= here_bits;
7244      bits -= here_bits;
7245      //---//
7246      state.back += here_bits;
7247      state.length = here_val;
7248      if (here_op === 0) {
7249        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
7250        //        "inflate:         literal '%c'\n" :
7251        //        "inflate:         literal 0x%02x\n", here.val));
7252        state.mode = LIT;
7253        break;
7254      }
7255      if (here_op & 32) {
7256        //Tracevv((stderr, "inflate:         end of block\n"));
7257        state.back = -1;
7258        state.mode = TYPE;
7259        break;
7260      }
7261      if (here_op & 64) {
7262        strm.msg = 'invalid literal/length code';
7263        state.mode = BAD;
7264        break;
7265      }
7266      state.extra = here_op & 15;
7267      state.mode = LENEXT;
7268      /* falls through */
7269    case LENEXT:
7270      if (state.extra) {
7271        //=== NEEDBITS(state.extra);
7272        n = state.extra;
7273        while (bits < n) {
7274          if (have === 0) { break inf_leave; }
7275          have--;
7276          hold += input[next++] << bits;
7277          bits += 8;
7278        }
7279        //===//
7280        state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
7281        //--- DROPBITS(state.extra) ---//
7282        hold >>>= state.extra;
7283        bits -= state.extra;
7284        //---//
7285        state.back += state.extra;
7286      }
7287      //Tracevv((stderr, "inflate:         length %u\n", state.length));
7288      state.was = state.length;
7289      state.mode = DIST;
7290      /* falls through */
7291    case DIST:
7292      for (;;) {
7293        here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/
7294        here_bits = here >>> 24;
7295        here_op = (here >>> 16) & 0xff;
7296        here_val = here & 0xffff;
7297
7298        if ((here_bits) <= bits) { break; }
7299        //--- PULLBYTE() ---//
7300        if (have === 0) { break inf_leave; }
7301        have--;
7302        hold += input[next++] << bits;
7303        bits += 8;
7304        //---//
7305      }
7306      if ((here_op & 0xf0) === 0) {
7307        last_bits = here_bits;
7308        last_op = here_op;
7309        last_val = here_val;
7310        for (;;) {
7311          here = state.distcode[last_val +
7312                  ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
7313          here_bits = here >>> 24;
7314          here_op = (here >>> 16) & 0xff;
7315          here_val = here & 0xffff;
7316
7317          if ((last_bits + here_bits) <= bits) { break; }
7318          //--- PULLBYTE() ---//
7319          if (have === 0) { break inf_leave; }
7320          have--;
7321          hold += input[next++] << bits;
7322          bits += 8;
7323          //---//
7324        }
7325        //--- DROPBITS(last.bits) ---//
7326        hold >>>= last_bits;
7327        bits -= last_bits;
7328        //---//
7329        state.back += last_bits;
7330      }
7331      //--- DROPBITS(here.bits) ---//
7332      hold >>>= here_bits;
7333      bits -= here_bits;
7334      //---//
7335      state.back += here_bits;
7336      if (here_op & 64) {
7337        strm.msg = 'invalid distance code';
7338        state.mode = BAD;
7339        break;
7340      }
7341      state.offset = here_val;
7342      state.extra = (here_op) & 15;
7343      state.mode = DISTEXT;
7344      /* falls through */
7345    case DISTEXT:
7346      if (state.extra) {
7347        //=== NEEDBITS(state.extra);
7348        n = state.extra;
7349        while (bits < n) {
7350          if (have === 0) { break inf_leave; }
7351          have--;
7352          hold += input[next++] << bits;
7353          bits += 8;
7354        }
7355        //===//
7356        state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
7357        //--- DROPBITS(state.extra) ---//
7358        hold >>>= state.extra;
7359        bits -= state.extra;
7360        //---//
7361        state.back += state.extra;
7362      }
7363//#ifdef INFLATE_STRICT
7364      if (state.offset > state.dmax) {
7365        strm.msg = 'invalid distance too far back';
7366        state.mode = BAD;
7367        break;
7368      }
7369//#endif
7370      //Tracevv((stderr, "inflate:         distance %u\n", state.offset));
7371      state.mode = MATCH;
7372      /* falls through */
7373    case MATCH:
7374      if (left === 0) { break inf_leave; }
7375      copy = _out - left;
7376      if (state.offset > copy) {         /* copy from window */
7377        copy = state.offset - copy;
7378        if (copy > state.whave) {
7379          if (state.sane) {
7380            strm.msg = 'invalid distance too far back';
7381            state.mode = BAD;
7382            break;
7383          }
7384// (!) This block is disabled in zlib defailts,
7385// don't enable it for binary compatibility
7386//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
7387//          Trace((stderr, "inflate.c too far\n"));
7388//          copy -= state.whave;
7389//          if (copy > state.length) { copy = state.length; }
7390//          if (copy > left) { copy = left; }
7391//          left -= copy;
7392//          state.length -= copy;
7393//          do {
7394//            output[put++] = 0;
7395//          } while (--copy);
7396//          if (state.length === 0) { state.mode = LEN; }
7397//          break;
7398//#endif
7399        }
7400        if (copy > state.wnext) {
7401          copy -= state.wnext;
7402          from = state.wsize - copy;
7403        }
7404        else {
7405          from = state.wnext - copy;
7406        }
7407        if (copy > state.length) { copy = state.length; }
7408        from_source = state.window;
7409      }
7410      else {                              /* copy from output */
7411        from_source = output;
7412        from = put - state.offset;
7413        copy = state.length;
7414      }
7415      if (copy > left) { copy = left; }
7416      left -= copy;
7417      state.length -= copy;
7418      do {
7419        output[put++] = from_source[from++];
7420      } while (--copy);
7421      if (state.length === 0) { state.mode = LEN; }
7422      break;
7423    case LIT:
7424      if (left === 0) { break inf_leave; }
7425      output[put++] = state.length;
7426      left--;
7427      state.mode = LEN;
7428      break;
7429    case CHECK:
7430      if (state.wrap) {
7431        //=== NEEDBITS(32);
7432        while (bits < 32) {
7433          if (have === 0) { break inf_leave; }
7434          have--;
7435          // Use '|' insdead of '+' to make sure that result is signed
7436          hold |= input[next++] << bits;
7437          bits += 8;
7438        }
7439        //===//
7440        _out -= left;
7441        strm.total_out += _out;
7442        state.total += _out;
7443        if (_out) {
7444          strm.adler = state.check =
7445              /*UPDATE(state.check, put - _out, _out);*/
7446              (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));
7447
7448        }
7449        _out = left;
7450        // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too
7451        if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) {
7452          strm.msg = 'incorrect data check';
7453          state.mode = BAD;
7454          break;
7455        }
7456        //=== INITBITS();
7457        hold = 0;
7458        bits = 0;
7459        //===//
7460        //Tracev((stderr, "inflate:   check matches trailer\n"));
7461      }
7462      state.mode = LENGTH;
7463      /* falls through */
7464    case LENGTH:
7465      if (state.wrap && state.flags) {
7466        //=== NEEDBITS(32);
7467        while (bits < 32) {
7468          if (have === 0) { break inf_leave; }
7469          have--;
7470          hold += input[next++] << bits;
7471          bits += 8;
7472        }
7473        //===//
7474        if (hold !== (state.total & 0xffffffff)) {
7475          strm.msg = 'incorrect length check';
7476          state.mode = BAD;
7477          break;
7478        }
7479        //=== INITBITS();
7480        hold = 0;
7481        bits = 0;
7482        //===//
7483        //Tracev((stderr, "inflate:   length matches trailer\n"));
7484      }
7485      state.mode = DONE;
7486      /* falls through */
7487    case DONE:
7488      ret = Z_STREAM_END;
7489      break inf_leave;
7490    case BAD:
7491      ret = Z_DATA_ERROR;
7492      break inf_leave;
7493    case MEM:
7494      return Z_MEM_ERROR;
7495    case SYNC:
7496      /* falls through */
7497    default:
7498      return Z_STREAM_ERROR;
7499    }
7500  }
7501
7502  // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
7503
7504  /*
7505     Return from inflate(), updating the total counts and the check value.
7506     If there was no progress during the inflate() call, return a buffer
7507     error.  Call updatewindow() to create and/or update the window state.
7508     Note: a memory error from inflate() is non-recoverable.
7509   */
7510
7511  //--- RESTORE() ---
7512  strm.next_out = put;
7513  strm.avail_out = left;
7514  strm.next_in = next;
7515  strm.avail_in = have;
7516  state.hold = hold;
7517  state.bits = bits;
7518  //---
7519
7520  if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
7521                      (state.mode < CHECK || flush !== Z_FINISH))) {
7522    if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
7523      state.mode = MEM;
7524      return Z_MEM_ERROR;
7525    }
7526  }
7527  _in -= strm.avail_in;
7528  _out -= strm.avail_out;
7529  strm.total_in += _in;
7530  strm.total_out += _out;
7531  state.total += _out;
7532  if (state.wrap && _out) {
7533    strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
7534      (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
7535  }
7536  strm.data_type = state.bits + (state.last ? 64 : 0) +
7537                    (state.mode === TYPE ? 128 : 0) +
7538                    (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
7539  if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
7540    ret = Z_BUF_ERROR;
7541  }
7542  return ret;
7543}
7544
7545function inflateEnd(strm) {
7546
7547  if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
7548    return Z_STREAM_ERROR;
7549  }
7550
7551  var state = strm.state;
7552  if (state.window) {
7553    state.window = null;
7554  }
7555  strm.state = null;
7556  return Z_OK;
7557}
7558
7559function inflateGetHeader(strm, head) {
7560  var state;
7561
7562  /* check state */
7563  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
7564  state = strm.state;
7565  if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }
7566
7567  /* save header structure */
7568  state.head = head;
7569  head.done = false;
7570  return Z_OK;
7571}
7572
7573
7574exports.inflateReset = inflateReset;
7575exports.inflateReset2 = inflateReset2;
7576exports.inflateResetKeep = inflateResetKeep;
7577exports.inflateInit = inflateInit;
7578exports.inflateInit2 = inflateInit2;
7579exports.inflate = inflate;
7580exports.inflateEnd = inflateEnd;
7581exports.inflateGetHeader = inflateGetHeader;
7582exports.inflateInfo = 'pako inflate (from Nodeca project)';
7583
7584/* Not implemented
7585exports.inflateCopy = inflateCopy;
7586exports.inflateGetDictionary = inflateGetDictionary;
7587exports.inflateMark = inflateMark;
7588exports.inflatePrime = inflatePrime;
7589exports.inflateSetDictionary = inflateSetDictionary;
7590exports.inflateSync = inflateSync;
7591exports.inflateSyncPoint = inflateSyncPoint;
7592exports.inflateUndermine = inflateUndermine;
7593*/
7594},{"../utils/common":27,"./adler32":29,"./crc32":31,"./inffast":34,"./inftrees":36}],36:[function(_dereq_,module,exports){
7595'use strict';
7596
7597
7598var utils = _dereq_('../utils/common');
7599
7600var MAXBITS = 15;
7601var ENOUGH_LENS = 852;
7602var ENOUGH_DISTS = 592;
7603//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
7604
7605var CODES = 0;
7606var LENS = 1;
7607var DISTS = 2;
7608
7609var lbase = [ /* Length codes 257..285 base */
7610  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
7611  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
7612];
7613
7614var lext = [ /* Length codes 257..285 extra */
7615  16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
7616  19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
7617];
7618
7619var dbase = [ /* Distance codes 0..29 base */
7620  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
7621  257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
7622  8193, 12289, 16385, 24577, 0, 0
7623];
7624
7625var dext = [ /* Distance codes 0..29 extra */
7626  16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
7627  23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
7628  28, 28, 29, 29, 64, 64
7629];
7630
7631module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)
7632{
7633  var bits = opts.bits;
7634      //here = opts.here; /* table entry for duplication */
7635
7636  var len = 0;               /* a code's length in bits */
7637  var sym = 0;               /* index of code symbols */
7638  var min = 0, max = 0;          /* minimum and maximum code lengths */
7639  var root = 0;              /* number of index bits for root table */
7640  var curr = 0;              /* number of index bits for current table */
7641  var drop = 0;              /* code bits to drop for sub-table */
7642  var left = 0;                   /* number of prefix codes available */
7643  var used = 0;              /* code entries in table used */
7644  var huff = 0;              /* Huffman code */
7645  var incr;              /* for incrementing code, index */
7646  var fill;              /* index for replicating entries */
7647  var low;               /* low bits for current root entry */
7648  var mask;              /* mask for low root bits */
7649  var next;             /* next available space in table */
7650  var base = null;     /* base value table to use */
7651  var base_index = 0;
7652//  var shoextra;    /* extra bits table to use */
7653  var end;                    /* use base and extra for symbol > end */
7654  var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1];    /* number of codes of each length */
7655  var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1];     /* offsets in table for each length */
7656  var extra = null;
7657  var extra_index = 0;
7658
7659  var here_bits, here_op, here_val;
7660
7661  /*
7662   Process a set of code lengths to create a canonical Huffman code.  The
7663   code lengths are lens[0..codes-1].  Each length corresponds to the
7664   symbols 0..codes-1.  The Huffman code is generated by first sorting the
7665   symbols by length from short to long, and retaining the symbol order
7666   for codes with equal lengths.  Then the code starts with all zero bits
7667   for the first code of the shortest length, and the codes are integer
7668   increments for the same length, and zeros are appended as the length
7669   increases.  For the deflate format, these bits are stored backwards
7670   from their more natural integer increment ordering, and so when the
7671   decoding tables are built in the large loop below, the integer codes
7672   are incremented backwards.
7673
7674   This routine assumes, but does not check, that all of the entries in
7675   lens[] are in the range 0..MAXBITS.  The caller must assure this.
7676   1..MAXBITS is interpreted as that code length.  zero means that that
7677   symbol does not occur in this code.
7678
7679   The codes are sorted by computing a count of codes for each length,
7680   creating from that a table of starting indices for each length in the
7681   sorted table, and then entering the symbols in order in the sorted
7682   table.  The sorted table is work[], with that space being provided by
7683   the caller.
7684
7685   The length counts are used for other purposes as well, i.e. finding
7686   the minimum and maximum length codes, determining if there are any
7687   codes at all, checking for a valid set of lengths, and looking ahead
7688   at length counts to determine sub-table sizes when building the
7689   decoding tables.
7690   */
7691
7692  /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
7693  for (len = 0; len <= MAXBITS; len++) {
7694    count[len] = 0;
7695  }
7696  for (sym = 0; sym < codes; sym++) {
7697    count[lens[lens_index + sym]]++;
7698  }
7699
7700  /* bound code lengths, force root to be within code lengths */
7701  root = bits;
7702  for (max = MAXBITS; max >= 1; max--) {
7703    if (count[max] !== 0) { break; }
7704  }
7705  if (root > max) {
7706    root = max;
7707  }
7708  if (max === 0) {                     /* no symbols to code at all */
7709    //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */
7710    //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;
7711    //table.val[opts.table_index++] = 0;   //here.val = (var short)0;
7712    table[table_index++] = (1 << 24) | (64 << 16) | 0;
7713
7714
7715    //table.op[opts.table_index] = 64;
7716    //table.bits[opts.table_index] = 1;
7717    //table.val[opts.table_index++] = 0;
7718    table[table_index++] = (1 << 24) | (64 << 16) | 0;
7719
7720    opts.bits = 1;
7721    return 0;     /* no symbols, but wait for decoding to report error */
7722  }
7723  for (min = 1; min < max; min++) {
7724    if (count[min] !== 0) { break; }
7725  }
7726  if (root < min) {
7727    root = min;
7728  }
7729
7730  /* check for an over-subscribed or incomplete set of lengths */
7731  left = 1;
7732  for (len = 1; len <= MAXBITS; len++) {
7733    left <<= 1;
7734    left -= count[len];
7735    if (left < 0) {
7736      return -1;
7737    }        /* over-subscribed */
7738  }
7739  if (left > 0 && (type === CODES || max !== 1)) {
7740    return -1;                      /* incomplete set */
7741  }
7742
7743  /* generate offsets into symbol table for each length for sorting */
7744  offs[1] = 0;
7745  for (len = 1; len < MAXBITS; len++) {
7746    offs[len + 1] = offs[len] + count[len];
7747  }
7748
7749  /* sort symbols by length, by symbol order within each length */
7750  for (sym = 0; sym < codes; sym++) {
7751    if (lens[lens_index + sym] !== 0) {
7752      work[offs[lens[lens_index + sym]]++] = sym;
7753    }
7754  }
7755
7756  /*
7757   Create and fill in decoding tables.  In this loop, the table being
7758   filled is at next and has curr index bits.  The code being used is huff
7759   with length len.  That code is converted to an index by dropping drop
7760   bits off of the bottom.  For codes where len is less than drop + curr,
7761   those top drop + curr - len bits are incremented through all values to
7762   fill the table with replicated entries.
7763
7764   root is the number of index bits for the root table.  When len exceeds
7765   root, sub-tables are created pointed to by the root entry with an index
7766   of the low root bits of huff.  This is saved in low to check for when a
7767   new sub-table should be started.  drop is zero when the root table is
7768   being filled, and drop is root when sub-tables are being filled.
7769
7770   When a new sub-table is needed, it is necessary to look ahead in the
7771   code lengths to determine what size sub-table is needed.  The length
7772   counts are used for this, and so count[] is decremented as codes are
7773   entered in the tables.
7774
7775   used keeps track of how many table entries have been allocated from the
7776   provided *table space.  It is checked for LENS and DIST tables against
7777   the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
7778   the initial root table size constants.  See the comments in inftrees.h
7779   for more information.
7780
7781   sym increments through all symbols, and the loop terminates when
7782   all codes of length max, i.e. all codes, have been processed.  This
7783   routine permits incomplete codes, so another loop after this one fills
7784   in the rest of the decoding tables with invalid code markers.
7785   */
7786
7787  /* set up for code type */
7788  // poor man optimization - use if-else instead of switch,
7789  // to avoid deopts in old v8
7790  if (type === CODES) {
7791      base = extra = work;    /* dummy value--not used */
7792      end = 19;
7793  } else if (type === LENS) {
7794      base = lbase;
7795      base_index -= 257;
7796      extra = lext;
7797      extra_index -= 257;
7798      end = 256;
7799  } else {                    /* DISTS */
7800      base = dbase;
7801      extra = dext;
7802      end = -1;
7803  }
7804
7805  /* initialize opts for loop */
7806  huff = 0;                   /* starting code */
7807  sym = 0;                    /* starting code symbol */
7808  len = min;                  /* starting code length */
7809  next = table_index;              /* current table to fill in */
7810  curr = root;                /* current table index bits */
7811  drop = 0;                   /* current bits to drop from code for index */
7812  low = -1;                   /* trigger new sub-table when len > root */
7813  used = 1 << root;          /* use root table entries */
7814  mask = used - 1;            /* mask for comparing low */
7815
7816  /* check available table space */
7817  if ((type === LENS && used > ENOUGH_LENS) ||
7818    (type === DISTS && used > ENOUGH_DISTS)) {
7819    return 1;
7820  }
7821
7822  var i=0;
7823  /* process all codes and make table entries */
7824  for (;;) {
7825    i++;
7826    /* create table entry */
7827    here_bits = len - drop;
7828    if (work[sym] < end) {
7829      here_op = 0;
7830      here_val = work[sym];
7831    }
7832    else if (work[sym] > end) {
7833      here_op = extra[extra_index + work[sym]];
7834      here_val = base[base_index + work[sym]];
7835    }
7836    else {
7837      here_op = 32 + 64;         /* end of block */
7838      here_val = 0;
7839    }
7840
7841    /* replicate for those indices with low len bits equal to huff */
7842    incr = 1 << (len - drop);
7843    fill = 1 << curr;
7844    min = fill;                 /* save offset to next table */
7845    do {
7846      fill -= incr;
7847      table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
7848    } while (fill !== 0);
7849
7850    /* backwards increment the len-bit code huff */
7851    incr = 1 << (len - 1);
7852    while (huff & incr) {
7853      incr >>= 1;
7854    }
7855    if (incr !== 0) {
7856      huff &= incr - 1;
7857      huff += incr;
7858    } else {
7859      huff = 0;
7860    }
7861
7862    /* go to next symbol, update count, len */
7863    sym++;
7864    if (--count[len] === 0) {
7865      if (len === max) { break; }
7866      len = lens[lens_index + work[sym]];
7867    }
7868
7869    /* create new sub-table if needed */
7870    if (len > root && (huff & mask) !== low) {
7871      /* if first time, transition to sub-tables */
7872      if (drop === 0) {
7873        drop = root;
7874      }
7875
7876      /* increment past last table */
7877      next += min;            /* here min is 1 << curr */
7878
7879      /* determine length of next table */
7880      curr = len - drop;
7881      left = 1 << curr;
7882      while (curr + drop < max) {
7883        left -= count[curr + drop];
7884        if (left <= 0) { break; }
7885        curr++;
7886        left <<= 1;
7887      }
7888
7889      /* check for enough space */
7890      used += 1 << curr;
7891      if ((type === LENS && used > ENOUGH_LENS) ||
7892        (type === DISTS && used > ENOUGH_DISTS)) {
7893        return 1;
7894      }
7895
7896      /* point entry in root table to sub-table */
7897      low = huff & mask;
7898      /*table.op[low] = curr;
7899      table.bits[low] = root;
7900      table.val[low] = next - opts.table_index;*/
7901      table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
7902    }
7903  }
7904
7905  /* fill in remaining table entry if code is incomplete (guaranteed to have
7906   at most one remaining entry, since if the code is incomplete, the
7907   maximum code length that was allowed to get this far is one bit) */
7908  if (huff !== 0) {
7909    //table.op[next + huff] = 64;            /* invalid code marker */
7910    //table.bits[next + huff] = len - drop;
7911    //table.val[next + huff] = 0;
7912    table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
7913  }
7914
7915  /* set return parameters */
7916  //opts.table_index += used;
7917  opts.bits = root;
7918  return 0;
7919};
7920
7921},{"../utils/common":27}],37:[function(_dereq_,module,exports){
7922'use strict';
7923
7924module.exports = {
7925  '2':    'need dictionary',     /* Z_NEED_DICT       2  */
7926  '1':    'stream end',          /* Z_STREAM_END      1  */
7927  '0':    '',                    /* Z_OK              0  */
7928  '-1':   'file error',          /* Z_ERRNO         (-1) */
7929  '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */
7930  '-3':   'data error',          /* Z_DATA_ERROR    (-3) */
7931  '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */
7932  '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */
7933  '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */
7934};
7935},{}],38:[function(_dereq_,module,exports){
7936'use strict';
7937
7938
7939var utils = _dereq_('../utils/common');
7940
7941/* Public constants ==========================================================*/
7942/* ===========================================================================*/
7943
7944
7945//var Z_FILTERED          = 1;
7946//var Z_HUFFMAN_ONLY      = 2;
7947//var Z_RLE               = 3;
7948var Z_FIXED               = 4;
7949//var Z_DEFAULT_STRATEGY  = 0;
7950
7951/* Possible values of the data_type field (though see inflate()) */
7952var Z_BINARY              = 0;
7953var Z_TEXT                = 1;
7954//var Z_ASCII             = 1; // = Z_TEXT
7955var Z_UNKNOWN             = 2;
7956
7957/*============================================================================*/
7958
7959
7960function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
7961
7962// From zutil.h
7963
7964var STORED_BLOCK = 0;
7965var STATIC_TREES = 1;
7966var DYN_TREES    = 2;
7967/* The three kinds of block type */
7968
7969var MIN_MATCH    = 3;
7970var MAX_MATCH    = 258;
7971/* The minimum and maximum match lengths */
7972
7973// From deflate.h
7974/* ===========================================================================
7975 * Internal compression state.
7976 */
7977
7978var LENGTH_CODES  = 29;
7979/* number of length codes, not counting the special END_BLOCK code */
7980
7981var LITERALS      = 256;
7982/* number of literal bytes 0..255 */
7983
7984var L_CODES       = LITERALS + 1 + LENGTH_CODES;
7985/* number of Literal or Length codes, including the END_BLOCK code */
7986
7987var D_CODES       = 30;
7988/* number of distance codes */
7989
7990var BL_CODES      = 19;
7991/* number of codes used to transfer the bit lengths */
7992
7993var HEAP_SIZE     = 2*L_CODES + 1;
7994/* maximum heap size */
7995
7996var MAX_BITS      = 15;
7997/* All codes must not exceed MAX_BITS bits */
7998
7999var Buf_size      = 16;
8000/* size of bit buffer in bi_buf */
8001
8002
8003/* ===========================================================================
8004 * Constants
8005 */
8006
8007var MAX_BL_BITS = 7;
8008/* Bit length codes must not exceed MAX_BL_BITS bits */
8009
8010var END_BLOCK   = 256;
8011/* end of block literal code */
8012
8013var REP_3_6     = 16;
8014/* repeat previous bit length 3-6 times (2 bits of repeat count) */
8015
8016var REPZ_3_10   = 17;
8017/* repeat a zero length 3-10 times  (3 bits of repeat count) */
8018
8019var REPZ_11_138 = 18;
8020/* repeat a zero length 11-138 times  (7 bits of repeat count) */
8021
8022var extra_lbits =   /* extra bits for each length code */
8023  [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];
8024
8025var extra_dbits =   /* extra bits for each distance code */
8026  [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];
8027
8028var extra_blbits =  /* extra bits for each bit length code */
8029  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
8030
8031var bl_order =
8032  [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
8033/* The lengths of the bit length codes are sent in order of decreasing
8034 * probability, to avoid transmitting the lengths for unused bit length codes.
8035 */
8036
8037/* ===========================================================================
8038 * Local data. These are initialized only once.
8039 */
8040
8041// We pre-fill arrays with 0 to avoid uninitialized gaps
8042
8043var DIST_CODE_LEN = 512; /* see definition of array dist_code below */
8044
8045// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1
8046var static_ltree  = new Array((L_CODES+2) * 2);
8047zero(static_ltree);
8048/* The static literal tree. Since the bit lengths are imposed, there is no
8049 * need for the L_CODES extra codes used during heap construction. However
8050 * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
8051 * below).
8052 */
8053
8054var static_dtree  = new Array(D_CODES * 2);
8055zero(static_dtree);
8056/* The static distance tree. (Actually a trivial tree since all codes use
8057 * 5 bits.)
8058 */
8059
8060var _dist_code    = new Array(DIST_CODE_LEN);
8061zero(_dist_code);
8062/* Distance codes. The first 256 values correspond to the distances
8063 * 3 .. 258, the last 256 values correspond to the top 8 bits of
8064 * the 15 bit distances.
8065 */
8066
8067var _length_code  = new Array(MAX_MATCH-MIN_MATCH+1);
8068zero(_length_code);
8069/* length code for each normalized match length (0 == MIN_MATCH) */
8070
8071var base_length   = new Array(LENGTH_CODES);
8072zero(base_length);
8073/* First normalized length for each code (0 = MIN_MATCH) */
8074
8075var base_dist     = new Array(D_CODES);
8076zero(base_dist);
8077/* First normalized distance for each code (0 = distance of 1) */
8078
8079
8080var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) {
8081
8082  this.static_tree  = static_tree;  /* static tree or NULL */
8083  this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */
8084  this.extra_base   = extra_base;   /* base index for extra_bits */
8085  this.elems        = elems;        /* max number of elements in the tree */
8086  this.max_length   = max_length;   /* max bit length for the codes */
8087
8088  // show if `static_tree` has data or dummy - needed for monomorphic objects
8089  this.has_stree    = static_tree && static_tree.length;
8090};
8091
8092
8093var static_l_desc;
8094var static_d_desc;
8095var static_bl_desc;
8096
8097
8098var TreeDesc = function(dyn_tree, stat_desc) {
8099  this.dyn_tree = dyn_tree;     /* the dynamic tree */
8100  this.max_code = 0;            /* largest code with non zero frequency */
8101  this.stat_desc = stat_desc;   /* the corresponding static tree */
8102};
8103
8104
8105
8106function d_code(dist) {
8107  return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
8108}
8109
8110
8111/* ===========================================================================
8112 * Output a short LSB first on the stream.
8113 * IN assertion: there is enough room in pendingBuf.
8114 */
8115function put_short (s, w) {
8116//    put_byte(s, (uch)((w) & 0xff));
8117//    put_byte(s, (uch)((ush)(w) >> 8));
8118  s.pending_buf[s.pending++] = (w) & 0xff;
8119  s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
8120}
8121
8122
8123/* ===========================================================================
8124 * Send a value on a given number of bits.
8125 * IN assertion: length <= 16 and value fits in length bits.
8126 */
8127function send_bits(s, value, length) {
8128  if (s.bi_valid > (Buf_size - length)) {
8129    s.bi_buf |= (value << s.bi_valid) & 0xffff;
8130    put_short(s, s.bi_buf);
8131    s.bi_buf = value >> (Buf_size - s.bi_valid);
8132    s.bi_valid += length - Buf_size;
8133  } else {
8134    s.bi_buf |= (value << s.bi_valid) & 0xffff;
8135    s.bi_valid += length;
8136  }
8137}
8138
8139
8140function send_code(s, c, tree) {
8141  send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/);
8142}
8143
8144
8145/* ===========================================================================
8146 * Reverse the first len bits of a code, using straightforward code (a faster
8147 * method would use a table)
8148 * IN assertion: 1 <= len <= 15
8149 */
8150function bi_reverse(code, len) {
8151  var res = 0;
8152  do {
8153    res |= code & 1;
8154    code >>>= 1;
8155    res <<= 1;
8156  } while (--len > 0);
8157  return res >>> 1;
8158}
8159
8160
8161/* ===========================================================================
8162 * Flush the bit buffer, keeping at most 7 bits in it.
8163 */
8164function bi_flush(s) {
8165  if (s.bi_valid === 16) {
8166    put_short(s, s.bi_buf);
8167    s.bi_buf = 0;
8168    s.bi_valid = 0;
8169
8170  } else if (s.bi_valid >= 8) {
8171    s.pending_buf[s.pending++] = s.bi_buf & 0xff;
8172    s.bi_buf >>= 8;
8173    s.bi_valid -= 8;
8174  }
8175}
8176
8177
8178/* ===========================================================================
8179 * Compute the optimal bit lengths for a tree and update the total bit length
8180 * for the current block.
8181 * IN assertion: the fields freq and dad are set, heap[heap_max] and
8182 *    above are the tree nodes sorted by increasing frequency.
8183 * OUT assertions: the field len is set to the optimal bit length, the
8184 *     array bl_count contains the frequencies for each bit length.
8185 *     The length opt_len is updated; static_len is also updated if stree is
8186 *     not null.
8187 */
8188function gen_bitlen(s, desc)
8189//    deflate_state *s;
8190//    tree_desc *desc;    /* the tree descriptor */
8191{
8192  var tree            = desc.dyn_tree;
8193  var max_code        = desc.max_code;
8194  var stree           = desc.stat_desc.static_tree;
8195  var has_stree       = desc.stat_desc.has_stree;
8196  var extra           = desc.stat_desc.extra_bits;
8197  var base            = desc.stat_desc.extra_base;
8198  var max_length      = desc.stat_desc.max_length;
8199  var h;              /* heap index */
8200  var n, m;           /* iterate over the tree elements */
8201  var bits;           /* bit length */
8202  var xbits;          /* extra bits */
8203  var f;              /* frequency */
8204  var overflow = 0;   /* number of elements with bit length too large */
8205
8206  for (bits = 0; bits <= MAX_BITS; bits++) {
8207    s.bl_count[bits] = 0;
8208  }
8209
8210  /* In a first pass, compute the optimal bit lengths (which may
8211   * overflow in the case of the bit length tree).
8212   */
8213  tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */
8214
8215  for (h = s.heap_max+1; h < HEAP_SIZE; h++) {
8216    n = s.heap[h];
8217    bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
8218    if (bits > max_length) {
8219      bits = max_length;
8220      overflow++;
8221    }
8222    tree[n*2 + 1]/*.Len*/ = bits;
8223    /* We overwrite tree[n].Dad which is no longer needed */
8224
8225    if (n > max_code) { continue; } /* not a leaf node */
8226
8227    s.bl_count[bits]++;
8228    xbits = 0;
8229    if (n >= base) {
8230      xbits = extra[n-base];
8231    }
8232    f = tree[n * 2]/*.Freq*/;
8233    s.opt_len += f * (bits + xbits);
8234    if (has_stree) {
8235      s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits);
8236    }
8237  }
8238  if (overflow === 0) { return; }
8239
8240  // Trace((stderr,"\nbit length overflow\n"));
8241  /* This happens for example on obj2 and pic of the Calgary corpus */
8242
8243  /* Find the first bit length which could increase: */
8244  do {
8245    bits = max_length-1;
8246    while (s.bl_count[bits] === 0) { bits--; }
8247    s.bl_count[bits]--;      /* move one leaf down the tree */
8248    s.bl_count[bits+1] += 2; /* move one overflow item as its brother */
8249    s.bl_count[max_length]--;
8250    /* The brother of the overflow item also moves one step up,
8251     * but this does not affect bl_count[max_length]
8252     */
8253    overflow -= 2;
8254  } while (overflow > 0);
8255
8256  /* Now recompute all bit lengths, scanning in increasing frequency.
8257   * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
8258   * lengths instead of fixing only the wrong ones. This idea is taken
8259   * from 'ar' written by Haruhiko Okumura.)
8260   */
8261  for (bits = max_length; bits !== 0; bits--) {
8262    n = s.bl_count[bits];
8263    while (n !== 0) {
8264      m = s.heap[--h];
8265      if (m > max_code) { continue; }
8266      if (tree[m*2 + 1]/*.Len*/ !== bits) {
8267        // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
8268        s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/;
8269        tree[m*2 + 1]/*.Len*/ = bits;
8270      }
8271      n--;
8272    }
8273  }
8274}
8275
8276
8277/* ===========================================================================
8278 * Generate the codes for a given tree and bit counts (which need not be
8279 * optimal).
8280 * IN assertion: the array bl_count contains the bit length statistics for
8281 * the given tree and the field len is set for all tree elements.
8282 * OUT assertion: the field code is set for all tree elements of non
8283 *     zero code length.
8284 */
8285function gen_codes(tree, max_code, bl_count)
8286//    ct_data *tree;             /* the tree to decorate */
8287//    int max_code;              /* largest code with non zero frequency */
8288//    ushf *bl_count;            /* number of codes at each bit length */
8289{
8290  var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */
8291  var code = 0;              /* running code value */
8292  var bits;                  /* bit index */
8293  var n;                     /* code index */
8294
8295  /* The distribution counts are first used to generate the code values
8296   * without bit reversal.
8297   */
8298  for (bits = 1; bits <= MAX_BITS; bits++) {
8299    next_code[bits] = code = (code + bl_count[bits-1]) << 1;
8300  }
8301  /* Check that the bit counts in bl_count are consistent. The last code
8302   * must be all ones.
8303   */
8304  //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
8305  //        "inconsistent bit counts");
8306  //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
8307
8308  for (n = 0;  n <= max_code; n++) {
8309    var len = tree[n*2 + 1]/*.Len*/;
8310    if (len === 0) { continue; }
8311    /* Now reverse the bits */
8312    tree[n*2]/*.Code*/ = bi_reverse(next_code[len]++, len);
8313
8314    //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
8315    //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
8316  }
8317}
8318
8319
8320/* ===========================================================================
8321 * Initialize the various 'constant' tables.
8322 */
8323function tr_static_init() {
8324  var n;        /* iterates over tree elements */
8325  var bits;     /* bit counter */
8326  var length;   /* length value */
8327  var code;     /* code value */
8328  var dist;     /* distance index */
8329  var bl_count = new Array(MAX_BITS+1);
8330  /* number of codes at each bit length for an optimal tree */
8331
8332  // do check in _tr_init()
8333  //if (static_init_done) return;
8334
8335  /* For some embedded targets, global variables are not initialized: */
8336/*#ifdef NO_INIT_GLOBAL_POINTERS
8337  static_l_desc.static_tree = static_ltree;
8338  static_l_desc.extra_bits = extra_lbits;
8339  static_d_desc.static_tree = static_dtree;
8340  static_d_desc.extra_bits = extra_dbits;
8341  static_bl_desc.extra_bits = extra_blbits;
8342#endif*/
8343
8344  /* Initialize the mapping length (0..255) -> length code (0..28) */
8345  length = 0;
8346  for (code = 0; code < LENGTH_CODES-1; code++) {
8347    base_length[code] = length;
8348    for (n = 0; n < (1<<extra_lbits[code]); n++) {
8349      _length_code[length++] = code;
8350    }
8351  }
8352  //Assert (length == 256, "tr_static_init: length != 256");
8353  /* Note that the length 255 (match length 258) can be represented
8354   * in two different ways: code 284 + 5 bits or code 285, so we
8355   * overwrite length_code[255] to use the best encoding:
8356   */
8357  _length_code[length-1] = code;
8358
8359  /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
8360  dist = 0;
8361  for (code = 0 ; code < 16; code++) {
8362    base_dist[code] = dist;
8363    for (n = 0; n < (1<<extra_dbits[code]); n++) {
8364      _dist_code[dist++] = code;
8365    }
8366  }
8367  //Assert (dist == 256, "tr_static_init: dist != 256");
8368  dist >>= 7; /* from now on, all distances are divided by 128 */
8369  for ( ; code < D_CODES; code++) {
8370    base_dist[code] = dist << 7;
8371    for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
8372      _dist_code[256 + dist++] = code;
8373    }
8374  }
8375  //Assert (dist == 256, "tr_static_init: 256+dist != 512");
8376
8377  /* Construct the codes of the static literal tree */
8378  for (bits = 0; bits <= MAX_BITS; bits++) {
8379    bl_count[bits] = 0;
8380  }
8381
8382  n = 0;
8383  while (n <= 143) {
8384    static_ltree[n*2 + 1]/*.Len*/ = 8;
8385    n++;
8386    bl_count[8]++;
8387  }
8388  while (n <= 255) {
8389    static_ltree[n*2 + 1]/*.Len*/ = 9;
8390    n++;
8391    bl_count[9]++;
8392  }
8393  while (n <= 279) {
8394    static_ltree[n*2 + 1]/*.Len*/ = 7;
8395    n++;
8396    bl_count[7]++;
8397  }
8398  while (n <= 287) {
8399    static_ltree[n*2 + 1]/*.Len*/ = 8;
8400    n++;
8401    bl_count[8]++;
8402  }
8403  /* Codes 286 and 287 do not exist, but we must include them in the
8404   * tree construction to get a canonical Huffman tree (longest code
8405   * all ones)
8406   */
8407  gen_codes(static_ltree, L_CODES+1, bl_count);
8408
8409  /* The static distance tree is trivial: */
8410  for (n = 0; n < D_CODES; n++) {
8411    static_dtree[n*2 + 1]/*.Len*/ = 5;
8412    static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5);
8413  }
8414
8415  // Now data ready and we can init static trees
8416  static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS);
8417  static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS);
8418  static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES, MAX_BL_BITS);
8419
8420  //static_init_done = true;
8421}
8422
8423
8424/* ===========================================================================
8425 * Initialize a new block.
8426 */
8427function init_block(s) {
8428  var n; /* iterates over tree elements */
8429
8430  /* Initialize the trees. */
8431  for (n = 0; n < L_CODES;  n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; }
8432  for (n = 0; n < D_CODES;  n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; }
8433  for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; }
8434
8435  s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1;
8436  s.opt_len = s.static_len = 0;
8437  s.last_lit = s.matches = 0;
8438}
8439
8440
8441/* ===========================================================================
8442 * Flush the bit buffer and align the output on a byte boundary
8443 */
8444function bi_windup(s)
8445{
8446  if (s.bi_valid > 8) {
8447    put_short(s, s.bi_buf);
8448  } else if (s.bi_valid > 0) {
8449    //put_byte(s, (Byte)s->bi_buf);
8450    s.pending_buf[s.pending++] = s.bi_buf;
8451  }
8452  s.bi_buf = 0;
8453  s.bi_valid = 0;
8454}
8455
8456/* ===========================================================================
8457 * Copy a stored block, storing first the length and its
8458 * one's complement if requested.
8459 */
8460function copy_block(s, buf, len, header)
8461//DeflateState *s;
8462//charf    *buf;    /* the input data */
8463//unsigned len;     /* its length */
8464//int      header;  /* true if block header must be written */
8465{
8466  bi_windup(s);        /* align on byte boundary */
8467
8468  if (header) {
8469    put_short(s, len);
8470    put_short(s, ~len);
8471  }
8472//  while (len--) {
8473//    put_byte(s, *buf++);
8474//  }
8475  utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);
8476  s.pending += len;
8477}
8478
8479/* ===========================================================================
8480 * Compares to subtrees, using the tree depth as tie breaker when
8481 * the subtrees have equal frequency. This minimizes the worst case length.
8482 */
8483function smaller(tree, n, m, depth) {
8484  var _n2 = n*2;
8485  var _m2 = m*2;
8486  return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
8487         (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
8488}
8489
8490/* ===========================================================================
8491 * Restore the heap property by moving down the tree starting at node k,
8492 * exchanging a node with the smallest of its two sons if necessary, stopping
8493 * when the heap property is re-established (each father smaller than its
8494 * two sons).
8495 */
8496function pqdownheap(s, tree, k)
8497//    deflate_state *s;
8498//    ct_data *tree;  /* the tree to restore */
8499//    int k;               /* node to move down */
8500{
8501  var v = s.heap[k];
8502  var j = k << 1;  /* left son of k */
8503  while (j <= s.heap_len) {
8504    /* Set j to the smallest of the two sons: */
8505    if (j < s.heap_len &&
8506      smaller(tree, s.heap[j+1], s.heap[j], s.depth)) {
8507      j++;
8508    }
8509    /* Exit if v is smaller than both sons */
8510    if (smaller(tree, v, s.heap[j], s.depth)) { break; }
8511
8512    /* Exchange v with the smallest son */
8513    s.heap[k] = s.heap[j];
8514    k = j;
8515
8516    /* And continue down the tree, setting j to the left son of k */
8517    j <<= 1;
8518  }
8519  s.heap[k] = v;
8520}
8521
8522
8523// inlined manually
8524// var SMALLEST = 1;
8525
8526/* ===========================================================================
8527 * Send the block data compressed using the given Huffman trees
8528 */
8529function compress_block(s, ltree, dtree)
8530//    deflate_state *s;
8531//    const ct_data *ltree; /* literal tree */
8532//    const ct_data *dtree; /* distance tree */
8533{
8534  var dist;           /* distance of matched string */
8535  var lc;             /* match length or unmatched char (if dist == 0) */
8536  var lx = 0;         /* running index in l_buf */
8537  var code;           /* the code to send */
8538  var extra;          /* number of extra bits to send */
8539
8540  if (s.last_lit !== 0) {
8541    do {
8542      dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]);
8543      lc = s.pending_buf[s.l_buf + lx];
8544      lx++;
8545
8546      if (dist === 0) {
8547        send_code(s, lc, ltree); /* send a literal byte */
8548        //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
8549      } else {
8550        /* Here, lc is the match length - MIN_MATCH */
8551        code = _length_code[lc];
8552        send_code(s, code+LITERALS+1, ltree); /* send the length code */
8553        extra = extra_lbits[code];
8554        if (extra !== 0) {
8555          lc -= base_length[code];
8556          send_bits(s, lc, extra);       /* send the extra length bits */
8557        }
8558        dist--; /* dist is now the match distance - 1 */
8559        code = d_code(dist);
8560        //Assert (code < D_CODES, "bad d_code");
8561
8562        send_code(s, code, dtree);       /* send the distance code */
8563        extra = extra_dbits[code];
8564        if (extra !== 0) {
8565          dist -= base_dist[code];
8566          send_bits(s, dist, extra);   /* send the extra distance bits */
8567        }
8568      } /* literal or match pair ? */
8569
8570      /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
8571      //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
8572      //       "pendingBuf overflow");
8573
8574    } while (lx < s.last_lit);
8575  }
8576
8577  send_code(s, END_BLOCK, ltree);
8578}
8579
8580
8581/* ===========================================================================
8582 * Construct one Huffman tree and assigns the code bit strings and lengths.
8583 * Update the total bit length for the current block.
8584 * IN assertion: the field freq is set for all tree elements.
8585 * OUT assertions: the fields len and code are set to the optimal bit length
8586 *     and corresponding code. The length opt_len is updated; static_len is
8587 *     also updated if stree is not null. The field max_code is set.
8588 */
8589function build_tree(s, desc)
8590//    deflate_state *s;
8591//    tree_desc *desc; /* the tree descriptor */
8592{
8593  var tree     = desc.dyn_tree;
8594  var stree    = desc.stat_desc.static_tree;
8595  var has_stree = desc.stat_desc.has_stree;
8596  var elems    = desc.stat_desc.elems;
8597  var n, m;          /* iterate over heap elements */
8598  var max_code = -1; /* largest code with non zero frequency */
8599  var node;          /* new node being created */
8600
8601  /* Construct the initial heap, with least frequent element in
8602   * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
8603   * heap[0] is not used.
8604   */
8605  s.heap_len = 0;
8606  s.heap_max = HEAP_SIZE;
8607
8608  for (n = 0; n < elems; n++) {
8609    if (tree[n * 2]/*.Freq*/ !== 0) {
8610      s.heap[++s.heap_len] = max_code = n;
8611      s.depth[n] = 0;
8612
8613    } else {
8614      tree[n*2 + 1]/*.Len*/ = 0;
8615    }
8616  }
8617
8618  /* The pkzip format requires that at least one distance code exists,
8619   * and that at least one bit should be sent even if there is only one
8620   * possible code. So to avoid special checks later on we force at least
8621   * two codes of non zero frequency.
8622   */
8623  while (s.heap_len < 2) {
8624    node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
8625    tree[node * 2]/*.Freq*/ = 1;
8626    s.depth[node] = 0;
8627    s.opt_len--;
8628
8629    if (has_stree) {
8630      s.static_len -= stree[node*2 + 1]/*.Len*/;
8631    }
8632    /* node is 0 or 1 so it does not have extra bits */
8633  }
8634  desc.max_code = max_code;
8635
8636  /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
8637   * establish sub-heaps of increasing lengths:
8638   */
8639  for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
8640
8641  /* Construct the Huffman tree by repeatedly combining the least two
8642   * frequent nodes.
8643   */
8644  node = elems;              /* next internal node of the tree */
8645  do {
8646    //pqremove(s, tree, n);  /* n = node of least frequency */
8647    /*** pqremove ***/
8648    n = s.heap[1/*SMALLEST*/];
8649    s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
8650    pqdownheap(s, tree, 1/*SMALLEST*/);
8651    /***/
8652
8653    m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
8654
8655    s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
8656    s.heap[--s.heap_max] = m;
8657
8658    /* Create a new node father of n and m */
8659    tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
8660    s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
8661    tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node;
8662
8663    /* and insert the new node in the heap */
8664    s.heap[1/*SMALLEST*/] = node++;
8665    pqdownheap(s, tree, 1/*SMALLEST*/);
8666
8667  } while (s.heap_len >= 2);
8668
8669  s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
8670
8671  /* At this point, the fields freq and dad are set. We can now
8672   * generate the bit lengths.
8673   */
8674  gen_bitlen(s, desc);
8675
8676  /* The field len is now set, we can generate the bit codes */
8677  gen_codes(tree, max_code, s.bl_count);
8678}
8679
8680
8681/* ===========================================================================
8682 * Scan a literal or distance tree to determine the frequencies of the codes
8683 * in the bit length tree.
8684 */
8685function scan_tree(s, tree, max_code)
8686//    deflate_state *s;
8687//    ct_data *tree;   /* the tree to be scanned */
8688//    int max_code;    /* and its largest code of non zero frequency */
8689{
8690  var n;                     /* iterates over all tree elements */
8691  var prevlen = -1;          /* last emitted length */
8692  var curlen;                /* length of current code */
8693
8694  var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */
8695
8696  var count = 0;             /* repeat count of the current code */
8697  var max_count = 7;         /* max repeat count */
8698  var min_count = 4;         /* min repeat count */
8699
8700  if (nextlen === 0) {
8701    max_count = 138;
8702    min_count = 3;
8703  }
8704  tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */
8705
8706  for (n = 0; n <= max_code; n++) {
8707    curlen = nextlen;
8708    nextlen = tree[(n+1)*2 + 1]/*.Len*/;
8709
8710    if (++count < max_count && curlen === nextlen) {
8711      continue;
8712
8713    } else if (count < min_count) {
8714      s.bl_tree[curlen * 2]/*.Freq*/ += count;
8715
8716    } else if (curlen !== 0) {
8717
8718      if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
8719      s.bl_tree[REP_3_6*2]/*.Freq*/++;
8720
8721    } else if (count <= 10) {
8722      s.bl_tree[REPZ_3_10*2]/*.Freq*/++;
8723
8724    } else {
8725      s.bl_tree[REPZ_11_138*2]/*.Freq*/++;
8726    }
8727
8728    count = 0;
8729    prevlen = curlen;
8730
8731    if (nextlen === 0) {
8732      max_count = 138;
8733      min_count = 3;
8734
8735    } else if (curlen === nextlen) {
8736      max_count = 6;
8737      min_count = 3;
8738
8739    } else {
8740      max_count = 7;
8741      min_count = 4;
8742    }
8743  }
8744}
8745
8746
8747/* ===========================================================================
8748 * Send a literal or distance tree in compressed form, using the codes in
8749 * bl_tree.
8750 */
8751function send_tree(s, tree, max_code)
8752//    deflate_state *s;
8753//    ct_data *tree; /* the tree to be scanned */
8754//    int max_code;       /* and its largest code of non zero frequency */
8755{
8756  var n;                     /* iterates over all tree elements */
8757  var prevlen = -1;          /* last emitted length */
8758  var curlen;                /* length of current code */
8759
8760  var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */
8761
8762  var count = 0;             /* repeat count of the current code */
8763  var max_count = 7;         /* max repeat count */
8764  var min_count = 4;         /* min repeat count */
8765
8766  /* tree[max_code+1].Len = -1; */  /* guard already set */
8767  if (nextlen === 0) {
8768    max_count = 138;
8769    min_count = 3;
8770  }
8771
8772  for (n = 0; n <= max_code; n++) {
8773    curlen = nextlen;
8774    nextlen = tree[(n+1)*2 + 1]/*.Len*/;
8775
8776    if (++count < max_count && curlen === nextlen) {
8777      continue;
8778
8779    } else if (count < min_count) {
8780      do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
8781
8782    } else if (curlen !== 0) {
8783      if (curlen !== prevlen) {
8784        send_code(s, curlen, s.bl_tree);
8785        count--;
8786      }
8787      //Assert(count >= 3 && count <= 6, " 3_6?");
8788      send_code(s, REP_3_6, s.bl_tree);
8789      send_bits(s, count-3, 2);
8790
8791    } else if (count <= 10) {
8792      send_code(s, REPZ_3_10, s.bl_tree);
8793      send_bits(s, count-3, 3);
8794
8795    } else {
8796      send_code(s, REPZ_11_138, s.bl_tree);
8797      send_bits(s, count-11, 7);
8798    }
8799
8800    count = 0;
8801    prevlen = curlen;
8802    if (nextlen === 0) {
8803      max_count = 138;
8804      min_count = 3;
8805
8806    } else if (curlen === nextlen) {
8807      max_count = 6;
8808      min_count = 3;
8809
8810    } else {
8811      max_count = 7;
8812      min_count = 4;
8813    }
8814  }
8815}
8816
8817
8818/* ===========================================================================
8819 * Construct the Huffman tree for the bit lengths and return the index in
8820 * bl_order of the last bit length code to send.
8821 */
8822function build_bl_tree(s) {
8823  var max_blindex;  /* index of last bit length code of non zero freq */
8824
8825  /* Determine the bit length frequencies for literal and distance trees */
8826  scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
8827  scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
8828
8829  /* Build the bit length tree: */
8830  build_tree(s, s.bl_desc);
8831  /* opt_len now includes the length of the tree representations, except
8832   * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
8833   */
8834
8835  /* Determine the number of bit length codes to send. The pkzip format
8836   * requires that at least 4 bit length codes be sent. (appnote.txt says
8837   * 3 but the actual value used is 4.)
8838   */
8839  for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
8840    if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) {
8841      break;
8842    }
8843  }
8844  /* Update opt_len to include the bit length tree and counts */
8845  s.opt_len += 3*(max_blindex+1) + 5+5+4;
8846  //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
8847  //        s->opt_len, s->static_len));
8848
8849  return max_blindex;
8850}
8851
8852
8853/* ===========================================================================
8854 * Send the header for a block using dynamic Huffman trees: the counts, the
8855 * lengths of the bit length codes, the literal tree and the distance tree.
8856 * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
8857 */
8858function send_all_trees(s, lcodes, dcodes, blcodes)
8859//    deflate_state *s;
8860//    int lcodes, dcodes, blcodes; /* number of codes for each tree */
8861{
8862  var rank;                    /* index in bl_order */
8863
8864  //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
8865  //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
8866  //        "too many codes");
8867  //Tracev((stderr, "\nbl counts: "));
8868  send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
8869  send_bits(s, dcodes-1,   5);
8870  send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
8871  for (rank = 0; rank < blcodes; rank++) {
8872    //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
8873    send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3);
8874  }
8875  //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
8876
8877  send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */
8878  //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
8879
8880  send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */
8881  //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
8882}
8883
8884
8885/* ===========================================================================
8886 * Check if the data type is TEXT or BINARY, using the following algorithm:
8887 * - TEXT if the two conditions below are satisfied:
8888 *    a) There are no non-portable control characters belonging to the
8889 *       "black list" (0..6, 14..25, 28..31).
8890 *    b) There is at least one printable character belonging to the
8891 *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
8892 * - BINARY otherwise.
8893 * - The following partially-portable control characters form a
8894 *   "gray list" that is ignored in this detection algorithm:
8895 *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
8896 * IN assertion: the fields Freq of dyn_ltree are set.
8897 */
8898function detect_data_type(s) {
8899  /* black_mask is the bit mask of black-listed bytes
8900   * set bits 0..6, 14..25, and 28..31
8901   * 0xf3ffc07f = binary 11110011111111111100000001111111
8902   */
8903  var black_mask = 0xf3ffc07f;
8904  var n;
8905
8906  /* Check for non-textual ("black-listed") bytes. */
8907  for (n = 0; n <= 31; n++, black_mask >>>= 1) {
8908    if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) {
8909      return Z_BINARY;
8910    }
8911  }
8912
8913  /* Check for textual ("white-listed") bytes. */
8914  if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
8915      s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
8916    return Z_TEXT;
8917  }
8918  for (n = 32; n < LITERALS; n++) {
8919    if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
8920      return Z_TEXT;
8921    }
8922  }
8923
8924  /* There are no "black-listed" or "white-listed" bytes:
8925   * this stream either is empty or has tolerated ("gray-listed") bytes only.
8926   */
8927  return Z_BINARY;
8928}
8929
8930
8931var static_init_done = false;
8932
8933/* ===========================================================================
8934 * Initialize the tree data structures for a new zlib stream.
8935 */
8936function _tr_init(s)
8937{
8938
8939  if (!static_init_done) {
8940    tr_static_init();
8941    static_init_done = true;
8942  }
8943
8944  s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);
8945  s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);
8946  s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
8947
8948  s.bi_buf = 0;
8949  s.bi_valid = 0;
8950
8951  /* Initialize the first block of the first file: */
8952  init_block(s);
8953}
8954
8955
8956/* ===========================================================================
8957 * Send a stored block
8958 */
8959function _tr_stored_block(s, buf, stored_len, last)
8960//DeflateState *s;
8961//charf *buf;       /* input block */
8962//ulg stored_len;   /* length of input block */
8963//int last;         /* one if this is the last block for a file */
8964{
8965  send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3);    /* send block type */
8966  copy_block(s, buf, stored_len, true); /* with header */
8967}
8968
8969
8970/* ===========================================================================
8971 * Send one empty static block to give enough lookahead for inflate.
8972 * This takes 10 bits, of which 7 may remain in the bit buffer.
8973 */
8974function _tr_align(s) {
8975  send_bits(s, STATIC_TREES<<1, 3);
8976  send_code(s, END_BLOCK, static_ltree);
8977  bi_flush(s);
8978}
8979
8980
8981/* ===========================================================================
8982 * Determine the best encoding for the current block: dynamic trees, static
8983 * trees or store, and output the encoded block to the zip file.
8984 */
8985function _tr_flush_block(s, buf, stored_len, last)
8986//DeflateState *s;
8987//charf *buf;       /* input block, or NULL if too old */
8988//ulg stored_len;   /* length of input block */
8989//int last;         /* one if this is the last block for a file */
8990{
8991  var opt_lenb, static_lenb;  /* opt_len and static_len in bytes */
8992  var max_blindex = 0;        /* index of last bit length code of non zero freq */
8993
8994  /* Build the Huffman trees unless a stored block is forced */
8995  if (s.level > 0) {
8996
8997    /* Check if the file is binary or text */
8998    if (s.strm.data_type === Z_UNKNOWN) {
8999      s.strm.data_type = detect_data_type(s);
9000    }
9001
9002    /* Construct the literal and distance trees */
9003    build_tree(s, s.l_desc);
9004    // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
9005    //        s->static_len));
9006
9007    build_tree(s, s.d_desc);
9008    // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
9009    //        s->static_len));
9010    /* At this point, opt_len and static_len are the total bit lengths of
9011     * the compressed block data, excluding the tree representations.
9012     */
9013
9014    /* Build the bit length tree for the above two trees, and get the index
9015     * in bl_order of the last bit length code to send.
9016     */
9017    max_blindex = build_bl_tree(s);
9018
9019    /* Determine the best encoding. Compute the block lengths in bytes. */
9020    opt_lenb = (s.opt_len+3+7) >>> 3;
9021    static_lenb = (s.static_len+3+7) >>> 3;
9022
9023    // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
9024    //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
9025    //        s->last_lit));
9026
9027    if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
9028
9029  } else {
9030    // Assert(buf != (char*)0, "lost buf");
9031    opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
9032  }
9033
9034  if ((stored_len+4 <= opt_lenb) && (buf !== -1)) {
9035    /* 4: two words for the lengths */
9036
9037    /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
9038     * Otherwise we can't have processed more than WSIZE input bytes since
9039     * the last block flush, because compression would have been
9040     * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
9041     * transform a block into a stored block.
9042     */
9043    _tr_stored_block(s, buf, stored_len, last);
9044
9045  } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {
9046
9047    send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3);
9048    compress_block(s, static_ltree, static_dtree);
9049
9050  } else {
9051    send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3);
9052    send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1);
9053    compress_block(s, s.dyn_ltree, s.dyn_dtree);
9054  }
9055  // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
9056  /* The above check is made mod 2^32, for files larger than 512 MB
9057   * and uLong implemented on 32 bits.
9058   */
9059  init_block(s);
9060
9061  if (last) {
9062    bi_windup(s);
9063  }
9064  // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
9065  //       s->compressed_len-7*last));
9066}
9067
9068/* ===========================================================================
9069 * Save the match info and tally the frequency counts. Return true if
9070 * the current block must be flushed.
9071 */
9072function _tr_tally(s, dist, lc)
9073//    deflate_state *s;
9074//    unsigned dist;  /* distance of matched string */
9075//    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
9076{
9077  //var out_length, in_length, dcode;
9078
9079  s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;
9080  s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;
9081
9082  s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
9083  s.last_lit++;
9084
9085  if (dist === 0) {
9086    /* lc is the unmatched char */
9087    s.dyn_ltree[lc*2]/*.Freq*/++;
9088  } else {
9089    s.matches++;
9090    /* Here, lc is the match length - MIN_MATCH */
9091    dist--;             /* dist = match distance - 1 */
9092    //Assert((ush)dist < (ush)MAX_DIST(s) &&
9093    //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
9094    //       (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
9095
9096    s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++;
9097    s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
9098  }
9099
9100// (!) This block is disabled in zlib defailts,
9101// don't enable it for binary compatibility
9102
9103//#ifdef TRUNCATE_BLOCK
9104//  /* Try to guess if it is profitable to stop the current block here */
9105//  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
9106//    /* Compute an upper bound for the compressed length */
9107//    out_length = s.last_lit*8;
9108//    in_length = s.strstart - s.block_start;
9109//
9110//    for (dcode = 0; dcode < D_CODES; dcode++) {
9111//      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
9112//    }
9113//    out_length >>>= 3;
9114//    //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
9115//    //       s->last_lit, in_length, out_length,
9116//    //       100L - out_length*100L/in_length));
9117//    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
9118//      return true;
9119//    }
9120//  }
9121//#endif
9122
9123  return (s.last_lit === s.lit_bufsize-1);
9124  /* We avoid equality with lit_bufsize because of wraparound at 64K
9125   * on 16 bit machines and because stored blocks are restricted to
9126   * 64K-1 bytes.
9127   */
9128}
9129
9130exports._tr_init  = _tr_init;
9131exports._tr_stored_block = _tr_stored_block;
9132exports._tr_flush_block  = _tr_flush_block;
9133exports._tr_tally = _tr_tally;
9134exports._tr_align = _tr_align;
9135},{"../utils/common":27}],39:[function(_dereq_,module,exports){
9136'use strict';
9137
9138
9139function ZStream() {
9140  /* next input byte */
9141  this.input = null; // JS specific, because we have no pointers
9142  this.next_in = 0;
9143  /* number of bytes available at input */
9144  this.avail_in = 0;
9145  /* total number of input bytes read so far */
9146  this.total_in = 0;
9147  /* next output byte should be put there */
9148  this.output = null; // JS specific, because we have no pointers
9149  this.next_out = 0;
9150  /* remaining free space at output */
9151  this.avail_out = 0;
9152  /* total number of bytes output so far */
9153  this.total_out = 0;
9154  /* last error message, NULL if no error */
9155  this.msg = ''/*Z_NULL*/;
9156  /* not visible by applications */
9157  this.state = null;
9158  /* best guess about the data type: binary or text */
9159  this.data_type = 2/*Z_UNKNOWN*/;
9160  /* adler32 value of the uncompressed data */
9161  this.adler = 0;
9162}
9163
9164module.exports = ZStream;
9165},{}]},{},[9])
9166(9)
9167});
9168
9169/*! DataTables 1.10.18
9170 * ©2008-2018 SpryMedia Ltd - datatables.net/license
9171 */
9172
9173/**
9174 * @summary     DataTables
9175 * @description Paginate, search and order HTML tables
9176 * @version     1.10.18
9177 * @file        jquery.dataTables.js
9178 * @author      SpryMedia Ltd
9179 * @contact     www.datatables.net
9180 * @copyright   Copyright 2008-2018 SpryMedia Ltd.
9181 *
9182 * This source file is free software, available under the following license:
9183 *   MIT license - http://datatables.net/license
9184 *
9185 * This source file is distributed in the hope that it will be useful, but
9186 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9187 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
9188 *
9189 * For details please refer to: http://www.datatables.net
9190 */
9191
9192/*jslint evil: true, undef: true, browser: true */
9193/*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*/
9194
9195(function( factory ) {
9196	"use strict";
9197
9198	if ( typeof define === 'function' && define.amd ) {
9199		// AMD
9200		define( ['jquery'], function ( $ ) {
9201			return factory( $, window, document );
9202		} );
9203	}
9204	else if ( typeof exports === 'object' ) {
9205		// CommonJS
9206		module.exports = function (root, $) {
9207			if ( ! root ) {
9208				// CommonJS environments without a window global must pass a
9209				// root. This will give an error otherwise
9210				root = window;
9211			}
9212
9213			if ( ! $ ) {
9214				$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
9215					require('jquery') :
9216					require('jquery')( root );
9217			}
9218
9219			return factory( $, root, root.document );
9220		};
9221	}
9222	else {
9223		// Browser
9224		factory( jQuery, window, document );
9225	}
9226}
9227(function( $, window, document, undefined ) {
9228	"use strict";
9229
9230	/**
9231	 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
9232	 * flexible tool, based upon the foundations of progressive enhancement,
9233	 * which will add advanced interaction controls to any HTML table. For a
9234	 * full list of features please refer to
9235	 * [DataTables.net](href="http://datatables.net).
9236	 *
9237	 * Note that the `DataTable` object is not a global variable but is aliased
9238	 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
9239	 * be  accessed.
9240	 *
9241	 *  @class
9242	 *  @param {object} [init={}] Configuration object for DataTables. Options
9243	 *    are defined by {@link DataTable.defaults}
9244	 *  @requires jQuery 1.7+
9245	 *
9246	 *  @example
9247	 *    // Basic initialisation
9248	 *    $(document).ready( function {
9249	 *      $('#example').dataTable();
9250	 *    } );
9251	 *
9252	 *  @example
9253	 *    // Initialisation with configuration options - in this case, disable
9254	 *    // pagination and sorting.
9255	 *    $(document).ready( function {
9256	 *      $('#example').dataTable( {
9257	 *        "paginate": false,
9258	 *        "sort": false
9259	 *      } );
9260	 *    } );
9261	 */
9262	var DataTable = function ( options )
9263	{
vendor: 6,636 bytes, lines 9263-9422
9263
9264		/**
9265		 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
9266		 * return the resulting jQuery object.
9267		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
9268		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
9269		 *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
9270		 *    criterion ("applied") or all TR elements (i.e. no filter).
9271		 *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
9272		 *    Can be either 'current', whereby the current sorting of the table is used, or
9273		 *    'original' whereby the original order the data was read into the table is used.
9274		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
9275		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
9276		 *    'current' and filter is 'applied', regardless of what they might be given as.
9277		 *  @returns {object} jQuery object, filtered by the given selector.
9278		 *  @dtopt API
9279		 *  @deprecated Since v1.10
9280		 *
9281		 *  @example
9282		 *    $(document).ready(function() {
9283		 *      var oTable = $('#example').dataTable();
9284		 *
9285		 *      // Highlight every second row
9286		 *      oTable.$('tr:odd').css('backgroundColor', 'blue');
9287		 *    } );
9288		 *
9289		 *  @example
9290		 *    $(document).ready(function() {
9291		 *      var oTable = $('#example').dataTable();
9292		 *
9293		 *      // Filter to rows with 'Webkit' in them, add a background colour and then
9294		 *      // remove the filter, thus highlighting the 'Webkit' rows only.
9295		 *      oTable.fnFilter('Webkit');
9296		 *      oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
9297		 *      oTable.fnFilter('');
9298		 *    } );
9299		 */
9300		this.$ = function ( sSelector, oOpts )
9301		{
9302			return this.api(true).$( sSelector, oOpts );
9303		};
9304		
9305		
9306		/**
9307		 * Almost identical to $ in operation, but in this case returns the data for the matched
9308		 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
9309		 * rather than any descendants, so the data can be obtained for the row/cell. If matching
9310		 * rows are found, the data returned is the original data array/object that was used to
9311		 * create the row (or a generated array if from a DOM source).
9312		 *
9313		 * This method is often useful in-combination with $ where both functions are given the
9314		 * same parameters and the array indexes will match identically.
9315		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
9316		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
9317		 *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
9318		 *    criterion ("applied") or all elements (i.e. no filter).
9319		 *  @param {string} [oOpts.order=current] Order of the data in the processed array.
9320		 *    Can be either 'current', whereby the current sorting of the table is used, or
9321		 *    'original' whereby the original order the data was read into the table is used.
9322		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
9323		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
9324		 *    'current' and filter is 'applied', regardless of what they might be given as.
9325		 *  @returns {array} Data for the matched elements. If any elements, as a result of the
9326		 *    selector, were not TR, TD or TH elements in the DataTable, they will have a null
9327		 *    entry in the array.
9328		 *  @dtopt API
9329		 *  @deprecated Since v1.10
9330		 *
9331		 *  @example
9332		 *    $(document).ready(function() {
9333		 *      var oTable = $('#example').dataTable();
9334		 *
9335		 *      // Get the data from the first row in the table
9336		 *      var data = oTable._('tr:first');
9337		 *
9338		 *      // Do something useful with the data
9339		 *      alert( "First cell is: "+data[0] );
9340		 *    } );
9341		 *
9342		 *  @example
9343		 *    $(document).ready(function() {
9344		 *      var oTable = $('#example').dataTable();
9345		 *
9346		 *      // Filter to 'Webkit' and get all data for
9347		 *      oTable.fnFilter('Webkit');
9348		 *      var data = oTable._('tr', {"search": "applied"});
9349		 *
9350		 *      // Do something with the data
9351		 *      alert( data.length+" rows matched the search" );
9352		 *    } );
9353		 */
9354		this._ = function ( sSelector, oOpts )
9355		{
9356			return this.api(true).rows( sSelector, oOpts ).data();
9357		};
9358		
9359		
9360		/**
9361		 * Create a DataTables Api instance, with the currently selected tables for
9362		 * the Api's context.
9363		 * @param {boolean} [traditional=false] Set the API instance's context to be
9364		 *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was
9365		 *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),
9366		 *   or if all tables captured in the jQuery object should be used.
9367		 * @return {DataTables.Api}
9368		 */
9369		this.api = function ( traditional )
9370		{
9371			return traditional ?
9372				new _Api(
9373					_fnSettingsFromNode( this[ _ext.iApiIndex ] )
9374				) :
9375				new _Api( this );
9376		};
9377		
9378		
9379		/**
9380		 * Add a single new row or multiple rows of data to the table. Please note
9381		 * that this is suitable for client-side processing only - if you are using
9382		 * server-side processing (i.e. "bServerSide": true), then to add data, you
9383		 * must add it to the data source, i.e. the server-side, through an Ajax call.
9384		 *  @param {array|object} data The data to be added to the table. This can be:
9385		 *    <ul>
9386		 *      <li>1D array of data - add a single row with the data provided</li>
9387		 *      <li>2D array of arrays - add multiple rows in a single call</li>
9388		 *      <li>object - data object when using <i>mData</i></li>
9389		 *      <li>array of objects - multiple data objects when using <i>mData</i></li>
9390		 *    </ul>
9391		 *  @param {bool} [redraw=true] redraw the table or not
9392		 *  @returns {array} An array of integers, representing the list of indexes in
9393		 *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
9394		 *    the table.
9395		 *  @dtopt API
9396		 *  @deprecated Since v1.10
9397		 *
9398		 *  @example
9399		 *    // Global var for counter
9400		 *    var giCount = 2;
9401		 *
9402		 *    $(document).ready(function() {
9403		 *      $('#example').dataTable();
9404		 *    } );
9405		 *
9406		 *    function fnClickAddRow() {
9407		 *      $('#example').dataTable().fnAddData( [
9408		 *        giCount+".1",
9409		 *        giCount+".2",
9410		 *        giCount+".3",
9411		 *        giCount+".4" ]
9412		 *      );
9413		 *
9414		 *      giCount++;
9415		 *    }
9416		 */
9417		this.fnAddData = function( data, redraw )
9418		{
9419			var api = this.api( true );
9420		
9421			/* Check if we want to add multiple rows or not */
9422			var rows = 
9422$.isArray(data) && ( $
vendor: 18,409 bytes, lines 9422-10018
9422.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
9423				api.rows.add( data ) :
9424				api.row.add( data );
9425		
9426			if ( redraw === undefined || redraw ) {
9427				api.draw();
9428			}
9429		
9430			return rows.flatten().toArray();
9431		};
9432		
9433		
9434		/**
9435		 * This function will make DataTables recalculate the column sizes, based on the data
9436		 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
9437		 * through the sWidth parameter). This can be useful when the width of the table's
9438		 * parent element changes (for example a window resize).
9439		 *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
9440		 *  @dtopt API
9441		 *  @deprecated Since v1.10
9442		 *
9443		 *  @example
9444		 *    $(document).ready(function() {
9445		 *      var oTable = $('#example').dataTable( {
9446		 *        "sScrollY": "200px",
9447		 *        "bPaginate": false
9448		 *      } );
9449		 *
9450		 *      $(window).on('resize', function () {
9451		 *        oTable.fnAdjustColumnSizing();
9452		 *      } );
9453		 *    } );
9454		 */
9455		this.fnAdjustColumnSizing = function ( bRedraw )
9456		{
9457			var api = this.api( true ).columns.adjust();
9458			var settings = api.settings()[0];
9459			var scroll = settings.oScroll;
9460		
9461			if ( bRedraw === undefined || bRedraw ) {
9462				api.draw( false );
9463			}
9464			else if ( scroll.sX !== "" || scroll.sY !== "" ) {
9465				/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
9466				_fnScrollDraw( settings );
9467			}
9468		};
9469		
9470		
9471		/**
9472		 * Quickly and simply clear a table
9473		 *  @param {bool} [bRedraw=true] redraw the table or not
9474		 *  @dtopt API
9475		 *  @deprecated Since v1.10
9476		 *
9477		 *  @example
9478		 *    $(document).ready(function() {
9479		 *      var oTable = $('#example').dataTable();
9480		 *
9481		 *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
9482		 *      oTable.fnClearTable();
9483		 *    } );
9484		 */
9485		this.fnClearTable = function( bRedraw )
9486		{
9487			var api = this.api( true ).clear();
9488		
9489			if ( bRedraw === undefined || bRedraw ) {
9490				api.draw();
9491			}
9492		};
9493		
9494		
9495		/**
9496		 * The exact opposite of 'opening' a row, this function will close any rows which
9497		 * are currently 'open'.
9498		 *  @param {node} nTr the table row to 'close'
9499		 *  @returns {int} 0 on success, or 1 if failed (can't find the row)
9500		 *  @dtopt API
9501		 *  @deprecated Since v1.10
9502		 *
9503		 *  @example
9504		 *    $(document).ready(function() {
9505		 *      var oTable;
9506		 *
9507		 *      // 'open' an information row when a row is clicked on
9508		 *      $('#example tbody tr').click( function () {
9509		 *        if ( oTable.fnIsOpen(this) ) {
9510		 *          oTable.fnClose( this );
9511		 *        } else {
9512		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
9513		 *        }
9514		 *      } );
9515		 *
9516		 *      oTable = $('#example').dataTable();
9517		 *    } );
9518		 */
9519		this.fnClose = function( nTr )
9520		{
9521			this.api( true ).row( nTr ).child.hide();
9522		};
9523		
9524		
9525		/**
9526		 * Remove a row for the table
9527		 *  @param {mixed} target The index of the row from aoData to be deleted, or
9528		 *    the TR element you want to delete
9529		 *  @param {function|null} [callBack] Callback function
9530		 *  @param {bool} [redraw=true] Redraw the table or not
9531		 *  @returns {array} The row that was deleted
9532		 *  @dtopt API
9533		 *  @deprecated Since v1.10
9534		 *
9535		 *  @example
9536		 *    $(document).ready(function() {
9537		 *      var oTable = $('#example').dataTable();
9538		 *
9539		 *      // Immediately remove the first row
9540		 *      oTable.fnDeleteRow( 0 );
9541		 *    } );
9542		 */
9543		this.fnDeleteRow = function( target, callback, redraw )
9544		{
9545			var api = this.api( true );
9546			var rows = api.rows( target );
9547			var settings = rows.settings()[0];
9548			var data = settings.aoData[ rows[0][0] ];
9549		
9550			rows.remove();
9551		
9552			if ( callback ) {
9553				callback.call( this, settings, data );
9554			}
9555		
9556			if ( redraw === undefined || redraw ) {
9557				api.draw();
9558			}
9559		
9560			return data;
9561		};
9562		
9563		
9564		/**
9565		 * Restore the table to it's original state in the DOM by removing all of DataTables
9566		 * enhancements, alterations to the DOM structure of the table and event listeners.
9567		 *  @param {boolean} [remove=false] Completely remove the table from the DOM
9568		 *  @dtopt API
9569		 *  @deprecated Since v1.10
9570		 *
9571		 *  @example
9572		 *    $(document).ready(function() {
9573		 *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
9574		 *      var oTable = $('#example').dataTable();
9575		 *      oTable.fnDestroy();
9576		 *    } );
9577		 */
9578		this.fnDestroy = function ( remove )
9579		{
9580			this.api( true ).destroy( remove );
9581		};
9582		
9583		
9584		/**
9585		 * Redraw the table
9586		 *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
9587		 *  @dtopt API
9588		 *  @deprecated Since v1.10
9589		 *
9590		 *  @example
9591		 *    $(document).ready(function() {
9592		 *      var oTable = $('#example').dataTable();
9593		 *
9594		 *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
9595		 *      oTable.fnDraw();
9596		 *    } );
9597		 */
9598		this.fnDraw = function( complete )
9599		{
9600			// Note that this isn't an exact match to the old call to _fnDraw - it takes
9601			// into account the new data, but can hold position.
9602			this.api( true ).draw( complete );
9603		};
9604		
9605		
9606		/**
9607		 * Filter the input based on data
9608		 *  @param {string} sInput String to filter the table on
9609		 *  @param {int|null} [iColumn] Column to limit filtering to
9610		 *  @param {bool} [bRegex=false] Treat as regular expression or not
9611		 *  @param {bool} [bSmart=true] Perform smart filtering or not
9612		 *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
9613		 *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
9614		 *  @dtopt API
9615		 *  @deprecated Since v1.10
9616		 *
9617		 *  @example
9618		 *    $(document).ready(function() {
9619		 *      var oTable = $('#example').dataTable();
9620		 *
9621		 *      // Sometime later - filter...
9622		 *      oTable.fnFilter( 'test string' );
9623		 *    } );
9624		 */
9625		this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
9626		{
9627			var api = this.api( true );
9628		
9629			if ( iColumn === null || iColumn === undefined ) {
9630				api.search( sInput, bRegex, bSmart, bCaseInsensitive );
9631			}
9632			else {
9633				api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
9634			}
9635		
9636			api.draw();
9637		};
9638		
9639		
9640		/**
9641		 * Get the data for the whole table, an individual row or an individual cell based on the
9642		 * provided parameters.
9643		 *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
9644		 *    a TR node then the data source for the whole row will be returned. If given as a
9645		 *    TD/TH cell node then iCol will be automatically calculated and the data for the
9646		 *    cell returned. If given as an integer, then this is treated as the aoData internal
9647		 *    data index for the row (see fnGetPosition) and the data for that row used.
9648		 *  @param {int} [col] Optional column index that you want the data of.
9649		 *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
9650		 *    returned. If mRow is defined, just data for that row, and is iCol is
9651		 *    defined, only data for the designated cell is returned.
9652		 *  @dtopt API
9653		 *  @deprecated Since v1.10
9654		 *
9655		 *  @example
9656		 *    // Row data
9657		 *    $(document).ready(function() {
9658		 *      oTable = $('#example').dataTable();
9659		 *
9660		 *      oTable.$('tr').click( function () {
9661		 *        var data = oTable.fnGetData( this );
9662		 *        // ... do something with the array / object of data for the row
9663		 *      } );
9664		 *    } );
9665		 *
9666		 *  @example
9667		 *    // Individual cell data
9668		 *    $(document).ready(function() {
9669		 *      oTable = $('#example').dataTable();
9670		 *
9671		 *      oTable.$('td').click( function () {
9672		 *        var sData = oTable.fnGetData( this );
9673		 *        alert( 'The cell clicked on had the value of '+sData );
9674		 *      } );
9675		 *    } );
9676		 */
9677		this.fnGetData = function( src, col )
9678		{
9679			var api = this.api( true );
9680		
9681			if ( src !== undefined ) {
9682				var type = src.nodeName ? src.nodeName.toLowerCase() : '';
9683		
9684				return col !== undefined || type == 'td' || type == 'th' ?
9685					api.cell( src, col ).data() :
9686					api.row( src ).data() || null;
9687			}
9688		
9689			return api.data().toArray();
9690		};
9691		
9692		
9693		/**
9694		 * Get an array of the TR nodes that are used in the table's body. Note that you will
9695		 * typically want to use the '$' API method in preference to this as it is more
9696		 * flexible.
9697		 *  @param {int} [iRow] Optional row index for the TR element you want
9698		 *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
9699		 *    in the table's body, or iRow is defined, just the TR element requested.
9700		 *  @dtopt API
9701		 *  @deprecated Since v1.10
9702		 *
9703		 *  @example
9704		 *    $(document).ready(function() {
9705		 *      var oTable = $('#example').dataTable();
9706		 *
9707		 *      // Get the nodes from the table
9708		 *      var nNodes = oTable.fnGetNodes( );
9709		 *    } );
9710		 */
9711		this.fnGetNodes = function( iRow )
9712		{
9713			var api = this.api( true );
9714		
9715			return iRow !== undefined ?
9716				api.row( iRow ).node() :
9717				api.rows().nodes().flatten().toArray();
9718		};
9719		
9720		
9721		/**
9722		 * Get the array indexes of a particular cell from it's DOM element
9723		 * and column index including hidden columns
9724		 *  @param {node} node this can either be a TR, TD or TH in the table's body
9725		 *  @returns {int} If nNode is given as a TR, then a single index is returned, or
9726		 *    if given as a cell, an array of [row index, column index (visible),
9727		 *    column index (all)] is given.
9728		 *  @dtopt API
9729		 *  @deprecated Since v1.10
9730		 *
9731		 *  @example
9732		 *    $(document).ready(function() {
9733		 *      $('#example tbody td').click( function () {
9734		 *        // Get the position of the current data from the node
9735		 *        var aPos = oTable.fnGetPosition( this );
9736		 *
9737		 *        // Get the data array for this row
9738		 *        var aData = oTable.fnGetData( aPos[0] );
9739		 *
9740		 *        // Update the data array and return the value
9741		 *        aData[ aPos[1] ] = 'clicked';
9742		 *        this.innerHTML = 'clicked';
9743		 *      } );
9744		 *
9745		 *      // Init DataTables
9746		 *      oTable = $('#example').dataTable();
9747		 *    } );
9748		 */
9749		this.fnGetPosition = function( node )
9750		{
9751			var api = this.api( true );
9752			var nodeName = node.nodeName.toUpperCase();
9753		
9754			if ( nodeName == 'TR' ) {
9755				return api.row( node ).index();
9756			}
9757			else if ( nodeName == 'TD' || nodeName == 'TH' ) {
9758				var cell = api.cell( node ).index();
9759		
9760				return [
9761					cell.row,
9762					cell.columnVisible,
9763					cell.column
9764				];
9765			}
9766			return null;
9767		};
9768		
9769		
9770		/**
9771		 * Check to see if a row is 'open' or not.
9772		 *  @param {node} nTr the table row to check
9773		 *  @returns {boolean} true if the row is currently open, false otherwise
9774		 *  @dtopt API
9775		 *  @deprecated Since v1.10
9776		 *
9777		 *  @example
9778		 *    $(document).ready(function() {
9779		 *      var oTable;
9780		 *
9781		 *      // 'open' an information row when a row is clicked on
9782		 *      $('#example tbody tr').click( function () {
9783		 *        if ( oTable.fnIsOpen(this) ) {
9784		 *          oTable.fnClose( this );
9785		 *        } else {
9786		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
9787		 *        }
9788		 *      } );
9789		 *
9790		 *      oTable = $('#example').dataTable();
9791		 *    } );
9792		 */
9793		this.fnIsOpen = function( nTr )
9794		{
9795			return this.api( true ).row( nTr ).child.isShown();
9796		};
9797		
9798		
9799		/**
9800		 * This function will place a new row directly after a row which is currently
9801		 * on display on the page, with the HTML contents that is passed into the
9802		 * function. This can be used, for example, to ask for confirmation that a
9803		 * particular record should be deleted.
9804		 *  @param {node} nTr The table row to 'open'
9805		 *  @param {string|node|jQuery} mHtml The HTML to put into the row
9806		 *  @param {string} sClass Class to give the new TD cell
9807		 *  @returns {node} The row opened. Note that if the table row passed in as the
9808		 *    first parameter, is not found in the table, this method will silently
9809		 *    return.
9810		 *  @dtopt API
9811		 *  @deprecated Since v1.10
9812		 *
9813		 *  @example
9814		 *    $(document).ready(function() {
9815		 *      var oTable;
9816		 *
9817		 *      // 'open' an information row when a row is clicked on
9818		 *      $('#example tbody tr').click( function () {
9819		 *        if ( oTable.fnIsOpen(this) ) {
9820		 *          oTable.fnClose( this );
9821		 *        } else {
9822		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
9823		 *        }
9824		 *      } );
9825		 *
9826		 *      oTable = $('#example').dataTable();
9827		 *    } );
9828		 */
9829		this.fnOpen = function( nTr, mHtml, sClass )
9830		{
9831			return this.api( true )
9832				.row( nTr )
9833				.child( mHtml, sClass )
9834				.show()
9835				.child()[0];
9836		};
9837		
9838		
9839		/**
9840		 * Change the pagination - provides the internal logic for pagination in a simple API
9841		 * function. With this function you can have a DataTables table go to the next,
9842		 * previous, first or last pages.
9843		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
9844		 *    or page number to jump to (integer), note that page 0 is the first page.
9845		 *  @param {bool} [bRedraw=true] Redraw the table or not
9846		 *  @dtopt API
9847		 *  @deprecated Since v1.10
9848		 *
9849		 *  @example
9850		 *    $(document).ready(function() {
9851		 *      var oTable = $('#example').dataTable();
9852		 *      oTable.fnPageChange( 'next' );
9853		 *    } );
9854		 */
9855		this.fnPageChange = function ( mAction, bRedraw )
9856		{
9857			var api = this.api( true ).page( mAction );
9858		
9859			if ( bRedraw === undefined || bRedraw ) {
9860				api.draw(false);
9861			}
9862		};
9863		
9864		
9865		/**
9866		 * Show a particular column
9867		 *  @param {int} iCol The column whose display should be changed
9868		 *  @param {bool} bShow Show (true) or hide (false) the column
9869		 *  @param {bool} [bRedraw=true] Redraw the table or not
9870		 *  @dtopt API
9871		 *  @deprecated Since v1.10
9872		 *
9873		 *  @example
9874		 *    $(document).ready(function() {
9875		 *      var oTable = $('#example').dataTable();
9876		 *
9877		 *      // Hide the second column after initialisation
9878		 *      oTable.fnSetColumnVis( 1, false );
9879		 *    } );
9880		 */
9881		this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
9882		{
9883			var api = this.api( true ).column( iCol ).visible( bShow );
9884		
9885			if ( bRedraw === undefined || bRedraw ) {
9886				api.columns.adjust().draw();
9887			}
9888		};
9889		
9890		
9891		/**
9892		 * Get the settings for a particular table for external manipulation
9893		 *  @returns {object} DataTables settings object. See
9894		 *    {@link DataTable.models.oSettings}
9895		 *  @dtopt API
9896		 *  @deprecated Since v1.10
9897		 *
9898		 *  @example
9899		 *    $(document).ready(function() {
9900		 *      var oTable = $('#example').dataTable();
9901		 *      var oSettings = oTable.fnSettings();
9902		 *
9903		 *      // Show an example parameter from the settings
9904		 *      alert( oSettings._iDisplayStart );
9905		 *    } );
9906		 */
9907		this.fnSettings = function()
9908		{
9909			return _fnSettingsFromNode( this[_ext.iApiIndex] );
9910		};
9911		
9912		
9913		/**
9914		 * Sort the table by a particular column
9915		 *  @param {int} iCol the data index to sort on. Note that this will not match the
9916		 *    'display index' if you have hidden data entries
9917		 *  @dtopt API
9918		 *  @deprecated Since v1.10
9919		 *
9920		 *  @example
9921		 *    $(document).ready(function() {
9922		 *      var oTable = $('#example').dataTable();
9923		 *
9924		 *      // Sort immediately with columns 0 and 1
9925		 *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
9926		 *    } );
9927		 */
9928		this.fnSort = function( aaSort )
9929		{
9930			this.api( true ).order( aaSort ).draw();
9931		};
9932		
9933		
9934		/**
9935		 * Attach a sort listener to an element for a given column
9936		 *  @param {node} nNode the element to attach the sort listener to
9937		 *  @param {int} iColumn the column that a click on this node will sort on
9938		 *  @param {function} [fnCallback] callback function when sort is run
9939		 *  @dtopt API
9940		 *  @deprecated Since v1.10
9941		 *
9942		 *  @example
9943		 *    $(document).ready(function() {
9944		 *      var oTable = $('#example').dataTable();
9945		 *
9946		 *      // Sort on column 1, when 'sorter' is clicked on
9947		 *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
9948		 *    } );
9949		 */
9950		this.fnSortListener = function( nNode, iColumn, fnCallback )
9951		{
9952			this.api( true ).order.listener( nNode, iColumn, fnCallback );
9953		};
9954		
9955		
9956		/**
9957		 * Update a table cell or row - this method will accept either a single value to
9958		 * update the cell with, an array of values with one element for each column or
9959		 * an object in the same format as the original data source. The function is
9960		 * self-referencing in order to make the multi column updates easier.
9961		 *  @param {object|array|string} mData Data to update the cell/row with
9962		 *  @param {node|int} mRow TR element you want to update or the aoData index
9963		 *  @param {int} [iColumn] The column to update, give as null or undefined to
9964		 *    update a whole row.
9965		 *  @param {bool} [bRedraw=true] Redraw the table or not
9966		 *  @param {bool} [bAction=true] Perform pre-draw actions or not
9967		 *  @returns {int} 0 on success, 1 on error
9968		 *  @dtopt API
9969		 *  @deprecated Since v1.10
9970		 *
9971		 *  @example
9972		 *    $(document).ready(function() {
9973		 *      var oTable = $('#example').dataTable();
9974		 *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
9975		 *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
9976		 *    } );
9977		 */
9978		this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
9979		{
9980			var api = this.api( true );
9981		
9982			if ( iColumn === undefined || iColumn === null ) {
9983				api.row( mRow ).data( mData );
9984			}
9985			else {
9986				api.cell( mRow, iColumn ).data( mData );
9987			}
9988		
9989			if ( bAction === undefined || bAction ) {
9990				api.columns.adjust();
9991			}
9992		
9993			if ( bRedraw === undefined || bRedraw ) {
9994				api.draw();
9995			}
9996			return 0;
9997		};
9998		
9999		
10000		/**
10001		 * Provide a common method for plug-ins to check the version of DataTables being used, in order
10002		 * to ensure compatibility.
10003		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
10004		 *    formats "X" and "X.Y" are also acceptable.
10005		 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
10006		 *    version, or false if this version of DataTales is not suitable
10007		 *  @method
10008		 *  @dtopt API
10009		 *  @deprecated Since v1.10
10010		 *
10011		 *  @example
10012		 *    $(document).ready(function() {
10013		 *      var oTable = $('#example').dataTable();
10014		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
10015		 *    } );
10016		 */
10017		this.fnVersionCheck = _ext.fnVersionCheck;
10018		
vendor: 57,803 bytes, lines 10019-12039
10019
10020		var _that = this;
10021		var emptyInit = options === undefined;
10022		var len = this.length;
10023
10024		if ( emptyInit ) {
10025			options = {};
10026		}
10027
10028		this.oApi = this.internal = _ext.internal;
10029
10030		// Extend with old style plug-in API methods
10031		for ( var fn in DataTable.ext.internal ) {
10032			if ( fn ) {
10033				this[fn] = _fnExternApiFunc(fn);
10034			}
10035		}
10036
10037		this.each(function() {
10038			// For each initialisation we want to give it a clean initialisation
10039			// object that can be bashed around
10040			var o = {};
10041			var oInit = len > 1 ? // optimisation for single table case
10042				_fnExtend( o, options, true ) :
10043				options;
10044
10045			/*global oInit,_that,emptyInit*/
10046			var i=0, iLen, j, jLen, k, kLen;
10047			var sId = this.getAttribute( 'id' );
10048			var bInitHandedOff = false;
10049			var defaults = DataTable.defaults;
10050			var $this = $(this);
10051			
10052			
10053			/* Sanity check */
10054			if ( this.nodeName.toLowerCase() != 'table' )
10055			{
10056				_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
10057				return;
10058			}
10059			
10060			/* Backwards compatibility for the defaults */
10061			_fnCompatOpts( defaults );
10062			_fnCompatCols( defaults.column );
10063			
10064			/* Convert the camel-case defaults to Hungarian */
10065			_fnCamelToHungarian( defaults, defaults, true );
10066			_fnCamelToHungarian( defaults.column, defaults.column, true );
10067			
10068			/* Setting up the initialisation object */
10069			_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
10070			
10071			
10072			
10073			/* Check to see if we are re-initialising a table */
10074			var allSettings = DataTable.settings;
10075			for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
10076			{
10077				var s = allSettings[i];
10078			
10079				/* Base check on table node */
10080				if (
10081					s.nTable == this ||
10082					(s.nTHead && s.nTHead.parentNode == this) ||
10083					(s.nTFoot && s.nTFoot.parentNode == this)
10084				) {
10085					var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
10086					var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
10087			
10088					if ( emptyInit || bRetrieve )
10089					{
10090						return s.oInstance;
10091					}
10092					else if ( bDestroy )
10093					{
10094						s.oInstance.fnDestroy();
10095						break;
10096					}
10097					else
10098					{
10099						_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
10100						return;
10101					}
10102				}
10103			
10104				/* If the element we are initialising has the same ID as a table which was previously
10105				 * initialised, but the table nodes don't match (from before) then we destroy the old
10106				 * instance by simply deleting it. This is under the assumption that the table has been
10107				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
10108				 */
10109				if ( s.sTableId == this.id )
10110				{
10111					allSettings.splice( i, 1 );
10112					break;
10113				}
10114			}
10115			
10116			/* Ensure the table has an ID - required for accessibility */
10117			if ( sId === null || sId === "" )
10118			{
10119				sId = "DataTables_Table_"+(DataTable.ext._unique++);
10120				this.id = sId;
10121			}
10122			
10123			/* Create the settings object for this table and set some of the default parameters */
10124			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
10125				"sDestroyWidth": $this[0].style.width,
10126				"sInstance":     sId,
10127				"sTableId":      sId
10128			} );
10129			oSettings.nTable = this;
10130			oSettings.oApi   = _that.internal;
10131			oSettings.oInit  = oInit;
10132			
10133			allSettings.push( oSettings );
10134			
10135			// Need to add the instance after the instance after the settings object has been added
10136			// to the settings array, so we can self reference the table instance if more than one
10137			oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
10138			
10139			// Backwards compatibility, before we apply all the defaults
10140			_fnCompatOpts( oInit );
10141			_fnLanguageCompat( oInit.oLanguage );
10142			
10143			// If the length menu is given, but the init display length is not, use the length menu
10144			if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
10145			{
10146				oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
10147					oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
10148			}
10149			
10150			// Apply the defaults and init options to make a single init object will all
10151			// options defined from defaults and instance options.
10152			oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
10153			
10154			
10155			// Map the initialisation options onto the settings object
10156			_fnMap( oSettings.oFeatures, oInit, [
10157				"bPaginate",
10158				"bLengthChange",
10159				"bFilter",
10160				"bSort",
10161				"bSortMulti",
10162				"bInfo",
10163				"bProcessing",
10164				"bAutoWidth",
10165				"bSortClasses",
10166				"bServerSide",
10167				"bDeferRender"
10168			] );
10169			_fnMap( oSettings, oInit, [
10170				"asStripeClasses",
10171				"ajax",
10172				"fnServerData",
10173				"fnFormatNumber",
10174				"sServerMethod",
10175				"aaSorting",
10176				"aaSortingFixed",
10177				"aLengthMenu",
10178				"sPaginationType",
10179				"sAjaxSource",
10180				"sAjaxDataProp",
10181				"iStateDuration",
10182				"sDom",
10183				"bSortCellsTop",
10184				"iTabIndex",
10185				"fnStateLoadCallback",
10186				"fnStateSaveCallback",
10187				"renderer",
10188				"searchDelay",
10189				"rowId",
10190				[ "iCookieDuration", "iStateDuration" ], // backwards compat
10191				[ "oSearch", "oPreviousSearch" ],
10192				[ "aoSearchCols", "aoPreSearchCols" ],
10193				[ "iDisplayLength", "_iDisplayLength" ]
10194			] );
10195			_fnMap( oSettings.oScroll, oInit, [
10196				[ "sScrollX", "sX" ],
10197				[ "sScrollXInner", "sXInner" ],
10198				[ "sScrollY", "sY" ],
10199				[ "bScrollCollapse", "bCollapse" ]
10200			] );
10201			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
10202			
10203			/* Callback functions which are array driven */
10204			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
10205			_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
10206			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
10207			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
10208			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
10209			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
10210			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
10211			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
10212			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
10213			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
10214			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
10215			
10216			oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
10217			
10218			/* Browser support detection */
10219			_fnBrowserDetect( oSettings );
10220			
10221			var oClasses = oSettings.oClasses;
10222			
10223			$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
10224			$this.addClass( oClasses.sTable );
10225			
10226			
10227			if ( oSettings.iInitDisplayStart === undefined )
10228			{
10229				/* Display start point, taking into account the save saving */
10230				oSettings.iInitDisplayStart = oInit.iDisplayStart;
10231				oSettings._iDisplayStart = oInit.iDisplayStart;
10232			}
10233			
10234			if ( oInit.iDeferLoading !== null )
10235			{
10236				oSettings.bDeferLoading = true;
10237				var tmp = $.isArray( oInit.iDeferLoading );
10238				oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
10239				oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
10240			}
10241			
10242			/* Language definitions */
10243			var oLanguage = oSettings.oLanguage;
10244			$.extend( true, oLanguage, oInit.oLanguage );
10245			
10246			if ( oLanguage.sUrl )
10247			{
10248				/* Get the language definitions from a file - because this Ajax call makes the language
10249				 * get async to the remainder of this function we use bInitHandedOff to indicate that
10250				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
10251				 */
10252				$.ajax( {
10253					dataType: 'json',
10254					url: oLanguage.sUrl,
10255					success: function ( json ) {
10256						_fnLanguageCompat( json );
10257						_fnCamelToHungarian( defaults.oLanguage, json );
10258						$.extend( true, oLanguage, json );
10259						_fnInitialise( oSettings );
10260					},
10261					error: function () {
10262						// Error occurred loading language file, continue on as best we can
10263						_fnInitialise( oSettings );
10264					}
10265				} );
10266				bInitHandedOff = true;
10267			}
10268			
10269			/*
10270			 * Stripes
10271			 */
10272			if ( oInit.asStripeClasses === null )
10273			{
10274				oSettings.asStripeClasses =[
10275					oClasses.sStripeOdd,
10276					oClasses.sStripeEven
10277				];
10278			}
10279			
10280			/* Remove row stripe classes if they are already on the table row */
10281			var stripeClasses = oSettings.asStripeClasses;
10282			var rowOne = $this.children('tbody').find('tr').eq(0);
10283			if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
10284				return rowOne.hasClass(el);
10285			} ) ) !== -1 ) {
10286				$('tbody tr', this).removeClass( stripeClasses.join(' ') );
10287				oSettings.asDestroyStripes = stripeClasses.slice();
10288			}
10289			
10290			/*
10291			 * Columns
10292			 * See if we should load columns automatically or use defined ones
10293			 */
10294			var anThs = [];
10295			var aoColumnsInit;
10296			var nThead = this.getElementsByTagName('thead');
10297			if ( nThead.length !== 0 )
10298			{
10299				_fnDetectHeader( oSettings.aoHeader, nThead[0] );
10300				anThs = _fnGetUniqueThs( oSettings );
10301			}
10302			
10303			/* If not given a column array, generate one with nulls */
10304			if ( oInit.aoColumns === null )
10305			{
10306				aoColumnsInit = [];
10307				for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
10308				{
10309					aoColumnsInit.push( null );
10310				}
10311			}
10312			else
10313			{
10314				aoColumnsInit = oInit.aoColumns;
10315			}
10316			
10317			/* Add the columns */
10318			for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
10319			{
10320				_fnAddColumn( oSettings, anThs ? anThs[i] : null );
10321			}
10322			
10323			/* Apply the column definitions */
10324			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
10325				_fnColumnOptions( oSettings, iCol, oDef );
10326			} );
10327			
10328			/* HTML5 attribute detection - build an mData object automatically if the
10329			 * attributes are found
10330			 */
10331			if ( rowOne.length ) {
10332				var a = function ( cell, name ) {
10333					return cell.getAttribute( 'data-'+name ) !== null ? name : null;
10334				};
10335			
10336				$( rowOne[0] ).children('th, td').each( function (i, cell) {
10337					var col = oSettings.aoColumns[i];
10338			
10339					if ( col.mData === i ) {
10340						var sort = a( cell, 'sort' ) || a( cell, 'order' );
10341						var filter = a( cell, 'filter' ) || a( cell, 'search' );
10342			
10343						if ( sort !== null || filter !== null ) {
10344							col.mData = {
10345								_:      i+'.display',
10346								sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
10347								type:   sort !== null   ? i+'.@data-'+sort   : undefined,
10348								filter: filter !== null ? i+'.@data-'+filter : undefined
10349							};
10350			
10351							_fnColumnOptions( oSettings, i );
10352						}
10353					}
10354				} );
10355			}
10356			
10357			var features = oSettings.oFeatures;
10358			var loadedInit = function () {
10359				/*
10360				 * Sorting
10361				 * @todo For modularisation (1.11) this needs to do into a sort start up handler
10362				 */
10363			
10364				// If aaSorting is not defined, then we use the first indicator in asSorting
10365				// in case that has been altered, so the default sort reflects that option
10366				if ( oInit.aaSorting === undefined ) {
10367					var sorting = oSettings.aaSorting;
10368					for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
10369						sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
10370					}
10371				}
10372			
10373				/* Do a first pass on the sorting classes (allows any size changes to be taken into
10374				 * account, and also will apply sorting disabled classes if disabled
10375				 */
10376				_fnSortingClasses( oSettings );
10377			
10378				if ( features.bSort ) {
10379					_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
10380						if ( oSettings.bSorted ) {
10381							var aSort = _fnSortFlatten( oSettings );
10382							var sortedColumns = {};
10383			
10384							$.each( aSort, function (i, val) {
10385								sortedColumns[ val.src ] = val.dir;
10386							} );
10387			
10388							_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
10389							_fnSortAria( oSettings );
10390						}
10391					} );
10392				}
10393			
10394				_fnCallbackReg( oSettings, 'aoDrawCallback', function () {
10395					if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
10396						_fnSortingClasses( oSettings );
10397					}
10398				}, 'sc' );
10399			
10400			
10401				/*
10402				 * Final init
10403				 * Cache the header, body and footer as required, creating them if needed
10404				 */
10405			
10406				// Work around for Webkit bug 83867 - store the caption-side before removing from doc
10407				var captions = $this.children('caption').each( function () {
10408					this._captionSide = $(this).css('caption-side');
10409				} );
10410			
10411				var thead = $this.children('thead');
10412				if ( thead.length === 0 ) {
10413					thead = $('<thead/>').appendTo($this);
10414				}
10415				oSettings.nTHead = thead[0];
10416			
10417				var tbody = $this.children('tbody');
10418				if ( tbody.length === 0 ) {
10419					tbody = $('<tbody/>').appendTo($this);
10420				}
10421				oSettings.nTBody = tbody[0];
10422			
10423				var tfoot = $this.children('tfoot');
10424				if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
10425					// If we are a scrolling table, and no footer has been given, then we need to create
10426					// a tfoot element for the caption element to be appended to
10427					tfoot = $('<tfoot/>').appendTo($this);
10428				}
10429			
10430				if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
10431					$this.addClass( oClasses.sNoFooter );
10432				}
10433				else if ( tfoot.length > 0 ) {
10434					oSettings.nTFoot = tfoot[0];
10435					_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
10436				}
10437			
10438				/* Check if there is data passing into the constructor */
10439				if ( oInit.aaData ) {
10440					for ( i=0 ; i<oInit.aaData.length ; i++ ) {
10441						_fnAddData( oSettings, oInit.aaData[ i ] );
10442					}
10443				}
10444				else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
10445					/* Grab the data from the page - only do this when deferred loading or no Ajax
10446					 * source since there is no point in reading the DOM data if we are then going
10447					 * to replace it with Ajax data
10448					 */
10449					_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
10450				}
10451			
10452				/* Copy the data index array */
10453				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
10454			
10455				/* Initialisation complete - table can be drawn */
10456				oSettings.bInitialised = true;
10457			
10458				/* Check if we need to initialise the table (it might not have been handed off to the
10459				 * language processor)
10460				 */
10461				if ( bInitHandedOff === false ) {
10462					_fnInitialise( oSettings );
10463				}
10464			};
10465			
10466			/* Must be done after everything which can be overridden by the state saving! */
10467			if ( oInit.bStateSave )
10468			{
10469				features.bStateSave = true;
10470				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
10471				_fnLoadState( oSettings, oInit, loadedInit );
10472			}
10473			else {
10474				loadedInit();
10475			}
10476			
10477		} );
10478		_that = null;
10479		return this;
10480	};
10481
10482	
10483	/*
10484	 * It is useful to have variables which are scoped locally so only the
10485	 * DataTables functions can access them and they don't leak into global space.
10486	 * At the same time these functions are often useful over multiple files in the
10487	 * core and API, so we list, or at least document, all variables which are used
10488	 * by DataTables as private variables here. This also ensures that there is no
10489	 * clashing of variable names and that they can easily referenced for reuse.
10490	 */
10491	
10492	
10493	// Defined else where
10494	//  _selector_run
10495	//  _selector_opts
10496	//  _selector_first
10497	//  _selector_row_indexes
10498	
10499	var _ext; // DataTable.ext
10500	var _Api; // DataTable.Api
10501	var _api_register; // DataTable.Api.register
10502	var _api_registerPlural; // DataTable.Api.registerPlural
10503	
10504	var _re_dic = {};
10505	var _re_new_lines = /[\r\n]/g;
10506	var _re_html = /<.*?>/g;
10507	
10508	// This is not strict ISO8601 - Date.parse() is quite lax, although
10509	// implementations differ between browsers.
10510	var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
10511	
10512	// Escape regular expression special characters
10513	var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
10514	
10515	// http://en.wikipedia.org/wiki/Foreign_exchange_market
10516	// - \u20BD - Russian ruble.
10517	// - \u20a9 - South Korean Won
10518	// - \u20BA - Turkish Lira
10519	// - \u20B9 - Indian Rupee
10520	// - R - Brazil (R$) and South Africa
10521	// - fr - Swiss Franc
10522	// - kr - Swedish krona, Norwegian krone and Danish krone
10523	// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
10524	// - Ƀ - Bitcoin
10525	// - Ξ - Ethereum
10526	//   standards as thousands separators.
10527	var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
10528	
10529	
10530	var _empty = function ( d ) {
10531		return !d || d === true || d === '-' ? true : false;
10532	};
10533	
10534	
10535	var _intVal = function ( s ) {
10536		var integer = parseInt( s, 10 );
10537		return !isNaN(integer) && isFinite(s) ? integer : null;
10538	};
10539	
10540	// Convert from a formatted number with characters other than `.` as the
10541	// decimal place, to a Javascript number
10542	var _numToDecimal = function ( num, decimalPoint ) {
10543		// Cache created regular expressions for speed as this function is called often
10544		if ( ! _re_dic[ decimalPoint ] ) {
10545			_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
10546		}
10547		return typeof num === 'string' && decimalPoint !== '.' ?
10548			num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
10549			num;
10550	};
10551	
10552	
10553	var _isNumber = function ( d, decimalPoint, formatted ) {
10554		var strType = typeof d === 'string';
10555	
10556		// If empty return immediately so there must be a number if it is a
10557		// formatted string (this stops the string "k", or "kr", etc being detected
10558		// as a formatted number for currency
10559		if ( _empty( d ) ) {
10560			return true;
10561		}
10562	
10563		if ( decimalPoint && strType ) {
10564			d = _numToDecimal( d, decimalPoint );
10565		}
10566	
10567		if ( formatted && strType ) {
10568			d = d.replace( _re_formatted_numeric, '' );
10569		}
10570	
10571		return !isNaN( parseFloat(d) ) && isFinite( d );
10572	};
10573	
10574	
10575	// A string without HTML in it can be considered to be HTML still
10576	var _isHtml = function ( d ) {
10577		return _empty( d ) || typeof d === 'string';
10578	};
10579	
10580	
10581	var _htmlNumeric = function ( d, decimalPoint, formatted ) {
10582		if ( _empty( d ) ) {
10583			return true;
10584		}
10585	
10586		var html = _isHtml( d );
10587		return ! html ?
10588			null :
10589			_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
10590				true :
10591				null;
10592	};
10593	
10594	
10595	var _pluck = function ( a, prop, prop2 ) {
10596		var out = [];
10597		var i=0, ien=a.length;
10598	
10599		// Could have the test in the loop for slightly smaller code, but speed
10600		// is essential here
10601		if ( prop2 !== undefined ) {
10602			for ( ; i<ien ; i++ ) {
10603				if ( a[i] && a[i][ prop ] ) {
10604					out.push( a[i][ prop ][ prop2 ] );
10605				}
10606			}
10607		}
10608		else {
10609			for ( ; i<ien ; i++ ) {
10610				if ( a[i] ) {
10611					out.push( a[i][ prop ] );
10612				}
10613			}
10614		}
10615	
10616		return out;
10617	};
10618	
10619	
10620	// Basically the same as _pluck, but rather than looping over `a` we use `order`
10621	// as the indexes to pick from `a`
10622	var _pluck_order = function ( a, order, prop, prop2 )
10623	{
10624		var out = [];
10625		var i=0, ien=order.length;
10626	
10627		// Could have the test in the loop for slightly smaller code, but speed
10628		// is essential here
10629		if ( prop2 !== undefined ) {
10630			for ( ; i<ien ; i++ ) {
10631				if ( a[ order[i] ][ prop ] ) {
10632					out.push( a[ order[i] ][ prop ][ prop2 ] );
10633				}
10634			}
10635		}
10636		else {
10637			for ( ; i<ien ; i++ ) {
10638				out.push( a[ order[i] ][ prop ] );
10639			}
10640		}
10641	
10642		return out;
10643	};
10644	
10645	
10646	var _range = function ( len, start )
10647	{
10648		var out = [];
10649		var end;
10650	
10651		if ( start === undefined ) {
10652			start = 0;
10653			end = len;
10654		}
10655		else {
10656			end = start;
10657			start = len;
10658		}
10659	
10660		for ( var i=start ; i<end ; i++ ) {
10661			out.push( i );
10662		}
10663	
10664		return out;
10665	};
10666	
10667	
10668	var _removeEmpty = function ( a )
10669	{
10670		var out = [];
10671	
10672		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
10673			if ( a[i] ) { // careful - will remove all falsy values!
10674				out.push( a[i] );
10675			}
10676		}
10677	
10678		return out;
10679	};
10680	
10681	
10682	var _stripHtml = function ( d ) {
10683		return d.replace( _re_html, '' );
10684	};
10685	
10686	
10687	/**
10688	 * Determine if all values in the array are unique. This means we can short
10689	 * cut the _unique method at the cost of a single loop. A sorted array is used
10690	 * to easily check the values.
10691	 *
10692	 * @param  {array} src Source array
10693	 * @return {boolean} true if all unique, false otherwise
10694	 * @ignore
10695	 */
10696	var _areAllUnique = function ( src ) {
10697		if ( src.length < 2 ) {
10698			return true;
10699		}
10700	
10701		var sorted = src.slice().sort();
10702		var last = sorted[0];
10703	
10704		for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
10705			if ( sorted[i] === last ) {
10706				return false;
10707			}
10708	
10709			last = sorted[i];
10710		}
10711	
10712		return true;
10713	};
10714	
10715	
10716	/**
10717	 * Find the unique elements in a source array.
10718	 *
10719	 * @param  {array} src Source array
10720	 * @return {array} Array of unique items
10721	 * @ignore
10722	 */
10723	var _unique = function ( src )
10724	{
10725		if ( _areAllUnique( src ) ) {
10726			return src.slice();
10727		}
10728	
10729		// A faster unique method is to use object keys to identify used values,
10730		// but this doesn't work with arrays or objects, which we must also
10731		// consider. See jsperf.com/compare-array-unique-versions/4 for more
10732		// information.
10733		var
10734			out = [],
10735			val,
10736			i, ien=src.length,
10737			j, k=0;
10738	
10739		again: for ( i=0 ; i<ien ; i++ ) {
10740			val = src[i];
10741	
10742			for ( j=0 ; j<k ; j++ ) {
10743				if ( out[j] === val ) {
10744					continue again;
10745				}
10746			}
10747	
10748			out.push( val );
10749			k++;
10750		}
10751	
10752		return out;
10753	};
10754	
10755	
10756	/**
10757	 * DataTables utility methods
10758	 * 
10759	 * This namespace provides helper methods that DataTables uses internally to
10760	 * create a DataTable, but which are not exclusively used only for DataTables.
10761	 * These methods can be used by extension authors to save the duplication of
10762	 * code.
10763	 *
10764	 *  @namespace
10765	 */
10766	DataTable.util = {
10767		/**
10768		 * Throttle the calls to a function. Arguments and context are maintained
10769		 * for the throttled function.
10770		 *
10771		 * @param {function} fn Function to be called
10772		 * @param {integer} freq Call frequency in mS
10773		 * @return {function} Wrapped function
10774		 */
10775		throttle: function ( fn, freq ) {
10776			var
10777				frequency = freq !== undefined ? freq : 200,
10778				last,
10779				timer;
10780	
10781			return function () {
10782				var
10783					that = this,
10784					now  = +new Date(),
10785					args = arguments;
10786	
10787				if ( last && now < last + frequency ) {
10788					clearTimeout( timer );
10789	
10790					timer = setTimeout( function () {
10791						last = undefined;
10792						fn.apply( that, args );
10793					}, frequency );
10794				}
10795				else {
10796					last = now;
10797					fn.apply( that, args );
10798				}
10799			};
10800		},
10801	
10802	
10803		/**
10804		 * Escape a string such that it can be used in a regular expression
10805		 *
10806		 *  @param {string} val string to escape
10807		 *  @returns {string} escaped string
10808		 */
10809		escapeRegex: function ( val ) {
10810			return val.replace( _re_escape_regex, '\\$1' );
10811		}
10812	};
10813	
10814	
10815	
10816	/**
10817	 * Create a mapping object that allows camel case parameters to be looked up
10818	 * for their Hungarian counterparts. The mapping is stored in a private
10819	 * parameter called `_hungarianMap` which can be accessed on the source object.
10820	 *  @param {object} o
10821	 *  @memberof DataTable#oApi
10822	 */
10823	function _fnHungarianMap ( o )
10824	{
10825		var
10826			hungarian = 'a aa ai ao as b fn i m o s ',
10827			match,
10828			newKey,
10829			map = {};
10830	
10831		$.each( o, function (key, val) {
10832			match = key.match(/^([^A-Z]+?)([A-Z])/);
10833	
10834			if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
10835			{
10836				newKey = key.replace( match[0], match[2].toLowerCase() );
10837				map[ newKey ] = key;
10838	
10839				if ( match[1] === 'o' )
10840				{
10841					_fnHungarianMap( o[key] );
10842				}
10843			}
10844		} );
10845	
10846		o._hungarianMap = map;
10847	}
10848	
10849	
10850	/**
10851	 * Convert from camel case parameters to Hungarian, based on a Hungarian map
10852	 * created by _fnHungarianMap.
10853	 *  @param {object} src The model object which holds all parameters that can be
10854	 *    mapped.
10855	 *  @param {object} user The object to convert from camel case to Hungarian.
10856	 *  @param {boolean} force When set to `true`, properties which already have a
10857	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
10858	 *    won't be.
10859	 *  @memberof DataTable#oApi
10860	 */
10861	function _fnCamelToHungarian ( src, user, force )
10862	{
10863		if ( ! src._hungarianMap ) {
10864			_fnHungarianMap( src );
10865		}
10866	
10867		var hungarianKey;
10868	
10869		$.each( user, function (key, val) {
10870			hungarianKey = src._hungarianMap[ key ];
10871	
10872			if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
10873			{
10874				// For objects, we need to buzz down into the object to copy parameters
10875				if ( hungarianKey.charAt(0) === 'o' )
10876				{
10877					// Copy the camelCase options over to the hungarian
10878					if ( ! user[ hungarianKey ] ) {
10879						user[ hungarianKey ] = {};
10880					}
10881					$.extend( true, user[hungarianKey], user[key] );
10882	
10883					_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
10884				}
10885				else {
10886					user[hungarianKey] = user[ key ];
10887				}
10888			}
10889		} );
10890	}
10891	
10892	
10893	/**
10894	 * Language compatibility - when certain options are given, and others aren't, we
10895	 * need to duplicate the values over, in order to provide backwards compatibility
10896	 * with older language files.
10897	 *  @param {object} oSettings dataTables settings object
10898	 *  @memberof DataTable#oApi
10899	 */
10900	function _fnLanguageCompat( lang )
10901	{
10902		// Note the use of the Hungarian notation for the parameters in this method as
10903		// this is called after the mapping of camelCase to Hungarian
10904		var defaults = DataTable.defaults.oLanguage;
10905	
10906		// Default mapping
10907		var defaultDecimal = defaults.sDecimal;
10908		if ( defaultDecimal ) {
10909			_addNumericSort( defaultDecimal );
10910		}
10911	
10912		if ( lang ) {
10913			var zeroRecords = lang.sZeroRecords;
10914	
10915			// Backwards compatibility - if there is no sEmptyTable given, then use the same as
10916			// sZeroRecords - assuming that is given.
10917			if ( ! lang.sEmptyTable && zeroRecords &&
10918				defaults.sEmptyTable === "No data available in table" )
10919			{
10920				_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
10921			}
10922	
10923			// Likewise with loading records
10924			if ( ! lang.sLoadingRecords && zeroRecords &&
10925				defaults.sLoadingRecords === "Loading..." )
10926			{
10927				_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
10928			}
10929	
10930			// Old parameter name of the thousands separator mapped onto the new
10931			if ( lang.sInfoThousands ) {
10932				lang.sThousands = lang.sInfoThousands;
10933			}
10934	
10935			var decimal = lang.sDecimal;
10936			if ( decimal && defaultDecimal !== decimal ) {
10937				_addNumericSort( decimal );
10938			}
10939		}
10940	}
10941	
10942	
10943	/**
10944	 * Map one parameter onto another
10945	 *  @param {object} o Object to map
10946	 *  @param {*} knew The new parameter name
10947	 *  @param {*} old The old parameter name
10948	 */
10949	var _fnCompatMap = function ( o, knew, old ) {
10950		if ( o[ knew ] !== undefined ) {
10951			o[ old ] = o[ knew ];
10952		}
10953	};
10954	
10955	
10956	/**
10957	 * Provide backwards compatibility for the main DT options. Note that the new
10958	 * options are mapped onto the old parameters, so this is an external interface
10959	 * change only.
10960	 *  @param {object} init Object to map
10961	 */
10962	function _fnCompatOpts ( init )
10963	{
10964		_fnCompatMap( init, 'ordering',      'bSort' );
10965		_fnCompatMap( init, 'orderMulti',    'bSortMulti' );
10966		_fnCompatMap( init, 'orderClasses',  'bSortClasses' );
10967		_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
10968		_fnCompatMap( init, 'order',         'aaSorting' );
10969		_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
10970		_fnCompatMap( init, 'paging',        'bPaginate' );
10971		_fnCompatMap( init, 'pagingType',    'sPaginationType' );
10972		_fnCompatMap( init, 'pageLength',    'iDisplayLength' );
10973		_fnCompatMap( init, 'searching',     'bFilter' );
10974	
10975		// Boolean initialisation of x-scrolling
10976		if ( typeof init.sScrollX === 'boolean' ) {
10977			init.sScrollX = init.sScrollX ? '100%' : '';
10978		}
10979		if ( typeof init.scrollX === 'boolean' ) {
10980			init.scrollX = init.scrollX ? '100%' : '';
10981		}
10982	
10983		// Column search objects are in an array, so it needs to be converted
10984		// element by element
10985		var searchCols = init.aoSearchCols;
10986	
10987		if ( searchCols ) {
10988			for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
10989				if ( searchCols[i] ) {
10990					_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
10991				}
10992			}
10993		}
10994	}
10995	
10996	
10997	/**
10998	 * Provide backwards compatibility for column options. Note that the new options
10999	 * are mapped onto the old parameters, so this is an external interface change
11000	 * only.
11001	 *  @param {object} init Object to map
11002	 */
11003	function _fnCompatCols ( init )
11004	{
11005		_fnCompatMap( init, 'orderable',     'bSortable' );
11006		_fnCompatMap( init, 'orderData',     'aDataSort' );
11007		_fnCompatMap( init, 'orderSequence', 'asSorting' );
11008		_fnCompatMap( init, 'orderDataType', 'sortDataType' );
11009	
11010		// orderData can be given as an integer
11011		var dataSort = init.aDataSort;
11012		if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
11013			init.aDataSort = [ dataSort ];
11014		}
11015	}
11016	
11017	
11018	/**
11019	 * Browser feature detection for capabilities, quirks
11020	 *  @param {object} settings dataTables settings object
11021	 *  @memberof DataTable#oApi
11022	 */
11023	function _fnBrowserDetect( settings )
11024	{
11025		// We don't need to do this every time DataTables is constructed, the values
11026		// calculated are specific to the browser and OS configuration which we
11027		// don't expect to change between initialisations
11028		if ( ! DataTable.__browser ) {
11029			var browser = {};
11030			DataTable.__browser = browser;
11031	
11032			// Scrolling feature / quirks detection
11033			var n = $('<div/>')
11034				.css( {
11035					position: 'fixed',
11036					top: 0,
11037					left: $(window).scrollLeft()*-1, // allow for scrolling
11038					height: 1,
11039					width: 1,
11040					overflow: 'hidden'
11041				} )
11042				.append(
11043					$('<div/>')
11044						.css( {
11045							position: 'absolute',
11046							top: 1,
11047							left: 1,
11048							width: 100,
11049							overflow: 'scroll'
11050						} )
11051						.append(
11052							$('<div/>')
11053								.css( {
11054									width: '100%',
11055									height: 10
11056								} )
11057						)
11058				)
11059				.appendTo( 'body' );
11060	
11061			var outer = n.children();
11062			var inner = outer.children();
11063	
11064			// Numbers below, in order, are:
11065			// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
11066			//
11067			// IE6 XP:                           100 100 100  83
11068			// IE7 Vista:                        100 100 100  83
11069			// IE 8+ Windows:                     83  83 100  83
11070			// Evergreen Windows:                 83  83 100  83
11071			// Evergreen Mac with scrollbars:     85  85 100  85
11072			// Evergreen Mac without scrollbars: 100 100 100 100
11073	
11074			// Get scrollbar width
11075			browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
11076	
11077			// IE6/7 will oversize a width 100% element inside a scrolling element, to
11078			// include the width of the scrollbar, while other browsers ensure the inner
11079			// element is contained without forcing scrolling
11080			browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
11081	
11082			// In rtl text layout, some browsers (most, but not all) will place the
11083			// scrollbar on the left, rather than the right.
11084			browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
11085	
11086			// IE8- don't provide height and width for getBoundingClientRect
11087			browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
11088	
11089			n.remove();
11090		}
11091	
11092		$.extend( settings.oBrowser, DataTable.__browser );
11093		settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
11094	}
11095	
11096	
11097	/**
11098	 * Array.prototype reduce[Right] method, used for browsers which don't support
11099	 * JS 1.6. Done this way to reduce code size, since we iterate either way
11100	 *  @param {object} settings dataTables settings object
11101	 *  @memberof DataTable#oApi
11102	 */
11103	function _fnReduce ( that, fn, init, start, end, inc )
11104	{
11105		var
11106			i = start,
11107			value,
11108			isSet = false;
11109	
11110		if ( init !== undefined ) {
11111			value = init;
11112			isSet = true;
11113		}
11114	
11115		while ( i !== end ) {
11116			if ( ! that.hasOwnProperty(i) ) {
11117				continue;
11118			}
11119	
11120			value = isSet ?
11121				fn( value, that[i], i, that ) :
11122				that[i];
11123	
11124			isSet = true;
11125			i += inc;
11126		}
11127	
11128		return value;
11129	}
11130	
11131	/**
11132	 * Add a column to the list used for the table with default values
11133	 *  @param {object} oSettings dataTables settings object
11134	 *  @param {node} nTh The th element for this column
11135	 *  @memberof DataTable#oApi
11136	 */
11137	function _fnAddColumn( oSettings, nTh )
11138	{
11139		// Add column to aoColumns array
11140		var oDefaults = DataTable.defaults.column;
11141		var iCol = oSettings.aoColumns.length;
11142		var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
11143			"nTh": nTh ? nTh : document.createElement('th'),
11144			"sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
11145			"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
11146			"mData": oDefaults.mData ? oDefaults.mData : iCol,
11147			idx: iCol
11148		} );
11149		oSettings.aoColumns.push( oCol );
11150	
11151		// Add search object for column specific search. Note that the `searchCols[ iCol ]`
11152		// passed into extend can be undefined. This allows the user to give a default
11153		// with only some of the parameters defined, and also not give a default
11154		var searchCols = oSettings.aoPreSearchCols;
11155		searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
11156	
11157		// Use the default column options function to initialise classes etc
11158		_fnColumnOptions( oSettings, iCol, $(nTh).data() );
11159	}
11160	
11161	
11162	/**
11163	 * Apply options for a column
11164	 *  @param {object} oSettings dataTables settings object
11165	 *  @param {int} iCol column index to consider
11166	 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
11167	 *  @memberof DataTable#oApi
11168	 */
11169	function _fnColumnOptions( oSettings, iCol, oOptions )
11170	{
11171		var oCol = oSettings.aoColumns[ iCol ];
11172		var oClasses = oSettings.oClasses;
11173		var th = $(oCol.nTh);
11174	
11175		// Try to get width information from the DOM. We can't get it from CSS
11176		// as we'd need to parse the CSS stylesheet. `width` option can override
11177		if ( ! oCol.sWidthOrig ) {
11178			// Width attribute
11179			oCol.sWidthOrig = th.attr('width') || null;
11180	
11181			// Style attribute
11182			var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
11183			if ( t ) {
11184				oCol.sWidthOrig = t[1];
11185			}
11186		}
11187	
11188		/* User specified column options */
11189		if ( oOptions !== undefined && oOptions !== null )
11190		{
11191			// Backwards compatibility
11192			_fnCompatCols( oOptions );
11193	
11194			// Map camel case parameters to their Hungarian counterparts
11195			_fnCamelToHungarian( DataTable.defaults.column, oOptions );
11196	
11197			/* Backwards compatibility for mDataProp */
11198			if ( oOptions.mDataProp !== undefined && !oOptions.mData )
11199			{
11200				oOptions.mData = oOptions.mDataProp;
11201			}
11202	
11203			if ( oOptions.sType )
11204			{
11205				oCol._sManualType = oOptions.sType;
11206			}
11207	
11208			// `class` is a reserved word in Javascript, so we need to provide
11209			// the ability to use a valid name for the camel case input
11210			if ( oOptions.className && ! oOptions.sClass )
11211			{
11212				oOptions.sClass = oOptions.className;
11213			}
11214			if ( oOptions.sClass ) {
11215				th.addClass( oOptions.sClass );
11216			}
11217	
11218			$.extend( oCol, oOptions );
11219			_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
11220	
11221			/* iDataSort to be applied (backwards compatibility), but aDataSort will take
11222			 * priority if defined
11223			 */
11224			if ( oOptions.iDataSort !== undefined )
11225			{
11226				oCol.aDataSort = [ oOptions.iDataSort ];
11227			}
11228			_fnMap( oCol, oOptions, "aDataSort" );
11229		}
11230	
11231		/* Cache the data get and set functions for speed */
11232		var mDataSrc = oCol.mData;
11233		var mData = _fnGetObjectDataFn( mDataSrc );
11234		var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
11235	
11236		var attrTest = function( src ) {
11237			return typeof src === 'string' && src.indexOf('@') !== -1;
11238		};
11239		oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
11240			attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
11241		);
11242		oCol._setter = null;
11243	
11244		oCol.fnGetData = function (rowData, type, meta) {
11245			var innerData = mData( rowData, type, undefined, meta );
11246	
11247			return mRender && type ?
11248				mRender( innerData, type, rowData, meta ) :
11249				innerData;
11250		};
11251		oCol.fnSetData = function ( rowData, val, meta ) {
11252			return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
11253		};
11254	
11255		// Indicate if DataTables should read DOM data as an object or array
11256		// Used in _fnGetRowElements
11257		if ( typeof mDataSrc !== 'number' ) {
11258			oSettings._rowReadObject = true;
11259		}
11260	
11261		/* Feature sorting overrides column specific when off */
11262		if ( !oSettings.oFeatures.bSort )
11263		{
11264			oCol.bSortable = false;
11265			th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
11266		}
11267	
11268		/* Check that the class assignment is correct for sorting */
11269		var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
11270		var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
11271		if ( !oCol.bSortable || (!bAsc && !bDesc) )
11272		{
11273			oCol.sSortingClass = oClasses.sSortableNone;
11274			oCol.sSortingClassJUI = "";
11275		}
11276		else if ( bAsc && !bDesc )
11277		{
11278			oCol.sSortingClass = oClasses.sSortableAsc;
11279			oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
11280		}
11281		else if ( !bAsc && bDesc )
11282		{
11283			oCol.sSortingClass = oClasses.sSortableDesc;
11284			oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
11285		}
11286		else
11287		{
11288			oCol.sSortingClass = oClasses.sSortable;
11289			oCol.sSortingClassJUI = oClasses.sSortJUI;
11290		}
11291	}
11292	
11293	
11294	/**
11295	 * Adjust the table column widths for new data. Note: you would probably want to
11296	 * do a redraw after calling this function!
11297	 *  @param {object} settings dataTables settings object
11298	 *  @memberof DataTable#oApi
11299	 */
11300	function _fnAdjustColumnSizing ( settings )
11301	{
11302		/* Not interested in doing column width calculation if auto-width is disabled */
11303		if ( settings.oFeatures.bAutoWidth !== false )
11304		{
11305			var columns = settings.aoColumns;
11306	
11307			_fnCalculateColumnWidths( settings );
11308			for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
11309			{
11310				columns[i].nTh.style.width = columns[i].sWidth;
11311			}
11312		}
11313	
11314		var scroll = settings.oScroll;
11315		if ( scroll.sY !== '' || scroll.sX !== '')
11316		{
11317			_fnScrollDraw( settings );
11318		}
11319	
11320		_fnCallbackFire( settings, null, 'column-sizing', [settings] );
11321	}
11322	
11323	
11324	/**
11325	 * Covert the index of a visible column to the index in the data array (take account
11326	 * of hidden columns)
11327	 *  @param {object} oSettings dataTables settings object
11328	 *  @param {int} iMatch Visible column index to lookup
11329	 *  @returns {int} i the data index
11330	 *  @memberof DataTable#oApi
11331	 */
11332	function _fnVisibleToColumnIndex( oSettings, iMatch )
11333	{
11334		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
11335	
11336		return typeof aiVis[iMatch] === 'number' ?
11337			aiVis[iMatch] :
11338			null;
11339	}
11340	
11341	
11342	/**
11343	 * Covert the index of an index in the data array and convert it to the visible
11344	 *   column index (take account of hidden columns)
11345	 *  @param {int} iMatch Column index to lookup
11346	 *  @param {object} oSettings dataTables settings object
11347	 *  @returns {int} i the data index
11348	 *  @memberof DataTable#oApi
11349	 */
11350	function _fnColumnIndexToVisible( oSettings, iMatch )
11351	{
11352		var aiVis = _fnGetColumns( oSettings, 'bVisible' );
11353		var iPos = $.inArray( iMatch, aiVis );
11354	
11355		return iPos !== -1 ? iPos : null;
11356	}
11357	
11358	
11359	/**
11360	 * Get the number of visible columns
11361	 *  @param {object} oSettings dataTables settings object
11362	 *  @returns {int} i the number of visible columns
11363	 *  @memberof DataTable#oApi
11364	 */
11365	function _fnVisbleColumns( oSettings )
11366	{
11367		var vis = 0;
11368	
11369		// No reduce in IE8, use a loop for now
11370		$.each( oSettings.aoColumns, function ( i, col ) {
11371			if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
11372				vis++;
11373			}
11374		} );
11375	
11376		return vis;
11377	}
11378	
11379	
11380	/**
11381	 * Get an array of column indexes that match a given property
11382	 *  @param {object} oSettings dataTables settings object
11383	 *  @param {string} sParam Parameter in aoColumns to look for - typically
11384	 *    bVisible or bSearchable
11385	 *  @returns {array} Array of indexes with matched properties
11386	 *  @memberof DataTable#oApi
11387	 */
11388	function _fnGetColumns( oSettings, sParam )
11389	{
11390		var a = [];
11391	
11392		$.map( oSettings.aoColumns, function(val, i) {
11393			if ( val[sParam] ) {
11394				a.push( i );
11395			}
11396		} );
11397	
11398		return a;
11399	}
11400	
11401	
11402	/**
11403	 * Calculate the 'type' of a column
11404	 *  @param {object} settings dataTables settings object
11405	 *  @memberof DataTable#oApi
11406	 */
11407	function _fnColumnTypes ( settings )
11408	{
11409		var columns = settings.aoColumns;
11410		var data = settings.aoData;
11411		var types = DataTable.ext.type.detect;
11412		var i, ien, j, jen, k, ken;
11413		var col, cell, detectedType, cache;
11414	
11415		// For each column, spin over the 
11416		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
11417			col = columns[i];
11418			cache = [];
11419	
11420			if ( ! col.sType && col._sManualType ) {
11421				col.sType = col._sManualType;
11422			}
11423			else if ( ! col.sType ) {
11424				for ( j=0, jen=types.length ; j<jen ; j++ ) {
11425					for ( k=0, ken=data.length ; k<ken ; k++ ) {
11426						// Use a cache array so we only need to get the type data
11427						// from the formatter once (when using multiple detectors)
11428						if ( cache[k] === undefined ) {
11429							cache[k] = _fnGetCellData( settings, k, i, 'type' );
11430						}
11431	
11432						detectedType = types[j]( cache[k], settings );
11433	
11434						// If null, then this type can't apply to this column, so
11435						// rather than testing all cells, break out. There is an
11436						// exception for the last type which is `html`. We need to
11437						// scan all rows since it is possible to mix string and HTML
11438						// types
11439						if ( ! detectedType && j !== types.length-1 ) {
11440							break;
11441						}
11442	
11443						// Only a single match is needed for html type since it is
11444						// bottom of the pile and very similar to string
11445						if ( detectedType === 'html' ) {
11446							break;
11447						}
11448					}
11449	
11450					// Type is valid for all data points in the column - use this
11451					// type
11452					if ( detectedType ) {
11453						col.sType = detectedType;
11454						break;
11455					}
11456				}
11457	
11458				// Fall back - if no type was detected, always use string
11459				if ( ! col.sType ) {
11460					col.sType = 'string';
11461				}
11462			}
11463		}
11464	}
11465	
11466	
11467	/**
11468	 * Take the column definitions and static columns arrays and calculate how
11469	 * they relate to column indexes. The callback function will then apply the
11470	 * definition found for a column to a suitable configuration object.
11471	 *  @param {object} oSettings dataTables settings object
11472	 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
11473	 *  @param {array} aoCols The aoColumns array that defines columns individually
11474	 *  @param {function} fn Callback function - takes two parameters, the calculated
11475	 *    column index and the definition for that column.
11476	 *  @memberof DataTable#oApi
11477	 */
11478	function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
11479	{
11480		var i, iLen, j, jLen, k, kLen, def;
11481		var columns = oSettings.aoColumns;
11482	
11483		// Column definitions with aTargets
11484		if ( aoColDefs )
11485		{
11486			/* Loop over the definitions array - loop in reverse so first instance has priority */
11487			for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
11488			{
11489				def = aoColDefs[i];
11490	
11491				/* Each definition can target multiple columns, as it is an array */
11492				var aTargets = def.targets !== undefined ?
11493					def.targets :
11494					def.aTargets;
11495	
11496				if ( ! $.isArray( aTargets ) )
11497				{
11498					aTargets = [ aTargets ];
11499				}
11500	
11501				for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
11502				{
11503					if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
11504					{
11505						/* Add columns that we don't yet know about */
11506						while( columns.length <= aTargets[j] )
11507						{
11508							_fnAddColumn( oSettings );
11509						}
11510	
11511						/* Integer, basic index */
11512						fn( aTargets[j], def );
11513					}
11514					else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
11515					{
11516						/* Negative integer, right to left column counting */
11517						fn( columns.length+aTargets[j], def );
11518					}
11519					else if ( typeof aTargets[j] === 'string' )
11520					{
11521						/* Class name matching on TH element */
11522						for ( k=0, kLen=columns.length ; k<kLen ; k++ )
11523						{
11524							if ( aTargets[j] == "_all" ||
11525							     $(columns[k].nTh).hasClass( aTargets[j] ) )
11526							{
11527								fn( k, def );
11528							}
11529						}
11530					}
11531				}
11532			}
11533		}
11534	
11535		// Statically defined columns array
11536		if ( aoCols )
11537		{
11538			for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
11539			{
11540				fn( i, aoCols[i] );
11541			}
11542		}
11543	}
11544	
11545	/**
11546	 * Add a data array to the table, creating DOM node etc. This is the parallel to
11547	 * _fnGatherData, but for adding rows from a Javascript source, rather than a
11548	 * DOM source.
11549	 *  @param {object} oSettings dataTables settings object
11550	 *  @param {array} aData data array to be added
11551	 *  @param {node} [nTr] TR element to add to the table - optional. If not given,
11552	 *    DataTables will create a row automatically
11553	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
11554	 *    if nTr is.
11555	 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
11556	 *  @memberof DataTable#oApi
11557	 */
11558	function _fnAddData ( oSettings, aDataIn, nTr, anTds )
11559	{
11560		/* Create the object for storing information about this new row */
11561		var iRow = oSettings.aoData.length;
11562		var oData = $.extend( true, {}, DataTable.models.oRow, {
11563			src: nTr ? 'dom' : 'data',
11564			idx: iRow
11565		} );
11566	
11567		oData._aData = aDataIn;
11568		oSettings.aoData.push( oData );
11569	
11570		/* Create the cells */
11571		var nTd, sThisType;
11572		var columns = oSettings.aoColumns;
11573	
11574		// Invalidate the column types as the new data needs to be revalidated
11575		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
11576		{
11577			columns[i].sType = null;
11578		}
11579	
11580		/* Add to the display array */
11581		oSettings.aiDisplayMaster.push( iRow );
11582	
11583		var id = oSettings.rowIdFn( aDataIn );
11584		if ( id !== undefined ) {
11585			oSettings.aIds[ id ] = oData;
11586		}
11587	
11588		/* Create the DOM information, or register it if already present */
11589		if ( nTr || ! oSettings.oFeatures.bDeferRender )
11590		{
11591			_fnCreateTr( oSettings, iRow, nTr, anTds );
11592		}
11593	
11594		return iRow;
11595	}
11596	
11597	
11598	/**
11599	 * Add one or more TR elements to the table. Generally we'd expect to
11600	 * use this for reading data from a DOM sourced table, but it could be
11601	 * used for an TR element. Note that if a TR is given, it is used (i.e.
11602	 * it is not cloned).
11603	 *  @param {object} settings dataTables settings object
11604	 *  @param {array|node|jQuery} trs The TR element(s) to add to the table
11605	 *  @returns {array} Array of indexes for the added rows
11606	 *  @memberof DataTable#oApi
11607	 */
11608	function _fnAddTr( settings, trs )
11609	{
11610		var row;
11611	
11612		// Allow an individual node to be passed in
11613		if ( ! (trs instanceof $) ) {
11614			trs = $(trs);
11615		}
11616	
11617		return trs.map( function (i, el) {
11618			row = _fnGetRowElements( settings, el );
11619			return _fnAddData( settings, row.data, el, row.cells );
11620		} );
11621	}
11622	
11623	
11624	/**
11625	 * Take a TR element and convert it to an index in aoData
11626	 *  @param {object} oSettings dataTables settings object
11627	 *  @param {node} n the TR element to find
11628	 *  @returns {int} index if the node is found, null if not
11629	 *  @memberof DataTable#oApi
11630	 */
11631	function _fnNodeToDataIndex( oSettings, n )
11632	{
11633		return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
11634	}
11635	
11636	
11637	/**
11638	 * Take a TD element and convert it into a column data index (not the visible index)
11639	 *  @param {object} oSettings dataTables settings object
11640	 *  @param {int} iRow The row number the TD/TH can be found in
11641	 *  @param {node} n The TD/TH element to find
11642	 *  @returns {int} index if the node is found, -1 if not
11643	 *  @memberof DataTable#oApi
11644	 */
11645	function _fnNodeToColumnIndex( oSettings, iRow, n )
11646	{
11647		return $.inArray( n, oSettings.aoData[ iRow ].anCells );
11648	}
11649	
11650	
11651	/**
11652	 * Get the data for a given cell from the internal cache, taking into account data mapping
11653	 *  @param {object} settings dataTables settings object
11654	 *  @param {int} rowIdx aoData row id
11655	 *  @param {int} colIdx Column index
11656	 *  @param {string} type data get type ('display', 'type' 'filter' 'sort')
11657	 *  @returns {*} Cell data
11658	 *  @memberof DataTable#oApi
11659	 */
11660	function _fnGetCellData( settings, rowIdx, colIdx, type )
11661	{
11662		var draw           = settings.iDraw;
11663		var col            = settings.aoColumns[colIdx];
11664		var rowData        = settings.aoData[rowIdx]._aData;
11665		var defaultContent = col.sDefaultContent;
11666		var cellData       = col.fnGetData( rowData, type, {
11667			settings: settings,
11668			row:      rowIdx,
11669			col:      colIdx
11670		} );
11671	
11672		if ( cellData === undefined ) {
11673			if ( settings.iDrawError != draw && defaultContent === null ) {
11674				_fnLog( settings, 0, "Requested unknown parameter "+
11675					(typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
11676					" for row "+rowIdx+", column "+colIdx, 4 );
11677				settings.iDrawError = draw;
11678			}
11679			return defaultContent;
11680		}
11681	
11682		// When the data source is null and a specific data type is requested (i.e.
11683		// not the original data), we can use default column data
11684		if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
11685			cellData = defaultContent;
11686		}
11687		else if ( typeof cellData === 'function' ) {
11688			// If the data source is a function, then we run it and use the return,
11689			// executing in the scope of the data object (for instances)
11690			return cellData.call( rowData );
11691		}
11692	
11693		if ( cellData === null && type == 'display' ) {
11694			return '';
11695		}
11696		return cellData;
11697	}
11698	
11699	
11700	/**
11701	 * Set the value for a specific cell, into the internal data cache
11702	 *  @param {object} settings dataTables settings object
11703	 *  @param {int} rowIdx aoData row id
11704	 *  @param {int} colIdx Column index
11705	 *  @param {*} val Value to set
11706	 *  @memberof DataTable#oApi
11707	 */
11708	function _fnSetCellData( settings, rowIdx, colIdx, val )
11709	{
11710		var col     = settings.aoColumns[colIdx];
11711		var rowData = settings.aoData[rowIdx]._aData;
11712	
11713		col.fnSetData( rowData, val, {
11714			settings: settings,
11715			row:      rowIdx,
11716			col:      colIdx
11717		}  );
11718	}
11719	
11720	
11721	// Private variable that is used to match action syntax in the data property object
11722	var __reArray = /\[.*?\]$/;
11723	var __reFn = /\(\)$/;
11724	
11725	/**
11726	 * Split string on periods, taking into account escaped periods
11727	 * @param  {string} str String to split
11728	 * @return {array} Split string
11729	 */
11730	function _fnSplitObjNotation( str )
11731	{
11732		return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
11733			return s.replace(/\\\./g, '.');
11734		} );
11735	}
11736	
11737	
11738	/**
11739	 * Return a function that can be used to get data from a source object, taking
11740	 * into account the ability to use nested objects as a source
11741	 *  @param {string|int|function} mSource The data source for the object
11742	 *  @returns {function} Data get function
11743	 *  @memberof DataTable#oApi
11744	 */
11745	function _fnGetObjectDataFn( mSource )
11746	{
11747		if ( $.isPlainObject( mSource ) )
11748		{
11749			/* Build an object of get functions, and wrap them in a single call */
11750			var o = {};
11751			$.each( mSource, function (key, val) {
11752				if ( val ) {
11753					o[key] = _fnGetObjectDataFn( val );
11754				}
11755			} );
11756	
11757			return function (data, type, row, meta) {
11758				var t = o[type] || o._;
11759				return t !== undefined ?
11760					t(data, type, row, meta) :
11761					data;
11762			};
11763		}
11764		else if ( mSource === null )
11765		{
11766			/* Give an empty string for rendering / sorting etc */
11767			return function (data) { // type, row and meta also passed, but not used
11768				return data;
11769			};
11770		}
11771		else if ( typeof mSource === 'function' )
11772		{
11773			return function (data, type, row, meta) {
11774				return mSource( data, type, row, meta );
11775			};
11776		}
11777		else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
11778			      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
11779		{
11780			/* If there is a . in the source string then the data source is in a
11781			 * nested object so we loop over the data for each level to get the next
11782			 * level down. On each loop we test for undefined, and if found immediately
11783			 * return. This allows entire objects to be missing and sDefaultContent to
11784			 * be used if defined, rather than throwing an error
11785			 */
11786			var fetchData = function (data, type, src) {
11787				var arrayNotation, funcNotation, out, innerSrc;
11788	
11789				if ( src !== "" )
11790				{
11791					var a = _fnSplitObjNotation( src );
11792	
11793					for ( var i=0, iLen=a.length ; i<iLen ; i++ )
11794					{
11795						// Check if we are dealing with special notation
11796						arrayNotation = a[i].match(__reArray);
11797						funcNotation = a[i].match(__reFn);
11798	
11799						if ( arrayNotation )
11800						{
11801							// Array notation
11802							a[i] = a[i].replace(__reArray, '');
11803	
11804							// Condition allows simply [] to be passed in
11805							if ( a[i] !== "" ) {
11806								data = data[ a[i] ];
11807							}
11808							out = [];
11809	
11810							// Get the remainder of the nested object to get
11811							a.splice( 0, i+1 );
11812							innerSrc = a.join('.');
11813	
11814							// Traverse each entry in the array getting the properties requested
11815							if ( $.isArray( data ) ) {
11816								for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
11817									out.push( fetchData( data[j], type, innerSrc ) );
11818								}
11819							}
11820	
11821							// If a string is given in between the array notation indicators, that
11822							// is used to join the strings together, otherwise an array is returned
11823							var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
11824							data = (join==="") ? out : out.join(join);
11825	
11826							// The inner call to fetchData has already traversed through the remainder
11827							// of the source requested, so we exit from the loop
11828							break;
11829						}
11830						else if ( funcNotation )
11831						{
11832							// Function call
11833							a[i] = a[i].replace(__reFn, '');
11834							data = data[ a[i] ]();
11835							continue;
11836						}
11837	
11838						if ( data === null || data[ a[i] ] === undefined )
11839						{
11840							return undefined;
11841						}
11842						data = data[ a[i] ];
11843					}
11844				}
11845	
11846				return data;
11847			};
11848	
11849			return function (data, type) { // row and meta also passed, but not used
11850				return fetchData( data, type, mSource );
11851			};
11852		}
11853		else
11854		{
11855			/* Array or flat object mapping */
11856			return function (data, type) { // row and meta also passed, but not used
11857				return data[mSource];
11858			};
11859		}
11860	}
11861	
11862	
11863	/**
11864	 * Return a function that can be used to set data from a source object, taking
11865	 * into account the ability to use nested objects as a source
11866	 *  @param {string|int|function} mSource The data source for the object
11867	 *  @returns {function} Data set function
11868	 *  @memberof DataTable#oApi
11869	 */
11870	function _fnSetObjectDataFn( mSource )
11871	{
11872		if ( $.isPlainObject( mSource ) )
11873		{
11874			/* Unlike get, only the underscore (global) option is used for for
11875			 * setting data since we don't know the type here. This is why an object
11876			 * option is not documented for `mData` (which is read/write), but it is
11877			 * for `mRender` which is read only.
11878			 */
11879			return _fnSetObjectDataFn( mSource._ );
11880		}
11881		else if ( mSource === null )
11882		{
11883			/* Nothing to do when the data source is null */
11884			return function () {};
11885		}
11886		else if ( typeof mSource === 'function' )
11887		{
11888			return function (data, val, meta) {
11889				mSource( data, 'set', val, meta );
11890			};
11891		}
11892		else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
11893			      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
11894		{
11895			/* Like the get, we need to get data from a nested object */
11896			var setData = function (data, val, src) {
11897				var a = _fnSplitObjNotation( src ), b;
11898				var aLast = a[a.length-1];
11899				var arrayNotation, funcNotation, o, innerSrc;
11900	
11901				for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
11902				{
11903					// Check if we are dealing with an array notation request
11904					arrayNotation = a[i].match(__reArray);
11905					funcNotation = a[i].match(__reFn);
11906	
11907					if ( arrayNotation )
11908					{
11909						a[i] = a[i].replace(__reArray, '');
11910						data[ a[i] ] = [];
11911	
11912						// Get the remainder of the nested object to set so we can recurse
11913						b = a.slice();
11914						b.splice( 0, i+1 );
11915						innerSrc = b.join('.');
11916	
11917						// Traverse each entry in the array setting the properties requested
11918						if ( $.isArray( val ) )
11919						{
11920							for ( var j=0, jLen=val.length ; j<jLen ; j++ )
11921							{
11922								o = {};
11923								setData( o, val[j], innerSrc );
11924								data[ a[i] ].push( o );
11925							}
11926						}
11927						else
11928						{
11929							// We've been asked to save data to an array, but it
11930							// isn't array data to be saved. Best that can be done
11931							// is to just save the value.
11932							data[ a[i] ] = val;
11933						}
11934	
11935						// The inner call to setData has already traversed through the remainder
11936						// of the source and has set the data, thus we can exit here
11937						return;
11938					}
11939					else if ( funcNotation )
11940					{
11941						// Function call
11942						a[i] = a[i].replace(__reFn, '');
11943						data = data[ a[i] ]( val );
11944					}
11945	
11946					// If the nested object doesn't currently exist - since we are
11947					// trying to set the value - create it
11948					if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
11949					{
11950						data[ a[i] ] = {};
11951					}
11952					data = data[ a[i] ];
11953				}
11954	
11955				// Last item in the input - i.e, the actual set
11956				if ( aLast.match(__reFn ) )
11957				{
11958					// Function call
11959					data = data[ aLast.replace(__reFn, '') ]( val );
11960				}
11961				else
11962				{
11963					// If array notation is used, we just want to strip it and use the property name
11964					// and assign the value. If it isn't used, then we get the result we want anyway
11965					data[ aLast.replace(__reArray, '') ] = val;
11966				}
11967			};
11968	
11969			return function (data, val) { // meta is also passed in, but not used
11970				return setData( data, val, mSource );
11971			};
11972		}
11973		else
11974		{
11975			/* Array or flat object mapping */
11976			return function (data, val) { // meta is also passed in, but not used
11977				data[mSource] = val;
11978			};
11979		}
11980	}
11981	
11982	
11983	/**
11984	 * Return an array with the full table data
11985	 *  @param {object} oSettings dataTables settings object
11986	 *  @returns array {array} aData Master data array
11987	 *  @memberof DataTable#oApi
11988	 */
11989	function _fnGetDataMaster ( settings )
11990	{
11991		return _pluck( settings.aoData, '_aData' );
11992	}
11993	
11994	
11995	/**
11996	 * Nuke the table
11997	 *  @param {object} oSettings dataTables settings object
11998	 *  @memberof DataTable#oApi
11999	 */
12000	function _fnClearTable( settings )
12001	{
12002		settings.aoData.length = 0;
12003		settings.aiDisplayMaster.length = 0;
12004		settings.aiDisplay.length = 0;
12005		settings.aIds = {};
12006	}
12007	
12008	
12009	 /**
12010	 * Take an array of integers (index array) and remove a target integer (value - not
12011	 * the key!)
12012	 *  @param {array} a Index array to target
12013	 *  @param {int} iTarget value to find
12014	 *  @memberof DataTable#oApi
12015	 */
12016	function _fnDeleteIndex( a, iTarget, splice )
12017	{
12018		var iTargetIndex = -1;
12019	
12020		for ( var i=0, iLen=a.length ; i<iLen ; i++ )
12021		{
12022			if ( a[i] == iTarget )
12023			{
12024				iTargetIndex = i;
12025			}
12026			else if ( a[i] > iTarget )
12027			{
12028				a[i]--;
12029			}
12030		}
12031	
12032		if ( iTargetIndex != -1 && splice === undefined )
12033		{
12034			a.splice( iTargetIndex, 1 );
12035		}
12036	}
12037	
12038	
12039	/**
12040	 * Mark cached data as invalid such that a re-read of the data will occur when
12041	 * the cached data is next requested. Also update from the data source object.
12042	 *
12043	 * @param {object} settings DataTables settings object
12044	 * @param {int}    rowIdx   Row index to invalidate
12045	 * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
12046	 *     or 'data'
12047	 * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
12048	 *     row will be invalidated
12049	 * @memberof DataTable#oApi
12050	 *
12051	 * @todo For the modularisation of v1.11 this will need to become a callback, so
12052	 *   the sort and filter methods can subscribe to it. That will required
12053	 *   initialisation options for sorting, which is why it is not already baked in
12054	 */
12055	function _fnInvalidate( settings, rowIdx, src, colIdx )
12056	{
12057		var row = settings.aoData[ rowIdx ];
12058		var i, ien;
12059		var cellWrite = function ( cell, col ) {
12060			// This is very frustrating, but in IE if you just write directly
12061			// to innerHTML, and elements that are overwritten are GC'ed,
12062			// even if there is a reference to them elsewhere
12063			while ( cell.childNodes.length ) {
12064				cell.removeChild( cell.firstChild );
12065			}
12066	
12067			cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
12068		};
12069	
12070		// Are we reading last data from DOM or the data object?
12071		if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
12072			// Read the data from the DOM
12073			row._aData = _fnGetRowElements(
12074					settings, row, colIdx, colIdx === undefined ? undefined : row._aData
12075				)
12076				.data;
12077		}
12078		else {
12079			// Reading from data object, update the DOM
12080			var cells = row.anCells;
12081	
12082			if ( cells ) {
12083				if ( colIdx !== undefined ) {
12084					cellWrite( cells[colIdx], colIdx );
12085				}
12086				else {
12087					for ( i=0, ien=cells.length ; i<ien ; i++ ) {
12088						cellWrite( cells[i], i );
12089					}
12090				}
12091			}
12092		}
12093	
12094		// For both row and cell invalidation, the cached data for sorting and
12095		// filtering is nulled out
12096		row._aSortData = null;
12097		row._aFilterData = null;
12098	
12099		// Invalidate the type for a specific column (if given) or all columns since
12100		// the data might have changed
12101		var cols = settings.aoColumns;
12102		if ( colIdx !== undefined ) {
12103			cols[ colIdx ].sType = null;
12104		}
12105		else {
12106			for ( i=0, ien=cols.length ; i<ien ; i++ ) {
12107				cols[i].sType = null;
12108			}
12109	
12110			// Update DataTables special `DT_*` attributes for the row
12111			_fnRowAttributes( settings, row );
12112		}
12113	}
12114	
12115	
12116	/**
12117	 * Build a data source object from an HTML row, reading the contents of the
12118	 * cells that are in the row.
12119	 *
12120	 * @param {object} settings DataTables settings object
12121	 * @param {node|object} TR element from which to read data or existing row
12122	 *   object from which to re-read the data from the cells
12123	 * @param {int} [colIdx] Optional column index
12124	 * @param {array|object} [d] Data source object. If `colIdx` is given then this
12125	 *   parameter should also be given and will be used to write the data into.
12126	 *   Only the column in question will be written
12127	 * @returns {object} Object with two parameters: `data` the data read, in
12128	 *   document order, and `cells` and array of nodes (they can be useful to the
12129	 *   caller, so rather than needing a second traversal to get them, just return
12130	 *   them from here).
12131	 * @memberof DataTable#oApi
12132	 */
12133	function _fnGetRowElements( settings, row, colIdx, d )
12134	{
12135		var
12136			tds = [],
12137			td = row.firstChild,
12138			name, col, o, i=0, contents,
12139			columns = settings.aoColumns,
12140			objectRead = settings._rowReadObject;
12141	
12142		// Allow the data object to be passed in, or construct
12143		d = d !== undefined ?
12144			d :
12145			objectRead ?
12146				{} :
12147				[];
12148	
12149		var attr = function ( str, td  ) {
12150			if ( typeof str === 'string' ) {
12151				var idx = str.indexOf('@');
12152	
12153				if ( idx !== -1 ) {
12154					var attr = str.substring( idx+1 );
12155					var setter = _fnSetObjectDataFn( str );
12156					setter( d, td.getAttribute( attr ) );
12157				}
12158			}
12159		};
12160	
12161		// Read data from a cell and store into the data object
12162		var cellProcess = function ( cell ) {
12163			if ( colIdx === undefined || colIdx === i ) {
12164				col = columns[i];
12165				contents = $.trim(cell.innerHTML);
12166	
12167				if ( col && col._bAttrSrc ) {
12168					var setter = _fnSetObjectDataFn( col.mData._ );
12169					setter( d, contents );
12170	
12171					attr( col.mData.sort, cell );
12172					attr( col.mData.type, cell );
12173					attr( col.mData.filter, cell );
12174				}
12175				else {
12176					// Depending on the `data` option for the columns the data can
12177					// be read to either an object or an array.
vendor: 10,997 bytes, lines 12178-12600
12178					if ( objectRead ) {
12179						if ( ! col._setter ) {
12180							// Cache the setter function
12181							col._setter = _fnSetObjectDataFn( col.mData );
12182						}
12183						col._setter( d, contents );
12184					}
12185					else {
12186						d[i] = contents;
12187					}
12188				}
12189			}
12190	
12191			i++;
12192		};
12193	
12194		if ( td ) {
12195			// `tr` element was passed in
12196			while ( td ) {
12197				name = td.nodeName.toUpperCase();
12198	
12199				if ( name == "TD" || name == "TH" ) {
12200					cellProcess( td );
12201					tds.push( td );
12202				}
12203	
12204				td = td.nextSibling;
12205			}
12206		}
12207		else {
12208			// Existing row object passed in
12209			tds = row.anCells;
12210	
12211			for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
12212				cellProcess( tds[j] );
12213			}
12214		}
12215	
12216		// Read the ID from the DOM if present
12217		var rowNode = row.firstChild ? row : row.nTr;
12218	
12219		if ( rowNode ) {
12220			var id = rowNode.getAttribute( 'id' );
12221	
12222			if ( id ) {
12223				_fnSetObjectDataFn( settings.rowId )( d, id );
12224			}
12225		}
12226	
12227		return {
12228			data: d,
12229			cells: tds
12230		};
12231	}
12232	/**
12233	 * Create a new TR element (and it's TD children) for a row
12234	 *  @param {object} oSettings dataTables settings object
12235	 *  @param {int} iRow Row to consider
12236	 *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
12237	 *    DataTables will create a row automatically
12238	 *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
12239	 *    if nTr is.
12240	 *  @memberof DataTable#oApi
12241	 */
12242	function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
12243	{
12244		var
12245			row = oSettings.aoData[iRow],
12246			rowData = row._aData,
12247			cells = [],
12248			nTr, nTd, oCol,
12249			i, iLen;
12250	
12251		if ( row.nTr === null )
12252		{
12253			nTr = nTrIn || document.createElement('tr');
12254	
12255			row.nTr = nTr;
12256			row.anCells = cells;
12257	
12258			/* Use a private property on the node to allow reserve mapping from the node
12259			 * to the aoData array for fast look up
12260			 */
12261			nTr._DT_RowIndex = iRow;
12262	
12263			/* Special parameters can be given by the data source to be used on the row */
12264			_fnRowAttributes( oSettings, row );
12265	
12266			/* Process each column */
12267			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
12268			{
12269				oCol = oSettings.aoColumns[i];
12270	
12271				nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
12272				nTd._DT_CellIndex = {
12273					row: iRow,
12274					column: i
12275				};
12276				
12277				cells.push( nTd );
12278	
12279				// Need to create the HTML if new, or if a rendering function is defined
12280				if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
12281					 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
12282				) {
12283					nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
12284				}
12285	
12286				/* Add user defined class */
12287				if ( oCol.sClass )
12288				{
12289					nTd.className += ' '+oCol.sClass;
12290				}
12291	
12292				// Visibility - add or remove as required
12293				if ( oCol.bVisible && ! nTrIn )
12294				{
12295					nTr.appendChild( nTd );
12296				}
12297				else if ( ! oCol.bVisible && nTrIn )
12298				{
12299					nTd.parentNode.removeChild( nTd );
12300				}
12301	
12302				if ( oCol.fnCreatedCell )
12303				{
12304					oCol.fnCreatedCell.call( oSettings.oInstance,
12305						nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
12306					);
12307				}
12308			}
12309	
12310			_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );
12311		}
12312	
12313		// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
12314		// and deployed
12315		row.nTr.setAttribute( 'role', 'row' );
12316	}
12317	
12318	
12319	/**
12320	 * Add attributes to a row based on the special `DT_*` parameters in a data
12321	 * source object.
12322	 *  @param {object} settings DataTables settings object
12323	 *  @param {object} DataTables row object for the row to be modified
12324	 *  @memberof DataTable#oApi
12325	 */
12326	function _fnRowAttributes( settings, row )
12327	{
12328		var tr = row.nTr;
12329		var data = row._aData;
12330	
12331		if ( tr ) {
12332			var id = settings.rowIdFn( data );
12333	
12334			if ( id ) {
12335				tr.id = id;
12336			}
12337	
12338			if ( data.DT_RowClass ) {
12339				// Remove any classes added by DT_RowClass before
12340				var a = data.DT_RowClass.split(' ');
12341				row.__rowc = row.__rowc ?
12342					_unique( row.__rowc.concat( a ) ) :
12343					a;
12344	
12345				$(tr)
12346					.removeClass( row.__rowc.join(' ') )
12347					.addClass( data.DT_RowClass );
12348			}
12349	
12350			if ( data.DT_RowAttr ) {
12351				$(tr).attr( data.DT_RowAttr );
12352			}
12353	
12354			if ( data.DT_RowData ) {
12355				$(tr).data( data.DT_RowData );
12356			}
12357		}
12358	}
12359	
12360	
12361	/**
12362	 * Create the HTML header for the table
12363	 *  @param {object} oSettings dataTables settings object
12364	 *  @memberof DataTable#oApi
12365	 */
12366	function _fnBuildHead( oSettings )
12367	{
12368		var i, ien, cell, row, column;
12369		var thead = oSettings.nTHead;
12370		var tfoot = oSettings.nTFoot;
12371		var createHeader = $('th, td', thead).length === 0;
12372		var classes = oSettings.oClasses;
12373		var columns = oSettings.aoColumns;
12374	
12375		if ( createHeader ) {
12376			row = $('<tr/>').appendTo( thead );
12377		}
12378	
12379		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
12380			column = columns[i];
12381			cell = $( column.nTh ).addClass( column.sClass );
12382	
12383			if ( createHeader ) {
12384				cell.appendTo( row );
12385			}
12386	
12387			// 1.11 move into sorting
12388			if ( oSettings.oFeatures.bSort ) {
12389				cell.addClass( column.sSortingClass );
12390	
12391				if ( column.bSortable !== false ) {
12392					cell
12393						.attr( 'tabindex', oSettings.iTabIndex )
12394						.attr( 'aria-controls', oSettings.sTableId );
12395	
12396					_fnSortAttachListener( oSettings, column.nTh, i );
12397				}
12398			}
12399	
12400			if ( column.sTitle != cell[0].innerHTML ) {
12401				cell.html( column.sTitle );
12402			}
12403	
12404			_fnRenderer( oSettings, 'header' )(
12405				oSettings, cell, column, classes
12406			);
12407		}
12408	
12409		if ( createHeader ) {
12410			_fnDetectHeader( oSettings.aoHeader, thead );
12411		}
12412		
12413		/* ARIA role for the rows */
12414	 	$(thead).find('>tr').attr('role', 'row');
12415	
12416		/* Deal with the footer - add classes if required */
12417		$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
12418		$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
12419	
12420		// Cache the footer cells. Note that we only take the cells from the first
12421		// row in the footer. If there is more than one row the user wants to
12422		// interact with, they need to use the table().foot() method. Note also this
12423		// allows cells to be used for multiple columns using colspan
12424		if ( tfoot !== null ) {
12425			var cells = oSettings.aoFooter[0];
12426	
12427			for ( i=0, ien=cells.length ; i<ien ; i++ ) {
12428				column = columns[i];
12429				column.nTf = cells[i].cell;
12430	
12431				if ( column.sClass ) {
12432					$(column.nTf).addClass( column.sClass );
12433				}
12434			}
12435		}
12436	}
12437	
12438	
12439	/**
12440	 * Draw the header (or footer) element based on the column visibility states. The
12441	 * methodology here is to use the layout array from _fnDetectHeader, modified for
12442	 * the instantaneous column visibility, to construct the new layout. The grid is
12443	 * traversed over cell at a time in a rows x columns grid fashion, although each
12444	 * cell insert can cover multiple elements in the grid - which is tracks using the
12445	 * aApplied array. Cell inserts in the grid will only occur where there isn't
12446	 * already a cell in that position.
12447	 *  @param {object} oSettings dataTables settings object
12448	 *  @param array {objects} aoSource Layout array from _fnDetectHeader
12449	 *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
12450	 *  @memberof DataTable#oApi
12451	 */
12452	function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
12453	{
12454		var i, iLen, j, jLen, k, kLen, n, nLocalTr;
12455		var aoLocal = [];
12456		var aApplied = [];
12457		var iColumns = oSettings.aoColumns.length;
12458		var iRowspan, iColspan;
12459	
12460		if ( ! aoSource )
12461		{
12462			return;
12463		}
12464	
12465		if (  bIncludeHidden === undefined )
12466		{
12467			bIncludeHidden = false;
12468		}
12469	
12470		/* Make a copy of the master layout array, but without the visible columns in it */
12471		for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
12472		{
12473			aoLocal[i] = aoSource[i].slice();
12474			aoLocal[i].nTr = aoSource[i].nTr;
12475	
12476			/* Remove any columns which are currently hidden */
12477			for ( j=iColumns-1 ; j>=0 ; j-- )
12478			{
12479				if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
12480				{
12481					aoLocal[i].splice( j, 1 );
12482				}
12483			}
12484	
12485			/* Prep the applied array - it needs an element for each row */
12486			aApplied.push( [] );
12487		}
12488	
12489		for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
12490		{
12491			nLocalTr = aoLocal[i].nTr;
12492	
12493			/* All cells are going to be replaced, so empty out the row */
12494			if ( nLocalTr )
12495			{
12496				while( (n = nLocalTr.firstChild) )
12497				{
12498					nLocalTr.removeChild( n );
12499				}
12500			}
12501	
12502			for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
12503			{
12504				iRowspan = 1;
12505				iColspan = 1;
12506	
12507				/* Check to see if there is already a cell (row/colspan) covering our target
12508				 * insert point. If there is, then there is nothing to do.
12509				 */
12510				if ( aApplied[i][j] === undefined )
12511				{
12512					nLocalTr.appendChild( aoLocal[i][j].cell );
12513					aApplied[i][j] = 1;
12514	
12515					/* Expand the cell to cover as many rows as needed */
12516					while ( aoLocal[i+iRowspan] !== undefined &&
12517					        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
12518					{
12519						aApplied[i+iRowspan][j] = 1;
12520						iRowspan++;
12521					}
12522	
12523					/* Expand the cell to cover as many columns as needed */
12524					while ( aoLocal[i][j+iColspan] !== undefined &&
12525					        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
12526					{
12527						/* Must update the applied array over the rows for the columns */
12528						for ( k=0 ; k<iRowspan ; k++ )
12529						{
12530							aApplied[i+k][j+iColspan] = 1;
12531						}
12532						iColspan++;
12533					}
12534	
12535					/* Do the actual expansion in the DOM */
12536					$(aoLocal[i][j].cell)
12537						.attr('rowspan', iRowspan)
12538						.attr('colspan', iColspan);
12539				}
12540			}
12541		}
12542	}
12543	
12544	
12545	/**
12546	 * Insert the required TR nodes into the table for display
12547	 *  @param {object} oSettings dataTables settings object
12548	 *  @memberof DataTable#oApi
12549	 */
12550	function _fnDraw( oSettings )
12551	{
12552		/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
12553		var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
12554		if ( $.inArray( false, aPreDraw ) !== -1 )
12555		{
12556			_fnProcessingDisplay( oSettings, false );
12557			return;
12558		}
12559	
12560		var i, iLen, n;
12561		var anRows = [];
12562		var iRowCount = 0;
12563		var asStripeClasses = oSettings.asStripeClasses;
12564		var iStripes = asStripeClasses.length;
12565		var iOpenRows = oSettings.aoOpenRows.length;
12566		var oLang = oSettings.oLanguage;
12567		var iInitDisplayStart = oSettings.iInitDisplayStart;
12568		var bServerSide = _fnDataSource( oSettings ) == 'ssp';
12569		var aiDisplay = oSettings.aiDisplay;
12570	
12571		oSettings.bDrawing = true;
12572	
12573		/* Check and see if we have an initial draw position from state saving */
12574		if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
12575		{
12576			oSettings._iDisplayStart = bServerSide ?
12577				iInitDisplayStart :
12578				iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
12579					0 :
12580					iInitDisplayStart;
12581	
12582			oSettings.iInitDisplayStart = -1;
12583		}
12584	
12585		var iDisplayStart = oSettings._iDisplayStart;
12586		var iDisplayEnd = oSettings.fnDisplayEnd();
12587	
12588		/* Server-side processing draw intercept */
12589		if ( oSettings.bDeferLoading )
12590		{
12591			oSettings.bDeferLoading = false;
12592			oSettings.iDraw++;
12593			_fnProcessingDisplay( oSettings, false );
12594		}
12595		else if ( !bServerSide )
12596		{
12597			oSettings.iDraw++;
12598		}
12599		else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
12600		{
vendor: 10,503 bytes, lines 12600-12989
12600
12601			return;
12602		}
12603	
12604		if ( aiDisplay.length !== 0 )
12605		{
12606			var iStart = bServerSide ? 0 : iDisplayStart;
12607			var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
12608	
12609			for ( var j=iStart ; j<iEnd ; j++ )
12610			{
12611				var iDataIndex = aiDisplay[j];
12612				var aoData = oSettings.aoData[ iDataIndex ];
12613				if ( aoData.nTr === null )
12614				{
12615					_fnCreateTr( oSettings, iDataIndex );
12616				}
12617	
12618				var nRow = aoData.nTr;
12619	
12620				/* Remove the old striping classes and then add the new one */
12621				if ( iStripes !== 0 )
12622				{
12623					var sStripe = asStripeClasses[ iRowCount % iStripes ];
12624					if ( aoData._sRowStripe != sStripe )
12625					{
12626						$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
12627						aoData._sRowStripe = sStripe;
12628					}
12629				}
12630	
12631				// Row callback functions - might want to manipulate the row
12632				// iRowCount and j are not currently documented. Are they at all
12633				// useful?
12634				_fnCallbackFire( oSettings, 'aoRowCallback', null,
12635					[nRow, aoData._aData, iRowCount, j, iDataIndex] );
12636	
12637				anRows.push( nRow );
12638				iRowCount++;
12639			}
12640		}
12641		else
12642		{
12643			/* Table is empty - create a row with an empty message in it */
12644			var sZero = oLang.sZeroRecords;
12645			if ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )
12646			{
12647				sZero = oLang.sLoadingRecords;
12648			}
12649			else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
12650			{
12651				sZero = oLang.sEmptyTable;
12652			}
12653	
12654			anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
12655				.append( $('<td />', {
12656					'valign':  'top',
12657					'colSpan': _fnVisbleColumns( oSettings ),
12658					'class':   oSettings.oClasses.sRowEmpty
12659				} ).html( sZero ) )[0];
12660		}
12661	
12662		/* Header and footer callbacks */
12663		_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
12664			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
12665	
12666		_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
12667			_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
12668	
12669		var body = $(oSettings.nTBody);
12670	
12671		body.children().detach();
12672		body.append( $(anRows) );
12673	
12674		/* Call all required callback functions for the end of a draw */
12675		_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
12676	
12677		/* Draw is complete, sorting and filtering must be as well */
12678		oSettings.bSorted = false;
12679		oSettings.bFiltered = false;
12680		oSettings.bDrawing = false;
12681	}
12682	
12683	
12684	/**
12685	 * Redraw the table - taking account of the various features which are enabled
12686	 *  @param {object} oSettings dataTables settings object
12687	 *  @param {boolean} [holdPosition] Keep the current paging position. By default
12688	 *    the paging is reset to the first page
12689	 *  @memberof DataTable#oApi
12690	 */
12691	function _fnReDraw( settings, holdPosition )
12692	{
12693		var
12694			features = settings.oFeatures,
12695			sort     = features.bSort,
12696			filter   = features.bFilter;
12697	
12698		if ( sort ) {
12699			_fnSort( settings );
12700		}
12701	
12702		if ( filter ) {
12703			_fnFilterComplete( settings, settings.oPreviousSearch );
12704		}
12705		else {
12706			// No filtering, so we want to just use the display master
12707			settings.aiDisplay = settings.aiDisplayMaster.slice();
12708		}
12709	
12710		if ( holdPosition !== true ) {
12711			settings._iDisplayStart = 0;
12712		}
12713	
12714		// Let any modules know about the draw hold position state (used by
12715		// scrolling internally)
12716		settings._drawHold = holdPosition;
12717	
12718		_fnDraw( settings );
12719	
12720		settings._drawHold = false;
12721	}
12722	
12723	
12724	/**
12725	 * Add the options to the page HTML for the table
12726	 *  @param {object} oSettings dataTables settings object
12727	 *  @memberof DataTable#oApi
12728	 */
12729	function _fnAddOptionsHtml ( oSettings )
12730	{
12731		var classes = oSettings.oClasses;
12732		var table = $(oSettings.nTable);
12733		var holding = $('<div/>').insertBefore( table ); // Holding element for speed
12734		var features = oSettings.oFeatures;
12735	
12736		// All DataTables are wrapped in a div
12737		var insert = $('<div/>', {
12738			id:      oSettings.sTableId+'_wrapper',
12739			'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
12740		} );
12741	
12742		oSettings.nHolding = holding[0];
12743		oSettings.nTableWrapper = insert[0];
12744		oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
12745	
12746		/* Loop over the user set positioning and place the elements as needed */
12747		var aDom = oSettings.sDom.split('');
12748		var featureNode, cOption, nNewNode, cNext, sAttr, j;
12749		for ( var i=0 ; i<aDom.length ; i++ )
12750		{
12751			featureNode = null;
12752			cOption = aDom[i];
12753	
12754			if ( cOption == '<' )
12755			{
12756				/* New container div */
12757				nNewNode = $('<div/>')[0];
12758	
12759				/* Check to see if we should append an id and/or a class name to the container */
12760				cNext = aDom[i+1];
12761				if ( cNext == "'" || cNext == '"' )
12762				{
12763					sAttr = "";
12764					j = 2;
12765					while ( aDom[i+j] != cNext )
12766					{
12767						sAttr += aDom[i+j];
12768						j++;
12769					}
12770	
12771					/* Replace jQuery UI constants @todo depreciated */
12772					if ( sAttr == "H" )
12773					{
12774						sAttr = classes.sJUIHeader;
12775					}
12776					else if ( sAttr == "F" )
12777					{
12778						sAttr = classes.sJUIFooter;
12779					}
12780	
12781					/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
12782					 * breaks the string into parts and applies them as needed
12783					 */
12784					if ( sAttr.indexOf('.') != -1 )
12785					{
12786						var aSplit = sAttr.split('.');
12787						nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
12788						nNewNode.className = aSplit[1];
12789					}
12790					else if ( sAttr.charAt(0) == "#" )
12791					{
12792						nNewNode.id = sAttr.substr(1, sAttr.length-1);
12793					}
12794					else
12795					{
12796						nNewNode.className = sAttr;
12797					}
12798	
12799					i += j; /* Move along the position array */
12800				}
12801	
12802				insert.append( nNewNode );
12803				insert = $(nNewNode);
12804			}
12805			else if ( cOption == '>' )
12806			{
12807				/* End container div */
12808				insert = insert.parent();
12809			}
12810			// @todo Move options into their own plugins?
12811			else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
12812			{
12813				/* Length */
12814				featureNode = _fnFeatureHtmlLength( oSettings );
12815			}
12816			else if ( cOption == 'f' && features.bFilter )
12817			{
12818				/* Filter */
12819				featureNode = _fnFeatureHtmlFilter( oSettings );
12820			}
12821			else if ( cOption == 'r' && features.bProcessing )
12822			{
12823				/* pRocessing */
12824				featureNode = _fnFeatureHtmlProcessing( oSettings );
12825			}
12826			else if ( cOption == 't' )
12827			{
12828				/* Table */
12829				featureNode = _fnFeatureHtmlTable( oSettings );
12830			}
12831			else if ( cOption ==  'i' && features.bInfo )
12832			{
12833				/* Info */
12834				featureNode = _fnFeatureHtmlInfo( oSettings );
12835			}
12836			else if ( cOption == 'p' && features.bPaginate )
12837			{
12838				/* Pagination */
12839				featureNode = _fnFeatureHtmlPaginate( oSettings );
12840			}
12841			else if ( DataTable.ext.feature.length !== 0 )
12842			{
12843				/* Plug-in features */
12844				var aoFeatures = DataTable.ext.feature;
12845				for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
12846				{
12847					if ( cOption == aoFeatures[k].cFeature )
12848					{
12849						featureNode = aoFeatures[k].fnInit( oSettings );
12850						break;
12851					}
12852				}
12853			}
12854	
12855			/* Add to the 2D features array */
12856			if ( featureNode )
12857			{
12858				var aanFeatures = oSettings.aanFeatures;
12859	
12860				if ( ! aanFeatures[cOption] )
12861				{
12862					aanFeatures[cOption] = [];
12863				}
12864	
12865				aanFeatures[cOption].push( featureNode );
12866				insert.append( featureNode );
12867			}
12868		}
12869	
12870		/* Built our DOM structure - replace the holding div with what we want */
12871		holding.replaceWith( insert );
12872		oSettings.nHolding = null;
12873	}
12874	
12875	
12876	/**
12877	 * Use the DOM source to create up an array of header cells. The idea here is to
12878	 * create a layout grid (array) of rows x columns, which contains a reference
12879	 * to the cell that that point in the grid (regardless of col/rowspan), such that
12880	 * any column / row could be removed and the new grid constructed
12881	 *  @param array {object} aLayout Array to store the calculated layout in
12882	 *  @param {node} nThead The header/footer element for the table
12883	 *  @memberof DataTable#oApi
12884	 */
12885	function _fnDetectHeader ( aLayout, nThead )
12886	{
12887		var nTrs = $(nThead).children('tr');
12888		var nTr, nCell;
12889		var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
12890		var bUnique;
12891		var fnShiftCol = function ( a, i, j ) {
12892			var k = a[i];
12893	                while ( k[j] ) {
12894				j++;
12895			}
12896			return j;
12897		};
12898	
12899		aLayout.splice( 0, aLayout.length );
12900	
12901		/* We know how many rows there are in the layout - so prep it */
12902		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
12903		{
12904			aLayout.push( [] );
12905		}
12906	
12907		/* Calculate a layout array */
12908		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
12909		{
12910			nTr = nTrs[i];
12911			iColumn = 0;
12912	
12913			/* For every cell in the row... */
12914			nCell = nTr.firstChild;
12915			while ( nCell ) {
12916				if ( nCell.nodeName.toUpperCase() == "TD" ||
12917				     nCell.nodeName.toUpperCase() == "TH" )
12918				{
12919					/* Get the col and rowspan attributes from the DOM and sanitise them */
12920					iColspan = nCell.getAttribute('colspan') * 1;
12921					iRowspan = nCell.getAttribute('rowspan') * 1;
12922					iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
12923					iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
12924	
12925					/* There might be colspan cells already in this row, so shift our target
12926					 * accordingly
12927					 */
12928					iColShifted = fnShiftCol( aLayout, i, iColumn );
12929	
12930					/* Cache calculation for unique columns */
12931					bUnique = iColspan === 1 ? true : false;
12932	
12933					/* If there is col / rowspan, copy the information into the layout grid */
12934					for ( l=0 ; l<iColspan ; l++ )
12935					{
12936						for ( k=0 ; k<iRowspan ; k++ )
12937						{
12938							aLayout[i+k][iColShifted+l] = {
12939								"cell": nCell,
12940								"unique": bUnique
12941							};
12942							aLayout[i+k].nTr = nTr;
12943						}
12944					}
12945				}
12946				nCell = nCell.nextSibling;
12947			}
12948		}
12949	}
12950	
12951	
12952	/**
12953	 * Get an array of unique th elements, one for each column
12954	 *  @param {object} oSettings dataTables settings object
12955	 *  @param {node} nHeader automatically detect the layout from this node - optional
12956	 *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
12957	 *  @returns array {node} aReturn list of unique th's
12958	 *  @memberof DataTable#oApi
12959	 */
12960	function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
12961	{
12962		var aReturn = [];
12963		if ( !aLayout )
12964		{
12965			aLayout = oSettings.aoHeader;
12966			if ( nHeader )
12967			{
12968				aLayout = [];
12969				_fnDetectHeader( aLayout, nHeader );
12970			}
12971		}
12972	
12973		for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
12974		{
12975			for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
12976			{
12977				if ( aLayout[i][j].unique &&
12978					 (!aReturn[j] || !oSettings.bSortCellsTop) )
12979				{
12980					aReturn[j] = aLayout[i][j].cell;
12981				}
12982			}
12983		}
12984	
12985		return aReturn;
12986	}
12987	
12988	/**
12989	 * 
vendor: 47,797 bytes, lines 12989-14636
12989Create an Ajax call based on the table's settings, taking into account that
12990	 * parameters can have multiple forms, and backwards compatibility.
12991	 *
12992	 * @param {object} oSettings dataTables settings object
12993	 * @param {array} data Data to send to the server, required by
12994	 *     DataTables - may be augmented by developer callbacks
12995	 * @param {function} fn Callback function to run when data is obtained
12996	 */
12997	function _fnBuildAjax( oSettings, data, fn )
12998	{
12999		// Compatibility with 1.9-, allow fnServerData and event to manipulate
13000		_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
13001	
13002		// Convert to object based for 1.10+ if using the old array scheme which can
13003		// come from server-side processing or serverParams
13004		if ( data && $.isArray(data) ) {
13005			var tmp = {};
13006			var rbracket = /(.*?)\[\]$/;
13007	
13008			$.each( data, function (key, val) {
13009				var match = val.name.match(rbracket);
13010	
13011				if ( match ) {
13012					// Support for arrays
13013					var name = match[0];
13014	
13015					if ( ! tmp[ name ] ) {
13016						tmp[ name ] = [];
13017					}
13018					tmp[ name ].push( val.value );
13019				}
13020				else {
13021					tmp[val.name] = val.value;
13022				}
13023			} );
13024			data = tmp;
13025		}
13026	
13027		var ajaxData;
13028		var ajax = oSettings.ajax;
13029		var instance = oSettings.oInstance;
13030		var callback = function ( json ) {
13031			_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
13032			fn( json );
13033		};
13034	
13035		if ( $.isPlainObject( ajax ) && ajax.data )
13036		{
13037			ajaxData = ajax.data;
13038	
13039			var newData = typeof ajaxData === 'function' ?
13040				ajaxData( data, oSettings ) :  // fn can manipulate data or return
13041				ajaxData;                      // an object object or array to merge
13042	
13043			// If the function returned something, use that alone
13044			data = typeof ajaxData === 'function' && newData ?
13045				newData :
13046				$.extend( true, data, newData );
13047	
13048			// Remove the data property as we've resolved it already and don't want
13049			// jQuery to do it again (it is restored at the end of the function)
13050			delete ajax.data;
13051		}
13052	
13053		var baseAjax = {
13054			"data": data,
13055			"success": function (json) {
13056				var error = json.error || json.sError;
13057				if ( error ) {
13058					_fnLog( oSettings, 0, error );
13059				}
13060	
13061				oSettings.json = json;
13062				callback( json );
13063			},
13064			"dataType": "json",
13065			"cache": false,
13066			"type": oSettings.sServerMethod,
13067			"error": function (xhr, error, thrown) {
13068				var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
13069	
13070				if ( $.inArray( true, ret ) === -1 ) {
13071					if ( error == "parsererror" ) {
13072						_fnLog( oSettings, 0, 'Invalid JSON response', 1 );
13073					}
13074					else if ( xhr.readyState === 4 ) {
13075						_fnLog( oSettings, 0, 'Ajax error', 7 );
13076					}
13077				}
13078	
13079				_fnProcessingDisplay( oSettings, false );
13080			}
13081		};
13082	
13083		// Store the data submitted for the API
13084		oSettings.oAjaxData = data;
13085	
13086		// Allow plug-ins and external processes to modify the data
13087		_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
13088	
13089		if ( oSettings.fnServerData )
13090		{
13091			// DataTables 1.9- compatibility
13092			oSettings.fnServerData.call( instance,
13093				oSettings.sAjaxSource,
13094				$.map( data, function (val, key) { // Need to convert back to 1.9 trad format
13095					return { name: key, value: val };
13096				} ),
13097				callback,
13098				oSettings
13099			);
13100		}
13101		else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
13102		{
13103			// DataTables 1.9- compatibility
13104			oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
13105				url: ajax || oSettings.sAjaxSource
13106			} ) );
13107		}
13108		else if ( typeof ajax === 'function' )
13109		{
13110			// Is a function - let the caller define what needs to be done
13111			oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
13112		}
13113		else
13114		{
13115			// Object to extend the base settings
13116			oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
13117	
13118			// Restore for next time around
13119			ajax.data = ajaxData;
13120		}
13121	}
13122	
13123	
13124	/**
13125	 * Update the table using an Ajax call
13126	 *  @param {object} settings dataTables settings object
13127	 *  @returns {boolean} Block the table drawing or not
13128	 *  @memberof DataTable#oApi
13129	 */
13130	function _fnAjaxUpdate( settings )
13131	{
13132		if ( settings.bAjaxDataGet ) {
13133			settings.iDraw++;
13134			_fnProcessingDisplay( settings, true );
13135	
13136			_fnBuildAjax(
13137				settings,
13138				_fnAjaxParameters( settings ),
13139				function(json) {
13140					_fnAjaxUpdateDraw( settings, json );
13141				}
13142			);
13143	
13144			return false;
13145		}
13146		return true;
13147	}
13148	
13149	
13150	/**
13151	 * Build up the parameters in an object needed for a server-side processing
13152	 * request. Note that this is basically done twice, is different ways - a modern
13153	 * method which is used by default in DataTables 1.10 which uses objects and
13154	 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
13155	 * the sAjaxSource option is used in the initialisation, or the legacyAjax
13156	 * option is set.
13157	 *  @param {object} oSettings dataTables settings object
13158	 *  @returns {bool} block the table drawing or not
13159	 *  @memberof DataTable#oApi
13160	 */
13161	function _fnAjaxParameters( settings )
13162	{
13163		var
13164			columns = settings.aoColumns,
13165			columnCount = columns.length,
13166			features = settings.oFeatures,
13167			preSearch = settings.oPreviousSearch,
13168			preColSearch = settings.aoPreSearchCols,
13169			i, data = [], dataProp, column, columnSearch,
13170			sort = _fnSortFlatten( settings ),
13171			displayStart = settings._iDisplayStart,
13172			displayLength = features.bPaginate !== false ?
13173				settings._iDisplayLength :
13174				-1;
13175	
13176		var param = function ( name, value ) {
13177			data.push( { 'name': name, 'value': value } );
13178		};
13179	
13180		// DataTables 1.9- compatible method
13181		param( 'sEcho',          settings.iDraw );
13182		param( 'iColumns',       columnCount );
13183		param( 'sColumns',       _pluck( columns, 'sName' ).join(',') );
13184		param( 'iDisplayStart',  displayStart );
13185		param( 'iDisplayLength', displayLength );
13186	
13187		// DataTables 1.10+ method
13188		var d = {
13189			draw:    settings.iDraw,
13190			columns: [],
13191			order:   [],
13192			start:   displayStart,
13193			length:  displayLength,
13194			search:  {
13195				value: preSearch.sSearch,
13196				regex: preSearch.bRegex
13197			}
13198		};
13199	
13200		for ( i=0 ; i<columnCount ; i++ ) {
13201			column = columns[i];
13202			columnSearch = preColSearch[i];
13203			dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
13204	
13205			d.columns.push( {
13206				data:       dataProp,
13207				name:       column.sName,
13208				searchable: column.bSearchable,
13209				orderable:  column.bSortable,
13210				search:     {
13211					value: columnSearch.sSearch,
13212					regex: columnSearch.bRegex
13213				}
13214			} );
13215	
13216			param( "mDataProp_"+i, dataProp );
13217	
13218			if ( features.bFilter ) {
13219				param( 'sSearch_'+i,     columnSearch.sSearch );
13220				param( 'bRegex_'+i,      columnSearch.bRegex );
13221				param( 'bSearchable_'+i, column.bSearchable );
13222			}
13223	
13224			if ( features.bSort ) {
13225				param( 'bSortable_'+i, column.bSortable );
13226			}
13227		}
13228	
13229		if ( features.bFilter ) {
13230			param( 'sSearch', preSearch.sSearch );
13231			param( 'bRegex', preSearch.bRegex );
13232		}
13233	
13234		if ( features.bSort ) {
13235			$.each( sort, function ( i, val ) {
13236				d.order.push( { column: val.col, dir: val.dir } );
13237	
13238				param( 'iSortCol_'+i, val.col );
13239				param( 'sSortDir_'+i, val.dir );
13240			} );
13241	
13242			param( 'iSortingCols', sort.length );
13243		}
13244	
13245		// If the legacy.ajax parameter is null, then we automatically decide which
13246		// form to use, based on sAjaxSource
13247		var legacy = DataTable.ext.legacy.ajax;
13248		if ( legacy === null ) {
13249			return settings.sAjaxSource ? data : d;
13250		}
13251	
13252		// Otherwise, if legacy has been specified then we use that to decide on the
13253		// form
13254		return legacy ? data : d;
13255	}
13256	
13257	
13258	/**
13259	 * Data the data from the server (nuking the old) and redraw the table
13260	 *  @param {object} oSettings dataTables settings object
13261	 *  @param {object} json json data return from the server.
13262	 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
13263	 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
13264	 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
13265	 *  @param {array} json.aaData The data to display on this page
13266	 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
13267	 *  @memberof DataTable#oApi
13268	 */
13269	function _fnAjaxUpdateDraw ( settings, json )
13270	{
13271		// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
13272		// Support both
13273		var compat = function ( old, modern ) {
13274			return json[old] !== undefined ? json[old] : json[modern];
13275		};
13276	
13277		var data = _fnAjaxDataSrc( settings, json );
13278		var draw            = compat( 'sEcho',                'draw' );
13279		var recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );
13280		var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
13281	
13282		if ( draw ) {
13283			// Protect against out of sequence returns
13284			if ( draw*1 < settings.iDraw ) {
13285				return;
13286			}
13287			settings.iDraw = draw * 1;
13288		}
13289	
13290		_fnClearTable( settings );
13291		settings._iRecordsTotal   = parseInt(recordsTotal, 10);
13292		settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
13293	
13294		for ( var i=0, ien=data.length ; i<ien ; i++ ) {
13295			_fnAddData( settings, data[i] );
13296		}
13297		settings.aiDisplay = settings.aiDisplayMaster.slice();
13298	
13299		settings.bAjaxDataGet = false;
13300		_fnDraw( settings );
13301	
13302		if ( ! settings._bInitComplete ) {
13303			_fnInitComplete( settings, json );
13304		}
13305	
13306		settings.bAjaxDataGet = true;
13307		_fnProcessingDisplay( settings, false );
13308	}
13309	
13310	
13311	/**
13312	 * Get the data from the JSON data source to use for drawing a table. Using
13313	 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
13314	 * source object, or from a processing function.
13315	 *  @param {object} oSettings dataTables settings object
13316	 *  @param  {object} json Data source object / array from the server
13317	 *  @return {array} Array of data to use
13318	 */
13319	function _fnAjaxDataSrc ( oSettings, json )
13320	{
13321		var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
13322			oSettings.ajax.dataSrc :
13323			oSettings.sAjaxDataProp; // Compatibility with 1.9-.
13324	
13325		// Compatibility with 1.9-. In order to read from aaData, check if the
13326		// default has been changed, if not, check for aaData
13327		if ( dataSrc === 'data' ) {
13328			return json.aaData || json[dataSrc];
13329		}
13330	
13331		return dataSrc !== "" ?
13332			_fnGetObjectDataFn( dataSrc )( json ) :
13333			json;
13334	}
13335	
13336	/**
13337	 * Generate the node required for filtering text
13338	 *  @returns {node} Filter control element
13339	 *  @param {object} oSettings dataTables settings object
13340	 *  @memberof DataTable#oApi
13341	 */
13342	function _fnFeatureHtmlFilter ( settings )
13343	{
13344		var classes = settings.oClasses;
13345		var tableId = settings.sTableId;
13346		var language = settings.oLanguage;
13347		var previousSearch = settings.oPreviousSearch;
13348		var features = settings.aanFeatures;
13349		var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
13350	
13351		var str = language.sSearch;
13352		str = str.match(/_INPUT_/) ?
13353			str.replace('_INPUT_', input) :
13354			str+input;
13355	
13356		var filter = $('<div/>', {
13357				'id': ! features.f ? tableId+'_filter' : null,
13358				'class': classes.sFilter
13359			} )
13360			.append( $('<label/>' ).append( str ) );
13361	
13362		var searchFn = function() {
13363			/* Update all other filter input elements for the new display */
13364			var n = features.f;
13365			var val = !this.value ? "" : this.value; // mental IE8 fix :-(
13366	
13367			/* Now do the filter */
13368			if ( val != previousSearch.sSearch ) {
13369				_fnFilterComplete( settings, {
13370					"sSearch": val,
13371					"bRegex": previousSearch.bRegex,
13372					"bSmart": previousSearch.bSmart ,
13373					"bCaseInsensitive": previousSearch.bCaseInsensitive
13374				} );
13375	
13376				// Need to redraw, without resorting
13377				settings._iDisplayStart = 0;
13378				_fnDraw( settings );
13379			}
13380		};
13381	
13382		var searchDelay = settings.searchDelay !== null ?
13383			settings.searchDelay :
13384			_fnDataSource( settings ) === 'ssp' ?
13385				400 :
13386				0;
13387	
13388		var jqFilter = $('input', filter)
13389			.val( previousSearch.sSearch )
13390			.attr( 'placeholder', language.sSearchPlaceholder )
13391			.on(
13392				'keyup.DT search.DT input.DT paste.DT cut.DT',
13393				searchDelay ?
13394					_fnThrottle( searchFn, searchDelay ) :
13395					searchFn
13396			)
13397			.on( 'keypress.DT', function(e) {
13398				/* Prevent form submission */
13399				if ( e.keyCode == 13 ) {
13400					return false;
13401				}
13402			} )
13403			.attr('aria-controls', tableId);
13404	
13405		// Update the input elements whenever the table is filtered
13406		$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
13407			if ( settings === s ) {
13408				// IE9 throws an 'unknown error' if document.activeElement is used
13409				// inside an iframe or frame...
13410				try {
13411					if ( jqFilter[0] !== document.activeElement ) {
13412						jqFilter.val( previousSearch.sSearch );
13413					}
13414				}
13415				catch ( e ) {}
13416			}
13417		} );
13418	
13419		return filter[0];
13420	}
13421	
13422	
13423	/**
13424	 * Filter the table using both the global filter and column based filtering
13425	 *  @param {object} oSettings dataTables settings object
13426	 *  @param {object} oSearch search information
13427	 *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
13428	 *  @memberof DataTable#oApi
13429	 */
13430	function _fnFilterComplete ( oSettings, oInput, iForce )
13431	{
13432		var oPrevSearch = oSettings.oPreviousSearch;
13433		var aoPrevSearch = oSettings.aoPreSearchCols;
13434		var fnSaveFilter = function ( oFilter ) {
13435			/* Save the filtering values */
13436			oPrevSearch.sSearch = oFilter.sSearch;
13437			oPrevSearch.bRegex = oFilter.bRegex;
13438			oPrevSearch.bSmart = oFilter.bSmart;
13439			oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
13440		};
13441		var fnRegex = function ( o ) {
13442			// Backwards compatibility with the bEscapeRegex option
13443			return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
13444		};
13445	
13446		// Resolve any column types that are unknown due to addition or invalidation
13447		// @todo As per sort - can this be moved into an event handler?
13448		_fnColumnTypes( oSettings );
13449	
13450		/* In server-side processing all filtering is done by the server, so no point hanging around here */
13451		if ( _fnDataSource( oSettings ) != 'ssp' )
13452		{
13453			/* Global filter */
13454			_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
13455			fnSaveFilter( oInput );
13456	
13457			/* Now do the individual column filter */
13458			for ( var i=0 ; i<aoPrevSearch.length ; i++ )
13459			{
13460				_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
13461					aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
13462			}
13463	
13464			/* Custom filtering */
13465			_fnFilterCustom( oSettings );
13466		}
13467		else
13468		{
13469			fnSaveFilter( oInput );
13470		}
13471	
13472		/* Tell the draw function we have been filtering */
13473		oSettings.bFiltered = true;
13474		_fnCallbackFire( oSettings, null, 'search', [oSettings] );
13475	}
13476	
13477	
13478	/**
13479	 * Apply custom filtering functions
13480	 *  @param {object} oSettings dataTables settings object
13481	 *  @memberof DataTable#oApi
13482	 */
13483	function _fnFilterCustom( settings )
13484	{
13485		var filters = DataTable.ext.search;
13486		var displayRows = settings.aiDisplay;
13487		var row, rowIdx;
13488	
13489		for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
13490			var rows = [];
13491	
13492			// Loop over each row and see if it should be included
13493			for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
13494				rowIdx = displayRows[ j ];
13495				row = settings.aoData[ rowIdx ];
13496	
13497				if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
13498					rows.push( rowIdx );
13499				}
13500			}
13501	
13502			// So the array reference doesn't break set the results into the
13503			// existing array
13504			displayRows.length = 0;
13505			$.merge( displayRows, rows );
13506		}
13507	}
13508	
13509	
13510	/**
13511	 * Filter the table on a per-column basis
13512	 *  @param {object} oSettings dataTables settings object
13513	 *  @param {string} sInput string to filter on
13514	 *  @param {int} iColumn column to filter
13515	 *  @param {bool} bRegex treat search string as a regular expression or not
13516	 *  @param {bool} bSmart use smart filtering or not
13517	 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
13518	 *  @memberof DataTable#oApi
13519	 */
13520	function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
13521	{
13522		if ( searchStr === '' ) {
13523			return;
13524		}
13525	
13526		var data;
13527		var out = [];
13528		var display = settings.aiDisplay;
13529		var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
13530	
13531		for ( var i=0 ; i<display.length ; i++ ) {
13532			data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
13533	
13534			if ( rpSearch.test( data ) ) {
13535				out.push( display[i] );
13536			}
13537		}
13538	
13539		settings.aiDisplay = out;
13540	}
13541	
13542	
13543	/**
13544	 * Filter the data table based on user input and draw the table
13545	 *  @param {object} settings dataTables settings object
13546	 *  @param {string} input string to filter on
13547	 *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
13548	 *  @param {bool} regex treat as a regular expression or not
13549	 *  @param {bool} smart perform smart filtering or not
13550	 *  @param {bool} caseInsensitive Do case insenstive matching or not
13551	 *  @memberof DataTable#oApi
13552	 */
13553	function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
13554	{
13555		var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
13556		var prevSearch = settings.oPreviousSearch.sSearch;
13557		var displayMaster = settings.aiDisplayMaster;
13558		var display, invalidated, i;
13559		var filtered = [];
13560	
13561		// Need to take account of custom filtering functions - always filter
13562		if ( DataTable.ext.search.length !== 0 ) {
13563			force = true;
13564		}
13565	
13566		// Check if any of the rows were invalidated
13567		invalidated = _fnFilterData( settings );
13568	
13569		// If the input is blank - we just want the full data set
13570		if ( input.length <= 0 ) {
13571			settings.aiDisplay = displayMaster.slice();
13572		}
13573		else {
13574			// New search - start from the master array
13575			if ( invalidated ||
13576				 force ||
13577				 prevSearch.length > input.length ||
13578				 input.indexOf(prevSearch) !== 0 ||
13579				 settings.bSorted // On resort, the display master needs to be
13580				                  // re-filtered since indexes will have changed
13581			) {
13582				settings.aiDisplay = displayMaster.slice();
13583			}
13584	
13585			// Search the display array
13586			display = settings.aiDisplay;
13587	
13588			for ( i=0 ; i<display.length ; i++ ) {
13589				if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
13590					filtered.push( display[i] );
13591				}
13592			}
13593	
13594			settings.aiDisplay = filtered;
13595		}
13596	}
13597	
13598	
13599	/**
13600	 * Build a regular expression object suitable for searching a table
13601	 *  @param {string} sSearch string to search for
13602	 *  @param {bool} bRegex treat as a regular expression or not
13603	 *  @param {bool} bSmart perform smart filtering or not
13604	 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
13605	 *  @returns {RegExp} constructed object
13606	 *  @memberof DataTable#oApi
13607	 */
13608	function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
13609	{
13610		search = regex ?
13611			search :
13612			_fnEscapeRegex( search );
13613		
13614		if ( smart ) {
13615			/* For smart filtering we want to allow the search to work regardless of
13616			 * word order. We also want double quoted text to be preserved, so word
13617			 * order is important - a la google. So this is what we want to
13618			 * generate:
13619			 * 
13620			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
13621			 */
13622			var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
13623				if ( word.charAt(0) === '"' ) {
13624					var m = word.match( /^"(.*)"$/ );
13625					word = m ? m[1] : word;
13626				}
13627	
13628				return word.replace('"', '');
13629			} );
13630	
13631			search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
13632		}
13633	
13634		return new RegExp( search, caseInsensitive ? 'i' : '' );
13635	}
13636	
13637	
13638	/**
13639	 * Escape a string such that it can be used in a regular expression
13640	 *  @param {string} sVal string to escape
13641	 *  @returns {string} escaped string
13642	 *  @memberof DataTable#oApi
13643	 */
13644	var _fnEscapeRegex = DataTable.util.escapeRegex;
13645	
13646	var __filter_div = $('<div>')[0];
13647	var __filter_div_textContent = __filter_div.textContent !== undefined;
13648	
13649	// Update the filtering data for each row if needed (by invalidation or first run)
13650	function _fnFilterData ( settings )
13651	{
13652		var columns = settings.aoColumns;
13653		var column;
13654		var i, j, ien, jen, filterData, cellData, row;
13655		var fomatters = DataTable.ext.type.search;
13656		var wasInvalidated = false;
13657	
13658		for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
13659			row = settings.aoData[i];
13660	
13661			if ( ! row._aFilterData ) {
13662				filterData = [];
13663	
13664				for ( j=0, jen=columns.length ; j<jen ; j++ ) {
13665					column = columns[j];
13666	
13667					if ( column.bSearchable ) {
13668						cellData = _fnGetCellData( settings, i, j, 'filter' );
13669	
13670						if ( fomatters[ column.sType ] ) {
13671							cellData = fomatters[ column.sType ]( cellData );
13672						}
13673	
13674						// Search in DataTables 1.10 is string based. In 1.11 this
13675						// should be altered to also allow strict type checking.
13676						if ( cellData === null ) {
13677							cellData = '';
13678						}
13679	
13680						if ( typeof cellData !== 'string' && cellData.toString ) {
13681							cellData = cellData.toString();
13682						}
13683					}
13684					else {
13685						cellData = '';
13686					}
13687	
13688					// If it looks like there is an HTML entity in the string,
13689					// attempt to decode it so sorting works as expected. Note that
13690					// we could use a single line of jQuery to do this, but the DOM
13691					// method used here is much faster http://jsperf.com/html-decode
13692					if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
13693						__filter_div.innerHTML = cellData;
13694						cellData = __filter_div_textContent ?
13695							__filter_div.textContent :
13696							__filter_div.innerText;
13697					}
13698	
13699					if ( cellData.replace ) {
13700						cellData = cellData.replace(/[\r\n]/g, '');
13701					}
13702	
13703					filterData.push( cellData );
13704				}
13705	
13706				row._aFilterData = filterData;
13707				row._sFilterRow = filterData.join('  ');
13708				wasInvalidated = true;
13709			}
13710		}
13711	
13712		return wasInvalidated;
13713	}
13714	
13715	
13716	/**
13717	 * Convert from the internal Hungarian notation to camelCase for external
13718	 * interaction
13719	 *  @param {object} obj Object to convert
13720	 *  @returns {object} Inverted object
13721	 *  @memberof DataTable#oApi
13722	 */
13723	function _fnSearchToCamel ( obj )
13724	{
13725		return {
13726			search:          obj.sSearch,
13727			smart:           obj.bSmart,
13728			regex:           obj.bRegex,
13729			caseInsensitive: obj.bCaseInsensitive
13730		};
13731	}
13732	
13733	
13734	
13735	/**
13736	 * Convert from camelCase notation to the internal Hungarian. We could use the
13737	 * Hungarian convert function here, but this is cleaner
13738	 *  @param {object} obj Object to convert
13739	 *  @returns {object} Inverted object
13740	 *  @memberof DataTable#oApi
13741	 */
13742	function _fnSearchToHung ( obj )
13743	{
13744		return {
13745			sSearch:          obj.search,
13746			bSmart:           obj.smart,
13747			bRegex:           obj.regex,
13748			bCaseInsensitive: obj.caseInsensitive
13749		};
13750	}
13751	
13752	/**
13753	 * Generate the node required for the info display
13754	 *  @param {object} oSettings dataTables settings object
13755	 *  @returns {node} Information element
13756	 *  @memberof DataTable#oApi
13757	 */
13758	function _fnFeatureHtmlInfo ( settings )
13759	{
13760		var
13761			tid = settings.sTableId,
13762			nodes = settings.aanFeatures.i,
13763			n = $('<div/>', {
13764				'class': settings.oClasses.sInfo,
13765				'id': ! nodes ? tid+'_info' : null
13766			} );
13767	
13768		if ( ! nodes ) {
13769			// Update display on each draw
13770			settings.aoDrawCallback.push( {
13771				"fn": _fnUpdateInfo,
13772				"sName": "information"
13773			} );
13774	
13775			n
13776				.attr( 'role', 'status' )
13777				.attr( 'aria-live', 'polite' );
13778	
13779			// Table is described by our info div
13780			$(settings.nTable).attr( 'aria-describedby', tid+'_info' );
13781		}
13782	
13783		return n[0];
13784	}
13785	
13786	
13787	/**
13788	 * Update the information elements in the display
13789	 *  @param {object} settings dataTables settings object
13790	 *  @memberof DataTable#oApi
13791	 */
13792	function _fnUpdateInfo ( settings )
13793	{
13794		/* Show information about the table */
13795		var nodes = settings.aanFeatures.i;
13796		if ( nodes.length === 0 ) {
13797			return;
13798		}
13799	
13800		var
13801			lang  = settings.oLanguage,
13802			start = settings._iDisplayStart+1,
13803			end   = settings.fnDisplayEnd(),
13804			max   = settings.fnRecordsTotal(),
13805			total = settings.fnRecordsDisplay(),
13806			out   = total ?
13807				lang.sInfo :
13808				lang.sInfoEmpty;
13809	
13810		if ( total !== max ) {
13811			/* Record set after filtering */
13812			out += ' ' + lang.sInfoFiltered;
13813		}
13814	
13815		// Convert the macros
13816		out += lang.sInfoPostFix;
13817		out = _fnInfoMacros( settings, out );
13818	
13819		var callback = lang.fnInfoCallback;
13820		if ( callback !== null ) {
13821			out = callback.call( settings.oInstance,
13822				settings, start, end, max, total, out
13823			);
13824		}
13825	
13826		$(nodes).html( out );
13827	}
13828	
13829	
13830	function _fnInfoMacros ( settings, str )
13831	{
13832		// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
13833		// internally
13834		var
13835			formatter  = settings.fnFormatNumber,
13836			start      = settings._iDisplayStart+1,
13837			len        = settings._iDisplayLength,
13838			vis        = settings.fnRecordsDisplay(),
13839			all        = len === -1;
13840	
13841		return str.
13842			replace(/_START_/g, formatter.call( settings, start ) ).
13843			replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
13844			replace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).
13845			replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
13846			replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
13847			replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
13848	}
13849	
13850	
13851	
13852	/**
13853	 * Draw the table for the first time, adding all required features
13854	 *  @param {object} settings dataTables settings object
13855	 *  @memberof DataTable#oApi
13856	 */
13857	function _fnInitialise ( settings )
13858	{
13859		var i, iLen, iAjaxStart=settings.iInitDisplayStart;
13860		var columns = settings.aoColumns, column;
13861		var features = settings.oFeatures;
13862		var deferLoading = settings.bDeferLoading; // value modified by the draw
13863	
13864		/* Ensure that the table data is fully initialised */
13865		if ( ! settings.bInitialised ) {
13866			setTimeout( function(){ _fnInitialise( settings ); }, 200 );
13867			return;
13868		}
13869	
13870		/* Show the display HTML options */
13871		_fnAddOptionsHtml( settings );
13872	
13873		/* Build and draw the header / footer for the table */
13874		_fnBuildHead( settings );
13875		_fnDrawHead( settings, settings.aoHeader );
13876		_fnDrawHead( settings, settings.aoFooter );
13877	
13878		/* Okay to show that something is going on now */
13879		_fnProcessingDisplay( settings, true );
13880	
13881		/* Calculate sizes for columns */
13882		if ( features.bAutoWidth ) {
13883			_fnCalculateColumnWidths( settings );
13884		}
13885	
13886		for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
13887			column = columns[i];
13888	
13889			if ( column.sWidth ) {
13890				column.nTh.style.width = _fnStringToCss( column.sWidth );
13891			}
13892		}
13893	
13894		_fnCallbackFire( settings, null, 'preInit', [settings] );
13895	
13896		// If there is default sorting required - let's do it. The sort function
13897		// will do the drawing for us. Otherwise we draw the table regardless of the
13898		// Ajax source - this allows the table to look initialised for Ajax sourcing
13899		// data (show 'loading' message possibly)
13900		_fnReDraw( settings );
13901	
13902		// Server-side processing init complete is done by _fnAjaxUpdateDraw
13903		var dataSrc = _fnDataSource( settings );
13904		if ( dataSrc != 'ssp' || deferLoading ) {
13905			// if there is an ajax source load the data
13906			if ( dataSrc == 'ajax' ) {
13907				_fnBuildAjax( settings, [], function(json) {
13908					var aData = _fnAjaxDataSrc( settings, json );
13909	
13910					// Got the data - add it to the table
13911					for ( i=0 ; i<aData.length ; i++ ) {
13912						_fnAddData( settings, aData[i] );
13913					}
13914	
13915					// Reset the init display for cookie saving. We've already done
13916					// a filter, and therefore cleared it before. So we need to make
13917					// it appear 'fresh'
13918					settings.iInitDisplayStart = iAjaxStart;
13919	
13920					_fnReDraw( settings );
13921	
13922					_fnProcessingDisplay( settings, false );
13923					_fnInitComplete( settings, json );
13924				}, settings );
13925			}
13926			else {
13927				_fnProcessingDisplay( settings, false );
13928				_fnInitComplete( settings );
13929			}
13930		}
13931	}
13932	
13933	
13934	/**
13935	 * Draw the table for the first time, adding all required features
13936	 *  @param {object} oSettings dataTables settings object
13937	 *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
13938	 *    with client-side processing (optional)
13939	 *  @memberof DataTable#oApi
13940	 */
13941	function _fnInitComplete ( settings, json )
13942	{
13943		settings._bInitComplete = true;
13944	
13945		// When data was added after the initialisation (data or Ajax) we need to
13946		// calculate the column sizing
13947		if ( json || settings.oInit.aaData ) {
13948			_fnAdjustColumnSizing( settings );
13949		}
13950	
13951		_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
13952		_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
13953	}
13954	
13955	
13956	function _fnLengthChange ( settings, val )
13957	{
13958		var len = parseInt( val, 10 );
13959		settings._iDisplayLength = len;
13960	
13961		_fnLengthOverflow( settings );
13962	
13963		// Fire length change event
13964		_fnCallbackFire( settings, null, 'length', [settings, len] );
13965	}
13966	
13967	
13968	/**
13969	 * Generate the node required for user display length changing
13970	 *  @param {object} settings dataTables settings object
13971	 *  @returns {node} Display length feature node
13972	 *  @memberof DataTable#oApi
13973	 */
13974	function _fnFeatureHtmlLength ( settings )
13975	{
13976		var
13977			classes  = settings.oClasses,
13978			tableId  = settings.sTableId,
13979			menu     = settings.aLengthMenu,
13980			d2       = $.isArray( menu[0] ),
13981			lengths  = d2 ? menu[0] : menu,
13982			language = d2 ? menu[1] : menu;
13983	
13984		var select = $('<select/>', {
13985			'name':          tableId+'_length',
13986			'aria-controls': tableId,
13987			'class':         classes.sLengthSelect
13988		} );
13989	
13990		for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
13991			select[0][ i ] = new Option(
13992				typeof language[i] === 'number' ?
13993					settings.fnFormatNumber( language[i] ) :
13994					language[i],
13995				lengths[i]
13996			);
13997		}
13998	
13999		var div = $('<div><label/></div>').addClass( classes.sLength );
14000		if ( ! settings.aanFeatures.l ) {
14001			div[0].id = tableId+'_length';
14002		}
14003	
14004		div.children().append(
14005			settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
14006		);
14007	
14008		// Can't use `select` variable as user might provide their own and the
14009		// reference is broken by the use of outerHTML
14010		$('select', div)
14011			.val( settings._iDisplayLength )
14012			.on( 'change.DT', function(e) {
14013				_fnLengthChange( settings, $(this).val() );
14014				_fnDraw( settings );
14015			} );
14016	
14017		// Update node value whenever anything changes the table's length
14018		$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
14019			if ( settings === s ) {
14020				$('select', div).val( len );
14021			}
14022		} );
14023	
14024		return div[0];
14025	}
14026	
14027	
14028	
14029	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
14030	 * Note that most of the paging logic is done in
14031	 * DataTable.ext.pager
14032	 */
14033	
14034	/**
14035	 * Generate the node required for default pagination
14036	 *  @param {object} oSettings dataTables settings object
14037	 *  @returns {node} Pagination feature node
14038	 *  @memberof DataTable#oApi
14039	 */
14040	function _fnFeatureHtmlPaginate ( settings )
14041	{
14042		var
14043			type   = settings.sPaginationType,
14044			plugin = DataTable.ext.pager[ type ],
14045			modern = typeof plugin === 'function',
14046			redraw = function( settings ) {
14047				_fnDraw( settings );
14048			},
14049			node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
14050			features = settings.aanFeatures;
14051	
14052		if ( ! modern ) {
14053			plugin.fnInit( settings, node, redraw );
14054		}
14055	
14056		/* Add a draw callback for the pagination on first instance, to update the paging display */
14057		if ( ! features.p )
14058		{
14059			node.id = settings.sTableId+'_paginate';
14060	
14061			settings.aoDrawCallback.push( {
14062				"fn": function( settings ) {
14063					if ( modern ) {
14064						var
14065							start      = settings._iDisplayStart,
14066							len        = settings._iDisplayLength,
14067							visRecords = settings.fnRecordsDisplay(),
14068							all        = len === -1,
14069							page = all ? 0 : Math.ceil( start / len ),
14070							pages = all ? 1 : Math.ceil( visRecords / len ),
14071							buttons = plugin(page, pages),
14072							i, ien;
14073	
14074						for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
14075							_fnRenderer( settings, 'pageButton' )(
14076								settings, features.p[i], i, buttons, page, pages
14077							);
14078						}
14079					}
14080					else {
14081						plugin.fnUpdate( settings, redraw );
14082					}
14083				},
14084				"sName": "pagination"
14085			} );
14086		}
14087	
14088		return node;
14089	}
14090	
14091	
14092	/**
14093	 * Alter the display settings to change the page
14094	 *  @param {object} settings DataTables settings object
14095	 *  @param {string|int} action Paging action to take: "first", "previous",
14096	 *    "next" or "last" or page number to jump to (integer)
14097	 *  @param [bool] redraw Automatically draw the update or not
14098	 *  @returns {bool} true page has changed, false - no change
14099	 *  @memberof DataTable#oApi
14100	 */
14101	function _fnPageChange ( settings, action, redraw )
14102	{
14103		var
14104			start     = settings._iDisplayStart,
14105			len       = settings._iDisplayLength,
14106			records   = settings.fnRecordsDisplay();
14107	
14108		if ( records === 0 || len === -1 )
14109		{
14110			start = 0;
14111		}
14112		else if ( typeof action === "number" )
14113		{
14114			start = action * len;
14115	
14116			if ( start > records )
14117			{
14118				start = 0;
14119			}
14120		}
14121		else if ( action == "first" )
14122		{
14123			start = 0;
14124		}
14125		else if ( action == "previous" )
14126		{
14127			start = len >= 0 ?
14128				start - len :
14129				0;
14130	
14131			if ( start < 0 )
14132			{
14133			  start = 0;
14134			}
14135		}
14136		else if ( action == "next" )
14137		{
14138			if ( start + len < records )
14139			{
14140				start += len;
14141			}
14142		}
14143		else if ( action == "last" )
14144		{
14145			start = Math.floor( (records-1) / len) * len;
14146		}
14147		else
14148		{
14149			_fnLog( settings, 0, "Unknown paging action: "+action, 5 );
14150		}
14151	
14152		var changed = settings._iDisplayStart !== start;
14153		settings._iDisplayStart = start;
14154	
14155		if ( changed ) {
14156			_fnCallbackFire( settings, null, 'page', [settings] );
14157	
14158			if ( redraw ) {
14159				_fnDraw( settings );
14160			}
14161		}
14162	
14163		return changed;
14164	}
14165	
14166	
14167	
14168	/**
14169	 * Generate the node required for the processing node
14170	 *  @param {object} settings dataTables settings object
14171	 *  @returns {node} Processing element
14172	 *  @memberof DataTable#oApi
14173	 */
14174	function _fnFeatureHtmlProcessing ( settings )
14175	{
14176		return $('<div/>', {
14177				'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
14178				'class': settings.oClasses.sProcessing
14179			} )
14180			.html( settings.oLanguage.sProcessing )
14181			.insertBefore( settings.nTable )[0];
14182	}
14183	
14184	
14185	/**
14186	 * Display or hide the processing indicator
14187	 *  @param {object} settings dataTables settings object
14188	 *  @param {bool} show Show the processing indicator (true) or not (false)
14189	 *  @memberof DataTable#oApi
14190	 */
14191	function _fnProcessingDisplay ( settings, show )
14192	{
14193		if ( settings.oFeatures.bProcessing ) {
14194			$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
14195		}
14196	
14197		_fnCallbackFire( settings, null, 'processing', [settings, show] );
14198	}
14199	
14200	/**
14201	 * Add any control elements for the table - specifically scrolling
14202	 *  @param {object} settings dataTables settings object
14203	 *  @returns {node} Node to add to the DOM
14204	 *  @memberof DataTable#oApi
14205	 */
14206	function _fnFeatureHtmlTable ( settings )
14207	{
14208		var table = $(settings.nTable);
14209	
14210		// Add the ARIA grid role to the table
14211		table.attr( 'role', 'grid' );
14212	
14213		// Scrolling from here on in
14214		var scroll = settings.oScroll;
14215	
14216		if ( scroll.sX === '' && scroll.sY === '' ) {
14217			return settings.nTable;
14218		}
14219	
14220		var scrollX = scroll.sX;
14221		var scrollY = scroll.sY;
14222		var classes = settings.oClasses;
14223		var caption = table.children('caption');
14224		var captionSide = caption.length ? caption[0]._captionSide : null;
14225		var headerClone = $( table[0].cloneNode(false) );
14226		var footerClone = $( table[0].cloneNode(false) );
14227		var footer = table.children('tfoot');
14228		var _div = '<div/>';
14229		var size = function ( s ) {
14230			return !s ? null : _fnStringToCss( s );
14231		};
14232	
14233		if ( ! footer.length ) {
14234			footer = null;
14235		}
14236	
14237		/*
14238		 * The HTML structure that we want to generate in this function is:
14239		 *  div - scroller
14240		 *    div - scroll head
14241		 *      div - scroll head inner
14242		 *        table - scroll head table
14243		 *          thead - thead
14244		 *    div - scroll body
14245		 *      table - table (master table)
14246		 *        thead - thead clone for sizing
14247		 *        tbody - tbody
14248		 *    div - scroll foot
14249		 *      div - scroll foot inner
14250		 *        table - scroll foot table
14251		 *          tfoot - tfoot
14252		 */
14253		var scroller = $( _div, { 'class': classes.sScrollWrapper } )
14254			.append(
14255				$(_div, { 'class': classes.sScrollHead } )
14256					.css( {
14257						overflow: 'hidden',
14258						position: 'relative',
14259						border: 0,
14260						width: scrollX ? size(scrollX) : '100%'
14261					} )
14262					.append(
14263						$(_div, { 'class': classes.sScrollHeadInner } )
14264							.css( {
14265								'box-sizing': 'content-box',
14266								width: scroll.sXInner || '100%'
14267							} )
14268							.append(
14269								headerClone
14270									.removeAttr('id')
14271									.css( 'margin-left', 0 )
14272									.append( captionSide === 'top' ? caption : null )
14273									.append(
14274										table.children('thead')
14275									)
14276							)
14277					)
14278			)
14279			.append(
14280				$(_div, { 'class': classes.sScrollBody } )
14281					.css( {
14282						position: 'relative',
14283						overflow: 'auto',
14284						width: size( scrollX )
14285					} )
14286					.append( table )
14287			);
14288	
14289		if ( footer ) {
14290			scroller.append(
14291				$(_div, { 'class': classes.sScrollFoot } )
14292					.css( {
14293						overflow: 'hidden',
14294						border: 0,
14295						width: scrollX ? size(scrollX) : '100%'
14296					} )
14297					.append(
14298						$(_div, { 'class': classes.sScrollFootInner } )
14299							.append(
14300								footerClone
14301									.removeAttr('id')
14302									.css( 'margin-left', 0 )
14303									.append( captionSide === 'bottom' ? caption : null )
14304									.append(
14305										table.children('tfoot')
14306									)
14307							)
14308					)
14309			);
14310		}
14311	
14312		var children = scroller.children();
14313		var scrollHead = children[0];
14314		var scrollBody = children[1];
14315		var scrollFoot = footer ? children[2] : null;
14316	
14317		// When the body is scrolled, then we also want to scroll the headers
14318		if ( scrollX ) {
14319			$(scrollBody).on( 'scroll.DT', function (e) {
14320				var scrollLeft = this.scrollLeft;
14321	
14322				scrollHead.scrollLeft = scrollLeft;
14323	
14324				if ( footer ) {
14325					scrollFoot.scrollLeft = scrollLeft;
14326				}
14327			} );
14328		}
14329	
14330		$(scrollBody).css(
14331			scrollY && scroll.bCollapse ? 'max-height' : 'height', 
14332			scrollY
14333		);
14334	
14335		settings.nScrollHead = scrollHead;
14336		settings.nScrollBody = scrollBody;
14337		settings.nScrollFoot = scrollFoot;
14338	
14339		// On redraw - align columns
14340		settings.aoDrawCallback.push( {
14341			"fn": _fnScrollDraw,
14342			"sName": "scrolling"
14343		} );
14344	
14345		return scroller[0];
14346	}
14347	
14348	
14349	
14350	/**
14351	 * Update the header, footer and body tables for resizing - i.e. column
14352	 * alignment.
14353	 *
14354	 * Welcome to the most horrible function DataTables. The process that this
14355	 * function follows is basically:
14356	 *   1. Re-create the table inside the scrolling div
14357	 *   2. Take live measurements from the DOM
14358	 *   3. Apply the measurements to align the columns
14359	 *   4. Clean up
14360	 *
14361	 *  @param {object} settings dataTables settings object
14362	 *  @memberof DataTable#oApi
14363	 */
14364	function _fnScrollDraw ( settings )
14365	{
14366		// Given that this is such a monster function, a lot of variables are use
14367		// to try and keep the minimised size as small as possible
14368		var
14369			scroll         = settings.oScroll,
14370			scrollX        = scroll.sX,
14371			scrollXInner   = scroll.sXInner,
14372			scrollY        = scroll.sY,
14373			barWidth       = scroll.iBarWidth,
14374			divHeader      = $(settings.nScrollHead);
14375
14376        // OVERRIDE
14377        // prevent error if divHeader still not existing
14378        // to let next js run smoothly 
14379        if ('undefined' == typeof divHeader[0])
14380            return;
14381
14382        var
14383			divHeaderStyle = divHeader[0].style,
14384			divHeaderInner = divHeader.children('div'),
14385			divHeaderInnerStyle = divHeaderInner[0].style,
14386			divHeaderTable = divHeaderInner.children('table'),
14387			divBodyEl      = settings.nScrollBody,
14388			divBody        = $(divBodyEl),
14389			divBodyStyle   = divBodyEl.style,
14390			divFooter      = $(settings.nScrollFoot),
14391			divFooterInner = divFooter.children('div'),
14392			divFooterTable = divFooterInner.children('table'),
14393			header         = $(settings.nTHead),
14394			table          = $(settings.nTable),
14395			tableEl        = table[0],
14396			tableStyle     = tableEl.style,
14397			footer         = settings.nTFoot ? $(settings.nTFoot) : null,
14398			browser        = settings.oBrowser,
14399			ie67           = browser.bScrollOversize,
14400			dtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),
14401			headerTrgEls, footerTrgEls,
14402			headerSrcEls, footerSrcEls,
14403			headerCopy, footerCopy,
14404			headerWidths=[], footerWidths=[],
14405			headerContent=[], footerContent=[],
14406			idx, correction, sanityWidth,
14407			zeroOut = function(nSizer) {
14408				var style = nSizer.style;
14409				style.paddingTop = "0";
14410				style.paddingBottom = "0";
14411				style.borderTopWidth = "0";
14412				style.borderBottomWidth = "0";
14413				style.height = 0;
14414			};
14415	
14416		// If the scrollbar visibility has changed from the last draw, we need to
14417		// adjust the column sizes as the table width will have changed to account
14418		// for the scrollbar
14419		var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
14420		
14421		if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
14422			settings.scrollBarVis = scrollBarVis;
14423			_fnAdjustColumnSizing( settings );
14424			return; // adjust column sizing will call this function again
14425		}
14426		else {
14427			settings.scrollBarVis = scrollBarVis;
14428		}
14429	
14430		/*
14431		 * 1. Re-create the table inside the scrolling div
14432		 */
14433	
14434		// Remove the old minimised thead and tfoot elements in the inner table
14435		table.children('thead, tfoot').remove();
14436	
14437		if ( footer ) {
14438			footerCopy = footer.clone().prependTo( table );
14439			footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
14440			footerSrcEls = footerCopy.find('tr');
14441		}
14442	
14443		// Clone the current header and footer elements and then place it into the inner table
14444		headerCopy = header.clone().prependTo( table );
14445		headerTrgEls = header.find('tr'); // original header is in its own table
14446		headerSrcEls = headerCopy.find('tr');
14447		headerCopy.find('th, td').removeAttr('tabindex');
14448	
14449	
14450		/*
14451		 * 2. Take live measurements from the DOM - do not alter the DOM itself!
14452		 */
14453	
14454		// Remove old sizing and apply the calculated column widths
14455		// Get the unique column headers in the newly created (cloned) header. We want to apply the
14456		// calculated sizes to this header
14457		if ( ! scrollX )
14458		{
14459			divBodyStyle.width = '100%';
14460			divHeader[0].style.width = '100%';
14461		}
14462	
14463		$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
14464			idx = _fnVisibleToColumnIndex( settings, i );
14465			el.style.width = settings.aoColumns[idx].sWidth;
14466		} );
14467	
14468		if ( footer ) {
14469			_fnApplyToChildren( function(n) {
14470				n.style.width = "";
14471			}, footerSrcEls );
14472		}
14473	
14474		// Size the table as a whole
14475		sanityWidth = table.outerWidth();
14476		if ( scrollX === "" ) {
14477			// No x scrolling
14478			tableStyle.width = "100%";
14479	
14480			// IE7 will make the width of the table when 100% include the scrollbar
14481			// - which is shouldn't. When there is a scrollbar we need to take this
14482			// into account.
14483			if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
14484				divBody.css('overflow-y') == "scroll")
14485			) {
14486				tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
14487			}
14488	
14489			// Recalculate the sanity width
14490			sanityWidth = table.outerWidth();
14491		}
14492		else if ( scrollXInner !== "" ) {
14493			// legacy x scroll inner has been given - use it
14494			tableStyle.width = _fnStringToCss(scrollXInner);
14495	
14496			// Recalculate the sanity width
14497			sanityWidth = table.outerWidth();
14498		}
14499	
14500		// Hidden header should have zero height, so remove padding and borders. Then
14501		// set the width based on the real headers
14502	
14503		// Apply all styles in one pass
14504		_fnApplyToChildren( zeroOut, headerSrcEls );
14505	
14506		// Read all widths in next pass
14507		_fnApplyToChildren( function(nSizer) {
14508			headerContent.push( nSizer.innerHTML );
14509			headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
14510		}, headerSrcEls );
14511	
14512		// Apply all widths in final pass
14513		_fnApplyToChildren( function(nToSize, i) {
14514			// Only apply widths to the DataTables detected header cells - this
14515			// prevents complex headers from having contradictory sizes applied
14516			if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
14517				nToSize.style.width = headerWidths[i];
14518			}
14519		}, headerTrgEls );
14520	
14521		$(headerSrcEls).height(0);
14522	
14523		/* Same again with the footer if we have one */
14524		if ( footer )
14525		{
14526			_fnApplyToChildren( zeroOut, footerSrcEls );
14527	
14528			_fnApplyToChildren( function(nSizer) {
14529				footerContent.push( nSizer.innerHTML );
14530				footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
14531			}, footerSrcEls );
14532	
14533			_fnApplyToChildren( function(nToSize, i) {
14534				nToSize.style.width = footerWidths[i];
14535			}, footerTrgEls );
14536	
14537			$(footerSrcEls).height(0);
14538		}
14539	
14540	
14541		/*
14542		 * 3. Apply the measurements
14543		 */
14544	
14545		// "Hide" the header and footer that we used for the sizing. We need to keep
14546		// the content of the cell so that the width applied to the header and body
14547		// both match, but we want to hide it completely. We want to also fix their
14548		// width to what they currently are
14549		_fnApplyToChildren( function(nSizer, i) {
14550			nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>';
14551			nSizer.childNodes[0].style.height = "0";
14552			nSizer.childNodes[0].style.overflow = "hidden";
14553			nSizer.style.width = headerWidths[i];
14554		}, headerSrcEls );
14555	
14556		if ( footer )
14557		{
14558			_fnApplyToChildren( function(nSizer, i) {
14559				nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>';
14560				nSizer.childNodes[0].style.height = "0";
14561				nSizer.childNodes[0].style.overflow = "hidden";
14562				nSizer.style.width = footerWidths[i];
14563			}, footerSrcEls );
14564		}
14565	
14566		// Sanity check that the table is of a sensible width. If not then we are going to get
14567		// misalignment - try to prevent this by not allowing the table to shrink below its min width
14568		if ( table.outerWidth() < sanityWidth )
14569		{
14570			// The min width depends upon if we have a vertical scrollbar visible or not */
14571			correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
14572				divBody.css('overflow-y') == "scroll")) ?
14573					sanityWidth+barWidth :
14574					sanityWidth;
14575	
14576			// IE6/7 are a law unto themselves...
14577			if ( ie67 && (divBodyEl.scrollHeight >
14578				divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
14579			) {
14580				tableStyle.width = _fnStringToCss( correction-barWidth );
14581			}
14582	
14583			// And give the user a warning that we've stopped the table getting too small
14584			if ( scrollX === "" || scrollXInner !== "" ) {
14585				_fnLog( settings, 1, 'Possible column misalignment', 6 );
14586			}
14587		}
14588		else
14589		{
14590			correction = '100%';
14591		}
14592	
14593		// Apply to the container elements
14594		divBodyStyle.width = _fnStringToCss( correction );
14595		divHeaderStyle.width = _fnStringToCss( correction );
14596	
14597		if ( footer ) {
14598			settings.nScrollFoot.style.width = _fnStringToCss( correction );
14599		}
14600	
14601	
14602		/*
14603		 * 4. Clean up
14604		 */
14605		if ( ! scrollY ) {
14606			/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
14607			 * the scrollbar height from the visible display, rather than adding it on. We need to
14608			 * set the height in order to sort this. Don't want to do it in any other browsers.
14609			 */
14610			if ( ie67 ) {
14611				divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
14612			}
14613		}
14614	
14615		/* Finally set the width's of the header and footer tables */
14616		var iOuterWidth = table.outerWidth();
14617		divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
14618		divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
14619	
14620		// Figure out if there are scrollbar present - if so then we need a the header and footer to
14621		// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
14622		var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
14623		var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
14624		divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
14625	
14626		if ( footer ) {
14627			divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
14628			divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
14629			divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
14630		}
14631	
14632		// Correct DOM ordering for colgroup - comes before the thead
14633		table.children('colgroup').insertBefore( table.children('thead') );
14634	
14635		/* Adjust the position of the header in case we loose the y-scrollbar */
14636		divBody.scroll(
vendor: 11,594 bytes, lines 14636-15034
14636);
14637	
14638		// If sorting or filtering has occurred, jump the scrolling back to the top
14639		// only if we aren't holding the position
14640		if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
14641			divBodyEl.scrollTop = 0;
14642		}
14643	}
14644	
14645	
14646	
14647	/**
14648	 * Apply a given function to the display child nodes of an element array (typically
14649	 * TD children of TR rows
14650	 *  @param {function} fn Method to apply to the objects
14651	 *  @param array {nodes} an1 List of elements to look through for display children
14652	 *  @param array {nodes} an2 Another list (identical structure to the first) - optional
14653	 *  @memberof DataTable#oApi
14654	 */
14655	function _fnApplyToChildren( fn, an1, an2 )
14656	{
14657		var index=0, i=0, iLen=an1.length;
14658		var nNode1, nNode2;
14659	
14660		while ( i < iLen ) {
14661			nNode1 = an1[i].firstChild;
14662			nNode2 = an2 ? an2[i].firstChild : null;
14663	
14664			while ( nNode1 ) {
14665				if ( nNode1.nodeType === 1 ) {
14666					if ( an2 ) {
14667						fn( nNode1, nNode2, index );
14668					}
14669					else {
14670						fn( nNode1, index );
14671					}
14672	
14673					index++;
14674				}
14675	
14676				nNode1 = nNode1.nextSibling;
14677				nNode2 = an2 ? nNode2.nextSibling : null;
14678			}
14679	
14680			i++;
14681		}
14682	}
14683	
14684	
14685	
14686	var __re_html_remove = /<.*?>/g;
14687	
14688	
14689	/**
14690	 * Calculate the width of columns for the table
14691	 *  @param {object} oSettings dataTables settings object
14692	 *  @memberof DataTable#oApi
14693	 */
14694	function _fnCalculateColumnWidths ( oSettings )
14695	{
14696		var
14697			table = oSettings.nTable,
14698			columns = oSettings.aoColumns,
14699			scroll = oSettings.oScroll,
14700			scrollY = scroll.sY,
14701			scrollX = scroll.sX,
14702			scrollXInner = scroll.sXInner,
14703			columnCount = columns.length,
14704			visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
14705			headerCells = $('th', oSettings.nTHead),
14706			tableWidthAttr = table.getAttribute('width'), // from DOM element
14707			tableContainer = table.parentNode,
14708			userInputs = false,
14709			i, column, columnIdx, width, outerWidth,
14710			browser = oSettings.oBrowser,
14711			ie67 = browser.bScrollOversize;
14712	
14713		var styleWidth = table.style.width;
14714		if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
14715			tableWidthAttr = styleWidth;
14716		}
14717	
14718		/* Convert any user input sizes into pixel sizes */
14719		for ( i=0 ; i<visibleColumns.length ; i++ ) {
14720			column = columns[ visibleColumns[i] ];
14721	
14722			if ( column.sWidth !== null ) {
14723				column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
14724	
14725				userInputs = true;
14726			}
14727		}
14728	
14729		/* If the number of columns in the DOM equals the number that we have to
14730		 * process in DataTables, then we can use the offsets that are created by
14731		 * the web- browser. No custom sizes can be set in order for this to happen,
14732		 * nor scrolling used
14733		 */
14734		if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
14735		     columnCount == _fnVisbleColumns( oSettings ) &&
14736		     columnCount == headerCells.length
14737		) {
14738			for ( i=0 ; i<columnCount ; i++ ) {
14739				var colIdx = _fnVisibleToColumnIndex( oSettings, i );
14740	
14741				if ( colIdx !== null ) {
14742					columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
14743				}
14744			}
14745		}
14746		else
14747		{
14748			// Otherwise construct a single row, worst case, table with the widest
14749			// node in the data, assign any user defined widths, then insert it into
14750			// the DOM and allow the browser to do all the hard work of calculating
14751			// table widths
14752			var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
14753				.css( 'visibility', 'hidden' )
14754				.removeAttr( 'id' );
14755	
14756			// Clean up the table body
14757			tmpTable.find('tbody tr').remove();
14758			var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
14759	
14760			// Clone the table header and footer - we can't use the header / footer
14761			// from the cloned table, since if scrolling is active, the table's
14762			// real header and footer are contained in different table tags
14763			tmpTable.find('thead, tfoot').remove();
14764			tmpTable
14765				.append( $(oSettings.nTHead).clone() )
14766				.append( $(oSettings.nTFoot).clone() );
14767	
14768			// Remove any assigned widths from the footer (from scrolling)
14769			tmpTable.find('tfoot th, tfoot td').css('width', '');
14770	
14771			// Apply custom sizing to the cloned header
14772			headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
14773	
14774			for ( i=0 ; i<visibleColumns.length ; i++ ) {
14775				column = columns[ visibleColumns[i] ];
14776	
14777				headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
14778					_fnStringToCss( column.sWidthOrig ) :
14779					'';
14780	
14781				// For scrollX we need to force the column width otherwise the
14782				// browser will collapse it. If this width is smaller than the
14783				// width the column requires, then it will have no effect
14784				if ( column.sWidthOrig && scrollX ) {
14785					$( headerCells[i] ).append( $('<div/>').css( {
14786						width: column.sWidthOrig,
14787						margin: 0,
14788						padding: 0,
14789						border: 0,
14790						height: 1
14791					} ) );
14792				}
14793			}
14794	
14795			// Find the widest cell for each column and put it into the table
14796			if ( oSettings.aoData.length ) {
14797				for ( i=0 ; i<visibleColumns.length ; i++ ) {
14798					columnIdx = visibleColumns[i];
14799					column = columns[ columnIdx ];
14800	
14801					$( _fnGetWidestNode( oSettings, columnIdx ) )
14802						.clone( false )
14803						.append( column.sContentPadding )
14804						.appendTo( tr );
14805				}
14806			}
14807	
14808			// Tidy the temporary table - remove name attributes so there aren't
14809			// duplicated in the dom (radio elements for example)
14810			$('[name]', tmpTable).removeAttr('name');
14811	
14812			// Table has been built, attach to the document so we can work with it.
14813			// A holding element is used, positioned at the top of the container
14814			// with minimal height, so it has no effect on if the container scrolls
14815			// or not. Otherwise it might trigger scrolling when it actually isn't
14816			// needed
14817			var holder = $('<div/>').css( scrollX || scrollY ?
14818					{
14819						position: 'absolute',
14820						top: 0,
14821						left: 0,
14822						height: 1,
14823						right: 0,
14824						overflow: 'hidden'
14825					} :
14826					{}
14827				)
14828				.append( tmpTable )
14829				.appendTo( tableContainer );
14830	
14831			// When scrolling (X or Y) we want to set the width of the table as 
14832			// appropriate. However, when not scrolling leave the table width as it
14833			// is. This results in slightly different, but I think correct behaviour
14834			if ( scrollX && scrollXInner ) {
14835				tmpTable.width( scrollXInner );
14836			}
14837			else if ( scrollX ) {
14838				tmpTable.css( 'width', 'auto' );
14839				tmpTable.removeAttr('width');
14840	
14841				// If there is no width attribute or style, then allow the table to
14842				// collapse
14843				if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
14844					tmpTable.width( tableContainer.clientWidth );
14845				}
14846			}
14847			else if ( scrollY ) {
14848				tmpTable.width( tableContainer.clientWidth );
14849			}
14850			else if ( tableWidthAttr ) {
14851				tmpTable.width( tableWidthAttr );
14852			}
14853	
14854			// Get the width of each column in the constructed table - we need to
14855			// know the inner width (so it can be assigned to the other table's
14856			// cells) and the outer width so we can calculate the full width of the
14857			// table. This is safe since DataTables requires a unique cell for each
14858			// column, but if ever a header can span multiple columns, this will
14859			// need to be modified.
14860			var total = 0;
14861			for ( i=0 ; i<visibleColumns.length ; i++ ) {
14862				var cell = $(headerCells[i]);
14863				var border = cell.outerWidth() - cell.width();
14864	
14865				// Use getBounding... where possible (not IE8-) because it can give
14866				// sub-pixel accuracy, which we then want to round up!
14867				var bounding = browser.bBounding ?
14868					Math.ceil( headerCells[i].getBoundingClientRect().width ) :
14869					cell.outerWidth();
14870	
14871				// Total is tracked to remove any sub-pixel errors as the outerWidth
14872				// of the table might not equal the total given here (IE!).
14873				total += bounding;
14874	
14875				// Width for each column to use
14876				columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
14877			}
14878	
14879			table.style.width = _fnStringToCss( total );
14880	
14881			// Finished with the table - ditch it
14882			holder.remove();
14883		}
14884	
14885		// If there is a width attr, we want to attach an event listener which
14886		// allows the table sizing to automatically adjust when the window is
14887		// resized. Use the width attr rather than CSS, since we can't know if the
14888		// CSS is a relative value or absolute - DOM read is always px.
14889		if ( tableWidthAttr ) {
14890			table.style.width = _fnStringToCss( tableWidthAttr );
14891		}
14892	
14893		if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
14894			var bindResize = function () {
14895				$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
14896					_fnAdjustColumnSizing( oSettings );
14897				} ) );
14898			};
14899	
14900			// IE6/7 will crash if we bind a resize event handler on page load.
14901			// To be removed in 1.11 which drops IE6/7 support
14902			if ( ie67 ) {
14903				setTimeout( bindResize, 1000 );
14904			}
14905			else {
14906				bindResize();
14907			}
14908	
14909			oSettings._reszEvt = true;
14910		}
14911	}
14912	
14913	
14914	/**
14915	 * Throttle the calls to a function. Arguments and context are maintained for
14916	 * the throttled function
14917	 *  @param {function} fn Function to be called
14918	 *  @param {int} [freq=200] call frequency in mS
14919	 *  @returns {function} wrapped function
14920	 *  @memberof DataTable#oApi
14921	 */
14922	var _fnThrottle = DataTable.util.throttle;
14923	
14924	
14925	/**
14926	 * Convert a CSS unit width to pixels (e.g. 2em)
14927	 *  @param {string} width width to be converted
14928	 *  @param {node} parent parent to get the with for (required for relative widths) - optional
14929	 *  @returns {int} width in pixels
14930	 *  @memberof DataTable#oApi
14931	 */
14932	function _fnConvertToWidth ( width, parent )
14933	{
14934		if ( ! width ) {
14935			return 0;
14936		}
14937	
14938		var n = $('<div/>')
14939			.css( 'width', _fnStringToCss( width ) )
14940			.appendTo( parent || document.body );
14941	
14942		var val = n[0].offsetWidth;
14943		n.remove();
14944	
14945		return val;
14946	}
14947	
14948	
14949	/**
14950	 * Get the widest node
14951	 *  @param {object} settings dataTables settings object
14952	 *  @param {int} colIdx column of interest
14953	 *  @returns {node} widest table node
14954	 *  @memberof DataTable#oApi
14955	 */
14956	function _fnGetWidestNode( settings, colIdx )
14957	{
14958		var idx = _fnGetMaxLenString( settings, colIdx );
14959		if ( idx < 0 ) {
14960			return null;
14961		}
14962	
14963		var data = settings.aoData[ idx ];
14964		return ! data.nTr ? // Might not have been created when deferred rendering
14965			$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
14966			data.anCells[ colIdx ];
14967	}
14968	
14969	
14970	/**
14971	 * Get the maximum strlen for each data column
14972	 *  @param {object} settings dataTables settings object
14973	 *  @param {int} colIdx column of interest
14974	 *  @returns {string} max string length for each column
14975	 *  @memberof DataTable#oApi
14976	 */
14977	function _fnGetMaxLenString( settings, colIdx )
14978	{
14979		var s, max=-1, maxIdx = -1;
14980	
14981		for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
14982			s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
14983			s = s.replace( __re_html_remove, '' );
14984			s = s.replace( /&nbsp;/g, ' ' );
14985	
14986			if ( s.length > max ) {
14987				max = s.length;
14988				maxIdx = i;
14989			}
14990		}
14991	
14992		return maxIdx;
14993	}
14994	
14995	
14996	/**
14997	 * Append a CSS unit (only if required) to a string
14998	 *  @param {string} value to css-ify
14999	 *  @returns {string} value with css unit
15000	 *  @memberof DataTable#oApi
15001	 */
15002	function _fnStringToCss( s )
15003	{
15004		if ( s === null ) {
15005			return '0px';
15006		}
15007	
15008		if ( typeof s == 'number' ) {
15009			return s < 0 ?
15010				'0px' :
15011				s+'px';
15012		}
15013	
15014		// Check it has a unit character already
15015		return s.match(/\d$/) ?
15016			s+'px' :
15017			s;
15018	}
15019	
15020	
15021	
15022	function _fnSortFlatten ( settings )
15023	{
15024		var
15025			i, iLen, k, kLen,
15026			aSort = [],
15027			aiOrig = [],
15028			aoColumns = settings.aoColumns,
15029			aDataSort, iCol, sType, srcCol,
15030			fixed = settings.aaSortingFixed,
15031			fixedObj = $.isPlainObject( fixed ),
15032			nestedSort = [],
15033			add = function ( a ) {
15034				if ( a.length && ! 
vendor: 39,758 bytes, lines 15034-16555
15034$.isArray( a[0] ) ) {
15035					// 1D array
15036					nestedSort.push( a );
15037				}
15038				else {
15039					// 2D array
15040					$.merge( nestedSort, a );
15041				}
15042			};
15043	
15044		// Build the sort array, with pre-fix and post-fix options if they have been
15045		// specified
15046		if ( $.isArray( fixed ) ) {
15047			add( fixed );
15048		}
15049	
15050		if ( fixedObj && fixed.pre ) {
15051			add( fixed.pre );
15052		}
15053	
15054		add( settings.aaSorting );
15055	
15056		if (fixedObj && fixed.post ) {
15057			add( fixed.post );
15058		}
15059	
15060		for ( i=0 ; i<nestedSort.length ; i++ )
15061		{
15062			srcCol = nestedSort[i][0];
15063			aDataSort = aoColumns[ srcCol ].aDataSort;
15064	
15065			for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
15066			{
15067				iCol = aDataSort[k];
15068				sType = aoColumns[ iCol ].sType || 'string';
15069	
15070				if ( nestedSort[i]._idx === undefined ) {
15071					nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
15072				}
15073	
15074				aSort.push( {
15075					src:       srcCol,
15076					col:       iCol,
15077					dir:       nestedSort[i][1],
15078					index:     nestedSort[i]._idx,
15079					type:      sType,
15080					formatter: DataTable.ext.type.order[ sType+"-pre" ]
15081				} );
15082			}
15083		}
15084	
15085		return aSort;
15086	}
15087	
15088	/**
15089	 * Change the order of the table
15090	 *  @param {object} oSettings dataTables settings object
15091	 *  @memberof DataTable#oApi
15092	 *  @todo This really needs split up!
15093	 */
15094	function _fnSort ( oSettings )
15095	{
15096		var
15097			i, ien, iLen, j, jLen, k, kLen,
15098			sDataType, nTh,
15099			aiOrig = [],
15100			oExtSort = DataTable.ext.type.order,
15101			aoData = oSettings.aoData,
15102			aoColumns = oSettings.aoColumns,
15103			aDataSort, data, iCol, sType, oSort,
15104			formatters = 0,
15105			sortCol,
15106			displayMaster = oSettings.aiDisplayMaster,
15107			aSort;
15108	
15109		// Resolve any column types that are unknown due to addition or invalidation
15110		// @todo Can this be moved into a 'data-ready' handler which is called when
15111		//   data is going to be used in the table?
15112		_fnColumnTypes( oSettings );
15113	
15114		aSort = _fnSortFlatten( oSettings );
15115	
15116		for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
15117			sortCol = aSort[i];
15118	
15119			// Track if we can use the fast sort algorithm
15120			if ( sortCol.formatter ) {
15121				formatters++;
15122			}
15123	
15124			// Load the data needed for the sort, for each cell
15125			_fnSortData( oSettings, sortCol.col );
15126		}
15127	
15128		/* No sorting required if server-side or no sorting array */
15129		if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
15130		{
15131			// Create a value - key array of the current row positions such that we can use their
15132			// current position during the sort, if values match, in order to perform stable sorting
15133			for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
15134				aiOrig[ displayMaster[i] ] = i;
15135			}
15136	
15137			/* Do the sort - here we want multi-column sorting based on a given data source (column)
15138			 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
15139			 * follow on it's own, but this is what we want (example two column sorting):
15140			 *  fnLocalSorting = function(a,b){
15141			 *    var iTest;
15142			 *    iTest = oSort['string-asc']('data11', 'data12');
15143			 *      if (iTest !== 0)
15144			 *        return iTest;
15145			 *    iTest = oSort['numeric-desc']('data21', 'data22');
15146			 *    if (iTest !== 0)
15147			 *      return iTest;
15148			 *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
15149			 *  }
15150			 * Basically we have a test for each sorting column, if the data in that column is equal,
15151			 * test the next column. If all columns match, then we use a numeric sort on the row
15152			 * positions in the original data array to provide a stable sort.
15153			 *
15154			 * Note - I know it seems excessive to have two sorting methods, but the first is around
15155			 * 15% faster, so the second is only maintained for backwards compatibility with sorting
15156			 * methods which do not have a pre-sort formatting function.
15157			 */
15158			if ( formatters === aSort.length ) {
15159				// All sort types have formatting functions
15160				displayMaster.sort( function ( a, b ) {
15161					var
15162						x, y, k, test, sort,
15163						len=aSort.length,
15164						dataA = aoData[a]._aSortData,
15165						dataB = aoData[b]._aSortData;
15166	
15167					for ( k=0 ; k<len ; k++ ) {
15168						sort = aSort[k];
15169	
15170						x = dataA[ sort.col ];
15171						y = dataB[ sort.col ];
15172	
15173						test = x<y ? -1 : x>y ? 1 : 0;
15174						if ( test !== 0 ) {
15175							return sort.dir === 'asc' ? test : -test;
15176						}
15177					}
15178	
15179					x = aiOrig[a];
15180					y = aiOrig[b];
15181					return x<y ? -1 : x>y ? 1 : 0;
15182				} );
15183			}
15184			else {
15185				// Depreciated - remove in 1.11 (providing a plug-in option)
15186				// Not all sort types have formatting methods, so we have to call their sorting
15187				// methods.
15188				displayMaster.sort( function ( a, b ) {
15189					var
15190						x, y, k, l, test, sort, fn,
15191						len=aSort.length,
15192						dataA = aoData[a]._aSortData,
15193						dataB = aoData[b]._aSortData;
15194	
15195					for ( k=0 ; k<len ; k++ ) {
15196						sort = aSort[k];
15197	
15198						x = dataA[ sort.col ];
15199						y = dataB[ sort.col ];
15200	
15201						fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
15202						test = fn( x, y );
15203						if ( test !== 0 ) {
15204							return test;
15205						}
15206					}
15207	
15208					x = aiOrig[a];
15209					y = aiOrig[b];
15210					return x<y ? -1 : x>y ? 1 : 0;
15211				} );
15212			}
15213		}
15214	
15215		/* Tell the draw function that we have sorted the data */
15216		oSettings.bSorted = true;
15217	}
15218	
15219	
15220	function _fnSortAria ( settings )
15221	{
15222		var label;
15223		var nextSort;
15224		var columns = settings.aoColumns;
15225		var aSort = _fnSortFlatten( settings );
15226		var oAria = settings.oLanguage.oAria;
15227	
15228		// ARIA attributes - need to loop all columns, to update all (removing old
15229		// attributes as needed)
15230		for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
15231		{
15232			var col = columns[i];
15233			var asSorting = col.asSorting;
15234			var sTitle = col.sTitle.replace( /<.*?>/g, "" );
15235			var th = col.nTh;
15236	
15237			// IE7 is throwing an error when setting these properties with jQuery's
15238			// attr() and removeAttr() methods...
15239			th.removeAttribute('aria-sort');
15240	
15241			/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
15242			if ( col.bSortable ) {
15243				if ( aSort.length > 0 && aSort[0].col == i ) {
15244					th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
15245					nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
15246				}
15247				else {
15248					nextSort = asSorting[0];
15249				}
15250	
15251				label = sTitle + ( nextSort === "asc" ?
15252					oAria.sSortAscending :
15253					oAria.sSortDescending
15254				);
15255			}
15256			else {
15257				label = sTitle;
15258			}
15259	
15260			th.setAttribute('aria-label', label);
15261		}
15262	}
15263	
15264	
15265	/**
15266	 * Function to run on user sort request
15267	 *  @param {object} settings dataTables settings object
15268	 *  @param {node} attachTo node to attach the handler to
15269	 *  @param {int} colIdx column sorting index
15270	 *  @param {boolean} [append=false] Append the requested sort to the existing
15271	 *    sort if true (i.e. multi-column sort)
15272	 *  @param {function} [callback] callback function
15273	 *  @memberof DataTable#oApi
15274	 */
15275	function _fnSortListener ( settings, colIdx, append, callback )
15276	{
15277		var col = settings.aoColumns[ colIdx ];
15278		var sorting = settings.aaSorting;
15279		var asSorting = col.asSorting;
15280		var nextSortIdx;
15281		var next = function ( a, overflow ) {
15282			var idx = a._idx;
15283			if ( idx === undefined ) {
15284				idx = $.inArray( a[1], asSorting );
15285			}
15286	
15287			return idx+1 < asSorting.length ?
15288				idx+1 :
15289				overflow ?
15290					null :
15291					0;
15292		};
15293	
15294		// Convert to 2D array if needed
15295		if ( typeof sorting[0] === 'number' ) {
15296			sorting = settings.aaSorting = [ sorting ];
15297		}
15298	
15299		// If appending the sort then we are multi-column sorting
15300		if ( append && settings.oFeatures.bSortMulti ) {
15301			// Are we already doing some kind of sort on this column?
15302			var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
15303	
15304			if ( sortIdx !== -1 ) {
15305				// Yes, modify the sort
15306				nextSortIdx = next( sorting[sortIdx], true );
15307	
15308				if ( nextSortIdx === null && sorting.length === 1 ) {
15309					nextSortIdx = 0; // can't remove sorting completely
15310				}
15311	
15312				if ( nextSortIdx === null ) {
15313					sorting.splice( sortIdx, 1 );
15314				}
15315				else {
15316					sorting[sortIdx][1] = asSorting[ nextSortIdx ];
15317					sorting[sortIdx]._idx = nextSortIdx;
15318				}
15319			}
15320			else {
15321				// No sort on this column yet
15322				sorting.push( [ colIdx, asSorting[0], 0 ] );
15323				sorting[sorting.length-1]._idx = 0;
15324			}
15325		}
15326		else if ( sorting.length && sorting[0][0] == colIdx ) {
15327			// Single column - already sorting on this column, modify the sort
15328			nextSortIdx = next( sorting[0] );
15329	
15330			sorting.length = 1;
15331			sorting[0][1] = asSorting[ nextSortIdx ];
15332			sorting[0]._idx = nextSortIdx;
15333		}
15334		else {
15335			// Single column - sort only on this column
15336			sorting.length = 0;
15337			sorting.push( [ colIdx, asSorting[0] ] );
15338			sorting[0]._idx = 0;
15339		}
15340	
15341		// Run the sort by calling a full redraw
15342		_fnReDraw( settings );
15343	
15344		// callback used for async user interaction
15345		if ( typeof callback == 'function' ) {
15346			callback( settings );
15347		}
15348	}
15349	
15350	
15351	/**
15352	 * Attach a sort handler (click) to a node
15353	 *  @param {object} settings dataTables settings object
15354	 *  @param {node} attachTo node to attach the handler to
15355	 *  @param {int} colIdx column sorting index
15356	 *  @param {function} [callback] callback function
15357	 *  @memberof DataTable#oApi
15358	 */
15359	function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
15360	{
15361		var col = settings.aoColumns[ colIdx ];
15362	
15363		_fnBindAction( attachTo, {}, function (e) {
15364			/* If the column is not sortable - don't to anything */
15365			if ( col.bSortable === false ) {
15366				return;
15367			}
15368	
15369			// If processing is enabled use a timeout to allow the processing
15370			// display to be shown - otherwise to it synchronously
15371			if ( settings.oFeatures.bProcessing ) {
15372				_fnProcessingDisplay( settings, true );
15373	
15374				setTimeout( function() {
15375					_fnSortListener( settings, colIdx, e.shiftKey, callback );
15376	
15377					// In server-side processing, the draw callback will remove the
15378					// processing display
15379					if ( _fnDataSource( settings ) !== 'ssp' ) {
15380						_fnProcessingDisplay( settings, false );
15381					}
15382				}, 0 );
15383			}
15384			else {
15385				_fnSortListener( settings, colIdx, e.shiftKey, callback );
15386			}
15387		} );
15388	}
15389	
15390	
15391	/**
15392	 * Set the sorting classes on table's body, Note: it is safe to call this function
15393	 * when bSort and bSortClasses are false
15394	 *  @param {object} oSettings dataTables settings object
15395	 *  @memberof DataTable#oApi
15396	 */
15397	function _fnSortingClasses( settings )
15398	{
15399		var oldSort = settings.aLastSort;
15400		var sortClass = settings.oClasses.sSortColumn;
15401		var sort = _fnSortFlatten( settings );
15402		var features = settings.oFeatures;
15403		var i, ien, colIdx;
15404	
15405		if ( features.bSort && features.bSortClasses ) {
15406			// Remove old sorting classes
15407			for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
15408				colIdx = oldSort[i].src;
15409	
15410				// Remove column sorting
15411				$( _pluck( settings.aoData, 'anCells', colIdx ) )
15412					.removeClass( sortClass + (i<2 ? i+1 : 3) );
15413			}
15414	
15415			// Add new column sorting
15416			for ( i=0, ien=sort.length ; i<ien ; i++ ) {
15417				colIdx = sort[i].src;
15418	
15419				$( _pluck( settings.aoData, 'anCells', colIdx ) )
15420					.addClass( sortClass + (i<2 ? i+1 : 3) );
15421			}
15422		}
15423	
15424		settings.aLastSort = sort;
15425	}
15426	
15427	
15428	// Get the data to sort a column, be it from cache, fresh (populating the
15429	// cache), or from a sort formatter
15430	function _fnSortData( settings, idx )
15431	{
15432		// Custom sorting function - provided by the sort data type
15433		var column = settings.aoColumns[ idx ];
15434		var customSort = DataTable.ext.order[ column.sSortDataType ];
15435		var customData;
15436	
15437		if ( customSort ) {
15438			customData = customSort.call( settings.oInstance, settings, idx,
15439				_fnColumnIndexToVisible( settings, idx )
15440			);
15441		}
15442	
15443		// Use / populate cache
15444		var row, cellData;
15445		var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
15446	
15447		for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
15448			row = settings.aoData[i];
15449	
15450			if ( ! row._aSortData ) {
15451				row._aSortData = [];
15452			}
15453	
15454			if ( ! row._aSortData[idx] || customSort ) {
15455				cellData = customSort ?
15456					customData[i] : // If there was a custom sort function, use data from there
15457					_fnGetCellData( settings, i, idx, 'sort' );
15458	
15459				row._aSortData[ idx ] = formatter ?
15460					formatter( cellData ) :
15461					cellData;
15462			}
15463		}
15464	}
15465	
15466	
15467	
15468	/**
15469	 * Save the state of a table
15470	 *  @param {object} oSettings dataTables settings object
15471	 *  @memberof DataTable#oApi
15472	 */
15473	function _fnSaveState ( settings )
15474	{
15475		if ( !settings.oFeatures.bStateSave || settings.bDestroying )
15476		{
15477			return;
15478		}
15479	
15480		/* Store the interesting variables */
15481		var state = {
15482			time:    +new Date(),
15483			start:   settings._iDisplayStart,
15484			length:  settings._iDisplayLength,
15485			order:   $.extend( true, [], settings.aaSorting ),
15486			search:  _fnSearchToCamel( settings.oPreviousSearch ),
15487			columns: $.map( settings.aoColumns, function ( col, i ) {
15488				return {
15489					visible: col.bVisible,
15490					search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
15491				};
15492			} )
15493		};
15494	
15495		_fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
15496	
15497		settings.oSavedState = state;
15498		settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
15499	}
15500	
15501	
15502	/**
15503	 * Attempt to load a saved table state
15504	 *  @param {object} oSettings dataTables settings object
15505	 *  @param {object} oInit DataTables init object so we can override settings
15506	 *  @param {function} callback Callback to execute when the state has been loaded
15507	 *  @memberof DataTable#oApi
15508	 */
15509	function _fnLoadState ( settings, oInit, callback )
15510	{
15511		var i, ien;
15512		var columns = settings.aoColumns;
15513		var loaded = function ( s ) {
15514			if ( ! s || ! s.time ) {
15515				callback();
15516				return;
15517			}
15518	
15519			// Allow custom and plug-in manipulation functions to alter the saved data set and
15520			// cancelling of loading by returning false
15521			var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
15522			if ( $.inArray( false, abStateLoad ) !== -1 ) {
15523				callback();
15524				return;
15525			}
15526	
15527			// Reject old data
15528			var duration = settings.iStateDuration;
15529			if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
15530				callback();
15531				return;
15532			}
15533	
15534			// Number of columns have changed - all bets are off, no restore of settings
15535			if ( s.columns && columns.length !== s.columns.length ) {
15536				callback();
15537				return;
15538			}
15539	
15540			// Store the saved state so it might be accessed at any time
15541			settings.oLoadedState = $.extend( true, {}, s );
15542	
15543			// Restore key features - todo - for 1.11 this needs to be done by
15544			// subscribed events
15545			if ( s.start !== undefined ) {
15546				settings._iDisplayStart    = s.start;
15547				settings.iInitDisplayStart = s.start;
15548			}
15549			if ( s.length !== undefined ) {
15550				settings._iDisplayLength   = s.length;
15551			}
15552	
15553			// Order
15554			if ( s.order !== undefined ) {
15555				settings.aaSorting = [];
15556				$.each( s.order, function ( i, col ) {
15557					settings.aaSorting.push( col[0] >= columns.length ?
15558						[ 0, col[1] ] :
15559						col
15560					);
15561				} );
15562			}
15563	
15564			// Search
15565			if ( s.search !== undefined ) {
15566				$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
15567			}
15568	
15569			// Columns
15570			//
15571			if ( s.columns ) {
15572				for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
15573					var col = s.columns[i];
15574	
15575					// Visibility
15576					if ( col.visible !== undefined ) {
15577						columns[i].bVisible = col.visible;
15578					}
15579	
15580					// Search
15581					if ( col.search !== undefined ) {
15582						$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
15583					}
15584				}
15585			}
15586	
15587			_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
15588			callback();
15589		}
15590	
15591		if ( ! settings.oFeatures.bStateSave ) {
15592			callback();
15593			return;
15594		}
15595	
15596		var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
15597	
15598		if ( state !== undefined ) {
15599			loaded( state );
15600		}
15601		// otherwise, wait for the loaded callback to be executed
15602	}
15603	
15604	
15605	/**
15606	 * Return the settings object for a particular table
15607	 *  @param {node} table table we are using as a dataTable
15608	 *  @returns {object} Settings object - or null if not found
15609	 *  @memberof DataTable#oApi
15610	 */
15611	function _fnSettingsFromNode ( table )
15612	{
15613		var settings = DataTable.settings;
15614		var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
15615	
15616		return idx !== -1 ?
15617			settings[ idx ] :
15618			null;
15619	}
15620	
15621	
15622	/**
15623	 * Log an error message
15624	 *  @param {object} settings dataTables settings object
15625	 *  @param {int} level log error messages, or display them to the user
15626	 *  @param {string} msg error message
15627	 *  @param {int} tn Technical note id to get more information about the error.
15628	 *  @memberof DataTable#oApi
15629	 */
15630	function _fnLog( settings, level, msg, tn )
15631	{
15632		msg = 'DataTables warning: '+
15633			(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
15634	
15635		if ( tn ) {
15636			msg += '. For more information about this error, please see '+
15637			'http://datatables.net/tn/'+tn;
15638		}
15639	
15640		if ( ! level  ) {
15641			// Backwards compatibility pre 1.10
15642			var ext = DataTable.ext;
15643			var type = ext.sErrMode || ext.errMode;
15644	
15645			if ( settings ) {
15646				_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
15647			}
15648	
15649			if ( type == 'alert' ) {
15650				alert( msg );
15651			}
15652			else if ( type == 'throw' ) {
15653				throw new Error(msg);
15654			}
15655			else if ( typeof type == 'function' ) {
15656				type( settings, tn, msg );
15657			}
15658		}
15659		else if ( window.console && console.log ) {
15660			console.log( msg );
15661		}
15662	}
15663	
15664	
15665	/**
15666	 * See if a property is defined on one object, if so assign it to the other object
15667	 *  @param {object} ret target object
15668	 *  @param {object} src source object
15669	 *  @param {string} name property
15670	 *  @param {string} [mappedName] name to map too - optional, name used if not given
15671	 *  @memberof DataTable#oApi
15672	 */
15673	function _fnMap( ret, src, name, mappedName )
15674	{
15675		if ( $.isArray( name ) ) {
15676			$.each( name, function (i, val) {
15677				if ( $.isArray( val ) ) {
15678					_fnMap( ret, src, val[0], val[1] );
15679				}
15680				else {
15681					_fnMap( ret, src, val );
15682				}
15683			} );
15684	
15685			return;
15686		}
15687	
15688		if ( mappedName === undefined ) {
15689			mappedName = name;
15690		}
15691	
15692		if ( src[name] !== undefined ) {
15693			ret[mappedName] = src[name];
15694		}
15695	}
15696	
15697	
15698	/**
15699	 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
15700	 * shallow copy arrays. The reason we need to do this, is that we don't want to
15701	 * deep copy array init values (such as aaSorting) since the dev wouldn't be
15702	 * able to override them, but we do want to deep copy arrays.
15703	 *  @param {object} out Object to extend
15704	 *  @param {object} extender Object from which the properties will be applied to
15705	 *      out
15706	 *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
15707	 *      independent copy with the exception of the `data` or `aaData` parameters
15708	 *      if they are present. This is so you can pass in a collection to
15709	 *      DataTables and have that used as your data source without breaking the
15710	 *      references
15711	 *  @returns {object} out Reference, just for convenience - out === the return.
15712	 *  @memberof DataTable#oApi
15713	 *  @todo This doesn't take account of arrays inside the deep copied objects.
15714	 */
15715	function _fnExtend( out, extender, breakRefs )
15716	{
15717		var val;
15718	
15719		for ( var prop in extender ) {
15720			if ( extender.hasOwnProperty(prop) ) {
15721				val = extender[prop];
15722	
15723				if ( $.isPlainObject( val ) ) {
15724					if ( ! $.isPlainObject( out[prop] ) ) {
15725						out[prop] = {};
15726					}
15727					$.extend( true, out[prop], val );
15728				}
15729				else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
15730					out[prop] = val.slice();
15731				}
15732				else {
15733					out[prop] = val;
15734				}
15735			}
15736		}
15737	
15738		return out;
15739	}
15740	
15741	
15742	/**
15743	 * Bind an event handers to allow a click or return key to activate the callback.
15744	 * This is good for accessibility since a return on the keyboard will have the
15745	 * same effect as a click, if the element has focus.
15746	 *  @param {element} n Element to bind the action to
15747	 *  @param {object} oData Data object to pass to the triggered function
15748	 *  @param {function} fn Callback function for when the event is triggered
15749	 *  @memberof DataTable#oApi
15750	 */
15751	function _fnBindAction( n, oData, fn )
15752	{
15753		$(n)
15754			.on( 'click.DT', oData, function (e) {
15755					$(n).blur(); // Remove focus outline for mouse users
15756					fn(e);
15757				} )
15758			.on( 'keypress.DT', oData, function (e){
15759					if ( e.which === 13 ) {
15760						e.preventDefault();
15761						fn(e);
15762					}
15763				} )
15764			.on( 'selectstart.DT', function () {
15765					/* Take the brutal approach to cancelling text selection */
15766					return false;
15767				} );
15768	}
15769	
15770	
15771	/**
15772	 * Register a callback function. Easily allows a callback function to be added to
15773	 * an array store of callback functions that can then all be called together.
15774	 *  @param {object} oSettings dataTables settings object
15775	 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
15776	 *  @param {function} fn Function to be called back
15777	 *  @param {string} sName Identifying name for the callback (i.e. a label)
15778	 *  @memberof DataTable#oApi
15779	 */
15780	function _fnCallbackReg( oSettings, sStore, fn, sName )
15781	{
15782		if ( fn )
15783		{
15784			oSettings[sStore].push( {
15785				"fn": fn,
15786				"sName": sName
15787			} );
15788		}
15789	}
15790	
15791	
15792	/**
15793	 * Fire callback functions and trigger events. Note that the loop over the
15794	 * callback array store is done backwards! Further note that you do not want to
15795	 * fire off triggers in time sensitive applications (for example cell creation)
15796	 * as its slow.
15797	 *  @param {object} settings dataTables settings object
15798	 *  @param {string} callbackArr Name of the array storage for the callbacks in
15799	 *      oSettings
15800	 *  @param {string} eventName Name of the jQuery custom event to trigger. If
15801	 *      null no trigger is fired
15802	 *  @param {array} args Array of arguments to pass to the callback function /
15803	 *      trigger
15804	 *  @memberof DataTable#oApi
15805	 */
15806	function _fnCallbackFire( settings, callbackArr, eventName, args )
15807	{
15808		var ret = [];
15809	
15810		if ( callbackArr ) {
15811			ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
15812				return val.fn.apply( settings.oInstance, args );
15813			} );
15814		}
15815	
15816		if ( eventName !== null ) {
15817			var e = $.Event( eventName+'.dt' );
15818	
15819			$(settings.nTable).trigger( e, args );
15820	
15821			ret.push( e.result );
15822		}
15823	
15824		return ret;
15825	}
15826	
15827	
15828	function _fnLengthOverflow ( settings )
15829	{
15830		var
15831			start = settings._iDisplayStart,
15832			end = settings.fnDisplayEnd(),
15833			len = settings._iDisplayLength;
15834	
15835		/* If we have space to show extra rows (backing up from the end point - then do so */
15836		if ( start >= end )
15837		{
15838			start = end - len;
15839		}
15840	
15841		// Keep the start record on the current page
15842		start -= (start % len);
15843	
15844		if ( len === -1 || start < 0 )
15845		{
15846			start = 0;
15847		}
15848	
15849		settings._iDisplayStart = start;
15850	}
15851	
15852	
15853	function _fnRenderer( settings, type )
15854	{
15855		var renderer = settings.renderer;
15856		var host = DataTable.ext.renderer[type];
15857	
15858		if ( $.isPlainObject( renderer ) && renderer[type] ) {
15859			// Specific renderer for this type. If available use it, otherwise use
15860			// the default.
15861			return host[renderer[type]] || host._;
15862		}
15863		else if ( typeof renderer === 'string' ) {
15864			// Common renderer - if there is one available for this type use it,
15865			// otherwise use the default
15866			return host[renderer] || host._;
15867		}
15868	
15869		// Use the default
15870		return host._;
15871	}
15872	
15873	
15874	/**
15875	 * Detect the data source being used for the table. Used to simplify the code
15876	 * a little (ajax) and to make it compress a little smaller.
15877	 *
15878	 *  @param {object} settings dataTables settings object
15879	 *  @returns {string} Data source
15880	 *  @memberof DataTable#oApi
15881	 */
15882	function _fnDataSource ( settings )
15883	{
15884		if ( settings.oFeatures.bServerSide ) {
15885			return 'ssp';
15886		}
15887		else if ( settings.ajax || settings.sAjaxSource ) {
15888			return 'ajax';
15889		}
15890		return 'dom';
15891	}
15892	
15893
15894	
15895	
15896	/**
15897	 * Computed structure of the DataTables API, defined by the options passed to
15898	 * `DataTable.Api.register()` when building the API.
15899	 *
15900	 * The structure is built in order to speed creation and extension of the Api
15901	 * objects since the extensions are effectively pre-parsed.
15902	 *
15903	 * The array is an array of objects with the following structure, where this
15904	 * base array represents the Api prototype base:
15905	 *
15906	 *     [
15907	 *       {
15908	 *         name:      'data'                -- string   - Property name
15909	 *         val:       function () {},       -- function - Api method (or undefined if just an object
15910	 *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
15911	 *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
15912	 *       },
15913	 *       {
15914	 *         name:     'row'
15915	 *         val:       {},
15916	 *         methodExt: [ ... ],
15917	 *         propExt:   [
15918	 *           {
15919	 *             name:      'data'
15920	 *             val:       function () {},
15921	 *             methodExt: [ ... ],
15922	 *             propExt:   [ ... ]
15923	 *           },
15924	 *           ...
15925	 *         ]
15926	 *       }
15927	 *     ]
15928	 *
15929	 * @type {Array}
15930	 * @ignore
15931	 */
15932	var __apiStruct = [];
15933	
15934	
15935	/**
15936	 * `Array.prototype` reference.
15937	 *
15938	 * @type object
15939	 * @ignore
15940	 */
15941	var __arrayProto = Array.prototype;
15942	
15943	
15944	/**
15945	 * Abstraction for `context` parameter of the `Api` constructor to allow it to
15946	 * take several different forms for ease of use.
15947	 *
15948	 * Each of the input parameter types will be converted to a DataTables settings
15949	 * object where possible.
15950	 *
15951	 * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
15952	 *   of:
15953	 *
15954	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
15955	 *     with be found and used.
15956	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
15957	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
15958	 *   * `object` - DataTables settings object
15959	 *   * `DataTables.Api` - API instance
15960	 * @return {array|null} Matching DataTables settings objects. `null` or
15961	 *   `undefined` is returned if no matching DataTable is found.
15962	 * @ignore
15963	 */
15964	var _toSettings = function ( mixed )
15965	{
15966		var idx, jq;
15967		var settings = DataTable.settings;
15968		var tables = $.map( settings, function (el, i) {
15969			return el.nTable;
15970		} );
15971	
15972		if ( ! mixed ) {
15973			return [];
15974		}
15975		else if ( mixed.nTable && mixed.oApi ) {
15976			// DataTables settings object
15977			return [ mixed ];
15978		}
15979		else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
15980			// Table node
15981			idx = $.inArray( mixed, tables );
15982			return idx !== -1 ? [ settings[idx] ] : null;
15983		}
15984		else if ( mixed && typeof mixed.settings === 'function' ) {
15985			return mixed.settings().toArray();
15986		}
15987		else if ( typeof mixed === 'string' ) {
15988			// jQuery selector
15989			jq = $(mixed);
15990		}
15991		else if ( mixed instanceof $ ) {
15992			// jQuery object (also DataTables instance)
15993			jq = mixed;
15994		}
15995	
15996		if ( jq ) {
15997			return jq.map( function(i) {
15998				idx = $.inArray( this, tables );
15999				return idx !== -1 ? settings[idx] : null;
16000			} ).toArray();
16001		}
16002	};
16003	
16004	
16005	/**
16006	 * DataTables API class - used to control and interface with  one or more
16007	 * DataTables enhanced tables.
16008	 *
16009	 * The API class is heavily based on jQuery, presenting a chainable interface
16010	 * that you can use to interact with tables. Each instance of the API class has
16011	 * a "context" - i.e. the tables that it will operate on. This could be a single
16012	 * table, all tables on a page or a sub-set thereof.
16013	 *
16014	 * Additionally the API is designed to allow you to easily work with the data in
16015	 * the tables, retrieving and manipulating it as required. This is done by
16016	 * presenting the API class as an array like interface. The contents of the
16017	 * array depend upon the actions requested by each method (for example
16018	 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
16019	 * return an array of objects or arrays depending upon your table's
16020	 * configuration). The API object has a number of array like methods (`push`,
16021	 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
16022	 * `unique` etc) to assist your working with the data held in a table.
16023	 *
16024	 * Most methods (those which return an Api instance) are chainable, which means
16025	 * the return from a method call also has all of the methods available that the
16026	 * top level object had. For example, these two calls are equivalent:
16027	 *
16028	 *     // Not chained
16029	 *     api.row.add( {...} );
16030	 *     api.draw();
16031	 *
16032	 *     // Chained
16033	 *     api.row.add( {...} ).draw();
16034	 *
16035	 * @class DataTable.Api
16036	 * @param {array|object|string|jQuery} context DataTable identifier. This is
16037	 *   used to define which DataTables enhanced tables this API will operate on.
16038	 *   Can be one of:
16039	 *
16040	 *   * `string` - jQuery selector. Any DataTables' matching the given selector
16041	 *     with be found and used.
16042	 *   * `node` - `TABLE` node which has already been formed into a DataTable.
16043	 *   * `jQuery` - A jQuery object of `TABLE` nodes.
16044	 *   * `object` - DataTables settings object
16045	 * @param {array} [data] Data to initialise the Api instance with.
16046	 *
16047	 * @example
16048	 *   // Direct initialisation during DataTables construction
16049	 *   var api = $('#example').DataTable();
16050	 *
16051	 * @example
16052	 *   // Initialisation using a DataTables jQuery object
16053	 *   var api = $('#example').dataTable().api();
16054	 *
16055	 * @example
16056	 *   // Initialisation as a constructor
16057	 *   var api = new $.fn.DataTable.Api( 'table.dataTable' );
16058	 */
16059	_Api = function ( context, data )
16060	{
16061		if ( ! (this instanceof _Api) ) {
16062			return new _Api( context, data );
16063		}
16064	
16065		var settings = [];
16066		var ctxSettings = function ( o ) {
16067			var a = _toSettings( o );
16068			if ( a ) {
16069				settings = settings.concat( a );
16070			}
16071		};
16072	
16073		if ( $.isArray( context ) ) {
16074			for ( var i=0, ien=context.length ; i<ien ; i++ ) {
16075				ctxSettings( context[i] );
16076			}
16077		}
16078		else {
16079			ctxSettings( context );
16080		}
16081	
16082		// Remove duplicates
16083		this.context = _unique( settings );
16084	
16085		// Initial data
16086		if ( data ) {
16087			$.merge( this, data );
16088		}
16089	
16090		// selector
16091		this.selector = {
16092			rows: null,
16093			cols: null,
16094			opts: null
16095		};
16096	
16097		_Api.extend( this, this, __apiStruct );
16098	};
16099	
16100	DataTable.Api = _Api;
16101	
16102	// Don't destroy the existing prototype, just extend it. Required for jQuery 2's
16103	// isPlainObject.
16104	$.extend( _Api.prototype, {
16105		any: function ()
16106		{
16107			return this.count() !== 0;
16108		},
16109	
16110	
16111		concat:  __arrayProto.concat,
16112	
16113	
16114		context: [], // array of table settings objects
16115	
16116	
16117		count: function ()
16118		{
16119			return this.flatten().length;
16120		},
16121	
16122	
16123		each: function ( fn )
16124		{
16125			for ( var i=0, ien=this.length ; i<ien; i++ ) {
16126				fn.call( this, this[i], i, this );
16127			}
16128	
16129			return this;
16130		},
16131	
16132	
16133		eq: function ( idx )
16134		{
16135			var ctx = this.context;
16136	
16137			return ctx.length > idx ?
16138				new _Api( ctx[idx], this[idx] ) :
16139				null;
16140		},
16141	
16142	
16143		filter: function ( fn )
16144		{
16145			var a = [];
16146	
16147			if ( __arrayProto.filter ) {
16148				a = __arrayProto.filter.call( this, fn, this );
16149			}
16150			else {
16151				// Compatibility for browsers without EMCA-252-5 (JS 1.6)
16152				for ( var i=0, ien=this.length ; i<ien ; i++ ) {
16153					if ( fn.call( this, this[i], i, this ) ) {
16154						a.push( this[i] );
16155					}
16156				}
16157			}
16158	
16159			return new _Api( this.context, a );
16160		},
16161	
16162	
16163		flatten: function ()
16164		{
16165			var a = [];
16166			return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
16167		},
16168	
16169	
16170		join:    __arrayProto.join,
16171	
16172	
16173		indexOf: __arrayProto.indexOf || function (obj, start)
16174		{
16175			for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
16176				if ( this[i] === obj ) {
16177					return i;
16178				}
16179			}
16180			return -1;
16181		},
16182	
16183		iterator: function ( flatten, type, fn, alwaysNew ) {
16184			var
16185				a = [], ret,
16186				i, ien, j, jen,
16187				context = this.context,
16188				rows, items, item,
16189				selector = this.selector;
16190	
16191			// Argument shifting
16192			if ( typeof flatten === 'string' ) {
16193				alwaysNew = fn;
16194				fn = type;
16195				type = flatten;
16196				flatten = false;
16197			}
16198	
16199			for ( i=0, ien=context.length ; i<ien ; i++ ) {
16200				var apiInst = new _Api( context[i] );
16201	
16202				if ( type === 'table' ) {
16203					ret = fn.call( apiInst, context[i], i );
16204	
16205					if ( ret !== undefined ) {
16206						a.push( ret );
16207					}
16208				}
16209				else if ( type === 'columns' || type === 'rows' ) {
16210					// this has same length as context - one entry for each table
16211					ret = fn.call( apiInst, context[i], this[i], i );
16212	
16213					if ( ret !== undefined ) {
16214						a.push( ret );
16215					}
16216				}
16217				else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
16218					// columns and rows share the same structure.
16219					// 'this' is an array of column indexes for each context
16220					items = this[i];
16221	
16222					if ( type === 'column-rows' ) {
16223						rows = _selector_row_indexes( context[i], selector.opts );
16224					}
16225	
16226					for ( j=0, jen=items.length ; j<jen ; j++ ) {
16227						item = items[j];
16228	
16229						if ( type === 'cell' ) {
16230							ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
16231						}
16232						else {
16233							ret = fn.call( apiInst, context[i], item, i, j, rows );
16234						}
16235	
16236						if ( ret !== undefined ) {
16237							a.push( ret );
16238						}
16239					}
16240				}
16241			}
16242	
16243			if ( a.length || alwaysNew ) {
16244				var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
16245				var apiSelector = api.selector;
16246				apiSelector.rows = selector.rows;
16247				apiSelector.cols = selector.cols;
16248				apiSelector.opts = selector.opts;
16249				return api;
16250			}
16251			return this;
16252		},
16253	
16254	
16255		lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
16256		{
16257			// Bit cheeky...
16258			return this.indexOf.apply( this.toArray.reverse(), arguments );
16259		},
16260	
16261	
16262		length:  0,
16263	
16264	
16265		map: function ( fn )
16266		{
16267			var a = [];
16268	
16269			if ( __arrayProto.map ) {
16270				a = __arrayProto.map.call( this, fn, this );
16271			}
16272			else {
16273				// Compatibility for browsers without EMCA-252-5 (JS 1.6)
16274				for ( var i=0, ien=this.length ; i<ien ; i++ ) {
16275					a.push( fn.call( this, this[i], i ) );
16276				}
16277			}
16278	
16279			return new _Api( this.context, a );
16280		},
16281	
16282	
16283		pluck: function ( prop )
16284		{
16285			return this.map( function ( el ) {
16286				return el[ prop ];
16287			} );
16288		},
16289	
16290		pop:     __arrayProto.pop,
16291	
16292	
16293		push:    __arrayProto.push,
16294	
16295	
16296		// Does not return an API instance
16297		reduce: __arrayProto.reduce || function ( fn, init )
16298		{
16299			return _fnReduce( this, fn, init, 0, this.length, 1 );
16300		},
16301	
16302	
16303		reduceRight: __arrayProto.reduceRight || function ( fn, init )
16304		{
16305			return _fnReduce( this, fn, init, this.length-1, -1, -1 );
16306		},
16307	
16308	
16309		reverse: __arrayProto.reverse,
16310	
16311	
16312		// Object with rows, columns and opts
16313		selector: null,
16314	
16315	
16316		shift:   __arrayProto.shift,
16317	
16318	
16319		slice: function () {
16320			return new _Api( this.context, this );
16321		},
16322	
16323	
16324		sort:    __arrayProto.sort, // ? name - order?
16325	
16326	
16327		splice:  __arrayProto.splice,
16328	
16329	
16330		toArray: function ()
16331		{
16332			return __arrayProto.slice.call( this );
16333		},
16334	
16335	
16336		to$: function ()
16337		{
16338			return $( this );
16339		},
16340	
16341	
16342		toJQuery: function ()
16343		{
16344			return $( this );
16345		},
16346	
16347	
16348		unique: function ()
16349		{
16350			return new _Api( this.context, _unique(this) );
16351		},
16352	
16353	
16354		unshift: __arrayProto.unshift
16355	} );
16356	
16357	
16358	_Api.extend = function ( scope, obj, ext )
16359	{
16360		// Only extend API instances and static properties of the API
16361		if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
16362			return;
16363		}
16364	
16365		var
16366			i, ien,
16367			j, jen,
16368			struct, inner,
16369			methodScoping = function ( scope, fn, struc ) {
16370				return function () {
16371					var ret = fn.apply( scope, arguments );
16372	
16373					// Method extension
16374					_Api.extend( ret, ret, struc.methodExt );
16375					return ret;
16376				};
16377			};
16378	
16379		for ( i=0, ien=ext.length ; i<ien ; i++ ) {
16380			struct = ext[i];
16381	
16382			// Value
16383			obj[ struct.name ] = typeof struct.val === 'function' ?
16384				methodScoping( scope, struct.val, struct ) :
16385				$.isPlainObject( struct.val ) ?
16386					{} :
16387					struct.val;
16388	
16389			obj[ struct.name ].__dt_wrapper = true;
16390	
16391			// Property extension
16392			_Api.extend( scope, obj[ struct.name ], struct.propExt );
16393		}
16394	};
16395	
16396	
16397	// @todo - Is there need for an augment function?
16398	// _Api.augment = function ( inst, name )
16399	// {
16400	// 	// Find src object in the structure from the name
16401	// 	var parts = name.split('.');
16402	
16403	// 	_Api.extend( inst, obj );
16404	// };
16405	
16406	
16407	//     [
16408	//       {
16409	//         name:      'data'                -- string   - Property name
16410	//         val:       function () {},       -- function - Api method (or undefined if just an object
16411	//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
16412	//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
16413	//       },
16414	//       {
16415	//         name:     'row'
16416	//         val:       {},
16417	//         methodExt: [ ... ],
16418	//         propExt:   [
16419	//           {
16420	//             name:      'data'
16421	//             val:       function () {},
16422	//             methodExt: [ ... ],
16423	//             propExt:   [ ... ]
16424	//           },
16425	//           ...
16426	//         ]
16427	//       }
16428	//     ]
16429	
16430	_Api.register = _api_register = function ( name, val )
16431	{
16432		if ( $.isArray( name ) ) {
16433			for ( var j=0, jen=name.length ; j<jen ; j++ ) {
16434				_Api.register( name[j], val );
16435			}
16436			return;
16437		}
16438	
16439		var
16440			i, ien,
16441			heir = name.split('.'),
16442			struct = __apiStruct,
16443			key, method;
16444	
16445		var find = function ( src, name ) {
16446			for ( var i=0, ien=src.length ; i<ien ; i++ ) {
16447				if ( src[i].name === name ) {
16448					return src[i];
16449				}
16450			}
16451			return null;
16452		};
16453	
16454		for ( i=0, ien=heir.length ; i<ien ; i++ ) {
16455			method = heir[i].indexOf('()') !== -1;
16456			key = method ?
16457				heir[i].replace('()', '') :
16458				heir[i];
16459	
16460			var src = find( struct, key );
16461			if ( ! src ) {
16462				src = {
16463					name:      key,
16464					val:       {},
16465					methodExt: [],
16466					propExt:   []
16467				};
16468				struct.push( src );
16469			}
16470	
16471			if ( i === ien-1 ) {
16472				src.val = val;
16473			}
16474			else {
16475				struct = method ?
16476					src.methodExt :
16477					src.propExt;
16478			}
16479		}
16480	};
16481	
16482	
16483	_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
16484		_Api.register( pluralName, val );
16485	
16486		_Api.register( singularName, function () {
16487			var ret = val.apply( this, arguments );
16488	
16489			if ( ret === this ) {
16490				// Returned item is the API instance that was passed in, return it
16491				return this;
16492			}
16493			else if ( ret instanceof _Api ) {
16494				// New API instance returned, want the value from the first item
16495				// in the returned array for the singular result.
16496				return ret.length ?
16497					$.isArray( ret[0] ) ?
16498						new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
16499						ret[0] :
16500					undefined;
16501			}
16502	
16503			// Non-API return - just fire it back
16504			return ret;
16505		} );
16506	};
16507	
16508	
16509	/**
16510	 * Selector for HTML tables. Apply the given selector to the give array of
16511	 * DataTables settings objects.
16512	 *
16513	 * @param {string|integer} [selector] jQuery selector string or integer
16514	 * @param  {array} Array of DataTables settings objects to be filtered
16515	 * @return {array}
16516	 * @ignore
16517	 */
16518	var __table_selector = function ( selector, a )
16519	{
16520		// Integer is used to pick out a table by index
16521		if ( typeof selector === 'number' ) {
16522			return [ a[ selector ] ];
16523		}
16524	
16525		// Perform a jQuery selector on the table nodes
16526		var nodes = $.map( a, function (el, i) {
16527			return el.nTable;
16528		} );
16529	
16530		return $(nodes)
16531			.filter( selector )
16532			.map( function (i) {
16533				// Need to translate back from the table node to the settings
16534				var idx = $.inArray( this, nodes );
16535				return a[ idx ];
16536			} )
16537			.toArray();
16538	};
16539	
16540	
16541	
16542	/**
16543	 * Context selector for the API's context (i.e. the tables the API instance
16544	 * refers to.
16545	 *
16546	 * @name    DataTable.Api#tables
16547	 * @param {string|integer} [selector] Selector to pick which tables the iterator
16548	 *   should operate on. If not given, all tables in the current context are
16549	 *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
16550	 *   select multiple tables or as an integer to select a single table.
16551	 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
16552	 */
16553	_api_register( 'tables()', function ( selector ) {
16554		// A new instance is created if there was a selector specified
16555		return selector
vendor: 9,632 bytes, lines 16555-16903
16555 ?
16556			new _Api( __table_selector( selector, this.context ) ) :
16557			this;
16558	} );
16559	
16560	
16561	_api_register( 'table()', function ( selector ) {
16562		var tables = this.tables( selector );
16563		var ctx = tables.context;
16564	
16565		// Truncate to the first matched table
16566		return ctx.length ?
16567			new _Api( ctx[0] ) :
16568			tables;
16569	} );
16570	
16571	
16572	_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
16573		return this.iterator( 'table', function ( ctx ) {
16574			return ctx.nTable;
16575		}, 1 );
16576	} );
16577	
16578	
16579	_api_registerPlural( 'tables().body()', 'table().body()' , function () {
16580		return this.iterator( 'table', function ( ctx ) {
16581			return ctx.nTBody;
16582		}, 1 );
16583	} );
16584	
16585	
16586	_api_registerPlural( 'tables().header()', 'table().header()' , function () {
16587		return this.iterator( 'table', function ( ctx ) {
16588			return ctx.nTHead;
16589		}, 1 );
16590	} );
16591	
16592	
16593	_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
16594		return this.iterator( 'table', function ( ctx ) {
16595			return ctx.nTFoot;
16596		}, 1 );
16597	} );
16598	
16599	
16600	_api_registerPlural( 'tables().containers()', 'table().container()' , function () {
16601		return this.iterator( 'table', function ( ctx ) {
16602			return ctx.nTableWrapper;
16603		}, 1 );
16604	} );
16605	
16606	
16607	
16608	/**
16609	 * Redraw the tables in the current context.
16610	 */
16611	_api_register( 'draw()', function ( paging ) {
16612		return this.iterator( 'table', function ( settings ) {
16613			if ( paging === 'page' ) {
16614				_fnDraw( settings );
16615			}
16616			else {
16617				if ( typeof paging === 'string' ) {
16618					paging = paging === 'full-hold' ?
16619						false :
16620						true;
16621				}
16622	
16623				_fnReDraw( settings, paging===false );
16624			}
16625		} );
16626	} );
16627	
16628	
16629	
16630	/**
16631	 * Get the current page index.
16632	 *
16633	 * @return {integer} Current page index (zero based)
16634	 *//**
16635	 * Set the current page.
16636	 *
16637	 * Note that if you attempt to show a page which does not exist, DataTables will
16638	 * not throw an error, but rather reset the paging.
16639	 *
16640	 * @param {integer|string} action The paging action to take. This can be one of:
16641	 *  * `integer` - The page index to jump to
16642	 *  * `string` - An action to take:
16643	 *    * `first` - Jump to first page.
16644	 *    * `next` - Jump to the next page
16645	 *    * `previous` - Jump to previous page
16646	 *    * `last` - Jump to the last page.
16647	 * @returns {DataTables.Api} this
16648	 */
16649	_api_register( 'page()', function ( action ) {
16650		if ( action === undefined ) {
16651			return this.page.info().page; // not an expensive call
16652		}
16653	
16654		// else, have an action to take on all tables
16655		return this.iterator( 'table', function ( settings ) {
16656			_fnPageChange( settings, action );
16657		} );
16658	} );
16659	
16660	
16661	/**
16662	 * Paging information for the first table in the current context.
16663	 *
16664	 * If you require paging information for another table, use the `table()` method
16665	 * with a suitable selector.
16666	 *
16667	 * @return {object} Object with the following properties set:
16668	 *  * `page` - Current page index (zero based - i.e. the first page is `0`)
16669	 *  * `pages` - Total number of pages
16670	 *  * `start` - Display index for the first record shown on the current page
16671	 *  * `end` - Display index for the last record shown on the current page
16672	 *  * `length` - Display length (number of records). Note that generally `start
16673	 *    + length = end`, but this is not always true, for example if there are
16674	 *    only 2 records to show on the final page, with a length of 10.
16675	 *  * `recordsTotal` - Full data set length
16676	 *  * `recordsDisplay` - Data set length once the current filtering criterion
16677	 *    are applied.
16678	 */
16679	_api_register( 'page.info()', function ( action ) {
16680		if ( this.context.length === 0 ) {
16681			return undefined;
16682		}
16683	
16684		var
16685			settings   = this.context[0],
16686			start      = settings._iDisplayStart,
16687			len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
16688			visRecords = settings.fnRecordsDisplay(),
16689			all        = len === -1;
16690	
16691		return {
16692			"page":           all ? 0 : Math.floor( start / len ),
16693			"pages":          all ? 1 : Math.ceil( visRecords / len ),
16694			"start":          start,
16695			"end":            settings.fnDisplayEnd(),
16696			"length":         len,
16697			"recordsTotal":   settings.fnRecordsTotal(),
16698			"recordsDisplay": visRecords,
16699			"serverSide":     _fnDataSource( settings ) === 'ssp'
16700		};
16701	} );
16702	
16703	
16704	/**
16705	 * Get the current page length.
16706	 *
16707	 * @return {integer} Current page length. Note `-1` indicates that all records
16708	 *   are to be shown.
16709	 *//**
16710	 * Set the current page length.
16711	 *
16712	 * @param {integer} Page length to set. Use `-1` to show all records.
16713	 * @returns {DataTables.Api} this
16714	 */
16715	_api_register( 'page.len()', function ( len ) {
16716		// Note that we can't call this function 'length()' because `length`
16717		// is a Javascript property of functions which defines how many arguments
16718		// the function expects.
16719		if ( len === undefined ) {
16720			return this.context.length !== 0 ?
16721				this.context[0]._iDisplayLength :
16722				undefined;
16723		}
16724	
16725		// else, set the page length
16726		return this.iterator( 'table', function ( settings ) {
16727			_fnLengthChange( settings, len );
16728		} );
16729	} );
16730	
16731	
16732	
16733	var __reload = function ( settings, holdPosition, callback ) {
16734		// Use the draw event to trigger a callback
16735		if ( callback ) {
16736			var api = new _Api( settings );
16737	
16738			api.one( 'draw', function () {
16739				callback( api.ajax.json() );
16740			} );
16741		}
16742	
16743		if ( _fnDataSource( settings ) == 'ssp' ) {
16744			_fnReDraw( settings, holdPosition );
16745		}
16746		else {
16747			_fnProcessingDisplay( settings, true );
16748	
16749			// Cancel an existing request
16750			var xhr = settings.jqXHR;
16751			if ( xhr && xhr.readyState !== 4 ) {
16752				xhr.abort();
16753			}
16754	
16755			// Trigger xhr
16756			_fnBuildAjax( settings, [], function( json ) {
16757				_fnClearTable( settings );
16758	
16759				var data = _fnAjaxDataSrc( settings, json );
16760				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
16761					_fnAddData( settings, data[i] );
16762				}
16763	
16764				_fnReDraw( settings, holdPosition );
16765				_fnProcessingDisplay( settings, false );
16766			} );
16767		}
16768	};
16769	
16770	
16771	/**
16772	 * Get the JSON response from the last Ajax request that DataTables made to the
16773	 * server. Note that this returns the JSON from the first table in the current
16774	 * context.
16775	 *
16776	 * @return {object} JSON received from the server.
16777	 */
16778	_api_register( 'ajax.json()', function () {
16779		var ctx = this.context;
16780	
16781		if ( ctx.length > 0 ) {
16782			return ctx[0].json;
16783		}
16784	
16785		// else return undefined;
16786	} );
16787	
16788	
16789	/**
16790	 * Get the data submitted in the last Ajax request
16791	 */
16792	_api_register( 'ajax.params()', function () {
16793		var ctx = this.context;
16794	
16795		if ( ctx.length > 0 ) {
16796			return ctx[0].oAjaxData;
16797		}
16798	
16799		// else return undefined;
16800	} );
16801	
16802	
16803	/**
16804	 * Reload tables from the Ajax data source. Note that this function will
16805	 * automatically re-draw the table when the remote data has been loaded.
16806	 *
16807	 * @param {boolean} [reset=true] Reset (default) or hold the current paging
16808	 *   position. A full re-sort and re-filter is performed when this method is
16809	 *   called, which is why the pagination reset is the default action.
16810	 * @returns {DataTables.Api} this
16811	 */
16812	_api_register( 'ajax.reload()', function ( callback, resetPaging ) {
16813		return this.iterator( 'table', function (settings) {
16814			__reload( settings, resetPaging===false, callback );
16815		} );
16816	} );
16817	
16818	
16819	/**
16820	 * Get the current Ajax URL. Note that this returns the URL from the first
16821	 * table in the current context.
16822	 *
16823	 * @return {string} Current Ajax source URL
16824	 *//**
16825	 * Set the Ajax URL. Note that this will set the URL for all tables in the
16826	 * current context.
16827	 *
16828	 * @param {string} url URL to set.
16829	 * @returns {DataTables.Api} this
16830	 */
16831	_api_register( 'ajax.url()', function ( url ) {
16832		var ctx = this.context;
16833	
16834		if ( url === undefined ) {
16835			// get
16836			if ( ctx.length === 0 ) {
16837				return undefined;
16838			}
16839			ctx = ctx[0];
16840	
16841			return ctx.ajax ?
16842				$.isPlainObject( ctx.ajax ) ?
16843					ctx.ajax.url :
16844					ctx.ajax :
16845				ctx.sAjaxSource;
16846		}
16847	
16848		// set
16849		return this.iterator( 'table', function ( settings ) {
16850			if ( $.isPlainObject( settings.ajax ) ) {
16851				settings.ajax.url = url;
16852			}
16853			else {
16854				settings.ajax = url;
16855			}
16856			// No need to consider sAjaxSource here since DataTables gives priority
16857			// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
16858			// value of `sAjaxSource` redundant.
16859		} );
16860	} );
16861	
16862	
16863	/**
16864	 * Load data from the newly set Ajax URL. Note that this method is only
16865	 * available when `ajax.url()` is used to set a URL. Additionally, this method
16866	 * has the same effect as calling `ajax.reload()` but is provided for
16867	 * convenience when setting a new URL. Like `ajax.reload()` it will
16868	 * automatically redraw the table once the remote data has been loaded.
16869	 *
16870	 * @returns {DataTables.Api} this
16871	 */
16872	_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
16873		// Same as a reload, but makes sense to present it for easy access after a
16874		// url change
16875		return this.iterator( 'table', function ( ctx ) {
16876			__reload( ctx, resetPaging===false, callback );
16877		} );
16878	} );
16879	
16880	
16881	
16882	
16883	var _selector_run = function ( type, selector, selectFn, settings, opts )
16884	{
16885		var
16886			out = [], res,
16887			a, i, ien, j, jen,
16888			selectorType = typeof selector;
16889	
16890		// Can't just check for isArray here, as an API or jQuery instance might be
16891		// given with their array like look
16892		if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
16893			selector = [ selector ];
16894		}
16895	
16896		for ( i=0, ien=selector.length ; i<ien ; i++ ) {
16897			// Only split on simple strings - complex expressions will be jQuery selectors
16898			a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
16899				selector[i].split(',') :
16900				[ selector[i] ];
16901	
16902			for ( j=0, jen=a.length ; j<jen ; j++ ) {
16903				res = selectFn( typeof a[j] === 'string' ? 
vendor: 47,871 bytes, lines 16903-18703
16903$.trim(a[j]) : a[j] );
16904	
16905				if ( res && res.length ) {
16906					out = out.concat( res );
16907				}
16908			}
16909		}
16910	
16911		// selector extensions
16912		var ext = _ext.selector[ type ];
16913		if ( ext.length ) {
16914			for ( i=0, ien=ext.length ; i<ien ; i++ ) {
16915				out = ext[i]( settings, opts, out );
16916			}
16917		}
16918	
16919		return _unique( out );
16920	};
16921	
16922	
16923	var _selector_opts = function ( opts )
16924	{
16925		if ( ! opts ) {
16926			opts = {};
16927		}
16928	
16929		// Backwards compatibility for 1.9- which used the terminology filter rather
16930		// than search
16931		if ( opts.filter && opts.search === undefined ) {
16932			opts.search = opts.filter;
16933		}
16934	
16935		return $.extend( {
16936			search: 'none',
16937			order: 'current',
16938			page: 'all'
16939		}, opts );
16940	};
16941	
16942	
16943	var _selector_first = function ( inst )
16944	{
16945		// Reduce the API instance to the first item found
16946		for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
16947			if ( inst[i].length > 0 ) {
16948				// Assign the first element to the first item in the instance
16949				// and truncate the instance and context
16950				inst[0] = inst[i];
16951				inst[0].length = 1;
16952				inst.length = 1;
16953				inst.context = [ inst.context[i] ];
16954	
16955				return inst;
16956			}
16957		}
16958	
16959		// Not found - return an empty instance
16960		inst.length = 0;
16961		return inst;
16962	};
16963	
16964	
16965	var _selector_row_indexes = function ( settings, opts )
16966	{
16967		var
16968			i, ien, tmp, a=[],
16969			displayFiltered = settings.aiDisplay,
16970			displayMaster = settings.aiDisplayMaster;
16971	
16972		var
16973			search = opts.search,  // none, applied, removed
16974			order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
16975			page   = opts.page;    // all, current
16976	
16977		if ( _fnDataSource( settings ) == 'ssp' ) {
16978			// In server-side processing mode, most options are irrelevant since
16979			// rows not shown don't exist and the index order is the applied order
16980			// Removed is a special case - for consistency just return an empty
16981			// array
16982			return search === 'removed' ?
16983				[] :
16984				_range( 0, displayMaster.length );
16985		}
16986		else if ( page == 'current' ) {
16987			// Current page implies that order=current and fitler=applied, since it is
16988			// fairly senseless otherwise, regardless of what order and search actually
16989			// are
16990			for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
16991				a.push( displayFiltered[i] );
16992			}
16993		}
16994		else if ( order == 'current' || order == 'applied' ) {
16995			if ( search == 'none') {
16996				a = displayMaster.slice();
16997			}
16998			else if ( search == 'applied' ) {
16999				a = displayFiltered.slice();
17000			}
17001			else if ( search == 'removed' ) {
17002				// O(n+m) solution by creating a hash map
17003				var displayFilteredMap = {};
17004	
17005				for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
17006					displayFilteredMap[displayFiltered[i]] = null;
17007				}
17008	
17009				a = $.map( displayMaster, function (el) {
17010					return ! displayFilteredMap.hasOwnProperty(el) ?
17011						el :
17012						null;
17013				} );
17014			}
17015		}
17016		else if ( order == 'index' || order == 'original' ) {
17017			for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
17018				if ( search == 'none' ) {
17019					a.push( i );
17020				}
17021				else { // applied | removed
17022					tmp = $.inArray( i, displayFiltered );
17023	
17024					if ((tmp === -1 && search == 'removed') ||
17025						(tmp >= 0   && search == 'applied') )
17026					{
17027						a.push( i );
17028					}
17029				}
17030			}
17031		}
17032	
17033		return a;
17034	};
17035	
17036	
17037	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17038	 * Rows
17039	 *
17040	 * {}          - no selector - use all available rows
17041	 * {integer}   - row aoData index
17042	 * {node}      - TR node
17043	 * {string}    - jQuery selector to apply to the TR elements
17044	 * {array}     - jQuery array of nodes, or simply an array of TR nodes
17045	 *
17046	 */
17047	var __row_selector = function ( settings, selector, opts )
17048	{
17049		var rows;
17050		var run = function ( sel ) {
17051			var selInt = _intVal( sel );
17052			var i, ien;
17053			var aoData = settings.aoData;
17054	
17055			// Short cut - selector is a number and no options provided (default is
17056			// all records, so no need to check if the index is in there, since it
17057			// must be - dev error if the index doesn't exist).
17058			if ( selInt !== null && ! opts ) {
17059				return [ selInt ];
17060			}
17061	
17062			if ( ! rows ) {
17063				rows = _selector_row_indexes( settings, opts );
17064			}
17065	
17066			if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
17067				// Selector - integer
17068				return [ selInt ];
17069			}
17070			else if ( sel === null || sel === undefined || sel === '' ) {
17071				// Selector - none
17072				return rows;
17073			}
17074	
17075			// Selector - function
17076			if ( typeof sel === 'function' ) {
17077				return $.map( rows, function (idx) {
17078					var row = aoData[ idx ];
17079					return sel( idx, row._aData, row.nTr ) ? idx : null;
17080				} );
17081			}
17082	
17083			// Selector - node
17084			if ( sel.nodeName ) {
17085				var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
17086				var cellIdx = sel._DT_CellIndex;
17087	
17088				if ( rowIdx !== undefined ) {
17089					// Make sure that the row is actually still present in the table
17090					return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
17091						[ rowIdx ] :
17092						[];
17093				}
17094				else if ( cellIdx ) {
17095					return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel ?
17096						[ cellIdx.row ] :
17097						[];
17098				}
17099				else {
17100					var host = $(sel).closest('*[data-dt-row]');
17101					return host.length ?
17102						[ host.data('dt-row') ] :
17103						[];
17104				}
17105			}
17106	
17107			// ID selector. Want to always be able to select rows by id, regardless
17108			// of if the tr element has been created or not, so can't rely upon
17109			// jQuery here - hence a custom implementation. This does not match
17110			// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
17111			// but to select it using a CSS selector engine (like Sizzle or
17112			// querySelect) it would need to need to be escaped for some characters.
17113			// DataTables simplifies this for row selectors since you can select
17114			// only a row. A # indicates an id any anything that follows is the id -
17115			// unescaped.
17116			if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
17117				// get row index from id
17118				var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
17119				if ( rowObj !== undefined ) {
17120					return [ rowObj.idx ];
17121				}
17122	
17123				// need to fall through to jQuery in case there is DOM id that
17124				// matches
17125			}
17126			
17127			// Get nodes in the order from the `rows` array with null values removed
17128			var nodes = _removeEmpty(
17129				_pluck_order( settings.aoData, rows, 'nTr' )
17130			);
17131	
17132			// Selector - jQuery selector string, array of nodes or jQuery object/
17133			// As jQuery's .filter() allows jQuery objects to be passed in filter,
17134			// it also allows arrays, so this will cope with all three options
17135			return $(nodes)
17136				.filter( sel )
17137				.map( function () {
17138					return this._DT_RowIndex;
17139				} )
17140				.toArray();
17141		};
17142	
17143		return _selector_run( 'row', selector, run, settings, opts );
17144	};
17145	
17146	
17147	_api_register( 'rows()', function ( selector, opts ) {
17148		// argument shifting
17149		if ( selector === undefined ) {
17150			selector = '';
17151		}
17152		else if ( $.isPlainObject( selector ) ) {
17153			opts = selector;
17154			selector = '';
17155		}
17156	
17157		opts = _selector_opts( opts );
17158	
17159		var inst = this.iterator( 'table', function ( settings ) {
17160			return __row_selector( settings, selector, opts );
17161		}, 1 );
17162	
17163		// Want argument shifting here and in __row_selector?
17164		inst.selector.rows = selector;
17165		inst.selector.opts = opts;
17166	
17167		return inst;
17168	} );
17169	
17170	_api_register( 'rows().nodes()', function () {
17171		return this.iterator( 'row', function ( settings, row ) {
17172			return settings.aoData[ row ].nTr || undefined;
17173		}, 1 );
17174	} );
17175	
17176	_api_register( 'rows().data()', function () {
17177		return this.iterator( true, 'rows', function ( settings, rows ) {
17178			return _pluck_order( settings.aoData, rows, '_aData' );
17179		}, 1 );
17180	} );
17181	
17182	_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
17183		return this.iterator( 'row', function ( settings, row ) {
17184			var r = settings.aoData[ row ];
17185			return type === 'search' ? r._aFilterData : r._aSortData;
17186		}, 1 );
17187	} );
17188	
17189	_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
17190		return this.iterator( 'row', function ( settings, row ) {
17191			_fnInvalidate( settings, row, src );
17192		} );
17193	} );
17194	
17195	_api_registerPlural( 'rows().indexes()', 'row().index()', function () {
17196		return this.iterator( 'row', function ( settings, row ) {
17197			return row;
17198		}, 1 );
17199	} );
17200	
17201	_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
17202		var a = [];
17203		var context = this.context;
17204	
17205		// `iterator` will drop undefined values, but in this case we want them
17206		for ( var i=0, ien=context.length ; i<ien ; i++ ) {
17207			for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
17208				var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
17209				a.push( (hash === true ? '#' : '' )+ id );
17210			}
17211		}
17212	
17213		return new _Api( context, a );
17214	} );
17215	
17216	_api_registerPlural( 'rows().remove()', 'row().remove()', function () {
17217		var that = this;
17218	
17219		this.iterator( 'row', function ( settings, row, thatIdx ) {
17220			var data = settings.aoData;
17221			var rowData = data[ row ];
17222			var i, ien, j, jen;
17223			var loopRow, loopCells;
17224	
17225			data.splice( row, 1 );
17226	
17227			// Update the cached indexes
17228			for ( i=0, ien=data.length ; i<ien ; i++ ) {
17229				loopRow = data[i];
17230				loopCells = loopRow.anCells;
17231	
17232				// Rows
17233				if ( loopRow.nTr !== null ) {
17234					loopRow.nTr._DT_RowIndex = i;
17235				}
17236	
17237				// Cells
17238				if ( loopCells !== null ) {
17239					for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
17240						loopCells[j]._DT_CellIndex.row = i;
17241					}
17242				}
17243			}
17244	
17245			// Delete from the display arrays
17246			_fnDeleteIndex( settings.aiDisplayMaster, row );
17247			_fnDeleteIndex( settings.aiDisplay, row );
17248			_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
17249	
17250			// For server-side processing tables - subtract the deleted row from the count
17251			if ( settings._iRecordsDisplay > 0 ) {
17252				settings._iRecordsDisplay--;
17253			}
17254	
17255			// Check for an 'overflow' they case for displaying the table
17256			_fnLengthOverflow( settings );
17257	
17258			// Remove the row's ID reference if there is one
17259			var id = settings.rowIdFn( rowData._aData );
17260			if ( id !== undefined ) {
17261				delete settings.aIds[ id ];
17262			}
17263		} );
17264	
17265		this.iterator( 'table', function ( settings ) {
17266			for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
17267				settings.aoData[i].idx = i;
17268			}
17269		} );
17270	
17271		return this;
17272	} );
17273	
17274	
17275	_api_register( 'rows.add()', function ( rows ) {
17276		var newRows = this.iterator( 'table', function ( settings ) {
17277				var row, i, ien;
17278				var out = [];
17279	
17280				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
17281					row = rows[i];
17282	
17283					if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
17284						out.push( _fnAddTr( settings, row )[0] );
17285					}
17286					else {
17287						out.push( _fnAddData( settings, row ) );
17288					}
17289				}
17290	
17291				return out;
17292			}, 1 );
17293	
17294		// Return an Api.rows() extended instance, so rows().nodes() etc can be used
17295		var modRows = this.rows( -1 );
17296		modRows.pop();
17297		$.merge( modRows, newRows );
17298	
17299		return modRows;
17300	} );
17301	
17302	
17303	
17304	
17305	
17306	/**
17307	 *
17308	 */
17309	_api_register( 'row()', function ( selector, opts ) {
17310		return _selector_first( this.rows( selector, opts ) );
17311	} );
17312	
17313	
17314	_api_register( 'row().data()', function ( data ) {
17315		var ctx = this.context;
17316	
17317		if ( data === undefined ) {
17318			// Get
17319			return ctx.length && this.length ?
17320				ctx[0].aoData[ this[0] ]._aData :
17321				undefined;
17322		}
17323	
17324		// Set
17325		var row = ctx[0].aoData[ this[0] ];
17326		row._aData = data;
17327	
17328		// If the DOM has an id, and the data source is an array
17329		if ( $.isArray( data ) && row.nTr.id ) {
17330			_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
17331		}
17332	
17333		// Automatically invalidate
17334		_fnInvalidate( ctx[0], this[0], 'data' );
17335	
17336		return this;
17337	} );
17338	
17339	
17340	_api_register( 'row().node()', function () {
17341		var ctx = this.context;
17342	
17343		return ctx.length && this.length ?
17344			ctx[0].aoData[ this[0] ].nTr || null :
17345			null;
17346	} );
17347	
17348	
17349	_api_register( 'row.add()', function ( row ) {
17350		// Allow a jQuery object to be passed in - only a single row is added from
17351		// it though - the first element in the set
17352		if ( row instanceof $ && row.length ) {
17353			row = row[0];
17354		}
17355	
17356		var rows = this.iterator( 'table', function ( settings ) {
17357			if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
17358				return _fnAddTr( settings, row )[0];
17359			}
17360			return _fnAddData( settings, row );
17361		} );
17362	
17363		// Return an Api.rows() extended instance, with the newly added row selected
17364		return this.row( rows[0] );
17365	} );
17366	
17367	
17368	
17369	var __details_add = function ( ctx, row, data, klass )
17370	{
17371		// Convert to array of TR elements
17372		var rows = [];
17373		var addRow = function ( r, k ) {
17374			// Recursion to allow for arrays of jQuery objects
17375			if ( $.isArray( r ) || r instanceof $ ) {
17376				for ( var i=0, ien=r.length ; i<ien ; i++ ) {
17377					addRow( r[i], k );
17378				}
17379				return;
17380			}
17381	
17382			// If we get a TR element, then just add it directly - up to the dev
17383			// to add the correct number of columns etc
17384			if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
17385				rows.push( r );
17386			}
17387			else {
17388				// Otherwise create a row with a wrapper
17389				var created = $('<tr><td/></tr>').addClass( k );
17390				$('td', created)
17391					.addClass( k )
17392					.html( r )
17393					[0].colSpan = _fnVisbleColumns( ctx );
17394	
17395				rows.push( created[0] );
17396			}
17397		};
17398	
17399		addRow( data, klass );
17400	
17401		if ( row._details ) {
17402			row._details.detach();
17403		}
17404	
17405		row._details = $(rows);
17406	
17407		// If the children were already shown, that state should be retained
17408		if ( row._detailsShow ) {
17409			row._details.insertAfter( row.nTr );
17410		}
17411	};
17412	
17413	
17414	var __details_remove = function ( api, idx )
17415	{
17416		var ctx = api.context;
17417	
17418		if ( ctx.length ) {
17419			var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
17420	
17421			if ( row && row._details ) {
17422				row._details.remove();
17423	
17424				row._detailsShow = undefined;
17425				row._details = undefined;
17426			}
17427		}
17428	};
17429	
17430	
17431	var __details_display = function ( api, show ) {
17432		var ctx = api.context;
17433	
17434		if ( ctx.length && api.length ) {
17435			var row = ctx[0].aoData[ api[0] ];
17436	
17437			if ( row._details ) {
17438				row._detailsShow = show;
17439	
17440				if ( show ) {
17441					row._details.insertAfter( row.nTr );
17442				}
17443				else {
17444					row._details.detach();
17445				}
17446	
17447				__details_events( ctx[0] );
17448			}
17449		}
17450	};
17451	
17452	
17453	var __details_events = function ( settings )
17454	{
17455		var api = new _Api( settings );
17456		var namespace = '.dt.DT_details';
17457		var drawEvent = 'draw'+namespace;
17458		var colvisEvent = 'column-visibility'+namespace;
17459		var destroyEvent = 'destroy'+namespace;
17460		var data = settings.aoData;
17461	
17462		api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
17463	
17464		if ( _pluck( data, '_details' ).length > 0 ) {
17465			// On each draw, insert the required elements into the document
17466			api.on( drawEvent, function ( e, ctx ) {
17467				if ( settings !== ctx ) {
17468					return;
17469				}
17470	
17471				api.rows( {page:'current'} ).eq(0).each( function (idx) {
17472					// Internal data grab
17473					var row = data[ idx ];
17474	
17475					if ( row._detailsShow ) {
17476						row._details.insertAfter( row.nTr );
17477					}
17478				} );
17479			} );
17480	
17481			// Column visibility change - update the colspan
17482			api.on( colvisEvent, function ( e, ctx, idx, vis ) {
17483				if ( settings !== ctx ) {
17484					return;
17485				}
17486	
17487				// Update the colspan for the details rows (note, only if it already has
17488				// a colspan)
17489				var row, visible = _fnVisbleColumns( ctx );
17490	
17491				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
17492					row = data[i];
17493	
17494					if ( row._details ) {
17495						row._details.children('td[colspan]').attr('colspan', visible );
17496					}
17497				}
17498			} );
17499	
17500			// Table destroyed - nuke any child rows
17501			api.on( destroyEvent, function ( e, ctx ) {
17502				if ( settings !== ctx ) {
17503					return;
17504				}
17505	
17506				for ( var i=0, ien=data.length ; i<ien ; i++ ) {
17507					if ( data[i]._details ) {
17508						__details_remove( api, i );
17509					}
17510				}
17511			} );
17512		}
17513	};
17514	
17515	// Strings for the method names to help minification
17516	var _emp = '';
17517	var _child_obj = _emp+'row().child';
17518	var _child_mth = _child_obj+'()';
17519	
17520	// data can be:
17521	//  tr
17522	//  string
17523	//  jQuery or array of any of the above
17524	_api_register( _child_mth, function ( data, klass ) {
17525		var ctx = this.context;
17526	
17527		if ( data === undefined ) {
17528			// get
17529			return ctx.length && this.length ?
17530				ctx[0].aoData[ this[0] ]._details :
17531				undefined;
17532		}
17533		else if ( data === true ) {
17534			// show
17535			this.child.show();
17536		}
17537		else if ( data === false ) {
17538			// remove
17539			__details_remove( this );
17540		}
17541		else if ( ctx.length && this.length ) {
17542			// set
17543			__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
17544		}
17545	
17546		return this;
17547	} );
17548	
17549	
17550	_api_register( [
17551		_child_obj+'.show()',
17552		_child_mth+'.show()' // only when `child()` was called with parameters (without
17553	], function ( show ) {   // it returns an object and this method is not executed)
17554		__details_display( this, true );
17555		return this;
17556	} );
17557	
17558	
17559	_api_register( [
17560		_child_obj+'.hide()',
17561		_child_mth+'.hide()' // only when `child()` was called with parameters (without
17562	], function () {         // it returns an object and this method is not executed)
17563		__details_display( this, false );
17564		return this;
17565	} );
17566	
17567	
17568	_api_register( [
17569		_child_obj+'.remove()',
17570		_child_mth+'.remove()' // only when `child()` was called with parameters (without
17571	], function () {           // it returns an object and this method is not executed)
17572		__details_remove( this );
17573		return this;
17574	} );
17575	
17576	
17577	_api_register( _child_obj+'.isShown()', function () {
17578		var ctx = this.context;
17579	
17580		if ( ctx.length && this.length ) {
17581			// _detailsShown as false or undefined will fall through to return false
17582			return ctx[0].aoData[ this[0] ]._detailsShow || false;
17583		}
17584		return false;
17585	} );
17586	
17587	
17588	
17589	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17590	 * Columns
17591	 *
17592	 * {integer}           - column index (>=0 count from left, <0 count from right)
17593	 * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
17594	 * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
17595	 * "{string}:name"     - column name
17596	 * "{string}"          - jQuery selector on column header nodes
17597	 *
17598	 */
17599	
17600	// can be an array of these items, comma separated list, or an array of comma
17601	// separated lists
17602	
17603	var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
17604	
17605	
17606	// r1 and r2 are redundant - but it means that the parameters match for the
17607	// iterator callback in columns().data()
17608	var __columnData = function ( settings, column, r1, r2, rows ) {
17609		var a = [];
17610		for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
17611			a.push( _fnGetCellData( settings, rows[row], column ) );
17612		}
17613		return a;
17614	};
17615	
17616	
17617	var __column_selector = function ( settings, selector, opts )
17618	{
17619		var
17620			columns = settings.aoColumns,
17621			names = _pluck( columns, 'sName' ),
17622			nodes = _pluck( columns, 'nTh' );
17623	
17624		var run = function ( s ) {
17625			var selInt = _intVal( s );
17626	
17627			// Selector - all
17628			if ( s === '' ) {
17629				return _range( columns.length );
17630			}
17631	
17632			// Selector - index
17633			if ( selInt !== null ) {
17634				return [ selInt >= 0 ?
17635					selInt : // Count from left
17636					columns.length + selInt // Count from right (+ because its a negative value)
17637				];
17638			}
17639	
17640			// Selector = function
17641			if ( typeof s === 'function' ) {
17642				var rows = _selector_row_indexes( settings, opts );
17643	
17644				return $.map( columns, function (col, idx) {
17645					return s(
17646							idx,
17647							__columnData( settings, idx, 0, 0, rows ),
17648							nodes[ idx ]
17649						) ? idx : null;
17650				} );
17651			}
17652	
17653			// jQuery or string selector
17654			var match = typeof s === 'string' ?
17655				s.match( __re_column_selector ) :
17656				'';
17657	
17658			if ( match ) {
17659				switch( match[2] ) {
17660					case 'visIdx':
17661					case 'visible':
17662						var idx = parseInt( match[1], 10 );
17663						// Visible index given, convert to column index
17664						if ( idx < 0 ) {
17665							// Counting from the right
17666							var visColumns = $.map( columns, function (col,i) {
17667								return col.bVisible ? i : null;
17668							} );
17669							return [ visColumns[ visColumns.length + idx ] ];
17670						}
17671						// Counting from the left
17672						return [ _fnVisibleToColumnIndex( settings, idx ) ];
17673	
17674					case 'name':
17675						// match by name. `names` is column index complete and in order
17676						return $.map( names, function (name, i) {
17677							return name === match[1] ? i : null;
17678						} );
17679	
17680					default:
17681						return [];
17682				}
17683			}
17684	
17685			// Cell in the table body
17686			if ( s.nodeName && s._DT_CellIndex ) {
17687				return [ s._DT_CellIndex.column ];
17688			}
17689	
17690			// jQuery selector on the TH elements for the columns
17691			var jqResult = $( nodes )
17692				.filter( s )
17693				.map( function () {
17694					return $.inArray( this, nodes ); // `nodes` is column index complete and in order
17695				} )
17696				.toArray();
17697	
17698			if ( jqResult.length || ! s.nodeName ) {
17699				return jqResult;
17700			}
17701	
17702			// Otherwise a node which might have a `dt-column` data attribute, or be
17703			// a child or such an element
17704			var host = $(s).closest('*[data-dt-column]');
17705			return host.length ?
17706				[ host.data('dt-column') ] :
17707				[];
17708		};
17709	
17710		return _selector_run( 'column', selector, run, settings, opts );
17711	};
17712	
17713	
17714	var __setColumnVis = function ( settings, column, vis ) {
17715		var
17716			cols = settings.aoColumns,
17717			col  = cols[ column ],
17718			data = settings.aoData,
17719			row, cells, i, ien, tr;
17720	
17721		// Get
17722		if ( vis === undefined ) {
17723			return col.bVisible;
17724		}
17725	
17726		// Set
17727		// No change
17728		if ( col.bVisible === vis ) {
17729			return;
17730		}
17731	
17732		if ( vis ) {
17733			// Insert column
17734			// Need to decide if we should use appendChild or insertBefore
17735			var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
17736	
17737			for ( i=0, ien=data.length ; i<ien ; i++ ) {
17738				tr = data[i].nTr;
17739				cells = data[i].anCells;
17740	
17741				if ( tr ) {
17742					// insertBefore can act like appendChild if 2nd arg is null
17743					tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
17744				}
17745			}
17746		}
17747		else {
17748			// Remove column
17749			$( _pluck( settings.aoData, 'anCells', column ) ).detach();
17750		}
17751	
17752		// Common actions
17753		col.bVisible = vis;
17754		_fnDrawHead( settings, settings.aoHeader );
17755		_fnDrawHead( settings, settings.aoFooter );
17756	
17757		// Update colspan for no records display. Child rows and extensions will use their own
17758		// listeners to do this - only need to update the empty table item here
17759		if ( ! settings.aiDisplay.length ) {
17760			$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
17761		}
17762	
17763		_fnSaveState( settings );
17764	};
17765	
17766	
17767	_api_register( 'columns()', function ( selector, opts ) {
17768		// argument shifting
17769		if ( selector === undefined ) {
17770			selector = '';
17771		}
17772		else if ( $.isPlainObject( selector ) ) {
17773			opts = selector;
17774			selector = '';
17775		}
17776	
17777		opts = _selector_opts( opts );
17778	
17779		var inst = this.iterator( 'table', function ( settings ) {
17780			return __column_selector( settings, selector, opts );
17781		}, 1 );
17782	
17783		// Want argument shifting here and in _row_selector?
17784		inst.selector.cols = selector;
17785		inst.selector.opts = opts;
17786	
17787		return inst;
17788	} );
17789	
17790	_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
17791		return this.iterator( 'column', function ( settings, column ) {
17792			return settings.aoColumns[column].nTh;
17793		}, 1 );
17794	} );
17795	
17796	_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
17797		return this.iterator( 'column', function ( settings, column ) {
17798			return settings.aoColumns[column].nTf;
17799		}, 1 );
17800	} );
17801	
17802	_api_registerPlural( 'columns().data()', 'column().data()', function () {
17803		return this.iterator( 'column-rows', __columnData, 1 );
17804	} );
17805	
17806	_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
17807		return this.iterator( 'column', function ( settings, column ) {
17808			return settings.aoColumns[column].mData;
17809		}, 1 );
17810	} );
17811	
17812	_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
17813		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
17814			return _pluck_order( settings.aoData, rows,
17815				type === 'search' ? '_aFilterData' : '_aSortData', column
17816			);
17817		}, 1 );
17818	} );
17819	
17820	_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
17821		return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
17822			return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
17823		}, 1 );
17824	} );
17825	
17826	_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
17827		var ret = this.iterator( 'column', function ( settings, column ) {
17828			if ( vis === undefined ) {
17829				return settings.aoColumns[ column ].bVisible;
17830			} // else
17831			__setColumnVis( settings, column, vis );
17832		} );
17833	
17834		// Group the column visibility changes
17835		if ( vis !== undefined ) {
17836			// Second loop once the first is done for events
17837			this.iterator( 'column', function ( settings, column ) {
17838				_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
17839			} );
17840	
17841			if ( calc === undefined || calc ) {
17842				this.columns.adjust();
17843			}
17844		}
17845	
17846		return ret;
17847	} );
17848	
17849	_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
17850		return this.iterator( 'column', function ( settings, column ) {
17851			return type === 'visible' ?
17852				_fnColumnIndexToVisible( settings, column ) :
17853				column;
17854		}, 1 );
17855	} );
17856	
17857	_api_register( 'columns.adjust()', function () {
17858		return this.iterator( 'table', function ( settings ) {
17859			_fnAdjustColumnSizing( settings );
17860		}, 1 );
17861	} );
17862	
17863	_api_register( 'column.index()', function ( type, idx ) {
17864		if ( this.context.length !== 0 ) {
17865			var ctx = this.context[0];
17866	
17867			if ( type === 'fromVisible' || type === 'toData' ) {
17868				return _fnVisibleToColumnIndex( ctx, idx );
17869			}
17870			else if ( type === 'fromData' || type === 'toVisible' ) {
17871				return _fnColumnIndexToVisible( ctx, idx );
17872			}
17873		}
17874	} );
17875	
17876	_api_register( 'column()', function ( selector, opts ) {
17877		return _selector_first( this.columns( selector, opts ) );
17878	} );
17879	
17880	
17881	
17882	var __cell_selector = function ( settings, selector, opts )
17883	{
17884		var data = settings.aoData;
17885		var rows = _selector_row_indexes( settings, opts );
17886		var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
17887		var allCells = $( [].concat.apply([], cells) );
17888		var row;
17889		var columns = settings.aoColumns.length;
17890		var a, i, ien, j, o, host;
17891	
17892		var run = function ( s ) {
17893			var fnSelector = typeof s === 'function';
17894	
17895			if ( s === null || s === undefined || fnSelector ) {
17896				// All cells and function selectors
17897				a = [];
17898	
17899				for ( i=0, ien=rows.length ; i<ien ; i++ ) {
17900					row = rows[i];
17901	
17902					for ( j=0 ; j<columns ; j++ ) {
17903						o = {
17904							row: row,
17905							column: j
17906						};
17907	
17908						if ( fnSelector ) {
17909							// Selector - function
17910							host = data[ row ];
17911	
17912							if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
17913								a.push( o );
17914							}
17915						}
17916						else {
17917							// Selector - all
17918							a.push( o );
17919						}
17920					}
17921				}
17922	
17923				return a;
17924			}
17925			
17926			// Selector - index
17927			if ( $.isPlainObject( s ) ) {
17928				// Valid cell index and its in the array of selectable rows
17929				return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?
17930					[s] :
17931					[];
17932			}
17933	
17934			// Selector - jQuery filtered cells
17935			var jqResult = allCells
17936				.filter( s )
17937				.map( function (i, el) {
17938					return { // use a new object, in case someone changes the values
17939						row:    el._DT_CellIndex.row,
17940						column: el._DT_CellIndex.column
17941	 				};
17942				} )
17943				.toArray();
17944	
17945			if ( jqResult.length || ! s.nodeName ) {
17946				return jqResult;
17947			}
17948	
17949			// Otherwise the selector is a node, and there is one last option - the
17950			// element might be a child of an element which has dt-row and dt-column
17951			// data attributes
17952			host = $(s).closest('*[data-dt-row]');
17953			return host.length ?
17954				[ {
17955					row: host.data('dt-row'),
17956					column: host.data('dt-column')
17957				} ] :
17958				[];
17959		};
17960	
17961		return _selector_run( 'cell', selector, run, settings, opts );
17962	};
17963	
17964	
17965	
17966	
17967	_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
17968		// Argument shifting
17969		if ( $.isPlainObject( rowSelector ) ) {
17970			// Indexes
17971			if ( rowSelector.row === undefined ) {
17972				// Selector options in first parameter
17973				opts = rowSelector;
17974				rowSelector = null;
17975			}
17976			else {
17977				// Cell index objects in first parameter
17978				opts = columnSelector;
17979				columnSelector = null;
17980			}
17981		}
17982		if ( $.isPlainObject( columnSelector ) ) {
17983			opts = columnSelector;
17984			columnSelector = null;
17985		}
17986	
17987		// Cell selector
17988		if ( columnSelector === null || columnSelector === undefined ) {
17989			return this.iterator( 'table', function ( settings ) {
17990				return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
17991			} );
17992		}
17993	
17994		// Row + column selector
17995		var columns = this.columns( columnSelector );
17996		var rows = this.rows( rowSelector );
17997		var a, i, ien, j, jen;
17998	
17999		this.iterator( 'table', function ( settings, idx ) {
18000			a = [];
18001	
18002			for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
18003				for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
18004					a.push( {
18005						row:    rows[idx][i],
18006						column: columns[idx][j]
18007					} );
18008				}
18009			}
18010		}, 1 );
18011	
18012	    // Now pass through the cell selector for options
18013	    var cells = this.cells( a, opts );
18014	
18015		$.extend( cells.selector, {
18016			cols: columnSelector,
18017			rows: rowSelector,
18018			opts: opts
18019		} );
18020	
18021		return cells;
18022	} );
18023	
18024	
18025	_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
18026		return this.iterator( 'cell', function ( settings, row, column ) {
18027			var data = settings.aoData[ row ];
18028	
18029			return data && data.anCells ?
18030				data.anCells[ column ] :
18031				undefined;
18032		}, 1 );
18033	} );
18034	
18035	
18036	_api_register( 'cells().data()', function () {
18037		return this.iterator( 'cell', function ( settings, row, column ) {
18038			return _fnGetCellData( settings, row, column );
18039		}, 1 );
18040	} );
18041	
18042	
18043	_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
18044		type = type === 'search' ? '_aFilterData' : '_aSortData';
18045	
18046		return this.iterator( 'cell', function ( settings, row, column ) {
18047			return settings.aoData[ row ][ type ][ column ];
18048		}, 1 );
18049	} );
18050	
18051	
18052	_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
18053		return this.iterator( 'cell', function ( settings, row, column ) {
18054			return _fnGetCellData( settings, row, column, type );
18055		}, 1 );
18056	} );
18057	
18058	
18059	_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
18060		return this.iterator( 'cell', function ( settings, row, column ) {
18061			return {
18062				row: row,
18063				column: column,
18064				columnVisible: _fnColumnIndexToVisible( settings, column )
18065			};
18066		}, 1 );
18067	} );
18068	
18069	
18070	_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
18071		return this.iterator( 'cell', function ( settings, row, column ) {
18072			_fnInvalidate( settings, row, src, column );
18073		} );
18074	} );
18075	
18076	
18077	
18078	_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
18079		return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
18080	} );
18081	
18082	
18083	_api_register( 'cell().data()', function ( data ) {
18084		var ctx = this.context;
18085		var cell = this[0];
18086	
18087		if ( data === undefined ) {
18088			// Get
18089			return ctx.length && cell.length ?
18090				_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
18091				undefined;
18092		}
18093	
18094		// Set
18095		_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
18096		_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
18097	
18098		return this;
18099	} );
18100	
18101	
18102	
18103	/**
18104	 * Get current ordering (sorting) that has been applied to the table.
18105	 *
18106	 * @returns {array} 2D array containing the sorting information for the first
18107	 *   table in the current context. Each element in the parent array represents
18108	 *   a column being sorted upon (i.e. multi-sorting with two columns would have
18109	 *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
18110	 *   the column index that the sorting condition applies to, the second is the
18111	 *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
18112	 *   index of the sorting order from the `column.sorting` initialisation array.
18113	 *//**
18114	 * Set the ordering for the table.
18115	 *
18116	 * @param {integer} order Column index to sort upon.
18117	 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
18118	 * @returns {DataTables.Api} this
18119	 *//**
18120	 * Set the ordering for the table.
18121	 *
18122	 * @param {array} order 1D array of sorting information to be applied.
18123	 * @param {array} [...] Optional additional sorting conditions
18124	 * @returns {DataTables.Api} this
18125	 *//**
18126	 * Set the ordering for the table.
18127	 *
18128	 * @param {array} order 2D array of sorting information to be applied.
18129	 * @returns {DataTables.Api} this
18130	 */
18131	_api_register( 'order()', function ( order, dir ) {
18132		var ctx = this.context;
18133	
18134		if ( order === undefined ) {
18135			// get
18136			return ctx.length !== 0 ?
18137				ctx[0].aaSorting :
18138				undefined;
18139		}
18140	
18141		// set
18142		if ( typeof order === 'number' ) {
18143			// Simple column / direction passed in
18144			order = [ [ order, dir ] ];
18145		}
18146		else if ( order.length && ! $.isArray( order[0] ) ) {
18147			// Arguments passed in (list of 1D arrays)
18148			order = Array.prototype.slice.call( arguments );
18149		}
18150		// otherwise a 2D array was passed in
18151	
18152		return this.iterator( 'table', function ( settings ) {
18153			settings.aaSorting = order.slice();
18154		} );
18155	} );
18156	
18157	
18158	/**
18159	 * Attach a sort listener to an element for a given column
18160	 *
18161	 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
18162	 *   listener to. This can take the form of a single DOM node, a jQuery
18163	 *   collection of nodes or a jQuery selector which will identify the node(s).
18164	 * @param {integer} column the column that a click on this node will sort on
18165	 * @param {function} [callback] callback function when sort is run
18166	 * @returns {DataTables.Api} this
18167	 */
18168	_api_register( 'order.listener()', function ( node, column, callback ) {
18169		return this.iterator( 'table', function ( settings ) {
18170			_fnSortAttachListener( settings, node, column, callback );
18171		} );
18172	} );
18173	
18174	
18175	_api_register( 'order.fixed()', function ( set ) {
18176		if ( ! set ) {
18177			var ctx = this.context;
18178			var fixed = ctx.length ?
18179				ctx[0].aaSortingFixed :
18180				undefined;
18181	
18182			return $.isArray( fixed ) ?
18183				{ pre: fixed } :
18184				fixed;
18185		}
18186	
18187		return this.iterator( 'table', function ( settings ) {
18188			settings.aaSortingFixed = $.extend( true, {}, set );
18189		} );
18190	} );
18191	
18192	
18193	// Order by the selected column(s)
18194	_api_register( [
18195		'columns().order()',
18196		'column().order()'
18197	], function ( dir ) {
18198		var that = this;
18199	
18200		return this.iterator( 'table', function ( settings, i ) {
18201			var sort = [];
18202	
18203			$.each( that[i], function (j, col) {
18204				sort.push( [ col, dir ] );
18205			} );
18206	
18207			settings.aaSorting = sort;
18208		} );
18209	} );
18210	
18211	
18212	
18213	_api_register( 'search()', function ( input, regex, smart, caseInsen ) {
18214		var ctx = this.context;
18215	
18216		if ( input === undefined ) {
18217			// get
18218			return ctx.length !== 0 ?
18219				ctx[0].oPreviousSearch.sSearch :
18220				undefined;
18221		}
18222	
18223		// set
18224		return this.iterator( 'table', function ( settings ) {
18225			if ( ! settings.oFeatures.bFilter ) {
18226				return;
18227			}
18228	
18229			_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
18230				"sSearch": input+"",
18231				"bRegex":  regex === null ? false : regex,
18232				"bSmart":  smart === null ? true  : smart,
18233				"bCaseInsensitive": caseInsen === null ? true : caseInsen
18234			} ), 1 );
18235		} );
18236	} );
18237	
18238	
18239	_api_registerPlural(
18240		'columns().search()',
18241		'column().search()',
18242		function ( input, regex, smart, caseInsen ) {
18243			return this.iterator( 'column', function ( settings, column ) {
18244				var preSearch = settings.aoPreSearchCols;
18245	
18246				if ( input === undefined ) {
18247					// get
18248					return preSearch[ column ].sSearch;
18249				}
18250	
18251				// set
18252				if ( ! settings.oFeatures.bFilter ) {
18253					return;
18254				}
18255	
18256				$.extend( preSearch[ column ], {
18257					"sSearch": input+"",
18258					"bRegex":  regex === null ? false : regex,
18259					"bSmart":  smart === null ? true  : smart,
18260					"bCaseInsensitive": caseInsen === null ? true : caseInsen
18261				} );
18262	
18263				_fnFilterComplete( settings, settings.oPreviousSearch, 1 );
18264			} );
18265		}
18266	);
18267	
18268	/*
18269	 * State API methods
18270	 */
18271	
18272	_api_register( 'state()', function () {
18273		return this.context.length ?
18274			this.context[0].oSavedState :
18275			null;
18276	} );
18277	
18278	
18279	_api_register( 'state.clear()', function () {
18280		return this.iterator( 'table', function ( settings ) {
18281			// Save an empty object
18282			settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
18283		} );
18284	} );
18285	
18286	
18287	_api_register( 'state.loaded()', function () {
18288		return this.context.length ?
18289			this.context[0].oLoadedState :
18290			null;
18291	} );
18292	
18293	
18294	_api_register( 'state.save()', function () {
18295		return this.iterator( 'table', function ( settings ) {
18296			_fnSaveState( settings );
18297		} );
18298	} );
18299	
18300	
18301	
18302	/**
18303	 * Provide a common method for plug-ins to check the version of DataTables being
18304	 * used, in order to ensure compatibility.
18305	 *
18306	 *  @param {string} version Version string to check for, in the format "X.Y.Z".
18307	 *    Note that the formats "X" and "X.Y" are also acceptable.
18308	 *  @returns {boolean} true if this version of DataTables is greater or equal to
18309	 *    the required version, or false if this version of DataTales is not
18310	 *    suitable
18311	 *  @static
18312	 *  @dtopt API-Static
18313	 *
18314	 *  @example
18315	 *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
18316	 */
18317	DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
18318	{
18319		var aThis = DataTable.version.split('.');
18320		var aThat = version.split('.');
18321		var iThis, iThat;
18322	
18323		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
18324			iThis = parseInt( aThis[i], 10 ) || 0;
18325			iThat = parseInt( aThat[i], 10 ) || 0;
18326	
18327			// Parts are the same, keep comparing
18328			if (iThis === iThat) {
18329				continue;
18330			}
18331	
18332			// Parts are different, return immediately
18333			return iThis > iThat;
18334		}
18335	
18336		return true;
18337	};
18338	
18339	
18340	/**
18341	 * Check if a `<table>` node is a DataTable table already or not.
18342	 *
18343	 *  @param {node|jquery|string} table Table node, jQuery object or jQuery
18344	 *      selector for the table to test. Note that if more than more than one
18345	 *      table is passed on, only the first will be checked
18346	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
18347	 *  @static
18348	 *  @dtopt API-Static
18349	 *
18350	 *  @example
18351	 *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
18352	 *      $('#example').dataTable();
18353	 *    }
18354	 */
18355	DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
18356	{
18357		var t = $(table).get(0);
18358		var is = false;
18359	
18360		if ( table instanceof DataTable.Api ) {
18361			return true;
18362		}
18363	
18364		$.each( DataTable.settings, function (i, o) {
18365			var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
18366			var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
18367	
18368			if ( o.nTable === t || head === t || foot === t ) {
18369				is = true;
18370			}
18371		} );
18372	
18373		return is;
18374	};
18375	
18376	
18377	/**
18378	 * Get all DataTable tables that have been initialised - optionally you can
18379	 * select to get only currently visible tables.
18380	 *
18381	 *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
18382	 *    or visible tables only.
18383	 *  @returns {array} Array of `table` nodes (not DataTable instances) which are
18384	 *    DataTables
18385	 *  @static
18386	 *  @dtopt API-Static
18387	 *
18388	 *  @example
18389	 *    $.each( $.fn.dataTable.tables(true), function () {
18390	 *      $(table).DataTable().columns.adjust();
18391	 *    } );
18392	 */
18393	DataTable.tables = DataTable.fnTables = function ( visible )
18394	{
18395		var api = false;
18396	
18397		if ( $.isPlainObject( visible ) ) {
18398			api = visible.api;
18399			visible = visible.visible;
18400		}
18401	
18402		var a = $.map( DataTable.settings, function (o) {
18403			if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
18404				return o.nTable;
18405			}
18406		} );
18407	
18408		return api ?
18409			new _Api( a ) :
18410			a;
18411	};
18412	
18413	
18414	/**
18415	 * Convert from camel case parameters to Hungarian notation. This is made public
18416	 * for the extensions to provide the same ability as DataTables core to accept
18417	 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
18418	 * parameters.
18419	 *
18420	 *  @param {object} src The model object which holds all parameters that can be
18421	 *    mapped.
18422	 *  @param {object} user The object to convert from camel case to Hungarian.
18423	 *  @param {boolean} force When set to `true`, properties which already have a
18424	 *    Hungarian value in the `user` object will be overwritten. Otherwise they
18425	 *    won't be.
18426	 */
18427	DataTable.camelToHungarian = _fnCamelToHungarian;
18428	
18429	
18430	
18431	/**
18432	 *
18433	 */
18434	_api_register( '$()', function ( selector, opts ) {
18435		var
18436			rows   = this.rows( opts ).nodes(), // Get all rows
18437			jqRows = $(rows);
18438	
18439		return $( [].concat(
18440			jqRows.filter( selector ).toArray(),
18441			jqRows.find( selector ).toArray()
18442		) );
18443	} );
18444	
18445	
18446	// jQuery functions to operate on the tables
18447	$.each( [ 'on', 'one', 'off' ], function (i, key) {
18448		_api_register( key+'()', function ( /* event, handler */ ) {
18449			var args = Array.prototype.slice.call(arguments);
18450	
18451			// Add the `dt` namespace automatically if it isn't already present
18452			args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
18453				return ! e.match(/\.dt\b/) ?
18454					e+'.dt' :
18455					e;
18456				} ).join( ' ' );
18457	
18458			var inst = $( this.tables().nodes() );
18459			inst[key].apply( inst, args );
18460			return this;
18461		} );
18462	} );
18463	
18464	
18465	_api_register( 'clear()', function () {
18466		return this.iterator( 'table', function ( settings ) {
18467			_fnClearTable( settings );
18468		} );
18469	} );
18470	
18471	
18472	_api_register( 'settings()', function () {
18473		return new _Api( this.context, this.context );
18474	} );
18475	
18476	
18477	_api_register( 'init()', function () {
18478		var ctx = this.context;
18479		return ctx.length ? ctx[0].oInit : null;
18480	} );
18481	
18482	
18483	_api_register( 'data()', function () {
18484		return this.iterator( 'table', function ( settings ) {
18485			return _pluck( settings.aoData, '_aData' );
18486		} ).flatten();
18487	} );
18488	
18489	
18490	_api_register( 'destroy()', function ( remove ) {
18491		remove = remove || false;
18492	
18493		return this.iterator( 'table', function ( settings ) {
18494			var orig      = settings.nTableWrapper.parentNode;
18495			var classes   = settings.oClasses;
18496			var table     = settings.nTable;
18497			var tbody     = settings.nTBody;
18498			var thead     = settings.nTHead;
18499			var tfoot     = settings.nTFoot;
18500			var jqTable   = $(table);
18501			var jqTbody   = $(tbody);
18502			var jqWrapper = $(settings.nTableWrapper);
18503			var rows      = $.map( settings.aoData, function (r) { return r.nTr; } );
18504			var i, ien;
18505	
18506			// Flag to note that the table is currently being destroyed - no action
18507			// should be taken
18508			settings.bDestroying = true;
18509	
18510			// Fire off the destroy callbacks for plug-ins etc
18511			_fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
18512	
18513			// If not being removed from the document, make all columns visible
18514			if ( ! remove ) {
18515				new _Api( settings ).columns().visible( true );
18516			}
18517	
18518			// Blitz all `DT` namespaced events (these are internal events, the
18519			// lowercase, `dt` events are user subscribed and they are responsible
18520			// for removing them
18521			jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
18522			$(window).off('.DT-'+settings.sInstance);
18523	
18524			// When scrolling we had to break the table up - restore it
18525			if ( table != thead.parentNode ) {
18526				jqTable.children('thead').detach();
18527				jqTable.append( thead );
18528			}
18529	
18530			if ( tfoot && table != tfoot.parentNode ) {
18531				jqTable.children('tfoot').detach();
18532				jqTable.append( tfoot );
18533			}
18534	
18535			settings.aaSorting = [];
18536			settings.aaSortingFixed = [];
18537			_fnSortingClasses( settings );
18538	
18539			$( rows ).removeClass( settings.asStripeClasses.join(' ') );
18540	
18541			$('th, td', thead).removeClass( classes.sSortable+' '+
18542				classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
18543			);
18544	
18545			// Add the TR elements back into the table in their original order
18546			jqTbody.children().detach();
18547			jqTbody.append( rows );
18548	
18549			// Remove the DataTables generated nodes, events and classes
18550			var removedMethod = remove ? 'remove' : 'detach';
18551			jqTable[ removedMethod ]();
18552			jqWrapper[ removedMethod ]();
18553	
18554			// If we need to reattach the table to the document
18555			if ( ! remove && orig ) {
18556				// insertBefore acts like appendChild if !arg[1]
18557				orig.insertBefore( table, settings.nTableReinsertBefore );
18558	
18559				// Restore the width of the original table - was read from the style property,
18560				// so we can restore directly to that
18561				jqTable
18562					.css( 'width', settings.sDestroyWidth )
18563					.removeClass( classes.sTable );
18564	
18565				// If the were originally stripe classes - then we add them back here.
18566				// Note this is not fool proof (for example if not all rows had stripe
18567				// classes - but it's a good effort without getting carried away
18568				ien = settings.asDestroyStripes.length;
18569	
18570				if ( ien ) {
18571					jqTbody.children().each( function (i) {
18572						$(this).addClass( settings.asDestroyStripes[i % ien] );
18573					} );
18574				}
18575			}
18576	
18577			/* Remove the settings object from the settings array */
18578			var idx = $.inArray( settings, DataTable.settings );
18579			if ( idx !== -1 ) {
18580				DataTable.settings.splice( idx, 1 );
18581			}
18582		} );
18583	} );
18584	
18585	
18586	// Add the `every()` method for rows, columns and cells in a compact form
18587	$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
18588		_api_register( type+'s().every()', function ( fn ) {
18589			var opts = this.selector.opts;
18590			var api = this;
18591	
18592			return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
18593				// Rows and columns:
18594				//  arg1 - index
18595				//  arg2 - table counter
18596				//  arg3 - loop counter
18597				//  arg4 - undefined
18598				// Cells:
18599				//  arg1 - row index
18600				//  arg2 - column index
18601				//  arg3 - table counter
18602				//  arg4 - loop counter
18603				fn.call(
18604					api[ type ](
18605						arg1,
18606						type==='cell' ? arg2 : opts,
18607						type==='cell' ? opts : undefined
18608					),
18609					arg1, arg2, arg3, arg4
18610				);
18611			} );
18612		} );
18613	} );
18614	
18615	
18616	// i18n method for extensions to be able to use the language object from the
18617	// DataTable
18618	_api_register( 'i18n()', function ( token, def, plural ) {
18619		var ctx = this.context[0];
18620		var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
18621	
18622		if ( resolved === undefined ) {
18623			resolved = def;
18624		}
18625	
18626		if ( plural !== undefined && $.isPlainObject( resolved ) ) {
18627			resolved = resolved[ plural ] !== undefined ?
18628				resolved[ plural ] :
18629				resolved._;
18630		}
18631	
18632		return resolved.replace( '%d', plural ); // nb: plural might be undefined,
18633	} );
18634
18635	/**
18636	 * Version string for plug-ins to check compatibility. Allowed format is
18637	 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
18638	 * only for non-release builds. See http://semver.org/ for more information.
18639	 *  @member
18640	 *  @type string
18641	 *  @default Version number
18642	 */
18643	DataTable.version = "1.10.18";
18644
18645	/**
18646	 * Private data store, containing all of the settings objects that are
18647	 * created for the tables on a given page.
18648	 *
18649	 * Note that the `DataTable.settings` object is aliased to
18650	 * `jQuery.fn.dataTableExt` through which it may be accessed and
18651	 * manipulated, or `jQuery.fn.dataTable.settings`.
18652	 *  @member
18653	 *  @type array
18654	 *  @default []
18655	 *  @private
18656	 */
18657	DataTable.settings = [];
18658
18659	/**
18660	 * Object models container, for the various models that DataTables has
18661	 * available to it. These models define the objects that are used to hold
18662	 * the active state and configuration of the table.
18663	 *  @namespace
18664	 */
18665	DataTable.models = {};
18666	
18667	
18668	
18669	/**
18670	 * Template object for the way in which DataTables holds information about
18671	 * search information for the global filter and individual column filters.
18672	 *  @namespace
18673	 */
18674	DataTable.models.oSearch = {
18675		/**
18676		 * Flag to indicate if the filtering should be case insensitive or not
18677		 *  @type boolean
18678		 *  @default true
18679		 */
18680		"bCaseInsensitive": true,
18681	
18682		/**
18683		 * Applied search term
18684		 *  @type string
18685		 *  @default <i>Empty string</i>
18686		 */
18687		"sSearch": "",
18688	
18689		/**
18690		 * Flag to indicate if the search term should be interpreted as a
18691		 * regular expression (true) or not (false) and therefore and special
18692		 * regex characters escaped.
18693		 *  @type boolean
18694		 *  @default false
18695		 */
18696		"bRegex": false,
18697	
18698		/**
18699		 * Flag to indicate if DataTables is to use its smart filtering or not.
18700		 *  @type boolean
18701		 *  @default true
18702		 */
18703		"bSmart": tru
vendor: 11,217 bytes, lines 18703-19061
18703e
18704	};
18705	
18706	
18707	
18708	
18709	/**
18710	 * Template object for the way in which DataTables holds information about
18711	 * each individual row. This is the object format used for the settings
18712	 * aoData array.
18713	 *  @namespace
18714	 */
18715	DataTable.models.oRow = {
18716		/**
18717		 * TR element for the row
18718		 *  @type node
18719		 *  @default null
18720		 */
18721		"nTr": null,
18722	
18723		/**
18724		 * Array of TD elements for each row. This is null until the row has been
18725		 * created.
18726		 *  @type array nodes
18727		 *  @default []
18728		 */
18729		"anCells": null,
18730	
18731		/**
18732		 * Data object from the original data source for the row. This is either
18733		 * an array if using the traditional form of DataTables, or an object if
18734		 * using mData options. The exact type will depend on the passed in
18735		 * data from the data source, or will be an array if using DOM a data
18736		 * source.
18737		 *  @type array|object
18738		 *  @default []
18739		 */
18740		"_aData": [],
18741	
18742		/**
18743		 * Sorting data cache - this array is ostensibly the same length as the
18744		 * number of columns (although each index is generated only as it is
18745		 * needed), and holds the data that is used for sorting each column in the
18746		 * row. We do this cache generation at the start of the sort in order that
18747		 * the formatting of the sort data need be done only once for each cell
18748		 * per sort. This array should not be read from or written to by anything
18749		 * other than the master sorting methods.
18750		 *  @type array
18751		 *  @default null
18752		 *  @private
18753		 */
18754		"_aSortData": null,
18755	
18756		/**
18757		 * Per cell filtering data cache. As per the sort data cache, used to
18758		 * increase the performance of the filtering in DataTables
18759		 *  @type array
18760		 *  @default null
18761		 *  @private
18762		 */
18763		"_aFilterData": null,
18764	
18765		/**
18766		 * Filtering data cache. This is the same as the cell filtering cache, but
18767		 * in this case a string rather than an array. This is easily computed with
18768		 * a join on `_aFilterData`, but is provided as a cache so the join isn't
18769		 * needed on every search (memory traded for performance)
18770		 *  @type array
18771		 *  @default null
18772		 *  @private
18773		 */
18774		"_sFilterRow": null,
18775	
18776		/**
18777		 * Cache of the class name that DataTables has applied to the row, so we
18778		 * can quickly look at this variable rather than needing to do a DOM check
18779		 * on className for the nTr property.
18780		 *  @type string
18781		 *  @default <i>Empty string</i>
18782		 *  @private
18783		 */
18784		"_sRowStripe": "",
18785	
18786		/**
18787		 * Denote if the original data source was from the DOM, or the data source
18788		 * object. This is used for invalidating data, so DataTables can
18789		 * automatically read data from the original source, unless uninstructed
18790		 * otherwise.
18791		 *  @type string
18792		 *  @default null
18793		 *  @private
18794		 */
18795		"src": null,
18796	
18797		/**
18798		 * Index in the aoData array. This saves an indexOf lookup when we have the
18799		 * object, but want to know the index
18800		 *  @type integer
18801		 *  @default -1
18802		 *  @private
18803		 */
18804		"idx": -1
18805	};
18806	
18807	
18808	/**
18809	 * Template object for the column information object in DataTables. This object
18810	 * is held in the settings aoColumns array and contains all the information that
18811	 * DataTables needs about each individual column.
18812	 *
18813	 * Note that this object is related to {@link DataTable.defaults.column}
18814	 * but this one is the internal data store for DataTables's cache of columns.
18815	 * It should NOT be manipulated outside of DataTables. Any configuration should
18816	 * be done through the initialisation options.
18817	 *  @namespace
18818	 */
18819	DataTable.models.oColumn = {
18820		/**
18821		 * Column index. This could be worked out on-the-fly with $.inArray, but it
18822		 * is faster to just hold it as a variable
18823		 *  @type integer
18824		 *  @default null
18825		 */
18826		"idx": null,
18827	
18828		/**
18829		 * A list of the columns that sorting should occur on when this column
18830		 * is sorted. That this property is an array allows multi-column sorting
18831		 * to be defined for a column (for example first name / last name columns
18832		 * would benefit from this). The values are integers pointing to the
18833		 * columns to be sorted on (typically it will be a single integer pointing
18834		 * at itself, but that doesn't need to be the case).
18835		 *  @type array
18836		 */
18837		"aDataSort": null,
18838	
18839		/**
18840		 * Define the sorting directions that are applied to the column, in sequence
18841		 * as the column is repeatedly sorted upon - i.e. the first value is used
18842		 * as the sorting direction when the column if first sorted (clicked on).
18843		 * Sort it again (click again) and it will move on to the next index.
18844		 * Repeat until loop.
18845		 *  @type array
18846		 */
18847		"asSorting": null,
18848	
18849		/**
18850		 * Flag to indicate if the column is searchable, and thus should be included
18851		 * in the filtering or not.
18852		 *  @type boolean
18853		 */
18854		"bSearchable": null,
18855	
18856		/**
18857		 * Flag to indicate if the column is sortable or not.
18858		 *  @type boolean
18859		 */
18860		"bSortable": null,
18861	
18862		/**
18863		 * Flag to indicate if the column is currently visible in the table or not
18864		 *  @type boolean
18865		 */
18866		"bVisible": null,
18867	
18868		/**
18869		 * Store for manual type assignment using the `column.type` option. This
18870		 * is held in store so we can manipulate the column's `sType` property.
18871		 *  @type string
18872		 *  @default null
18873		 *  @private
18874		 */
18875		"_sManualType": null,
18876	
18877		/**
18878		 * Flag to indicate if HTML5 data attributes should be used as the data
18879		 * source for filtering or sorting. True is either are.
18880		 *  @type boolean
18881		 *  @default false
18882		 *  @private
18883		 */
18884		"_bAttrSrc": false,
18885	
18886		/**
18887		 * Developer definable function that is called whenever a cell is created (Ajax source,
18888		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
18889		 * allowing you to modify the DOM element (add background colour for example) when the
18890		 * element is available.
18891		 *  @type function
18892		 *  @param {element} nTd The TD node that has been created
18893		 *  @param {*} sData The Data for the cell
18894		 *  @param {array|object} oData The data for the whole row
18895		 *  @param {int} iRow The row index for the aoData data store
18896		 *  @default null
18897		 */
18898		"fnCreatedCell": null,
18899	
18900		/**
18901		 * Function to get data from a cell in a column. You should <b>never</b>
18902		 * access data directly through _aData internally in DataTables - always use
18903		 * the method attached to this property. It allows mData to function as
18904		 * required. This function is automatically assigned by the column
18905		 * initialisation method
18906		 *  @type function
18907		 *  @param {array|object} oData The data array/object for the array
18908		 *    (i.e. aoData[]._aData)
18909		 *  @param {string} sSpecific The specific data type you want to get -
18910		 *    'display', 'type' 'filter' 'sort'
18911		 *  @returns {*} The data for the cell from the given row's data
18912		 *  @default null
18913		 */
18914		"fnGetData": null,
18915	
18916		/**
18917		 * Function to set data for a cell in the column. You should <b>never</b>
18918		 * set the data directly to _aData internally in DataTables - always use
18919		 * this method. It allows mData to function as required. This function
18920		 * is automatically assigned by the column initialisation method
18921		 *  @type function
18922		 *  @param {array|object} oData The data array/object for the array
18923		 *    (i.e. aoData[]._aData)
18924		 *  @param {*} sValue Value to set
18925		 *  @default null
18926		 */
18927		"fnSetData": null,
18928	
18929		/**
18930		 * Property to read the value for the cells in the column from the data
18931		 * source array / object. If null, then the default content is used, if a
18932		 * function is given then the return from the function is used.
18933		 *  @type function|int|string|null
18934		 *  @default null
18935		 */
18936		"mData": null,
18937	
18938		/**
18939		 * Partner property to mData which is used (only when defined) to get
18940		 * the data - i.e. it is basically the same as mData, but without the
18941		 * 'set' option, and also the data fed to it is the result from mData.
18942		 * This is the rendering method to match the data method of mData.
18943		 *  @type function|int|string|null
18944		 *  @default null
18945		 */
18946		"mRender": null,
18947	
18948		/**
18949		 * Unique header TH/TD element for this column - this is what the sorting
18950		 * listener is attached to (if sorting is enabled.)
18951		 *  @type node
18952		 *  @default null
18953		 */
18954		"nTh": null,
18955	
18956		/**
18957		 * Unique footer TH/TD element for this column (if there is one). Not used
18958		 * in DataTables as such, but can be used for plug-ins to reference the
18959		 * footer for each column.
18960		 *  @type node
18961		 *  @default null
18962		 */
18963		"nTf": null,
18964	
18965		/**
18966		 * The class to apply to all TD elements in the table's TBODY for the column
18967		 *  @type string
18968		 *  @default null
18969		 */
18970		"sClass": null,
18971	
18972		/**
18973		 * When DataTables calculates the column widths to assign to each column,
18974		 * it finds the longest string in each column and then constructs a
18975		 * temporary table and reads the widths from that. The problem with this
18976		 * is that "mmm" is much wider then "iiii", but the latter is a longer
18977		 * string - thus the calculation can go wrong (doing it properly and putting
18978		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
18979		 * a "work around" we provide this option. It will append its value to the
18980		 * text that is found to be the longest string for the column - i.e. padding.
18981		 *  @type string
18982		 */
18983		"sContentPadding": null,
18984	
18985		/**
18986		 * Allows a default value to be given for a column's data, and will be used
18987		 * whenever a null data source is encountered (this can be because mData
18988		 * is set to null, or because the data source itself is null).
18989		 *  @type string
18990		 *  @default null
18991		 */
18992		"sDefaultContent": null,
18993	
18994		/**
18995		 * Name for the column, allowing reference to the column by name as well as
18996		 * by index (needs a lookup to work by name).
18997		 *  @type string
18998		 */
18999		"sName": null,
19000	
19001		/**
19002		 * Custom sorting data type - defines which of the available plug-ins in
19003		 * afnSortData the custom sorting will use - if any is defined.
19004		 *  @type string
19005		 *  @default std
19006		 */
19007		"sSortDataType": 'std',
19008	
19009		/**
19010		 * Class to be applied to the header element when sorting on this column
19011		 *  @type string
19012		 *  @default null
19013		 */
19014		"sSortingClass": null,
19015	
19016		/**
19017		 * Class to be applied to the header element when sorting on this column -
19018		 * when jQuery UI theming is used.
19019		 *  @type string
19020		 *  @default null
19021		 */
19022		"sSortingClassJUI": null,
19023	
19024		/**
19025		 * Title of the column - what is seen in the TH element (nTh).
19026		 *  @type string
19027		 */
19028		"sTitle": null,
19029	
19030		/**
19031		 * Column sorting and filtering type
19032		 *  @type string
19033		 *  @default null
19034		 */
19035		"sType": null,
19036	
19037		/**
19038		 * Width of the column
19039		 *  @type string
19040		 *  @default null
19041		 */
19042		"sWidth": null,
19043	
19044		/**
19045		 * Width of the column when it was first "encountered"
19046		 *  @type string
19047		 *  @default null
19048		 */
19049		"sWidthOrig": null
19050	};
19051	
19052	
19053	/*
19054	 * Developer note: The properties of the object below are given in Hungarian
19055	 * notation, that was used as the interface for DataTables prior to v1.10, however
19056	 * from v1.10 onwards the primary interface is camel case. In order to avoid
19057	 * breaking backwards compatibility utterly with this change, the Hungarian
19058	 * version is still, internally the primary interface, but is is not documented
19059	 * - hence the @name tags in each doc comment. This allows a Javascript function
19060	 * to create a map from Hungarian notation to camel case (going the other direction
19061	 * would require each property to be listed, which would a
19061t around 3K to the size
19062	 * of DataTables, while this method is about a 0.5K hit
vendor: 57,087 bytes, lines 19062-20838
19062.
19063	 *
19064	 * Ultimately this does pave the way for Hungarian notation to be dropped
19065	 * completely, but that is a massive amount of work and will break current
19066	 * installs (therefore is on-hold until v2).
19067	 */
19068	
19069	/**
19070	 * Initialisation options that can be given to DataTables at initialisation
19071	 * time.
19072	 *  @namespace
19073	 */
19074	DataTable.defaults = {
19075		/**
19076		 * An array of data to use for the table, passed in at initialisation which
19077		 * will be used in preference to any data which is already in the DOM. This is
19078		 * particularly useful for constructing tables purely in Javascript, for
19079		 * example with a custom Ajax call.
19080		 *  @type array
19081		 *  @default null
19082		 *
19083		 *  @dtopt Option
19084		 *  @name DataTable.defaults.data
19085		 *
19086		 *  @example
19087		 *    // Using a 2D array data source
19088		 *    $(document).ready( function () {
19089		 *      $('#example').dataTable( {
19090		 *        "data": [
19091		 *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
19092		 *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
19093		 *        ],
19094		 *        "columns": [
19095		 *          { "title": "Engine" },
19096		 *          { "title": "Browser" },
19097		 *          { "title": "Platform" },
19098		 *          { "title": "Version" },
19099		 *          { "title": "Grade" }
19100		 *        ]
19101		 *      } );
19102		 *    } );
19103		 *
19104		 *  @example
19105		 *    // Using an array of objects as a data source (`data`)
19106		 *    $(document).ready( function () {
19107		 *      $('#example').dataTable( {
19108		 *        "data": [
19109		 *          {
19110		 *            "engine":   "Trident",
19111		 *            "browser":  "Internet Explorer 4.0",
19112		 *            "platform": "Win 95+",
19113		 *            "version":  4,
19114		 *            "grade":    "X"
19115		 *          },
19116		 *          {
19117		 *            "engine":   "Trident",
19118		 *            "browser":  "Internet Explorer 5.0",
19119		 *            "platform": "Win 95+",
19120		 *            "version":  5,
19121		 *            "grade":    "C"
19122		 *          }
19123		 *        ],
19124		 *        "columns": [
19125		 *          { "title": "Engine",   "data": "engine" },
19126		 *          { "title": "Browser",  "data": "browser" },
19127		 *          { "title": "Platform", "data": "platform" },
19128		 *          { "title": "Version",  "data": "version" },
19129		 *          { "title": "Grade",    "data": "grade" }
19130		 *        ]
19131		 *      } );
19132		 *    } );
19133		 */
19134		"aaData": null,
19135	
19136	
19137		/**
19138		 * If ordering is enabled, then DataTables will perform a first pass sort on
19139		 * initialisation. You can define which column(s) the sort is performed
19140		 * upon, and the sorting direction, with this variable. The `sorting` array
19141		 * should contain an array for each column to be sorted initially containing
19142		 * the column's index and a direction string ('asc' or 'desc').
19143		 *  @type array
19144		 *  @default [[0,'asc']]
19145		 *
19146		 *  @dtopt Option
19147		 *  @name DataTable.defaults.order
19148		 *
19149		 *  @example
19150		 *    // Sort by 3rd column first, and then 4th column
19151		 *    $(document).ready( function() {
19152		 *      $('#example').dataTable( {
19153		 *        "order": [[2,'asc'], [3,'desc']]
19154		 *      } );
19155		 *    } );
19156		 *
19157		 *    // No initial sorting
19158		 *    $(document).ready( function() {
19159		 *      $('#example').dataTable( {
19160		 *        "order": []
19161		 *      } );
19162		 *    } );
19163		 */
19164		"aaSorting": [[0,'asc']],
19165	
19166	
19167		/**
19168		 * This parameter is basically identical to the `sorting` parameter, but
19169		 * cannot be overridden by user interaction with the table. What this means
19170		 * is that you could have a column (visible or hidden) which the sorting
19171		 * will always be forced on first - any sorting after that (from the user)
19172		 * will then be performed as required. This can be useful for grouping rows
19173		 * together.
19174		 *  @type array
19175		 *  @default null
19176		 *
19177		 *  @dtopt Option
19178		 *  @name DataTable.defaults.orderFixed
19179		 *
19180		 *  @example
19181		 *    $(document).ready( function() {
19182		 *      $('#example').dataTable( {
19183		 *        "orderFixed": [[0,'asc']]
19184		 *      } );
19185		 *    } )
19186		 */
19187		"aaSortingFixed": [],
19188	
19189	
19190		/**
19191		 * DataTables can be instructed to load data to display in the table from a
19192		 * Ajax source. This option defines how that Ajax call is made and where to.
19193		 *
19194		 * The `ajax` property has three different modes of operation, depending on
19195		 * how it is defined. These are:
19196		 *
19197		 * * `string` - Set the URL from where the data should be loaded from.
19198		 * * `object` - Define properties for `jQuery.ajax`.
19199		 * * `function` - Custom data get function
19200		 *
19201		 * `string`
19202		 * --------
19203		 *
19204		 * As a string, the `ajax` property simply defines the URL from which
19205		 * DataTables will load data.
19206		 *
19207		 * `object`
19208		 * --------
19209		 *
19210		 * As an object, the parameters in the object are passed to
19211		 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
19212		 * of the Ajax request. DataTables has a number of default parameters which
19213		 * you can override using this option. Please refer to the jQuery
19214		 * documentation for a full description of the options available, although
19215		 * the following parameters provide additional options in DataTables or
19216		 * require special consideration:
19217		 *
19218		 * * `data` - As with jQuery, `data` can be provided as an object, but it
19219		 *   can also be used as a function to manipulate the data DataTables sends
19220		 *   to the server. The function takes a single parameter, an object of
19221		 *   parameters with the values that DataTables has readied for sending. An
19222		 *   object may be returned which will be merged into the DataTables
19223		 *   defaults, or you can add the items to the object that was passed in and
19224		 *   not return anything from the function. This supersedes `fnServerParams`
19225		 *   from DataTables 1.9-.
19226		 *
19227		 * * `dataSrc` - By default DataTables will look for the property `data` (or
19228		 *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
19229		 *   from an Ajax source or for server-side processing - this parameter
19230		 *   allows that property to be changed. You can use Javascript dotted
19231		 *   object notation to get a data source for multiple levels of nesting, or
19232		 *   it my be used as a function. As a function it takes a single parameter,
19233		 *   the JSON returned from the server, which can be manipulated as
19234		 *   required, with the returned value being that used by DataTables as the
19235		 *   data source for the table. This supersedes `sAjaxDataProp` from
19236		 *   DataTables 1.9-.
19237		 *
19238		 * * `success` - Should not be overridden it is used internally in
19239		 *   DataTables. To manipulate / transform the data returned by the server
19240		 *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
19241		 *
19242		 * `function`
19243		 * ----------
19244		 *
19245		 * As a function, making the Ajax call is left up to yourself allowing
19246		 * complete control of the Ajax request. Indeed, if desired, a method other
19247		 * than Ajax could be used to obtain the required data, such as Web storage
19248		 * or an AIR database.
19249		 *
19250		 * The function is given four parameters and no return is required. The
19251		 * parameters are:
19252		 *
19253		 * 1. _object_ - Data to send to the server
19254		 * 2. _function_ - Callback function that must be executed when the required
19255		 *    data has been obtained. That data should be passed into the callback
19256		 *    as the only parameter
19257		 * 3. _object_ - DataTables settings object for the table
19258		 *
19259		 * Note that this supersedes `fnServerData` from DataTables 1.9-.
19260		 *
19261		 *  @type string|object|function
19262		 *  @default null
19263		 *
19264		 *  @dtopt Option
19265		 *  @name DataTable.defaults.ajax
19266		 *  @since 1.10.0
19267		 *
19268		 * @example
19269		 *   // Get JSON data from a file via Ajax.
19270		 *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
19271		 *   $('#example').dataTable( {
19272		 *     "ajax": "data.json"
19273		 *   } );
19274		 *
19275		 * @example
19276		 *   // Get JSON data from a file via Ajax, using `dataSrc` to change
19277		 *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
19278		 *   $('#example').dataTable( {
19279		 *     "ajax": {
19280		 *       "url": "data.json",
19281		 *       "dataSrc": "tableData"
19282		 *     }
19283		 *   } );
19284		 *
19285		 * @example
19286		 *   // Get JSON data from a file via Ajax, using `dataSrc` to read data
19287		 *   // from a plain array rather than an array in an object
19288		 *   $('#example').dataTable( {
19289		 *     "ajax": {
19290		 *       "url": "data.json",
19291		 *       "dataSrc": ""
19292		 *     }
19293		 *   } );
19294		 *
19295		 * @example
19296		 *   // Manipulate the data returned from the server - add a link to data
19297		 *   // (note this can, should, be done using `render` for the column - this
19298		 *   // is just a simple example of how the data can be manipulated).
19299		 *   $('#example').dataTable( {
19300		 *     "ajax": {
19301		 *       "url": "data.json",
19302		 *       "dataSrc": function ( json ) {
19303		 *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {
19304		 *           json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
19305		 *         }
19306		 *         return json;
19307		 *       }
19308		 *     }
19309		 *   } );
19310		 *
19311		 * @example
19312		 *   // Add data to the request
19313		 *   $('#example').dataTable( {
19314		 *     "ajax": {
19315		 *       "url": "data.json",
19316		 *       "data": function ( d ) {
19317		 *         return {
19318		 *           "extra_search": $('#extra').val()
19319		 *         };
19320		 *       }
19321		 *     }
19322		 *   } );
19323		 *
19324		 * @example
19325		 *   // Send request as POST
19326		 *   $('#example').dataTable( {
19327		 *     "ajax": {
19328		 *       "url": "data.json",
19329		 *       "type": "POST"
19330		 *     }
19331		 *   } );
19332		 *
19333		 * @example
19334		 *   // Get the data from localStorage (could interface with a form for
19335		 *   // adding, editing and removing rows).
19336		 *   $('#example').dataTable( {
19337		 *     "ajax": function (data, callback, settings) {
19338		 *       callback(
19339		 *         JSON.parse( localStorage.getItem('dataTablesData') )
19340		 *       );
19341		 *     }
19342		 *   } );
19343		 */
19344		"ajax": null,
19345	
19346	
19347		/**
19348		 * This parameter allows you to readily specify the entries in the length drop
19349		 * down menu that DataTables shows when pagination is enabled. It can be
19350		 * either a 1D array of options which will be used for both the displayed
19351		 * option and the value, or a 2D array which will use the array in the first
19352		 * position as the value, and the array in the second position as the
19353		 * displayed options (useful for language strings such as 'All').
19354		 *
19355		 * Note that the `pageLength` property will be automatically set to the
19356		 * first value given in this array, unless `pageLength` is also provided.
19357		 *  @type array
19358		 *  @default [ 10, 25, 50, 100 ]
19359		 *
19360		 *  @dtopt Option
19361		 *  @name DataTable.defaults.lengthMenu
19362		 *
19363		 *  @example
19364		 *    $(document).ready( function() {
19365		 *      $('#example').dataTable( {
19366		 *        "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
19367		 *      } );
19368		 *    } );
19369		 */
19370		"aLengthMenu": [ 10, 25, 50, 100 ],
19371	
19372	
19373		/**
19374		 * The `columns` option in the initialisation parameter allows you to define
19375		 * details about the way individual columns behave. For a full list of
19376		 * column options that can be set, please see
19377		 * {@link DataTable.defaults.column}. Note that if you use `columns` to
19378		 * define your columns, you must have an entry in the array for every single
19379		 * column that you have in your table (these can be null if you don't which
19380		 * to specify any options).
19381		 *  @member
19382		 *
19383		 *  @name DataTable.defaults.column
19384		 */
19385		"aoColumns": null,
19386	
19387		/**
19388		 * Very similar to `columns`, `columnDefs` allows you to target a specific
19389		 * column, multiple columns, or all columns, using the `targets` property of
19390		 * each object in the array. This allows great flexibility when creating
19391		 * tables, as the `columnDefs` arrays can be of any length, targeting the
19392		 * columns you specifically want. `columnDefs` may use any of the column
19393		 * options available: {@link DataTable.defaults.column}, but it _must_
19394		 * have `targets` defined in each object in the array. Values in the `targets`
19395		 * array may be:
19396		 *   <ul>
19397		 *     <li>a string - class name will be matched on the TH for the column</li>
19398		 *     <li>0 or a positive integer - column index counting from the left</li>
19399		 *     <li>a negative integer - column index counting from the right</li>
19400		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
19401		 *   </ul>
19402		 *  @member
19403		 *
19404		 *  @name DataTable.defaults.columnDefs
19405		 */
19406		"aoColumnDefs": null,
19407	
19408	
19409		/**
19410		 * Basically the same as `search`, this parameter defines the individual column
19411		 * filtering state at initialisation time. The array must be of the same size
19412		 * as the number of columns, and each element be an object with the parameters
19413		 * `search` and `escapeRegex` (the latter is optional). 'null' is also
19414		 * accepted and the default will be used.
19415		 *  @type array
19416		 *  @default []
19417		 *
19418		 *  @dtopt Option
19419		 *  @name DataTable.defaults.searchCols
19420		 *
19421		 *  @example
19422		 *    $(document).ready( function() {
19423		 *      $('#example').dataTable( {
19424		 *        "searchCols": [
19425		 *          null,
19426		 *          { "search": "My filter" },
19427		 *          null,
19428		 *          { "search": "^[0-9]", "escapeRegex": false }
19429		 *        ]
19430		 *      } );
19431		 *    } )
19432		 */
19433		"aoSearchCols": [],
19434	
19435	
19436		/**
19437		 * An array of CSS classes that should be applied to displayed rows. This
19438		 * array may be of any length, and DataTables will apply each class
19439		 * sequentially, looping when required.
19440		 *  @type array
19441		 *  @default null <i>Will take the values determined by the `oClasses.stripe*`
19442		 *    options</i>
19443		 *
19444		 *  @dtopt Option
19445		 *  @name DataTable.defaults.stripeClasses
19446		 *
19447		 *  @example
19448		 *    $(document).ready( function() {
19449		 *      $('#example').dataTable( {
19450		 *        "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
19451		 *      } );
19452		 *    } )
19453		 */
19454		"asStripeClasses": null,
19455	
19456	
19457		/**
19458		 * Enable or disable automatic column width calculation. This can be disabled
19459		 * as an optimisation (it takes some time to calculate the widths) if the
19460		 * tables widths are passed in using `columns`.
19461		 *  @type boolean
19462		 *  @default true
19463		 *
19464		 *  @dtopt Features
19465		 *  @name DataTable.defaults.autoWidth
19466		 *
19467		 *  @example
19468		 *    $(document).ready( function () {
19469		 *      $('#example').dataTable( {
19470		 *        "autoWidth": false
19471		 *      } );
19472		 *    } );
19473		 */
19474		"bAutoWidth": true,
19475	
19476	
19477		/**
19478		 * Deferred rendering can provide DataTables with a huge speed boost when you
19479		 * are using an Ajax or JS data source for the table. This option, when set to
19480		 * true, will cause DataTables to defer the creation of the table elements for
19481		 * each row until they are needed for a draw - saving a significant amount of
19482		 * time.
19483		 *  @type boolean
19484		 *  @default false
19485		 *
19486		 *  @dtopt Features
19487		 *  @name DataTable.defaults.deferRender
19488		 *
19489		 *  @example
19490		 *    $(document).ready( function() {
19491		 *      $('#example').dataTable( {
19492		 *        "ajax": "sources/arrays.txt",
19493		 *        "deferRender": true
19494		 *      } );
19495		 *    } );
19496		 */
19497		"bDeferRender": false,
19498	
19499	
19500		/**
19501		 * Replace a DataTable which matches the given selector and replace it with
19502		 * one which has the properties of the new initialisation object passed. If no
19503		 * table matches the selector, then the new DataTable will be constructed as
19504		 * per normal.
19505		 *  @type boolean
19506		 *  @default false
19507		 *
19508		 *  @dtopt Options
19509		 *  @name DataTable.defaults.destroy
19510		 *
19511		 *  @example
19512		 *    $(document).ready( function() {
19513		 *      $('#example').dataTable( {
19514		 *        "srollY": "200px",
19515		 *        "paginate": false
19516		 *      } );
19517		 *
19518		 *      // Some time later....
19519		 *      $('#example').dataTable( {
19520		 *        "filter": false,
19521		 *        "destroy": true
19522		 *      } );
19523		 *    } );
19524		 */
19525		"bDestroy": false,
19526	
19527	
19528		/**
19529		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
19530		 * that it allows the end user to input multiple words (space separated) and
19531		 * will match a row containing those words, even if not in the order that was
19532		 * specified (this allow matching across multiple columns). Note that if you
19533		 * wish to use filtering in DataTables this must remain 'true' - to remove the
19534		 * default filtering input box and retain filtering abilities, please use
19535		 * {@link DataTable.defaults.dom}.
19536		 *  @type boolean
19537		 *  @default true
19538		 *
19539		 *  @dtopt Features
19540		 *  @name DataTable.defaults.searching
19541		 *
19542		 *  @example
19543		 *    $(document).ready( function () {
19544		 *      $('#example').dataTable( {
19545		 *        "searching": false
19546		 *      } );
19547		 *    } );
19548		 */
19549		"bFilter": true,
19550	
19551	
19552		/**
19553		 * Enable or disable the table information display. This shows information
19554		 * about the data that is currently visible on the page, including information
19555		 * about filtered data if that action is being performed.
19556		 *  @type boolean
19557		 *  @default true
19558		 *
19559		 *  @dtopt Features
19560		 *  @name DataTable.defaults.info
19561		 *
19562		 *  @example
19563		 *    $(document).ready( function () {
19564		 *      $('#example').dataTable( {
19565		 *        "info": false
19566		 *      } );
19567		 *    } );
19568		 */
19569		"bInfo": true,
19570	
19571	
19572		/**
19573		 * Allows the end user to select the size of a formatted page from a select
19574		 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
19575		 *  @type boolean
19576		 *  @default true
19577		 *
19578		 *  @dtopt Features
19579		 *  @name DataTable.defaults.lengthChange
19580		 *
19581		 *  @example
19582		 *    $(document).ready( function () {
19583		 *      $('#example').dataTable( {
19584		 *        "lengthChange": false
19585		 *      } );
19586		 *    } );
19587		 */
19588		"bLengthChange": true,
19589	
19590	
19591		/**
19592		 * Enable or disable pagination.
19593		 *  @type boolean
19594		 *  @default true
19595		 *
19596		 *  @dtopt Features
19597		 *  @name DataTable.defaults.paging
19598		 *
19599		 *  @example
19600		 *    $(document).ready( function () {
19601		 *      $('#example').dataTable( {
19602		 *        "paging": false
19603		 *      } );
19604		 *    } );
19605		 */
19606		"bPaginate": true,
19607	
19608	
19609		/**
19610		 * Enable or disable the display of a 'processing' indicator when the table is
19611		 * being processed (e.g. a sort). This is particularly useful for tables with
19612		 * large amounts of data where it can take a noticeable amount of time to sort
19613		 * the entries.
19614		 *  @type boolean
19615		 *  @default false
19616		 *
19617		 *  @dtopt Features
19618		 *  @name DataTable.defaults.processing
19619		 *
19620		 *  @example
19621		 *    $(document).ready( function () {
19622		 *      $('#example').dataTable( {
19623		 *        "processing": true
19624		 *      } );
19625		 *    } );
19626		 */
19627		"bProcessing": false,
19628	
19629	
19630		/**
19631		 * Retrieve the DataTables object for the given selector. Note that if the
19632		 * table has already been initialised, this parameter will cause DataTables
19633		 * to simply return the object that has already been set up - it will not take
19634		 * account of any changes you might have made to the initialisation object
19635		 * passed to DataTables (setting this parameter to true is an acknowledgement
19636		 * that you understand this). `destroy` can be used to reinitialise a table if
19637		 * you need.
19638		 *  @type boolean
19639		 *  @default false
19640		 *
19641		 *  @dtopt Options
19642		 *  @name DataTable.defaults.retrieve
19643		 *
19644		 *  @example
19645		 *    $(document).ready( function() {
19646		 *      initTable();
19647		 *      tableActions();
19648		 *    } );
19649		 *
19650		 *    function initTable ()
19651		 *    {
19652		 *      return $('#example').dataTable( {
19653		 *        "scrollY": "200px",
19654		 *        "paginate": false,
19655		 *        "retrieve": true
19656		 *      } );
19657		 *    }
19658		 *
19659		 *    function tableActions ()
19660		 *    {
19661		 *      var table = initTable();
19662		 *      // perform API operations with oTable
19663		 *    }
19664		 */
19665		"bRetrieve": false,
19666	
19667	
19668		/**
19669		 * When vertical (y) scrolling is enabled, DataTables will force the height of
19670		 * the table's viewport to the given height at all times (useful for layout).
19671		 * However, this can look odd when filtering data down to a small data set,
19672		 * and the footer is left "floating" further down. This parameter (when
19673		 * enabled) will cause DataTables to collapse the table's viewport down when
19674		 * the result set will fit within the given Y height.
19675		 *  @type boolean
19676		 *  @default false
19677		 *
19678		 *  @dtopt Options
19679		 *  @name DataTable.defaults.scrollCollapse
19680		 *
19681		 *  @example
19682		 *    $(document).ready( function() {
19683		 *      $('#example').dataTable( {
19684		 *        "scrollY": "200",
19685		 *        "scrollCollapse": true
19686		 *      } );
19687		 *    } );
19688		 */
19689		"bScrollCollapse": false,
19690	
19691	
19692		/**
19693		 * Configure DataTables to use server-side processing. Note that the
19694		 * `ajax` parameter must also be given in order to give DataTables a
19695		 * source to obtain the required data for each draw.
19696		 *  @type boolean
19697		 *  @default false
19698		 *
19699		 *  @dtopt Features
19700		 *  @dtopt Server-side
19701		 *  @name DataTable.defaults.serverSide
19702		 *
19703		 *  @example
19704		 *    $(document).ready( function () {
19705		 *      $('#example').dataTable( {
19706		 *        "serverSide": true,
19707		 *        "ajax": "xhr.php"
19708		 *      } );
19709		 *    } );
19710		 */
19711		"bServerSide": false,
19712	
19713	
19714		/**
19715		 * Enable or disable sorting of columns. Sorting of individual columns can be
19716		 * disabled by the `sortable` option for each column.
19717		 *  @type boolean
19718		 *  @default true
19719		 *
19720		 *  @dtopt Features
19721		 *  @name DataTable.defaults.ordering
19722		 *
19723		 *  @example
19724		 *    $(document).ready( function () {
19725		 *      $('#example').dataTable( {
19726		 *        "ordering": false
19727		 *      } );
19728		 *    } );
19729		 */
19730		"bSort": true,
19731	
19732	
19733		/**
19734		 * Enable or display DataTables' ability to sort multiple columns at the
19735		 * same time (activated by shift-click by the user).
19736		 *  @type boolean
19737		 *  @default true
19738		 *
19739		 *  @dtopt Options
19740		 *  @name DataTable.defaults.orderMulti
19741		 *
19742		 *  @example
19743		 *    // Disable multiple column sorting ability
19744		 *    $(document).ready( function () {
19745		 *      $('#example').dataTable( {
19746		 *        "orderMulti": false
19747		 *      } );
19748		 *    } );
19749		 */
19750		"bSortMulti": true,
19751	
19752	
19753		/**
19754		 * Allows control over whether DataTables should use the top (true) unique
19755		 * cell that is found for a single column, or the bottom (false - default).
19756		 * This is useful when using complex headers.
19757		 *  @type boolean
19758		 *  @default false
19759		 *
19760		 *  @dtopt Options
19761		 *  @name DataTable.defaults.orderCellsTop
19762		 *
19763		 *  @example
19764		 *    $(document).ready( function() {
19765		 *      $('#example').dataTable( {
19766		 *        "orderCellsTop": true
19767		 *      } );
19768		 *    } );
19769		 */
19770		"bSortCellsTop": false,
19771	
19772	
19773		/**
19774		 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
19775		 * `sorting\_3` to the columns which are currently being sorted on. This is
19776		 * presented as a feature switch as it can increase processing time (while
19777		 * classes are removed and added) so for large data sets you might want to
19778		 * turn this off.
19779		 *  @type boolean
19780		 *  @default true
19781		 *
19782		 *  @dtopt Features
19783		 *  @name DataTable.defaults.orderClasses
19784		 *
19785		 *  @example
19786		 *    $(document).ready( function () {
19787		 *      $('#example').dataTable( {
19788		 *        "orderClasses": false
19789		 *      } );
19790		 *    } );
19791		 */
19792		"bSortClasses": true,
19793	
19794	
19795		/**
19796		 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
19797		 * used to save table display information such as pagination information,
19798		 * display length, filtering and sorting. As such when the end user reloads
19799		 * the page the display display will match what thy had previously set up.
19800		 *
19801		 * Due to the use of `localStorage` the default state saving is not supported
19802		 * in IE6 or 7. If state saving is required in those browsers, use
19803		 * `stateSaveCallback` to provide a storage solution such as cookies.
19804		 *  @type boolean
19805		 *  @default false
19806		 *
19807		 *  @dtopt Features
19808		 *  @name DataTable.defaults.stateSave
19809		 *
19810		 *  @example
19811		 *    $(document).ready( function () {
19812		 *      $('#example').dataTable( {
19813		 *        "stateSave": true
19814		 *      } );
19815		 *    } );
19816		 */
19817		"bStateSave": false,
19818	
19819	
19820		/**
19821		 * This function is called when a TR element is created (and all TD child
19822		 * elements have been inserted), or registered if using a DOM source, allowing
19823		 * manipulation of the TR element (adding classes etc).
19824		 *  @type function
19825		 *  @param {node} row "TR" element for the current row
19826		 *  @param {array} data Raw data array for this row
19827		 *  @param {int} dataIndex The index of this row in the internal aoData array
19828		 *
19829		 *  @dtopt Callbacks
19830		 *  @name DataTable.defaults.createdRow
19831		 *
19832		 *  @example
19833		 *    $(document).ready( function() {
19834		 *      $('#example').dataTable( {
19835		 *        "createdRow": function( row, data, dataIndex ) {
19836		 *          // Bold the grade for all 'A' grade browsers
19837		 *          if ( data[4] == "A" )
19838		 *          {
19839		 *            $('td:eq(4)', row).html( '<b>A</b>' );
19840		 *          }
19841		 *        }
19842		 *      } );
19843		 *    } );
19844		 */
19845		"fnCreatedRow": null,
19846	
19847	
19848		/**
19849		 * This function is called on every 'draw' event, and allows you to
19850		 * dynamically modify any aspect you want about the created DOM.
19851		 *  @type function
19852		 *  @param {object} settings DataTables settings object
19853		 *
19854		 *  @dtopt Callbacks
19855		 *  @name DataTable.defaults.drawCallback
19856		 *
19857		 *  @example
19858		 *    $(document).ready( function() {
19859		 *      $('#example').dataTable( {
19860		 *        "drawCallback": function( settings ) {
19861		 *          alert( 'DataTables has redrawn the table' );
19862		 *        }
19863		 *      } );
19864		 *    } );
19865		 */
19866		"fnDrawCallback": null,
19867	
19868	
19869		/**
19870		 * Identical to fnHeaderCallback() but for the table footer this function
19871		 * allows you to modify the table footer on every 'draw' event.
19872		 *  @type function
19873		 *  @param {node} foot "TR" element for the footer
19874		 *  @param {array} data Full table data (as derived from the original HTML)
19875		 *  @param {int} start Index for the current display starting point in the
19876		 *    display array
19877		 *  @param {int} end Index for the current display ending point in the
19878		 *    display array
19879		 *  @param {array int} display Index array to translate the visual position
19880		 *    to the full data array
19881		 *
19882		 *  @dtopt Callbacks
19883		 *  @name DataTable.defaults.footerCallback
19884		 *
19885		 *  @example
19886		 *    $(document).ready( function() {
19887		 *      $('#example').dataTable( {
19888		 *        "footerCallback": function( tfoot, data, start, end, display ) {
19889		 *          tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
19890		 *        }
19891		 *      } );
19892		 *    } )
19893		 */
19894		"fnFooterCallback": null,
19895	
19896	
19897		/**
19898		 * When rendering large numbers in the information element for the table
19899		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
19900		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
19901		 * rendered as "1,000,000") to help readability for the end user. This
19902		 * function will override the default method DataTables uses.
19903		 *  @type function
19904		 *  @member
19905		 *  @param {int} toFormat number to be formatted
19906		 *  @returns {string} formatted string for DataTables to show the number
19907		 *
19908		 *  @dtopt Callbacks
19909		 *  @name DataTable.defaults.formatNumber
19910		 *
19911		 *  @example
19912		 *    // Format a number using a single quote for the separator (note that
19913		 *    // this can also be done with the language.thousands option)
19914		 *    $(document).ready( function() {
19915		 *      $('#example').dataTable( {
19916		 *        "formatNumber": function ( toFormat ) {
19917		 *          return toFormat.toString().replace(
19918		 *            /\B(?=(\d{3})+(?!\d))/g, "'"
19919		 *          );
19920		 *        };
19921		 *      } );
19922		 *    } );
19923		 */
19924		"fnFormatNumber": function ( toFormat ) {
19925			return toFormat.toString().replace(
19926				/\B(?=(\d{3})+(?!\d))/g,
19927				this.oLanguage.sThousands
19928			);
19929		},
19930	
19931	
19932		/**
19933		 * This function is called on every 'draw' event, and allows you to
19934		 * dynamically modify the header row. This can be used to calculate and
19935		 * display useful information about the table.
19936		 *  @type function
19937		 *  @param {node} head "TR" element for the header
19938		 *  @param {array} data Full table data (as derived from the original HTML)
19939		 *  @param {int} start Index for the current display starting point in the
19940		 *    display array
19941		 *  @param {int} end Index for the current display ending point in the
19942		 *    display array
19943		 *  @param {array int} display Index array to translate the visual position
19944		 *    to the full data array
19945		 *
19946		 *  @dtopt Callbacks
19947		 *  @name DataTable.defaults.headerCallback
19948		 *
19949		 *  @example
19950		 *    $(document).ready( function() {
19951		 *      $('#example').dataTable( {
19952		 *        "fheaderCallback": function( head, data, start, end, display ) {
19953		 *          head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
19954		 *        }
19955		 *      } );
19956		 *    } )
19957		 */
19958		"fnHeaderCallback": null,
19959	
19960	
19961		/**
19962		 * The information element can be used to convey information about the current
19963		 * state of the table. Although the internationalisation options presented by
19964		 * DataTables are quite capable of dealing with most customisations, there may
19965		 * be times where you wish to customise the string further. This callback
19966		 * allows you to do exactly that.
19967		 *  @type function
19968		 *  @param {object} oSettings DataTables settings object
19969		 *  @param {int} start Starting position in data for the draw
19970		 *  @param {int} end End position in data for the draw
19971		 *  @param {int} max Total number of rows in the table (regardless of
19972		 *    filtering)
19973		 *  @param {int} total Total number of rows in the data set, after filtering
19974		 *  @param {string} pre The string that DataTables has formatted using it's
19975		 *    own rules
19976		 *  @returns {string} The string to be displayed in the information element.
19977		 *
19978		 *  @dtopt Callbacks
19979		 *  @name DataTable.defaults.infoCallback
19980		 *
19981		 *  @example
19982		 *    $('#example').dataTable( {
19983		 *      "infoCallback": function( settings, start, end, max, total, pre ) {
19984		 *        return start +" to "+ end;
19985		 *      }
19986		 *    } );
19987		 */
19988		"fnInfoCallback": null,
19989	
19990	
19991		/**
19992		 * Called when the table has been initialised. Normally DataTables will
19993		 * initialise sequentially and there will be no need for this function,
19994		 * however, this does not hold true when using external language information
19995		 * since that is obtained using an async XHR call.
19996		 *  @type function
19997		 *  @param {object} settings DataTables settings object
19998		 *  @param {object} json The JSON object request from the server - only
19999		 *    present if client-side Ajax sourced data is used
20000		 *
20001		 *  @dtopt Callbacks
20002		 *  @name DataTable.defaults.initComplete
20003		 *
20004		 *  @example
20005		 *    $(document).ready( function() {
20006		 *      $('#example').dataTable( {
20007		 *        "initComplete": function(settings, json) {
20008		 *          alert( 'DataTables has finished its initialisation.' );
20009		 *        }
20010		 *      } );
20011		 *    } )
20012		 */
20013		"fnInitComplete": null,
20014	
20015	
20016		/**
20017		 * Called at the very start of each table draw and can be used to cancel the
20018		 * draw by returning false, any other return (including undefined) results in
20019		 * the full draw occurring).
20020		 *  @type function
20021		 *  @param {object} settings DataTables settings object
20022		 *  @returns {boolean} False will cancel the draw, anything else (including no
20023		 *    return) will allow it to complete.
20024		 *
20025		 *  @dtopt Callbacks
20026		 *  @name DataTable.defaults.preDrawCallback
20027		 *
20028		 *  @example
20029		 *    $(document).ready( function() {
20030		 *      $('#example').dataTable( {
20031		 *        "preDrawCallback": function( settings ) {
20032		 *          if ( $('#test').val() == 1 ) {
20033		 *            return false;
20034		 *          }
20035		 *        }
20036		 *      } );
20037		 *    } );
20038		 */
20039		"fnPreDrawCallback": null,
20040	
20041	
20042		/**
20043		 * This function allows you to 'post process' each row after it have been
20044		 * generated for each table draw, but before it is rendered on screen. This
20045		 * function might be used for setting the row class name etc.
20046		 *  @type function
20047		 *  @param {node} row "TR" element for the current row
20048		 *  @param {array} data Raw data array for this row
20049		 *  @param {int} displayIndex The display index for the current table draw
20050		 *  @param {int} displayIndexFull The index of the data in the full list of
20051		 *    rows (after filtering)
20052		 *
20053		 *  @dtopt Callbacks
20054		 *  @name DataTable.defaults.rowCallback
20055		 *
20056		 *  @example
20057		 *    $(document).ready( function() {
20058		 *      $('#example').dataTable( {
20059		 *        "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
20060		 *          // Bold the grade for all 'A' grade browsers
20061		 *          if ( data[4] == "A" ) {
20062		 *            $('td:eq(4)', row).html( '<b>A</b>' );
20063		 *          }
20064		 *        }
20065		 *      } );
20066		 *    } );
20067		 */
20068		"fnRowCallback": null,
20069	
20070	
20071		/**
20072		 * __Deprecated__ The functionality provided by this parameter has now been
20073		 * superseded by that provided through `ajax`, which should be used instead.
20074		 *
20075		 * This parameter allows you to override the default function which obtains
20076		 * the data from the server so something more suitable for your application.
20077		 * For example you could use POST data, or pull information from a Gears or
20078		 * AIR database.
20079		 *  @type function
20080		 *  @member
20081		 *  @param {string} source HTTP source to obtain the data from (`ajax`)
20082		 *  @param {array} data A key/value pair object containing the data to send
20083		 *    to the server
20084		 *  @param {function} callback to be called on completion of the data get
20085		 *    process that will draw the data on the page.
20086		 *  @param {object} settings DataTables settings object
20087		 *
20088		 *  @dtopt Callbacks
20089		 *  @dtopt Server-side
20090		 *  @name DataTable.defaults.serverData
20091		 *
20092		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
20093		 */
20094		"fnServerData": null,
20095	
20096	
20097		/**
20098		 * __Deprecated__ The functionality provided by this parameter has now been
20099		 * superseded by that provided through `ajax`, which should be used instead.
20100		 *
20101		 *  It is often useful to send extra data to the server when making an Ajax
20102		 * request - for example custom filtering information, and this callback
20103		 * function makes it trivial to send extra information to the server. The
20104		 * passed in parameter is the data set that has been constructed by
20105		 * DataTables, and you can add to this or modify it as you require.
20106		 *  @type function
20107		 *  @param {array} data Data array (array of objects which are name/value
20108		 *    pairs) that has been constructed by DataTables and will be sent to the
20109		 *    server. In the case of Ajax sourced data with server-side processing
20110		 *    this will be an empty array, for server-side processing there will be a
20111		 *    significant number of parameters!
20112		 *  @returns {undefined} Ensure that you modify the data array passed in,
20113		 *    as this is passed by reference.
20114		 *
20115		 *  @dtopt Callbacks
20116		 *  @dtopt Server-side
20117		 *  @name DataTable.defaults.serverParams
20118		 *
20119		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
20120		 */
20121		"fnServerParams": null,
20122	
20123	
20124		/**
20125		 * Load the table state. With this function you can define from where, and how, the
20126		 * state of a table is loaded. By default DataTables will load from `localStorage`
20127		 * but you might wish to use a server-side database or cookies.
20128		 *  @type function
20129		 *  @member
20130		 *  @param {object} settings DataTables settings object
20131		 *  @param {object} callback Callback that can be executed when done. It
20132		 *    should be passed the loaded state object.
20133		 *  @return {object} The DataTables state object to be loaded
20134		 *
20135		 *  @dtopt Callbacks
20136		 *  @name DataTable.defaults.stateLoadCallback
20137		 *
20138		 *  @example
20139		 *    $(document).ready( function() {
20140		 *      $('#example').dataTable( {
20141		 *        "stateSave": true,
20142		 *        "stateLoadCallback": function (settings, callback) {
20143		 *          $.ajax( {
20144		 *            "url": "/state_load",
20145		 *            "dataType": "json",
20146		 *            "success": function (json) {
20147		 *              callback( json );
20148		 *            }
20149		 *          } );
20150		 *        }
20151		 *      } );
20152		 *    } );
20153		 */
20154		"fnStateLoadCallback": function ( settings ) {
20155			try {
20156				return JSON.parse(
20157					(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
20158						'DataTables_'+settings.sInstance+'_'+location.pathname
20159					)
20160				);
20161			} catch (e) {}
20162		},
20163	
20164	
20165		/**
20166		 * Callback which allows modification of the saved state prior to loading that state.
20167		 * This callback is called when the table is loading state from the stored data, but
20168		 * prior to the settings object being modified by the saved state. Note that for
20169		 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
20170		 * a plug-in.
20171		 *  @type function
20172		 *  @param {object} settings DataTables settings object
20173		 *  @param {object} data The state object that is to be loaded
20174		 *
20175		 *  @dtopt Callbacks
20176		 *  @name DataTable.defaults.stateLoadParams
20177		 *
20178		 *  @example
20179		 *    // Remove a saved filter, so filtering is never loaded
20180		 *    $(document).ready( function() {
20181		 *      $('#example').dataTable( {
20182		 *        "stateSave": true,
20183		 *        "stateLoadParams": function (settings, data) {
20184		 *          data.oSearch.sSearch = "";
20185		 *        }
20186		 *      } );
20187		 *    } );
20188		 *
20189		 *  @example
20190		 *    // Disallow state loading by returning false
20191		 *    $(document).ready( function() {
20192		 *      $('#example').dataTable( {
20193		 *        "stateSave": true,
20194		 *        "stateLoadParams": function (settings, data) {
20195		 *          return false;
20196		 *        }
20197		 *      } );
20198		 *    } );
20199		 */
20200		"fnStateLoadParams": null,
20201	
20202	
20203		/**
20204		 * Callback that is called when the state has been loaded from the state saving method
20205		 * and the DataTables settings object has been modified as a result of the loaded state.
20206		 *  @type function
20207		 *  @param {object} settings DataTables settings object
20208		 *  @param {object} data The state object that was loaded
20209		 *
20210		 *  @dtopt Callbacks
20211		 *  @name DataTable.defaults.stateLoaded
20212		 *
20213		 *  @example
20214		 *    // Show an alert with the filtering value that was saved
20215		 *    $(document).ready( function() {
20216		 *      $('#example').dataTable( {
20217		 *        "stateSave": true,
20218		 *        "stateLoaded": function (settings, data) {
20219		 *          alert( 'Saved filter was: '+data.oSearch.sSearch );
20220		 *        }
20221		 *      } );
20222		 *    } );
20223		 */
20224		"fnStateLoaded": null,
20225	
20226	
20227		/**
20228		 * Save the table state. This function allows you to define where and how the state
20229		 * information for the table is stored By default DataTables will use `localStorage`
20230		 * but you might wish to use a server-side database or cookies.
20231		 *  @type function
20232		 *  @member
20233		 *  @param {object} settings DataTables settings object
20234		 *  @param {object} data The state object to be saved
20235		 *
20236		 *  @dtopt Callbacks
20237		 *  @name DataTable.defaults.stateSaveCallback
20238		 *
20239		 *  @example
20240		 *    $(document).ready( function() {
20241		 *      $('#example').dataTable( {
20242		 *        "stateSave": true,
20243		 *        "stateSaveCallback": function (settings, data) {
20244		 *          // Send an Ajax request to the server with the state object
20245		 *          $.ajax( {
20246		 *            "url": "/state_save",
20247		 *            "data": data,
20248		 *            "dataType": "json",
20249		 *            "method": "POST"
20250		 *            "success": function () {}
20251		 *          } );
20252		 *        }
20253		 *      } );
20254		 *    } );
20255		 */
20256		"fnStateSaveCallback": function ( settings, data ) {
20257			try {
20258				(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
20259					'DataTables_'+settings.sInstance+'_'+location.pathname,
20260					JSON.stringify( data )
20261				);
20262			} catch (e) {}
20263		},
20264	
20265	
20266		/**
20267		 * Callback which allows modification of the state to be saved. Called when the table
20268		 * has changed state a new state save is required. This method allows modification of
20269		 * the state saving object prior to actually doing the save, including addition or
20270		 * other state properties or modification. Note that for plug-in authors, you should
20271		 * use the `stateSaveParams` event to save parameters for a plug-in.
20272		 *  @type function
20273		 *  @param {object} settings DataTables settings object
20274		 *  @param {object} data The state object to be saved
20275		 *
20276		 *  @dtopt Callbacks
20277		 *  @name DataTable.defaults.stateSaveParams
20278		 *
20279		 *  @example
20280		 *    // Remove a saved filter, so filtering is never saved
20281		 *    $(document).ready( function() {
20282		 *      $('#example').dataTable( {
20283		 *        "stateSave": true,
20284		 *        "stateSaveParams": function (settings, data) {
20285		 *          data.oSearch.sSearch = "";
20286		 *        }
20287		 *      } );
20288		 *    } );
20289		 */
20290		"fnStateSaveParams": null,
20291	
20292	
20293		/**
20294		 * Duration for which the saved state information is considered valid. After this period
20295		 * has elapsed the state will be returned to the default.
20296		 * Value is given in seconds.
20297		 *  @type int
20298		 *  @default 7200 <i>(2 hours)</i>
20299		 *
20300		 *  @dtopt Options
20301		 *  @name DataTable.defaults.stateDuration
20302		 *
20303		 *  @example
20304		 *    $(document).ready( function() {
20305		 *      $('#example').dataTable( {
20306		 *        "stateDuration": 60*60*24; // 1 day
20307		 *      } );
20308		 *    } )
20309		 */
20310		"iStateDuration": 7200,
20311	
20312	
20313		/**
20314		 * When enabled DataTables will not make a request to the server for the first
20315		 * page draw - rather it will use the data already on the page (no sorting etc
20316		 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
20317		 * is used to indicate that deferred loading is required, but it is also used
20318		 * to tell DataTables how many records there are in the full table (allowing
20319		 * the information element and pagination to be displayed correctly). In the case
20320		 * where a filtering is applied to the table on initial load, this can be
20321		 * indicated by giving the parameter as an array, where the first element is
20322		 * the number of records available after filtering and the second element is the
20323		 * number of records without filtering (allowing the table information element
20324		 * to be shown correctly).
20325		 *  @type int | array
20326		 *  @default null
20327		 *
20328		 *  @dtopt Options
20329		 *  @name DataTable.defaults.deferLoading
20330		 *
20331		 *  @example
20332		 *    // 57 records available in the table, no filtering applied
20333		 *    $(document).ready( function() {
20334		 *      $('#example').dataTable( {
20335		 *        "serverSide": true,
20336		 *        "ajax": "scripts/server_processing.php",
20337		 *        "deferLoading": 57
20338		 *      } );
20339		 *    } );
20340		 *
20341		 *  @example
20342		 *    // 57 records after filtering, 100 without filtering (an initial filter applied)
20343		 *    $(document).ready( function() {
20344		 *      $('#example').dataTable( {
20345		 *        "serverSide": true,
20346		 *        "ajax": "scripts/server_processing.php",
20347		 *        "deferLoading": [ 57, 100 ],
20348		 *        "search": {
20349		 *          "search": "my_filter"
20350		 *        }
20351		 *      } );
20352		 *    } );
20353		 */
20354		"iDeferLoading": null,
20355	
20356	
20357		/**
20358		 * Number of rows to display on a single page when using pagination. If
20359		 * feature enabled (`lengthChange`) then the end user will be able to override
20360		 * this to a custom setting using a pop-up menu.
20361		 *  @type int
20362		 *  @default 10
20363		 *
20364		 *  @dtopt Options
20365		 *  @name DataTable.defaults.pageLength
20366		 *
20367		 *  @example
20368		 *    $(document).ready( function() {
20369		 *      $('#example').dataTable( {
20370		 *        "pageLength": 50
20371		 *      } );
20372		 *    } )
20373		 */
20374		"iDisplayLength": 10,
20375	
20376	
20377		/**
20378		 * Define the starting point for data display when using DataTables with
20379		 * pagination. Note that this parameter is the number of records, rather than
20380		 * the page number, so if you have 10 records per page and want to start on
20381		 * the third page, it should be "20".
20382		 *  @type int
20383		 *  @default 0
20384		 *
20385		 *  @dtopt Options
20386		 *  @name DataTable.defaults.displayStart
20387		 *
20388		 *  @example
20389		 *    $(document).ready( function() {
20390		 *      $('#example').dataTable( {
20391		 *        "displayStart": 20
20392		 *      } );
20393		 *    } )
20394		 */
20395		"iDisplayStart": 0,
20396	
20397	
20398		/**
20399		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
20400		 * and filtering) by adding a `tabindex` attribute to the required elements. This
20401		 * allows you to tab through the controls and press the enter key to activate them.
20402		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
20403		 * You can overrule this using this parameter if you wish. Use a value of -1 to
20404		 * disable built-in keyboard navigation.
20405		 *  @type int
20406		 *  @default 0
20407		 *
20408		 *  @dtopt Options
20409		 *  @name DataTable.defaults.tabIndex
20410		 *
20411		 *  @example
20412		 *    $(document).ready( function() {
20413		 *      $('#example').dataTable( {
20414		 *        "tabIndex": 1
20415		 *      } );
20416		 *    } );
20417		 */
20418		"iTabIndex": 0,
20419	
20420	
20421		/**
20422		 * Classes that DataTables assigns to the various components and features
20423		 * that it adds to the HTML table. This allows classes to be configured
20424		 * during initialisation in addition to through the static
20425		 * {@link DataTable.ext.oStdClasses} object).
20426		 *  @namespace
20427		 *  @name DataTable.defaults.classes
20428		 */
20429		"oClasses": {},
20430	
20431	
20432		/**
20433		 * All strings that DataTables uses in the user interface that it creates
20434		 * are defined in this object, allowing you to modified them individually or
20435		 * completely replace them all as required.
20436		 *  @namespace
20437		 *  @name DataTable.defaults.language
20438		 */
20439		"oLanguage": {
20440			/**
20441			 * Strings that are used for WAI-ARIA labels and controls only (these are not
20442			 * actually visible on the page, but will be read by screenreaders, and thus
20443			 * must be internationalised as well).
20444			 *  @namespace
20445			 *  @name DataTable.defaults.language.aria
20446			 */
20447			"oAria": {
20448				/**
20449				 * ARIA label that is added to the table headers when the column may be
20450				 * sorted ascending by activing the column (click or return when focused).
20451				 * Note that the column header is prefixed to this string.
20452				 *  @type string
20453				 *  @default : activate to sort column ascending
20454				 *
20455				 *  @dtopt Language
20456				 *  @name DataTable.defaults.language.aria.sortAscending
20457				 *
20458				 *  @example
20459				 *    $(document).ready( function() {
20460				 *      $('#example').dataTable( {
20461				 *        "language": {
20462				 *          "aria": {
20463				 *            "sortAscending": " - click/return to sort ascending"
20464				 *          }
20465				 *        }
20466				 *      } );
20467				 *    } );
20468				 */
20469				"sSortAscending": ": activate to sort column ascending",
20470	
20471				/**
20472				 * ARIA label that is added to the table headers when the column may be
20473				 * sorted descending by activing the column (click or return when focused).
20474				 * Note that the column header is prefixed to this string.
20475				 *  @type string
20476				 *  @default : activate to sort column ascending
20477				 *
20478				 *  @dtopt Language
20479				 *  @name DataTable.defaults.language.aria.sortDescending
20480				 *
20481				 *  @example
20482				 *    $(document).ready( function() {
20483				 *      $('#example').dataTable( {
20484				 *        "language": {
20485				 *          "aria": {
20486				 *            "sortDescending": " - click/return to sort descending"
20487				 *          }
20488				 *        }
20489				 *      } );
20490				 *    } );
20491				 */
20492				"sSortDescending": ": activate to sort column descending"
20493			},
20494	
20495			/**
20496			 * Pagination string used by DataTables for the built-in pagination
20497			 * control types.
20498			 *  @namespace
20499			 *  @name DataTable.defaults.language.paginate
20500			 */
20501			"oPaginate": {
20502				/**
20503				 * Text to use when using the 'full_numbers' type of pagination for the
20504				 * button to take the user to the first page.
20505				 *  @type string
20506				 *  @default First
20507				 *
20508				 *  @dtopt Language
20509				 *  @name DataTable.defaults.language.paginate.first
20510				 *
20511				 *  @example
20512				 *    $(document).ready( function() {
20513				 *      $('#example').dataTable( {
20514				 *        "language": {
20515				 *          "paginate": {
20516				 *            "first": "First page"
20517				 *          }
20518				 *        }
20519				 *      } );
20520				 *    } );
20521				 */
20522				"sFirst": "First",
20523	
20524	
20525				/**
20526				 * Text to use when using the 'full_numbers' type of pagination for the
20527				 * button to take the user to the last page.
20528				 *  @type string
20529				 *  @default Last
20530				 *
20531				 *  @dtopt Language
20532				 *  @name DataTable.defaults.language.paginate.last
20533				 *
20534				 *  @example
20535				 *    $(document).ready( function() {
20536				 *      $('#example').dataTable( {
20537				 *        "language": {
20538				 *          "paginate": {
20539				 *            "last": "Last page"
20540				 *          }
20541				 *        }
20542				 *      } );
20543				 *    } );
20544				 */
20545				"sLast": "Last",
20546	
20547	
20548				/**
20549				 * Text to use for the 'next' pagination button (to take the user to the
20550				 * next page).
20551				 *  @type string
20552				 *  @default Next
20553				 *
20554				 *  @dtopt Language
20555				 *  @name DataTable.defaults.language.paginate.next
20556				 *
20557				 *  @example
20558				 *    $(document).ready( function() {
20559				 *      $('#example').dataTable( {
20560				 *        "language": {
20561				 *          "paginate": {
20562				 *            "next": "Next page"
20563				 *          }
20564				 *        }
20565				 *      } );
20566				 *    } );
20567				 */
20568				"sNext": "Next",
20569	
20570	
20571				/**
20572				 * Text to use for the 'previous' pagination button (to take the user to
20573				 * the previous page).
20574				 *  @type string
20575				 *  @default Previous
20576				 *
20577				 *  @dtopt Language
20578				 *  @name DataTable.defaults.language.paginate.previous
20579				 *
20580				 *  @example
20581				 *    $(document).ready( function() {
20582				 *      $('#example').dataTable( {
20583				 *        "language": {
20584				 *          "paginate": {
20585				 *            "previous": "Previous page"
20586				 *          }
20587				 *        }
20588				 *      } );
20589				 *    } );
20590				 */
20591				"sPrevious": "Previous"
20592			},
20593	
20594			/**
20595			 * This string is shown in preference to `zeroRecords` when the table is
20596			 * empty of data (regardless of filtering). Note that this is an optional
20597			 * parameter - if it is not given, the value of `zeroRecords` will be used
20598			 * instead (either the default or given value).
20599			 *  @type string
20600			 *  @default No data available in table
20601			 *
20602			 *  @dtopt Language
20603			 *  @name DataTable.defaults.language.emptyTable
20604			 *
20605			 *  @example
20606			 *    $(document).ready( function() {
20607			 *      $('#example').dataTable( {
20608			 *        "language": {
20609			 *          "emptyTable": "No data available in table"
20610			 *        }
20611			 *      } );
20612			 *    } );
20613			 */
20614			"sEmptyTable": "No data available in table",
20615	
20616	
20617			/**
20618			 * This string gives information to the end user about the information
20619			 * that is current on display on the page. The following tokens can be
20620			 * used in the string and will be dynamically replaced as the table
20621			 * display updates. This tokens can be placed anywhere in the string, or
20622			 * removed as needed by the language requires:
20623			 *
20624			 * * `\_START\_` - Display index of the first record on the current page
20625			 * * `\_END\_` - Display index of the last record on the current page
20626			 * * `\_TOTAL\_` - Number of records in the table after filtering
20627			 * * `\_MAX\_` - Number of records in the table without filtering
20628			 * * `\_PAGE\_` - Current page number
20629			 * * `\_PAGES\_` - Total number of pages of data in the table
20630			 *
20631			 *  @type string
20632			 *  @default Showing _START_ to _END_ of _TOTAL_ entries
20633			 *
20634			 *  @dtopt Language
20635			 *  @name DataTable.defaults.language.info
20636			 *
20637			 *  @example
20638			 *    $(document).ready( function() {
20639			 *      $('#example').dataTable( {
20640			 *        "language": {
20641			 *          "info": "Showing page _PAGE_ of _PAGES_"
20642			 *        }
20643			 *      } );
20644			 *    } );
20645			 */
20646			"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
20647	
20648	
20649			/**
20650			 * Display information string for when the table is empty. Typically the
20651			 * format of this string should match `info`.
20652			 *  @type string
20653			 *  @default Showing 0 to 0 of 0 entries
20654			 *
20655			 *  @dtopt Language
20656			 *  @name DataTable.defaults.language.infoEmpty
20657			 *
20658			 *  @example
20659			 *    $(document).ready( function() {
20660			 *      $('#example').dataTable( {
20661			 *        "language": {
20662			 *          "infoEmpty": "No entries to show"
20663			 *        }
20664			 *      } );
20665			 *    } );
20666			 */
20667			"sInfoEmpty": "Showing 0 to 0 of 0 entries",
20668	
20669	
20670			/**
20671			 * When a user filters the information in a table, this string is appended
20672			 * to the information (`info`) to give an idea of how strong the filtering
20673			 * is. The variable _MAX_ is dynamically updated.
20674			 *  @type string
20675			 *  @default (filtered from _MAX_ total entries)
20676			 *
20677			 *  @dtopt Language
20678			 *  @name DataTable.defaults.language.infoFiltered
20679			 *
20680			 *  @example
20681			 *    $(document).ready( function() {
20682			 *      $('#example').dataTable( {
20683			 *        "language": {
20684			 *          "infoFiltered": " - filtering from _MAX_ records"
20685			 *        }
20686			 *      } );
20687			 *    } );
20688			 */
20689			"sInfoFiltered": "(filtered from _MAX_ total entries)",
20690	
20691	
20692			/**
20693			 * If can be useful to append extra information to the info string at times,
20694			 * and this variable does exactly that. This information will be appended to
20695			 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
20696			 * being used) at all times.
20697			 *  @type string
20698			 *  @default <i>Empty string</i>
20699			 *
20700			 *  @dtopt Language
20701			 *  @name DataTable.defaults.language.infoPostFix
20702			 *
20703			 *  @example
20704			 *    $(document).ready( function() {
20705			 *      $('#example').dataTable( {
20706			 *        "language": {
20707			 *          "infoPostFix": "All records shown are derived from real information."
20708			 *        }
20709			 *      } );
20710			 *    } );
20711			 */
20712			"sInfoPostFix": "",
20713	
20714	
20715			/**
20716			 * This decimal place operator is a little different from the other
20717			 * language options since DataTables doesn't output floating point
20718			 * numbers, so it won't ever use this for display of a number. Rather,
20719			 * what this parameter does is modify the sort methods of the table so
20720			 * that numbers which are in a format which has a character other than
20721			 * a period (`.`) as a decimal place will be sorted numerically.
20722			 *
20723			 * Note that numbers with different decimal places cannot be shown in
20724			 * the same table and still be sortable, the table must be consistent.
20725			 * However, multiple different tables on the page can use different
20726			 * decimal place characters.
20727			 *  @type string
20728			 *  @default 
20729			 *
20730			 *  @dtopt Language
20731			 *  @name DataTable.defaults.language.decimal
20732			 *
20733			 *  @example
20734			 *    $(document).ready( function() {
20735			 *      $('#example').dataTable( {
20736			 *        "language": {
20737			 *          "decimal": ","
20738			 *          "thousands": "."
20739			 *        }
20740			 *      } );
20741			 *    } );
20742			 */
20743			"sDecimal": "",
20744	
20745	
20746			/**
20747			 * DataTables has a build in number formatter (`formatNumber`) which is
20748			 * used to format large numbers that are used in the table information.
20749			 * By default a comma is used, but this can be trivially changed to any
20750			 * character you wish with this parameter.
20751			 *  @type string
20752			 *  @default ,
20753			 *
20754			 *  @dtopt Language
20755			 *  @name DataTable.defaults.language.thousands
20756			 *
20757			 *  @example
20758			 *    $(document).ready( function() {
20759			 *      $('#example').dataTable( {
20760			 *        "language": {
20761			 *          "thousands": "'"
20762			 *        }
20763			 *      } );
20764			 *    } );
20765			 */
20766			"sThousands": ",",
20767	
20768	
20769			/**
20770			 * Detail the action that will be taken when the drop down menu for the
20771			 * pagination length option is changed. The '_MENU_' variable is replaced
20772			 * with a default select list of 10, 25, 50 and 100, and can be replaced
20773			 * with a custom select box if required.
20774			 *  @type string
20775			 *  @default Show _MENU_ entries
20776			 *
20777			 *  @dtopt Language
20778			 *  @name DataTable.defaults.language.lengthMenu
20779			 *
20780			 *  @example
20781			 *    // Language change only
20782			 *    $(document).ready( function() {
20783			 *      $('#example').dataTable( {
20784			 *        "language": {
20785			 *          "lengthMenu": "Display _MENU_ records"
20786			 *        }
20787			 *      } );
20788			 *    } );
20789			 *
20790			 *  @example
20791			 *    // Language and options change
20792			 *    $(document).ready( function() {
20793			 *      $('#example').dataTable( {
20794			 *        "language": {
20795			 *          "lengthMenu": 'Display <select>'+
20796			 *            '<option value="10">10</option>'+
20797			 *            '<option value="20">20</option>'+
20798			 *            '<option value="30">30</option>'+
20799			 *            '<option value="40">40</option>'+
20800			 *            '<option value="50">50</option>'+
20801			 *            '<option value="-1">All</option>'+
20802			 *            '</select> records'
20803			 *        }
20804			 *      } );
20805			 *    } );
20806			 */
20807			"sLengthMenu": "Show _MENU_ entries",
20808	
20809	
20810			/**
20811			 * When using Ajax sourced data and during the first draw when DataTables is
20812			 * gathering the data, this message is shown in an empty row in the table to
20813			 * indicate to the end user the the data is being loaded. Note that this
20814			 * parameter is not used when loading data by server-side processing, just
20815			 * Ajax sourced data with client-side processing.
20816			 *  @type string
20817			 *  @default Loading...
20818			 *
20819			 *  @dtopt Language
20820			 *  @name DataTable.defaults.language.loadingRecords
20821			 *
20822			 *  @example
20823			 *    $(document).ready( function() {
20824			 *      $('#example').dataTable( {
20825			 *        "language": {
20826			 *          "loadingRecords": "Please wait - loading..."
20827			 *        }
20828			 *      } );
20829			 *    } );
20830			 */
20831			"sLoadingRecords": "Loading...",
20832	
20833	
20834			/**
20835			 * Text which is displayed when the table is processing a user action
20836			 * (usually a sort command or similar).
20837			 *  @type string
20838			 *
20838  @default Processing...
20839			 *
20840			 *  @dtopt Language
20841			 *  @name DataTable.defaults.language.processing
20842			 *
20843			 *  @example
20844			 *    $(document).ready( function() {
20845			 *      $('#example').dataTable( {
20846			 *        "language": {
20847			 *          "processing": "DataTables is currently busy"
20848			 *        }
20849			 *      } );
20850			 *    } );
20851			 */
20852			"sProcessing": "Processing...
vendor: 42,942 bytes, lines 20852-22146
20852",
20853	
20854	
20855			/**
20856			 * Details the actions that will be taken when the user types into the
20857			 * filtering input text box. The variable "_INPUT_", if used in the string,
20858			 * is replaced with the HTML text box for the filtering input allowing
20859			 * control over where it appears in the string. If "_INPUT_" is not given
20860			 * then the input box is appended to the string automatically.
20861			 *  @type string
20862			 *  @default Search:
20863			 *
20864			 *  @dtopt Language
20865			 *  @name DataTable.defaults.language.search
20866			 *
20867			 *  @example
20868			 *    // Input text box will be appended at the end automatically
20869			 *    $(document).ready( function() {
20870			 *      $('#example').dataTable( {
20871			 *        "language": {
20872			 *          "search": "Filter records:"
20873			 *        }
20874			 *      } );
20875			 *    } );
20876			 *
20877			 *  @example
20878			 *    // Specify where the filter should appear
20879			 *    $(document).ready( function() {
20880			 *      $('#example').dataTable( {
20881			 *        "language": {
20882			 *          "search": "Apply filter _INPUT_ to table"
20883			 *        }
20884			 *      } );
20885			 *    } );
20886			 */
20887			"sSearch": "Search:",
20888	
20889	
20890			/**
20891			 * Assign a `placeholder` attribute to the search `input` element
20892			 *  @type string
20893			 *  @default 
20894			 *
20895			 *  @dtopt Language
20896			 *  @name DataTable.defaults.language.searchPlaceholder
20897			 */
20898			"sSearchPlaceholder": "",
20899	
20900	
20901			/**
20902			 * All of the language information can be stored in a file on the
20903			 * server-side, which DataTables will look up if this parameter is passed.
20904			 * It must store the URL of the language file, which is in a JSON format,
20905			 * and the object has the same properties as the oLanguage object in the
20906			 * initialiser object (i.e. the above parameters). Please refer to one of
20907			 * the example language files to see how this works in action.
20908			 *  @type string
20909			 *  @default <i>Empty string - i.e. disabled</i>
20910			 *
20911			 *  @dtopt Language
20912			 *  @name DataTable.defaults.language.url
20913			 *
20914			 *  @example
20915			 *    $(document).ready( function() {
20916			 *      $('#example').dataTable( {
20917			 *        "language": {
20918			 *          "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
20919			 *        }
20920			 *      } );
20921			 *    } );
20922			 */
20923			"sUrl": "",
20924	
20925	
20926			/**
20927			 * Text shown inside the table records when the is no information to be
20928			 * displayed after filtering. `emptyTable` is shown when there is simply no
20929			 * information in the table at all (regardless of filtering).
20930			 *  @type string
20931			 *  @default No matching records found
20932			 *
20933			 *  @dtopt Language
20934			 *  @name DataTable.defaults.language.zeroRecords
20935			 *
20936			 *  @example
20937			 *    $(document).ready( function() {
20938			 *      $('#example').dataTable( {
20939			 *        "language": {
20940			 *          "zeroRecords": "No records to display"
20941			 *        }
20942			 *      } );
20943			 *    } );
20944			 */
20945			"sZeroRecords": "No matching records found"
20946		},
20947	
20948	
20949		/**
20950		 * This parameter allows you to have define the global filtering state at
20951		 * initialisation time. As an object the `search` parameter must be
20952		 * defined, but all other parameters are optional. When `regex` is true,
20953		 * the search string will be treated as a regular expression, when false
20954		 * (default) it will be treated as a straight string. When `smart`
20955		 * DataTables will use it's smart filtering methods (to word match at
20956		 * any point in the data), when false this will not be done.
20957		 *  @namespace
20958		 *  @extends DataTable.models.oSearch
20959		 *
20960		 *  @dtopt Options
20961		 *  @name DataTable.defaults.search
20962		 *
20963		 *  @example
20964		 *    $(document).ready( function() {
20965		 *      $('#example').dataTable( {
20966		 *        "search": {"search": "Initial search"}
20967		 *      } );
20968		 *    } )
20969		 */
20970		"oSearch": $.extend( {}, DataTable.models.oSearch ),
20971	
20972	
20973		/**
20974		 * __Deprecated__ The functionality provided by this parameter has now been
20975		 * superseded by that provided through `ajax`, which should be used instead.
20976		 *
20977		 * By default DataTables will look for the property `data` (or `aaData` for
20978		 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
20979		 * source or for server-side processing - this parameter allows that
20980		 * property to be changed. You can use Javascript dotted object notation to
20981		 * get a data source for multiple levels of nesting.
20982		 *  @type string
20983		 *  @default data
20984		 *
20985		 *  @dtopt Options
20986		 *  @dtopt Server-side
20987		 *  @name DataTable.defaults.ajaxDataProp
20988		 *
20989		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
20990		 */
20991		"sAjaxDataProp": "data",
20992	
20993	
20994		/**
20995		 * __Deprecated__ The functionality provided by this parameter has now been
20996		 * superseded by that provided through `ajax`, which should be used instead.
20997		 *
20998		 * You can instruct DataTables to load data from an external
20999		 * source using this parameter (use aData if you want to pass data in you
21000		 * already have). Simply provide a url a JSON object can be obtained from.
21001		 *  @type string
21002		 *  @default null
21003		 *
21004		 *  @dtopt Options
21005		 *  @dtopt Server-side
21006		 *  @name DataTable.defaults.ajaxSource
21007		 *
21008		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
21009		 */
21010		"sAjaxSource": null,
21011	
21012	
21013		/**
21014		 * This initialisation variable allows you to specify exactly where in the
21015		 * DOM you want DataTables to inject the various controls it adds to the page
21016		 * (for example you might want the pagination controls at the top of the
21017		 * table). DIV elements (with or without a custom class) can also be added to
21018		 * aid styling. The follow syntax is used:
21019		 *   <ul>
21020		 *     <li>The following options are allowed:
21021		 *       <ul>
21022		 *         <li>'l' - Length changing</li>
21023		 *         <li>'f' - Filtering input</li>
21024		 *         <li>'t' - The table!</li>
21025		 *         <li>'i' - Information</li>
21026		 *         <li>'p' - Pagination</li>
21027		 *         <li>'r' - pRocessing</li>
21028		 *       </ul>
21029		 *     </li>
21030		 *     <li>The following constants are allowed:
21031		 *       <ul>
21032		 *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
21033		 *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
21034		 *       </ul>
21035		 *     </li>
21036		 *     <li>The following syntax is expected:
21037		 *       <ul>
21038		 *         <li>'&lt;' and '&gt;' - div elements</li>
21039		 *         <li>'&lt;"class" and '&gt;' - div with a class</li>
21040		 *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
21041		 *       </ul>
21042		 *     </li>
21043		 *     <li>Examples:
21044		 *       <ul>
21045		 *         <li>'&lt;"wrapper"flipt&gt;'</li>
21046		 *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
21047		 *       </ul>
21048		 *     </li>
21049		 *   </ul>
21050		 *  @type string
21051		 *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
21052		 *    <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
21053		 *
21054		 *  @dtopt Options
21055		 *  @name DataTable.defaults.dom
21056		 *
21057		 *  @example
21058		 *    $(document).ready( function() {
21059		 *      $('#example').dataTable( {
21060		 *        "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
21061		 *      } );
21062		 *    } );
21063		 */
21064		"sDom": "lfrtip",
21065	
21066	
21067		/**
21068		 * Search delay option. This will throttle full table searches that use the
21069		 * DataTables provided search input element (it does not effect calls to
21070		 * `dt-api search()`, providing a delay before the search is made.
21071		 *  @type integer
21072		 *  @default 0
21073		 *
21074		 *  @dtopt Options
21075		 *  @name DataTable.defaults.searchDelay
21076		 *
21077		 *  @example
21078		 *    $(document).ready( function() {
21079		 *      $('#example').dataTable( {
21080		 *        "searchDelay": 200
21081		 *      } );
21082		 *    } )
21083		 */
21084		"searchDelay": null,
21085	
21086	
21087		/**
21088		 * DataTables features six different built-in options for the buttons to
21089		 * display for pagination control:
21090		 *
21091		 * * `numbers` - Page number buttons only
21092		 * * `simple` - 'Previous' and 'Next' buttons only
21093		 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
21094		 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
21095		 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
21096		 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
21097		 *  
21098		 * Further methods can be added using {@link DataTable.ext.oPagination}.
21099		 *  @type string
21100		 *  @default simple_numbers
21101		 *
21102		 *  @dtopt Options
21103		 *  @name DataTable.defaults.pagingType
21104		 *
21105		 *  @example
21106		 *    $(document).ready( function() {
21107		 *      $('#example').dataTable( {
21108		 *        "pagingType": "full_numbers"
21109		 *      } );
21110		 *    } )
21111		 */
21112		"sPaginationType": "simple_numbers",
21113	
21114	
21115		/**
21116		 * Enable horizontal scrolling. When a table is too wide to fit into a
21117		 * certain layout, or you have a large number of columns in the table, you
21118		 * can enable x-scrolling to show the table in a viewport, which can be
21119		 * scrolled. This property can be `true` which will allow the table to
21120		 * scroll horizontally when needed, or any CSS unit, or a number (in which
21121		 * case it will be treated as a pixel measurement). Setting as simply `true`
21122		 * is recommended.
21123		 *  @type boolean|string
21124		 *  @default <i>blank string - i.e. disabled</i>
21125		 *
21126		 *  @dtopt Features
21127		 *  @name DataTable.defaults.scrollX
21128		 *
21129		 *  @example
21130		 *    $(document).ready( function() {
21131		 *      $('#example').dataTable( {
21132		 *        "scrollX": true,
21133		 *        "scrollCollapse": true
21134		 *      } );
21135		 *    } );
21136		 */
21137		"sScrollX": "",
21138	
21139	
21140		/**
21141		 * This property can be used to force a DataTable to use more width than it
21142		 * might otherwise do when x-scrolling is enabled. For example if you have a
21143		 * table which requires to be well spaced, this parameter is useful for
21144		 * "over-sizing" the table, and thus forcing scrolling. This property can by
21145		 * any CSS unit, or a number (in which case it will be treated as a pixel
21146		 * measurement).
21147		 *  @type string
21148		 *  @default <i>blank string - i.e. disabled</i>
21149		 *
21150		 *  @dtopt Options
21151		 *  @name DataTable.defaults.scrollXInner
21152		 *
21153		 *  @example
21154		 *    $(document).ready( function() {
21155		 *      $('#example').dataTable( {
21156		 *        "scrollX": "100%",
21157		 *        "scrollXInner": "110%"
21158		 *      } );
21159		 *    } );
21160		 */
21161		"sScrollXInner": "",
21162	
21163	
21164		/**
21165		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
21166		 * to the given height, and enable scrolling for any data which overflows the
21167		 * current viewport. This can be used as an alternative to paging to display
21168		 * a lot of data in a small area (although paging and scrolling can both be
21169		 * enabled at the same time). This property can be any CSS unit, or a number
21170		 * (in which case it will be treated as a pixel measurement).
21171		 *  @type string
21172		 *  @default <i>blank string - i.e. disabled</i>
21173		 *
21174		 *  @dtopt Features
21175		 *  @name DataTable.defaults.scrollY
21176		 *
21177		 *  @example
21178		 *    $(document).ready( function() {
21179		 *      $('#example').dataTable( {
21180		 *        "scrollY": "200px",
21181		 *        "paginate": false
21182		 *      } );
21183		 *    } );
21184		 */
21185		"sScrollY": "",
21186	
21187	
21188		/**
21189		 * __Deprecated__ The functionality provided by this parameter has now been
21190		 * superseded by that provided through `ajax`, which should be used instead.
21191		 *
21192		 * Set the HTTP method that is used to make the Ajax call for server-side
21193		 * processing or Ajax sourced data.
21194		 *  @type string
21195		 *  @default GET
21196		 *
21197		 *  @dtopt Options
21198		 *  @dtopt Server-side
21199		 *  @name DataTable.defaults.serverMethod
21200		 *
21201		 *  @deprecated 1.10. Please use `ajax` for this functionality now.
21202		 */
21203		"sServerMethod": "GET",
21204	
21205	
21206		/**
21207		 * DataTables makes use of renderers when displaying HTML elements for
21208		 * a table. These renderers can be added or modified by plug-ins to
21209		 * generate suitable mark-up for a site. For example the Bootstrap
21210		 * integration plug-in for DataTables uses a paging button renderer to
21211		 * display pagination buttons in the mark-up required by Bootstrap.
21212		 *
21213		 * For further information about the renderers available see
21214		 * DataTable.ext.renderer
21215		 *  @type string|object
21216		 *  @default null
21217		 *
21218		 *  @name DataTable.defaults.renderer
21219		 *
21220		 */
21221		"renderer": null,
21222	
21223	
21224		/**
21225		 * Set the data property name that DataTables should use to get a row's id
21226		 * to set as the `id` property in the node.
21227		 *  @type string
21228		 *  @default DT_RowId
21229		 *
21230		 *  @name DataTable.defaults.rowId
21231		 */
21232		"rowId": "DT_RowId"
21233	};
21234	
21235	_fnHungarianMap( DataTable.defaults );
21236	
21237	
21238	
21239	/*
21240	 * Developer note - See note in model.defaults.js about the use of Hungarian
21241	 * notation and camel case.
21242	 */
21243	
21244	/**
21245	 * Column options that can be given to DataTables at initialisation time.
21246	 *  @namespace
21247	 */
21248	DataTable.defaults.column = {
21249		/**
21250		 * Define which column(s) an order will occur on for this column. This
21251		 * allows a column's ordering to take multiple columns into account when
21252		 * doing a sort or use the data from a different column. For example first
21253		 * name / last name columns make sense to do a multi-column sort over the
21254		 * two columns.
21255		 *  @type array|int
21256		 *  @default null <i>Takes the value of the column index automatically</i>
21257		 *
21258		 *  @name DataTable.defaults.column.orderData
21259		 *  @dtopt Columns
21260		 *
21261		 *  @example
21262		 *    // Using `columnDefs`
21263		 *    $(document).ready( function() {
21264		 *      $('#example').dataTable( {
21265		 *        "columnDefs": [
21266		 *          { "orderData": [ 0, 1 ], "targets": [ 0 ] },
21267		 *          { "orderData": [ 1, 0 ], "targets": [ 1 ] },
21268		 *          { "orderData": 2, "targets": [ 2 ] }
21269		 *        ]
21270		 *      } );
21271		 *    } );
21272		 *
21273		 *  @example
21274		 *    // Using `columns`
21275		 *    $(document).ready( function() {
21276		 *      $('#example').dataTable( {
21277		 *        "columns": [
21278		 *          { "orderData": [ 0, 1 ] },
21279		 *          { "orderData": [ 1, 0 ] },
21280		 *          { "orderData": 2 },
21281		 *          null,
21282		 *          null
21283		 *        ]
21284		 *      } );
21285		 *    } );
21286		 */
21287		"aDataSort": null,
21288		"iDataSort": -1,
21289	
21290	
21291		/**
21292		 * You can control the default ordering direction, and even alter the
21293		 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
21294		 * using this parameter.
21295		 *  @type array
21296		 *  @default [ 'asc', 'desc' ]
21297		 *
21298		 *  @name DataTable.defaults.column.orderSequence
21299		 *  @dtopt Columns
21300		 *
21301		 *  @example
21302		 *    // Using `columnDefs`
21303		 *    $(document).ready( function() {
21304		 *      $('#example').dataTable( {
21305		 *        "columnDefs": [
21306		 *          { "orderSequence": [ "asc" ], "targets": [ 1 ] },
21307		 *          { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
21308		 *          { "orderSequence": [ "desc" ], "targets": [ 3 ] }
21309		 *        ]
21310		 *      } );
21311		 *    } );
21312		 *
21313		 *  @example
21314		 *    // Using `columns`
21315		 *    $(document).ready( function() {
21316		 *      $('#example').dataTable( {
21317		 *        "columns": [
21318		 *          null,
21319		 *          { "orderSequence": [ "asc" ] },
21320		 *          { "orderSequence": [ "desc", "asc", "asc" ] },
21321		 *          { "orderSequence": [ "desc" ] },
21322		 *          null
21323		 *        ]
21324		 *      } );
21325		 *    } );
21326		 */
21327		"asSorting": [ 'asc', 'desc' ],
21328	
21329	
21330		/**
21331		 * Enable or disable filtering on the data in this column.
21332		 *  @type boolean
21333		 *  @default true
21334		 *
21335		 *  @name DataTable.defaults.column.searchable
21336		 *  @dtopt Columns
21337		 *
21338		 *  @example
21339		 *    // Using `columnDefs`
21340		 *    $(document).ready( function() {
21341		 *      $('#example').dataTable( {
21342		 *        "columnDefs": [
21343		 *          { "searchable": false, "targets": [ 0 ] }
21344		 *        ] } );
21345		 *    } );
21346		 *
21347		 *  @example
21348		 *    // Using `columns`
21349		 *    $(document).ready( function() {
21350		 *      $('#example').dataTable( {
21351		 *        "columns": [
21352		 *          { "searchable": false },
21353		 *          null,
21354		 *          null,
21355		 *          null,
21356		 *          null
21357		 *        ] } );
21358		 *    } );
21359		 */
21360		"bSearchable": true,
21361	
21362	
21363		/**
21364		 * Enable or disable ordering on this column.
21365		 *  @type boolean
21366		 *  @default true
21367		 *
21368		 *  @name DataTable.defaults.column.orderable
21369		 *  @dtopt Columns
21370		 *
21371		 *  @example
21372		 *    // Using `columnDefs`
21373		 *    $(document).ready( function() {
21374		 *      $('#example').dataTable( {
21375		 *        "columnDefs": [
21376		 *          { "orderable": false, "targets": [ 0 ] }
21377		 *        ] } );
21378		 *    } );
21379		 *
21380		 *  @example
21381		 *    // Using `columns`
21382		 *    $(document).ready( function() {
21383		 *      $('#example').dataTable( {
21384		 *        "columns": [
21385		 *          { "orderable": false },
21386		 *          null,
21387		 *          null,
21388		 *          null,
21389		 *          null
21390		 *        ] } );
21391		 *    } );
21392		 */
21393		"bSortable": true,
21394	
21395	
21396		/**
21397		 * Enable or disable the display of this column.
21398		 *  @type boolean
21399		 *  @default true
21400		 *
21401		 *  @name DataTable.defaults.column.visible
21402		 *  @dtopt Columns
21403		 *
21404		 *  @example
21405		 *    // Using `columnDefs`
21406		 *    $(document).ready( function() {
21407		 *      $('#example').dataTable( {
21408		 *        "columnDefs": [
21409		 *          { "visible": false, "targets": [ 0 ] }
21410		 *        ] } );
21411		 *    } );
21412		 *
21413		 *  @example
21414		 *    // Using `columns`
21415		 *    $(document).ready( function() {
21416		 *      $('#example').dataTable( {
21417		 *        "columns": [
21418		 *          { "visible": false },
21419		 *          null,
21420		 *          null,
21421		 *          null,
21422		 *          null
21423		 *        ] } );
21424		 *    } );
21425		 */
21426		"bVisible": true,
21427	
21428	
21429		/**
21430		 * Developer definable function that is called whenever a cell is created (Ajax source,
21431		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
21432		 * allowing you to modify the DOM element (add background colour for example) when the
21433		 * element is available.
21434		 *  @type function
21435		 *  @param {element} td The TD node that has been created
21436		 *  @param {*} cellData The Data for the cell
21437		 *  @param {array|object} rowData The data for the whole row
21438		 *  @param {int} row The row index for the aoData data store
21439		 *  @param {int} col The column index for aoColumns
21440		 *
21441		 *  @name DataTable.defaults.column.createdCell
21442		 *  @dtopt Columns
21443		 *
21444		 *  @example
21445		 *    $(document).ready( function() {
21446		 *      $('#example').dataTable( {
21447		 *        "columnDefs": [ {
21448		 *          "targets": [3],
21449		 *          "createdCell": function (td, cellData, rowData, row, col) {
21450		 *            if ( cellData == "1.7" ) {
21451		 *              $(td).css('color', 'blue')
21452		 *            }
21453		 *          }
21454		 *        } ]
21455		 *      });
21456		 *    } );
21457		 */
21458		"fnCreatedCell": null,
21459	
21460	
21461		/**
21462		 * This parameter has been replaced by `data` in DataTables to ensure naming
21463		 * consistency. `dataProp` can still be used, as there is backwards
21464		 * compatibility in DataTables for this option, but it is strongly
21465		 * recommended that you use `data` in preference to `dataProp`.
21466		 *  @name DataTable.defaults.column.dataProp
21467		 */
21468	
21469	
21470		/**
21471		 * This property can be used to read data from any data source property,
21472		 * including deeply nested objects / properties. `data` can be given in a
21473		 * number of different ways which effect its behaviour:
21474		 *
21475		 * * `integer` - treated as an array index for the data source. This is the
21476		 *   default that DataTables uses (incrementally increased for each column).
21477		 * * `string` - read an object property from the data source. There are
21478		 *   three 'special' options that can be used in the string to alter how
21479		 *   DataTables reads the data from the source object:
21480		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
21481		 *      Javascript to read from nested objects, so to can the options
21482		 *      specified in `data`. For example: `browser.version` or
21483		 *      `browser.name`. If your object parameter name contains a period, use
21484		 *      `\\` to escape it - i.e. `first\\.name`.
21485		 *    * `[]` - Array notation. DataTables can automatically combine data
21486		 *      from and array source, joining the data with the characters provided
21487		 *      between the two brackets. For example: `name[, ]` would provide a
21488		 *      comma-space separated list from the source array. If no characters
21489		 *      are provided between the brackets, the original array source is
21490		 *      returned.
21491		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
21492		 *      execute a function of the name given. For example: `browser()` for a
21493		 *      simple function on the data source, `browser.version()` for a
21494		 *      function in a nested property or even `browser().version` to get an
21495		 *      object property if the function called returns an object. Note that
21496		 *      function notation is recommended for use in `render` rather than
21497		 *      `data` as it is much simpler to use as a renderer.
21498		 * * `null` - use the original data source for the row rather than plucking
21499		 *   data directly from it. This action has effects on two other
21500		 *   initialisation options:
21501		 *    * `defaultContent` - When null is given as the `data` option and
21502		 *      `defaultContent` is specified for the column, the value defined by
21503		 *      `defaultContent` will be used for the cell.
21504		 *    * `render` - When null is used for the `data` option and the `render`
21505		 *      option is specified for the column, the whole data source for the
21506		 *      row is used for the renderer.
21507		 * * `function` - the function given will be executed whenever DataTables
21508		 *   needs to set or get the data for a cell in the column. The function
21509		 *   takes three parameters:
21510		 *    * Parameters:
21511		 *      * `{array|object}` The data source for the row
21512		 *      * `{string}` The type call data requested - this will be 'set' when
21513		 *        setting data or 'filter', 'display', 'type', 'sort' or undefined
21514		 *        when gathering data. Note that when `undefined` is given for the
21515		 *        type DataTables expects to get the raw data for the object back<
21516		 *      * `{*}` Data to set when the second parameter is 'set'.
21517		 *    * Return:
21518		 *      * The return value from the function is not required when 'set' is
21519		 *        the type of call, but otherwise the return is what will be used
21520		 *        for the data requested.
21521		 *
21522		 * Note that `data` is a getter and setter option. If you just require
21523		 * formatting of data for output, you will likely want to use `render` which
21524		 * is simply a getter and thus simpler to use.
21525		 *
21526		 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
21527		 * name change reflects the flexibility of this property and is consistent
21528		 * with the naming of mRender. If 'mDataProp' is given, then it will still
21529		 * be used by DataTables, as it automatically maps the old name to the new
21530		 * if required.
21531		 *
21532		 *  @type string|int|function|null
21533		 *  @default null <i>Use automatically calculated column index</i>
21534		 *
21535		 *  @name DataTable.defaults.column.data
21536		 *  @dtopt Columns
21537		 *
21538		 *  @example
21539		 *    // Read table data from objects
21540		 *    // JSON structure for each row:
21541		 *    //   {
21542		 *    //      "engine": {value},
21543		 *    //      "browser": {value},
21544		 *    //      "platform": {value},
21545		 *    //      "version": {value},
21546		 *    //      "grade": {value}
21547		 *    //   }
21548		 *    $(document).ready( function() {
21549		 *      $('#example').dataTable( {
21550		 *        "ajaxSource": "sources/objects.txt",
21551		 *        "columns": [
21552		 *          { "data": "engine" },
21553		 *          { "data": "browser" },
21554		 *          { "data": "platform" },
21555		 *          { "data": "version" },
21556		 *          { "data": "grade" }
21557		 *        ]
21558		 *      } );
21559		 *    } );
21560		 *
21561		 *  @example
21562		 *    // Read information from deeply nested objects
21563		 *    // JSON structure for each row:
21564		 *    //   {
21565		 *    //      "engine": {value},
21566		 *    //      "browser": {value},
21567		 *    //      "platform": {
21568		 *    //         "inner": {value}
21569		 *    //      },
21570		 *    //      "details": [
21571		 *    //         {value}, {value}
21572		 *    //      ]
21573		 *    //   }
21574		 *    $(document).ready( function() {
21575		 *      $('#example').dataTable( {
21576		 *        "ajaxSource": "sources/deep.txt",
21577		 *        "columns": [
21578		 *          { "data": "engine" },
21579		 *          { "data": "browser" },
21580		 *          { "data": "platform.inner" },
21581		 *          { "data": "details.0" },
21582		 *          { "data": "details.1" }
21583		 *        ]
21584		 *      } );
21585		 *    } );
21586		 *
21587		 *  @example
21588		 *    // Using `data` as a function to provide different information for
21589		 *    // sorting, filtering and display. In this case, currency (price)
21590		 *    $(document).ready( function() {
21591		 *      $('#example').dataTable( {
21592		 *        "columnDefs": [ {
21593		 *          "targets": [ 0 ],
21594		 *          "data": function ( source, type, val ) {
21595		 *            if (type === 'set') {
21596		 *              source.price = val;
21597		 *              // Store the computed dislay and filter values for efficiency
21598		 *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
21599		 *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
21600		 *              return;
21601		 *            }
21602		 *            else if (type === 'display') {
21603		 *              return source.price_display;
21604		 *            }
21605		 *            else if (type === 'filter') {
21606		 *              return source.price_filter;
21607		 *            }
21608		 *            // 'sort', 'type' and undefined all just use the integer
21609		 *            return source.price;
21610		 *          }
21611		 *        } ]
21612		 *      } );
21613		 *    } );
21614		 *
21615		 *  @example
21616		 *    // Using default content
21617		 *    $(document).ready( function() {
21618		 *      $('#example').dataTable( {
21619		 *        "columnDefs": [ {
21620		 *          "targets": [ 0 ],
21621		 *          "data": null,
21622		 *          "defaultContent": "Click to edit"
21623		 *        } ]
21624		 *      } );
21625		 *    } );
21626		 *
21627		 *  @example
21628		 *    // Using array notation - outputting a list from an array
21629		 *    $(document).ready( function() {
21630		 *      $('#example').dataTable( {
21631		 *        "columnDefs": [ {
21632		 *          "targets": [ 0 ],
21633		 *          "data": "name[, ]"
21634		 *        } ]
21635		 *      } );
21636		 *    } );
21637		 *
21638		 */
21639		"mData": null,
21640	
21641	
21642		/**
21643		 * This property is the rendering partner to `data` and it is suggested that
21644		 * when you want to manipulate data for display (including filtering,
21645		 * sorting etc) without altering the underlying data for the table, use this
21646		 * property. `render` can be considered to be the the read only companion to
21647		 * `data` which is read / write (then as such more complex). Like `data`
21648		 * this option can be given in a number of different ways to effect its
21649		 * behaviour:
21650		 *
21651		 * * `integer` - treated as an array index for the data source. This is the
21652		 *   default that DataTables uses (incrementally increased for each column).
21653		 * * `string` - read an object property from the data source. There are
21654		 *   three 'special' options that can be used in the string to alter how
21655		 *   DataTables reads the data from the source object:
21656		 *    * `.` - Dotted Javascript notation. Just as you use a `.` in
21657		 *      Javascript to read from nested objects, so to can the options
21658		 *      specified in `data`. For example: `browser.version` or
21659		 *      `browser.name`. If your object parameter name contains a period, use
21660		 *      `\\` to escape it - i.e. `first\\.name`.
21661		 *    * `[]` - Array notation. DataTables can automatically combine data
21662		 *      from and array source, joining the data with the characters provided
21663		 *      between the two brackets. For example: `name[, ]` would provide a
21664		 *      comma-space separated list from the source array. If no characters
21665		 *      are provided between the brackets, the original array source is
21666		 *      returned.
21667		 *    * `()` - Function notation. Adding `()` to the end of a parameter will
21668		 *      execute a function of the name given. For example: `browser()` for a
21669		 *      simple function on the data source, `browser.version()` for a
21670		 *      function in a nested property or even `browser().version` to get an
21671		 *      object property if the function called returns an object.
21672		 * * `object` - use different data for the different data types requested by
21673		 *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
21674		 *   of the object is the data type the property refers to and the value can
21675		 *   defined using an integer, string or function using the same rules as
21676		 *   `render` normally does. Note that an `_` option _must_ be specified.
21677		 *   This is the default value to use if you haven't specified a value for
21678		 *   the data type requested by DataTables.
21679		 * * `function` - the function given will be executed whenever DataTables
21680		 *   needs to set or get the data for a cell in the column. The function
21681		 *   takes three parameters:
21682		 *    * Parameters:
21683		 *      * {array|object} The data source for the row (based on `data`)
21684		 *      * {string} The type call data requested - this will be 'filter',
21685		 *        'display', 'type' or 'sort'.
21686		 *      * {array|object} The full data source for the row (not based on
21687		 *        `data`)
21688		 *    * Return:
21689		 *      * The return value from the function is what will be used for the
21690		 *        data requested.
21691		 *
21692		 *  @type string|int|function|object|null
21693		 *  @default null Use the data source value.
21694		 *
21695		 *  @name DataTable.defaults.column.render
21696		 *  @dtopt Columns
21697		 *
21698		 *  @example
21699		 *    // Create a comma separated list from an array of objects
21700		 *    $(document).ready( function() {
21701		 *      $('#example').dataTable( {
21702		 *        "ajaxSource": "sources/deep.txt",
21703		 *        "columns": [
21704		 *          { "data": "engine" },
21705		 *          { "data": "browser" },
21706		 *          {
21707		 *            "data": "platform",
21708		 *            "render": "[, ].name"
21709		 *          }
21710		 *        ]
21711		 *      } );
21712		 *    } );
21713		 *
21714		 *  @example
21715		 *    // Execute a function to obtain data
21716		 *    $(document).ready( function() {
21717		 *      $('#example').dataTable( {
21718		 *        "columnDefs": [ {
21719		 *          "targets": [ 0 ],
21720		 *          "data": null, // Use the full data source object for the renderer's source
21721		 *          "render": "browserName()"
21722		 *        } ]
21723		 *      } );
21724		 *    } );
21725		 *
21726		 *  @example
21727		 *    // As an object, extracting different data for the different types
21728		 *    // This would be used with a data source such as:
21729		 *    //   { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
21730		 *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
21731		 *    // (which has both forms) is used for filtering for if a user inputs either format, while
21732		 *    // the formatted phone number is the one that is shown in the table.
21733		 *    $(document).ready( function() {
21734		 *      $('#example').dataTable( {
21735		 *        "columnDefs": [ {
21736		 *          "targets": [ 0 ],
21737		 *          "data": null, // Use the full data source object for the renderer's source
21738		 *          "render": {
21739		 *            "_": "phone",
21740		 *            "filter": "phone_filter",
21741		 *            "display": "phone_display"
21742		 *          }
21743		 *        } ]
21744		 *      } );
21745		 *    } );
21746		 *
21747		 *  @example
21748		 *    // Use as a function to create a link from the data source
21749		 *    $(document).ready( function() {
21750		 *      $('#example').dataTable( {
21751		 *        "columnDefs": [ {
21752		 *          "targets": [ 0 ],
21753		 *          "data": "download_link",
21754		 *          "render": function ( data, type, full ) {
21755		 *            return '<a href="'+data+'">Download</a>';
21756		 *          }
21757		 *        } ]
21758		 *      } );
21759		 *    } );
21760		 */
21761		"mRender": null,
21762	
21763	
21764		/**
21765		 * Change the cell type created for the column - either TD cells or TH cells. This
21766		 * can be useful as TH cells have semantic meaning in the table body, allowing them
21767		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
21768		 *  @type string
21769		 *  @default td
21770		 *
21771		 *  @name DataTable.defaults.column.cellType
21772		 *  @dtopt Columns
21773		 *
21774		 *  @example
21775		 *    // Make the first column use TH cells
21776		 *    $(document).ready( function() {
21777		 *      $('#example').dataTable( {
21778		 *        "columnDefs": [ {
21779		 *          "targets": [ 0 ],
21780		 *          "cellType": "th"
21781		 *        } ]
21782		 *      } );
21783		 *    } );
21784		 */
21785		"sCellType": "td",
21786	
21787	
21788		/**
21789		 * Class to give to each cell in this column.
21790		 *  @type string
21791		 *  @default <i>Empty string</i>
21792		 *
21793		 *  @name DataTable.defaults.column.class
21794		 *  @dtopt Columns
21795		 *
21796		 *  @example
21797		 *    // Using `columnDefs`
21798		 *    $(document).ready( function() {
21799		 *      $('#example').dataTable( {
21800		 *        "columnDefs": [
21801		 *          { "class": "my_class", "targets": [ 0 ] }
21802		 *        ]
21803		 *      } );
21804		 *    } );
21805		 *
21806		 *  @example
21807		 *    // Using `columns`
21808		 *    $(document).ready( function() {
21809		 *      $('#example').dataTable( {
21810		 *        "columns": [
21811		 *          { "class": "my_class" },
21812		 *          null,
21813		 *          null,
21814		 *          null,
21815		 *          null
21816		 *        ]
21817		 *      } );
21818		 *    } );
21819		 */
21820		"sClass": "",
21821	
21822		/**
21823		 * When DataTables calculates the column widths to assign to each column,
21824		 * it finds the longest string in each column and then constructs a
21825		 * temporary table and reads the widths from that. The problem with this
21826		 * is that "mmm" is much wider then "iiii", but the latter is a longer
21827		 * string - thus the calculation can go wrong (doing it properly and putting
21828		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
21829		 * a "work around" we provide this option. It will append its value to the
21830		 * text that is found to be the longest string for the column - i.e. padding.
21831		 * Generally you shouldn't need this!
21832		 *  @type string
21833		 *  @default <i>Empty string<i>
21834		 *
21835		 *  @name DataTable.defaults.column.contentPadding
21836		 *  @dtopt Columns
21837		 *
21838		 *  @example
21839		 *    // Using `columns`
21840		 *    $(document).ready( function() {
21841		 *      $('#example').dataTable( {
21842		 *        "columns": [
21843		 *          null,
21844		 *          null,
21845		 *          null,
21846		 *          {
21847		 *            "contentPadding": "mmm"
21848		 *          }
21849		 *        ]
21850		 *      } );
21851		 *    } );
21852		 */
21853		"sContentPadding": "",
21854	
21855	
21856		/**
21857		 * Allows a default value to be given for a column's data, and will be used
21858		 * whenever a null data source is encountered (this can be because `data`
21859		 * is set to null, or because the data source itself is null).
21860		 *  @type string
21861		 *  @default null
21862		 *
21863		 *  @name DataTable.defaults.column.defaultContent
21864		 *  @dtopt Columns
21865		 *
21866		 *  @example
21867		 *    // Using `columnDefs`
21868		 *    $(document).ready( function() {
21869		 *      $('#example').dataTable( {
21870		 *        "columnDefs": [
21871		 *          {
21872		 *            "data": null,
21873		 *            "defaultContent": "Edit",
21874		 *            "targets": [ -1 ]
21875		 *          }
21876		 *        ]
21877		 *      } );
21878		 *    } );
21879		 *
21880		 *  @example
21881		 *    // Using `columns`
21882		 *    $(document).ready( function() {
21883		 *      $('#example').dataTable( {
21884		 *        "columns": [
21885		 *          null,
21886		 *          null,
21887		 *          null,
21888		 *          {
21889		 *            "data": null,
21890		 *            "defaultContent": "Edit"
21891		 *          }
21892		 *        ]
21893		 *      } );
21894		 *    } );
21895		 */
21896		"sDefaultContent": null,
21897	
21898	
21899		/**
21900		 * This parameter is only used in DataTables' server-side processing. It can
21901		 * be exceptionally useful to know what columns are being displayed on the
21902		 * client side, and to map these to database fields. When defined, the names
21903		 * also allow DataTables to reorder information from the server if it comes
21904		 * back in an unexpected order (i.e. if you switch your columns around on the
21905		 * client-side, your server-side code does not also need updating).
21906		 *  @type string
21907		 *  @default <i>Empty string</i>
21908		 *
21909		 *  @name DataTable.defaults.column.name
21910		 *  @dtopt Columns
21911		 *
21912		 *  @example
21913		 *    // Using `columnDefs`
21914		 *    $(document).ready( function() {
21915		 *      $('#example').dataTable( {
21916		 *        "columnDefs": [
21917		 *          { "name": "engine", "targets": [ 0 ] },
21918		 *          { "name": "browser", "targets": [ 1 ] },
21919		 *          { "name": "platform", "targets": [ 2 ] },
21920		 *          { "name": "version", "targets": [ 3 ] },
21921		 *          { "name": "grade", "targets": [ 4 ] }
21922		 *        ]
21923		 *      } );
21924		 *    } );
21925		 *
21926		 *  @example
21927		 *    // Using `columns`
21928		 *    $(document).ready( function() {
21929		 *      $('#example').dataTable( {
21930		 *        "columns": [
21931		 *          { "name": "engine" },
21932		 *          { "name": "browser" },
21933		 *          { "name": "platform" },
21934		 *          { "name": "version" },
21935		 *          { "name": "grade" }
21936		 *        ]
21937		 *      } );
21938		 *    } );
21939		 */
21940		"sName": "",
21941	
21942	
21943		/**
21944		 * Defines a data source type for the ordering which can be used to read
21945		 * real-time information from the table (updating the internally cached
21946		 * version) prior to ordering. This allows ordering to occur on user
21947		 * editable elements such as form inputs.
21948		 *  @type string
21949		 *  @default std
21950		 *
21951		 *  @name DataTable.defaults.column.orderDataType
21952		 *  @dtopt Columns
21953		 *
21954		 *  @example
21955		 *    // Using `columnDefs`
21956		 *    $(document).ready( function() {
21957		 *      $('#example').dataTable( {
21958		 *        "columnDefs": [
21959		 *          { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
21960		 *          { "type": "numeric", "targets": [ 3 ] },
21961		 *          { "orderDataType": "dom-select", "targets": [ 4 ] },
21962		 *          { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
21963		 *        ]
21964		 *      } );
21965		 *    } );
21966		 *
21967		 *  @example
21968		 *    // Using `columns`
21969		 *    $(document).ready( function() {
21970		 *      $('#example').dataTable( {
21971		 *        "columns": [
21972		 *          null,
21973		 *          null,
21974		 *          { "orderDataType": "dom-text" },
21975		 *          { "orderDataType": "dom-text", "type": "numeric" },
21976		 *          { "orderDataType": "dom-select" },
21977		 *          { "orderDataType": "dom-checkbox" }
21978		 *        ]
21979		 *      } );
21980		 *    } );
21981		 */
21982		"sSortDataType": "std",
21983	
21984	
21985		/**
21986		 * The title of this column.
21987		 *  @type string
21988		 *  @default null <i>Derived from the 'TH' value for this column in the
21989		 *    original HTML table.</i>
21990		 *
21991		 *  @name DataTable.defaults.column.title
21992		 *  @dtopt Columns
21993		 *
21994		 *  @example
21995		 *    // Using `columnDefs`
21996		 *    $(document).ready( function() {
21997		 *      $('#example').dataTable( {
21998		 *        "columnDefs": [
21999		 *          { "title": "My column title", "targets": [ 0 ] }
22000		 *        ]
22001		 *      } );
22002		 *    } );
22003		 *
22004		 *  @example
22005		 *    // Using `columns`
22006		 *    $(document).ready( function() {
22007		 *      $('#example').dataTable( {
22008		 *        "columns": [
22009		 *          { "title": "My column title" },
22010		 *          null,
22011		 *          null,
22012		 *          null,
22013		 *          null
22014		 *        ]
22015		 *      } );
22016		 *    } );
22017		 */
22018		"sTitle": null,
22019	
22020	
22021		/**
22022		 * The type allows you to specify how the data for this column will be
22023		 * ordered. Four types (string, numeric, date and html (which will strip
22024		 * HTML tags before ordering)) are currently available. Note that only date
22025		 * formats understood by Javascript's Date() object will be accepted as type
22026		 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
22027		 * 'numeric', 'date' or 'html' (by default). Further types can be adding
22028		 * through plug-ins.
22029		 *  @type string
22030		 *  @default null <i>Auto-detected from raw data</i>
22031		 *
22032		 *  @name DataTable.defaults.column.type
22033		 *  @dtopt Columns
22034		 *
22035		 *  @example
22036		 *    // Using `columnDefs`
22037		 *    $(document).ready( function() {
22038		 *      $('#example').dataTable( {
22039		 *        "columnDefs": [
22040		 *          { "type": "html", "targets": [ 0 ] }
22041		 *        ]
22042		 *      } );
22043		 *    } );
22044		 *
22045		 *  @example
22046		 *    // Using `columns`
22047		 *    $(document).ready( function() {
22048		 *      $('#example').dataTable( {
22049		 *        "columns": [
22050		 *          { "type": "html" },
22051		 *          null,
22052		 *          null,
22053		 *          null,
22054		 *          null
22055		 *        ]
22056		 *      } );
22057		 *    } );
22058		 */
22059		"sType": null,
22060	
22061	
22062		/**
22063		 * Defining the width of the column, this parameter may take any CSS value
22064		 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
22065		 * been given a specific width through this interface ensuring that the table
22066		 * remains readable.
22067		 *  @type string
22068		 *  @default null <i>Automatic</i>
22069		 *
22070		 *  @name DataTable.defaults.column.width
22071		 *  @dtopt Columns
22072		 *
22073		 *  @example
22074		 *    // Using `columnDefs`
22075		 *    $(document).ready( function() {
22076		 *      $('#example').dataTable( {
22077		 *        "columnDefs": [
22078		 *          { "width": "20%", "targets": [ 0 ] }
22079		 *        ]
22080		 *      } );
22081		 *    } );
22082		 *
22083		 *  @example
22084		 *    // Using `columns`
22085		 *    $(document).ready( function() {
22086		 *      $('#example').dataTable( {
22087		 *        "columns": [
22088		 *          { "width": "20%" },
22089		 *          null,
22090		 *          null,
22091		 *          null,
22092		 *          null
22093		 *        ]
22094		 *      } );
22095		 *    } );
22096		 */
22097		"sWidth": null
22098	};
22099	
22100	_fnHungarianMap( DataTable.defaults.column );
22101	
22102	
22103	
22104	/**
22105	 * DataTables settings object - this holds all the information needed for a
22106	 * given table, including configuration, data and current application of the
22107	 * table options. DataTables does not have a single instance for each DataTable
22108	 * with the settings attached to that instance, but rather instances of the
22109	 * DataTable "class" are created on-the-fly as needed (typically by a
22110	 * $().dataTable() call) and the settings object is then applied to that
22111	 * instance.
22112	 *
22113	 * Note that this object is related to {@link DataTable.defaults} but this
22114	 * one is the internal data store for DataTables's cache of columns. It should
22115	 * NOT be manipulated outside of DataTables. Any configuration should be done
22116	 * through the initialisation options.
22117	 *  @namespace
22118	 *  @todo Really should attach the settings object to individual instances so we
22119	 *    don't need to create new instances on each $().dataTable() call (if the
22120	 *    table already exists). It would also save passing oSettings around and
22121	 *    into every single function. However, this is a very significant
22122	 *    architecture change for DataTables and will almost certainly break
22123	 *    backwards compatibility with older installations. This is something that
22124	 *    will be done in 2.0.
22125	 */
22126	DataTable.models.oSettings = {
22127		/**
22128		 * Primary features of DataTables and their enablement state.
22129		 *  @namespace
22130		 */
22131		"oFeatures": {
22132	
22133			/**
22134			 * Flag to say if DataTables should automatically try to calculate the
22135			 * optimum table and columns widths (true) or not (false).
22136			 * Note that this parameter will be set by the initialisation routine. To
22137			 * set a default use {@link DataTable.defaults}.
22138			 *  @type boolean
22139			 */
22140			"bAutoWidth": null,
22141	
22142			/**
22143			 * Delay the creation of TR and TD elements until they are actually
22144			 * needed by a driven page draw. This can give a significant speed
22145			 * increase for Ajax source and Javascript source data, but makes no
22146			 * difference at all f
22146ro
vendor: 14,836 bytes, lines 22146-22723
22146 DOM and server-side processing tables.
22147			 * Note that this parameter will be set by the initialisation routine. To
22148			 * set a default use {@link DataTable.defaults}.
22149			 *  @type boolean
22150			 */
22151			"bDeferRender": null,
22152	
22153			/**
22154			 * Enable filtering on the table or not. Note that if this is disabled
22155			 * then there is no filtering at all on the table, including fnFilter.
22156			 * To just remove the filtering input use sDom and remove the 'f' option.
22157			 * Note that this parameter will be set by the initialisation routine. To
22158			 * set a default use {@link DataTable.defaults}.
22159			 *  @type boolean
22160			 */
22161			"bFilter": null,
22162	
22163			/**
22164			 * Table information element (the 'Showing x of y records' div) enable
22165			 * flag.
22166			 * Note that this parameter will be set by the initialisation routine. To
22167			 * set a default use {@link DataTable.defaults}.
22168			 *  @type boolean
22169			 */
22170			"bInfo": null,
22171	
22172			/**
22173			 * Present a user control allowing the end user to change the page size
22174			 * when pagination is enabled.
22175			 * Note that this parameter will be set by the initialisation routine. To
22176			 * set a default use {@link DataTable.defaults}.
22177			 *  @type boolean
22178			 */
22179			"bLengthChange": null,
22180	
22181			/**
22182			 * Pagination enabled or not. Note that if this is disabled then length
22183			 * changing must also be disabled.
22184			 * Note that this parameter will be set by the initialisation routine. To
22185			 * set a default use {@link DataTable.defaults}.
22186			 *  @type boolean
22187			 */
22188			"bPaginate": null,
22189	
22190			/**
22191			 * Processing indicator enable flag whenever DataTables is enacting a
22192			 * user request - typically an Ajax request for server-side processing.
22193			 * Note that this parameter will be set by the initialisation routine. To
22194			 * set a default use {@link DataTable.defaults}.
22195			 *  @type boolean
22196			 */
22197			"bProcessing": null,
22198	
22199			/**
22200			 * Server-side processing enabled flag - when enabled DataTables will
22201			 * get all data from the server for every draw - there is no filtering,
22202			 * sorting or paging done on the client-side.
22203			 * Note that this parameter will be set by the initialisation routine. To
22204			 * set a default use {@link DataTable.defaults}.
22205			 *  @type boolean
22206			 */
22207			"bServerSide": null,
22208	
22209			/**
22210			 * Sorting enablement flag.
22211			 * Note that this parameter will be set by the initialisation routine. To
22212			 * set a default use {@link DataTable.defaults}.
22213			 *  @type boolean
22214			 */
22215			"bSort": null,
22216	
22217			/**
22218			 * Multi-column sorting
22219			 * Note that this parameter will be set by the initialisation routine. To
22220			 * set a default use {@link DataTable.defaults}.
22221			 *  @type boolean
22222			 */
22223			"bSortMulti": null,
22224	
22225			/**
22226			 * Apply a class to the columns which are being sorted to provide a
22227			 * visual highlight or not. This can slow things down when enabled since
22228			 * there is a lot of DOM interaction.
22229			 * Note that this parameter will be set by the initialisation routine. To
22230			 * set a default use {@link DataTable.defaults}.
22231			 *  @type boolean
22232			 */
22233			"bSortClasses": null,
22234	
22235			/**
22236			 * State saving enablement flag.
22237			 * Note that this parameter will be set by the initialisation routine. To
22238			 * set a default use {@link DataTable.defaults}.
22239			 *  @type boolean
22240			 */
22241			"bStateSave": null
22242		},
22243	
22244	
22245		/**
22246		 * Scrolling settings for a table.
22247		 *  @namespace
22248		 */
22249		"oScroll": {
22250			/**
22251			 * When the table is shorter in height than sScrollY, collapse the
22252			 * table container down to the height of the table (when true).
22253			 * Note that this parameter will be set by the initialisation routine. To
22254			 * set a default use {@link DataTable.defaults}.
22255			 *  @type boolean
22256			 */
22257			"bCollapse": null,
22258	
22259			/**
22260			 * Width of the scrollbar for the web-browser's platform. Calculated
22261			 * during table initialisation.
22262			 *  @type int
22263			 *  @default 0
22264			 */
22265			"iBarWidth": 0,
22266	
22267			/**
22268			 * Viewport width for horizontal scrolling. Horizontal scrolling is
22269			 * disabled if an empty string.
22270			 * Note that this parameter will be set by the initialisation routine. To
22271			 * set a default use {@link DataTable.defaults}.
22272			 *  @type string
22273			 */
22274			"sX": null,
22275	
22276			/**
22277			 * Width to expand the table to when using x-scrolling. Typically you
22278			 * should not need to use this.
22279			 * Note that this parameter will be set by the initialisation routine. To
22280			 * set a default use {@link DataTable.defaults}.
22281			 *  @type string
22282			 *  @deprecated
22283			 */
22284			"sXInner": null,
22285	
22286			/**
22287			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
22288			 * if an empty string.
22289			 * Note that this parameter will be set by the initialisation routine. To
22290			 * set a default use {@link DataTable.defaults}.
22291			 *  @type string
22292			 */
22293			"sY": null
22294		},
22295	
22296		/**
22297		 * Language information for the table.
22298		 *  @namespace
22299		 *  @extends DataTable.defaults.oLanguage
22300		 */
22301		"oLanguage": {
22302			/**
22303			 * Information callback function. See
22304			 * {@link DataTable.defaults.fnInfoCallback}
22305			 *  @type function
22306			 *  @default null
22307			 */
22308			"fnInfoCallback": null
22309		},
22310	
22311		/**
22312		 * Browser support parameters
22313		 *  @namespace
22314		 */
22315		"oBrowser": {
22316			/**
22317			 * Indicate if the browser incorrectly calculates width:100% inside a
22318			 * scrolling element (IE6/7)
22319			 *  @type boolean
22320			 *  @default false
22321			 */
22322			"bScrollOversize": false,
22323	
22324			/**
22325			 * Determine if the vertical scrollbar is on the right or left of the
22326			 * scrolling container - needed for rtl language layout, although not
22327			 * all browsers move the scrollbar (Safari).
22328			 *  @type boolean
22329			 *  @default false
22330			 */
22331			"bScrollbarLeft": false,
22332	
22333			/**
22334			 * Flag for if `getBoundingClientRect` is fully supported or not
22335			 *  @type boolean
22336			 *  @default false
22337			 */
22338			"bBounding": false,
22339	
22340			/**
22341			 * Browser scrollbar width
22342			 *  @type integer
22343			 *  @default 0
22344			 */
22345			"barWidth": 0
22346		},
22347	
22348	
22349		"ajax": null,
22350	
22351	
22352		/**
22353		 * Array referencing the nodes which are used for the features. The
22354		 * parameters of this object match what is allowed by sDom - i.e.
22355		 *   <ul>
22356		 *     <li>'l' - Length changing</li>
22357		 *     <li>'f' - Filtering input</li>
22358		 *     <li>'t' - The table!</li>
22359		 *     <li>'i' - Information</li>
22360		 *     <li>'p' - Pagination</li>
22361		 *     <li>'r' - pRocessing</li>
22362		 *   </ul>
22363		 *  @type array
22364		 *  @default []
22365		 */
22366		"aanFeatures": [],
22367	
22368		/**
22369		 * Store data information - see {@link DataTable.models.oRow} for detailed
22370		 * information.
22371		 *  @type array
22372		 *  @default []
22373		 */
22374		"aoData": [],
22375	
22376		/**
22377		 * Array of indexes which are in the current display (after filtering etc)
22378		 *  @type array
22379		 *  @default []
22380		 */
22381		"aiDisplay": [],
22382	
22383		/**
22384		 * Array of indexes for display - no filtering
22385		 *  @type array
22386		 *  @default []
22387		 */
22388		"aiDisplayMaster": [],
22389	
22390		/**
22391		 * Map of row ids to data indexes
22392		 *  @type object
22393		 *  @default {}
22394		 */
22395		"aIds": {},
22396	
22397		/**
22398		 * Store information about each column that is in use
22399		 *  @type array
22400		 *  @default []
22401		 */
22402		"aoColumns": [],
22403	
22404		/**
22405		 * Store information about the table's header
22406		 *  @type array
22407		 *  @default []
22408		 */
22409		"aoHeader": [],
22410	
22411		/**
22412		 * Store information about the table's footer
22413		 *  @type array
22414		 *  @default []
22415		 */
22416		"aoFooter": [],
22417	
22418		/**
22419		 * Store the applied global search information in case we want to force a
22420		 * research or compare the old search to a new one.
22421		 * Note that this parameter will be set by the initialisation routine. To
22422		 * set a default use {@link DataTable.defaults}.
22423		 *  @namespace
22424		 *  @extends DataTable.models.oSearch
22425		 */
22426		"oPreviousSearch": {},
22427	
22428		/**
22429		 * Store the applied search for each column - see
22430		 * {@link DataTable.models.oSearch} for the format that is used for the
22431		 * filtering information for each column.
22432		 *  @type array
22433		 *  @default []
22434		 */
22435		"aoPreSearchCols": [],
22436	
22437		/**
22438		 * Sorting that is applied to the table. Note that the inner arrays are
22439		 * used in the following manner:
22440		 * <ul>
22441		 *   <li>Index 0 - column number</li>
22442		 *   <li>Index 1 - current sorting direction</li>
22443		 * </ul>
22444		 * Note that this parameter will be set by the initialisation routine. To
22445		 * set a default use {@link DataTable.defaults}.
22446		 *  @type array
22447		 *  @todo These inner arrays should really be objects
22448		 */
22449		"aaSorting": null,
22450	
22451		/**
22452		 * Sorting that is always applied to the table (i.e. prefixed in front of
22453		 * aaSorting).
22454		 * Note that this parameter will be set by the initialisation routine. To
22455		 * set a default use {@link DataTable.defaults}.
22456		 *  @type array
22457		 *  @default []
22458		 */
22459		"aaSortingFixed": [],
22460	
22461		/**
22462		 * Classes to use for the striping of a table.
22463		 * Note that this parameter will be set by the initialisation routine. To
22464		 * set a default use {@link DataTable.defaults}.
22465		 *  @type array
22466		 *  @default []
22467		 */
22468		"asStripeClasses": null,
22469	
22470		/**
22471		 * If restoring a table - we should restore its striping classes as well
22472		 *  @type array
22473		 *  @default []
22474		 */
22475		"asDestroyStripes": [],
22476	
22477		/**
22478		 * If restoring a table - we should restore its width
22479		 *  @type int
22480		 *  @default 0
22481		 */
22482		"sDestroyWidth": 0,
22483	
22484		/**
22485		 * Callback functions array for every time a row is inserted (i.e. on a draw).
22486		 *  @type array
22487		 *  @default []
22488		 */
22489		"aoRowCallback": [],
22490	
22491		/**
22492		 * Callback functions for the header on each draw.
22493		 *  @type array
22494		 *  @default []
22495		 */
22496		"aoHeaderCallback": [],
22497	
22498		/**
22499		 * Callback function for the footer on each draw.
22500		 *  @type array
22501		 *  @default []
22502		 */
22503		"aoFooterCallback": [],
22504	
22505		/**
22506		 * Array of callback functions for draw callback functions
22507		 *  @type array
22508		 *  @default []
22509		 */
22510		"aoDrawCallback": [],
22511	
22512		/**
22513		 * Array of callback functions for row created function
22514		 *  @type array
22515		 *  @default []
22516		 */
22517		"aoRowCreatedCallback": [],
22518	
22519		/**
22520		 * Callback functions for just before the table is redrawn. A return of
22521		 * false will be used to cancel the draw.
22522		 *  @type array
22523		 *  @default []
22524		 */
22525		"aoPreDrawCallback": [],
22526	
22527		/**
22528		 * Callback functions for when the table has been initialised.
22529		 *  @type array
22530		 *  @default []
22531		 */
22532		"aoInitComplete": [],
22533	
22534	
22535		/**
22536		 * Callbacks for modifying the settings to be stored for state saving, prior to
22537		 * saving state.
22538		 *  @type array
22539		 *  @default []
22540		 */
22541		"aoStateSaveParams": [],
22542	
22543		/**
22544		 * Callbacks for modifying the settings that have been stored for state saving
22545		 * prior to using the stored values to restore the state.
22546		 *  @type array
22547		 *  @default []
22548		 */
22549		"aoStateLoadParams": [],
22550	
22551		/**
22552		 * Callbacks for operating on the settings object once the saved state has been
22553		 * loaded
22554		 *  @type array
22555		 *  @default []
22556		 */
22557		"aoStateLoaded": [],
22558	
22559		/**
22560		 * Cache the table ID for quick access
22561		 *  @type string
22562		 *  @default <i>Empty string</i>
22563		 */
22564		"sTableId": "",
22565	
22566		/**
22567		 * The TABLE node for the main table
22568		 *  @type node
22569		 *  @default null
22570		 */
22571		"nTable": null,
22572	
22573		/**
22574		 * Permanent ref to the thead element
22575		 *  @type node
22576		 *  @default null
22577		 */
22578		"nTHead": null,
22579	
22580		/**
22581		 * Permanent ref to the tfoot element - if it exists
22582		 *  @type node
22583		 *  @default null
22584		 */
22585		"nTFoot": null,
22586	
22587		/**
22588		 * Permanent ref to the tbody element
22589		 *  @type node
22590		 *  @default null
22591		 */
22592		"nTBody": null,
22593	
22594		/**
22595		 * Cache the wrapper node (contains all DataTables controlled elements)
22596		 *  @type node
22597		 *  @default null
22598		 */
22599		"nTableWrapper": null,
22600	
22601		/**
22602		 * Indicate if when using server-side processing the loading of data
22603		 * should be deferred until the second draw.
22604		 * Note that this parameter will be set by the initialisation routine. To
22605		 * set a default use {@link DataTable.defaults}.
22606		 *  @type boolean
22607		 *  @default false
22608		 */
22609		"bDeferLoading": false,
22610	
22611		/**
22612		 * Indicate if all required information has been read in
22613		 *  @type boolean
22614		 *  @default false
22615		 */
22616		"bInitialised": false,
22617	
22618		/**
22619		 * Information about open rows. Each object in the array has the parameters
22620		 * 'nTr' and 'nParent'
22621		 *  @type array
22622		 *  @default []
22623		 */
22624		"aoOpenRows": [],
22625	
22626		/**
22627		 * Dictate the positioning of DataTables' control elements - see
22628		 * {@link DataTable.model.oInit.sDom}.
22629		 * Note that this parameter will be set by the initialisation routine. To
22630		 * set a default use {@link DataTable.defaults}.
22631		 *  @type string
22632		 *  @default null
22633		 */
22634		"sDom": null,
22635	
22636		/**
22637		 * Search delay (in mS)
22638		 *  @type integer
22639		 *  @default null
22640		 */
22641		"searchDelay": null,
22642	
22643		/**
22644		 * Which type of pagination should be used.
22645		 * Note that this parameter will be set by the initialisation routine. To
22646		 * set a default use {@link DataTable.defaults}.
22647		 *  @type string
22648		 *  @default two_button
22649		 */
22650		"sPaginationType": "two_button",
22651	
22652		/**
22653		 * The state duration (for `stateSave`) in seconds.
22654		 * Note that this parameter will be set by the initialisation routine. To
22655		 * set a default use {@link DataTable.defaults}.
22656		 *  @type int
22657		 *  @default 0
22658		 */
22659		"iStateDuration": 0,
22660	
22661		/**
22662		 * Array of callback functions for state saving. Each array element is an
22663		 * object with the following parameters:
22664		 *   <ul>
22665		 *     <li>function:fn - function to call. Takes two parameters, oSettings
22666		 *       and the JSON string to save that has been thus far created. Returns
22667		 *       a JSON string to be inserted into a json object
22668		 *       (i.e. '"param": [ 0, 1, 2]')</li>
22669		 *     <li>string:sName - name of callback</li>
22670		 *   </ul>
22671		 *  @type array
22672		 *  @default []
22673		 */
22674		"aoStateSave": [],
22675	
22676		/**
22677		 * Array of callback functions for state loading. Each array element is an
22678		 * object with the following parameters:
22679		 *   <ul>
22680		 *     <li>function:fn - function to call. Takes two parameters, oSettings
22681		 *       and the object stored. May return false to cancel state loading</li>
22682		 *     <li>string:sName - name of callback</li>
22683		 *   </ul>
22684		 *  @type array
22685		 *  @default []
22686		 */
22687		"aoStateLoad": [],
22688	
22689		/**
22690		 * State that was saved. Useful for back reference
22691		 *  @type object
22692		 *  @default null
22693		 */
22694		"oSavedState": null,
22695	
22696		/**
22697		 * State that was loaded. Useful for back reference
22698		 *  @type object
22699		 *  @default null
22700		 */
22701		"oLoadedState": null,
22702	
22703		/**
22704		 * Source url for AJAX data for the table.
22705		 * Note that this parameter will be set by the initialisation routine. To
22706		 * set a default use {@link DataTable.defaults}.
22707		 *  @type string
22708		 *  @default null
22709		 */
22710		"sAjaxSource": null,
22711	
22712		/**
22713		 * Property from a given object from which to read the table data from. This
22714		 * can be an empty string (when not server-side processing), in which case
22715		 * it is  assumed an an array is given directly.
22716		 * Note that this parameter will be set by the initialisation routine. To
22717		 * set a default use {@link DataTable.defaults}.
22718		 *  @type string
22719		 */
22720		"sAjaxDataProp": null,
22721	
22722		/**
22723		 * 
22723Note if draw should be blocked while getting data
22724		 *  @type boolean
22725		 *  @default true
22726		 */
22727		"bAjaxDataGet": true,
22728	
22729		/**
22730		 * The last jQuery XHR object that was used for server-side data gathering.
22731		 * This can be used for working with the XHR information in one of the
22732		 * callbacks
22733		 *  @type object
22734		 *  @default null
22735		 */
22736		"jqXHR": null,
22737	
22738		/**
22739		 * JSON returned from the server in the last Ajax request
22740		 *  @type object
22741		 *  @default undefined
22742		 */
22743		"json": undefined,
22744	
22745		/**
22746		 * Data submitted as part of the last Ajax request
22747		 *  @type object
22748		 *  @default undefined
22749		 */
22750		"oAjaxData": undefined,
22751	
22752		/**
22753		 * Function to get the server-side data.
22754		 * Note that this parameter will be set by the initialisation routine. To
22755		 * set a default use {@link DataTable.defaults}.
22756		 *  @type function
22757		 */
22758		"fnServerData": null,
22759	
22760		/**
22761		 * Functions which are called prior to sending an Ajax request so extra
22762		 * parameters can easily be sent to the server
22763		 *  @type array
22764		 *  @default []
22765		 */
22766		"aoServerParams": [],
22767	
22768		/**
22769		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
22770		 * required).
22771		 * Note that this parameter will be set by the initialisation routine. To
22772		 * set a default use {@link DataTable.defaults}.
22773		 *  @type string
22774		 */
22775		"sServerMethod": null,
22776	
22777		/**
22778		 * Format numbers for display.
22779		 * Note that this parameter will be set by the initialisation routine. To
22780		 * set a default use {@link DataTable.defaults}.
22781		 *  @type function
22782		 */
22783		"fnFormatNumber": null,
22784	
22785		/**
22786		 * List of options that can be used for the user selectable length menu.
22787		 * Note that this parameter will be set by the initialisation routine. To
22788		 * set a default use {@link DataTable.defaults}.
22789		 *  @type array
22790		 *  @default []
22791		 */
22792		"aLengthMenu": null,
22793	
22794		/**
22795		 * Counter for the draws that the table does. Also used as a tracker for
22796		 * server-side processing
22797		 *  @type int
22798		 *  @default 0
22799		 */
22800		"iDraw": 0,
22801	
22802		/**
22803		 * Indicate if a redraw is being done - useful for Ajax
22804		 *  @type boolean
22805		 *  @default false
22806		 */
22807		"bDrawing": false,
22808	
22809		/**
22810		 * Draw index (iDraw) of the last error when parsing the returned data
22811		 *  @type int
22812		 *  @default -1
22813		 */
22814		"iDrawError": -1,
22815	
22816		/**
22817		 * Paging display length
22818		 *  @type int
22819		 *  @default 10
22820		 */
22821		"_iDisplayLength": 10,
22822	
22823		/**
22824		 * Paging start point - aiDisplay index
22825		 *  @type int
22826		 *  @default 0
22827		 */
22828		"_iDisplayStart": 0,
22829	
22830		/**
22831		 * Server-side processing - number of records in the result set
22832		 * (i.e. before filtering), Use fnRecordsTotal rather than
22833		 * this property to get the value of the number of records, regardless of
22834		 * the server-side processing setting.
22835		 *  @type int
22836		 *  @default 0
22837		 *  @private
22838		 */
22839		"_iRecordsTotal": 0,
22840	
22841		/**
22842		 * Server-side processing - number of records in the current display set
22843		 * (i.e. after filtering). Use fnRecordsDisplay rather than
22844		 * this property to get the value of the number of records, regardless of
22845		 * the server-side processing setting.
22846		 *  @type boolean
22847		 *  @default 0
22848		 *  @private
22849		 */
22850		"_iRecordsDisplay": 0,
22851	
22852		/**
22853		 * The classes to use for the table
22854		 *  @type object
22855		 *  @default {}
22856		 */
vendor: 4,924 bytes, lines 22857-23065
22857		"oClasses": {},
22858	
22859		/**
22860		 * Flag attached to the settings object so you can check in the draw
22861		 * callback if filtering has been done in the draw. Deprecated in favour of
22862		 * events.
22863		 *  @type boolean
22864		 *  @default false
22865		 *  @deprecated
22866		 */
22867		"bFiltered": false,
22868	
22869		/**
22870		 * Flag attached to the settings object so you can check in the draw
22871		 * callback if sorting has been done in the draw. Deprecated in favour of
22872		 * events.
22873		 *  @type boolean
22874		 *  @default false
22875		 *  @deprecated
22876		 */
22877		"bSorted": false,
22878	
22879		/**
22880		 * Indicate that if multiple rows are in the header and there is more than
22881		 * one unique cell per column, if the top one (true) or bottom one (false)
22882		 * should be used for sorting / title by DataTables.
22883		 * Note that this parameter will be set by the initialisation routine. To
22884		 * set a default use {@link DataTable.defaults}.
22885		 *  @type boolean
22886		 */
22887		"bSortCellsTop": null,
22888	
22889		/**
22890		 * Initialisation object that is used for the table
22891		 *  @type object
22892		 *  @default null
22893		 */
22894		"oInit": null,
22895	
22896		/**
22897		 * Destroy callback functions - for plug-ins to attach themselves to the
22898		 * destroy so they can clean up markup and events.
22899		 *  @type array
22900		 *  @default []
22901		 */
22902		"aoDestroyCallback": [],
22903	
22904	
22905		/**
22906		 * Get the number of records in the current record set, before filtering
22907		 *  @type function
22908		 */
22909		"fnRecordsTotal": function ()
22910		{
22911			return _fnDataSource( this ) == 'ssp' ?
22912				this._iRecordsTotal * 1 :
22913				this.aiDisplayMaster.length;
22914		},
22915	
22916		/**
22917		 * Get the number of records in the current record set, after filtering
22918		 *  @type function
22919		 */
22920		"fnRecordsDisplay": function ()
22921		{
22922			return _fnDataSource( this ) == 'ssp' ?
22923				this._iRecordsDisplay * 1 :
22924				this.aiDisplay.length;
22925		},
22926	
22927		/**
22928		 * Get the display end point - aiDisplay index
22929		 *  @type function
22930		 */
22931		"fnDisplayEnd": function ()
22932		{
22933			var
22934				len      = this._iDisplayLength,
22935				start    = this._iDisplayStart,
22936				calc     = start + len,
22937				records  = this.aiDisplay.length,
22938				features = this.oFeatures,
22939				paginate = features.bPaginate;
22940	
22941			if ( features.bServerSide ) {
22942				return paginate === false || len === -1 ?
22943					start + records :
22944					Math.min( start+len, this._iRecordsDisplay );
22945			}
22946			else {
22947				return ! paginate || calc>records || len===-1 ?
22948					records :
22949					calc;
22950			}
22951		},
22952	
22953		/**
22954		 * The DataTables object for this table
22955		 *  @type object
22956		 *  @default null
22957		 */
22958		"oInstance": null,
22959	
22960		/**
22961		 * Unique identifier for each instance of the DataTables object. If there
22962		 * is an ID on the table node, then it takes that value, otherwise an
22963		 * incrementing internal counter is used.
22964		 *  @type string
22965		 *  @default null
22966		 */
22967		"sInstance": null,
22968	
22969		/**
22970		 * tabindex attribute value that is added to DataTables control elements, allowing
22971		 * keyboard navigation of the table and its controls.
22972		 */
22973		"iTabIndex": 0,
22974	
22975		/**
22976		 * DIV container for the footer scrolling table if scrolling
22977		 */
22978		"nScrollHead": null,
22979	
22980		/**
22981		 * DIV container for the footer scrolling table if scrolling
22982		 */
22983		"nScrollFoot": null,
22984	
22985		/**
22986		 * Last applied sort
22987		 *  @type array
22988		 *  @default []
22989		 */
22990		"aLastSort": [],
22991	
22992		/**
22993		 * Stored plug-in instances
22994		 *  @type object
22995		 *  @default {}
22996		 */
22997		"oPlugins": {},
22998	
22999		/**
23000		 * Function used to get a row's id from the row's data
23001		 *  @type function
23002		 *  @default null
23003		 */
23004		"rowIdFn": null,
23005	
23006		/**
23007		 * Data location where to store a row's id
23008		 *  @type string
23009		 *  @default null
23010		 */
23011		"rowId": null
23012	};
23013
23014	/**
23015	 * Extension object for DataTables that is used to provide all extension
23016	 * options.
23017	 *
23018	 * Note that the `DataTable.ext` object is available through
23019	 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
23020	 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
23021	 *  @namespace
23022	 *  @extends DataTable.models.ext
23023	 */
23024	
23025	
23026	/**
23027	 * DataTables extensions
23028	 * 
23029	 * This namespace acts as a collection area for plug-ins that can be used to
23030	 * extend DataTables capabilities. Indeed many of the build in methods
23031	 * use this method to provide their own capabilities (sorting methods for
23032	 * example).
23033	 *
23034	 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
23035	 * reasons
23036	 *
23037	 *  @namespace
23038	 */
23039	DataTable.ext = _ext = {
23040		/**
23041		 * Buttons. For use with the Buttons extension for DataTables. This is
23042		 * defined here so other extensions can define buttons regardless of load
23043		 * order. It is _not_ used by DataTables core.
23044		 *
23045		 *  @type object
23046		 *  @default {}
23047		 */
23048		buttons: {},
23049	
23050	
23051		/**
23052		 * Element class names
23053		 *
23054		 *  @type object
23055		 *  @default {}
23056		 */
23057		classes: {},
23058	
23059	
23060		/**
23061		 * DataTables build type (expanded by the download builder)
23062		 *
23063		 *  @type string
23064		 */
23065		build:"bs/jszip-2.5.0/dt-1.10.18/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/cr-1.5.0/fh-3.1.4/r-2.2.2/rg-1.1.0/sc-1.5.0/sl-1.2.6
vendor: 15,138 bytes, lines 23065-23511
23065",
23066	
23067	
23068		/**
23069		 * Error reporting.
23070		 * 
23071		 * How should DataTables report an error. Can take the value 'alert',
23072		 * 'throw', 'none' or a function.
23073		 *
23074		 *  @type string|function
23075		 *  @default alert
23076		 */
23077		errMode: "alert",
23078	
23079	
23080		/**
23081		 * Feature plug-ins.
23082		 * 
23083		 * This is an array of objects which describe the feature plug-ins that are
23084		 * available to DataTables. These feature plug-ins are then available for
23085		 * use through the `dom` initialisation option.
23086		 * 
23087		 * Each feature plug-in is described by an object which must have the
23088		 * following properties:
23089		 * 
23090		 * * `fnInit` - function that is used to initialise the plug-in,
23091		 * * `cFeature` - a character so the feature can be enabled by the `dom`
23092		 *   instillation option. This is case sensitive.
23093		 *
23094		 * The `fnInit` function has the following input parameters:
23095		 *
23096		 * 1. `{object}` DataTables settings object: see
23097		 *    {@link DataTable.models.oSettings}
23098		 *
23099		 * And the following return is expected:
23100		 * 
23101		 * * {node|null} The element which contains your feature. Note that the
23102		 *   return may also be void if your plug-in does not require to inject any
23103		 *   DOM elements into DataTables control (`dom`) - for example this might
23104		 *   be useful when developing a plug-in which allows table control via
23105		 *   keyboard entry
23106		 *
23107		 *  @type array
23108		 *
23109		 *  @example
23110		 *    $.fn.dataTable.ext.features.push( {
23111		 *      "fnInit": function( oSettings ) {
23112		 *        return new TableTools( { "oDTSettings": oSettings } );
23113		 *      },
23114		 *      "cFeature": "T"
23115		 *    } );
23116		 */
23117		feature: [],
23118	
23119	
23120		/**
23121		 * Row searching.
23122		 * 
23123		 * This method of searching is complimentary to the default type based
23124		 * searching, and a lot more comprehensive as it allows you complete control
23125		 * over the searching logic. Each element in this array is a function
23126		 * (parameters described below) that is called for every row in the table,
23127		 * and your logic decides if it should be included in the searching data set
23128		 * or not.
23129		 *
23130		 * Searching functions have the following input parameters:
23131		 *
23132		 * 1. `{object}` DataTables settings object: see
23133		 *    {@link DataTable.models.oSettings}
23134		 * 2. `{array|object}` Data for the row to be processed (same as the
23135		 *    original format that was passed in as the data source, or an array
23136		 *    from a DOM data source
23137		 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
23138		 *    can be useful to retrieve the `TR` element if you need DOM interaction.
23139		 *
23140		 * And the following return is expected:
23141		 *
23142		 * * {boolean} Include the row in the searched result set (true) or not
23143		 *   (false)
23144		 *
23145		 * Note that as with the main search ability in DataTables, technically this
23146		 * is "filtering", since it is subtractive. However, for consistency in
23147		 * naming we call it searching here.
23148		 *
23149		 *  @type array
23150		 *  @default []
23151		 *
23152		 *  @example
23153		 *    // The following example shows custom search being applied to the
23154		 *    // fourth column (i.e. the data[3] index) based on two input values
23155		 *    // from the end-user, matching the data in a certain range.
23156		 *    $.fn.dataTable.ext.search.push(
23157		 *      function( settings, data, dataIndex ) {
23158		 *        var min = document.getElementById('min').value * 1;
23159		 *        var max = document.getElementById('max').value * 1;
23160		 *        var version = data[3] == "-" ? 0 : data[3]*1;
23161		 *
23162		 *        if ( min == "" && max == "" ) {
23163		 *          return true;
23164		 *        }
23165		 *        else if ( min == "" && version < max ) {
23166		 *          return true;
23167		 *        }
23168		 *        else if ( min < version && "" == max ) {
23169		 *          return true;
23170		 *        }
23171		 *        else if ( min < version && version < max ) {
23172		 *          return true;
23173		 *        }
23174		 *        return false;
23175		 *      }
23176		 *    );
23177		 */
23178		search: [],
23179	
23180	
23181		/**
23182		 * Selector extensions
23183		 *
23184		 * The `selector` option can be used to extend the options available for the
23185		 * selector modifier options (`selector-modifier` object data type) that
23186		 * each of the three built in selector types offer (row, column and cell +
23187		 * their plural counterparts). For example the Select extension uses this
23188		 * mechanism to provide an option to select only rows, columns and cells
23189		 * that have been marked as selected by the end user (`{selected: true}`),
23190		 * which can be used in conjunction with the existing built in selector
23191		 * options.
23192		 *
23193		 * Each property is an array to which functions can be pushed. The functions
23194		 * take three attributes:
23195		 *
23196		 * * Settings object for the host table
23197		 * * Options object (`selector-modifier` object type)
23198		 * * Array of selected item indexes
23199		 *
23200		 * The return is an array of the resulting item indexes after the custom
23201		 * selector has been applied.
23202		 *
23203		 *  @type object
23204		 */
23205		selector: {
23206			cell: [],
23207			column: [],
23208			row: []
23209		},
23210	
23211	
23212		/**
23213		 * Internal functions, exposed for used in plug-ins.
23214		 * 
23215		 * Please note that you should not need to use the internal methods for
23216		 * anything other than a plug-in (and even then, try to avoid if possible).
23217		 * The internal function may change between releases.
23218		 *
23219		 *  @type object
23220		 *  @default {}
23221		 */
23222		internal: {},
23223	
23224	
23225		/**
23226		 * Legacy configuration options. Enable and disable legacy options that
23227		 * are available in DataTables.
23228		 *
23229		 *  @type object
23230		 */
23231		legacy: {
23232			/**
23233			 * Enable / disable DataTables 1.9 compatible server-side processing
23234			 * requests
23235			 *
23236			 *  @type boolean
23237			 *  @default null
23238			 */
23239			ajax: null
23240		},
23241	
23242	
23243		/**
23244		 * Pagination plug-in methods.
23245		 * 
23246		 * Each entry in this object is a function and defines which buttons should
23247		 * be shown by the pagination rendering method that is used for the table:
23248		 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
23249		 * buttons are displayed in the document, while the functions here tell it
23250		 * what buttons to display. This is done by returning an array of button
23251		 * descriptions (what each button will do).
23252		 *
23253		 * Pagination types (the four built in options and any additional plug-in
23254		 * options defined here) can be used through the `paginationType`
23255		 * initialisation parameter.
23256		 *
23257		 * The functions defined take two parameters:
23258		 *
23259		 * 1. `{int} page` The current page index
23260		 * 2. `{int} pages` The number of pages in the table
23261		 *
23262		 * Each function is expected to return an array where each element of the
23263		 * array can be one of:
23264		 *
23265		 * * `first` - Jump to first page when activated
23266		 * * `last` - Jump to last page when activated
23267		 * * `previous` - Show previous page when activated
23268		 * * `next` - Show next page when activated
23269		 * * `{int}` - Show page of the index given
23270		 * * `{array}` - A nested array containing the above elements to add a
23271		 *   containing 'DIV' element (might be useful for styling).
23272		 *
23273		 * Note that DataTables v1.9- used this object slightly differently whereby
23274		 * an object with two functions would be defined for each plug-in. That
23275		 * ability is still supported by DataTables 1.10+ to provide backwards
23276		 * compatibility, but this option of use is now decremented and no longer
23277		 * documented in DataTables 1.10+.
23278		 *
23279		 *  @type object
23280		 *  @default {}
23281		 *
23282		 *  @example
23283		 *    // Show previous, next and current page buttons only
23284		 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
23285		 *      return [ 'previous', page, 'next' ];
23286		 *    };
23287		 */
23288		pager: {},
23289	
23290	
23291		renderer: {
23292			pageButton: {},
23293			header: {}
23294		},
23295	
23296	
23297		/**
23298		 * Ordering plug-ins - custom data source
23299		 * 
23300		 * The extension options for ordering of data available here is complimentary
23301		 * to the default type based ordering that DataTables typically uses. It
23302		 * allows much greater control over the the data that is being used to
23303		 * order a column, but is necessarily therefore more complex.
23304		 * 
23305		 * This type of ordering is useful if you want to do ordering based on data
23306		 * live from the DOM (for example the contents of an 'input' element) rather
23307		 * than just the static string that DataTables knows of.
23308		 * 
23309		 * The way these plug-ins work is that you create an array of the values you
23310		 * wish to be ordering for the column in question and then return that
23311		 * array. The data in the array much be in the index order of the rows in
23312		 * the table (not the currently ordering order!). Which order data gathering
23313		 * function is run here depends on the `dt-init columns.orderDataType`
23314		 * parameter that is used for the column (if any).
23315		 *
23316		 * The functions defined take two parameters:
23317		 *
23318		 * 1. `{object}` DataTables settings object: see
23319		 *    {@link DataTable.models.oSettings}
23320		 * 2. `{int}` Target column index
23321		 *
23322		 * Each function is expected to return an array:
23323		 *
23324		 * * `{array}` Data for the column to be ordering upon
23325		 *
23326		 *  @type array
23327		 *
23328		 *  @example
23329		 *    // Ordering using `input` node values
23330		 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
23331		 *    {
23332		 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
23333		 *        return $('input', td).val();
23334		 *      } );
23335		 *    }
23336		 */
23337		order: {},
23338	
23339	
23340		/**
23341		 * Type based plug-ins.
23342		 *
23343		 * Each column in DataTables has a type assigned to it, either by automatic
23344		 * detection or by direct assignment using the `type` option for the column.
23345		 * The type of a column will effect how it is ordering and search (plug-ins
23346		 * can also make use of the column type if required).
23347		 *
23348		 * @namespace
23349		 */
23350		type: {
23351			/**
23352			 * Type detection functions.
23353			 *
23354			 * The functions defined in this object are used to automatically detect
23355			 * a column's type, making initialisation of DataTables super easy, even
23356			 * when complex data is in the table.
23357			 *
23358			 * The functions defined take two parameters:
23359			 *
23360		     *  1. `{*}` Data from the column cell to be analysed
23361		     *  2. `{settings}` DataTables settings object. This can be used to
23362		     *     perform context specific type detection - for example detection
23363		     *     based on language settings such as using a comma for a decimal
23364		     *     place. Generally speaking the options from the settings will not
23365		     *     be required
23366			 *
23367			 * Each function is expected to return:
23368			 *
23369			 * * `{string|null}` Data type detected, or null if unknown (and thus
23370			 *   pass it on to the other type detection functions.
23371			 *
23372			 *  @type array
23373			 *
23374			 *  @example
23375			 *    // Currency type detection plug-in:
23376			 *    $.fn.dataTable.ext.type.detect.push(
23377			 *      function ( data, settings ) {
23378			 *        // Check the numeric part
23379			 *        if ( ! data.substring(1).match(/[0-9]/) ) {
23380			 *          return null;
23381			 *        }
23382			 *
23383			 *        // Check prefixed by currency
23384			 *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
23385			 *          return 'currency';
23386			 *        }
23387			 *        return null;
23388			 *      }
23389			 *    );
23390			 */
23391			detect: [],
23392	
23393	
23394			/**
23395			 * Type based search formatting.
23396			 *
23397			 * The type based searching functions can be used to pre-format the
23398			 * data to be search on. For example, it can be used to strip HTML
23399			 * tags or to de-format telephone numbers for numeric only searching.
23400			 *
23401			 * Note that is a search is not defined for a column of a given type,
23402			 * no search formatting will be performed.
23403			 * 
23404			 * Pre-processing of searching data plug-ins - When you assign the sType
23405			 * for a column (or have it automatically detected for you by DataTables
23406			 * or a type detection plug-in), you will typically be using this for
23407			 * custom sorting, but it can also be used to provide custom searching
23408			 * by allowing you to pre-processing the data and returning the data in
23409			 * the format that should be searched upon. This is done by adding
23410			 * functions this object with a parameter name which matches the sType
23411			 * for that target column. This is the corollary of <i>afnSortData</i>
23412			 * for searching data.
23413			 *
23414			 * The functions defined take a single parameter:
23415			 *
23416		     *  1. `{*}` Data from the column cell to be prepared for searching
23417			 *
23418			 * Each function is expected to return:
23419			 *
23420			 * * `{string|null}` Formatted string that will be used for the searching.
23421			 *
23422			 *  @type object
23423			 *  @default {}
23424			 *
23425			 *  @example
23426			 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
23427			 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
23428			 *    }
23429			 */
23430			search: {},
23431	
23432	
23433			/**
23434			 * Type based ordering.
23435			 *
23436			 * The column type tells DataTables what ordering to apply to the table
23437			 * when a column is sorted upon. The order for each type that is defined,
23438			 * is defined by the functions available in this object.
23439			 *
23440			 * Each ordering option can be described by three properties added to
23441			 * this object:
23442			 *
23443			 * * `{type}-pre` - Pre-formatting function
23444			 * * `{type}-asc` - Ascending order function
23445			 * * `{type}-desc` - Descending order function
23446			 *
23447			 * All three can be used together, only `{type}-pre` or only
23448			 * `{type}-asc` and `{type}-desc` together. It is generally recommended
23449			 * that only `{type}-pre` is used, as this provides the optimal
23450			 * implementation in terms of speed, although the others are provided
23451			 * for compatibility with existing Javascript sort functions.
23452			 *
23453			 * `{type}-pre`: Functions defined take a single parameter:
23454			 *
23455		     *  1. `{*}` Data from the column cell to be prepared for ordering
23456			 *
23457			 * And return:
23458			 *
23459			 * * `{*}` Data to be sorted upon
23460			 *
23461			 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
23462			 * functions, taking two parameters:
23463			 *
23464		     *  1. `{*}` Data to compare to the second parameter
23465		     *  2. `{*}` Data to compare to the first parameter
23466			 *
23467			 * And returning:
23468			 *
23469			 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
23470			 *   than the second parameter, ===0 if the two parameters are equal and
23471			 *   >0 if the first parameter should be sorted height than the second
23472			 *   parameter.
23473			 * 
23474			 *  @type object
23475			 *  @default {}
23476			 *
23477			 *  @example
23478			 *    // Numeric ordering of formatted numbers with a pre-formatter
23479			 *    $.extend( $.fn.dataTable.ext.type.order, {
23480			 *      "string-pre": function(x) {
23481			 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
23482			 *        return parseFloat( a );
23483			 *      }
23484			 *    } );
23485			 *
23486			 *  @example
23487			 *    // Case-sensitive string ordering, with no pre-formatting method
23488			 *    $.extend( $.fn.dataTable.ext.order, {
23489			 *      "string-case-asc": function(x,y) {
23490			 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
23491			 *      },
23492			 *      "string-case-desc": function(x,y) {
23493			 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
23494			 *      }
23495			 *    } );
23496			 */
23497			order: {}
23498		},
23499	
23500		/**
23501		 * Unique DataTables instance counter
23502		 *
23503		 * @type int
23504		 * @private
23505		 */
23506		_unique: 0,
23507	
23508	
23509		//
23510		// Depreciated
23511		// The following properties are retained for backwards compatib
vendor: 3,168 bytes, lines 23511-23648
23511lity only.
23512		// The should not be used in new projects and will be removed in a future
23513		// version
23514		//
23515	
23516		/**
23517		 * Version check function.
23518		 *  @type function
23519		 *  @depreciated Since 1.10
23520		 */
23521		fnVersionCheck: DataTable.fnVersionCheck,
23522	
23523	
23524		/**
23525		 * Index for what 'this' index API functions should use
23526		 *  @type int
23527		 *  @deprecated Since v1.10
23528		 */
23529		iApiIndex: 0,
23530	
23531	
23532		/**
23533		 * jQuery UI class container
23534		 *  @type object
23535		 *  @deprecated Since v1.10
23536		 */
23537		oJUIClasses: {},
23538	
23539	
23540		/**
23541		 * Software version
23542		 *  @type string
23543		 *  @deprecated Since v1.10
23544		 */
23545		sVersion: DataTable.version
23546	};
23547	
23548	
23549	//
23550	// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
23551	//
23552	$.extend( _ext, {
23553		afnFiltering: _ext.search,
23554		aTypes:       _ext.type.detect,
23555		ofnSearch:    _ext.type.search,
23556		oSort:        _ext.type.order,
23557		afnSortData:  _ext.order,
23558		aoFeatures:   _ext.feature,
23559		oApi:         _ext.internal,
23560		oStdClasses:  _ext.classes,
23561		oPagination:  _ext.pager
23562	} );
23563	
23564	
23565	$.extend( DataTable.ext.classes, {
23566		"sTable": "dataTable",
23567		"sNoFooter": "no-footer",
23568	
23569		/* Paging buttons */
23570		"sPageButton": "paginate_button",
23571		"sPageButtonActive": "current",
23572		"sPageButtonDisabled": "disabled",
23573	
23574		/* Striping classes */
23575		"sStripeOdd": "odd",
23576		"sStripeEven": "even",
23577	
23578		/* Empty row */
23579		"sRowEmpty": "dataTables_empty",
23580	
23581		/* Features */
23582		"sWrapper": "dataTables_wrapper",
23583		"sFilter": "dataTables_filter",
23584		"sInfo": "dataTables_info",
23585		"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
23586		"sLength": "dataTables_length",
23587		"sProcessing": "dataTables_processing",
23588	
23589		/* Sorting */
23590		"sSortAsc": "sorting_asc",
23591		"sSortDesc": "sorting_desc",
23592		"sSortable": "sorting", /* Sortable in both directions */
23593		"sSortableAsc": "sorting_asc_disabled",
23594		"sSortableDesc": "sorting_desc_disabled",
23595		"sSortableNone": "sorting_disabled",
23596		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
23597	
23598		/* Filtering */
23599		"sFilterInput": "",
23600	
23601		/* Page length */
23602		"sLengthSelect": "",
23603	
23604		/* Scrolling */
23605		"sScrollWrapper": "dataTables_scroll",
23606		"sScrollHead": "dataTables_scrollHead",
23607		"sScrollHeadInner": "dataTables_scrollHeadInner",
23608		"sScrollBody": "dataTables_scrollBody",
23609		"sScrollFoot": "dataTables_scrollFoot",
23610		"sScrollFootInner": "dataTables_scrollFootInner",
23611	
23612		/* Misc */
23613		"sHeaderTH": "",
23614		"sFooterTH": "",
23615	
23616		// Deprecated
23617		"sSortJUIAsc": "",
23618		"sSortJUIDesc": "",
23619		"sSortJUI": "",
23620		"sSortJUIAscAllowed": "",
23621		"sSortJUIDescAllowed": "",
23622		"sSortJUIWrapper": "",
23623		"sSortIcon": "",
23624		"sJUIHeader": "",
23625		"sJUIFooter": ""
23626	} );
23627	
23628	
23629	var extPagination = DataTable.ext.pager;
23630	
23631	function _numbers ( page, pages ) {
23632		var
23633			numbers = [],
23634			buttons = extPagination.numbers_length,
23635			half = Math.floor( buttons / 2 ),
23636			i = 1;
23637	
23638		if ( pages <= buttons ) {
23639			numbers = _range( 0, pages );
23640		}
23641		else if ( page <= half ) {
23642			numbers = _range( 0, buttons-2 );
23643			numbers.push( 'ellipsis' );
23644			numbers.push( pages-1 );
23645		}
23646		else if ( page >= pages - 1 - half ) {
23647			numbers = _range( pages-(buttons-2), pages );
23648			numbers.splice( 0, 0, 'ellipsis' );
23648 // no unshift in ie6
23649			numbers.splice( 0, 0, 0 );
23650		}
23651		else {
23652			numbers = _range( page-half+2, page+half-1 );
23653			numbers.push( 'ellipsis' );
23654			numbers.push( pages-1 );
23655			numbers.splice( 0, 0, 'ellipsis' );
23656			numbers.splice( 0, 0, 0 );
23657		}
23658	
23659		numbers.DT_el = 'span';
23660		return numbers;
23661	}
23662	
23663	
23664	$.extend( extPagination, {
23665		simple: function ( page, pages ) {
23666			return [ 'previous', 'next' ];
23667		},
23668	
23669		full: function ( page, pages ) {
23670			return [  'first', 'previous', 'next', 'last' ];
23671		},
23672	
23673		numbers: function ( page, pages ) {
23674			return [ _numbers(page, pages) ];
23675		},
23676	
23677		simple_numbers: function ( page, pages ) {
23678			return [ 'previous', _numbers(page, pages), 'next' ];
23679		},
23680	
23681		full_numbers: function ( page, pages ) {
23682			return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
23683		},
23684		
23685		first_last_numbers: function (page, pages) {
23686	 		return ['first', _numbers(page, pages), 'last'];
23687	 	},
23688	
23689		// For testing and plug-ins to use
23690		_numbers: _numbers,
23691	
23692		// Number of number buttons (including ellipsis) to show. _Must be odd!_
23693		numbers_length: 7
23694	} );
23695	
23696	
23697	$.extend( true, DataTable.ext.renderer, {
23698		pageButton: {
23699			_: function ( settings, host, idx, buttons, page, pages ) {
23700				var classes = settings.oClasses;
23701				var lang = settings.oLanguage.oPaginate;
23702				var aria = settings.oLanguage.oAria.paginate || {};
23703				var btnDisplay, btnClass, counter=0;
23704	
23705				var attach = function( container, buttons ) {
23706					var i, ien, node, button;
23707					var clickHandler = function ( e ) {
23708						_fnPageChange( settings, e.data.action, true );
23709					};
23710	
23711					for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
23712						button = buttons[i];
23713	
23714						if ( $.isArray( button ) ) {
23715							var inner = $( '<'+(button.DT_el || 'div')+'/>' )
23716								.appendTo( container );
23717							attach( inner, button );
23718						}
23719						else {
23720							btnDisplay = null;
23721							btnClass = '';
23722	
23723							switch ( button ) {
23724								case 'ellipsis':
23725									container.append('<span class="ellipsis">&#x2026;</span>');
23726									break;
23727	
23728								case 'first':
23729									btnDisplay = lang.sFirst;
23730									btnClass = button + (page > 0 ?
23731										'' : ' '+classes.sPageButtonDisabled);
23732									break;
23733	
23734								case 'previous':
23735									btnDisplay = lang.sPrevious;
23736									btnClass = button + (page > 0 ?
23737										'' : ' '+classes.sPageButtonDisabled);
23738									break;
23739	
23740								case 'next':
23741									btnDisplay = lang.sNext;
23742									btnClass = button + (page < pages-1 ?
23743										'' : ' '+classes.sPageButtonDisabled);
23744									break;
23745	
23746								case 'last':
23747									btnDisplay = lang.sLast;
23748									btnClass = button + (page < pages-1 ?
23749										'' : ' '+classes.sPageButtonDisabled);
23750									break;
23751	
23752								default:
23753									btnDisplay = button + 1;
23754									btnClass = page === button ?
23755										classes.sPageButtonActive : '';
23756									break;
23757							}
23758	
23759							if ( btnDisplay !== null ) {
23760								node = $('<a>', {
23761										'class': classes.sPageButton+' '+btnClass,
23762										'aria-controls': settings.sTableId,
23763										'aria-label': aria[ button ],
23764										'data-dt-idx': counter,
23765										'tabindex': settings.iTabIndex,
23766										'id': idx === 0 && typeof button === 'string' ?
23767											settings.sTableId +'_'+ button :
23768											null
23769									} )
23770									.html( btnDisplay )
23771									.appendTo( container );
23772	
23773								_fnBindAction(
23774									node, {action: button}, clickHandler
23775								);
23776	
23777								counter++;
23778							}
23779						}
23780					}
23781				};
23782	
23783				// IE9 throws an 'unknown error' if document.activeElement is used
23784				// inside an iframe or frame. Try / catch the error. Not good for
23785				// accessibility, but neither are frames.
23786				var activeEl;
23787	
23788				try {
23789					// Because this approach is destroying and recreating the paging
23790					// elements, focus is lost on the select button which is bad for
23791					// accessibility. So we want to restore focus once the draw has
23792					// completed
23793					activeEl = $(host).find(document.activeElement).data('dt-idx');
23794				}
23795				catch (e) {}
23796	
23797				attach( $(host).empty(), buttons );
23798	
23799				if ( activeEl !== undefined ) {
23800					$(host).find( '[data-dt-idx='+activeEl+']' ).focus();
23801				}
23802			}
23803		}
23804	} );
23805	
23806	
23807	
23808	// Built in type detection. See model.ext.aTypes for information about
23809	// what is required from this methods.
23810	$.extend( DataTable.ext.type.detect, [
vendor: 18,210 bytes, lines 23811-24407
23811		// Plain numbers - first since V8 detects some plain numbers as dates
23812		// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
23813		function ( d, settings )
23814		{
23815			var decimal = settings.oLanguage.sDecimal;
23816			return _isNumber( d, decimal ) ? 'num'+decimal : null;
23817		},
23818	
23819		// Dates (only those recognised by the browser's Date.parse)
23820		function ( d, settings )
23821		{
23822			// V8 tries _very_ hard to make a string passed into `Date.parse()`
23823			// valid, so we need to use a regex to restrict date formats. Use a
23824			// plug-in for anything other than ISO8601 style strings
23825			if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
23826				return null;
23827			}
23828			var parsed = Date.parse(d);
23829			return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
23830		},
23831	
23832		// Formatted numbers
23833		function ( d, settings )
23834		{
23835			var decimal = settings.oLanguage.sDecimal;
23836			return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
23837		},
23838	
23839		// HTML numeric
23840		function ( d, settings )
23841		{
23842			var decimal = settings.oLanguage.sDecimal;
23843			return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
23844		},
23845	
23846		// HTML numeric, formatted
23847		function ( d, settings )
23848		{
23849			var decimal = settings.oLanguage.sDecimal;
23850			return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
23851		},
23852	
23853		// HTML (this is strict checking - there must be html)
23854		function ( d, settings )
23855		{
23856			return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
23857				'html' : null;
23858		}
23859	] );
23860	
23861	
23862	
23863	// Filter formatting functions. See model.ext.ofnSearch for information about
23864	// what is required from these methods.
23865	// 
23866	// Note that additional search methods are added for the html numbers and
23867	// html formatted numbers by `_addNumericSort()` when we know what the decimal
23868	// place is
23869	
23870	
23871	$.extend( DataTable.ext.type.search, {
23872		html: function ( data ) {
23873			return _empty(data) ?
23874				data :
23875				typeof data === 'string' ?
23876					data
23877						.replace( _re_new_lines, " " )
23878						.replace( _re_html, "" ) :
23879					'';
23880		},
23881	
23882		string: function ( data ) {
23883			return _empty(data) ?
23884				data :
23885				typeof data === 'string' ?
23886					data.replace( _re_new_lines, " " ) :
23887					data;
23888		}
23889	} );
23890	
23891	
23892	
23893	var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
23894		if ( d !== 0 && (!d || d === '-') ) {
23895			return -Infinity;
23896		}
23897	
23898		// If a decimal place other than `.` is used, it needs to be given to the
23899		// function so we can detect it and replace with a `.` which is the only
23900		// decimal place Javascript recognises - it is not locale aware.
23901		if ( decimalPlace ) {
23902			d = _numToDecimal( d, decimalPlace );
23903		}
23904	
23905		if ( d.replace ) {
23906			if ( re1 ) {
23907				d = d.replace( re1, '' );
23908			}
23909	
23910			if ( re2 ) {
23911				d = d.replace( re2, '' );
23912			}
23913		}
23914	
23915		return d * 1;
23916	};
23917	
23918	
23919	// Add the numeric 'deformatting' functions for sorting and search. This is done
23920	// in a function to provide an easy ability for the language options to add
23921	// additional methods if a non-period decimal place is used.
23922	function _addNumericSort ( decimalPlace ) {
23923		$.each(
23924			{
23925				// Plain numbers
23926				"num": function ( d ) {
23927					return __numericReplace( d, decimalPlace );
23928				},
23929	
23930				// Formatted numbers
23931				"num-fmt": function ( d ) {
23932					return __numericReplace( d, decimalPlace, _re_formatted_numeric );
23933				},
23934	
23935				// HTML numeric
23936				"html-num": function ( d ) {
23937					return __numericReplace( d, decimalPlace, _re_html );
23938				},
23939	
23940				// HTML numeric, formatted
23941				"html-num-fmt": function ( d ) {
23942					return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
23943				}
23944			},
23945			function ( key, fn ) {
23946				// Add the ordering method
23947				_ext.type.order[ key+decimalPlace+'-pre' ] = fn;
23948	
23949				// For HTML types add a search formatter that will strip the HTML
23950				if ( key.match(/^html\-/) ) {
23951					_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
23952				}
23953			}
23954		);
23955	}
23956	
23957	
23958	// Default sort methods
23959	$.extend( _ext.type.order, {
23960		// Dates
23961		"date-pre": function ( d ) {
23962			var ts = Date.parse( d );
23963			return isNaN(ts) ? -Infinity : ts;
23964		},
23965	
23966		// html
23967		"html-pre": function ( a ) {
23968			return _empty(a) ?
23969				'' :
23970				a.replace ?
23971					a.replace( /<.*?>/g, "" ).toLowerCase() :
23972					a+'';
23973		},
23974	
23975		// string
23976		"string-pre": function ( a ) {
23977			// This is a little complex, but faster than always calling toString,
23978			// http://jsperf.com/tostring-v-check
23979			return _empty(a) ?
23980				'' :
23981				typeof a === 'string' ?
23982					a.toLowerCase() :
23983					! a.toString ?
23984						'' :
23985						a.toString();
23986		},
23987	
23988		// string-asc and -desc are retained only for compatibility with the old
23989		// sort methods
23990		"string-asc": function ( x, y ) {
23991			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
23992		},
23993	
23994		"string-desc": function ( x, y ) {
23995			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
23996		}
23997	} );
23998	
23999	
24000	// Numeric sorting types - order doesn't matter here
24001	_addNumericSort( '' );
24002	
24003	
24004	$.extend( true, DataTable.ext.renderer, {
24005		header: {
24006			_: function ( settings, cell, column, classes ) {
24007				// No additional mark-up required
24008				// Attach a sort listener to update on sort - note that using the
24009				// `DT` namespace will allow the event to be removed automatically
24010				// on destroy, while the `dt` namespaced event is the one we are
24011				// listening for
24012				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
24013					if ( settings !== ctx ) { // need to check this this is the host
24014						return;               // table, not a nested one
24015					}
24016	
24017					var colIdx = column.idx;
24018	
24019					cell
24020						.removeClass(
24021							column.sSortingClass +' '+
24022							classes.sSortAsc +' '+
24023							classes.sSortDesc
24024						)
24025						.addClass( columns[ colIdx ] == 'asc' ?
24026							classes.sSortAsc : columns[ colIdx ] == 'desc' ?
24027								classes.sSortDesc :
24028								column.sSortingClass
24029						);
24030				} );
24031			},
24032	
24033			jqueryui: function ( settings, cell, column, classes ) {
24034				$('<div/>')
24035					.addClass( classes.sSortJUIWrapper )
24036					.append( cell.contents() )
24037					.append( $('<span/>')
24038						.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
24039					)
24040					.appendTo( cell );
24041	
24042				// Attach a sort listener to update on sort
24043				$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
24044					if ( settings !== ctx ) {
24045						return;
24046					}
24047	
24048					var colIdx = column.idx;
24049	
24050					cell
24051						.removeClass( classes.sSortAsc +" "+classes.sSortDesc )
24052						.addClass( columns[ colIdx ] == 'asc' ?
24053							classes.sSortAsc : columns[ colIdx ] == 'desc' ?
24054								classes.sSortDesc :
24055								column.sSortingClass
24056						);
24057	
24058					cell
24059						.find( 'span.'+classes.sSortIcon )
24060						.removeClass(
24061							classes.sSortJUIAsc +" "+
24062							classes.sSortJUIDesc +" "+
24063							classes.sSortJUI +" "+
24064							classes.sSortJUIAscAllowed +" "+
24065							classes.sSortJUIDescAllowed
24066						)
24067						.addClass( columns[ colIdx ] == 'asc' ?
24068							classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
24069								classes.sSortJUIDesc :
24070								column.sSortingClassJUI
24071						);
24072				} );
24073			}
24074		}
24075	} );
24076	
24077	/*
24078	 * Public helper functions. These aren't used internally by DataTables, or
24079	 * called by any of the options passed into DataTables, but they can be used
24080	 * externally by developers working with DataTables. They are helper functions
24081	 * to make working with DataTables a little bit easier.
24082	 */
24083	
24084	var __htmlEscapeEntities = function ( d ) {
24085		return typeof d === 'string' ?
24086			d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
24087			d;
24088	};
24089	
24090	/**
24091	 * Helpers for `columns.render`.
24092	 *
24093	 * The options defined here can be used with the `columns.render` initialisation
24094	 * option to provide a display renderer. The following functions are defined:
24095	 *
24096	 * * `number` - Will format numeric data (defined by `columns.data`) for
24097	 *   display, retaining the original unformatted data for sorting and filtering.
24098	 *   It takes 5 parameters:
24099	 *   * `string` - Thousands grouping separator
24100	 *   * `string` - Decimal point indicator
24101	 *   * `integer` - Number of decimal points to show
24102	 *   * `string` (optional) - Prefix.
24103	 *   * `string` (optional) - Postfix (/suffix).
24104	 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
24105	 *   parameters.
24106	 *
24107	 * @example
24108	 *   // Column definition using the number renderer
24109	 *   {
24110	 *     data: "salary",
24111	 *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
24112	 *   }
24113	 *
24114	 * @namespace
24115	 */
24116	DataTable.render = {
24117		number: function ( thousands, decimal, precision, prefix, postfix ) {
24118			return {
24119				display: function ( d ) {
24120					if ( typeof d !== 'number' && typeof d !== 'string' ) {
24121						return d;
24122					}
24123	
24124					var negative = d < 0 ? '-' : '';
24125					var flo = parseFloat( d );
24126	
24127					// If NaN then there isn't much formatting that we can do - just
24128					// return immediately, escaping any HTML (this was supposed to
24129					// be a number after all)
24130					if ( isNaN( flo ) ) {
24131						return __htmlEscapeEntities( d );
24132					}
24133	
24134					flo = flo.toFixed( precision );
24135					d = Math.abs( flo );
24136	
24137					var intPart = parseInt( d, 10 );
24138					var floatPart = precision ?
24139						decimal+(d - intPart).toFixed( precision ).substring( 2 ):
24140						'';
24141	
24142					return negative + (prefix||'') +
24143						intPart.toString().replace(
24144							/\B(?=(\d{3})+(?!\d))/g, thousands
24145						) +
24146						floatPart +
24147						(postfix||'');
24148				}
24149			};
24150		},
24151	
24152		text: function () {
24153			return {
24154				display: __htmlEscapeEntities
24155			};
24156		}
24157	};
24158	
24159	
24160	/*
24161	 * This is really a good bit rubbish this method of exposing the internal methods
24162	 * publicly... - To be fixed in 2.0 using methods on the prototype
24163	 */
24164	
24165	
24166	/**
24167	 * Create a wrapper function for exporting an internal functions to an external API.
24168	 *  @param {string} fn API function name
24169	 *  @returns {function} wrapped function
24170	 *  @memberof DataTable#internal
24171	 */
24172	function _fnExternApiFunc (fn)
24173	{
24174		return function() {
24175			var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
24176				Array.prototype.slice.call(arguments)
24177			);
24178			return DataTable.ext.internal[fn].apply( this, args );
24179		};
24180	}
24181	
24182	
24183	/**
24184	 * Reference to internal functions for use by plug-in developers. Note that
24185	 * these methods are references to internal functions and are considered to be
24186	 * private. If you use these methods, be aware that they are liable to change
24187	 * between versions.
24188	 *  @namespace
24189	 */
24190	$.extend( DataTable.ext.internal, {
24191		_fnExternApiFunc: _fnExternApiFunc,
24192		_fnBuildAjax: _fnBuildAjax,
24193		_fnAjaxUpdate: _fnAjaxUpdate,
24194		_fnAjaxParameters: _fnAjaxParameters,
24195		_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
24196		_fnAjaxDataSrc: _fnAjaxDataSrc,
24197		_fnAddColumn: _fnAddColumn,
24198		_fnColumnOptions: _fnColumnOptions,
24199		_fnAdjustColumnSizing: _fnAdjustColumnSizing,
24200		_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
24201		_fnColumnIndexToVisible: _fnColumnIndexToVisible,
24202		_fnVisbleColumns: _fnVisbleColumns,
24203		_fnGetColumns: _fnGetColumns,
24204		_fnColumnTypes: _fnColumnTypes,
24205		_fnApplyColumnDefs: _fnApplyColumnDefs,
24206		_fnHungarianMap: _fnHungarianMap,
24207		_fnCamelToHungarian: _fnCamelToHungarian,
24208		_fnLanguageCompat: _fnLanguageCompat,
24209		_fnBrowserDetect: _fnBrowserDetect,
24210		_fnAddData: _fnAddData,
24211		_fnAddTr: _fnAddTr,
24212		_fnNodeToDataIndex: _fnNodeToDataIndex,
24213		_fnNodeToColumnIndex: _fnNodeToColumnIndex,
24214		_fnGetCellData: _fnGetCellData,
24215		_fnSetCellData: _fnSetCellData,
24216		_fnSplitObjNotation: _fnSplitObjNotation,
24217		_fnGetObjectDataFn: _fnGetObjectDataFn,
24218		_fnSetObjectDataFn: _fnSetObjectDataFn,
24219		_fnGetDataMaster: _fnGetDataMaster,
24220		_fnClearTable: _fnClearTable,
24221		_fnDeleteIndex: _fnDeleteIndex,
24222		_fnInvalidate: _fnInvalidate,
24223		_fnGetRowElements: _fnGetRowElements,
24224		_fnCreateTr: _fnCreateTr,
24225		_fnBuildHead: _fnBuildHead,
24226		_fnDrawHead: _fnDrawHead,
24227		_fnDraw: _fnDraw,
24228		_fnReDraw: _fnReDraw,
24229		_fnAddOptionsHtml: _fnAddOptionsHtml,
24230		_fnDetectHeader: _fnDetectHeader,
24231		_fnGetUniqueThs: _fnGetUniqueThs,
24232		_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
24233		_fnFilterComplete: _fnFilterComplete,
24234		_fnFilterCustom: _fnFilterCustom,
24235		_fnFilterColumn: _fnFilterColumn,
24236		_fnFilter: _fnFilter,
24237		_fnFilterCreateSearch: _fnFilterCreateSearch,
24238		_fnEscapeRegex: _fnEscapeRegex,
24239		_fnFilterData: _fnFilterData,
24240		_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
24241		_fnUpdateInfo: _fnUpdateInfo,
24242		_fnInfoMacros: _fnInfoMacros,
24243		_fnInitialise: _fnInitialise,
24244		_fnInitComplete: _fnInitComplete,
24245		_fnLengthChange: _fnLengthChange,
24246		_fnFeatureHtmlLength: _fnFeatureHtmlLength,
24247		_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
24248		_fnPageChange: _fnPageChange,
24249		_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
24250		_fnProcessingDisplay: _fnProcessingDisplay,
24251		_fnFeatureHtmlTable: _fnFeatureHtmlTable,
24252		_fnScrollDraw: _fnScrollDraw,
24253		_fnApplyToChildren: _fnApplyToChildren,
24254		_fnCalculateColumnWidths: _fnCalculateColumnWidths,
24255		_fnThrottle: _fnThrottle,
24256		_fnConvertToWidth: _fnConvertToWidth,
24257		_fnGetWidestNode: _fnGetWidestNode,
24258		_fnGetMaxLenString: _fnGetMaxLenString,
24259		_fnStringToCss: _fnStringToCss,
24260		_fnSortFlatten: _fnSortFlatten,
24261		_fnSort: _fnSort,
24262		_fnSortAria: _fnSortAria,
24263		_fnSortListener: _fnSortListener,
24264		_fnSortAttachListener: _fnSortAttachListener,
24265		_fnSortingClasses: _fnSortingClasses,
24266		_fnSortData: _fnSortData,
24267		_fnSaveState: _fnSaveState,
24268		_fnLoadState: _fnLoadState,
24269		_fnSettingsFromNode: _fnSettingsFromNode,
24270		_fnLog: _fnLog,
24271		_fnMap: _fnMap,
24272		_fnBindAction: _fnBindAction,
24273		_fnCallbackReg: _fnCallbackReg,
24274		_fnCallbackFire: _fnCallbackFire,
24275		_fnLengthOverflow: _fnLengthOverflow,
24276		_fnRenderer: _fnRenderer,
24277		_fnDataSource: _fnDataSource,
24278		_fnRowAttributes: _fnRowAttributes,
24279		_fnExtend: _fnExtend,
24280		_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
24281		                                // in 1.10, so this dead-end function is
24282		                                // added to prevent errors
24283	} );
24284	
24285
24286	// jQuery access
24287	$.fn.dataTable = DataTable;
24288
24289	// Provide access to the host jQuery object (circular reference)
24290	DataTable.$ = $;
24291
24292	// Legacy aliases
24293	$.fn.dataTableSettings = DataTable.settings;
24294	$.fn.dataTableExt = DataTable.ext;
24295
24296	// With a capital `D` we return a DataTables API instance rather than a
24297	// jQuery object
24298	$.fn.DataTable = function ( opts ) {
24299		return $(this).dataTable( opts ).api();
24300	};
24301
24302	// All properties that are available to $.fn.dataTable should also be
24303	// available on $.fn.DataTable
24304	$.each( DataTable, function ( prop, val ) {
24305		$.fn.DataTable[ prop ] = val;
24306	} );
24307
24308
24309	// Information about events fired by DataTables - for documentation.
24310	/**
24311	 * Draw event, fired whenever the table is redrawn on the page, at the same
24312	 * point as fnDrawCallback. This may be useful for binding events or
24313	 * performing calculations when the table is altered at all.
24314	 *  @name DataTable#draw.dt
24315	 *  @event
24316	 *  @param {event} e jQuery event object
24317	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24318	 */
24319
24320	/**
24321	 * Search event, fired when the searching applied to the table (using the
24322	 * built-in global search, or column filters) is altered.
24323	 *  @name DataTable#search.dt
24324	 *  @event
24325	 *  @param {event} e jQuery event object
24326	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24327	 */
24328
24329	/**
24330	 * Page change event, fired when the paging of the table is altered.
24331	 *  @name DataTable#page.dt
24332	 *  @event
24333	 *  @param {event} e jQuery event object
24334	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24335	 */
24336
24337	/**
24338	 * Order event, fired when the ordering applied to the table is altered.
24339	 *  @name DataTable#order.dt
24340	 *  @event
24341	 *  @param {event} e jQuery event object
24342	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24343	 */
24344
24345	/**
24346	 * DataTables initialisation complete event, fired when the table is fully
24347	 * drawn, including Ajax data loaded, if Ajax data is required.
24348	 *  @name DataTable#init.dt
24349	 *  @event
24350	 *  @param {event} e jQuery event object
24351	 *  @param {object} oSettings DataTables settings object
24352	 *  @param {object} json The JSON object request from the server - only
24353	 *    present if client-side Ajax sourced data is used</li></ol>
24354	 */
24355
24356	/**
24357	 * State save event, fired when the table has changed state a new state save
24358	 * is required. This event allows modification of the state saving object
24359	 * prior to actually doing the save, including addition or other state
24360	 * properties (for plug-ins) or modification of a DataTables core property.
24361	 *  @name DataTable#stateSaveParams.dt
24362	 *  @event
24363	 *  @param {event} e jQuery event object
24364	 *  @param {object} oSettings DataTables settings object
24365	 *  @param {object} json The state information to be saved
24366	 */
24367
24368	/**
24369	 * State load event, fired when the table is loading state from the stored
24370	 * data, but prior to the settings object being modified by the saved state
24371	 * - allowing modification of the saved state is required or loading of
24372	 * state for a plug-in.
24373	 *  @name DataTable#stateLoadParams.dt
24374	 *  @event
24375	 *  @param {event} e jQuery event object
24376	 *  @param {object} oSettings DataTables settings object
24377	 *  @param {object} json The saved state information
24378	 */
24379
24380	/**
24381	 * State loaded event, fired when state has been loaded from stored data and
24382	 * the settings object has been modified by the loaded data.
24383	 *  @name DataTable#stateLoaded.dt
24384	 *  @event
24385	 *  @param {event} e jQuery event object
24386	 *  @param {object} oSettings DataTables settings object
24387	 *  @param {object} json The saved state information
24388	 */
24389
24390	/**
24391	 * Processing event, fired when DataTables is doing some kind of processing
24392	 * (be it, order, searcg or anything else). It can be used to indicate to
24393	 * the end user that there is something happening, or that something has
24394	 * finished.
24395	 *  @name DataTable#processing.dt
24396	 *  @event
24397	 *  @param {event} e jQuery event object
24398	 *  @param {object} oSettings DataTables settings object
24399	 *  @param {boolean} bShow Flag for if DataTables is doing processing or not
24400	 */
24401
24402	/**
24403	 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
24404	 * request to made to the server for new data. This event is called before
24405	 * DataTables processed the returned data, so it can also be used to pre-
24406	 * process the data returned from the server, if needed.
24407	 *
24408	 * Note that this trigger is called in `fnServerData`, if you override
24409	 * `fnServerData` and which to use this event, you need to trigger it in you
24410	 * success function.
24411	 *  @name DataTable#xhr.dt
24412	 *  @event
24413	 *  @param {event} e jQuery event object
24414	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24415	 *  @param {object} json JSON returned from the server
24416	 *
24417	 *  @example
24418	 *     // Use a custom property returned from the server in another DOM element
24419	 *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
24420	 *       $('#status').html( json.status );
24421	 *     } );
24422	 *
24423	 *  @example
24424	 *     // Pre-process the data returned from the server
24425	 *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
24426	 *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
24427	 *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
24428	 *       }
24429	 *       // Note no return - manipulate the data directly in the JSON object.
24430	 *     } );
24431	 */
24432
24433	/**
24434	 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
24435	 * or passing the bDestroy:true parameter in the initialisation object. This
24436	 * can be used to remove bound events, added DOM nodes, etc.
24437	 *  @name DataTable#destroy.dt
24438	 *  @event
24439	 *  @param {event} e jQuery event object
24440	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24441	 */
24442
24443	/**
24444	 * Page length change event, fired when number of records to show on each
24445	 * page (the length) is changed.
24446	 *  @name DataTable#length.dt
24447	 *  @event
24448	 *  @param {event} e jQuery event object
24449	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24450	 *  @param {integer} len New length
24451	 */
24452
24453	/**
24454	 * Column sizing has changed.
24455	 *  @name DataTable#column-sizing.dt
24456	 *  @event
24457	 *  @param {event} e jQuery event object
24458	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24459	 */
24460
24461	/**
24462	 * Column visibility has changed.
24463	 *  @name DataTable#column-visibility.dt
24464	 *  @event
24465	 *  @param {event} e jQuery event object
24466	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24467	 *  @param {int} column Column index
24468	 *  @param {bool} vis `false` if column now hidden, or `true` if visible
24469	 */
24470
24471	return $.fn.dataTable;
24472}));
24473
24474
24475/*! DataTables Bootstrap 3 integration
24476 * ©2011-2015 SpryMedia Ltd - datatables.net/license
24477 */
24478
24479/**
24480 * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and
24481 * DataTables 1.10 or newer.
24482 *
24483 * This file sets the defaults and adds options to DataTables to style its
24484 * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
24485 * for further information.
24486 */
24487(function( factory ){
24488	if ( typeof define === 'function' && define.amd ) {
24489		// AMD
24490		define( ['jquery', 'datatables.net'], function ( $ ) {
24491			return factory( $, window, document );
24492		} );
24493	}
24494	else if ( typeof exports === 'object' ) {
24495		// CommonJS
24496		module.exports = function (root, $) {
24497			if ( ! root ) {
24498				root = window;
24499			}
24500
24501			if ( ! $ || ! $.fn.dataTable ) {
24502				// Require DataTables, which attaches to jQuery, including
24503				// jQuery if needed and have a $ property so we can access the
24504				// jQuery object that is used
24505				$ = require('datatables.net')(root, $).$;
24506			}
24507
24508			return factory( $, root, root.document );
24509		};
24510	}
24511	else {
24512		// Browser
24513		factory( jQuery, window, document );
24514	}
24515}(function( $, window, document, undefined ) {
24516'use strict';
24517var DataTable = $.fn.dataTable;
24518
24519
24520/* Set the defaults for DataTables initialisation */
24521$.extend( true, DataTable.defaults, {
24522	dom:
24523		"<'row'<'col-sm-6'l><'col-sm-6'f>>" +
24524		"<'row'<'col-sm-12'tr>>" +
24525		"<'row'<'col-sm-5'i><'col-sm-7'p>>",
24526	renderer: 'bootstrap'
24527} );
24528
24529
24530/* Default class modification */
24531$.extend( DataTable.ext.classes, {
24532	sWrapper:      "dataTables_wrapper form-inline dt-bootstrap",
24533	sFilterInput:  "form-control input-sm",
24534	sLengthSelect: "form-control input-sm",
24535	sProcessing:   "dataTables_processing panel panel-default"
24536} );
24537
24538
24539/* Bootstrap paging button renderer */
24540DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {
24541	var api     = new DataTable.Api( settings );
24542	var classes = settings.oClasses;
24543	var lang    = settings.oLanguage.oPaginate;
24544	var aria = settings.oLanguage.oAria.paginate || {};
24545	var btnDisplay, btnClass, counter=0;
24546
24547	var attach = function( container, buttons ) {
24548		var i, ien, node, button;
24549		var clickHandler = function ( e ) {
24550			e.preventDefault();
24551			if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {
24552				api.page( e.data.action ).draw( 'page' );
24553			}
24554		};
24555
24556		for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
24557			button = buttons[i];
24558
24559			if ( $.isArray( button ) ) {
24560				attach( container, button );
24561			}
24562			else {
24563				btnDisplay = '';
24564				btnClass = '';
24565
24566				switch ( button ) {
24567					case 'ellipsis':
24568						btnDisplay = '&#x2026;';
24569						btnClass = 'disabled';
24570						break;
24571
24572					case 'first':
24573						btnDisplay = lang.sFirst;
24574						btnClass = button + (page > 0 ?
24575							'' : ' disabled');
24576						break;
24577
24578					case 'previous':
24579						btnDisplay = lang.sPrevious;
24580						btnClass = button + (page > 0 ?
24581							'' : ' disabled');
24582						break;
24583
24584					case 'next':
24585						btnDisplay = lang.sNext;
24586						btnClass = button + (page < pages-1 ?
24587							'' : ' disabled');
24588						break;
24589
24590					case 'last':
24591						btnDisplay = lang.sLast;
24592						btnClass = button + (page < pages-1 ?
24593							'' : ' disabled');
24594						break;
24595
24596					default:
24597						btnDisplay = button + 1;
24598						btnClass = page === button ?
24599							'active' : '';
24600						break;
24601				}
24602
24603				if ( btnDisplay ) {
24604					node = $('<li>', {
24605							'class': classes.sPageButton+' '+btnClass,
24606							'id': idx === 0 && typeof button === 'string' ?
24607								settings.sTableId +'_'+ button :
24608								null
24609						} )
24610						.append( $('<a>', {
24611								'href': '#',
24612								'aria-controls': settings.sTableId,
24613								'aria-label': aria[ button ],
24614								'data-dt-idx': counter,
24615								'tabindex': settings.iTabIndex
24616							} )
24617							.html( btnDisplay )
24618						)
24619						.appendTo( container );
24620
24621					settings.oApi._fnBindAction(
24622						node, {action: button}, clickHandler
24623					);
24624
24625					counter++;
24626				}
24627			}
24628		}
24629	};
24630
24631	// IE9 throws an 'unknown error' if document.activeElement is used
24632	// inside an iframe or frame. 
24633	var activeEl;
24634
24635	try {
24636		// Because this approach is destroying and recreating the paging
24637		// elements, focus is lost on the select button which is bad for
24638		// accessibility. So we want to restore focus once the draw has
24639		// completed
24640		activeEl = $(host).find(document.activeElement).data('dt-idx');
24641	}
24642	catch (e) {}
24643
24644	attach(
24645		$(host).empty().html('<ul class="pagination"/>').children('ul'),
24646		buttons
24647	);
24648
24649	if ( activeEl !== undefined ) {
24650		$(host).find( '[data-dt-idx='+activeEl+']' ).focus();
24651	}
24652};
24653
24654
24655return DataTable;
24656}));
24657
24658
24659/*! Buttons for DataTables 1.5.4
24660 * ©2016-2018 SpryMedia Ltd - datatables.net/license
24661 */
24662
24663(function( factory ){
24664	if ( typeof define === 'function' && define.amd ) {
24665		// AMD
24666		define( ['jquery', 'datatables.net'], function ( $ ) {
24667			return factory( $, window, document );
24668		} );
24669	}
24670	else if ( typeof exports === 'object' ) {
24671		// CommonJS
24672		module.exports = function (root, $) {
24673			if ( ! root ) {
24674				root = window;
24675			}
24676
24677			if ( ! $ || ! $.fn.dataTable ) {
24678				$ = require('datatables.net')(root, $).$;
24679			}
24680
24681			return factory( $, root, root.document );
24682		};
24683	}
24684	else {
24685		// Browser
24686		factory( jQuery, window, document );
24687	}
24688}(function( $, window, document, undefined ) {
24689'use strict';
24690var DataTable = $.fn.dataTable;
24691
24692
24693// Used for namespacing events added to the document by each instance, so they
24694// can be removed on destroy
24695var _instCounter = 0;
24696
24697// Button namespacing counter for namespacing events on individual buttons
24698var _buttonCounter = 0;
24699
24700var _dtButtons = DataTable.ext.buttons;
24701
24702/**
24703 * [Buttons description]
24704 * @param {[type]}
24705 * @param {[type]}
24706 */
24707var Buttons = function( dt, config )
24708{
24709	// If there is no config set it to an empty object
24710	if ( typeof( config ) === 'undefined' ) {
24711		config = {};	
24712	}
24713	
24714	// Allow a boolean true for defaults
24715	if ( config === true ) {
24716		config = {};
24717	}
24718
24719	// For easy configuration of buttons an array can be given
24720	if ( $.isArray( config ) ) {
24721		config = { buttons: config };
24722	}
24723
24724	this.c = $.extend( true, {}, Buttons.defaults, config );
24725
24726	// Don't want a deep copy for the buttons
24727	if ( config.buttons ) {
24728		this.c.buttons = config.buttons;
24729	}
24730
24731	this.s = {
24732		dt: new DataTable.Api( dt ),
24733		buttons: [],
24734		listenKeys: '',
24735		namespace: 'dtb'+(_instCounter++)
24736	};
24737
24738	this.dom = {
24739		container: $('<'+this.c.dom.container.tag+'/>')
24740			.addClass( this.c.dom.container.className )
24741	};
24742
24743	this._constructor();
24744};
24745
24746
24747$.extend( Buttons.prototype, {
24748	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
24749	 * Public methods
24750	 */
24751
24752	/**
24753	 * Get the action of a button
24754	 * @param  {int|string} Button index
24755	 * @return {function}
24756	 *//**
24757	 * Set the action of a button
24758	 * @param  {node} node Button element
24759	 * @param  {function} action Function to set
24760	 * @return {Buttons} Self for chaining
24761	 */
24762	action: function ( node, action )
24763	{
24764		var button = this._nodeToButton( node );
24765
24766		if ( action === undefined ) {
24767			return button.conf.action;
24768		}
24769
24770		button.conf.action = action;
24771
24772		return this;
24773	},
24774
24775	/**
24776	 * Add an active class to the button to make to look active or get current
24777	 * active state.
24778	 * @param  {node} node Button element
24779	 * @param  {boolean} [flag] Enable / disable flag
24780	 * @return {Buttons} Self for chaining or boolean for getter
24781	 */
24782	active: function ( node, flag ) {
24783		var button = this._nodeToButton( node );
24784		var klass = this.c.dom.button.active;
24785		var jqNode = $(button.node);
24786
24787		if ( flag === undefined ) {
24788			return jqNode.hasClass( klass );
24789		}
24790
24791		jqNode.toggleClass( klass, flag === undefined ? true : flag );
24792
24793		return this;
24794	},
24795
24796	/**
24797	 * Add a new button
24798	 * @param {object} config Button configuration object, base string name or function
24799	 * @param {int|string} [idx] Button index for where to insert the button
24800	 * @return {Buttons} Self for chaining
24801	 */
24802	add: function ( config, idx )
24803	{
24804		var buttons = this.s.buttons;
24805
24806		if ( typeof idx === 'string' ) {
24807			var split = idx.split('-');
24808			var base = this.s;
24809
24810			for ( var i=0, ien=split.length-1 ; i<ien ; i++ ) {
24811				base = base.buttons[ split[i]*1 ];
24812			}
24813
24814			buttons = base.buttons;
24815			idx = split[ split.length-1 ]*1;
24816		}
24817
24818		this._expandButton( buttons, config, false, idx );
24819		this._draw();
24820
24821		return this;
24822	},
24823
24824	/**
24825	 * Get the container node for the buttons
24826	 * @return {jQuery} Buttons node
24827	 */
24828	container: function ()
24829	{
24830		return this.dom.container;
24831	},
24832
24833	/**
24834	 * Disable a button
24835	 * @param  {node} node Button node
24836	 * @return {Buttons} Self for chaining
24837	 */
24838	disable: function ( node ) {
24839		var button = this._nodeToButton( node );
24840
24841		$(button.node).addClass( this.c.dom.button.disabled );
24842
24843		return this;
24844	},
24845
24846	/**
24847	 * Destroy the instance, cleaning up event handlers and removing DOM
24848	 * elements
24849	 * @return {Buttons} Self for chaining
24850	 */
24851	destroy: function ()
24852	{
24853		// Key event listener
24854		$('body').off( 'keyup.'+this.s.namespace );
24855
24856		// Individual button destroy (so they can remove their own events if
24857		// needed). Take a copy as the array is modified by `remove`
24858		var buttons = this.s.buttons.slice();
24859		var i, ien;
24860		
24861		for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
24862			this.remove( buttons[i].node );
24863		}
24864
24865		// Container
24866		this.dom.container.remove();
24867
24868		// Remove from the settings object collection
24869		var buttonInsts = this.s.dt.settings()[0];
24870
24871		for ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {
24872			if ( buttonInsts.inst === this ) {
24873				buttonInsts.splice( i, 1 );
24874				break;
24875			}
24876		}
24877
24878		return this;
24879	},
24880
24881	/**
24882	 * Enable / disable a button
24883	 * @param  {node} node Button node
24884	 * @param  {boolean} [flag=true] Enable / disable flag
24885	 * @return {Buttons} Self for chaining
24886	 */
24887	enable: function ( node, flag )
24888	{
24889		if ( flag === false ) {
24890			return this.disable( node );
24891		}
24892
24893		var button = this._nodeToButton( node );
24894		$(button.node).removeClass( this.c.dom.button.disabled );
24895
24896		return this;
24897	},
24898
24899	/**
24900	 * Get the instance name for the button set selector
24901	 * @return {string} Instance name
24902	 */
24903	name: function ()
24904	{
24905		return this.c.name;
24906	},
24907
24908	/**
24909	 * Get a button's node
24910	 * @param  {node} node Button node
24911	 * @return {jQuery} Button element
24912	 */
24913	node: function ( node )
24914	{
24915		var button = this._nodeToButton( node );
24916		return $(button.node);
24917	},
24918
24919	/**
24920	 * Set / get a processing class on the selected button
24921	 * @param  {boolean} flag true to add, false to remove, undefined to get
24922	 * @return {boolean|Buttons} Getter value or this if a setter.
24923	 */
24924	processing: function ( node, flag )
24925	{
24926		var button = this._nodeToButton( node );
24927
24928		if ( flag === undefined ) {
24929			return $(button.node).hasClass( 'processing' );
24930		}
24931
24932		$(button.node).toggleClass( 'processing', flag );
24933
24934		return this;
24935	},
24936
24937	/**
24938	 * Remove a button.
24939	 * @param  {node} node Button node
24940	 * @return {Buttons} Self for chaining
24941	 */
24942	remove: function ( node )
24943	{
24944		var button = this._nodeToButton( node );
24945		var host = this._nodeToHost( node );
24946		var dt = this.s.dt;
24947
24948		// Remove any child buttons first
24949		if ( button.buttons.length ) {
24950			for ( var i=button.buttons.length-1 ; i>=0 ; i-- ) {
24951				this.remove( button.buttons[i].node );
24952			}
24953		}
24954
24955		// Allow the button to remove event handlers, etc
24956		if ( button.conf.destroy ) {
24957			button.conf.destroy.call( dt.button(node), dt, $(node), button.conf );
24958		}
24959
24960		this._removeKey( button.conf );
24961
24962		$(button.node).remove();
24963
24964		var idx = $.inArray( button, host );
24965		host.splice( idx, 1 );
24966
24967		return this;
24968	},
24969
24970	/**
24971	 * Get the text for a button
24972	 * @param  {int|string} node Button index
24973	 * @return {string} Button text
24974	 *//**
24975	 * Set the text for a button
24976	 * @param  {int|string|function} node Button index
24977	 * @param  {string} label Text
24978	 * @return {Buttons} Self for chaining
24979	 */
24980	text: function ( node, label )
24981	{
24982		var button = this._nodeToButton( node );
24983		var buttonLiner = this.c.dom.collection.buttonLiner;
24984		var linerTag = button.inCollection && buttonLiner && buttonLiner.tag ?
24985			buttonLiner.tag :
24986			this.c.dom.buttonLiner.tag;
24987		var dt = this.s.dt;
24988		var jqNode = $(button.node);
24989		var text = function ( opt ) {
24990			return typeof opt === 'function' ?
24991				opt( dt, jqNode, button.conf ) :
24992				opt;
24993		};
24994
24995		if ( label === undefined ) {
24996			return text( button.conf.text );
24997		}
24998
24999		button.conf.text = label;
25000
25001		if ( linerTag ) {
25002			jqNode.children( linerTag ).html( text(label) );
25003		}
25004		else {
25005			jqNode.html( text(label) );
25006		}
25007
25008		return this;
25009	},
25010
25011
25012	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
25013	 * Constructor
25014	 */
25015
25016	/**
25017	 * Buttons constructor
25018	 * @private
25019	 */
25020	_constructor: function ()
25021	{
25022		var that = this;
25023		var dt = this.s.dt;
25024		var dtSettings = dt.settings()[0];
25025		var buttons =  this.c.buttons;
25026
25027		if ( ! dtSettings._buttons ) {
25028			dtSettings._buttons = [];
25029		}
25030
25031		dtSettings._buttons.push( {
25032			inst: this,
25033			name: this.c.name
25034		} );
25035
25036		for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
25037			this.add( buttons[i] );
25038		}
25039
25040		dt.on( 'destroy', function ( e, settings ) {
25041			if ( settings === dtSettings ) {
25042				that.destroy();
25043			}
25044		} );
25045
25046		// Global key event binding to listen for button keys
25047		$('body').on( 'keyup.'+this.s.namespace, function ( e ) {
25048			if ( ! document.activeElement || document.activeElement === document.body ) {
25049				// SUse a string of characters for fast lookup of if we need to
25050				// handle this
25051				var character = String.fromCharCode(e.keyCode).toLowerCase();
25052
25053				if ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {
25054					that._keypress( character, e );
25055				}
25056			}
25057		} );
25058	},
25059
25060
25061	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
25062	 * Private methods
25063	 */
25064
25065	/**
25066	 * Add a new button to the key press listener
25067	 * @param {object} conf Resolved button configuration object
25068	 * @private
25069	 */
25070	_addKey: function ( conf )
25071	{
25072		if ( conf.key ) {
25073			this.s.listenKeys += $.isPlainObject( conf.key ) ?
25074				conf.key.key :
25075				conf.key;
25076		}
25077	},
25078
25079	/**
25080	 * Insert the buttons into the container. Call without parameters!
25081	 * @param  {node} [container] Recursive only - Insert point
25082	 * @param  {array} [buttons] Recursive only - Buttons array
25083	 * @private
25084	 */
25085	_draw: function ( container, buttons )
25086	{
25087		if ( ! container ) {
25088			container = this.dom.container;
25089			buttons = this.s.buttons;
25090		}
25091
25092		container.children().detach();
25093
25094		for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
25095			container.append( buttons[i].inserter );
25096			container.append( ' ' );
25097
25098			if ( buttons[i].buttons && buttons[i].buttons.length ) {
25099				this._draw( buttons[i].collection, buttons[i].buttons );
25100			}
25101		}
25102	},
25103
25104	/**
25105	 * Create buttons from an array of buttons
25106	 * @param  {array} attachTo Buttons array to attach to
25107	 * @param  {object} button Button definition
25108	 * @param  {boolean} inCollection true if the button is in a collection
25109	 * @private
25110	 */
25111	_expandButton: function ( attachTo, button, inCollection, attachPoint )
25112	{
25113		var dt = this.s.dt;
25114		var buttonCounter = 0;
25115		var buttons = ! $.isArray( button ) ?
25116			[ button ] :
25117			button;
25118
25119		for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
25120			var conf = this._resolveExtends( buttons[i] );
25121
25122			if ( ! conf ) {
25123				continue;
25124			}
25125
25126			// If the configuration is an array, then expand the buttons at this
25127			// point
25128			if ( $.isArray( conf ) ) {
25129				this._expandButton( attachTo, conf, inCollection, attachPoint );
25130				continue;
25131			}
25132
25133			var built = this._buildButton( conf, inCollection );
25134			if ( ! built ) {
25135				continue;
25136			}
25137
25138			if ( attachPoint !== undefined ) {
25139				attachTo.splice( attachPoint, 0, built );
25140				attachPoint++;
25141			}
25142			else {
25143				attachTo.push( built );
25144			}
25145
25146			if ( built.conf.buttons ) {
25147				var collectionDom = this.c.dom.collection;
25148				built.collection = $('<'+collectionDom.tag+'/>')
25149					.addClass( collectionDom.className )
25150					.attr( 'role', 'menu' ) ;
25151				built.conf._collection = built.collection;
25152
25153				this._expandButton( built.buttons, built.conf.buttons, true, attachPoint );
25154			}
25155
25156			// init call is made here, rather than buildButton as it needs to
25157			// be selectable, and for that it needs to be in the buttons array
25158			if ( conf.init ) {
25159				conf.init.call( dt.button( built.node ), dt, $(built.node), conf );
25160			}
25161
25162			buttonCounter++;
25163		}
25164	},
25165
25166	/**
25167	 * Create an individual button
25168	 * @param  {object} config            Resolved button configuration
25169	 * @param  {boolean} inCollection `true` if a collection button
25170	 * @return {jQuery} Created button node (jQuery)
25171	 * @private
25172	 */
25173	_buildButton: function ( config, inCollection )
25174	{
25175		var buttonDom = this.c.dom.button;
25176		var linerDom = this.c.dom.buttonLiner;
25177		var collectionDom = this.c.dom.collection;
25178		var dt = this.s.dt;
25179		var text = function ( opt ) {
25180			return typeof opt === 'function' ?
25181				opt( dt, button, config ) :
25182				opt;
25183		};
25184
25185		if ( inCollection && collectionDom.button ) {
25186			buttonDom = collectionDom.button;
25187		}
25188
25189		if ( inCollection && collectionDom.buttonLiner ) {
25190			linerDom = collectionDom.buttonLiner;
25191		}
25192
25193		// Make sure that the button is available based on whatever requirements
25194		// it has. For example, Flash buttons require Flash
25195		if ( config.available && ! config.available( dt, config ) ) {
25196			return false;
25197		}
25198
25199		var action = function ( e, dt, button, config ) {
25200			config.action.call( dt.button( button ), e, dt, button, config );
25201
25202			$(dt.table().node()).triggerHandler( 'buttons-action.dt', [
25203				dt.button( button ), dt, button, config 
25204			] );
25205		};
25206
25207		var tag = config.tag || buttonDom.tag;
25208		var button = $('<'+tag+'/>')
25209			.addClass( buttonDom.className )
25210			.attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )
25211			.attr( 'aria-controls', this.s.dt.table().node().id )
25212			.on( 'click.dtb', function (e) {
25213				e.preventDefault();
25214
25215				if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
25216					action( e, dt, button, config );
25217				}
25218
25219				button.blur();
25220			} )
25221			.on( 'keyup.dtb', function (e) {
25222				if ( e.keyCode === 13 ) {
25223					if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
25224						action( e, dt, button, config );
25225					}
25226				}
25227			} );
25228
25229		// Make `a` tags act like a link
25230		if ( tag.toLowerCase() === 'a' ) {
25231			button.attr( 'href', '#' );
25232		}
25233
25234		// Button tags should have `type=button` so they don't have any default behaviour
25235		if ( tag.toLowerCase() === 'button' ) {
25236			button.attr( 'type', 'button' );
25237		}
25238
25239		if ( linerDom.tag ) {
25240			var liner = $('<'+linerDom.tag+'/>')
25241				.html( text( config.text ) )
25242				.addClass( linerDom.className );
25243
25244			if ( linerDom.tag.toLowerCase() === 'a' ) {
25245				liner.attr( 'href', '#' );
25246			}
25247
25248			button.append( liner );
25249		}
25250		else {
25251			button.html( text( config.text ) );
25252		}
25253
25254		if ( config.enabled === false ) {
25255			button.addClass( buttonDom.disabled );
25256		}
25257
25258		if ( config.className ) {
25259			button.addClass( config.className );
25260		}
25261
25262		if ( config.titleAttr ) {
25263			button.attr( 'title', text( config.titleAttr ) );
25264		}
25265
25266		if ( config.attr ) {
25267			button.attr( config.attr );
25268		}
25269
25270		if ( ! config.namespace ) {
25271			config.namespace = '.dt-button-'+(_buttonCounter++);
25272		}
25273
25274		var buttonContainer = this.c.dom.buttonContainer;
25275		var inserter;
25276		if ( buttonContainer && buttonContainer.tag ) {
25277			inserter = $('<'+buttonContainer.tag+'/>')
25278				.addClass( buttonContainer.className )
25279				.append( button );
25280		}
25281		else {
25282			inserter = button;
25283		}
25284
25285		this._addKey( config );
25286
25287		return {
25288			conf:         config,
25289			node:         button.get(0),
25290			inserter:     inserter,
25291			buttons:      [],
25292			inCollection: inCollection,
25293			collection:   null
25294		};
25295	},
25296
25297	/**
25298	 * Get the button object from a node (recursive)
25299	 * @param  {node} node Button node
25300	 * @param  {array} [buttons] Button array, uses base if not defined
25301	 * @return {object} Button object
25302	 * @private
25303	 */
25304	_nodeToButton: function ( node, buttons )
25305	{
25306		if ( ! buttons ) {
25307			buttons = this.s.buttons;
25308		}
25309
25310		for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
25311			if ( buttons[i].node === node ) {
25312				return buttons[i];
25313			}
25314
25315			if ( buttons[i].buttons.length ) {
25316				var ret = this._nodeToButton( node, buttons[i].buttons );
25317
25318				if ( ret ) {
25319					return ret;
25320				}
25321			}
25322		}
25323	},
25324
25325	/**
25326	 * Get container array for a button from a button node (recursive)
25327	 * @param  {node} node Button node
25328	 * @param  {array} [buttons] Button array, uses base if not defined
25329	 * @return {array} Button's host array
25330	 * @private
25331	 */
25332	_nodeToHost: function ( node, buttons )
25333	{
25334		if ( ! buttons ) {
25335			buttons = this.s.buttons;
25336		}
25337
25338		for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
25339			if ( buttons[i].node === node ) {
25340				return buttons;
25341			}
25342
25343			if ( buttons[i].buttons.length ) {
25344				var ret = this._nodeToHost( node, buttons[i].buttons );
25345
25346				if ( ret ) {
25347					return ret;
25348				}
25349			}
25350		}
25351	},
25352
25353	/**
25354	 * Handle a key press - determine if any button's key configured matches
25355	 * what was typed and trigger the action if so.
25356	 * @param  {string} character The character pressed
25357	 * @param  {object} e Key event that triggered this call
25358	 * @private
25359	 */
25360	_keypress: function ( character, e )
25361	{
25362		// Check if this button press already activated on another instance of Buttons
25363		if ( e._buttonsHandled ) {
25364			return;
25365		}
25366
25367		var run = function ( conf, node ) {
25368			if ( ! conf.key ) {
25369				return;
25370			}
25371
25372			if ( conf.key === character ) {
25373				e._buttonsHandled = true;
25374				$(node).click();
25375			}
25376			else if ( $.isPlainObject( conf.key ) ) {
25377				if ( conf.key.key !== character ) {
25378					return;
25379				}
25380
25381				if ( conf.key.shiftKey && ! e.shiftKey ) {
25382					return;
25383				}
25384
25385				if ( conf.key.altKey && ! e.altKey ) {
25386					return;
25387				}
25388
25389				if ( conf.key.ctrlKey && ! e.ctrlKey ) {
25390					return;
25391				}
25392
25393				if ( conf.key.metaKey && ! e.metaKey ) {
25394					return;
25395				}
25396
25397				// Made it this far - it is good
25398				e._buttonsHandled = true;
25399				$(node).click();
25400			}
25401		};
25402
25403		var recurse = function ( a ) {
25404			for ( var i=0, ien=a.length ; i<ien ; i++ ) {
25405				run( a[i].conf, a[i].node );
25406
25407				if ( a[i].buttons.length ) {
25408					recurse( a[i].buttons );
25409				}
25410			}
25411		};
25412
25413		recurse( this.s.buttons );
25414	},
25415
25416	/**
25417	 * Remove a key from the key listener for this instance (to be used when a
25418	 * button is removed)
25419	 * @param  {object} conf Button configuration
25420	 * @private
25421	 */
25422	_removeKey: function ( conf )
25423	{
25424		if ( conf.key ) {
25425			var character = $.isPlainObject( conf.key ) ?
25426				conf.key.key :
25427				conf.key;
25428
25429			// Remove only one character, as multiple buttons could have the
25430			// same listening key
25431			var a = this.s.listenKeys.split('');
25432			var idx = $.inArray( character, a );
25433			a.splice( idx, 1 );
25434			this.s.listenKeys = a.join('');
25435		}
25436	},
25437
25438	/**
25439	 * Resolve a button configuration
25440	 * @param  {string|function|object} conf Button config to resolve
25441	 * @return {object} Button configuration
25442	 * @private
25443	 */
25444	_resolveExtends: function ( conf )
25445	{
25446		var dt = this.s.dt;
25447		var i, ien;
25448		var toConfObject = function ( base ) {
25449			var loop = 0;
25450
25451			// Loop until we have resolved to a button configuration, or an
25452			// array of button configurations (which will be iterated
25453			// separately)
25454			while ( ! $.isPlainObject(base) && ! $.isArray(base) ) {
25455				if ( base === undefined ) {
25456					return;
25457				}
25458
25459				if ( typeof base === 'function' ) {
25460					base = base( dt, conf );
25461
25462					if ( ! base ) {
25463						return false;
25464					}
25465				}
25466				else if ( typeof base === 'string' ) {
25467					if ( ! _dtButtons[ base ] ) {
25468						throw 'Unknown button type: '+base;
25469					}
25470
25471					base = _dtButtons[ base ];
25472				}
25473
25474				loop++;
25475				if ( loop > 30 ) {
25476					// Protect against misconfiguration killing the browser
25477					throw 'Buttons: Too many iterations';
25478				}
25479			}
25480
25481			return $.isArray( base ) ?
25482				base :
25483				$.extend( {}, base );
25484		};
25485
25486		conf = toConfObject( conf );
25487
25488		while ( conf && conf.extend ) {
25489			// Use `toConfObject` in case the button definition being extended
25490			// is itself a string or a function
25491			if ( ! _dtButtons[ conf.extend ] ) {
25492				throw 'Cannot extend unknown button type: '+conf.extend;
25493			}
25494
25495			var objArray = toConfObject( _dtButtons[ conf.extend ] );
25496			if ( $.isArray( objArray ) ) {
25497				return objArray;
25498			}
25499			else if ( ! objArray ) {
25500				// This is a little brutal as it might be possible to have a
25501				// valid button without the extend, but if there is no extend
25502				// then the host button would be acting in an undefined state
25503				return false;
25504			}
25505
25506			// Stash the current class name
25507			var originalClassName = objArray.className;
25508
25509			conf = $.extend( {}, objArray, conf );
25510
25511			// The extend will have overwritten the original class name if the
25512			// `conf` object also assigned a class, but we want to concatenate
25513			// them so they are list that is combined from all extended buttons
25514			if ( originalClassName && conf.className !== originalClassName ) {
25515				conf.className = originalClassName+' '+conf.className;
25516			}
25517
25518			// Buttons to be added to a collection  -gives the ability to define
25519			// if buttons should be added to the start or end of a collection
25520			var postfixButtons = conf.postfixButtons;
25521			if ( postfixButtons ) {
25522				if ( ! conf.buttons ) {
25523					conf.buttons = [];
25524				}
25525
25526				for ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {
25527					conf.buttons.push( postfixButtons[i] );
25528				}
25529
25530				conf.postfixButtons = null;
25531			}
25532
25533			var prefixButtons = conf.prefixButtons;
25534			if ( prefixButtons ) {
25535				if ( ! conf.buttons ) {
25536					conf.buttons = [];
25537				}
25538
25539				for ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {
25540					conf.buttons.splice( i, 0, prefixButtons[i] );
25541				}
25542
25543				conf.prefixButtons = null;
25544			}
25545
25546			// Although we want the `conf` object to overwrite almost all of
25547			// the properties of the object being extended, the `extend`
25548			// property should come from the object being extended
25549			conf.extend = objArray.extend;
25550		}
25551
25552		return conf;
25553	}
25554} );
25555
25556
25557
25558/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
25559 * Statics
25560 */
25561
25562/**
25563 * Show / hide a background layer behind a collection
25564 * @param  {boolean} Flag to indicate if the background should be shown or
25565 *   hidden 
25566 * @param  {string} Class to assign to the background
25567 * @static
25568 */
25569Buttons.background = function ( show, className, fade, insertPoint ) {
25570	if ( fade === undefined ) {
25571		fade = 400;
25572	}
25573	if ( ! insertPoint ) {
25574		insertPoint = document.body;
25575	}
25576
25577	if ( show ) {
25578		$('<div/>')
25579			.addClass( className )
25580			.css( 'display', 'none' )
25581			.insertAfter( insertPoint )
25582			.fadeIn( fade );
25583	}
25584	else {
25585		$('div.'+className)
25586			.fadeOut( fade, function () {
25587				$(this)
25588					.removeClass( className )
25589					.remove();
25590			} );
25591	}
25592};
25593
25594/**
25595 * Instance selector - select Buttons instances based on an instance selector
25596 * value from the buttons assigned to a DataTable. This is only useful if
25597 * multiple instances are attached to a DataTable.
25598 * @param  {string|int|array} Instance selector - see `instance-selector`
25599 *   documentation on the DataTables site
25600 * @param  {array} Button instance array that was attached to the DataTables
25601 *   settings object
25602 * @return {array} Buttons instances
25603 * @static
25604 */
25605Buttons.instanceSelector = function ( group, buttons )
25606{
25607	if ( ! group ) {
25608		return $.map( buttons, function ( v ) {
25609			return v.inst;
25610		} );
25611	}
25612
25613	var ret = [];
25614	var names = $.map( buttons, function ( v ) {
25615		return v.name;
25616	} );
25617
25618	// Flatten the group selector into an array of single options
25619	var process = function ( input ) {
25620		if ( $.isArray( input ) ) {
25621			for ( var i=0, ien=input.length ; i<ien ; i++ ) {
25622				process( input[i] );
25623			}
25624			return;
25625		}
25626
25627		if ( typeof input === 'string' ) {
25628			if ( input.indexOf( ',' ) !== -1 ) {
25629				// String selector, list of names
25630				process( input.split(',') );
25631			}
25632			else {
25633				// String selector individual name
25634				var idx = $.inArray( $.trim(input), names );
25635
25636				if ( idx !== -1 ) {
25637					ret.push( buttons[ idx ].inst );
25638				}
25639			}
25640		}
25641		else if ( typeof input === 'number' ) {
25642			// Index selector
25643			ret.push( buttons[ input ].inst );
25644		}
25645	};
25646	
25647	process( group );
25648
25649	return ret;
25650};
25651
25652/**
25653 * Button selector - select one or more buttons from a selector input so some
25654 * operation can be performed on them.
25655 * @param  {array} Button instances array that the selector should operate on
25656 * @param  {string|int|node|jQuery|array} Button selector - see
25657 *   `button-selector` documentation on the DataTables site
25658 * @return {array} Array of objects containing `inst` and `idx` properties of
25659 *   the selected buttons so you know which instance each button belongs to.
25660 * @static
25661 */
25662Buttons.buttonSelector = function ( insts, selector )
25663{
25664	var ret = [];
25665	var nodeBuilder = function ( a, buttons, baseIdx ) {
25666		var button;
25667		var idx;
25668
25669		for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
25670			button = buttons[i];
25671
25672			if ( button ) {
25673				idx = baseIdx !== undefined ?
25674					baseIdx+i :
25675					i+'';
25676
25677				a.push( {
25678					node: button.node,
25679					name: button.conf.name,
25680					idx:  idx
25681				} );
25682
25683				if ( button.buttons ) {
25684					nodeBuilder( a, button.buttons, idx+'-' );
25685				}
25686			}
25687		}
25688	};
25689
25690	var run = function ( selector, inst ) {
25691		var i, ien;
25692		var buttons = [];
25693		nodeBuilder( buttons, inst.s.buttons );
25694
25695		var nodes = $.map( buttons, function (v) {
25696			return v.node;
25697		} );
25698
25699		if ( $.isArray( selector ) || selector instanceof $ ) {
25700			for ( i=0, ien=selector.length ; i<ien ; i++ ) {
25701				run( selector[i], inst );
25702			}
25703			return;
25704		}
25705
25706		if ( selector === null || selector === undefined || selector === '*' ) {
25707			// Select all
25708			for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
25709				ret.push( {
25710					inst: inst,
25711					node: buttons[i].node
25712				} );
25713			}
25714		}
25715		else if ( typeof selector === 'number' ) {
25716			// Main button index selector
25717			ret.push( {
25718				inst: inst,
25719				node: inst.s.buttons[ selector ].node
25720			} );
25721		}
25722		else if ( typeof selector === 'string' ) {
25723			if ( selector.indexOf( ',' ) !== -1 ) {
25724				// Split
25725				var a = selector.split(',');
25726
25727				for ( i=0, ien=a.length ; i<ien ; i++ ) {
25728					run( $.trim(a[i]), inst );
25729				}
25730			}
25731			else if ( selector.match( /^\d+(\-\d+)*$/ ) ) {
25732				// Sub-button index selector
25733				var indexes = $.map( buttons, function (v) {
25734					return v.idx;
25735				} );
25736
25737				ret.push( {
25738					inst: inst,
25739					node: buttons[ $.inArray( selector, indexes ) ].node
25740				} );
25741			}
25742			else if ( selector.indexOf( ':name' ) !== -1 ) {
25743				// Button name selector
25744				var name = selector.replace( ':name', '' );
25745
25746				for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
25747					if ( buttons[i].name === name ) {
25748						ret.push( {
25749							inst: inst,
25750							node: buttons[i].node
25751						} );
25752					}
25753				}
25754			}
25755			else {
25756				// jQuery selector on the nodes
25757				$( nodes ).filter( selector ).each( function () {
25758					ret.push( {
25759						inst: inst,
25760						node: this
25761					} );
25762				} );
25763			}
25764		}
25765		else if ( typeof selector === 'object' && selector.nodeName ) {
25766			// Node selector
25767			var idx = $.inArray( selector, nodes );
25768
25769			if ( idx !== -1 ) {
25770				ret.push( {
25771					inst: inst,
25772					node: nodes[ idx ]
25773				} );
25774			}
25775		}
25776	};
25777
25778
25779	for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
25780		var inst = insts[i];
25781
25782		run( selector, inst );
25783	}
25784
25785	return ret;
25786};
25787
25788
25789/**
25790 * Buttons defaults. For full documentation, please refer to the docs/option
25791 * directory or the DataTables site.
25792 * @type {Object}
25793 * @static
25794 */
25795Buttons.defaults = {
25796	buttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],
25797	name: 'main',
25798	tabIndex: 0,
25799	dom: {
25800		container: {
25801			tag: 'div',
25802			className: 'dt-buttons'
25803		},
25804		collection: {
25805			tag: 'div',
25806			className: 'dt-button-collection'
25807		},
25808		button: {
25809			// Flash buttons will not work with `<button>` in IE - it has to be `<a>`
25810			tag: 'ActiveXObject' in window ?
25811				'a' :
25812				'button',
25813			className: 'dt-button',
25814			active: 'active',
25815			disabled: 'disabled'
25816		},
25817		buttonLiner: {
25818			tag: 'span',
25819			className: ''
25820		}
25821	}
25822};
25823
25824/**
25825 * Version information
25826 * @type {string}
25827 * @static
25828 */
25829Buttons.version = '1.5.4';
25830
25831
25832$.extend( _dtButtons, {
25833	collection: {
25834		text: function ( dt ) {
25835			return dt.i18n( 'buttons.collection', 'Collection' );
25836		},
25837		className: 'buttons-collection',
25838		action: function ( e, dt, button, config ) {
25839			var host = button;
25840			var collectionParent = $(button).parents('div.dt-button-collection');
25841			var hostPosition = host.position();
25842			var tableContainer = $( dt.table().container() );
25843			var multiLevel = false;
25844			var insertPoint = host;
25845
25846			// Remove any old collection
25847			if ( collectionParent.length ) {
25848				multiLevel = $('.dt-button-collection').position();
25849				insertPoint = collectionParent;
25850				$('body').trigger( 'click.dtb-collection' );
25851			}
25852
25853			if ( insertPoint.parents('body')[0] !== document.body ) {
25854				insertPoint = document.body.lastChild;
25855			}
25856
25857			config._collection.find('.dt-button-collection-title').remove();
25858			config._collection.prepend('<div class="dt-button-collection-title">'+config.collectionTitle+'</div>');
25859
25860			config._collection
25861				.addClass( config.collectionLayout )
25862				.css( 'display', 'none' )
25863				.insertAfter( insertPoint )
25864				.fadeIn( config.fade );
25865
25866			var position = config._collection.css( 'position' );
25867
25868			if ( multiLevel && position === 'absolute' ) {
25869				config._collection.css( {
25870					top: multiLevel.top,
25871					left: multiLevel.left
25872				} );
25873			}
25874			else if ( position === 'absolute' ) {
25875				config._collection.css( {
25876					top: hostPosition.top + host.outerHeight(),
25877					left: hostPosition.left
25878				} );
25879
25880				// calculate overflow when positioned beneath
25881				var tableBottom = tableContainer.offset().top + tableContainer.height();
25882				var listBottom = hostPosition.top + host.outerHeight() + config._collection.outerHeight();
25883				var bottomOverflow = listBottom - tableBottom;
25884				
25885				// calculate overflow when positioned above
25886				var listTop = hostPosition.top - config._collection.outerHeight();
25887				var tableTop = tableContainer.offset().top;
25888				var topOverflow = tableTop - listTop;
25889				
25890				// if bottom overflow is larger, move to the top because it fits better, or if dropup is requested
25891				if (bottomOverflow > topOverflow || config.dropup) {
25892					config._collection.css( 'top', hostPosition.top - config._collection.outerHeight() - 5);
25893				}
25894
25895				// Right alignment is enabled on a class, e.g. bootstrap:
25896				// $.fn.dataTable.Buttons.defaults.dom.collection.className += " dropdown-menu-right"; 
25897				if ( config._collection.hasClass( config.rightAlignClassName ) ) {
25898					config._collection.css( 'left', hostPosition.left + host.outerWidth() - config._collection.outerWidth() );
25899				}
25900
25901				// Right alignment in table container
25902				var listRight = hostPosition.left + config._collection.outerWidth();
25903				var tableRight = tableContainer.offset().left + tableContainer.width();
25904				if ( listRight > tableRight ) {
25905					config._collection.css( 'left', hostPosition.left - ( listRight - tableRight ) );
25906				}
25907
25908				// Right alignment to window
25909				var listOffsetRight = host.offset().left + config._collection.outerWidth();
25910				if ( listOffsetRight > $(window).width() ) {
25911					config._collection.css( 'left', hostPosition.left - (listOffsetRight-$(window).width()) );
25912				}
25913			}
25914			else {
25915				// Fix position - centre on screen
25916				var top = config._collection.height() / 2;
25917				if ( top > $(window).height() / 2 ) {
25918					top = $(window).height() / 2;
25919				}
25920
25921				config._collection.css( 'marginTop', top*-1 );
25922			}
25923
25924			if ( config.background ) {
25925				Buttons.background( true, config.backgroundClassName, config.fade, insertPoint );
25926			}
25927
25928			var close = function () {
25929				config._collection
25930				.fadeOut( config.fade, function () {
25931					config._collection.detach();
25932				} );
25933
25934				$('div.dt-button-background').off( 'click.dtb-collection' );
25935				Buttons.background( false, config.backgroundClassName, config.fade, insertPoint );
25936
25937				$('body').off( '.dtb-collection' );
25938				dt.off( 'buttons-action.b-internal' );
25939			};
25940
25941			// Need to break the 'thread' for the collection button being
25942			// activated by a click - it would also trigger this event
25943			setTimeout( function () {
25944				// This is bonkers, but if we don't have a click listener on the
25945				// background element, iOS Safari will ignore the body click
25946				// listener below. An empty function here is all that is
25947				// required to make it work...
25948				$('div.dt-button-background').on( 'click.dtb-collection', function () {} );
25949
25950				$('body')
25951					.on( 'click.dtb-collection', function (e) {
25952						// andSelf is deprecated in jQ1.8, but we want 1.7 compat
25953						var back = $.fn.addBack ? 'addBack' : 'andSelf';
25954
25955						if ( ! $(e.target).parents()[back]().filter( config._collection ).length ) {
25956							close();
25957						}
25958					} )
25959					.on( 'keyup.dtb-collection', function (e) {
25960						if ( e.keyCode === 27 ) {
25961							close();
25962						}
25963					} );
25964
25965				if ( config.autoClose ) {
25966					dt.on( 'buttons-action.b-internal', function () {
25967						close();
25968					} );
25969				}
25970			}, 10 );
25971		},
25972		background: true,
25973		collectionLayout: '',
25974		collectionTitle: '',
25975		backgroundClassName: 'dt-button-background',
25976		rightAlignClassName: 'dt-button-right',
25977		autoClose: false,
25978		fade: 400,
25979		attr: {
25980			'aria-haspopup': true
25981		}
25982	},
25983	copy: function ( dt, conf ) {
25984		if ( _dtButtons.copyHtml5 ) {
25985			return 'copyHtml5';
25986		}
25987		if ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) {
25988			return 'copyFlash';
25989		}
25990	},
25991	csv: function ( dt, conf ) {
25992		// Common option that will use the HTML5 or Flash export buttons
25993		if ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {
25994			return 'csvHtml5';
25995		}
25996		if ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) {
25997			return 'csvFlash';
25998		}
25999	},
26000	excel: function ( dt, conf ) {
26001		// Common option that will use the HTML5 or Flash export buttons
26002		if ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {
26003			return 'excelHtml5';
26004		}
26005		if ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) {
26006			return 'excelFlash';
26007		}
26008	},
26009	pdf: function ( dt, conf ) {
26010		// Common option that will use the HTML5 or Flash export buttons
26011		if ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {
26012			return 'pdfHtml5';
26013		}
26014		if ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) {
26015			return 'pdfFlash';
26016		}
26017	},
26018	pageLength: function ( dt ) {
26019		var lengthMenu = dt.settings()[0].aLengthMenu;
26020		var vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu;
26021		var lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu;
26022		var text = function ( dt ) {
26023			return dt.i18n( 'buttons.pageLength', {
26024				"-1": 'Show all rows',
26025				_:    'Show %d rows'
26026			}, dt.page.len() );
26027		};
26028
26029		return {
26030			extend: 'collection',
26031			text: text,
26032			className: 'buttons-page-length',
26033			autoClose: true,
26034			buttons: $.map( vals, function ( val, i ) {
26035				return {
26036					text: lang[i],
26037					className: 'button-page-length',
26038					action: function ( e, dt ) {
26039						dt.page.len( val ).draw();
26040					},
26041					init: function ( dt, node, conf ) {
26042						var that = this;
26043						var fn = function () {
26044							that.active( dt.page.len() === val );
26045						};
26046
26047						dt.on( 'length.dt'+conf.namespace, fn );
26048						fn();
26049					},
26050					destroy: function ( dt, node, conf ) {
26051						dt.off( 'length.dt'+conf.namespace );
26052					}
26053				};
26054			} ),
26055			init: function ( dt, node, conf ) {
26056				var that = this;
26057				dt.on( 'length.dt'+conf.namespace, function () {
26058					that.text( text( dt ) );
26059				} );
26060			},
26061			destroy: function ( dt, node, conf ) {
26062				dt.off( 'length.dt'+conf.namespace );
26063			}
26064		};
26065	}
26066} );
26067
26068
26069/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26070 * DataTables API
26071 *
26072 * For complete documentation, please refer to the docs/api directory or the
26073 * DataTables site
26074 */
26075
26076// Buttons group and individual button selector
26077DataTable.Api.register( 'buttons()', function ( group, selector ) {
26078	// Argument shifting
26079	if ( selector === undefined ) {
26080		selector = group;
26081		group = undefined;
26082	}
26083
26084	this.selector.buttonGroup = group;
26085
26086	var res = this.iterator( true, 'table', function ( ctx ) {
26087		if ( ctx._buttons ) {
26088			return Buttons.buttonSelector(
26089				Buttons.instanceSelector( group, ctx._buttons ),
26090				selector
26091			);
26092		}
26093	}, true );
26094
26095	res._groupSelector = group;
26096	return res;
26097} );
26098
26099// Individual button selector
26100DataTable.Api.register( 'button()', function ( group, selector ) {
26101	// just run buttons() and truncate
26102	var buttons = this.buttons( group, selector );
26103
26104	if ( buttons.length > 1 ) {
26105		buttons.splice( 1, buttons.length );
26106	}
26107
26108	return buttons;
26109} );
26110
26111// Active buttons
26112DataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) {
26113	if ( flag === undefined ) {
26114		return this.map( function ( set ) {
26115			return set.inst.active( set.node );
26116		} );
26117	}
26118
26119	return this.each( function ( set ) {
26120		set.inst.active( set.node, flag );
26121	} );
26122} );
26123
26124// Get / set button action
26125DataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {
26126	if ( action === undefined ) {
26127		return this.map( function ( set ) {
26128			return set.inst.action( set.node );
26129		} );
26130	}
26131
26132	return this.each( function ( set ) {
26133		set.inst.action( set.node, action );
26134	} );
26135} );
26136
26137// Enable / disable buttons
26138DataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {
26139	return this.each( function ( set ) {
26140		set.inst.enable( set.node, flag );
26141	} );
26142} );
26143
26144// Disable buttons
26145DataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {
26146	return this.each( function ( set ) {
26147		set.inst.disable( set.node );
26148	} );
26149} );
26150
26151// Get button nodes
26152DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {
26153	var jq = $();
26154
26155	// jQuery will automatically reduce duplicates to a single entry
26156	$( this.each( function ( set ) {
26157		jq = jq.add( set.inst.node( set.node ) );
26158	} ) );
26159
26160	return jq;
26161} );
26162
26163// Get / set button processing state
26164DataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) {
26165	if ( flag === undefined ) {
26166		return this.map( function ( set ) {
26167			return set.inst.processing( set.node );
26168		} );
26169	}
26170
26171	return this.each( function ( set ) {
26172		set.inst.processing( set.node, flag );
26173	} );
26174} );
26175
26176// Get / set button text (i.e. the button labels)
26177DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {
26178	if ( label === undefined ) {
26179		return this.map( function ( set ) {
26180			return set.inst.text( set.node );
26181		} );
26182	}
26183
26184	return this.each( function ( set ) {
26185		set.inst.text( set.node, label );
26186	} );
26187} );
26188
26189// Trigger a button's action
26190DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {
26191	return this.each( function ( set ) {
26192		set.inst.node( set.node ).trigger( 'click' );
26193	} );
26194} );
26195
26196// Get the container elements
26197DataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () {
26198	var jq = $();
26199	var groupSelector = this._groupSelector;
26200
26201	// We need to use the group selector directly, since if there are no buttons
26202	// the result set will be empty
26203	this.iterator( true, 'table', function ( ctx ) {
26204		if ( ctx._buttons ) {
26205			var insts = Buttons.instanceSelector( groupSelector, ctx._buttons );
26206
26207			for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
26208				jq = jq.add( insts[i].container() );
26209			}
26210		}
26211	} );
26212
26213	return jq;
26214} );
26215
26216// Add a new button
26217DataTable.Api.register( 'button().add()', function ( idx, conf ) {
26218	var ctx = this.context;
26219
26220	// Don't use `this` as it could be empty - select the instances directly
26221	if ( ctx.length ) {
26222		var inst = Buttons.instanceSelector( this._groupSelector, ctx[0]._buttons );
26223
26224		if ( inst.length ) {
26225			inst[0].add( conf, idx );
26226		}
26227	}
26228
26229	return this.button( this._groupSelector, idx );
26230} );
26231
26232// Destroy the button sets selected
26233DataTable.Api.register( 'buttons().destroy()', function () {
26234	this.pluck( 'inst' ).unique().each( function ( inst ) {
26235		inst.destroy();
26236	} );
26237
26238	return this;
26239} );
26240
26241// Remove a button
26242DataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {
26243	this.each( function ( set ) {
26244		set.inst.remove( set.node );
26245	} );
26246
26247	return this;
26248} );
26249
26250// Information box that can be used by buttons
26251var _infoTimer;
26252DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
26253	var that = this;
26254
26255	if ( title === false ) {
26256		$('#datatables_buttons_info').fadeOut( function () {
26257			$(this).remove();
26258		} );
26259		clearTimeout( _infoTimer );
26260		_infoTimer = null;
26261
26262		return this;
26263	}
26264
26265	if ( _infoTimer ) {
26266		clearTimeout( _infoTimer );
26267	}
26268
26269	if ( $('#datatables_buttons_info').length ) {
26270		$('#datatables_buttons_info').remove();
26271	}
26272
26273	title = title ? '<h2>'+title+'</h2>' : '';
26274
26275	$('<div id="datatables_buttons_info" class="dt-button-info"/>')
26276		.html( title )
26277		.append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )
26278		.css( 'display', 'none' )
26279		.appendTo( 'body' )
26280		.fadeIn();
26281
26282	if ( time !== undefined && time !== 0 ) {
26283		_infoTimer = setTimeout( function () {
26284			that.buttons.info( false );
26285		}, time );
26286	}
26287
26288	return this;
26289} );
26290
26291// Get data from the table for export - this is common to a number of plug-in
26292// buttons so it is included in the Buttons core library
26293DataTable.Api.register( 'buttons.exportData()', function ( options ) {
26294	if ( this.context.length ) {
26295		return _exportData( new DataTable.Api( this.context[0] ), options );
26296	}
26297} );
26298
26299// Get information about the export that is common to many of the export data
26300// types (DRY)
26301DataTable.Api.register( 'buttons.exportInfo()', function ( conf ) {
26302	if ( ! conf ) {
26303		conf = {};
26304	}
26305
26306	return {
26307		filename: _filename( conf ),
26308		title: _title( conf ),
26309		messageTop: _message(this, conf.message || conf.messageTop, 'top'),
26310		messageBottom: _message(this, conf.messageBottom, 'bottom')
26311	};
26312} );
26313
26314
26315
26316/**
26317 * Get the file name for an exported file.
26318 *
26319 * @param {object}	config Button configuration
26320 * @param {boolean} incExtension Include the file name extension
26321 */
26322var _filename = function ( config )
26323{
26324	// Backwards compatibility
26325	var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined && config.title !== null && config.title !== '' ?
26326		config.title :
26327		config.filename;
26328
26329	if ( typeof filename === 'function' ) {
26330		filename = filename();
26331	}
26332
26333	if ( filename === undefined || filename === null ) {
26334		return null;
26335	}
26336
26337	if ( filename.indexOf( '*' ) !== -1 ) {
26338		filename = $.trim( filename.replace( '*', $('head > title').text() ) );
26339	}
26340
26341	// Strip characters which the OS will object to
26342	filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
26343
26344	var extension = _stringOrFunction( config.extension );
26345	if ( ! extension ) {
26346		extension = '';
26347	}
26348
26349	return filename + extension;
26350};
26351
26352/**
26353 * Simply utility method to allow parameters to be given as a function
26354 *
26355 * @param {undefined|string|function} option Option
26356 * @return {null|string} Resolved value
26357 */
26358var _stringOrFunction = function ( option )
26359{
26360	if ( option === null || option === undefined ) {
26361		return null;
26362	}
26363	else if ( typeof option === 'function' ) {
26364		return option();
26365	}
26366	return option;
26367};
26368
26369/**
26370 * Get the title for an exported file.
26371 *
26372 * @param {object} config	Button configuration
26373 */
26374var _title = function ( config )
26375{
26376	var title = _stringOrFunction( config.title );
26377
26378	return title === null ?
26379		null : title.indexOf( '*' ) !== -1 ?
26380			title.replace( '*', $('head > title').text() || 'Exported data' ) :
26381			title;
26382};
26383
26384var _message = function ( dt, option, position )
26385{
26386	var message = _stringOrFunction( option );
26387	if ( message === null ) {
26388		return null;
26389	}
26390
26391	var caption = $('caption', dt.table().container()).eq(0);
26392	if ( message === '*' ) {
26393		var side = caption.css( 'caption-side' );
26394		if ( side !== position ) {
26395			return null;
26396		}
26397
26398		return caption.length ?
26399			caption.text() :
26400			'';
26401	}
26402
26403	return message;
26404};
26405
26406
26407
26408
26409
26410
26411
26412var _exportTextarea = $('<textarea/>')[0];
26413var _exportData = function ( dt, inOpts )
26414{
26415	var config = $.extend( true, {}, {
26416		rows:           null,
26417		columns:        '',
26418		modifier:       {
26419			search: 'applied',
26420			order:  'applied'
26421		},
26422		orthogonal:     'display',
26423		stripHtml:      true,
26424		stripNewlines:  true,
26425		decodeEntities: true,
26426		trim:           true,
26427		format:         {
26428			header: function ( d ) {
26429				return strip( d );
26430			},
26431			footer: function ( d ) {
26432				return strip( d );
26433			},
26434			body: function ( d ) {
26435				return strip( d );
26436			}
26437		},
26438		customizeData: null
26439	}, inOpts );
26440
26441	var strip = function ( str ) {
26442		if ( typeof str !== 'string' ) {
26443			return str;
26444		}
26445
26446		// Always remove script tags
26447		str = str.replace( /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '' );
26448
26449		// Always remove comments
26450		str = str.replace( /<!\-\-.*?\-\->/g, '' );
26451
26452		if ( config.stripHtml ) {
26453			str = str.replace( /<[^>]*>/g, '' );
26454		}
26455
26456		if ( config.trim ) {
26457			str = str.replace( /^\s+|\s+$/g, '' );
26458		}
26459
26460		if ( config.stripNewlines ) {
26461			str = str.replace( /\n/g, ' ' );
26462		}
26463
26464		if ( config.decodeEntities ) {
26465			_exportTextarea.innerHTML = str;
26466			str = _exportTextarea.value;
26467		}
26468
26469		return str;
26470	};
26471
26472
26473	var header = dt.columns( config.columns ).indexes().map( function (idx) {
26474		var el = dt.column( idx ).header();
26475		return config.format.header( el.innerHTML, idx, el );
26476	} ).toArray();
26477
26478	var footer = dt.table().footer() ?
26479		dt.columns( config.columns ).indexes().map( function (idx) {
26480			var el = dt.column( idx ).footer();
26481			return config.format.footer( el ? el.innerHTML : '', idx, el );
26482		} ).toArray() :
26483		null;
26484	
26485	// If Select is available on this table, and any rows are selected, limit the export
26486	// to the selected rows. If no rows are selected, all rows will be exported. Specify
26487	// a `selected` modifier to control directly.
26488	var modifier = $.extend( {}, config.modifier );
26489	if ( dt.select && typeof dt.select.info === 'function' && modifier.selected === undefined ) {
26490		if ( dt.rows( config.rows, $.extend( { selected: true }, modifier ) ).any() ) {
26491			$.extend( modifier, { selected: true } )
26492		}
26493	}
26494
26495	var rowIndexes = dt.rows( config.rows, modifier ).indexes().toArray();
26496	var selectedCells = dt.cells( rowIndexes, config.columns );
26497	var cells = selectedCells
26498		.render( config.orthogonal )
26499		.toArray();
26500	var cellNodes = selectedCells
26501		.nodes()
26502		.toArray();
26503
26504	var columns = header.length;
26505	var rows = columns > 0 ? cells.length / columns : 0;
26506	var body = [];
26507	var cellCounter = 0;
26508
26509	for ( var i=0, ien=rows ; i<ien ; i++ ) {
26510		var row = [ columns ];
26511
26512		for ( var j=0 ; j<columns ; j++ ) {
26513			row[j] = config.format.body( cells[ cellCounter ], i, j, cellNodes[ cellCounter ] );
26514			cellCounter++;
26515		}
26516
26517		body[i] = row;
26518	}
26519
26520	var data = {
26521		header: header,
26522		footer: footer,
26523		body:   body
26524	};
26525
26526	if ( config.customizeData ) {
26527		config.customizeData( data );
26528	}
26529
26530	return data;
26531};
26532
26533
26534/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26535 * DataTables interface
26536 */
26537
26538// Attach to DataTables objects for global access
26539$.fn.dataTable.Buttons = Buttons;
26540$.fn.DataTable.Buttons = Buttons;
26541
26542
26543
26544// DataTables creation - check if the buttons have been defined for this table,
26545// they will have been if the `B` option was used in `dom`, otherwise we should
26546// create the buttons instance here so they can be inserted into the document
26547// using the API. Listen for `init` for compatibility with pre 1.10.10, but to
26548// be removed in future.
26549$(document).on( 'init.dt plugin-init.dt', function (e, settings) {
26550	if ( e.namespace !== 'dt' ) {
26551		return;
26552	}
26553
26554	var opts = settings.oInit.buttons || DataTable.defaults.buttons;
26555
26556	if ( opts && ! settings._buttons ) {
26557		new Buttons( settings, opts ).container();
26558	}
26559} );
26560
26561// DataTables `dom` feature option
26562DataTable.ext.feature.push( {
26563	fnInit: function( settings ) {
26564		var api = new DataTable.Api( settings );
26565		var opts = api.init().buttons || DataTable.defaults.buttons;
26566
26567		return new Buttons( api, opts ).container();
26568	},
26569	cFeature: "B"
26570} );
26571
26572
26573return Buttons;
26574}));
26575
26576
26577/*! Bootstrap integration for DataTables' Buttons
26578 * ©2016 SpryMedia Ltd - datatables.net/license
26579 */
26580
26581(function( factory ){
26582	if ( typeof define === 'function' && define.amd ) {
26583		// AMD
26584		define( ['jquery', 'datatables.net-bs', 'datatables.net-buttons'], function ( $ ) {
26585			return factory( $, window, document );
26586		} );
26587	}
26588	else if ( typeof exports === 'object' ) {
26589		// CommonJS
26590		module.exports = function (root, $) {
26591			if ( ! root ) {
26592				root = window;
26593			}
26594
26595			if ( ! $ || ! $.fn.dataTable ) {
26596				$ = require('datatables.net-bs')(root, $).$;
26597			}
26598
26599			if ( ! $.fn.dataTable.Buttons ) {
26600				require('datatables.net-buttons')(root, $);
26601			}
26602
26603			return factory( $, root, root.document );
26604		};
26605	}
26606	else {
26607		// Browser
26608		factory( jQuery, window, document );
26609	}
26610}(function( $, window, document, undefined ) {
26611'use strict';
26612var DataTable = $.fn.dataTable;
26613
26614
26615$.extend( true, DataTable.Buttons.defaults, {
26616	dom: {
26617		container: {
26618			className: 'dt-buttons btn-group'
26619		},
26620		button: {
26621			className: 'btn btn-default'
26622		},
26623		collection: {
26624			tag: 'ul',
26625			className: 'dt-button-collection dropdown-menu',
26626			button: {
26627				tag: 'li',
26628				className: 'dt-button',
26629				active: 'active',
26630				disabled: 'disabled'
26631			},
26632			buttonLiner: {
26633				tag: 'a',
26634				className: ''
26635			}
26636		}
26637	}
26638} );
26639
26640DataTable.ext.buttons.collection.text = function ( dt ) {
26641	return dt.i18n('buttons.collection', 'Collection <span class="caret"/>');
26642};
26643
26644
26645return DataTable.Buttons;
26646}));
26647
26648
26649/*!
26650 * Column visibility buttons for Buttons and DataTables.
26651 * 2016 SpryMedia Ltd - datatables.net/license
26652 */
26653
26654(function( factory ){
26655	if ( typeof define === 'function' && define.amd ) {
26656		// AMD
26657		define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
26658			return factory( $, window, document );
26659		} );
26660	}
26661	else if ( typeof exports === 'object' ) {
26662		// CommonJS
26663		module.exports = function (root, $) {
26664			if ( ! root ) {
26665				root = window;
26666			}
26667
26668			if ( ! $ || ! $.fn.dataTable ) {
26669				$ = require('datatables.net')(root, $).$;
26670			}
26671
26672			if ( ! $.fn.dataTable.Buttons ) {
26673				require('datatables.net-buttons')(root, $);
26674			}
26675
26676			return factory( $, root, root.document );
26677		};
26678	}
26679	else {
26680		// Browser
26681		factory( jQuery, window, document );
26682	}
26683}(function( $, window, document, undefined ) {
26684'use strict';
26685var DataTable = $.fn.dataTable;
26686
26687
26688$.extend( DataTable.ext.buttons, {
26689	// A collection of column visibility buttons
26690	colvis: function ( dt, conf ) {
26691		return {
26692			extend: 'collection',
26693			text: function ( dt ) {
26694				return dt.i18n( 'buttons.colvis', 'Column visibility' );
26695			},
26696			className: 'buttons-colvis',
26697			buttons: [ {
26698				extend: 'columnsToggle',
26699				columns: conf.columns,
26700				columnText: conf.columnText
26701			} ]
26702		};
26703	},
26704
26705	// Selected columns with individual buttons - toggle column visibility
26706	columnsToggle: function ( dt, conf ) {
26707		var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {
26708			return {
26709				extend: 'columnToggle',
26710				columns: idx,
26711				columnText: conf.columnText
26712			};
26713		} ).toArray();
26714
26715		return columns;
26716	},
26717
26718	// Single button to toggle column visibility
26719	columnToggle: function ( dt, conf ) {
26720		return {
26721			extend: 'columnVisibility',
26722			columns: conf.columns,
26723			columnText: conf.columnText
26724		};
26725	},
26726
26727	// Selected columns with individual buttons - set column visibility
26728	columnsVisibility: function ( dt, conf ) {
26729		var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {
26730			return {
26731				extend: 'columnVisibility',
26732				columns: idx,
26733				visibility: conf.visibility,
26734				columnText: conf.columnText
26735			};
26736		} ).toArray();
26737
26738		return columns;
26739	},
26740
26741	// Single button to set column visibility
26742	columnVisibility: {
26743		columns: undefined, // column selector
26744		text: function ( dt, button, conf ) {
26745			return conf._columnText( dt, conf );
26746		},
26747		className: 'buttons-columnVisibility',
26748		action: function ( e, dt, button, conf ) {
26749			var col = dt.columns( conf.columns );
26750			var curr = col.visible();
26751
26752			col.visible( conf.visibility !== undefined ?
26753				conf.visibility :
26754				! (curr.length ? curr[0] : false )
26755			);
26756		},
26757		init: function ( dt, button, conf ) {
26758			var that = this;
26759			button.attr( 'data-cv-idx', conf.columns );
26760
26761			dt
26762				.on( 'column-visibility.dt'+conf.namespace, function (e, settings) {
26763					if ( ! settings.bDestroying && settings.nTable == dt.settings()[0].nTable ) {
26764						that.active( dt.column( conf.columns ).visible() );
26765					}
26766				} )
26767				.on( 'column-reorder.dt'+conf.namespace, function (e, settings, details) {
26768					// Don't rename buttons based on column name if the button
26769					// controls more than one column!
26770					if ( dt.columns( conf.columns ).count() !== 1 ) {
26771						return;
26772					}
26773
26774					conf.columns = $.inArray( conf.columns, details.mapping );
26775					button.attr( 'data-cv-idx', conf.columns );
26776
26777					// Reorder buttons for new table order
26778					button
26779						.parent()
26780						.children('[data-cv-idx]')
26781						.sort( function (a, b) {
26782							return (a.getAttribute('data-cv-idx')*1) - (b.getAttribute('data-cv-idx')*1);
26783						} )
26784						.appendTo(button.parent());
26785				} );
26786
26787			this.active( dt.column( conf.columns ).visible() );
26788		},
26789		destroy: function ( dt, button, conf ) {
26790			dt
26791				.off( 'column-visibility.dt'+conf.namespace )
26792				.off( 'column-reorder.dt'+conf.namespace );
26793		},
26794
26795		_columnText: function ( dt, conf ) {
26796			// Use DataTables' internal data structure until this is presented
26797			// is a public API. The other option is to use
26798			// `$( column(col).node() ).text()` but the node might not have been
26799			// populated when Buttons is constructed.
26800			var idx = dt.column( conf.columns ).index();
26801			var title = dt.settings()[0].aoColumns[ idx ].sTitle
26802				.replace(/\n/g," ")        // remove new lines
26803				.replace(/<br\s*\/?>/gi, " ")  // replace line breaks with spaces
26804				.replace(/<select(.*?)<\/select>/g, "") // remove select tags, including options text
26805				.replace(/<!\-\-.*?\-\->/g, "") // strip HTML comments
26806				.replace(/<.*?>/g, "")   // strip HTML
26807				.replace(/^\s+|\s+$/g,""); // trim
26808
26809			return conf.columnText ?
26810				conf.columnText( dt, idx, title ) :
26811				title;
26812		}
26813	},
26814
26815
26816	colvisRestore: {
26817		className: 'buttons-colvisRestore',
26818
26819		text: function ( dt ) {
26820			return dt.i18n( 'buttons.colvisRestore', 'Restore visibility' );
26821		},
26822
26823		init: function ( dt, button, conf ) {
26824			conf._visOriginal 
26824= dt.columns().indexes().map( function ( idx ) {
26825				return dt.column( idx ).visible();
26826			} ).toArray();
26827		},
26828
26829		action: function ( e, dt, button, conf ) {
26830			dt.columns().every( function ( i ) {
26831				// Take into account that ColReorder might have disrupted our
26832				// indexes
26833				var idx = dt.colReorder && dt.colReorder.transpose ?
26834					dt.colReorder.transpose( i, 'toOriginal' ) :
26835					i;
26836
26837				this.visible( conf._visOriginal[ idx ] );
26838			} );
26839		}
26840	},
26841
26842
26843	colvisGroup: {
26844		className: 'buttons-colvisGroup',
26845
26846		action: function ( e, dt, button, conf ) {
26847			dt.columns( conf.show ).visible( true, false );
26848			dt.columns( conf.hide ).visible( false, false );
26849
26850			dt.columns.adjust();
26851		},
26852
26853		show: [],
26854
26855		hide: []
26856	}
26857} );
26858
26859
26860return DataTable.Buttons;
26861}));
26862
26863
26864/*!
26865 * HTML5 export buttons for Buttons and DataTables.
26866 * 2016 SpryMedia Ltd - datatables.net/license
26867 *
26868 * FileSaver.js (1.3.3) - MIT license
26869 * Copyright © 2016 Eli Grey - http://eligrey.com
26870 */
26871
26872(function( factory ){
26873	if ( typeof define === 'function' && define.amd ) {
26874		// AMD
26875		define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
26876			return factory( $, window, document );
26877		} );
26878	}
26879	else if ( typeof exports === 'object' ) {
26880		// CommonJS
26881		module.exports = function (root, $, jszip, pdfmake) {
26882			if ( ! root ) {
26883				root = window;
26884			}
26885
26886			if ( ! $ || ! $.fn.dataTable ) {
26887				$ = require('datatables.net')(root, $).$;
26888			}
26889
26890			if ( ! $.fn.dataTable.Buttons ) {
26891				require('datatables.net-buttons')(root, $);
26892			}
26893
26894			return factory( $, root, root.document, jszip, pdfmake );
26895		};
26896	}
26897	else {
26898		// Browser
26899		factory( jQuery, window, document );
26900	}
26901}(function( $, window, document, jszip, pdfmake, undefined ) {
26902'use strict';
26903var DataTable = $.fn.dataTable;
26904
26905// Allow the constructor to pass in JSZip and PDFMake from external requires.
26906// Otherwise, use globally defined variables, if they are available.
26907function _jsZip () {
26908	return jszip || window.JSZip;
26909}
26910function _pdfMake () {
26911	return pdfmake || window.pdfMake;
26912}
26913
26914DataTable.Buttons.pdfMake = function (_) {
26915	if ( ! _ ) {
26916		return _pdfMake();
26917	}
26918	pdfmake = m_ake;
26919}
26920
26921DataTable.Buttons.jszip = function (_) {
26922	if ( ! _ ) {
26923		return _jsZip();
26924	}
26925	jszip = _;
26926}
26927
26928
26929/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26930 * FileSaver.js dependency
26931 */
26932
26933/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
26934
26935var _saveAs = (function(view) {
26936	"use strict";
26937	// IE <10 is explicitly unsupported
26938	if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
26939		return;
26940	}
26941	var
26942		  doc = view.document
26943		  // only get URL when necessary in case Blob.js hasn't overridden it yet
26944		, get_URL = function() {
26945			return view.URL || view.webkitURL || view;
26946		}
26947		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
26948		, can_use_save_link = "download" in save_link
26949		, click = function(node) {
26950			var event = new MouseEvent("click");
26951			node.dispatchEvent(event);
26952		}
26953		, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
26954		, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
26955		, throw_outside = function(ex) {
26956			(view.setImmediate || view.setTimeout)(function() {
26957				throw ex;
26958			}, 0);
26959		}
26960		, force_saveable_type = "application/octet-stream"
26961		// the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
26962		, arbitrary_revoke_timeout = 1000 * 40 // in ms
26963		, revoke = function(file) {
26964			var revoker = function() {
26965				if (typeof file === "string") { // file is an object URL
26966					get_URL().revokeObjectURL(file);
26967				} else { // file is a File
26968					file.remove();
26969				}
26970			};
26971			setTimeout(revoker, arbitrary_revoke_timeout);
26972		}
26973		, dispatch = function(filesaver, event_types, event) {
26974			event_types = [].concat(event_types);
26975			var i = event_types.length;
26976			while (i--) {
26977				var listener = filesaver["on" + event_types[i]];
26978				if (typeof listener === "function") {
26979					try {
26980						listener.call(filesaver, event || filesaver);
26981					} catch (ex) {
26982						throw_outside(ex);
26983					}
26984				}
26985			}
26986		}
26987		, auto_bom = function(blob) {
26988			// prepend BOM for UTF-8 XML and text/* types (including HTML)
26989			// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
26990			if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
26991				return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
26992			}
26993			return blob;
26994		}
26995		, FileSaver = function(blob, name, no_auto_bom) {
26996			if (!no_auto_bom) {
26997				blob = auto_bom(blob);
26998			}
26999			// First try a.download, then web filesystem, then object URLs
27000			var
27001				  filesaver = this
27002				, type = blob.type
27003				, force = type === force_saveable_type
27004				, object_url
27005				, dispatch_all = function() {
27006					dispatch(filesaver, "writestart progress write writeend".split(" "));
27007				}
27008				// on any filesys errors revert to saving with object URLs
27009				, fs_error = function() {
27010					if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
27011						// Safari doesn't allow downloading of blob urls
27012						var reader = new FileReader();
27013						reader.onloadend = function() {
27014							var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
27015							var popup = view.open(url, '_blank');
27016							if(!popup) view.location.href = url;
27017							url=undefined; // release reference before dispatching
27018							filesaver.readyState = filesaver.DONE;
27019							dispatch_all();
27020						};
27021						reader.readAsDataURL(blob);
27022						filesaver.readyState = filesaver.INIT;
27023						return;
27024					}
27025					// don't create more object URLs than needed
27026					if (!object_url) {
27027						object_url = get_URL().createObjectURL(blob);
27028					}
27029					if (force) {
27030						view.location.href = object_url;
27031					} else {
27032						var opened = view.open(object_url, "_blank");
27033						if (!opened) {
27034							// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
27035							view.location.href = object_url;
27036						}
27037					}
27038					filesaver.readyState = filesaver.DONE;
27039					dispatch_all();
27040					revoke(object_url);
27041				}
27042			;
27043			filesaver.readyState = filesaver.INIT;
27044
27045			if (can_use_save_link) {
27046				object_url = get_URL().createObjectURL(blob);
27047				setTimeout(function() {
27048					save_link.href = object_url;
27049					save_link.download = name;
27050					click(save_link);
27051					dispatch_all();
27052					revoke(object_url);
27053					filesaver.readyState = filesaver.DONE;
27054				});
27055				return;
27056			}
27057
27058			fs_error();
27059		}
27060		, FS_proto = FileSaver.prototype
27061		, saveAs = function(blob, name, no_auto_bom) {
27062			return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
27063		}
27064	;
27065	// IE 10+ (native saveAs)
27066	if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
27067		return function(blob, name, no_auto_bom) {
27068			name = name || blob.name || "download";
27069
27070			if (!no_auto_bom) {
27071				blob = auto_bom(blob);
27072			}
27073			return navigator.msSaveOrOpenBlob(blob, name);
27074		};
27075	}
27076
27077	FS_proto.abort = function(){};
27078	FS_proto.readyState = FS_proto.INIT = 0;
27079	FS_proto.WRITING = 1;
27080	FS_proto.DONE = 2;
27081
27082	FS_proto.error =
27083	FS_proto.onwritestart =
27084	FS_proto.onprogress =
27085	FS_proto.onwrite =
27086	FS_proto.onabort =
27087	FS_proto.onerror =
27088	FS_proto.onwriteend =
27089		null;
27090
27091	return saveAs;
27092}(
27093	   typeof self !== "undefined" && self
27094	|| typeof window !== "undefined" && window
27095	|| this.content
27096));
27097
27098
27099// Expose file saver on the DataTables API. Can't attach to `DataTables.Buttons`
27100// since this file can be loaded before Button's core!
27101DataTable.fileSave = _saveAs;
27102
27103
27104/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
27105 * Local (private) functions
27106 */
27107
27108/**
27109 * Get the sheet name for Excel exports.
27110 *
27111 * @param {object}	config Button configuration
27112 */
27113var _sheetname = function ( config )
27114{
27115	var sheetName = 'Sheet1';
27116
27117	if ( config.sheetName ) {
27118		sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, '');
27119	}
27120
27121	return sheetName;
27122};
27123
27124/**
27125 * Get the newline character(s)
27126 *
27127 * @param {object}	config Button configuration
27128 * @return {string}				Newline character
27129 */
27130var _newLine = function ( config )
27131{
27132	return config.newline ?
27133		config.newline :
27134		navigator.userAgent.match(/Windows/) ?
27135			'\r\n' :
27136			'\n';
27137};
27138
27139/**
27140 * Combine the data from the `buttons.exportData` method into a string that
27141 * will be used in the export file.
27142 *
27143 * @param	{DataTable.Api} dt		 DataTables API instance
27144 * @param	{object}				config Button configuration
27145 * @return {object}							 The data to export
27146 */
27147var _exportData = function ( dt, config )
27148{
27149	var newLine = _newLine( config );
27150	var data = dt.buttons.exportData( config.exportOptions );
27151	var boundary = config.fieldBoundary;
27152	var separator = config.fieldSeparator;
27153	var reBoundary = new RegExp( boundary, 'g' );
27154	var escapeChar = config.escapeChar !== undefined ?
27155		config.escapeChar :
27156		'\\';
27157	var join = function ( a ) {
27158		var s = '';
27159
27160		// If there is a field boundary, then we might need to escape it in
27161		// the source data
27162		for ( var i=0, ien=a.length ; i<ien ; i++ ) {
27163			if ( i > 0 ) {
27164				s += separator;
27165			}
27166
27167			s += boundary ?
27168				boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :
27169				a[i];
27170		}
27171
27172		return s;
27173	};
27174
27175	var header = config.header ? join( data.header )+newLine : '';
27176	var footer = config.footer && data.footer ? newLine+join( data.footer ) : '';
27177	var body = [];
27178
27179	for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
27180		body.push( join( data.body[i] ) );
27181	}
27182
27183	return {
27184		str: header + body.join( newLine ) + footer,
27185		rows: body.length
27186	};
27187};
27188
27189/**
27190 * Older versions of Safari (prior to tech preview 18) don't support the
27191 * download option required.
27192 *
27193 * @return {Boolean} `true` if old Safari
27194 */
27195var _isDuffSafari = function ()
27196{
27197	var safari = navigator.userAgent.indexOf('Safari') !== -1 &&
27198		navigator.userAgent.indexOf('Chrome') === -1 &&
27199		navigator.userAgent.indexOf('Opera') === -1;
27200
27201	if ( ! safari ) {
27202		return false;
27203	}
27204
27205	var version = navigator.userAgent.match( /AppleWebKit\/(\d+\.\d+)/ );
27206	if ( version && version.length > 1 && version[1]*1 < 603.1 ) {
27207		return true;
27208	}
27209
27210	return false;
27211};
27212
27213/**
27214 * Convert from numeric position to letter for column names in Excel
27215 * @param  {int} n Column number
27216 * @return {string} Column letter(s) name
27217 */
27218function createCellPos( n ){
27219	var ordA = 'A'.charCodeAt(0);
27220	var ordZ = 'Z'.charCodeAt(0);
27221	var len = ordZ - ordA + 1;
27222	var s = "";
27223
27224	while( n >= 0 ) {
27225		s = String.fromCharCode(n % len + ordA) + s;
27226		n = Math.floor(n / len) - 1;
27227	}
27228
27229	return s;
27230}
27231
27232try {
27233	var _serialiser = new XMLSerializer();
27234	var _ieExcel;
27235}
27236catch (t) {}
27237
27238/**
27239 * Recursively add XML files from an object's structure to a ZIP file. This
27240 * allows the XSLX file to be easily defined with an object's structure matching
27241 * the files structure.
27242 *
27243 * @param {JSZip} zip ZIP package
27244 * @param {object} obj Object to add (recursive)
27245 */
27246function _addToZip( zip, obj ) {
27247	if ( _ieExcel === undefined ) {
27248		// Detect if we are dealing with IE's _awful_ serialiser by seeing if it
27249		// drop attributes
27250		_ieExcel = _serialiser
27251			.serializeToString(
27252				$.parseXML( excelStrings['xl/worksheets/sheet1.xml'] )
27253			)
27254			.indexOf( 'xmlns:r' ) === -1;
27255	}
27256
27257	$.each( obj, function ( name, val ) {
27258		if ( $.isPlainObject( val ) ) {
27259			var newDir = zip.folder( name );
27260			_addToZip( newDir, val );
27261		}
27262		else {
27263			if ( _ieExcel ) {
27264				// IE's XML serialiser will drop some name space attributes from
27265				// from the root node, so we need to save them. Do this by
27266				// replacing the namespace nodes with a regular attribute that
27267				// we convert back when serialised. Edge does not have this
27268				// issue
27269				var worksheet = val.childNodes[0];
27270				var i, ien;
27271				var attrs = [];
27272
27273				for ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) {
27274					var attrName = worksheet.attributes[i].nodeName;
27275					var attrValue = worksheet.attributes[i].nodeValue;
27276
27277					if ( attrName.indexOf( ':' ) !== -1 ) {
27278						attrs.push( { name: attrName, value: attrValue } );
27279
27280						worksheet.removeAttribute( attrName );
27281					}
27282				}
27283
27284				for ( i=0, ien=attrs.length ; i<ien ; i++ ) {
27285					var attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) );
27286					attr.value = attrs[i].value;
27287					worksheet.setAttributeNode( attr );
27288				}
27289			}
27290
27291			var str = _serialiser.serializeToString(val);
27292
27293			// Fix IE's XML
27294			if ( _ieExcel ) {
27295				// IE doesn't include the XML declaration
27296				if ( str.indexOf( '<?xml' ) === -1 ) {
27297					str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+str;
27298				}
27299
27300				// Return namespace attributes to being as such
27301				str = str.replace( /_dt_b_namespace_token_/g, ':' );
27302
27303				// Remove testing name space that IE puts into the space preserve attr
27304				str = str.replace( /xmlns:NS[\d]+="" NS[\d]+:/g, '' );
27305			}
27306
27307			// Safari, IE and Edge will put empty name space attributes onto
27308			// various elements making them useless. This strips them out
27309			str = str.replace( /<([^<>]*?) xmlns=""([^<>]*?)>/g, '<$1 $2>' );
27310
27311			zip.file( name, str );
27312		}
27313	} );
27314}
27315
27316/**
27317 * Create an XML node and add any children, attributes, etc without needing to
27318 * be verbose in the DOM.
27319 *
27320 * @param  {object} doc      XML document
27321 * @param  {string} nodeName Node name
27322 * @param  {object} opts     Options - can be `attr` (attributes), `children`
27323 *   (child nodes) and `text` (text content)
27324 * @return {node}            Created node
27325 */
27326function _createNode( doc, nodeName, opts ) {
27327	var tempNode = doc.createElement( nodeName );
27328
27329	if ( opts ) {
27330		if ( opts.attr ) {
27331			$(tempNode).attr( opts.attr );
27332		}
27333
27334		if ( opts.children ) {
27335			$.each( opts.children, function ( key, value ) {
27336				tempNode.appendChild( value );
27337			} );
27338		}
27339
27340		if ( opts.text !== null && opts.text !== undefined ) {
27341			tempNode.appendChild( doc.createTextNode( opts.text ) );
27342		}
27343	}
27344
27345	return tempNode;
27346}
27347
27348/**
27349 * Get the width for an Excel column based on the contents of that column
27350 * @param  {object} data Data for export
27351 * @param  {int}    col  Column index
27352 * @return {int}         Column width
27353 */
27354function _excelColWidth( data, col ) {
27355	var max = data.header[col].length;
27356	var len, lineSplit, str;
27357
27358	if ( data.footer && data.footer[col].length > max ) {
27359		max = data.footer[col].length;
27360	}
27361
27362	for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
27363		var point = data.body[i][col];
27364		str = point !== null && point !== undefined ?
27365			point.toString() :
27366			'';
27367
27368		// If there is a newline character, workout the width of the column
27369		// based on the longest line in the string
27370		if ( str.indexOf('\n') !== -1 ) {
27371			lineSplit = str.split('\n');
27372			lineSplit.sort( function (a, b) {
27373				return b.length - a.length;
27374			} );
27375
27376			len = lineSplit[0].length;
27377		}
27378		else {
27379			len = str.length;
27380		}
27381
27382		if ( len > max ) {
27383			max = len;
27384		}
27385
27386		// Max width rather than having potentially massive column widths
27387		if ( max > 40 ) {
27388			return 54; // 40 * 1.35
27389		}
27390	}
27391
27392	max *= 1.35;
27393
27394	// And a min width
27395	return max > 6 ? max : 6;
27396}
27397
27398// Excel - Pre-defined strings to build a basic XLSX file
27399var excelStrings = {
27400	"_rels/.rels":
27401		'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
27402		'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
27403			'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'+
27404		'</Relationships>',
27405
27406	"xl/_rels/workbook.xml.rels":
27407		'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
27408		'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
27409			'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'+
27410			'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'+
27411		'</Relationships>',
27412
27413	"[Content_Types].xml":
27414		'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
27415		'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'+
27416			'<Default Extension="xml" ContentType="application/xml" />'+
27417			'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />'+
27418			'<Default Extension="jpeg" ContentType="image/jpeg" />'+
27419			'<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />'+
27420			'<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />'+
27421			'<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" />'+
27422		'</Types>',
27423
27424	"xl/workbook.xml":
27425		'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
27426		'<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'+
27427			'<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/>'+
27428			'<workbookPr showInkAnnotation="0" autoCompressPictures="0"/>'+
27429			'<bookViews>'+
27430				'<workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/>'+
27431			'</bookViews>'+
27432			'<sheets>'+
27433				'<sheet name="Sheet1" sheetId="1" r:id="rId1"/>'+
27434			'</sheets>'+
27435			'<definedNames/>'+
27436		'</workbook>',
27437
27438	"xl/worksheets/sheet1.xml":
27439		'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
27440		'<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">'+
27441			'<sheetData/>'+
27442			'<mergeCells count="0"/>'+
27443		'</worksheet>',
27444
27445	"xl/styles.xml":
27446		'<?xml version="1.0" encoding="UTF-8"?>'+
27447		'<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+
27448			'<numFmts count="6">'+
27449				'<numFmt numFmtId="164" formatCode="#,##0.00_-\ [$$-45C]"/>'+
27450				'<numFmt numFmtId="165" formatCode="&quot;£&quot;#,##0.00"/>'+
27451				'<numFmt numFmtId="166" formatCode="[$€-2]\ #,##0.00"/>'+
27452				'<numFmt numFmtId="167" formatCode="0.0%"/>'+
27453				'<numFmt numFmtId="168" formatCode="#,##0;(#,##0)"/>'+
27454				'<numFmt numFmtId="169" formatCode="#,##0.00;(#,##0.00)"/>'+
27455			'</numFmts>'+
27456			'<fonts count="5" x14ac:knownFonts="1">'+
27457				'<font>'+
27458					'<sz val="11" />'+
27459					'<name val="Calibri" />'+
27460				'</font>'+
27461				'<font>'+
27462					'<sz val="11" />'+
27463					'<name val="Calibri" />'+
27464					'<color rgb="FFFFFFFF" />'+
27465				'</font>'+
27466				'<font>'+
27467					'<sz val="11" />'+
27468					'<name val="Calibri" />'+
27469					'<b />'+
27470				'</font>'+
27471				'<font>'+
27472					'<sz val="11" />'+
27473					'<name val="Calibri" />'+
27474					'<i />'+
27475				'</font>'+
27476				'<font>'+
27477					'<sz val="11" />'+
27478					'<name val="Calibri" />'+
27479					'<u />'+
27480				'</font>'+
27481			'</fonts>'+
27482			'<fills count="6">'+
27483				'<fill>'+
27484					'<patternFill patternType="none" />'+
27485				'</fill>'+
27486				'<fill>'+ // Excel appears to use this as a dotted background regardless of values but
27487					'<patternFill patternType="none" />'+ // to be valid to the schema, use a patternFill
27488				'</fill>'+
27489				'<fill>'+
27490					'<patternFill patternType="solid">'+
27491						'<fgColor rgb="FFD9D9D9" />'+
27492						'<bgColor indexed="64" />'+
27493					'</patternFill>'+
27494				'</fill>'+
27495				'<fill>'+
27496					'<patternFill patternType="solid">'+
27497						'<fgColor rgb="FFD99795" />'+
27498						'<bgColor indexed="64" />'+
27499					'</patternFill>'+
27500				'</fill>'+
27501				'<fill>'+
27502					'<patternFill patternType="solid">'+
27503						'<fgColor rgb="ffc6efce" />'+
27504						'<bgColor indexed="64" />'+
27505					'</patternFill>'+
27506				'</fill>'+
27507				'<fill>'+
27508					'<patternFill patternType="solid">'+
27509						'<fgColor rgb="ffc6cfef" />'+
27510						'<bgColor indexed="64" />'+
27511					'</patternFill>'+
27512				'</fill>'+
27513			'</fills>'+
27514			'<borders count="2">'+
27515				'<border>'+
27516					'<left />'+
27517					'<right />'+
27518					'<top />'+
27519					'<bottom />'+
27520					'<diagonal />'+
27521				'</border>'+
27522				'<border diagonalUp="false" diagonalDown="false">'+
27523					'<left style="thin">'+
27524						'<color auto="1" />'+
27525					'</left>'+
27526					'<right style="thin">'+
27527						'<color auto="1" />'+
27528					'</right>'+
27529					'<top style="thin">'+
27530						'<color auto="1" />'+
27531					'</top>'+
27532					'<bottom style="thin">'+
27533						'<color auto="1" />'+
27534					'</bottom>'+
27535					'<diagonal />'+
27536				'</border>'+
27537			'</borders>'+
27538			'<cellStyleXfs count="1">'+
27539				'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" />'+
27540			'</cellStyleXfs>'+
27541			'<cellXfs count="67">'+
27542				'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27543				'<xf numFmtId="0" fontId="1" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27544				'<xf numFmtId="0" fontId="2" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27545				'<xf numFmtId="0" fontId="3" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27546				'<xf numFmtId="0" fontId="4" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27547				'<xf numFmtId="0" fontId="0" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27548				'<xf numFmtId="0" fontId="1" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27549				'<xf numFmtId="0" fontId="2" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27550				'<xf numFmtId="0" fontId="3" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27551				'<xf numFmtId="0" fontId="4" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27552				'<xf numFmtId="0" fontId="0" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27553				'<xf numFmtId="0" fontId="1" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27554				'<xf numFmtId="0" fontId="2" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27555				'<xf numFmtId="0" fontId="3" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27556				'<xf numFmtId="0" fontId="4" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27557				'<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27558				'<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27559				'<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27560				'<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27561				'<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27562				'<xf numFmtId="0" fontId="0" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27563				'<xf numFmtId="0" fontId="1" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27564				'<xf numFmtId="0" fontId="2" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27565				'<xf numFmtId="0" fontId="3" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27566				'<xf numFmtId="0" fontId="4" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
27567				'<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27568				'<xf numFmtId="0" fontId="1" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27569				'<xf numFmtId="0" fontId="2" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27570				'<xf numFmtId="0" fontId="3" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27571				'<xf numFmtId="0" fontId="4" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27572				'<xf numFmtId="0" fontId="0" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27573				'<xf numFmtId="0" fontId="1" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27574				'<xf numFmtId="0" fontId="2" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27575				'<xf numFmtId="0" fontId="3" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27576				'<xf numFmtId="0" fontId="4" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27577				'<xf numFmtId="0" fontId="0" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27578				'<xf numFmtId="0" fontId="1" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27579				'<xf numFmtId="0" fontId="2" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27580				'<xf numFmtId="0" fontId="3" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27581				'<xf numFmtId="0" fontId="4" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27582				'<xf numFmtId="0" fontId="0" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27583				'<xf numFmtId="0" fontId="1" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27584				'<xf numFmtId="0" fontId="2" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27585				'<xf numFmtId="0" fontId="3" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27586				'<xf numFmtId="0" fontId="4" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27587				'<xf numFmtId="0" fontId="0" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27588				'<xf numFmtId="0" fontId="1" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27589				'<xf numFmtId="0" fontId="2" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27590				'<xf numFmtId="0" fontId="3" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27591				'<xf numFmtId="0" fontId="4" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
27592				'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
27593					'<alignment horizontal="left"/>'+
27594				'</xf>'+
27595				'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
27596					'<alignment horizontal="center"/>'+
27597				'</xf>'+
27598				'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
27599					'<alignment horizontal="right"/>'+
27600				'</xf>'+
27601				'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
27602					'<alignment horizontal="fill"/>'+
27603				'</xf>'+
27604				'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
27605					'<alignment textRotation="90"/>'+
27606				'</xf>'+
27607				'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
27608					'<alignment wrapText="1"/>'+
27609				'</xf>'+
27610				'<xf numFmtId="9"   fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27611				'<xf numFmtId="164" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27612				'<xf numFmtId="165" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27613				'<xf numFmtId="166" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27614				'<xf numFmtId="167" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27615				'<xf numFmtId="168" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27616				'<xf numFmtId="169" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27617				'<xf numFmtId="3" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27618				'<xf numFmtId="4" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27619				'<xf numFmtId="1" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27620				'<xf numFmtId="2" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
27621			'</cellXfs>'+
27622			'<cellStyles count="1">'+
27623				'<cellStyle name="Normal" xfId="0" builtinId="0" />'+
27624			'</cellStyles>'+
27625			'<dxfs count="0" />'+
27626			'<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4" />'+
27627		'</styleSheet>'
27628};
27629// Note we could use 3 `for` loops for the styles, but when gzipped there is
27630// virtually no difference in size, since the above can be easily compressed
27631
27632// Pattern matching for special number formats. Perhaps this should be exposed
27633// via an API in future?
27634// Ref: section 3.8.30 - built in formatters in open spreadsheet
27635//   https://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf
27636var _excelSpecials = [
27637	{ match: /^\-?\d+\.\d%$/,       style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p.
27638	{ match: /^\-?\d+\.?\d*%$/,     style: 56, fmt: function (d) { return d/100; } }, // Percent
27639	{ match: /^\-?\$[\d,]+.?\d*$/,  style: 57 }, // Dollars
27640	{ match: /^\-?£[\d,]+.?\d*$/,   style: 58 }, // Pounds
27641	{ match: /^\-?€[\d,]+.?\d*$/,   style: 59 }, // Euros
27642	{ match: /^\-?\d+$/,            style: 65 }, // Numbers without thousand separators
27643	{ match: /^\-?\d+\.\d{2}$/,     style: 66 }, // Numbers 2 d.p. without thousands separators
27644	{ match: /^\([\d,]+\)$/,        style: 61, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } },  // Negative numbers indicated by brackets
27645	{ match: /^\([\d,]+\.\d{2}\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } },  // Negative numbers indicated by brackets - 2d.p.
27646	{ match: /^\-?[\d,]+$/,         style: 63 }, // Numbers with thousand separators
27647	{ match: /^\-?[\d,]+\.\d{2}$/,  style: 64 }  // Numbers with 2 d.p. and thousands separators
27648];
27649
27650
27651
27652/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
27653 * Buttons
27654 */
27655
27656//
27657// Copy to clipboard
27658//
27659DataTable.ext.buttons.copyHtml5 = {
27660	className: 'buttons-copy buttons-html5',
27661
27662	text: function ( dt ) {
27663		return dt.i18n( 'buttons.copy', 'Copy' );
27664	},
27665
27666	action: function ( e, dt, button, config ) {
27667		this.processing( true );
27668
27669		var that = this;
27670		var exportData = _exportData( dt, config );
27671		var info = dt.buttons.exportInfo( config );
27672		var newline = _newLine(config);
27673		var output = exportData.str;
27674		var hiddenDiv = $('<div/>')
27675			.css( {
27676				height: 1,
27677				width: 1,
27678				overflow: 'hidden',
27679				position: 'fixed',
27680				top: 0,
27681				left: 0
27682			} );
27683
27684		if ( info.title ) {
27685			output = info.title + newline + newline + output;
27686		}
27687
27688		if ( info.messageTop ) {
27689			output = info.messageTop + newline + newline + output;
27690		}
27691
27692		if ( info.messageBottom ) {
27693			output = output + newline + newline + info.messageBottom;
27694		}
27695
27696		if ( config.customize ) {
27697			output = config.customize( output, config, dt );
27698		}
27699
27700		var textarea = $('<textarea readonly/>')
27701			.val( output )
27702			.appendTo( hiddenDiv );
27703
27704		// For browsers that support the copy execCommand, try to use it
27705		if ( document.queryCommandSupported('copy') ) {
27706			hiddenDiv.appendTo( dt.table().container() );
27707			textarea[0].focus();
27708			textarea[0].select();
27709
27710			try {
27711				var successful = document.execCommand( 'copy' );
27712				hiddenDiv.remove();
27713
27714				if (successful) {
27715					dt.buttons.info(
27716						dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
27717						dt.i18n( 'buttons.copySuccess', {
27718							1: 'Copied one row to clipboard',
27719							_: 'Copied %d rows to clipboard'
27720						}, exportData.rows ),
27721						2000
27722					);
27723
27724					this.processing( false );
27725					return;
27726				}
27727			}
27728			catch (t) {}
27729		}
27730
27731		// Otherwise we show the text box and instruct the user to use it
27732		var message = $('<span>'+dt.i18n( 'buttons.copyKeys',
27733				'Press <i>ctrl</i> or <i>\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+
27734				'To cancel, click this message or press escape.' )+'</span>'
27735			)
27736			.append( hiddenDiv );
27737
27738		dt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );
27739
27740		// Select the text so when the user activates their system clipboard
27741		// it will copy that text
27742		textarea[0].focus();
27743		textarea[0].select();
27744
27745		// Event to hide the message when the user is done
27746		var container = $(message).closest('.dt-button-info');
27747		var close = function () {
27748			container.off( 'click.buttons-copy' );
27749			$(document).off( '.buttons-copy' );
27750			dt.buttons.info( false );
27751		};
27752
27753		container.on( 'click.buttons-copy', close );
27754		$(document)
27755			.on( 'keydown.buttons-copy', function (e) {
27756				if ( e.keyCode === 27 ) { // esc
27757					close();
27758					that.processing( false );
27759				}
27760			} )
27761			.on( 'copy.buttons-copy cut.buttons-copy', function () {
27762				close();
27763				that.processing( false );
27764			} );
27765	},
27766
27767	exportOptions: {},
27768
27769	fieldSeparator: '\t',
27770
27771	fieldBoundary: '',
27772
27773	header: true,
27774
27775	footer: false,
27776
27777	title: '*',
27778
27779	messageTop: '*',
27780
27781	messageBottom: '*'
27782};
27783
27784//
27785// CSV export
27786//
27787DataTable.ext.buttons.csvHtml5 = {
27788	bom: false,
27789
27790	className: 'buttons-csv buttons-html5',
27791
27792	available: function () {
27793		return window.FileReader !== undefined && window.Blob;
27794	},
27795
27796	text: function ( dt ) {
27797		return dt.i18n( 'buttons.csv', 'CSV' );
27798	},
27799
27800	action: function ( e, dt, button, config ) {
27801		this.processing( true );
27802
27803		// Set the text
27804		var output = _exportData( dt, config ).str;
27805		var info = dt.buttons.exportInfo(config);
27806		var charset = config.charset;
27807
27808		if ( config.customize ) {
27809			output = config.customize( output, config, dt );
27810		}
27811
27812		if ( charset !== false ) {
27813			if ( ! charset ) {
27814				charset = document.characterSet || document.charset;
27815			}
27816
27817			if ( charset ) {
27818				charset = ';charset='+charset;
27819			}
27820		}
27821		else {
27822			charset = '';
27823		}
27824
27825		if ( config.bom ) {
27826			output = '\ufeff' + output;
27827		}
27828
27829		_saveAs(
27830			new Blob( [output], {type: 'text/csv'+charset} ),
27831			info.filename,
27832			true
27833		);
27834
27835		this.processing( false );
27836	},
27837
27838	filename: '*',
27839
27840	extension: '.csv',
27841
27842	exportOptions: {},
27843
27844	fieldSeparator: ',',
27845
27846	fieldBoundary: '"',
27847
27848	escapeChar: '"',
27849
27850	charset: null,
27851
27852	header: true,
27853
27854	footer: false
27855};
27856
27857//
27858// Excel (xlsx) export
27859//
27860DataTable.ext.buttons.excelHtml5 = {
27861	className: 'buttons-excel buttons-html5',
27862
27863	available: function () {
27864		return window.FileReader !== undefined && _jsZip() !== undefined && ! _isDuffSafari() && _serialiser;
27865	},
27866
27867	text: function ( dt ) {
27868		return dt.i18n( 'buttons.excel', 'Excel' );
27869	},
27870
27871	action: function ( e, dt, button, config ) {
27872		this.processing( true );
27873
27874		var that = this;
27875		var rowPos = 0;
27876		var dataStartRow, dataEndRow;
27877		var getXml = function ( type ) {
27878			var str = excelStrings[ type ];
27879
27880			//str = str.replace( /xmlns:/g, 'xmlns_' ).replace( /mc:/g, 'mc_' );
27881
27882			return $.parseXML( str );
27883		};
27884		var rels = getXml('xl/worksheets/sheet1.xml');
27885		var relsGet = rels.getElementsByTagName( "sheetData" )[0];
27886
27887		var xlsx = {
27888			_rels: {
27889				".rels": getXml('_rels/.rels')
27890			},
27891			xl: {
27892				_rels: {
27893					"workbook.xml.rels": getXml('xl/_rels/workbook.xml.rels')
27894				},
27895				"workbook.xml": getXml('xl/workbook.xml'),
27896				"styles.xml": getXml('xl/styles.xml'),
27897				"worksheets": {
27898					"sheet1.xml": rels
27899				}
27900
27901			},
27902			"[Content_Types].xml": getXml('[Content_Types].xml')
27903		};
27904
27905		var data = dt.buttons.exportData( config.exportOptions );
27906		var currentRow, rowNode;
27907		var addRow = function ( row ) {
27908			currentRow = rowPos+1;
27909			rowNode = _createNode( rels, "row", { attr: {r:currentRow} } );
27910
27911			for ( var i=0, ien=row.length ; i<ien ; i++ ) {
27912				// Concat both the Cell Columns as a letter and the Row of the cell.
27913				var cellId = createCellPos(i) + '' + currentRow;
27914				var cell = null;
27915
27916				// For null, undefined of blank cell, continue so it doesn't create the _createNode
27917				if ( row[i] === null || row[i] === undefined || row[i] === '' ) {
27918					if ( config.createEmptyCells === true ) {
27919						row[i] = '';
27920					}
27921					else {
27922						continue;
27923					}
27924				}
27925
27926				var originalContent = row[i];
27927				row[i] = $.trim( row[i] );
27928
27929				// Special number formatting options
27930				for ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {
27931					var special = _excelSpecials[j];
27932
27933					// TODO Need to provide the ability for the specials to say
27934					// if they are returning a string, since at the moment it is
27935					// assumed to be a number
27936					if ( row[i].match && ! row[i].match(/^0\d+/) && row[i].match( special.match ) ) {
27937						var val = row[i].replace(/[^\d\.\-]/g, '');
27938
27939						if ( special.fmt ) {
27940							val = special.fmt( val );
27941						}
27942
27943						cell = _createNode( rels, 'c', {
27944							attr: {
27945								r: cellId,
27946								s: special.style
27947							},
27948							children: [
27949								_createNode( rels, 'v', { text: val } )
27950							]
27951						} );
27952
27953						break;
27954					}
27955				}
27956
27957				if ( ! cell ) {
27958					if ( typeof row[i] === 'number' || (
27959						row[i].match &&
27960						row[i].match(/^-?\d+(\.\d+)?$/) &&
27961						! row[i].match(/^0\d+/) )
27962					) {
27963						// Detect numbers - don't match numbers with leading zeros
27964						// or a negative anywhere but the start
27965						cell = _createNode( rels, 'c', {
27966							attr: {
27967								t: 'n',
27968								r: cellId
27969							},
27970							children: [
27971								_createNode( rels, 'v', { text: row[i] } )
27972							]
27973						} );
27974					}
27975					else {
27976						// String output - replace non standard characters for text output
27977						var text = ! originalContent.replace ?
27978							originalContent :
27979							originalContent.replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');
27980
27981						cell = _createNode( rels, 'c', {
27982							attr: {
27983								t: 'inlineStr',
27984								r: cellId
27985							},
27986							children:{
27987								row: _createNode( rels, 'is', {
27988									children: {
27989										row: _createNode( rels, 't', {
27990											text: text,
27991											attr: {
27992												'xml:space': 'preserve'
27993											}
27994										} )
27995									}
27996								} )
27997							}
27998						} );
27999					}
28000				}
28001
28002				rowNode.appendChild( cell );
28003			}
28004
28005			relsGet.appendChild(rowNode);
28006			rowPos++;
28007		};
28008
28009		if ( config.customizeData ) {
28010			config.customizeData( data );
28011		}
28012
28013		var mergeCells = function ( row, colspan ) {
28014			var mergeCells = $('mergeCells', rels);
28015
28016			mergeCells[0].appendChild( _createNode( rels, 'mergeCell', {
28017				attr: {
28018					ref: 'A'+row+':'+createCellPos(colspan)+row
28019				}
28020			} ) );
28021			mergeCells.attr( 'count', parseFloat(mergeCells.attr( 'count' ))+1 );
28022			$('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre
28023		};
28024
28025		// Title and top messages
28026		var exportInfo = dt.buttons.exportInfo( config );
28027		if ( exportInfo.title ) {
28028			addRow( [exportInfo.title], rowPos );
28029			mergeCells( rowPos, data.header.length-1 );
28030		}
28031
28032		if ( exportInfo.messageTop ) {
28033			addRow( [exportInfo.messageTop], rowPos );
28034			mergeCells( rowPos, data.header.length-1 );
28035		}
28036
28037
28038		// Table itself
28039		if ( config.header ) {
28040			addRow( data.header, rowPos );
28041			$('row:last c', rels).attr( 's', '2' ); // bold
28042		}
28043	
28044		dataStartRow = rowPos;
28045
28046		for ( var n=0, ie=data.body.length ; n<ie ; n++ ) {
28047			addRow( data.body[n], rowPos );
28048		}
28049	
28050		dataEndRow = rowPos;
28051
28052		if ( config.footer && data.footer ) {
28053			addRow( data.footer, rowPos);
28054			$('row:last c', rels).attr( 's', '2' ); // bold
28055		}
28056
28057		// Below the table
28058		if ( exportInfo.messageBottom ) {
28059			addRow( [exportInfo.messageBottom], rowPos );
28060			mergeCells( rowPos, data.header.length-1 );
28061		}
28062
28063		// Set column widths
28064		var cols = _createNode( rels, 'cols' );
28065		$('worksheet', rels).prepend( cols );
28066
28067		for ( var i=0, ien=data.header.length ; i<ien ; i++ ) {
28068			cols.appendChild( _createNode( rels, 'col', {
28069				attr: {
28070					min: i+1,
28071					max: i+1,
28072					width: _excelColWidth( data, i ),
28073					customWidth: 1
28074				}
28075			} ) );
28076		}
28077
28078		// Auto filter for columns
28079		$('mergeCells', rels).before( _createNode( rels, 'autoFilter', {
28080			attr: {
28081				ref: 'A'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow
28082			}
28083		} ) );
28084
28085		// Workbook modifications
28086		var workbook = xlsx.xl['workbook.xml'];
28087
28088		$( 'sheets sheet', workbook ).attr( 'name', _sheetname( config ) );
28089
28090		if ( config.autoFilter ) {
28091			$('definedNames', workbook).append( _createNode( workbook, 'definedName', {
28092				attr: {
28093					name: '_xlnm._FilterDatabase',
28094					localSheetId: '0',
28095					hidden: 1
28096				},
28097				text: _sheetname(config)+'!$A$'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow
28098			} ) );
28099		}
28100
28101		// Let the developer customise the document if they want to
28102		if ( config.customize ) {
28103			config.customize( xlsx, config, dt );
28104		}
28105
28106		// Excel doesn't like an empty mergeCells tag
28107		if ( $('mergeCells', rels).children().length === 0 ) {
28108			$('mergeCells', rels).remove();
28109		}
28110
28111		var jszip = _jsZip();
28112		var zip = new jszip();
28113		var zipConfig = {
28114			type: 'blob',
28115			mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
28116		};
28117
28118		_addToZip( zip, xlsx );
28119
28120		if ( zip.generateAsync ) {
28121			// JSZip 3+
28122			zip
28123				.generateAsync( zipConfig )
28124				.then( function ( blob ) {
28125					_saveAs( blob, exportInfo.filename );
28126					that.processing( false );
28127				} );
28128		}
28129		else {
28130			// JSZip 2.5
28131			_saveAs(
28132				zip.generate( zipConfig ),
28133				exportInfo.filename
28134			);
28135			this.processing( false );
28136		}
28137	},
28138
28139	filename: '*',
28140
28141	extension: '.xlsx',
28142
28143	exportOptions: {},
28144
28145	header: true,
28146
28147	footer: false,
28148
28149	title: '*',
28150
28151	messageTop: '*',
28152
28153	messageBottom: '*',
28154
28155	createEmptyCells: false,
28156
28157	autoFilter: false,
28158
28159	sheetName: ''
28160};
28161
28162//
28163// PDF export - using pdfMake - http://pdfmake.org
28164//
28165DataTable.ext.buttons.pdfHtml5 = {
28166	className: 'buttons-pdf buttons-html5',
28167
28168	available: function () {
28169		return window.FileReader !== undefined && _pdfMake();
28170	},
28171
28172	text: function ( dt ) {
28173		return dt.i18n( 'buttons.pdf', 'PDF' );
28174	},
28175
28176	action: function ( e, dt, button, config ) {
28177		this.processing( true );
28178
28179		var that = this;
28180		var data = dt.buttons.exportData( config.exportOptions );
28181		var info = dt.buttons.exportInfo( config );
28182		var rows = [];
28183
28184		if ( config.header ) {
28185			rows.push( $.map( data.header, function ( d ) {
28186				return {
28187					text: typeof d === 'string' ? d : d+'',
28188					style: 'tableHeader'
28189				};
28190			} ) );
28191		}
28192
28193		for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
28194			rows.push( $.map( data.body[i], function ( d ) {
28195				if ( d === null || d === undefined ) {
28196					d = '';
28197				}
28198				return {
28199					text: typeof d === 'string' ? d : d+'',
28200					style: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'
28201				};
28202			} ) );
28203		}
28204
28205		if ( config.footer && data.footer) {
28206			rows.push( $.map( data.footer, function ( d ) {
28207				return {
28208					text: typeof d === 'string' ? d : d+'',
28209					style: 'tableFooter'
28210				};
28211			} ) );
28212		}
28213
28214		var doc = {
28215			pageSize: config.pageSize,
28216			pageOrientation: config.orientation,
28217			content: [
28218				{
28219					table: {
28220						headerRows: 1,
28221						body: rows
28222					},
28223					layout: 'noBorders'
28224				}
28225			],
28226			styles: {
28227				tableHeader: {
28228					bold: true,
28229					fontSize: 11,
28230					color: 'white',
28231					fillColor: '#2d4154',
28232					alignment: 'center'
28233				},
28234				tableBodyEven: {},
28235				tableBodyOdd: {
28236					fillColor: '#f3f3f3'
28237				},
28238				tableFooter: {
28239					bold: true,
28240					fontSize: 11,
28241					color: 'white',
28242					fillColor: '#2d4154'
28243				},
28244				title: {
28245					alignment: 'center',
28246					fontSize: 15
28247				},
28248				message: {}
28249			},
28250			defaultStyle: {
28251				fontSize: 10
28252			}
28253		};
28254
28255		if ( info.messageTop ) {
28256			doc.content.unshift( {
28257				text: info.messageTop,
28258				style: 'message',
28259				margin: [ 0, 0, 0, 12 ]
28260			} );
28261		}
28262
28263		if ( info.messageBottom ) {
28264			doc.content.push( {
28265				text: info.messageBottom,
28266				style: 'message',
28267				margin: [ 0, 0, 0, 12 ]
28268			} );
28269		}
28270
28271		if ( info.title ) {
28272			doc.content.unshift( {
28273				text: info.title,
28274				style: 'title',
28275				margin: [ 0, 0, 0, 12 ]
28276			} );
28277		}
28278
28279		if ( config.customize ) {
28280			config.customize( doc, config, dt );
28281		}
28282
28283		var pdf = _pdfMake().createPdf( doc );
28284
28285		if ( config.download === 'open' && ! _isDuffSafari() ) {
28286			pdf.open();
28287		}
28288		else {
28289			pdf.download( info.filename );
28290		}
28291
28292		this.processing( false );
28293	},
28294
28295	title: '*',
28296
28297	filename: '*',
28298
28299	extension: '.pdf',
28300
28301	exportOptions: {},
28302
28303	orientation: 'portrait',
28304
28305	pageSize: 'A4',
28306
28307	header: true,
28308
28309	footer: false,
28310
28311	messageTop: '*',
28312
28313	messageBottom: '*',
28314
28315	customize: null,
28316
28317	download: 'download'
28318};
28319
28320
28321return DataTable.Buttons;
28322}));
28323
28324
28325/*! ColReorder 1.5.0
28326 * ©2010-2018 SpryMedia Ltd - datatables.net/license
28327 */
28328
28329/**
28330 * @summary     ColReorder
28331 * @description Provide the ability to reorder columns in a DataTable
28332 * @version     1.5.0
28333 * @file        dataTables.colReorder.js
28334 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
28335 * @contact     www.sprymedia.co.uk/contact
28336 * @copyright   Copyright 2010-2018 SpryMedia Ltd.
28337 *
28338 * This source file is free software, available under the following license:
28339 *   MIT license - http://datatables.net/license/mit
28340 *
28341 * This source file is distributed in the hope that it will be useful, but
28342 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
28343 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
28344 *
28345 * For details please refer to: http://www.datatables.net
28346 */
28347(function( factory ){
28348	if ( typeof define === 'function' && define.amd ) {
28349		// AMD
28350		define( ['jquery', 'datatables.net'], function ( $ ) {
28351			return factory( $, window, document );
28352		} );
28353	}
28354	else if ( typeof exports === 'object' ) {
28355		// CommonJS
28356		module.exports = function (root, $) {
28357			if ( ! root ) {
28358				root = window;
28359			}
28360
28361			if ( ! $ || ! $.fn.dataTable ) {
28362				$ = require('datatables.net')(root, $).$;
28363			}
28364
28365			return factory( $, root, root.document );
28366		};
28367	}
28368	else {
28369		// Browser
28370		factory( jQuery, window, document );
28371	}
28372}(function( $, window, document, undefined ) {
28373'use strict';
28374var DataTable = $.fn.dataTable;
28375
28376
28377/**
28378 * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
28379 * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
28380 *  @method  fnInvertKeyValues
28381 *  @param   array aIn Array to switch around
28382 *  @returns array
28383 */
28384function fnInvertKeyValues( aIn )
28385{
28386	var aRet=[];
28387	for ( var i=0, iLen=aIn.length ; i<iLen ; i++ )
28388	{
28389		aRet[ aIn[i] ] = i;
28390	}
28391	return aRet;
28392}
28393
28394
28395/**
28396 * Modify an array by switching the position of two elements
28397 *  @method  fnArraySwitch
28398 *  @param   array aArray Array to consider, will be modified by reference (i.e. no return)
28399 *  @param   int iFrom From point
28400 *  @param   int iTo Insert point
28401 *  @returns void
28402 */
28403function fnArraySwitch( aArray, iFrom, iTo )
28404{
28405	var mStore = aArray.splice( iFrom, 1 )[0];
28406	aArray.splice( iTo, 0, mStore );
28407}
28408
28409
28410/**
28411 * Switch the positions of nodes in a parent node (note this is specifically designed for
28412 * table rows). Note this function considers all element nodes under the parent!
28413 *  @method  fnDomSwitch
28414 *  @param   string sTag Tag to consider
28415 *  @param   int iFrom Element to move
28416 *  @param   int Point to element the element to (before this point), can be null for append
28417 *  @returns void
28418 */
28419function fnDomSwitch( nParent, iFrom, iTo )
28420{
28421	var anTags = [];
28422	for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )
28423	{
28424		if ( nParent.childNodes[i].nodeType == 1 )
28425		{
28426			anTags.push( nParent.childNodes[i] );
28427		}
28428	}
28429	var nStore = anTags[ iFrom ];
28430
28431	if ( iTo !== null )
28432	{
28433		nParent.insertBefore( nStore, anTags[iTo] );
28434	}
28435	else
28436	{
28437		nParent.appendChild( nStore );
28438	}
28439}
28440
28441
28442/**
28443 * Plug-in for DataTables which will reorder the internal column structure by taking the column
28444 * from one position (iFrom) and insert it into a given point (iTo).
28445 *  @method  $.fn.dataTableExt.oApi.fnColReorder
28446 *  @param   object oSettings DataTables settings object - automatically added by DataTables!
28447 *  @param   int iFrom Take the column to be repositioned from this point
28448 *  @param   int iTo and insert it into this point
28449 *  @param   bool drop Indicate if the reorder is the final one (i.e. a drop)
28450 *    not a live reorder
28451 *  @param   bool invalidateRows speeds up processing if false passed
28452 *  @returns void
28453 */
28454$.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo, drop, invalidateRows )
28455{
28456	var i, iLen, j, jLen, jen, iCols=oSettings.aoColumns.length, nTrs, oCol;
28457	var attrMap = function ( obj, prop, mapping ) {
28458		if ( ! obj[ prop ] || typeof obj[ prop ] === 'function' ) {
28459			return;
28460		}
28461
28462		var a = obj[ prop ].split('.');
28463		var num = a.shift();
28464
28465		if ( isNaN( num*1 ) ) {
28466			return;
28467		}
28468
28469		obj[ prop ] = mapping[ num*1 ]+'.'+a.join('.');
28470	};
28471
28472	/* Sanity check in the input */
28473	if ( iFrom == iTo )
28474	{
28475		/* Pointless reorder */
28476		return;
28477	}
28478
28479	if ( iFrom < 0 || iFrom >= iCols )
28480	{
28481		this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom );
28482		return;
28483	}
28484
28485	if ( iTo < 0 || iTo >= iCols )
28486	{
28487		this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo );
28488		return;
28489	}
28490
28491	/*
28492	 * Calculate the new column array index, so we have a mapping between the old and new
28493	 */
28494	var aiMapping = [];
28495	for ( i=0, iLen=iCols ; i<iLen ; i++ )
28496	{
28497		aiMapping[i] = i;
28498	}
28499	fnArraySwitch( aiMapping, iFrom, iTo );
28500	var aiInvertMapping = fnInvertKeyValues( aiMapping );
28501
28502
28503	/*
28504	 * Convert all internal indexing to the new column order indexes
28505	 */
28506	/* Sorting */
28507	for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
28508	{
28509		oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
28510	}
28511
28512	/* Fixed sorting */
28513	if ( oSettings.aaSortingFixed !== null )
28514	{
28515		for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )
28516		{
28517			oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
28518		}
28519	}
28520
28521	/* Data column sorting (the column which the sort for a given column should take place on) */
28522	for ( i=0, iLen=iCols ; i<iLen ; i++ )
28523	{
28524		oCol = oSettings.aoColumns[i];
28525		for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )
28526		{
28527			oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
28528		}
28529
28530		// Update the column indexes
28531		oCol.idx = aiInvertMapping[ oCol.idx ];
28532	}
28533
28534	// Update 1.10 optimised sort class removal variable
28535	$.each( oSettings.aLastSort, function (i, val) {
28536		oSettings.aLastSort[i].src = aiInvertMapping[ val.src ];
28537	} );
28538
28539	/* Update the Get and Set functions for each column */
28540	for ( i=0, iLen=iCols ; i<iLen ; i++ )
28541	{
28542		oCol = oSettings.aoColumns[i];
28543
28544		if ( typeof oCol.mData == 'number' ) {
28545			oCol.mData = aiInvertMapping[ oCol.mData ];
28546		}
28547		else if ( $.isPlainObject( oCol.mData ) ) {
28548			// HTML5 data sourced
28549			attrMap( oCol.mData, '_',      aiInvertMapping );
28550			attrMap( oCol.mData, 'filter', aiInvertMapping );
28551			attrMap( oCol.mData, 'sort',   aiInvertMapping );
28552			attrMap( oCol.mData, 'type',   aiInvertMapping );
28553		}
28554	}
28555
28556	/*
28557	 * Move the DOM elements
28558	 */
28559	if ( oSettings.aoColumns[iFrom].bVisible )
28560	{
28561		/* Calculate the current visible index and the point to insert the node before. The insert
28562		 * before needs to take into account that there might not be an element to insert before,
28563		 * in which case it will be null, and an appendChild should be used
28564		 */
28565		var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
28566		var iInsertBeforeIndex = null;
28567
28568		i = iTo < iFrom ? iTo : iTo + 1;
28569		while ( iInsertBeforeIndex === null && i < iCols )
28570		{
28571			iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
28572			i++;
28573		}
28574
28575		/* Header */
28576		nTrs = oSettings.nTHead.getElementsByTagName('tr');
28577		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
28578		{
28579			fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
28580		}
28581
28582		/* Footer */
28583		if ( oSettings.nTFoot !== null )
28584		{
28585			nTrs = oSettings.nTFoot.getElementsByTagName('tr');
28586			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
28587			{
28588				fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
28589			}
28590		}
28591
28592		/* Body */
28593		for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
28594		{
28595			if ( oSettings.aoData[i].nTr !== null )
28596			{
28597				fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
28598			}
28599		}
28600	}
28601
28602	/*
28603	 * Move the internal array elements
28604	 */
28605	/* Columns */
28606	fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
28607
28608	// regenerate the get / set functions
28609	for ( i=0, iLen=iCols ; i<iLen ; i++ ) {
28610		oSettings.oApi._fnColumnOptions( oSettings, i, {} );
28611	}
28612
28613	/* Search columns */
28614	fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
28615
28616	/* Array array - internal data anodes cache */
28617	for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
28618	{
28619		var data = oSettings.aoData[i];
28620		var cells = data.anCells;
28621
28622		if ( cells ) {
28623			fnArraySwitch( cells, iFrom, iTo );
28624
28625			// Longer term, should this be moved into the DataTables' invalidate
28626			// methods?
28627			for ( j=0, jen=cells.length ; j<jen ; j++ ) {
28628				if ( cells[j] && cells[j]._DT_CellIndex ) {
28629					cells[j]._DT_CellIndex.column = j;
28630				}
28631			}
28632		}
28633
28634		// For DOM sourced data, the invalidate will reread the cell into
28635		// the data array, but for data sources as an array, they need to
28636		// be flipped
28637		if ( data.src !== 'dom' && $.isArray( data._aData ) ) {
28638			fnArraySwitch( data._aData, iFrom, iTo );
28639		}
28640	}
28641
28642	/* Reposition the header elements in the header layout array */
28643	for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
28644	{
28645		fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
28646	}
28647
28648	if ( oSettings.aoFooter !== null )
28649	{
28650		for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
28651		{
28652			fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
28653		}
28654	}
28655
28656	if ( invalidateRows || invalidateRows === undefined )
28657	{
28658		$.fn.dataTable.Api( oSettings ).rows().invalidate();
28659	}
28660
28661	/*
28662	 * Update DataTables' event handlers
28663	 */
28664
28665	/* Sort listener */
28666	for ( i=0, iLen=iCols ; i<iLen ; i++ )
28667	{
28668		$(oSettings.aoColumns[i].nTh).off('.DT');
28669		this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
28670	}
28671
28672
28673	/* Fire an event so other plug-ins can update */
28674	$(oSettings.oInstance).trigger( 'column-reorder.dt', [ oSettings, {
28675		from: iFrom,
28676		to: iTo,
28677		mapping: aiInvertMapping,
28678		drop: drop,
28679
28680		// Old style parameters for compatibility
28681		iFrom: iFrom,
28682		iTo: iTo,
28683		aiInvertMapping: aiInvertMapping
28684	} ] );
28685};
28686
28687/**
28688 * ColReorder provides column visibility control for DataTables
28689 * @class ColReorder
28690 * @constructor
28691 * @param {object} dt DataTables settings object
28692 * @param {object} opts ColReorder options
28693 */
28694var ColReorder = function( dt, opts )
28695{
28696	var settings = new $.fn.dataTable.Api( dt ).settings()[0];
28697
28698	// Ensure that we can't initialise on the same table twice
28699	if ( settings._colReorder ) {
28700		return settings._colReorder;
28701	}
28702
28703	// Allow the options to be a boolean for defaults
28704	if ( opts === true ) {
28705		opts = {};
28706	}
28707
28708	// Convert from camelCase to Hungarian, just as DataTables does
28709	var camelToHungarian = $.fn.dataTable.camelToHungarian;
28710	if ( camelToHungarian ) {
28711		camelToHungarian( ColReorder.defaults, ColReorder.defaults, true );
28712		camelToHungarian( ColReorder.defaults, opts || {} );
28713	}
28714
28715
28716	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
28717	 * Public class variables
28718	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
28719
28720	/**
28721	 * @namespace Settings object which contains customisable information for ColReorder instance
28722	 */
28723	this.s = {
28724		/**
28725		 * DataTables settings object
28726		 *  @property dt
28727		 *  @type     Object
28728		 *  @default  null
28729		 */
28730		"dt": null,
28731
28732		/**
28733		 * Enable flag
28734		 *  @property dt
28735		 *  @type     Object
28736		 *  @default  null
28737		 */
28738		"enable": null,
28739
28740		/**
28741		 * Initialisation object used for this instance
28742		 *  @property init
28743		 *  @type     object
28744		 *  @default  {}
28745		 */
28746		"init": $.extend( true, {}, ColReorder.defaults, opts ),
28747
28748		/**
28749		 * Number of columns to fix (not allow to be reordered)
28750		 *  @property fixed
28751		 *  @type     int
28752		 *  @default  0
28753		 */
28754		"fixed": 0,
28755
28756		/**
28757		 * Number of columns to fix counting from right (not allow to be reordered)
28758		 *  @property fixedRight
28759		 *  @type     int
28760		 *  @default  0
28761		 */
28762		"fixedRight": 0,
28763
28764		/**
28765		 * Callback function for once the reorder has been done
28766		 *  @property reorderCallback
28767		 *  @type     function
28768		 *  @default  null
28769		 */
28770		"reorderCallback": null,
28771
28772		/**
28773		 * @namespace Information used for the mouse drag
28774		 */
28775		"mouse": {
28776			"startX": -1,
28777			"startY": -1,
28778			"offsetX": -1,
28779			"offsetY": -1,
28780			"target": -1,
28781			"targetIndex": -1,
28782			"fromIndex": -1
28783		},
28784
28785		/**
28786		 * Information which is used for positioning the insert cusor and knowing where to do the
28787		 * insert. Array of objects with the properties:
28788		 *   x: x-axis position
28789		 *   to: insert point
28790		 *  @property aoTargets
28791		 *  @type     array
28792		 *  @default  []
28793		 */
28794		"aoTargets": []
28795	};
28796
28797
28798	/**
28799	 * @namespace Common and useful DOM elements for the class instance
28800	 */
28801	this.dom = {
28802		/**
28803		 * Dragging element (the one the mouse is moving)
28804		 *  @property drag
28805		 *  @type     element
28806		 *  @default  null
28807		 */
28808		"drag": null,
28809
28810		/**
28811		 * The insert cursor
28812		 *  @property pointer
28813		 *  @type     element
28814		 *  @default  null
28815		 */
28816		"pointer": null
28817	};
28818
28819	/* Constructor logic */
28820	this.s.enable = this.s.init.bEnable;
28821	this.s.dt = settings;
28822	this.s.dt._colReorder = this;
28823	this._fnConstruct();
28824
28825	return this;
28826};
28827
28828
28829
28830$.extend( ColReorder.prototype, {
28831	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
28832	 * Public methods
28833	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
28834
28835	/**
28836	 * Enable / disable end user interaction
28837	 */
28838	fnEnable: function ( flag )
28839	{
28840		if ( flag === false ) {
28841			return fnDisable();
28842		}
28843
28844		this.s.enable = true;
28845	},
28846
28847	/**
28848	 * Disable end user interaction
28849	 */
28850	fnDisable: function ()
28851	{
28852		this.s.enable = false;
28853	},
28854
28855	/**
28856	 * Reset the column ordering to the original ordering that was detected on
28857	 * start up.
28858	 *  @return {this} Returns `this` for chaining.
28859	 *
28860	 *  @example
28861	 *    // DataTables initialisation with ColReorder
28862	 *    var table = $('#example').dataTable( {
28863	 *        "sDom": 'Rlfrtip'
28864	 *    } );
28865	 *
28866	 *    // Add click event to a button to reset the ordering
28867	 *    $('#resetOrdering').click( function (e) {
28868	 *        e.preventDefault();
28869	 *        $.fn.dataTable.ColReorder( table ).fnReset();
28870	 *    } );
28871	 */
28872	"fnReset": function ()
28873	{
28874		this._fnOrderColumns( this.fnOrder() );
28875
28876		return this;
28877	},
28878
28879	/**
28880	 * `Deprecated` - Get the current order of the columns, as an array.
28881	 *  @return {array} Array of column identifiers
28882	 *  @deprecated `fnOrder` should be used in preference to this method.
28883	 *      `fnOrder` acts as a getter/setter.
28884	 */
28885	"fnGetCurrentOrder": function ()
28886	{
28887		return this.fnOrder();
28888	},
28889
28890	/**
28891	 * Get the current order of the columns, as an array. Note that the values
28892	 * given in the array are unique identifiers for each column. Currently
28893	 * these are the original ordering of the columns that was detected on
28894	 * start up, but this could potentially change in future.
28895	 *  @return {array} Array of column identifiers
28896	 *
28897	 *  @example
28898	 *    // Get column ordering for the table
28899	 *    var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder();
28900	 *//**
28901	 * Set the order of the columns, from the positions identified in the
28902	 * ordering array given. Note that ColReorder takes a brute force approach
28903	 * to reordering, so it is possible multiple reordering events will occur
28904	 * before the final order is settled upon.
28905	 *  @param {array} [set] Array of column identifiers in the new order. Note
28906	 *    that every column must be included, uniquely, in this array.
28907	 *  @return {this} Returns `this` for chaining.
28908	 *
28909	 *  @example
28910	 *    // Swap the first and second columns
28911	 *    $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] );
28912	 *
28913	 *  @example
28914	 *    // Move the first column to the end for the table `#example`
28915	 *    var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder();
28916	 *    var first = curr.shift();
28917	 *    curr.push( first );
28918	 *    $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr );
28919	 *
28920	 *  @example
28921	 *    // Reverse the table's order
28922	 *    $.fn.dataTable.ColReorder( '#example' ).fnOrder(
28923	 *      $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse()
28924	 *    );
28925	 */
28926	"fnOrder": function ( set, original )
28927	{
28928		var a = [], i, ien, j, jen;
28929		var columns = this.s.dt.aoColumns;
28930
28931		if ( set === undefined ){
28932			for ( i=0, ien=columns.length ; i<ien ; i++ ) {
28933				a.push( columns[i]._ColReorder_iOrigCol );
28934			}
28935
28936			return a;
28937		}
28938
28939		// The order given is based on the original indexes, rather than the
28940		// existing ones, so we need to translate from the original to current
28941		// before then doing the order
28942		if ( original ) {
28943			var order = this.fnOrder();
28944
28945			for ( i=0, ien=set.length ; i<ien ; i++ ) {
28946				a.push( $.inArray( set[i], order ) );
28947			}
28948
28949			set = a;
28950		}
28951
28952		this._fnOrderColumns( fnInvertKeyValues( set ) );
28953
28954		return this;
28955	},
28956
28957
28958	/**
28959	 * Convert from the original column index, to the original
28960	 *
28961	 * @param  {int|array} idx Index(es) to convert
28962	 * @param  {string} dir Transpose direction - `fromOriginal` / `toCurrent`
28963	 *   or `'toOriginal` / `fromCurrent`
28964	 * @return {int|array}     Converted values
28965	 */
28966	fnTranspose: function ( idx, dir )
28967	{
28968		if ( ! dir ) {
28969			dir = 'toCurrent';
28970		}
28971
28972		var order = this.fnOrder();
28973		var columns = this.s.dt.aoColumns;
28974
28975		if ( dir === 'toCurrent' ) {
28976			// Given an original index, want the current
28977			return ! $.isArray( idx ) ?
28978				$.inArray( idx, order ) :
28979				$.map( idx, function ( index ) {
28980					return $.inArray( index, order );
28981				} );
28982		}
28983		else {
28984			// Given a current index, want the original
28985			return ! $.isArray( idx ) ?
28986				columns[idx]._ColReorder_iOrigCol :
28987				$.map( idx, function ( index ) {
28988					return columns[index]._ColReorder_iOrigCol;
28989				} );
28990		}
28991	},
28992
28993
28994	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
28995	 * Private methods (they are of course public in JS, but recommended as private)
28996	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
28997
28998	/**
28999	 * Constructor logic
29000	 *  @method  _fnConstruct
29001	 *  @returns void
29002	 *  @private
29003	 */
29004	"_fnConstruct": function ()
29005	{
29006		var that = this;
29007		var iLen = this.s.dt.aoColumns.length;
29008		var table = this.s.dt.nTable;
29009		var i;
29010
29011		/* Columns discounted from reordering - counting left to right */
29012		if ( this.s.init.iFixedColumns )
29013		{
29014			this.s.fixed = this.s.init.iFixedColumns;
29015		}
29016
29017		if ( this.s.init.iFixedColumnsLeft )
29018		{
29019			this.s.fixed = this.s.init.iFixedColumnsLeft;
29020		}
29021
29022		/* Columns discounted from reordering - counting right to left */
29023		this.s.fixedRight = this.s.init.iFixedColumnsRight ?
29024			this.s.init.iFixedColumnsRight :
29025			0;
29026
29027		/* Drop callback initialisation option */
29028		if ( this.s.init.fnReorderCallback )
29029		{
29030			this.s.reorderCallback = this.s.init.fnReorderCallback;
29031		}
29032
29033		/* Add event handlers for the drag and drop, and also mark the original column order */
29034		for ( i = 0; i < iLen; i++ )
29035		{
29036			if ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight )
29037			{
29038				this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
29039			}
29040
29041			/* Mark the original column order for later reference */
29042			this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
29043		}
29044
29045		/* State saving */
29046		this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
29047			that._fnStateSave.call( that, oData );
29048		}, "ColReorder_State" );
29049
29050		/* An initial column order has been specified */
29051		var aiOrder = null;
29052		if ( this.s.init.aiOrder )
29053		{
29054			aiOrder = this.s.init.aiOrder.slice();
29055		}
29056
29057		/* State loading, overrides the column order given */
29058		if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
29059		  this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
29060		{
29061			aiOrder = this.s.dt.oLoadedState.ColReorder;
29062		}
29063
29064		/* If we have an order to apply - do so */
29065		if ( aiOrder )
29066		{
29067			/* We might be called during or after the DataTables initialisation. If before, then we need
29068			 * to wait until the draw is done, if after, then do what we need to do right away
29069			 */
29070			if ( !that.s.dt._bInitComplete )
29071			{
29072				var bDone = false;
29073				$(table).on( 'draw.dt.colReorder', function () {
29074					if ( !that.s.dt._bInitComplete && !bDone )
29075					{
29076						bDone = true;
29077						var resort = fnInvertKeyValues( aiOrder );
29078						that._fnOrderColumns.call( that, resort );
29079					}
29080				} );
29081			}
29082			else
29083			{
29084				var resort = fnInvertKeyValues( aiOrder );
29085				that._fnOrderColumns.call( that, resort );
29086			}
29087		}
29088		else {
29089			this._fnSetColumnIndexes();
29090		}
29091
29092		// Destroy clean up
29093		$(table).on( 'destroy.dt.colReorder', function () {
29094			$(table).off( 'destroy.dt.colReorder draw.dt.colReorder' );
29095
29096			$.each( that.s.dt.aoColumns, function (i, column) {
29097				$(column.nTh).off('.ColReorder');
29098				$(column.nTh).removeAttr('data-column-index');
29099			} );
29100
29101			that.s.dt._colReorder = null;
29102			that.s = null;
29103		} );
29104	},
29105
29106
29107	/**
29108	 * Set the column order from an array
29109	 *  @method  _fnOrderColumns
29110	 *  @param   array a An array of integers which dictate the column order that should be applied
29111	 *  @returns void
29112	 *  @private
29113	 */
29114	"_fnOrderColumns": function ( a )
29115	{
29116		var changed = false;
29117
29118		if ( a.length != this.s.dt.aoColumns.length )
29119		{
29120			this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+
29121				"match known number of columns. Skipping." );
29122			return;
29123		}
29124
29125		for ( var i=0, iLen=a.length ; i<iLen ; i++ )
29126		{
29127			var currIndex = $.inArray( i, a );
29128			if ( i != currIndex )
29129			{
29130				/* Reorder our switching array */
29131				fnArraySwitch( a, currIndex, i );
29132
29133				/* Do the column reorder in the table */
29134				this.s.dt.oInstance.fnColReorder( currIndex, i, true, false );
29135
29136				changed = true;
29137			}
29138		}
29139
29140		this._fnSetColumnIndexes();
29141
29142		// Has anything actually changed? If not, then nothing else to do
29143		if ( ! changed ) {
29144			return;
29145		}
29146
29147		$.fn.dataTable.Api( this.s.dt ).rows().invalidate();
29148
29149		/* When scrolling we need to recalculate the column sizes to allow for the shift */
29150		if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
29151		{
29152			this.s.dt.oInstance.fnAdjustColumnSizing( false );
29153		}
29154
29155		/* Save the state */
29156		this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
29157
29158		if ( this.s.reorderCallback !== null )
29159		{
29160			this.s.reorderCallback.call( this );
29161		}
29162	},
29163
29164
29165	/**
29166	 * Because we change the indexes of columns in the table, relative to their starting point
29167	 * we need to reorder the state columns to what they are at the starting point so we can
29168	 * then rearrange them again on state load!
29169	 *  @method  _fnStateSave
29170	 *  @param   object oState DataTables state
29171	 *  @returns string JSON encoded cookie string for DataTables
29172	 *  @private
29173	 */
29174	"_fnStateSave": function ( oState )
29175	{
29176		var i, iLen, aCopy, iOrigColumn;
29177		var oSettings = this.s.dt;
29178		var columns = oSettings.aoColumns;
29179
29180		oState.ColReorder = [];
29181
29182		/* Sorting */
29183		if ( oState.aaSorting ) {
29184			// 1.10.0-
29185			for ( i=0 ; i<oState.aaSorting.length ; i++ ) {
29186				oState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
29187			}
29188
29189			var aSearchCopy = $.extend( true, [], oState.aoSearchCols );
29190
29191			for ( i=0, iLen=columns.length ; i<iLen ; i++ )
29192			{
29193				iOrigColumn = columns[i]._ColReorder_iOrigCol;
29194
29195				/* Column filter */
29196				oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
29197
29198				/* Visibility */
29199				oState.abVisCols[ iOrigColumn ] = columns[i].bVisible;
29200
29201				/* Column reordering */
29202				oState.ColReorder.push( iOrigColumn );
29203			}
29204		}
29205		else if ( oState.order ) {
29206			// 1.10.1+
29207			for ( i=0 ; i<oState.order.length ; i++ ) {
29208				oState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol;
29209			}
29210
29211			var stateColumnsCopy = $.extend( true, [], oState.columns );
29212
29213			for ( i=0, iLen=columns.length ; i<iLen ; i++ )
29214			{
29215				iOrigColumn = columns[i]._ColReorder_iOrigCol;
29216
29217				/* Columns */
29218				oState.columns[ iOrigColumn ] = stateColumnsCopy[i];
29219
29220				/* Column reordering */
29221				oState.ColReorder.push( iOrigColumn );
29222			}
29223		}
29224	},
29225
29226
29227	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29228	 * Mouse drop and drag
29229	 */
29230
29231	/**
29232	 * Add a mouse down listener to a particluar TH element
29233	 *  @method  _fnMouseListener
29234	 *  @param   int i Column index
29235	 *  @param   element nTh TH element clicked on
29236	 *  @returns void
29237	 *  @private
29238	 */
29239	"_fnMouseListener": function ( i, nTh )
29240	{
29241		var that = this;
29242		$(nTh)
29243			.on( 'mousedown.ColReorder', function (e) {
29244				if ( that.s.enable ) {
29245					that._fnMouseDown.call( that, e, nTh );
29246				}
29247			} )
29248			.on( 'touchstart.ColReorder', function (e) {
29249				if ( that.s.enable ) {
29250					that._fnMouseDown.call( that, e, nTh );
29251				}
29252			} );
29253	},
29254
29255
29256	/**
29257	 * Mouse down on a TH element in the table header
29258	 *  @method  _fnMouseDown
29259	 *  @param   event e Mouse event
29260	 *  @param   element nTh TH element to be dragged
29261	 *  @returns void
29262	 *  @private
29263	 */
29264	"_fnMouseDown": function ( e, nTh )
29265	{
29266		var that = this;
29267
29268		/* Store information about the mouse position */
29269		var target = $(e.target).closest('th, td');
29270		var offset = target.offset();
29271		var idx = parseInt( $(nTh).attr('data-column-index'), 10 );
29272
29273		if ( idx === undefined ) {
29274			return;
29275		}
29276
29277		this.s.mouse.startX = this._fnCursorPosition( e, 'pageX' );
29278		this.s.mouse.startY = this._fnCursorPosition( e, 'pageY' );
29279		this.s.mouse.offsetX = this._fnCursorPosition( e, 'pageX' ) - offset.left;
29280		this.s.mouse.offsetY = this._fnCursorPosition( e, 'pageY' ) - offset.top;
29281		this.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0];
29282		this.s.mouse.targetIndex = idx;
29283		this.s.mouse.fromIndex = idx;
29284
29285		this._fnRegions();
29286
29287		/* Add event handlers to the document */
29288		$(document)
29289			.on( 'mousemove.ColReorder touchmove.ColReorder', function (e) {
29290				that._fnMouseMove.call( that, e );
29291			} )
29292			.on( 'mouseup.ColReorder touchend.ColReorder', function (e) {
29293				that._fnMouseUp.call( that, e );
29294			} );
29295	},
29296
29297
29298	/**
29299	 * Deal with a mouse move event while dragging a node
29300	 *  @method  _fnMouseMove
29301	 *  @param   event e Mouse event
29302	 *  @returns void
29303	 *  @private
29304	 */
29305	"_fnMouseMove": function ( e )
29306	{
29307		var that = this;
29308
29309		if ( this.dom.drag === null )
29310		{
29311			/* Only create the drag element if the mouse has moved a specific distance from the start
29312			 * point - this allows the user to make small mouse movements when sorting and not have a
29313			 * possibly confusing drag element showing up
29314			 */
29315			if ( Math.pow(
29316				Math.pow(this._fnCursorPosition( e, 'pageX') - this.s.mouse.startX, 2) +
29317				Math.pow(this._fnCursorPosition( e, 'pageY') - this.s.mouse.startY, 2), 0.5 ) < 5 )
29318			{
29319				return;
29320			}
29321			this._fnCreateDragNode();
29322		}
29323
29324		/* Position the element - we respect where in the element the click occured */
29325		this.dom.drag.css( {
29326			left: this._fnCursorPosition( e, 'pageX' ) - this.s.mouse.offsetX,
29327			top: this._fnCursorPosition( e, 'pageY' ) - this.s.mouse.offsetY
29328		} );
29329
29330		/* Based on the current mouse position, calculate where the insert should go */
29331		var bSet = false;
29332		var lastToIndex = this.s.mouse.toIndex;
29333
29334		for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )
29335		{
29336			if ( this._fnCursorPosition(e, 'pageX') < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )
29337			{
29338				this.dom.pointer.css( 'left', this.s.aoTargets[i-1].x );
29339				this.s.mouse.toIndex = this.s.aoTargets[i-1].to;
29340				bSet = true;
29341				break;
29342			}
29343		}
29344
29345		// The insert element wasn't positioned in the array (less than
29346		// operator), so we put it at the end
29347		if ( !bSet )
29348		{
29349			this.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x );
29350			this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;
29351		}
29352
29353		// Perform reordering if realtime updating is on and the column has moved
29354		if ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) {
29355			this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
29356			this.s.mouse.fromIndex = this.s.mouse.toIndex;
29357
29358			// Not great for performance, but required to keep everything in alignment
29359			if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
29360			{
29361				this.s.dt.oInstance.fnAdjustColumnSizing( false );
29362			}
29363
29364			this._fnRegions();
29365		}
29366	},
29367
29368
29369	/**
29370	 * Finish off the mouse drag and insert the column where needed
29371	 *  @method  _fnMouseUp
29372	 *  @param   event e Mouse event
29373	 *  @returns void
29374	 *  @private
29375	 */
29376	"_fnMouseUp": function ( e )
29377	{
29378		var that = this;
29379
29380		$(document).off( '.ColReorder' );
29381
29382		if ( this.dom.drag !== null )
29383		{
29384			/* Remove the guide elements */
29385			this.dom.drag.remove();
29386			this.dom.pointer.remove();
29387			this.dom.drag = null;
29388			this.dom.pointer = null;
29389
29390			/* Actually do the reorder */
29391			this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, true );
29392			this._fnSetColumnIndexes();
29393
29394			/* When scrolling we need to recalculate the column sizes to allow for the shift */
29395			if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
29396			{
29397				this.s.dt.oInstance.fnAdjustColumnSizing( false );
29398			}
29399
29400			/* Save the state */
29401			this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
29402
29403			if ( this.s.reorderCallback !== null )
29404			{
29405				this.s.reorderCallback.call( this );
29406			}
29407		}
29408	},
29409
29410
29411	/**
29412	 * Calculate a cached array with the points of the column inserts, and the
29413	 * 'to' points
29414	 *  @method  _fnRegions
29415	 *  @returns void
29416	 *  @private
29417	 */
29418	"_fnRegions": function ()
29419	{
29420		var aoColumns = this.s.dt.aoColumns;
29421
29422		this.s.aoTargets.splice( 0, this.s.aoTargets.length );
29423
29424		this.s.aoTargets.push( {
29425			"x":  $(this.s.dt.nTable).offset().left,
29426			"to": 0
29427		} );
29428
29429		var iToPoint = 0;
29430		var total = this.s.aoTargets[0].x;
29431
29432		for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
29433		{
29434			/* For the column / header in question, we want it's position to remain the same if the
29435			 * position is just to it's immediate left or right, so we only increment the counter for
29436			 * other columns
29437			 */
29438			if ( i != this.s.mouse.fromIndex )
29439			{
29440				iToPoint++;
29441			}
29442
29443			if ( aoColumns[i].bVisible && aoColumns[i].nTh.style.display !=='none' )
29444			{
29445				total += $(aoColumns[i].nTh).outerWidth();
29446
29447				this.s.aoTargets.push( {
29448					"x":  total,
29449					"to": iToPoint
29450				} );
29451			}
29452		}
29453
29454		/* Disallow columns for being reordered by drag and drop, counting right to left */
29455		if ( this.s.fixedRight !== 0 )
29456		{
29457			this.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight );
29458		}
29459
29460		/* Disallow columns for being reordered by drag and drop, counting left to right */
29461		if ( this.s.fixed !== 0 )
29462		{
29463			this.s.aoTargets.splice( 0, this.s.fixed );
29464		}
29465	},
29466
29467
29468	/**
29469	 * Copy the TH element that is being drags so the user has the idea that they are actually
29470	 * moving it around the page.
29471	 *  @method  _fnCreateDragNode
29472	 *  @returns void
29473	 *  @private
29474	 */
29475	"_fnCreateDragNode": function ()
29476	{
29477		var scrolling = this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "";
29478
29479		var origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh;
29480		var origTr = origCell.parentNode;
29481		var origThead = origTr.parentNode;
29482		var origTable = origThead.parentNode;
29483		var cloneCell = $(origCell).clone();
29484
29485		// This is a slightly odd combination of jQuery and DOM, but it is the
29486		// fastest and least resource intensive way I could think of cloning
29487		// the table with just a single header cell in it.
29488		this.dom.drag = $(origTable.cloneNode(false))
29489			.addClass( 'DTCR_clonedTable' )
29490			.append(
29491				$(origThead.cloneNode(false)).append(
29492					$(origTr.cloneNode(false)).append(
29493						cloneCell[0]
29494					)
29495				)
29496			)
29497			.css( {
29498				position: 'absolute',
29499				top: 0,
29500				left: 0,
29501				width: $(origCell).outerWidth(),
29502				height: $(origCell).outerHeight()
29503			} )
29504			.appendTo( 'body' );
29505
29506		this.dom.pointer = $('<div></div>')
29507			.addClass( 'DTCR_pointer' )
29508			.css( {
29509				position: 'absolute',
29510				top: scrolling ?
29511					$('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top :
29512					$(this.s.dt.nTable).offset().top,
29513				height : scrolling ?
29514					$('div.dataTables_scroll', this.s.dt.nTableWrapper).height() :
29515					$(this.s.dt.nTable).height()
29516			} )
29517			.appendTo( 'body' );
29518	},
29519
29520
29521	/**
29522	 * Add a data attribute to the column headers, so we know the index of
29523	 * the row to be reordered. This allows fast detection of the index, and
29524	 * for this plug-in to work with FixedHeader which clones the nodes.
29525	 *  @private
29526	 */
29527	"_fnSetColumnIndexes": function ()
29528	{
29529		$.each( this.s.dt.aoColumns, function (i, column) {
29530			$(column.nTh).attr('data-column-index', i);
29531		} );
29532	},
29533
29534
29535	/**
29536	 * Get cursor position regardless of mouse or touch input
29537	 * @param  {Event}  e    jQuery Event
29538	 * @param  {string} prop Property to get
29539	 * @return {number}      Value
29540	 */
29541	_fnCursorPosition: function ( e, prop ) {
29542		if ( e.type.indexOf('touch') !== -1 ) {
29543			return e.originalEvent.touches[0][ prop ];
29544		}
29545		return e[ prop ];
29546	}
29547} );
29548
29549
29550
29551
29552
29553/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29554 * Static parameters
29555 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
29556
29557
29558/**
29559 * ColReorder default settings for initialisation
29560 *  @namespace
29561 *  @static
29562 */
29563ColReorder.defaults = {
29564	/**
29565	 * Predefined ordering for the columns that will be applied automatically
29566	 * on initialisation. If not specified then the order that the columns are
29567	 * found to be in the HTML is the order used.
29568	 *  @type array
29569	 *  @default null
29570	 *  @static
29571	 */
29572	aiOrder: null,
29573
29574	/**
29575	 * ColReorder enable on initialisation
29576	 *  @type boolean
29577	 *  @default true
29578	 *  @static
29579	 */
29580	bEnable: true,
29581
29582	/**
29583	 * Redraw the table's column ordering as the end user draws the column
29584	 * (`true`) or wait until the mouse is released (`false` - default). Note
29585	 * that this will perform a redraw on each reordering, which involves an
29586	 * Ajax request each time if you are using server-side processing in
29587	 * DataTables.
29588	 *  @type boolean
29589	 *  @default false
29590	 *  @static
29591	 */
29592	bRealtime: true,
29593
29594	/**
29595	 * Indicate how many columns should be fixed in position (counting from the
29596	 * left). This will typically be 1 if used, but can be as high as you like.
29597	 *  @type int
29598	 *  @default 0
29599	 *  @static
29600	 */
29601	iFixedColumnsLeft: 0,
29602
29603	/**
29604	 * As `iFixedColumnsRight` but counting from the right.
29605	 *  @type int
29606	 *  @default 0
29607	 *  @static
29608	 */
29609	iFixedColumnsRight: 0,
29610
29611	/**
29612	 * Callback function that is fired when columns are reordered. The `column-
29613	 * reorder` event is preferred over this callback
29614	 *  @type function():void
29615	 *  @default null
29616	 *  @static
29617	 */
29618	fnReorderCallback: null
29619};
29620
29621
29622
29623/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29624 * Constants
29625 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
29626
29627/**
29628 * ColReorder version
29629 *  @constant  version
29630 *  @type      String
29631 *  @default   As code
29632 */
29633ColReorder.version = "1.5.0";
29634
29635
29636
29637/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29638 * DataTables interfaces
29639 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
29640
29641// Expose
29642$.fn.dataTable.ColReorder = ColReorder;
29643$.fn.DataTable.ColReorder = ColReorder;
29644
29645
29646// Register a new feature with DataTables
29647if ( typeof $.fn.dataTable == "function" &&
29648     typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
29649     $.fn.dataTableExt.fnVersionCheck('1.10.8') )
29650{
29651	$.fn.dataTableExt.aoFeatures.push( {
29652		"fnInit": function( settings ) {
29653			var table = settings.oInstance;
29654
29655			if ( ! settings._colReorder ) {
29656				var dtInit = settings.oInit;
29657				var opts = dtInit.colReorder || dtInit.oColReorder || {};
29658
29659				new ColReorder( settings, opts );
29660			}
29661			else {
29662				table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
29663			}
29664
29665			return null; /* No node for DataTables to insert */
29666		},
29667		"cFeature": "R",
29668		"sFeature": "ColReorder"
29669	} );
29670}
29671else {
29672	alert( "Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download");
29673}
29674
29675
29676// Attach a listener to the document which listens for DataTables initialisation
29677// events so we can automatically initialise
29678$(document).on( 'preInit.dt.colReorder', function (e, settings) {
29679	if ( e.namespace !== 'dt' ) {
29680		return;
29681	}
29682
29683	var init = settings.oInit.colReorder;
29684	var defaults = DataTable.defaults.colReorder;
29685
29686	if ( init || defaults ) {
29687		var opts = $.extend( {}, init, defaults );
29688
29689		if ( init !== false ) {
29690			new ColReorder( settings, opts  );
29691		}
29692	}
29693} );
29694
29695
29696// API augmentation
29697$.fn.dataTable.Api.register( 'colReorder.reset()', function () {
29698	return this.iterator( 'table', function ( ctx ) {
29699		ctx._colReorder.fnReset();
29700	} );
29701} );
29702
29703$.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) {
29704	if ( set ) {
29705		return this.iterator( 'table', function ( ctx ) {
29706			ctx._colReorder.fnOrder( set, original );
29707		} );
29708	}
29709
29710	return this.context.length ?
29711		this.context[0]._colReorder.fnOrder() :
29712		null;
29713} );
29714
29715$.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) {
29716	return this.context.length && this.context[0]._colReorder ?
29717		this.context[0]._colReorder.fnTranspose( idx, dir ) :
29718		idx;
29719} );
29720
29721$.fn.dataTable.Api.register( 'colReorder.move()', function( from, to, drop, invalidateRows ) {
29722	if (this.context.length) {
29723		this.context[0]._colReorder.s.dt.oInstance.fnColReorder( from, to, drop, invalidateRows );
29724	}
29725	return this;
29726} );
29727
29728$.fn.dataTable.Api.register( 'colReorder.enable()', function( flag ) {
29729	return this.iterator( 'table', function ( ctx ) {
29730		if ( ctx._colReorder ) {
29731			ctx._colReorder.fnEnable( flag );
29732		}
29733	} );
29734} );
29735
29736$.fn.dataTable.Api.register( 'colReorder.disable()', function() {
29737	return this.iterator( 'table', function ( ctx ) {
29738		if ( ctx._colReorder ) {
29739			ctx._colReorder.fnDisable();
29740		}
29741	} );
29742} );
29743
29744
29745return ColReorder;
29746}));
29747
29748
29749/*! FixedHeader 3.1.4
29750 * ©2009-2018 SpryMedia Ltd - datatables.net/license
29751 */
29752
29753/**
29754 * @summary     FixedHeader
29755 * @description Fix a table's header or footer, so it is always visible while
29756 *              scrolling
29757 * @version     3.1.4
29758 * @file        dataTables.fixedHeader.js
29759 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
29760 * @contact     www.sprymedia.co.uk/contact
29761 * @copyright   Copyright 2009-2018 SpryMedia Ltd.
29762 *
29763 * This source file is free software, available under the following license:
29764 *   MIT license - http://datatables.net/license/mit
29765 *
29766 * This source file is distributed in the hope that it will be useful, but
29767 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
29768 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
29769 *
29770 * For details please refer to: http://www.datatables.net
29771 */
29772
29773(function( factory ){
29774	if ( typeof define === 'function' && define.amd ) {
29775		// AMD
29776		define( ['jquery', 'datatables.net'], function ( $ ) {
29777			return factory( $, window, document );
29778		} );
29779	}
29780	else if ( typeof exports === 'object' ) {
29781		// CommonJS
29782		module.exports = function (root, $) {
29783			if ( ! root ) {
29784				root = window;
29785			}
29786
29787			if ( ! $ || ! $.fn.dataTable ) {
29788				$ = require('datatables.net')(root, $).$;
29789			}
29790
29791			return factory( $, root, root.document );
29792		};
29793	}
29794	else {
29795		// Browser
29796		factory( jQuery, window, document );
29797	}
29798}(function( $, window, document, undefined ) {
29799'use strict';
29800var DataTable = $.fn.dataTable;
29801
29802
29803var _instCounter = 0;
29804
29805var FixedHeader = function ( dt, config ) {
29806	// Sanity check - you just know it will happen
29807	if ( ! (this instanceof FixedHeader) ) {
29808		throw "FixedHeader must be initialised with the 'new' keyword.";
29809	}
29810
29811	// Allow a boolean true for defaults
29812	if ( config === true ) {
29813		config = {};
29814	}
29815
29816	dt = new DataTable.Api( dt );
29817
29818	this.c = $.extend( true, {}, FixedHeader.defaults, config );
29819
29820	this.s = {
29821		dt: dt,
29822		position: {
29823			theadTop: 0,
29824			tbodyTop: 0,
29825			tfootTop: 0,
29826			tfootBottom: 0,
29827			width: 0,
29828			left: 0,
29829			tfootHeight: 0,
29830			theadHeight: 0,
29831			windowHeight: $(window).height(),
29832			visible: true
29833		},
29834		headerMode: null,
29835		footerMode: null,
29836		autoWidth: dt.settings()[0].oFeatures.bAutoWidth,
29837		namespace: '.dtfc'+(_instCounter++),
29838		scrollLeft: {
29839			header: -1,
29840			footer: -1
29841		},
29842		enable: true
29843	};
29844
29845	this.dom = {
29846		floatingHeader: null,
29847		thead: $(dt.table().header()),
29848		tbody: $(dt.table().body()),
29849		tfoot: $(dt.table().footer()),
29850		header: {
29851			host: null,
29852			floating: null,
29853			placeholder: null
29854		},
29855		footer: {
29856			host: null,
29857			floating: null,
29858			placeholder: null
29859		}
29860	};
29861
29862	this.dom.header.host = this.dom.thead.parent();
29863	this.dom.footer.host = this.dom.tfoot.parent();
29864
29865	var dtSettings = dt.settings()[0];
29866	if ( dtSettings._fixedHeader ) {
29867		throw "FixedHeader already initialised on table "+dtSettings.nTable.id;
29868	}
29869
29870	dtSettings._fixedHeader = this;
29871
29872	this._constructor();
29873};
29874
29875
29876/*
29877 * Variable: FixedHeader
29878 * Purpose:  Prototype for FixedHeader
29879 * Scope:    global
29880 */
29881$.extend( FixedHeader.prototype, {
29882	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29883	 * API methods
29884	 */
29885	
29886	/**
29887	 * Enable / disable the fixed elements
29888	 *
29889	 * @param  {boolean} enable `true` to enable, `false` to disable
29890	 */
29891	enable: function ( enable )
29892	{
29893		this.s.enable = enable;
29894
29895		if ( this.c.header ) {
29896			this._modeChange( 'in-place', 'header', true );
29897		}
29898
29899		if ( this.c.footer && this.dom.tfoot.length ) {
29900			this._modeChange( 'in-place', 'footer', true );
29901		}
29902
29903		this.update();
29904	},
29905	
29906	/**
29907	 * Set header offset 
29908	 *
29909	 * @param  {int} new value for headerOffset
29910	 */
29911	headerOffset: function ( offset )
29912	{
29913		if ( offset !== undefined ) {
29914			this.c.headerOffset = offset;
29915			this.update();
29916		}
29917
29918		return this.c.headerOffset;
29919	},
29920	
29921	/**
29922	 * Set footer offset
29923	 *
29924	 * @param  {int} new value for footerOffset
29925	 */
29926	footerOffset: function ( offset )
29927	{
29928		if ( offset !== undefined ) {
29929			this.c.footerOffset = offset;
29930			this.update();
29931		}
29932
29933		return this.c.footerOffset;
29934	},
29935
29936	
29937	/**
29938	 * Recalculate the position of the fixed elements and force them into place
29939	 */
29940	update: function ()
29941	{
29942		this._positions();
29943		this._scroll( true );
29944	},
29945
29946
29947	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29948	 * Constructor
29949	 */
29950	
29951	/**
29952	 * FixedHeader constructor - adding the required event listeners and
29953	 * simple initialisation
29954	 *
29955	 * @private
29956	 */
29957	_constructor: function ()
29958	{
29959		var that = this;
29960		var dt = this.s.dt;
29961
29962		$(window)
29963			.on( 'scroll'+this.s.namespace, function () {
29964				that._scroll();
29965			} )
29966			.on( 'resize'+this.s.namespace, DataTable.util.throttle( function () {
29967				that.s.position.windowHeight = $(window).height();
29968				that.update();
29969			}, 50 ) );
29970
29971		var autoHeader = $('.fh-fixedHeader');
29972		if ( ! this.c.headerOffset && autoHeader.length ) {
29973			this.c.headerOffset = autoHeader.outerHeight();
29974		}
29975
29976		var autoFooter = $('.fh-fixedFooter');
29977		if ( ! this.c.footerOffset && autoFooter.length ) {
29978			this.c.footerOffset = autoFooter.outerHeight();
29979		}
29980
29981		dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function () {
29982			that.update();
29983		} );
29984
29985		dt.on( 'destroy.dtfc', function () {
29986			if ( that.c.header ) {
29987				that._modeChange( 'in-place', 'header', true );
29988			}
29989
29990			if ( that.c.footer && that.dom.tfoot.length ) {
29991				that._modeChange( 'in-place', 'footer', true );
29992			}
29993
29994			dt.off( '.dtfc' );
29995			$(window).off( that.s.namespace );
29996		} );
29997
29998		this._positions();
29999		this._scroll();
30000	},
30001
30002
30003	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
30004	 * Private methods
30005	 */
30006
30007	/**
30008	 * Clone a fixed item to act as a place holder for the original element
30009	 * which is moved into a clone of the table element, and moved around the
30010	 * document to give the fixed effect.
30011	 *
30012	 * @param  {string}  item  'header' or 'footer'
30013	 * @param  {boolean} force Force the clone to happen, or allow automatic
30014	 *   decision (reuse existing if available)
30015	 * @private
30016	 */
30017	_clone: function ( item, force )
30018	{
30019		var dt = this.s.dt;
30020		var itemDom = this.dom[ item ];
30021		var itemElement = item === 'header' ?
30022			this.dom.thead :
30023			this.dom.tfoot;
30024
30025		if ( ! force && itemDom.floating ) {
30026			// existing floating element - reuse it
30027			itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );
30028		}
30029		else {
30030			if ( itemDom.floating ) {
30031				itemDom.placeholder.remove();
30032				this._unsize( item );
30033				itemDom.floating.children().detach();
30034				itemDom.floating.remove();
30035			}
30036
30037			itemDom.floating = $( dt.table().node().cloneNode( false ) )
30038				.css( 'table-layout', 'fixed' )
30039				.attr( 'aria-hidden', 'true' )
30040				.removeAttr( 'id' )
30041				.append( itemElement )
30042				.appendTo( 'body' );
30043
30044			// Insert a fake thead/tfoot into the DataTable to stop it jumping around
30045			itemDom.placeholder = itemElement.clone( false )
30046			itemDom.placeholder
30047				.find( '*[id]' )
30048				.removeAttr( 'id' );
30049
30050			itemDom.host.prepend( itemDom.placeholder );
30051
30052			// Clone widths
30053			this._matchWidths( itemDom.placeholder, itemDom.floating );
30054		}
30055	},
30056
30057	/**
30058	 * Copy widths from the cells in one element to another. This is required
30059	 * for the footer as the footer in the main table takes its sizes from the
30060	 * header columns. That isn't present in the footer so to have it still
30061	 * align correctly, the sizes need to be copied over. It is also required
30062	 * for the header when auto width is not enabled
30063	 *
30064	 * @param  {jQuery} from Copy widths from
30065	 * @param  {jQuery} to   Copy widths to
30066	 * @private
30067	 */
30068	_matchWidths: function ( from, to ) {
30069		var get = function ( name ) {
30070			return $(name, from)
30071				.map( function () {
30072					return $(this).width();
30073				} ).toArray();
30074		};
30075
30076		var set = function ( name, toWidths ) {
30077			$(name, to).each( function ( i ) {
30078				$(this).css( {
30079					width: toWidths[i],
30080					minWidth: toWidths[i]
30081				} );
30082			} );
30083		};
30084
30085		var thWidths = get( 'th' );
30086		var tdWidths = get( 'td' );
30087
30088		set( 'th', thWidths );
30089		set( 'td', tdWidths );
30090	},
30091
30092	/**
30093	 * Remove assigned widths from the cells in an element. This is required
30094	 * when inserting the footer back into the main table so the size is defined
30095	 * by the header columns and also when auto width is disabled in the
30096	 * DataTable.
30097	 *
30098	 * @param  {string} item The `header` or `footer`
30099	 * @private
30100	 */
30101	_unsize: function ( item ) {
30102		var el = this.dom[ item ].floating;
30103
30104		if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {
30105			$('th, td', el).css( {
30106				width: '',
30107				minWidth: ''
30108			} );
30109		}
30110		else if ( el && item === 'header' ) {
30111			$('th, td', el).css( 'min-width', '' );
30112		}
30113	},
30114
30115	/**
30116	 * Reposition the floating elements to take account of horizontal page
30117	 * scroll
30118	 *
30119	 * @param  {string} item       The `header` or `footer`
30120	 * @param  {int}    scrollLeft Document scrollLeft
30121	 * @private
30122	 */
30123	_horizontal: function ( item, scrollLeft )
30124	{
30125		var itemDom = this.dom[ item ];
30126		var position = this.s.position;
30127		var lastScrollLeft = this.s.scrollLeft;
30128
30129		if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {
30130			itemDom.floating.css( 'left', position.left - scrollLeft );
30131
30132			lastScrollLeft[ item ] = scrollLeft;
30133		}
30134	},
30135
30136	/**
30137	 * Change from one display mode to another. Each fixed item can be in one
30138	 * of:
30139	 *
30140	 * * `in-place` - In the main DataTable
30141	 * * `in` - Floating over the DataTable
30142	 * * `below` - (Header only) Fixed to the bottom of the table body
30143	 * * `above` - (Footer only) Fixed to the top of the table body
30144	 * 
30145	 * @param  {string}  mode        Mode that the item should be shown in
30146	 * @param  {string}  item        'header' or 'footer'
30147	 * @param  {boolean} forceChange Force a redraw of the mode, even if already
30148	 *     in that mode.
30149	 * @private
30150	 */
30151	_modeChange: function ( mode, item, forceChange )
30152	{
30153		var dt = this.s.dt;
30154		var itemDom = this.dom[ item ];
30155		var position = this.s.position;
30156
30157		// Record focus. Browser's will cause input elements to loose focus if
30158		// they are inserted else where in the doc
30159		var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];
30160		var focus = $.contains( tablePart[0], document.activeElement ) ?
30161			document.activeElement :
30162			null;
30163		
30164		if ( focus ) {
30165			focus.blur();
30166		}
30167
30168		if ( mode === 'in-place' ) {
30169			// Insert the header back into the table's real header
30170			if ( itemDom.placeholder ) {
30171				itemDom.placeholder.remove();
30172				itemDom.placeholder = null;
30173			}
30174
30175			this._unsize( item );
30176
30177			if ( item === 'header' ) {
30178				itemDom.host.prepend( tablePart );
30179			}
30180			else {
30181				itemDom.host.append( tablePart );
30182			}
30183
30184			if ( itemDom.floating ) {
30185				itemDom.floating.remove();
30186				itemDom.floating = null;
30187			}
30188		}
30189		else if ( mode === 'in' ) {
30190			// Remove the header from the read header and insert into a fixed
30191			// positioned floating table clone
30192			this._clone( item, forceChange );
30193
30194			itemDom.floating
30195				.addClass( 'fixedHeader-floating' )
30196				.css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )
30197				.css( 'left', position.left+'px' )
30198				.css( 'width', position.width+'px' );
30199
30200			if ( item === 'footer' ) {
30201				itemDom.floating.css( 'top', '' );
30202			}
30203		}
30204		else if ( mode === 'below' ) { // only used for the header
30205			// Fix the position of the floating header at base of the table body
30206			this._clone( item, forceChange );
30207
30208			itemDom.floating
30209				.addClass( 'fixedHeader-locked' )
30210				.css( 'top', position.tfootTop - position.theadHeight )
30211				.css( 'left', position.left+'px' )
30212				.css( 'width', position.width+'px' );
30213		}
30214		else if ( mode === 'above' ) { // only used for the footer
30215			// Fix the position of the floating footer at top of the table body
30216			this._clone( item, forceChange );
30217
30218			itemDom.floating
30219				.addClass( 'fixedHeader-locked' )
30220				.css( 'top', position.tbodyTop )
30221				.css( 'left', position.left+'px' )
30222				.css( 'width', position.width+'px' );
30223		}
30224
30225		// Restore focus if it was lost
30226		if ( focus && focus !== document.activeElement ) {
30227			setTimeout( function () {
30228				focus.focus();
30229			}, 10 );
30230		}
30231
30232		this.s.scrollLeft.header = -1;
30233		this.s.scrollLeft.footer = -1;
30234		this.s[item+'Mode'] = mode;
30235	},
30236
30237	/**
30238	 * Cache the positional information that is required for the mode
30239	 * calculations that FixedHeader performs.
30240	 *
30241	 * @private
30242	 */
30243	_positions: function ()
30244	{
30245		var dt = this.s.dt;
30246		var table = dt.table();
30247		var position = this.s.position;
30248		var dom = this.dom;
30249		var tableNode = $(table.node());
30250
30251		// Need to use the header and footer that are in the main table,
30252		// regardless of if they are clones, since they hold the positions we
30253		// want to measure from
30254		var thead = tableNode.children('thead');
30255		var tfoot = tableNode.children('tfoot');
30256		var tbody = dom.tbody;
30257
30258		position.visible = tableNode.is(':visible');
30259		position.width = tableNode.outerWidth();
30260		position.left = tableNode.offset().left;
30261		position.theadTop = thead.offset().top;
30262		position.tbodyTop = tbody.offset().top;
30263		position.theadHeight = position.tbodyTop - position.theadTop;
30264
30265		if ( tfoot.length ) {
30266			position.tfootTop = tfoot.offset().top;
30267			position.tfootBottom = position.tfootTop + tfoot.outerHeight();
30268			position.tfootHeight = position.tfootBottom - position.tfootTop;
30269		}
30270		else {
30271			position.tfootTop = position.tbodyTop + tbody.outerHeight();
30272			position.tfootBottom = position.tfootTop;
30273			position.tfootHeight = position.tfootTop;
30274		}
30275	},
30276
30277
30278	/**
30279	 * Mode calculation - determine what mode the fixed items should be placed
30280	 * into.
30281	 *
30282	 * @param  {boolean} forceChange Force a redraw of the mode, even if already
30283	 *     in that mode.
30284	 * @private
30285	 */
30286	_scroll: function ( forceChange )
30287	{
30288		var windowTop = $(document).scrollTop();
30289		var windowLeft = $(document).scrollLeft();
30290		var position = this.s.position;
30291		var headerMode, footerMode;
30292
30293		if ( ! this.s.enable ) {
30294			return;
30295		}
30296
30297		if ( this.c.header ) {
30298			if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {
30299				headerMode = 'in-place';
30300			}
30301			else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {
30302				headerMode = 'in';
30303			}
30304			else {
30305				headerMode = 'below';
30306			}
30307
30308			if ( forceChange || headerMode !== this.s.headerMode ) {
30309				this._modeChange( headerMode, 'header', forceChange );
30310			}
30311
30312			this._horizontal( 'header', windowLeft );
30313		}
30314
30315		if ( this.c.footer && this.dom.tfoot.length ) {
30316			if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {
30317				footerMode = 'in-place';
30318			}
30319			else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {
30320				footerMode = 'in';
30321			}
30322			else {
30323				footerMode = 'above';
30324			}
30325
30326			if ( forceChange || footerMode !== this.s.footerMode ) {
30327				this._modeChange( footerMode, 'footer', forceChange );
30328			}
30329
30330			this._horizontal( 'footer', windowLeft );
30331		}
30332	}
30333} );
30334
30335
30336/**
30337 * Version
30338 * @type {String}
30339 * @static
30340 */
30341FixedHeader.version = "3.1.4";
30342
30343/**
30344 * Defaults
30345 * @type {Object}
30346 * @static
30347 */
30348FixedHeader.defaults = {
30349	header: true,
30350	footer: false,
30351	headerOffset: 0,
30352	footerOffset: 0
30353};
30354
30355
30356/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
30357 * DataTables interfaces
30358 */
30359
30360// Attach for constructor access
30361$.fn.dataTable.FixedHeader = FixedHeader;
30362$.fn.DataTable.FixedHeader = FixedHeader;
30363
30364
30365// DataTables creation - check if the FixedHeader option has been defined on the
30366// table and if so, initialise
30367$(document).on( 'init.dt.dtfh', function (e, settings, json) {
30368	if ( e.namespace !== 'dt' ) {
30369		return;
30370	}
30371
30372	var init = settings.oInit.fixedHeader;
30373	var defaults = DataTable.defaults.fixedHeader;
30374
30375	if ( (init || defaults) && ! settings._fixedHeader ) {
30376		var opts = $.extend( {}, defaults, init );
30377
30378		if ( init !== false ) {
30379			new FixedHeader( settings, opts );
30380		}
30381	}
30382} );
30383
30384// DataTables API methods
30385DataTable.Api.register( 'fixedHeader()', function () {} );
30386
30387DataTable.Api.register( 'fixedHeader.adjust()', function () {
30388	return this.iterator( 'table', function ( ctx ) {
30389		var fh = ctx._fixedHeader;
30390
30391		if ( fh ) {
30392			fh.update();
30393		}
30394	} );
30395} );
30396
30397DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {
30398	return this.iterator( 'table', function ( ctx ) {
30399		var fh = ctx._fixedHeader;
30400
30401		flag = ( flag !== undefined ? flag : true );
30402		if ( fh && flag !== fh.s.enable ) {
30403			fh.enable( flag );
30404		}
30405	} );
30406} );
30407
30408DataTable.Api.register( 'fixedHeader.disable()', function ( ) {
30409	return this.iterator( 'table', function ( ctx ) {
30410		var fh = ctx._fixedHeader;
30411
30412		if ( fh && fh.s.enable ) {
30413			fh.enable( false );
30414		}
30415	} );
30416} );
30417
30418$.each( ['header', 'footer'], function ( i, el ) {
30419	DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {
30420		var ctx = this.context;
30421
30422		if ( offset === undefined ) {
30423			return ctx.length && ctx[0]._fixedHeader ?
30424				ctx[0]._fixedHeader[el +'Offset']() :
30425				undefined;
30426		}
30427
30428		return this.iterator( 'table', function ( ctx ) {
30429			var fh = ctx._fixedHeader;
30430
30431			if ( fh ) {
30432				fh[ el +'Offset' ]( offset );
30433			}
30434		} );
30435	} );
30436} );
30437
30438
30439return FixedHeader;
30440}));
30441
30442
30443/*! Responsive 2.2.2
30444 * 2014-2018 SpryMedia Ltd - datatables.net/license
30445 */
30446
30447/**
30448 * @summary     Responsive
30449 * @description Responsive tables plug-in for DataTables
30450 * @version     2.2.2
30451 * @file        dataTables.responsive.js
30452 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
30453 * @contact     www.sprymedia.co.uk/contact
30454 * @copyright   Copyright 2014-2018 SpryMedia Ltd.
30455 *
30456 * This source file is free software, available under the following license:
30457 *   MIT license - http://datatables.net/license/mit
30458 *
30459 * This source file is distributed in the hope that it will be useful, but
30460 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
30461 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
30462 *
30463 * For details please refer to: http://www.datatables.net
30464 */
30465(function( factory ){
30466	if ( typeof define === 'function' && define.amd ) {
30467		// AMD
30468		define( ['jquery', 'datatables.net'], function ( $ ) {
30469			return factory( $, window, document );
30470		} );
30471	}
30472	else if ( typeof exports === 'object' ) {
30473		// CommonJS
30474		module.exports = function (root, $) {
30475			if ( ! root ) {
30476				root = window;
30477			}
30478
30479			if ( ! $ || ! $.fn.dataTable ) {
30480				$ = require('datatables.net')(root, $).$;
30481			}
30482
30483			return factory( $, root, root.document );
30484		};
30485	}
30486	else {
30487		// Browser
30488		factory( jQuery, window, document );
30489	}
30490}(function( $, window, document, undefined ) {
30491'use strict';
30492var DataTable = $.fn.dataTable;
30493
30494
30495/**
30496 * Responsive is a plug-in for the DataTables library that makes use of
30497 * DataTables' ability to change the visibility of columns, changing the
30498 * visibility of columns so the displayed columns fit into the table container.
30499 * The end result is that complex tables will be dynamically adjusted to fit
30500 * into the viewport, be it on a desktop, tablet or mobile browser.
30501 *
30502 * Responsive for DataTables has two modes of operation, which can used
30503 * individually or combined:
30504 *
30505 * * Class name based control - columns assigned class names that match the
30506 *   breakpoint logic can be shown / hidden as required for each breakpoint.
30507 * * Automatic control - columns are automatically hidden when there is no
30508 *   room left to display them. Columns removed from the right.
30509 *
30510 * In additional to column visibility control, Responsive also has built into
30511 * options to use DataTables' child row display to show / hide the information
30512 * from the table that has been hidden. There are also two modes of operation
30513 * for this child row display:
30514 *
30515 * * Inline - when the control element that the user can use to show / hide
30516 *   child rows is displayed inside the first column of the table.
30517 * * Column - where a whole column is dedicated to be the show / hide control.
30518 *
30519 * Initialisation of Responsive is performed by:
30520 *
30521 * * Adding the class `responsive` or `dt-responsive` to the table. In this case
30522 *   Responsive will automatically be initialised with the default configuration
30523 *   options when the DataTable is created.
30524 * * Using the `responsive` option in the DataTables configuration options. This
30525 *   can also be used to specify the configuration options, or simply set to
30526 *   `true` to use the defaults.
30527 *
30528 *  @class
30529 *  @param {object} settings DataTables settings object for the host table
30530 *  @param {object} [opts] Configuration options
30531 *  @requires jQuery 1.7+
30532 *  @requires DataTables 1.10.3+
30533 *
30534 *  @example
30535 *      $('#example').DataTable( {
30536 *        responsive: true
30537 *      } );
30538 *    } );
30539 */
30540var Responsive = function ( settings, opts ) {
30541	// Sanity check that we are using DataTables 1.10 or newer
30542	if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) {
30543		throw 'DataTables Responsive requires DataTables 1.10.10 or newer';
30544	}
30545
30546	this.s = {
30547		dt: new DataTable.Api( settings ),
30548		columns: [],
30549		current: []
30550	};
30551
30552	// Check if responsive has already been initialised on this table
30553	if ( this.s.dt.settings()[0].responsive ) {
30554		return;
30555	}
30556
30557	// details is an object, but for simplicity the user can give it as a string
30558	// or a boolean
30559	if ( opts && typeof opts.details === 'string' ) {
30560		opts.details = { type: opts.details };
30561	}
30562	else if ( opts && opts.details === false ) {
30563		opts.details = { type: false };
30564	}
30565	else if ( opts && opts.details === true ) {
30566		opts.details = { type: 'inline' };
30567	}
30568
30569	this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
30570	settings.responsive = this;
30571	this._constructor();
30572};
30573
30574$.extend( Responsive.prototype, {
30575	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
30576	 * Constructor
30577	 */
30578
30579	/**
30580	 * Initialise the Responsive instance
30581	 *
30582	 * @private
30583	 */
30584	_constructor: function ()
30585	{
30586		var that = this;
30587		var dt = this.s.dt;
30588		var dtPrivateSettings = dt.settings()[0];
30589		var oldWindowWidth = $(window).width();
30590
30591		dt.settings()[0]._responsive = this;
30592
30593		// Use DataTables' throttle function to avoid processor thrashing on
30594		// resize
30595		$(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
30596			// iOS has a bug whereby resize can fire when only scrolling
30597			// See: http://stackoverflow.com/questions/8898412
30598			var width = $(window).width();
30599
30600			if ( width !== oldWindowWidth ) {
30601				that._resize();
30602				oldWindowWidth = width;
30603			}
30604		} ) );
30605
30606		// DataTables doesn't currently trigger an event when a row is added, so
30607		// we need to hook into its private API to enforce the hidden rows when
30608		// new data is added
30609		dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
30610			if ( $.inArray( false, that.s.current ) !== -1 ) {
30611				$('>td, >th', tr).each( function ( i ) {
30612					var idx = dt.column.index( 'toData', i );
30613
30614					if ( that.s.current[idx] === false ) {
30615						$(this).css('display', 'none');
30616					}
30617				} );
30618			}
30619		} );
30620
30621		// Destroy event handler
30622		dt.on( 'destroy.dtr', function () {
30623			dt.off( '.dtr' );
30624			$( dt.table().body() ).off( '.dtr' );
30625			$(window).off( 'resize.dtr orientationchange.dtr' );
30626
30627			// Restore the columns that we've hidden
30628			$.each( that.s.current, function ( i, val ) {
30629				if ( val === false ) {
30630					that._setColumnVis( i, true );
30631				}
30632			} );
30633		} );
30634
30635		// Reorder the breakpoints array here in case they have been added out
30636		// of order
30637		this.c.breakpoints.sort( function (a, b) {
30638			return a.width < b.width ? 1 :
30639				a.width > b.width ? -1 : 0;
30640		} );
30641
30642		this._classLogic();
30643		this._resizeAuto();
30644
30645		// Details handler
30646		var details = this.c.details;
30647
30648		if ( details.type !== false ) {
30649			that._detailsInit();
30650
30651			// DataTables will trigger this event on every column it shows and
30652			// hides individually
30653			dt.on( 'column-visibility.dtr', function () {
30654				// Use a small debounce to allow multiple columns to be set together
30655				if ( that._timer ) {
30656					clearTimeout( that._timer );
30657				}
30658
30659				that._timer = setTimeout( function () {
30660					that._timer = null;
30661
30662					that._classLogic();
30663					that._resizeAuto();
30664					that._resize();
30665
30666					that._redrawChildren();
30667				}, 100 );
30668			} );
30669
30670			// Redraw the details box on each draw which will happen if the data
30671			// has changed. This is used until DataTables implements a native
30672			// `updated` event for rows
30673			dt.on( 'draw.dtr', function () {
30674				that._redrawChildren();
30675			} );
30676
30677			$(dt.table().node()).addClass( 'dtr-'+details.type );
30678		}
30679
30680		dt.on( 'column-reorder.dtr', function (e, settings, details) {
30681			that._classLogic();
30682			that._resizeAuto();
30683			that._resize();
30684		} );
30685
30686		// Change in column sizes means we need to calc
30687		dt.on( 'column-sizing.dtr', function () {
30688			that._resizeAuto();
30689			that._resize();
30690		});
30691
30692		// On Ajax reload we want to reopen any child rows which are displayed
30693		// by responsive
30694		dt.on( 'preXhr.dtr', function () {
30695			var rowIds = [];
30696			dt.rows().every( function () {
30697				if ( this.child.isShown() ) {
30698					rowIds.push( this.id(true) );
30699				}
30700			} );
30701
30702			dt.one( 'draw.dtr', function () {
30703				that._resizeAuto();
30704				that._resize();
30705
30706				dt.rows( rowIds ).every( function () {
30707					that._detailsDisplay( this, false );
30708				} );
30709			} );
30710		});
30711
30712		dt.on( 'init.dtr', function (e, settings, details) {
30713			that._resizeAuto();
30714			that._resize();
30715
30716			// If columns were hidden, then DataTables needs to adjust the
30717			// column sizing
30718			if ( $.inArray( false, that.s.current ) ) {
30719				dt.columns.adjust();
30720			}
30721		} );
30722
30723		// First pass - draw the table for the current viewport size
30724		this._resize();
30725	},
30726
30727
30728	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
30729	 * Private methods
30730	 */
30731
30732	/**
30733	 * Calculate the visibility for the columns in a table for a given
30734	 * breakpoint. The result is pre-determined based on the class logic if
30735	 * class names are used to control all columns, but the width of the table
30736	 * is also used if there are columns which are to be automatically shown
30737	 * and hidden.
30738	 *
30739	 * @param  {string} breakpoint Breakpoint name to use for the calculation
30740	 * @return {array} Array of boolean values initiating the visibility of each
30741	 *   column.
30742	 *  @private
30743	 */
30744	_columnsVisiblity: function ( breakpoint )
30745	{
30746		var dt = this.s.dt;
30747		var columns = this.s.columns;
30748		var i, ien;
30749
30750		// Create an array that defines the column ordering based first on the
30751		// column's priority, and secondly the column index. This allows the
30752		// columns to be removed from the right if the priority matches
30753		var order = columns
30754			.map( function ( col, idx ) {
30755				return {
30756					columnIdx: idx,
30757					priority: col.priority
30758				};
30759			} )
30760			.sort( function ( a, b ) {
30761				if ( a.priority !== b.priority ) {
30762					return a.priority - b.priority;
30763				}
30764				return a.columnIdx - b.columnIdx;
30765			} );
30766
30767		// Class logic - determine which columns are in this breakpoint based
30768		// on the classes. If no class control (i.e. `auto`) then `-` is used
30769		// to indicate this to the rest of the function
30770		var display = $.map( columns, function ( col, i ) {
30771			if ( dt.column(i).visible() === false ) {
30772				return 'not-visible';
30773			}
30774			return col.auto && col.minWidth === null ?
30775				false :
30776				col.auto === true ?
30777					'-' :
30778					$.inArray( breakpoint, col.includeIn ) !== -1;
30779		} );
30780
30781		// Auto column control - first pass: how much width is taken by the
30782		// ones that must be included from the non-auto columns
30783		var requiredWidth = 0;
30784		for ( i=0, ien=display.length ; i<ien ; i++ ) {
30785			if ( display[i] === true ) {
30786				requiredWidth += columns[i].minWidth;
30787			}
30788		}
30789
30790		// Second pass, use up any remaining width for other columns. For
30791		// scrolling tables we need to subtract the width of the scrollbar. It
30792		// may not be requires which makes this sub-optimal, but it would
30793		// require another full redraw to make complete use of those extra few
30794		// pixels
30795		var scrolling = dt.settings()[0].oScroll;
30796		var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
30797		var widthAvailable = dt.table().container().offsetWidth - bar;
30798		var usedWidth = widthAvailable - requiredWidth;
30799
30800		// Control column needs to always be included. This makes it sub-
30801		// optimal in terms of using the available with, but to stop layout
30802		// thrashing or overflow. Also we need to account for the control column
30803		// width first so we know how much width is available for the other
30804		// columns, since the control column might not be the first one shown
30805		for ( i=0, ien=display.length ; i<ien ; i++ ) {
30806			if ( columns[i].control ) {
30807				usedWidth -= columns[i].minWidth;
30808			}
30809		}
30810
30811		// Allow columns to be shown (counting by priority and then right to
30812		// left) until we run out of room
30813		var empty = false;
30814		for ( i=0, ien=order.length ; i<ien ; i++ ) {
30815			var colIdx = order[i].columnIdx;
30816
30817			if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
30818				// Once we've found a column that won't fit we don't let any
30819				// others display either, or columns might disappear in the
30820				// middle of the table
30821				if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
30822					empty = true;
30823					display[colIdx] = false;
30824				}
30825				else {
30826					display[colIdx] = true;
30827				}
30828
30829				usedWidth -= columns[colIdx].minWidth;
30830			}
30831		}
30832
30833		// Determine if the 'control' column should be shown (if there is one).
30834		// This is the case when there is a hidden column (that is not the
30835		// control column). The two loops look inefficient here, but they are
30836		// trivial and will fly through. We need to know the outcome from the
30837		// first , before the action in the second can be taken
30838		var showControl = false;
30839
30840		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
30841			if ( ! columns[i].control && ! columns[i].never && display[i] === false ) {
30842				showControl = true;
30843				break;
30844			}
30845		}
30846
30847		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
30848			if ( columns[i].control ) {
30849				display[i] = showControl;
30850			}
30851
30852			// Replace not visible string with false from the control column detection above
30853			if ( display[i] === 'not-visible' ) {
30854				display[i] = false;
30855			}
30856		}
30857
30858		// Finally we need to make sure that there is at least one column that
30859		// is visible
30860		if ( $.inArray( true, display ) === -1 ) {
30861			display[0] = true;
30862		}
30863
30864		return display;
30865	},
30866
30867
30868	/**
30869	 * Create the internal `columns` array with information about the columns
30870	 * for the table. This includes determining which breakpoints the column
30871	 * will appear in, based upon class names in the column, which makes up the
30872	 * vast majority of this method.
30873	 *
30874	 * @private
30875	 */
30876	_classLogic: function ()
30877	{
30878		var that = this;
30879		var calc = {};
30880		var breakpoints = this.c.breakpoints;
30881		var dt = this.s.dt;
30882		var columns = dt.columns().eq(0).map( function (i) {
30883			var column = this.column(i);
30884			var className = column.header().className;
30885			var priority = dt.settings()[0].aoColumns[i].responsivePriority;
30886
30887			if ( priority === undefined ) {
30888				var dataPriority = $(column.header()).data('priority');
30889
30890				priority = dataPriority !== undefined ?
30891					dataPriority * 1 :
30892					10000;
30893			}
30894
30895			return {
30896				className: className,
30897				includeIn: [],
30898				auto:      false,
30899				control:   false,
30900				never:     className.match(/\bnever\b/) ? true : false,
30901				priority:  priority
30902			};
30903		} );
30904
30905		// Simply add a breakpoint to `includeIn` array, ensuring that there are
30906		// no duplicates
30907		var add = function ( colIdx, name ) {
30908			var includeIn = columns[ colIdx ].includeIn;
30909
30910			if ( $.inArray( name, includeIn ) === -1 ) {
30911				includeIn.push( name );
30912			}
30913		};
30914
30915		var column = function ( colIdx, name, operator, matched ) {
30916			var size, i, ien;
30917
30918			if ( ! operator ) {
30919				columns[ colIdx ].includeIn.push( name );
30920			}
30921			else if ( operator === 'max-' ) {
30922				// Add this breakpoint and all smaller
30923				size = that._find( name ).width;
30924
30925				for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
30926					if ( breakpoints[i].width <= size ) {
30927						add( colIdx, breakpoints[i].name );
30928					}
30929				}
30930			}
30931			else if ( operator === 'min-' ) {
30932				// Add this breakpoint and all larger
30933				size = that._find( name ).width;
30934
30935				for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
30936					if ( breakpoints[i].width >= size ) {
30937						add( colIdx, breakpoints[i].name );
30938					}
30939				}
30940			}
30941			else if ( operator === 'not-' ) {
30942				// Add all but this breakpoint
30943				for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
30944					if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
30945						add( colIdx, breakpoints[i].name );
30946					}
30947				}
30948			}
30949		};
30950
30951		// Loop over each column and determine if it has a responsive control
30952		// class
30953		columns.each( function ( col, i ) {
30954			var classNames = col.className.split(' ');
30955			var hasClass = false;
30956
30957			// Split the class name up so multiple rules can be applied if needed
30958			for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
30959				var className = $.trim( classNames[k] );
30960
30961				if ( className === 'all' ) {
30962					// Include in all
30963					hasClass = true;
30964					col.includeIn = $.map( breakpoints, function (a) {
30965						return a.name;
30966					} );
30967					return;
30968				}
30969				else if ( className === 'none' || col.never ) {
30970					// Include in none (default) and no auto
30971					hasClass = true;
30972					return;
30973				}
30974				else if ( className === 'control' ) {
30975					// Special column that is only visible, when one of the other
30976					// columns is hidden. This is used for the details control
30977					hasClass = true;
30978					col.control = true;
30979					return;
30980				}
30981
30982				$.each( breakpoints, function ( j, breakpoint ) {
30983					// Does this column have a class that matches this breakpoint?
30984					var brokenPoint = breakpoint.name.split('-');
30985					var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
30986					var match = className.match( re );
30987
30988					if ( match ) {
30989						hasClass = true;
30990
30991						if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
30992							// Class name matches breakpoint name fully
30993							column( i, breakpoint.name, match[1], match[2]+match[3] );
30994						}
30995						else if ( match[2] === brokenPoint[0] && ! match[3] ) {
30996							// Class name matched primary breakpoint name with no qualifier
30997							column( i, breakpoint.name, match[1], match[2] );
30998						}
30999					}
31000				} );
31001			}
31002
31003			// If there was no control class, then automatic sizing is used
31004			if ( ! hasClass ) {
31005				col.auto = true;
31006			}
31007		} );
31008
31009		this.s.columns = columns;
31010	},
31011
31012
31013	/**
31014	 * Show the details for the child row
31015	 *
31016	 * @param  {DataTables.Api} row    API instance for the row
31017	 * @param  {boolean}        update Update flag
31018	 * @private
31019	 */
31020	_detailsDisplay: function ( row, update )
31021	{
31022		var that = this;
31023		var dt = this.s.dt;
31024		var details = this.c.details;
31025
31026		if ( details && details.type !== false ) {
31027			var res = details.display( row, update, function () {
31028				return details.renderer(
31029					dt, row[0], that._detailsObj(row[0])
31030				);
31031			} );
31032
31033			if ( res === true || res === false ) {
31034				$(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
31035			}
31036		}
31037	},
31038
31039
31040	/**
31041	 * Initialisation for the details handler
31042	 *
31043	 * @private
31044	 */
31045	_detailsInit: function ()
31046	{
31047		var that    = this;
31048		var dt      = this.s.dt;
31049		var details = this.c.details;
31050
31051		// The inline type always uses the first child as the target
31052		if ( details.type === 'inline' ) {
31053			details.target = 'td:first-child, th:first-child';
31054		}
31055
31056		// Keyboard accessibility
31057		dt.on( 'draw.dtr', function () {
31058			that._tabIndexes();
31059		} );
31060		that._tabIndexes(); // Initial draw has already happened
31061
31062		$( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
31063			if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
31064				$(this).click();
31065			}
31066		} );
31067
31068		// type.target can be a string jQuery selector or a column index
31069		var target   = details.target;
31070		var selector = typeof target === 'string' ? target : 'td, th';
31071
31072		// Click handler to show / hide the details rows when they are available
31073		$( dt.table().body() )
31074			.on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
31075				// If the table is not collapsed (i.e. there is no hidden columns)
31076				// then take no action
31077				if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
31078					return;
31079				}
31080
31081				// Check that the row is actually a DataTable's controlled node
31082				if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {
31083					return;
31084				}
31085
31086				// For column index, we determine if we should act or not in the
31087				// handler - otherwise it is already okay
31088				if ( typeof target === 'number' ) {
31089					var targetIdx = target < 0 ?
31090						dt.columns().eq(0).length + target :
31091						target;
31092
31093					if ( dt.cell( this ).index().column !== targetIdx ) {
31094						return;
31095					}
31096				}
31097
31098				// $().closest() includes itself in its check
31099				var row = dt.row( $(this).closest('tr') );
31100
31101				// Check event type to do an action
31102				if ( e.type === 'click' ) {
31103					// The renderer is given as a function so the caller can execute it
31104					// only when they need (i.e. if hiding there is no point is running
31105					// the renderer)
31106					that._detailsDisplay( row, false );
31107				}
31108				else if ( e.type === 'mousedown' ) {
31109					// For mouse users, prevent the focus ring from showing
31110					$(this).css('outline', 'none');
31111				}
31112				else if ( e.type === 'mouseup' ) {
31113					// And then re-allow at the end of the click
31114					$(this).blur().css('outline', '');
31115				}
31116			} );
31117	},
31118
31119
31120	/**
31121	 * Get the details to pass to a renderer for a row
31122	 * @param  {int} rowIdx Row index
31123	 * @private
31124	 */
31125	_detailsObj: function ( rowIdx )
31126	{
31127		var that = this;
31128		var dt = this.s.dt;
31129
31130		return $.map( this.s.columns, function( col, i ) {
31131			// Never and control columns should not be passed to the renderer
31132			if ( col.never || col.control ) {
31133				return;
31134			}
31135
31136			return {
31137				title:       dt.settings()[0].aoColumns[ i ].sTitle,
31138				data:        dt.cell( rowIdx, i ).render( that.c.orthogonal ),
31139				hidden:      dt.column( i ).visible() && !that.s.current[ i ],
31140				columnIndex: i,
31141				rowIndex:    rowIdx
31142			};
31143		} );
31144	},
31145
31146
31147	/**
31148	 * Find a breakpoint object from a name
31149	 *
31150	 * @param  {string} name Breakpoint name to find
31151	 * @return {object}      Breakpoint description object
31152	 * @private
31153	 */
31154	_find: function ( name )
31155	{
31156		var breakpoints = this.c.breakpoints;
31157
31158		for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
31159			if ( breakpoints[i].name === name ) {
31160				return breakpoints[i];
31161			}
31162		}
31163	},
31164
31165
31166	/**
31167	 * Re-create the contents of the child rows as the display has changed in
31168	 * some way.
31169	 *
31170	 * @private
31171	 */
31172	_redrawChildren: function ()
31173	{
31174		var that = this;
31175		var dt = this.s.dt;
31176
31177		dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
31178			var row = dt.row( idx );
31179
31180			that._detailsDisplay( dt.row( idx ), true );
31181		} );
31182	},
31183
31184
31185	/**
31186	 * Alter the table display for a resized viewport. This involves first
31187	 * determining what breakpoint the window currently is in, getting the
31188	 * column visibilities to apply and then setting them.
31189	 *
31190	 * @private
31191	 */
31192	_resize: function ()
31193	{
31194		var that = this;
31195		var dt = this.s.dt;
31196		var width = $(window).width();
31197		var breakpoints = this.c.breakpoints;
31198		var breakpoint = breakpoints[0].name;
31199		var columns = this.s.columns;
31200		var i, ien;
31201		var oldVis = this.s.current.slice();
31202
31203		// Determine what breakpoint we are currently at
31204		for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
31205			if ( width <= breakpoints[i].width ) {
31206				breakpoint = breakpoints[i].name;
31207				break;
31208			}
31209		}
31210		
31211		// Show the columns for that break point
31212		var columnsVis = this._columnsVisiblity( breakpoint );
31213		this.s.current = columnsVis;
31214
31215		// Set the class before the column visibility is changed so event
31216		// listeners know what the state is. Need to determine if there are
31217		// any columns that are not visible but can be shown
31218		var collapsedClass = false;
31219		for ( i=0, ien=columns.length ; i<ien ; i++ ) {
31220			if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control && ! dt.column(i).visible() === false ) {
31221				collapsedClass = true;
31222				break;
31223			}
31224		}
31225
31226		$( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
31227
31228		var changed = false;
31229		var visible = 0;
31230
31231		dt.columns().eq(0).each( function ( colIdx, i ) {
31232			if ( columnsVis[i] === true ) {
31233				visible++;
31234			}
31235
31236			if ( columnsVis[i] !== oldVis[i] ) {
31237				changed = true;
31238				that._setColumnVis( colIdx, columnsVis[i] );
31239			}
31240		} );
31241
31242		if ( changed ) {
31243			this._redrawChildren();
31244
31245			// Inform listeners of the change
31246			$(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
31247
31248			// If no records, update the "No records" display element
31249			if ( dt.page.info().recordsDisplay === 0 ) {
31250				$('td', dt.table().body()).eq(0).attr('colspan', visible);
31251			}
31252		}
31253	},
31254
31255
31256	/**
31257	 * Determine the width of each column in the table so the auto column hiding
31258	 * has that information to work with. This method is never going to be 100%
31259	 * perfect since column widths can change slightly per page, but without
31260	 * seriously compromising performance this is quite effective.
31261	 *
31262	 * @private
31263	 */
31264	_resizeAuto: function ()
31265	{
31266		var dt = this.s.dt;
31267		var columns = this.s.columns;
31268
31269		// Are we allowed to do auto sizing?
31270		if ( ! this.c.auto ) {
31271			return;
31272		}
31273
31274		// Are there any columns that actually need auto-sizing, or do they all
31275		// have classes defined
31276		if ( $.inArray( true, $.map( columns, function (c) { return c.auto; }
31276 ) ) === -1 ) {
31277			return;
31278		}
31279
31280		// Need to restore all children. They will be reinstated by a re-render
31281		if ( ! $.isEmptyObject( _childNodeStore ) ) {
31282			$.each( _childNodeStore, function ( key ) {
31283				var idx = key.split('-');
31284
31285				_childNodesRestore( dt, idx[0]*1, idx[1]*1 );
31286			} );
31287		}
31288
31289		// Clone the table with the current data in it
31290		var tableWidth   = dt.table().node().offsetWidth;
31291		var columnWidths = dt.columns;
31292		var clonedTable  = dt.table().node().cloneNode( false );
31293		var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
31294		var clonedBody   = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
31295
31296		// Header
31297		var headerCells = dt.columns()
31298			.header()
31299			.filter( function (idx) {
31300				return dt.column(idx).visible();
31301			} )
31302			.to$()
31303			.clone( false )
31304			.css( 'display', 'table-cell' )
31305			.css( 'min-width', 0 );
31306
31307		// Body rows - we don't need to take account of DataTables' column
31308		// visibility since we implement our own here (hence the `display` set)
31309		$(clonedBody)
31310			.append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
31311			.find( 'th, td' ).css( 'display', '' );
31312
31313		// Footer
31314		var footer = dt.table().footer();
31315		if ( footer ) {
31316			var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
31317			var footerCells = dt.columns()
31318				.footer()
31319				.filter( function (idx) {
31320					return dt.column(idx).visible();
31321				} )
31322				.to$()
31323				.clone( false )
31324				.css( 'display', 'table-cell' );
31325
31326			$('<tr/>')
31327				.append( footerCells )
31328				.appendTo( clonedFooter );
31329		}
31330
31331		$('<tr/>')
31332			.append( headerCells )
31333			.appendTo( clonedHeader );
31334
31335		// In the inline case extra padding is applied to the first column to
31336		// give space for the show / hide icon. We need to use this in the
31337		// calculation
31338		if ( this.c.details.type === 'inline' ) {
31339			$(clonedTable).addClass( 'dtr-inline collapsed' );
31340		}
31341		
31342		// It is unsafe to insert elements with the same name into the DOM
31343		// multiple times. For example, cloning and inserting a checked radio
31344		// clears the chcecked state of the original radio.
31345		$( clonedTable ).find( '[name]' ).removeAttr( 'name' );
31346
31347		// A position absolute table would take the table out of the flow of
31348		// our container element, bypassing the height and width (Scroller)
31349		$( clonedTable ).css( 'position', 'relative' )
31350		
31351		var inserted = $('<div/>')
31352			.css( {
31353				width: 1,
31354				height: 1,
31355				overflow: 'hidden',
31356				clear: 'both'
31357			} )
31358			.append( clonedTable );
31359
31360		inserted.insertBefore( dt.table().node() );
31361
31362		// The cloned header now contains the smallest that each column can be
31363		headerCells.each( function (i) {
31364			var idx = dt.column.index( 'fromVisible', i );
31365			columns[ idx ].minWidth =  this.offsetWidth || 0;
31366		} );
31367
31368		inserted.remove();
31369	},
31370
31371	/**
31372	 * Set a column's visibility.
31373	 *
31374	 * We don't use DataTables' column visibility controls in order to ensure
31375	 * that column visibility can Responsive can no-exist. Since only IE8+ is
31376	 * supported (and all evergreen browsers of course) the control of the
31377	 * display attribute works well.
31378	 *
31379	 * @param {integer} col      Column index
31380	 * @param {boolean} showHide Show or hide (true or false)
31381	 * @private
31382	 */
31383	_setColumnVis: function ( col, showHide )
31384	{
31385		var dt = this.s.dt;
31386		var display = showHide ? '' : 'none'; // empty string will remove the attr
31387
31388		$( dt.column( col ).header() ).css( 'display', display );
31389		$( dt.column( col ).footer() ).css( 'display', display );
31390		dt.column( col ).nodes().to$().css( 'display', display );
31391
31392		// If the are child nodes stored, we might need to reinsert them
31393		if ( ! $.isEmptyObject( _childNodeStore ) ) {
31394			dt.cells( null, col ).indexes().each( function (idx) {
31395				_childNodesRestore( dt, idx.row, idx.column );
31396			} );
31397		}
31398	},
31399
31400
31401	/**
31402	 * Update the cell tab indexes for keyboard accessibility. This is called on
31403	 * every table draw - that is potentially inefficient, but also the least
31404	 * complex option given that column visibility can change on the fly. Its a
31405	 * shame user-focus was removed from CSS 3 UI, as it would have solved this
31406	 * issue with a single CSS statement.
31407	 *
31408	 * @private
31409	 */
31410	_tabIndexes: function ()
31411	{
31412		var dt = this.s.dt;
31413		var cells = dt.cells( { page: 'current' } ).nodes().to$();
31414		var ctx = dt.settings()[0];
31415		var target = this.c.details.target;
31416
31417		cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
31418
31419		if ( typeof target === 'number' ) {
31420			dt.cells( null, target, { page: 'current' } ).nodes().to$()
31421				.attr( 'tabIndex', ctx.iTabIndex )
31422				.data( 'dtr-keyboard', 1 );
31423		}
31424		else {
31425			// This is a bit of a hack - we need to limit the selected nodes to just
31426			// those of this table
31427			if ( target === 'td:first-child, th:first-child' ) {
31428				target = '>td:first-child, >th:first-child';
31429			}
31430
31431			$( target, dt.rows( { page: 'current' } ).nodes() )
31432				.attr( 'tabIndex', ctx.iTabIndex )
31433				.data( 'dtr-keyboard', 1 );
31434		}
31435	}
31436} );
31437
31438
31439/**
31440 * List of default breakpoints. Each item in the array is an object with two
31441 * properties:
31442 *
31443 * * `name` - the breakpoint name.
31444 * * `width` - the breakpoint width
31445 *
31446 * @name Responsive.breakpoints
31447 * @static
31448 */
31449Responsive.breakpoints = [
31450	{ name: 'desktop',  width: Infinity },
31451	{ name: 'tablet-l', width: 1024 },
31452	{ name: 'tablet-p', width: 768 },
31453	{ name: 'mobile-l', width: 480 },
31454	{ name: 'mobile-p', width: 320 }
31455];
31456
31457
31458/**
31459 * Display methods - functions which define how the hidden data should be shown
31460 * in the table.
31461 *
31462 * @namespace
31463 * @name Responsive.defaults
31464 * @static
31465 */
31466Responsive.display = {
31467	childRow: function ( row, update, render ) {
31468		if ( update ) {
31469			if ( $(row.node()).hasClass('parent') ) {
31470				row.child( render(), 'child' ).show();
31471
31472				return true;
31473			}
31474		}
31475		else {
31476			if ( ! row.child.isShown()  ) {
31477				row.child( render(), 'child' ).show();
31478				$( row.node() ).addClass( 'parent' );
31479
31480				return true;
31481			}
31482			else {
31483				row.child( false );
31484				$( row.node() ).removeClass( 'parent' );
31485
31486				return false;
31487			}
31488		}
31489	},
31490
31491	childRowImmediate: function ( row, update, render ) {
31492		if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
31493			// User interaction and the row is show, or nothing to show
31494			row.child( false );
31495			$( row.node() ).removeClass( 'parent' );
31496
31497			return false;
31498		}
31499		else {
31500			// Display
31501			row.child( render(), 'child' ).show();
31502			$( row.node() ).addClass( 'parent' );
31503
31504			return true;
31505		}
31506	},
31507
31508	// This is a wrapper so the modal options for Bootstrap and jQuery UI can
31509	// have options passed into them. This specific one doesn't need to be a
31510	// function but it is for consistency in the `modal` name
31511	modal: function ( options ) {
31512		return function ( row, update, render ) {
31513			if ( ! update ) {
31514				// Show a modal
31515				var close = function () {
31516					modal.remove(); // will tidy events for us
31517					$(document).off( 'keypress.dtr' );
31518				};
31519
31520				var modal = $('<div class="dtr-modal"/>')
31521					.append( $('<div class="dtr-modal-display"/>')
31522						.append( $('<div class="dtr-modal-content"/>')
31523							.append( render() )
31524						)
31525						.append( $('<div class="dtr-modal-close">&times;</div>' )
31526							.click( function () {
31527								close();
31528							} )
31529						)
31530					)
31531					.append( $('<div class="dtr-modal-background"/>')
31532						.click( function () {
31533							close();
31534						} )
31535					)
31536					.appendTo( 'body' );
31537
31538				$(document).on( 'keyup.dtr', function (e) {
31539					if ( e.keyCode === 27 ) {
31540						e.stopPropagation();
31541
31542						close();
31543					}
31544				} );
31545			}
31546			else {
31547				$('div.dtr-modal-content')
31548					.empty()
31549					.append( render() );
31550			}
31551
31552			if ( options && options.header ) {
31553				$('div.dtr-modal-content').prepend(
31554					'<h2>'+options.header( row )+'</h2>'
31555				);
31556			}
31557		};
31558	}
31559};
31560
31561
31562var _childNodeStore = {};
31563
31564function _childNodes( dt, row, col ) {
31565	var name = row+'-'+col;
31566
31567	if ( _childNodeStore[ name ] ) {
31568		return _childNodeStore[ name ];
31569	}
31570
31571	// https://jsperf.com/childnodes-array-slice-vs-loop
31572	var nodes = [];
31573	var children = dt.cell( row, col ).node().childNodes;
31574	for ( var i=0, ien=children.length ; i<ien ; i++ ) {
31575		nodes.push( children[i] );
31576	}
31577
31578	_childNodeStore[ name ] = nodes;
31579
31580	return nodes;
31581}
31582
31583function _childNodesRestore( dt, row, col ) {
31584	var name = row+'-'+col;
31585
31586	if ( ! _childNodeStore[ name ] ) {
31587		return;
31588	}
31589
31590	var node = dt.cell( row, col ).node();
31591	var store = _childNodeStore[ name ];
31592	var parent = store[0].parentNode;
31593	var parentChildren = parent.childNodes;
31594	var a = [];
31595
31596	for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {
31597		a.push( parentChildren[i] );
31598	}
31599
31600	for ( var j=0, jen=a.length ; j<jen ; j++ ) {
31601		node.appendChild( a[j] );
31602	}
31603
31604	_childNodeStore[ name ] = undefined;
31605}
31606
31607
31608/**
31609 * Display methods - functions which define how the hidden data should be shown
31610 * in the table.
31611 *
31612 * @namespace
31613 * @name Responsive.defaults
31614 * @static
31615 */
31616Responsive.renderer = {
31617	listHiddenNodes: function () {
31618		return function ( api, rowIdx, columns ) {
31619			var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>');
31620			var found = false;
31621
31622			var data = $.each( columns, function ( i, col ) {
31623				if ( col.hidden ) {
31624					$(
31625						'<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
31626							'<span class="dtr-title">'+
31627								col.title+
31628							'</span> '+
31629						'</li>'
31630					)
31631						.append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
31632						.appendTo( ul );
31633
31634					found = true;
31635				}
31636			} );
31637
31638			return found ?
31639				ul :
31640				false;
31641		};
31642	},
31643
31644	listHidden: function () {
31645		return function ( api, rowIdx, columns ) {
31646			var data = $.map( columns, function ( col ) {
31647				return col.hidden ?
31648					'<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
31649						'<span class="dtr-title">'+
31650							col.title+
31651						'</span> '+
31652						'<span class="dtr-data">'+
31653							col.data+
31654						'</span>'+
31655					'</li>' :
31656					'';
31657			} ).join('');
31658
31659			return data ?
31660				$('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) :
31661				false;
31662		}
31663	},
31664
31665	tableAll: function ( options ) {
31666		options = $.extend( {
31667			tableClass: ''
31668		}, options );
31669
31670		return function ( api, rowIdx, columns ) {
31671			var data = $.map( columns, function ( col ) {
31672				return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
31673						'<td>'+col.title+':'+'</td> '+
31674						'<td>'+col.data+'</td>'+
31675					'</tr>';
31676			} ).join('');
31677
31678			return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data );
31679		}
31680	}
31681};
31682
31683/**
31684 * Responsive default settings for initialisation
31685 *
31686 * @namespace
31687 * @name Responsive.defaults
31688 * @static
31689 */
31690Responsive.defaults = {
31691	/**
31692	 * List of breakpoints for the instance. Note that this means that each
31693	 * instance can have its own breakpoints. Additionally, the breakpoints
31694	 * cannot be changed once an instance has been creased.
31695	 *
31696	 * @type {Array}
31697	 * @default Takes the value of `Responsive.breakpoints`
31698	 */
31699	breakpoints: Responsive.breakpoints,
31700
31701	/**
31702	 * Enable / disable auto hiding calculations. It can help to increase
31703	 * performance slightly if you disable this option, but all columns would
31704	 * need to have breakpoint classes assigned to them
31705	 *
31706	 * @type {Boolean}
31707	 * @default  `true`
31708	 */
31709	auto: true,
31710
31711	/**
31712	 * Details control. If given as a string value, the `type` property of the
31713	 * default object is set to that value, and the defaults used for the rest
31714	 * of the object - this is for ease of implementation.
31715	 *
31716	 * The object consists of the following properties:
31717	 *
31718	 * * `display` - A function that is used to show and hide the hidden details
31719	 * * `renderer` - function that is called for display of the child row data.
31720	 *   The default function will show the data from the hidden columns
31721	 * * `target` - Used as the selector for what objects to attach the child
31722	 *   open / close to
31723	 * * `type` - `false` to disable the details display, `inline` or `column`
31724	 *   for the two control types
31725	 *
31726	 * @type {Object|string}
31727	 */
31728	details: {
31729		display: Responsive.display.childRow,
31730
31731		renderer: Responsive.renderer.listHidden(),
31732
31733		target: 0,
31734
31735		type: 'inline'
31736	},
31737
31738	/**
31739	 * Orthogonal data request option. This is used to define the data type
31740	 * requested when Responsive gets the data to show in the child row.
31741	 *
31742	 * @type {String}
31743	 */
31744	orthogonal: 'display'
31745};
31746
31747
31748/*
31749 * API
31750 */
31751var Api = $.fn.dataTable.Api;
31752
31753// Doesn't do anything - work around for a bug in DT... Not documented
31754Api.register( 'responsive()', function () {
31755	return this;
31756} );
31757
31758Api.register( 'responsive.index()', function ( li ) {
31759	li = $(li);
31760
31761	return {
31762		column: li.data('dtr-index'),
31763		row:    li.parent().data('dtr-index')
31764	};
31765} );
31766
31767Api.register( 'responsive.rebuild()', function () {
31768	return this.iterator( 'table', function ( ctx ) {
31769		if ( ctx._responsive ) {
31770			ctx._responsive._classLogic();
31771		}
31772	} );
31773} );
31774
31775Api.register( 'responsive.recalc()', function () {
31776	return this.iterator( 'table', function ( ctx ) {
31777		if ( ctx._responsive ) {
31778			ctx._responsive._resizeAuto();
31779			ctx._responsive._resize();
31780		}
31781	} );
31782} );
31783
31784Api.register( 'responsive.hasHidden()', function () {
31785	var ctx = this.context[0];
31786
31787	return ctx._responsive ?
31788		$.inArray( false, ctx._responsive.s.current ) !== -1 :
31789		false;
31790} );
31791
31792Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {
31793	return this.iterator( 'column', function ( settings, column ) {
31794		return settings._responsive ?
31795			settings._responsive.s.current[ column ] :
31796			false;
31797	}, 1 );
31798} );
31799
31800
31801/**
31802 * Version information
31803 *
31804 * @name Responsive.version
31805 * @static
31806 */
31807Responsive.version = '2.2.2';
31808
31809
31810$.fn.dataTable.Responsive = Responsive;
31811$.fn.DataTable.Responsive = Responsive;
31812
31813// Attach a listener to the document which listens for DataTables initialisation
31814// events so we can automatically initialise
31815$(document).on( 'preInit.dt.dtr', function (e, settings, json) {
31816	if ( e.namespace !== 'dt' ) {
31817		return;
31818	}
31819
31820	if ( $(settings.nTable).hasClass( 'responsive' ) ||
31821		 $(settings.nTable).hasClass( 'dt-responsive' ) ||
31822		 settings.oInit.responsive ||
31823		 DataTable.defaults.responsive
31824	) {
31825		var init = settings.oInit.responsive;
31826
31827		if ( init !== false ) {
31828			new Responsive( settings, $.isPlainObject( init ) ? init : {}  );
31829		}
31830	}
31831} );
31832
31833
31834return Responsive;
31835}));
31836
31837
31838/*! RowGroup 1.1.0
31839 * ©2017-2018 SpryMedia Ltd - datatables.net/license
31840 */
31841
31842/**
31843 * @summary     RowGroup
31844 * @description RowGrouping for DataTables
31845 * @version     1.1.0
31846 * @file        dataTables.rowGroup.js
31847 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
31848 * @contact     datatables.net
31849 * @copyright   Copyright 2017-2018 SpryMedia Ltd.
31850 *
31851 * This source file is free software, available under the following license:
31852 *   MIT license - http://datatables.net/license/mit
31853 *
31854 * This source file is distributed in the hope that it will be useful, but
31855 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31856 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
31857 *
31858 * For details please refer to: http://www.datatables.net
31859 */
31860
31861(function( factory ){
31862	if ( typeof define === 'function' && define.amd ) {
31863		// AMD
31864		define( ['jquery', 'datatables.net'], function ( $ ) {
31865			return factory( $, window, document );
31866		} );
31867	}
31868	else if ( typeof exports === 'object' ) {
31869		// CommonJS
31870		module.exports = function (root, $) {
31871			if ( ! root ) {
31872				root = window;
31873			}
31874
31875			if ( ! $ || ! $.fn.dataTable ) {
31876				$ = require('datatables.net')(root, $).$;
31877			}
31878
31879			return factory( $, root, root.document );
31880		};
31881	}
31882	else {
31883		// Browser
31884		factory( jQuery, window, document );
31885	}
31886}(function( $, window, document, undefined ) {
31887'use strict';
31888var DataTable = $.fn.dataTable;
31889
31890
31891var RowGroup = function ( dt, opts ) {
31892	// Sanity check that we are using DataTables 1.10 or newer
31893	if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
31894		throw 'RowGroup requires DataTables 1.10.8 or newer';
31895	}
31896
31897	// User and defaults configuration object
31898	this.c = $.extend( true, {},
31899		DataTable.defaults.rowGroup,
31900		RowGroup.defaults,
31901		opts
31902	);
31903
31904	// Internal settings
31905	this.s = {
31906		dt: new DataTable.Api( dt )
31907	};
31908
31909	// DOM items
31910	this.dom = {
31911
31912	};
31913
31914	// Check if row grouping has already been initialised on this table
31915	var settings = this.s.dt.settings()[0];
31916	var existing = settings.rowGroup;
31917	if ( existing ) {
31918		return existing;
31919	}
31920
31921	settings.rowGroup = this;
31922	this._constructor();
31923};
31924
31925
31926$.extend( RowGroup.prototype, {
31927	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
31928	 * API methods for DataTables API interface
31929	 */
31930
31931	/**
31932	 * Get/set the grouping data source - need to call draw after this is
31933	 * executed as a setter
31934	 * @returns string~RowGroup
31935	 */
31936	dataSrc: function ( val )
31937	{
31938		if ( val === undefined ) {
31939			return this.c.dataSrc;
31940		}
31941
31942		var dt = this.s.dt;
31943
31944		this.c.dataSrc = val;
31945
31946		$(dt.table().node()).triggerHandler( 'rowgroup-datasrc.dt', [ dt, val ] );
31947
31948		return this;
31949	},
31950
31951	/**
31952	 * Disable - need to call draw after this is executed
31953	 * @returns RowGroup
31954	 */
31955	disable: function ()
31956	{
31957		this.c.enable = false;
31958		return this;
31959	},
31960
31961	/**
31962	 * Enable - need to call draw after this is executed
31963	 * @returns RowGroup
31964	 */
31965	enable: function ( flag )
31966	{
31967		if ( flag === false ) {
31968			return this.disable();
31969		}
31970
31971		this.c.enable = true;
31972		return this;
31973	},
31974
31975
31976	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
31977	 * Constructor
31978	 */
31979	_constructor: function ()
31980	{
31981		var that = this;
31982		var dt = this.s.dt;
31983
31984		dt.on( 'draw.dtrg', function () {
31985			if ( that.c.enable ) {
31986				that._draw();
31987			}
31988		} );
31989
31990		dt.on( 'column-visibility.dt.dtrg responsive-resize.dt.dtrg', function () {
31991			that._adjustColspan();
31992		} );
31993
31994		dt.on( 'destroy', function () {
31995			dt.off( '.dtrg' );
31996		} );
31997
31998		dt.on('responsive-resize.dt', function () {
31999			that._adjustColspan();
32000		})
32001	},
32002
32003
32004	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
32005	 * Private methods
32006	 */
32007
32008	/**
32009	 * Adjust column span when column visibility changes
32010	 * @private
32011	 */
32012	_adjustColspan: function ()
32013	{
32014		$( 'tr.'+this.c.className, this.s.dt.table().body() ).find('td')
32015			.attr( 'colspan', this._colspan() );
32016	},
32017
32018	/**
32019	 * Get the number of columns that a grouping row should span
32020	 * @private
32021	 */
32022	_colspan: function ()
32023	{
32024		return this.s.dt.columns().visible().reduce( function (a, b) {
32025			return a + b;
32026		}, 0 );
32027	},
32028
32029
32030	/**
32031	 * Update function that is called whenever we need to draw the grouping rows.
32032	 * This is basically a bootstrap for the self iterative _group and _groupDisplay
32033	 * methods
32034	 * @private
32035	 */
32036	_draw: function ()
32037	{
32038		var dt = this.s.dt;
32039		var groupedRows = this._group( 0, dt.rows( { page: 'current' } ).indexes() );
32040
32041		this._groupDisplay( 0, groupedRows );
32042	},
32043
32044	/**
32045	 * Get the grouping information from a data set (index) of rows
32046	 * @param {number} level Nesting level
32047	 * @param {DataTables.Api} rows API of the rows to consider for this group
32048	 * @returns {object[]} Nested grouping information - it is structured like this:
32049	 *	{
32050	 *		dataPoint: 'Edinburgh',
32051	 *		rows: [ 1,2,3,4,5,6,7 ],
32052	 *		children: [ {
32053	 *			dataPoint: 'developer'
32054	 *			rows: [ 1, 2, 3 ]
32055	 *		},
32056	 *		{
32057	 *			dataPoint: 'support',
32058	 *			rows: [ 4, 5, 6, 7 ]
32059	 *		} ]
32060	 *	}
32061	 * @private
32062	 */
32063	_group: function ( level, rows ) {
32064		var fns = $.isArray( this.c.dataSrc ) ? this.c.dataSrc : [ this.c.dataSrc ];
32065		var fn = DataTable.ext.oApi._fnGetObjectDataFn( fns[ level ] );
32066		var dt = this.s.dt;
32067		var group, last;
32068		var data = [];
32069
32070		for ( var i=0, ien=rows.length ; i<ien ; i++ ) {
32071			var rowIndex = rows[i];
32072			var rowData = dt.row( rowIndex ).data();
32073			var group = fn( rowData );
32074
32075			if ( group === null || group === undefined ) {
32076				group = that.c.emptyDataGroup;
32077			}
32078			
32079			if ( last === undefined || group !== last ) {
32080				data.push( {
32081					dataPoint: group,
32082					rows: []
32083				} );
32084
32085				last = group;
32086			}
32087
32088			data[ data.length-1 ].rows.push( rowIndex );
32089		}
32090
32091		if ( fns[ level+1 ] !== undefined ) {
32092			for ( var i=0, ien=data.length ; i<ien ; i++ ) {
32093				data[i].children = this._group( level+1, data[i].rows );
32094			}
32095		}
32096
32097		return data;
32098	},
32099
32100	/**
32101	 * Row group display - insert the rows into the document
32102	 * @param {number} level Nesting level
32103	 * @param {object[]} groups Takes the nested array from `_group`
32104	 * @private
32105	 */
32106	_groupDisplay: function ( level, groups )
32107	{
32108		var dt = this.s.dt;
32109		var display;
32110	
32111		for ( var i=0, ien=groups.length ; i<ien ; i++ ) {
32112			var group = groups[i];
32113			var groupName = group.dataPoint;
32114			var row;
32115			var rows = group.rows;
32116
32117			if ( this.c.startRender ) {
32118				display = this.c.startRender.call( this, dt.rows(rows), groupName, level );
32119				row = this._rowWrap( display, this.c.startClassName, level );
32120
32121				if ( row ) {
32122					row.insertBefore( dt.row( rows[0] ).node() );
32123				}
32124			}
32125
32126			if ( this.c.endRender ) {
32127				display = this.c.endRender.call( this, dt.rows(rows), groupName, level );
32128				row = this._rowWrap( display, this.c.endClassName, level );
32129
32130				if ( row ) {
32131					row.insertAfter( dt.row( rows[ rows.length-1 ] ).node() );
32132				}
32133			}
32134
32135			if ( group.children ) {
32136				this._groupDisplay( level+1, group.children );
32137			}
32138		}
32139	},
32140
32141	/**
32142	 * Take a rendered value from an end user and make it suitable for display
32143	 * as a row, by wrapping it in a row, or detecting that it is a row.
32144	 * @param {node|jQuery|string} display Display value
32145	 * @param {string} className Class to add to the row
32146	 * @param {array} group
32147	 * @param {number} group level
32148	 * @private
32149	 */
32150	_rowWrap: function ( display, className, level )
32151	{
32152		var row;
32153		
32154		if ( display === null || display === '' ) {
32155			display = this.c.emptyDataGroup;
32156		}
32157
32158		if ( display === undefined ) {
32159			return null;
32160		}
32161		
32162		if ( typeof display === 'object' && display.nodeName && display.nodeName.toLowerCase() === 'tr') {
32163			row = $(display);
32164		}
32165		else if (display instanceof $ && display.length && display[0].nodeName.toLowerCase() === 'tr') {
32166			row = display;
32167		}
32168		else {
32169			row = $('<tr/>')
32170				.append(
32171					$('<td/>')
32172						.attr( 'colspan', this._colspan() )
32173						.append( display  )
32174				);
32175		}
32176
32177		return row
32178			.addClass( this.c.className )
32179			.addClass( className )
32180			.addClass( 'dtrg-level-'+level );
32181	}
32182} );
32183
32184
32185/**
32186 * RowGroup default settings for initialisation
32187 *
32188 * @namespace
32189 * @name RowGroup.defaults
32190 * @static
32191 */
32192RowGroup.defaults = {
32193	/**
32194	 * Class to apply to grouping rows - applied to both the start and
32195	 * end grouping rows.
32196	 * @type string
32197	 */
32198	className: 'dtrg-group',
32199
32200	/**
32201	 * Data property from which to read the grouping information
32202	 * @type string|integer|array
32203	 */
32204	dataSrc: 0,
32205
32206	/**
32207	 * Text to show if no data is found for a group
32208	 * @type string
32209	 */
32210	emptyDataGroup: 'No group',
32211
32212	/**
32213	 * Initial enablement state
32214	 * @boolean
32215	 */
32216	enable: true,
32217
32218	/**
32219	 * Class name to give to the end grouping row
32220	 * @type string
32221	 */
32222	endClassName: 'dtrg-end',
32223
32224	/**
32225	 * End grouping label function
32226	 * @function
32227	 */
32228	endRender: null,
32229
32230	/**
32231	 * Class name to give to the start grouping row
32232	 * @type string
32233	 */
32234	startClassName: 'dtrg-start',
32235
32236	/**
32237	 * Start grouping label function
32238	 * @function
32239	 */
32240	startRender: function ( rows, group ) {
32241		return group;
32242	}
32243};
32244
32245
32246RowGroup.version = "1.1.0";
32247
32248
32249$.fn.dataTable.RowGroup = RowGroup;
32250$.fn.DataTable.RowGroup = RowGroup;
32251
32252
32253DataTable.Api.register( 'rowGroup()', function () {
32254	return this;
32255} );
32256
32257DataTable.Api.register( 'rowGroup().disable()', function () {
32258	return this.iterator( 'table', function (ctx) {
32259		if ( ctx.rowGroup ) {
32260			ctx.rowGroup.enable( false );
32261		}
32262	} );
32263} );
32264
32265DataTable.Api.register( 'rowGroup().enable()', function ( opts ) {
32266	return this.iterator( 'table', function (ctx) {
32267		if ( ctx.rowGroup ) {
32268			ctx.rowGroup.enable( opts === undefined ? true : opts );
32269		}
32270	} );
32271} );
32272
32273DataTable.Api.register( 'rowGroup().dataSrc()', function ( val ) {
32274	if ( val === undefined ) {
32275		return this.context[0].rowGroup.dataSrc();
32276	}
32277
32278	return this.iterator( 'table', function (ctx) {
32279		if ( ctx.rowGroup ) {
32280			ctx.rowGroup.dataSrc( val );
32281		}
32282	} );
32283} );
32284
32285
32286// Attach a listener to the document which listens for DataTables initialisation
32287// events so we can automatically initialise
32288$(document).on( 'preInit.dt.dtrg', function (e, settings, json) {
32289	if ( e.namespace !== 'dt' ) {
32290		return;
32291	}
32292
32293	var init = settings.oInit.rowGroup;
32294	var defaults = DataTable.defaults.rowGroup;
32295
32296	if ( init || defaults ) {
32297		var opts = $.extend( {}, defaults, init );
32298
32299		if ( init !== false ) {
32300			new RowGroup( settings, opts  );
32301		}
32302	}
32303} );
32304
32305
32306return RowGroup;
32307
32308}));
32309
32310
32311/*! Scroller 1.5.0
32312 * ©2011-2018 SpryMedia Ltd - datatables.net/license
32313 */
32314
32315/**
32316 * @summary     Scroller
32317 * @description Virtual rendering for DataTables
32318 * @version     1.5.0
32319 * @file        dataTables.scroller.js
32320 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
32321 * @contact     www.sprymedia.co.uk/contact
32322 * @copyright   Copyright 2011-2018 SpryMedia Ltd.
32323 *
32324 * This source file is free software, available under the following license:
32325 *   MIT license - http://datatables.net/license/mit
32326 *
32327 * This source file is distributed in the hope that it will be useful, but
32328 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
32329 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
32330 *
32331 * For details please refer to: http://www.datatables.net
32332 */
32333
32334(function( factory ){
32335	if ( typeof define === 'function' && define.amd ) {
32336		// AMD
32337		define( ['jquery', 'datatables.net'], function ( $ ) {
32338			return factory( $, window, document );
32339		} );
32340	}
32341	else if ( typeof exports === 'object' ) {
32342		// CommonJS
32343		module.exports = function (root, $) {
32344			if ( ! root ) {
32345				root = window;
32346			}
32347
32348			if ( ! $ || ! $.fn.dataTable ) {
32349				$ = require('datatables.net')(root, $).$;
32350			}
32351
32352			return factory( $, root, root.document );
32353		};
32354	}
32355	else {
32356		// Browser
32357		factory( jQuery, window, document );
32358	}
32359}(function( $, window, document, undefined ) {
32360'use strict';
32361var DataTable = $.fn.dataTable;
32362
32363
32364/**
32365 * Scroller is a virtual rendering plug-in for DataTables which allows large
32366 * datasets to be drawn on screen every quickly. What the virtual rendering means
32367 * is that only the visible portion of the table (and a bit to either side to make
32368 * the scrolling smooth) is drawn, while the scrolling container gives the
32369 * visual impression that the whole table is visible. This is done by making use
32370 * of the pagination abilities of DataTables and moving the table around in the
32371 * scrolling container DataTables adds to the page. The scrolling container is
32372 * forced to the height it would be for the full table display using an extra
32373 * element.
32374 *
32375 * Note that rows in the table MUST all be the same height. Information in a cell
32376 * which expands on to multiple lines will cause some odd behaviour in the scrolling.
32377 *
32378 * Scroller is initialised by simply including the letter 'S' in the sDom for the
32379 * table you want to have this feature enabled on. Note that the 'S' must come
32380 * AFTER the 't' parameter in `dom`.
32381 *
32382 * Key features include:
32383 *   <ul class="limit_length">
32384 *     <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>
32385 *     <li>Full compatibility with deferred rendering in DataTables for maximum speed</li>
32386 *     <li>Display millions of rows</li>
32387 *     <li>Integration with state saving in DataTables (scrolling position is saved)</li>
32388 *     <li>Easy to use</li>
32389 *   </ul>
32390 *
32391 *  @class
32392 *  @constructor
32393 *  @global
32394 *  @param {object} dt DataTables settings object or API instance
32395 *  @param {object} [opts={}] Configuration object for FixedColumns. Options 
32396 *    are defined by {@link Scroller.defaults}
32397 *
32398 *  @requires jQuery 1.7+
32399 *  @requires DataTables 1.10.0+
32400 *
32401 *  @example
32402 *    $(document).ready(function() {
32403 *        $('#example').DataTable( {
32404 *            "scrollY": "200px",
32405 *            "ajax": "media/dataset/large.txt",
32406 *            "dom": "frtiS",
32407 *            "deferRender": true
32408 *        } );
32409 *    } );
32410 */
32411var Scroller = function ( dt, opts ) {
32412	/* Sanity check - you just know it will happen */
32413	if ( ! (this instanceof Scroller) ) {
32414		alert( "Scroller warning: Scroller must be initialised with the 'new' keyword." );
32415		return;
32416	}
32417
32418	if ( opts === undefined ) {
32419		opts = {};
32420	}
32421
32422	var dtApi = $.fn.dataTable.Api( dt );
32423
32424	/**
32425	 * Settings object which contains customisable information for the Scroller instance
32426	 * @namespace
32427	 * @private
32428	 * @extends Scroller.defaults
32429	 */
32430	this.s = {
32431		/**
32432		 * DataTables settings object
32433		 *  @type     object
32434		 *  @default  Passed in as first parameter to constructor
32435		 */
32436		"dt": dtApi.settings()[0],
32437
32438		/**
32439		 * DataTables API instance
32440		 *  @type     DataTable.Api
32441		 */
32442		"dtApi": dtApi,
32443
32444		/**
32445		 * Pixel location of the top of the drawn table in the viewport
32446		 *  @type     int
32447		 *  @default  0
32448		 */
32449		"tableTop": 0,
32450
32451		/**
32452		 * Pixel location of the bottom of the drawn table in the viewport
32453		 *  @type     int
32454		 *  @default  0
32455		 */
32456		"tableBottom": 0,
32457
32458		/**
32459		 * Pixel location of the boundary for when the next data set should be loaded and drawn
32460		 * when scrolling up the way.
32461		 *  @type     int
32462		 *  @default  0
32463		 *  @private
32464		 */
32465		"redrawTop": 0,
32466
32467		/**
32468		 * Pixel location of the boundary for when the next data set should be loaded and drawn
32469		 * when scrolling down the way. Note that this is actually calculated as the offset from
32470		 * the top.
32471		 *  @type     int
32472		 *  @default  0
32473		 *  @private
32474		 */
32475		"redrawBottom": 0,
32476
32477		/**
32478		 * Auto row height or not indicator
32479		 *  @type     bool
32480		 *  @default  0
32481		 */
32482		"autoHeight": true,
32483
32484		/**
32485		 * Number of rows calculated as visible in the visible viewport
32486		 *  @type     int
32487		 *  @default  0
32488		 */
32489		"viewportRows": 0,
32490
32491		/**
32492		 * setTimeout reference for state saving, used when state saving is enabled in the DataTable
32493		 * and when the user scrolls the viewport in order to stop the cookie set taking too much
32494		 * CPU!
32495		 *  @type     int
32496		 *  @default  0
32497		 */
32498		"stateTO": null,
32499
32500		/**
32501		 * setTimeout reference for the redraw, used when server-side processing is enabled in the
32502		 * DataTables in order to prevent DoSing the server
32503		 *  @type     int
32504		 *  @default  null
32505		 */
32506		"drawTO": null,
32507
32508		heights: {
32509			jump: null,
32510			page: null,
32511			virtual: null,
32512			scroll: null,
32513
32514			/**
32515			 * Height of rows in the table
32516			 *  @type     int
32517			 *  @default  0
32518			 */
32519			row: null,
32520
32521			/**
32522			 * Pixel height of the viewport
32523			 *  @type     int
32524			 *  @default  0
32525			 */
32526			viewport: null
32527		},
32528
32529		topRowFloat: 0,
32530		scrollDrawDiff: null,
32531		loaderVisible: false,
32532		forceReposition: false
32533	};
32534
32535	// @todo The defaults should extend a `c` property and the internal settings
32536	// only held in the `s` property. At the moment they are mixed
32537	this.s = $.extend( this.s, Scroller.oDefaults, opts );
32538
32539	// Workaround for row height being read from height object (see above comment)
32540	this.s.heights.row = this.s.rowHeight;
32541
32542	/**
32543	 * DOM elements used by the class instance
32544	 * @private
32545	 * @namespace
32546	 *
32547	 */
32548	this.dom = {
32549		"force":    document.createElement('div'),
32550		"scroller": null,
32551		"table":    null,
32552		"loader":   null
32553	};
32554
32555	// Attach the instance to the DataTables instance so it can be accessed in
32556	// future. Don't initialise Scroller twice on the same table
32557	if ( this.s.dt.oScroller ) {
32558		return;
32559	}
32560
32561	this.s.dt.oScroller = this;
32562
32563	/* Let's do it */
32564	this._fnConstruct();
32565};
32566
32567
32568
32569$.extend( Scroller.prototype, {
32570	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
32571	 * Public methods
32572	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32573
32574	/**
32575	 * Calculate the pixel position from the top of the scrolling container for
32576	 * a given row
32577	 *  @param {int} iRow Row number to calculate the position of
32578	 *  @returns {int} Pixels
32579	 *  @example
32580	 *    $(document).ready(function() {
32581	 *      $('#example').dataTable( {
32582	 *        "sScrollY": "200px",
32583	 *        "sAjaxSource": "media/dataset/large.txt",
32584	 *        "sDom": "frtiS",
32585	 *        "bDeferRender": true,
32586	 *        "fnInitComplete": function (o) {
32587	 *          // Find where row 25 is
32588	 *          alert( o.oScroller.fnRowToPixels( 25 ) );
32589	 *        }
32590	 *      } );
32591	 *    } );
32592	 */
32593	"fnRowToPixels": function ( rowIdx, intParse, virtual )
32594	{
32595		var pixels;
32596		var diff = rowIdx - this.s.baseRowTop;
32597
32598		if ( virtual ) {
32599			pixels = this._domain( 'virtualToPhysical', this.s.baseScrollTop );
32600			pixels += diff * this.s.heights.row;
32601		}
32602		else {
32603			pixels = this.s.baseScrollTop;
32604			pixels += diff * this.s.heights.row;
32605		}
32606
32607		return intParse || intParse === undefined ?
32608			parseInt( pixels, 10 ) :
32609			pixels;
32610	},
32611
32612
32613	/**
32614	 * Calculate the row number that will be found at the given pixel position
32615	 * (y-scroll).
32616	 *
32617	 * Please note that when the height of the full table exceeds 1 million
32618	 * pixels, Scroller switches into a non-linear mode for the scrollbar to fit
32619	 * all of the records into a finite area, but this function returns a linear
32620	 * value (relative to the last non-linear positioning).
32621	 *  @param {int} iPixels Offset from top to calculate the row number of
32622	 *  @param {int} [intParse=true] If an integer value should be returned
32623	 *  @param {int} [virtual=false] Perform the calculations in the virtual domain
32624	 *  @returns {int} Row index
32625	 *  @example
32626	 *    $(document).ready(function() {
32627	 *      $('#example').dataTable( {
32628	 *        "sScrollY": "200px",
32629	 *        "sAjaxSource": "media/dataset/large.txt",
32630	 *        "sDom": "frtiS",
32631	 *        "bDeferRender": true,
32632	 *        "fnInitComplete": function (o) {
32633	 *          // Find what row number is at 500px
32634	 *          alert( o.oScroller.fnPixelsToRow( 500 ) );
32635	 *        }
32636	 *      } );
32637	 *    } );
32638	 */
32639	"fnPixelsToRow": function ( pixels, intParse, virtual )
32640	{
32641		var diff = pixels - this.s.baseScrollTop;
32642		var row = virtual ?
32643			(this._domain( 'physicalToVirtual', this.s.baseScrollTop ) + diff) / this.s.heights.row :
32644			( diff / this.s.heights.row ) + this.s.baseRowTop;
32645
32646		return intParse || intParse === undefined ?
32647			parseInt( row, 10 ) :
32648			row;
32649	},
32650
32651
32652	/**
32653	 * Calculate the row number that will be found at the given pixel position (y-scroll)
32654	 *  @param {int} iRow Row index to scroll to
32655	 *  @param {bool} [bAnimate=true] Animate the transition or not
32656	 *  @returns {void}
32657	 *  @example
32658	 *    $(document).ready(function() {
32659	 *      $('#example').dataTable( {
32660	 *        "sScrollY": "200px",
32661	 *        "sAjaxSource": "media/dataset/large.txt",
32662	 *        "sDom": "frtiS",
32663	 *        "bDeferRender": true,
32664	 *        "fnInitComplete": function (o) {
32665	 *          // Immediately scroll to row 1000
32666	 *          o.oScroller.fnScrollToRow( 1000 );
32667	 *        }
32668	 *      } );
32669	 *     
32670	 *      // Sometime later on use the following to scroll to row 500...
32671	 *          var oSettings = $('#example').dataTable().fnSettings();
32672	 *      oSettings.oScroller.fnScrollToRow( 500 );
32673	 *    } );
32674	 */
32675	"fnScrollToRow": function ( iRow, bAnimate )
32676	{
32677		var that = this;
32678		var ani = false;
32679		var px = this.fnRowToPixels( iRow );
32680
32681		// We need to know if the table will redraw or not before doing the
32682		// scroll. If it will not redraw, then we need to use the currently
32683		// displayed table, and scroll with the physical pixels. Otherwise, we
32684		// need to calculate the table's new position from the virtual
32685		// transform.
32686		var preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows;
32687		var drawRow = iRow - preRows;
32688		if ( drawRow < 0 ) {
32689			drawRow = 0;
32690		}
32691
32692		if ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) {
32693			ani = true;
32694			px = this._domain( 'virtualToPhysical', iRow * this.s.heights.row );
32695
32696			// If we need records outside the current draw region, but the new
32697			// scrolling position is inside that (due to the non-linear nature
32698			// for larger numbers of records), we need to force position update.
32699			if ( this.s.redrawTop < px && px < this.s.redrawBottom ) {
32700				this.s.forceReposition = true;
32701				bAnimate = false;
32702			}
32703		}
32704
32705		if ( typeof bAnimate == 'undefined' || bAnimate )
32706		{
32707			this.s.ani = ani;
32708			$(this.dom.scroller).animate( {
32709				"scrollTop": px
32710			}, function () {
32711				// This needs to happen after the animation has completed and
32712				// the final scroll event fired
32713				setTimeout( function () {
32714					that.s.ani = false;
32715				}, 25 );
32716			} );
32717		}
32718		else
32719		{
32720			$(this.dom.scroller).scrollTop( px );
32721		}
32722	},
32723
32724
32725	/**
32726	 * Calculate and store information about how many rows are to be displayed
32727	 * in the scrolling viewport, based on current dimensions in the browser's
32728	 * rendering. This can be particularly useful if the table is initially
32729	 * drawn in a hidden element - for example in a tab.
32730	 *  @param {bool} [bRedraw=true] Redraw the table automatically after the recalculation, with
32731	 *    the new dimensions forming the basis for the draw.
32732	 *  @returns {void}
32733	 *  @example
32734	 *    $(document).ready(function() {
32735	 *      // Make the example container hidden to throw off the browser's sizing
32736	 *      document.getElementById('container').style.display = "none";
32737	 *      var oTable = $('#example').dataTable( {
32738	 *        "sScrollY": "200px",
32739	 *        "sAjaxSource": "media/dataset/large.txt",
32740	 *        "sDom": "frtiS",
32741	 *        "bDeferRender": true,
32742	 *        "fnInitComplete": function (o) {
32743	 *          // Immediately scroll to row 1000
32744	 *          o.oScroller.fnScrollToRow( 1000 );
32745	 *        }
32746	 *      } );
32747	 *     
32748	 *      setTimeout( function () {
32749	 *        // Make the example container visible and recalculate the scroller sizes
32750	 *        document.getElementById('container').style.display = "block";
32751	 *        oTable.fnSettings().oScroller.fnMeasure();
32752	 *      }, 3000 );
32753	 */
32754	"fnMeasure": function ( bRedraw )
32755	{
32756		if ( this.s.autoHeight )
32757		{
32758			this._fnCalcRowHeight();
32759		}
32760
32761		var heights = this.s.heights;
32762
32763		if ( heights.row ) {
32764			heights.viewport = $.contains(document, this.dom.scroller) ?
32765				$(this.dom.scroller).height() :
32766				this._parseHeight($(this.dom.scroller).css('height'));
32767
32768			// If collapsed (no height) use the max-height parameter
32769			if ( ! heights.viewport ) {
32770				heights.viewport = this._parseHeight($(this.dom.scroller).css('max-height'));
32771			}
32772
32773			this.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1;
32774			this.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer;
32775		}
32776
32777		if ( bRedraw === undefined || bRedraw )
32778		{
32779			this.s.dt.oInstance.fnDraw( false );
32780		}
32781	},
32782
32783
32784	/**
32785	 * Get information about current displayed record range. This corresponds to
32786	 * the information usually displayed in the "Info" block of the table.
32787	 *
32788	 * @returns {object} info as an object:
32789	 *  {
32790	 *      start: {int}, // the 0-indexed record at the top of the viewport
32791	 *      end:   {int}, // the 0-indexed record at the bottom of the viewport
32792	 *  }
32793	*/
32794	"fnPageInfo": function()
32795	{
32796		var 
32797			dt = this.s.dt,
32798			iScrollTop = this.dom.scroller.scrollTop,
32799			iTotal = dt.fnRecordsDisplay(),
32800			iPossibleEnd = Math.ceil(this.fnPixelsToRow(iScrollTop + this.s.heights.viewport, false, this.s.ani));
32801
32802		return {
32803			start: Math.floor(this.fnPixelsToRow(iScrollTop, false, this.s.ani)),
32804			end: iTotal < iPossibleEnd ? iTotal-1 : iPossibleEnd-1
32805		};
32806	},
32807
32808
32809	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
32810	 * Private methods (they are of course public in JS, but recommended as private)
32811	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32812
32813	/**
32814	 * Initialisation for Scroller
32815	 *  @returns {void}
32816	 *  @private
32817	 */
32818	"_fnConstruct": function ()
32819	{
32820		var that = this;
32821		var dt = this.s.dtApi;
32822
32823		/* Sanity check */
32824		if ( !this.s.dt.oFeatures.bPaginate ) {
32825			this.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' );
32826			return;
32827		}
32828
32829		/* Insert a div element that we can use to force the DT scrolling container to
32830		 * the height that would be required if the whole table was being displayed
32831		 */
32832		this.dom.force.style.position = "relative";
32833		this.dom.force.style.top = "0px";
32834		this.dom.force.style.left = "0px";
32835		this.dom.force.style.width = "1px";
32836
32837		this.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0];
32838		this.dom.scroller.appendChild( this.dom.force );
32839		this.dom.scroller.style.position = "relative";
32840
32841		this.dom.table = $('>table', this.dom.scroller)[0];
32842		this.dom.table.style.position = "absolute";
32843		this.dom.table.style.top = "0px";
32844		this.dom.table.style.left = "0px";
32845
32846		// Add class to 'announce' that we are a Scroller table
32847		$(dt.table().container()).addClass('DTS');
32848
32849		// Add a 'loading' indicator
32850		if ( this.s.loadingIndicator )
32851		{
32852			this.dom.loader = $('<div class="dataTables_processing DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')
32853				.css('display', 'none');
32854
32855			$(this.dom.scroller.parentNode)
32856				.css('position', 'relative')
32857				.append( this.dom.loader );
32858		}
32859
32860		/* Initial size calculations */
32861		if ( this.s.heights.row && this.s.heights.row != 'auto' )
32862		{
32863			this.s.autoHeight = false;
32864		}
32865		this.fnMeasure( false );
32866
32867		// Scrolling callback to see if a page change is needed - use a throttled
32868		// function for the save save callback so we aren't hitting it on every
32869		// scroll
32870		this.s.ingnoreScroll = true;
32871		this.s.stateSaveThrottle = this.s.dt.oApi._fnThrottle( function () {
32872			that.s.dtApi.state.save();
32873		}, 500 );
32874		$(this.dom.scroller).on( 'scroll.dt-scroller', function (e) {
32875			that._fnScroll.call( that );
32876		} );
32877
32878		// In iOS we catch the touchstart event in case the user tries to scroll
32879		// while the display is already scrolling
32880		$(this.dom.scroller).on('touchstart.dt-scroller', function () {
32881			that._fnScroll.call( that );
32882		} );
32883
32884		// On resize, update the information element, since the number of rows shown might change
32885		$(window).on( 'resize.dt-scroller', function () {
32886			that.fnMeasure( false );
32887			that._fnInfo();
32888		} );
32889
32890		// Add a state saving parameter to the DT state saving so we can restore the exact
32891		// position of the scrolling. Slightly surprisingly the scroll position isn't actually
32892		// stored, but rather tha base units which are needed to calculate it. This allows for
32893		// virtual scrolling as well.
32894		var initialStateSave = true;
32895		var loadedState = dt.state.loaded();
32896
32897		dt.on( 'stateSaveParams.scroller', function ( e, settings, data ) {
32898			// Need to used the saved position on init
32899			data.scroller = {
32900				topRow: initialStateSave && loadedState && loadedState.scroller ?
32901					loadedState.scroller.topRow :
32902					that.s.topRowFloat,
32903				baseScrollTop: that.s.baseScrollTop,
32904				baseRowTop: that.s.baseRowTop
32905			};
32906
32907			initialStateSave = false;
32908		} );
32909
32910		if ( loadedState && loadedState.scroller ) {
32911			this.s.topRowFloat = loadedState.scroller.topRow;
32912			this.s.baseScrollTop = loadedState.scroller.baseScrollTop;
32913			this.s.baseRowTop = loadedState.scroller.baseRowTop;
32914		}
32915
32916		dt.on( 'init.scroller', function () {
32917			that.fnMeasure( false );
32918
32919			that._fnDrawCallback();
32920
32921			// Update the scroller when the DataTable is redrawn
32922			dt.on( 'draw.scroller', function () {
32923				that._fnDrawCallback();
32924			});
32925		} );
32926
32927		// Set height before the draw happens, allowing everything else to update
32928		// on draw complete without worry for roder.
32929		dt.on( 'preDraw.dt.scroller', function () {
32930			that._fnScrollForce();
32931		} );
32932
32933		// Destructor
32934		dt.on( 'destroy.scroller', function () {
32935			$(window).off( 'resize.dt-scroller' );
32936			$(that.dom.scroller).off('.dt-scroller');
32937			$(that.s.dt.nTable).off( '.scroller' );
32938
32939			$(that.s.dt.nTableWrapper).removeClass('DTS');
32940			$('div.DTS_Loading', that.dom.scroller.parentNode).remove();
32941
32942			that.dom.table.style.position = "";
32943			that.dom.table.style.top = "";
32944			that.dom.table.style.left = "";
32945		} );
32946	},
32947
32948
32949	/**
32950	 * Scrolling function - fired whenever the scrolling position is changed.
32951	 * This method needs to use the stored values to see if the table should be
32952	 * redrawn as we are moving towards the end of the information that is
32953	 * currently drawn or not. If needed, then it will redraw the table based on
32954	 * the new position.
32955	 *  @returns {void}
32956	 *  @private
32957	 */
32958	"_fnScroll": function ()
32959	{
32960		var
32961			that = this,
32962			heights = this.s.heights,
32963			iScrollTop = this.dom.scroller.scrollTop,
32964			iTopRow;
32965
32966		if ( this.s.skip ) {
32967			return;
32968		}
32969
32970		if ( this.s.ingnoreScroll ) {
32971			return;
32972		}
32973
32974		/* If the table has been sorted or filtered, then we use the redraw that
32975		 * DataTables as done, rather than performing our own
32976		 */
32977		if ( this.s.dt.bFiltered || this.s.dt.bSorted ) {
32978			this.s.lastScrollTop = 0;
32979			return;
32980		}
32981
32982		/* Update the table's information display for what is now in the viewport */
32983		this._fnInfo();
32984
32985		/* We don't want to state save on every scroll event - that's heavy
32986		 * handed, so use a timeout to update the state saving only when the
32987		 * scrolling has finished
32988		 */
32989		clearTimeout( this.s.stateTO );
32990		this.s.stateTO = setTimeout( function () {
32991			that.s.dtApi.state.save();
32992		}, 250 );
32993
32994		/* Check if the scroll point is outside the trigger boundary which w
32994ould required
32995		 * a DataTables redraw
32996		 */
32997		if ( this.s.forceReposition || iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {
32998
32999			var preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );
33000
33001			iTopRow = parseInt(this._domain( 'physicalToVirtual', iScrollTop ) / heights.row, 10) - preRows;
33002			this.s.topRowFloat = this._domain( 'physicalToVirtual', iScrollTop ) / heights.row;
33003			this.s.forceReposition = false;
33004
33005			if ( iTopRow <= 0 ) {
33006				/* At the start of the table */
33007				iTopRow = 0;
33008			}
33009			else if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {
33010				/* At the end of the table */
33011				iTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;
33012				if ( iTopRow < 0 ) {
33013					iTopRow = 0;
33014				}
33015			}
33016			else if ( iTopRow % 2 !== 0 ) {
33017				// For the row-striping classes (odd/even) we want only to start
33018				// on evens otherwise the stripes will change between draws and
33019				// look rubbish
33020				iTopRow++;
33021			}
33022
33023			if ( iTopRow != this.s.dt._iDisplayStart ) {
33024				/* Cache the new table position for quick lookups */
33025				this.s.tableTop = $(this.s.dt.nTable).offset().top;
33026				this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;
33027
33028				var draw =  function () {
33029					if ( that.s.scrollDrawReq === null ) {
33030						that.s.scrollDrawReq = iScrollTop;
33031					}
33032
33033					that.s.dt._iDisplayStart = iTopRow;
33034					that.s.dt.oApi._fnDraw( that.s.dt );
33035				};
33036
33037				/* Do the DataTables redraw based on the calculated start point - note that when
33038				 * using server-side processing we introduce a small delay to not DoS the server...
33039				 */
33040				if ( this.s.dt.oFeatures.bServerSide ) {
33041					clearTimeout( this.s.drawTO );
33042					this.s.drawTO = setTimeout( draw, this.s.serverWait );
33043				}
33044				else {
33045					draw();
33046				}
33047
33048				if ( this.dom.loader && ! this.s.loaderVisible ) {
33049					this.dom.loader.css( 'display', 'block' );
33050					this.s.loaderVisible = true;
33051				}
33052			}
33053		}
33054		else {
33055			this.s.topRowFloat = this.fnPixelsToRow( iScrollTop, false, true );
33056		}
33057
33058		this.s.lastScrollTop = iScrollTop;
33059		this.s.stateSaveThrottle();
33060	},
33061
33062
33063	/**
33064	 * Convert from one domain to another. The physical domain is the actual
33065	 * pixel count on the screen, while the virtual is if we had browsers which
33066	 * had scrolling containers of infinite height (i.e. the absolute value)
33067	 *
33068	 *  @param {string} dir Domain transform direction, `virtualToPhysical` or
33069	 *    `physicalToVirtual` 
33070	 *  @returns {number} Calculated transform
33071	 *  @private
33072	 */
33073	_domain: function ( dir, val )
33074	{
33075		var heights = this.s.heights;
33076		var coeff;
33077
33078		// If the virtual and physical height match, then we use a linear
33079		// transform between the two, allowing the scrollbar to be linear
33080		if ( heights.virtual === heights.scroll ) {
33081			return val;
33082		}
33083
33084		// Otherwise, we want a non-linear scrollbar to take account of the
33085		// redrawing regions at the start and end of the table, otherwise these
33086		// can stutter badly - on large tables 30px (for example) scroll might
33087		// be hundreds of rows, so the table would be redrawing every few px at
33088		// the start and end. Use a simple quadratic to stop this. It does mean
33089		// the scrollbar is non-linear, but with such massive data sets, the
33090		// scrollbar is going to be a best guess anyway
33091		var xMax = (heights.scroll - heights.viewport) / 2;
33092		var yMax = (heights.virtual - heights.viewport) / 2;
33093
33094		coeff = yMax / ( xMax * xMax );
33095
33096		if ( dir === 'virtualToPhysical' ) {
33097			if ( val < yMax ) {
33098				return Math.pow(val / coeff, 0.5);
33099			}
33100			else {
33101				val = (yMax*2) - val;
33102				return val < 0 ?
33103					heights.scroll :
33104					(xMax*2) - Math.pow(val / coeff, 0.5);
33105			}
33106		}
33107		else if ( dir === 'physicalToVirtual' ) {
33108			if ( val < xMax ) {
33109				return val * val * coeff;
33110			}
33111			else {
33112				val = (xMax*2) - val;
33113				return val < 0 ?
33114					heights.virtual :
33115					(yMax*2) - (val * val * coeff);
33116			}
33117		}
33118	},
33119
33120	/**
33121	 * Parse CSS height property string as number
33122	 *
33123	 * An attempt is made to parse the string as a number. Currently supported units are 'px',
33124	 * 'vh', and 'rem'. 'em' is partially supported; it works as long as the parent element's
33125	 * font size matches the body element. Zero is returned for unrecognized strings.
33126	 *  @param {string} cssHeight CSS height property string
33127	 *  @returns {number} height
33128	 *  @private
33129	 */
33130	_parseHeight: function(cssHeight) {
33131		var height;
33132		var matches = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(px|em|rem|vh)$/.exec(cssHeight);
33133
33134		if (matches === null) {
33135			return 0;
33136		}
33137
33138		var value = parseFloat(matches[1]);
33139		var unit = matches[2];
33140
33141		if ( unit === 'px' ) {
33142			height = value;
33143		}
33144		else if ( unit === 'vh' ) {
33145			height = ( value / 100 ) * $(window).height();
33146		}
33147		else if ( unit === 'rem' ) {
33148			height = value * parseFloat($(':root').css('font-size'));
33149		}
33150		else if ( unit === 'em' ) {
33151			height = value * parseFloat($('body').css('font-size'));
33152		}
33153
33154		return height ?
33155			height :
33156			0;
33157	},
33158
33159
33160	/**
33161	 * Draw callback function which is fired when the DataTable is redrawn. The main function of
33162	 * this method is to position the drawn table correctly the scrolling container for the rows
33163	 * that is displays as a result of the scrolling position.
33164	 *  @returns {void}
33165	 *  @private
33166	 */
33167	"_fnDrawCallback": function ()
33168	{
33169		var
33170			that = this,
33171			heights = this.s.heights,
33172			iScrollTop = this.dom.scroller.scrollTop,
33173			iActualScrollTop = iScrollTop,
33174			iScrollBottom = iScrollTop + heights.viewport,
33175			iTableHeight = $(this.s.dt.nTable).height(),
33176			displayStart = this.s.dt._iDisplayStart,
33177			displayLen = this.s.dt._iDisplayLength,
33178			displayEnd = this.s.dt.fnRecordsDisplay();
33179
33180		// Disable the scroll event listener while we are updating the DOM
33181		this.s.skip = true;
33182
33183		// If paging is reset
33184		if ( (this.s.dt.bSorted || this.s.dt.bFiltered) && displayStart === 0 ) {
33185			this.s.topRowFloat = 0;
33186		}
33187
33188		// Reposition the scrolling for the updated virtual position if needed
33189		if ( displayStart === 0 ) {
33190			// Linear calculation at the top of the table
33191			iScrollTop = this.s.topRowFloat * heights.row;
33192		}
33193		else if ( displayStart + displayLen >= displayEnd ) {
33194			// Linear calculation that the bottom as well
33195			iScrollTop = heights.scroll - ((displayEnd - this.s.topRowFloat) * heights.row);
33196		}
33197		else {
33198			// Domain scaled in the middle
33199			iScrollTop = this._domain( 'virtualToPhysical', this.s.topRowFloat * heights.row );
33200		}
33201
33202		this.dom.scroller.scrollTop = iScrollTop;
33203
33204		// Store positional information so positional calculations can be based
33205		// upon the current table draw position
33206		this.s.baseScrollTop = iScrollTop;
33207		this.s.baseRowTop = this.s.topRowFloat;
33208
33209		// Position the table in the virtual scroller
33210		var tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row);
33211		if ( displayStart === 0 ) {
33212			tableTop = 0;
33213		}
33214		else if ( displayStart + displayLen >= displayEnd ) {
33215			tableTop = heights.scroll - iTableHeight;
33216		}
33217
33218		this.dom.table.style.top = tableTop+'px';
33219
33220		/* Cache some information for the scroller */
33221		this.s.tableTop = tableTop;
33222		this.s.tableBottom = iTableHeight + this.s.tableTop;
33223
33224		// Calculate the boundaries for where a redraw will be triggered by the
33225		// scroll event listener
33226		var boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale;
33227		this.s.redrawTop = iScrollTop - boundaryPx;
33228		this.s.redrawBottom = iScrollTop + boundaryPx > heights.scroll - heights.viewport - heights.row ?
33229			heights.scroll - heights.viewport - heights.row :
33230			iScrollTop + boundaryPx;
33231
33232		this.s.skip = false;
33233
33234		// Restore the scrolling position that was saved by DataTable's state
33235		// saving Note that this is done on the second draw when data is Ajax
33236		// sourced, and the first draw when DOM soured
33237		if ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null &&
33238			 typeof this.s.dt.oLoadedState.iScroller != 'undefined' )
33239		{
33240			// A quirk of DataTables is that the draw callback will occur on an
33241			// empty set if Ajax sourced, but not if server-side processing.
33242			var ajaxSourced = (this.s.dt.sAjaxSource || that.s.dt.ajax) && ! this.s.dt.oFeatures.bServerSide ?
33243				true :
33244				false;
33245
33246			if ( ( ajaxSourced && this.s.dt.iDraw == 2) ||
33247			     (!ajaxSourced && this.s.dt.iDraw == 1) )
33248			{
33249				setTimeout( function () {
33250					$(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller );
33251					that.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2);
33252
33253					// In order to prevent layout thrashing we need another
33254					// small delay
33255					setTimeout( function () {
33256						that.s.ingnoreScroll = false;
33257					}, 0 );
33258				}, 0 );
33259			}
33260		}
33261		else {
33262			that.s.ingnoreScroll = false;
33263		}
33264
33265		// Because of the order of the DT callbacks, the info update will
33266		// take precedence over the one we want here. So a 'thread' break is
33267		// needed.  Only add the thread break if bInfo is set
33268		if ( this.s.dt.oFeatures.bInfo ) {
33269			setTimeout( function () {
33270				that._fnInfo.call( that );
33271			}, 0 );
33272		}
33273
33274		// Hide the loading indicator
33275		if ( this.dom.loader && this.s.loaderVisible ) {
33276			this.dom.loader.css( 'display', 'none' );
33277			this.s.loaderVisible = false;
33278		}
33279	},
33280
33281
33282	/**
33283	 * Force the scrolling container to have height beyond that of just the
33284	 * table that has been drawn so the user can scroll the whole data set.
33285	 *
33286	 * Note that if the calculated required scrolling height exceeds a maximum
33287	 * value (1 million pixels - hard-coded) the forcing element will be set
33288	 * only to that maximum value and virtual / physical domain transforms will
33289	 * be used to allow Scroller to display tables of any number of records.
33290	 *  @returns {void}
33291	 *  @private
33292	 */
33293	_fnScrollForce: function ()
33294	{
33295		var heights = this.s.heights;
33296		var max = 1000000;
33297
33298		heights.virtual = heights.row * this.s.dt.fnRecordsDisplay();
33299		heights.scroll = heights.virtual;
33300
33301		if ( heights.scroll > max ) {
33302			heights.scroll = max;
33303		}
33304
33305		// Minimum height so there is always a row visible (the 'no rows found'
33306		// if reduced to zero filtering)
33307		this.dom.force.style.height = heights.scroll > this.s.heights.row ?
33308			heights.scroll+'px' :
33309			this.s.heights.row+'px';
33310	},
33311
33312
33313	/**
33314	 * Automatic calculation of table row height. This is just a little tricky here as using
33315	 * initialisation DataTables has tale the table out of the document, so we need to create
33316	 * a new table and insert it into the document, calculate the row height and then whip the
33317	 * table out.
33318	 *  @returns {void}
33319	 *  @private
33320	 */
33321	"_fnCalcRowHeight": function ()
33322	{
33323		var dt = this.s.dt;
33324		var origTable = dt.nTable;
33325		var nTable = origTable.cloneNode( false );
33326		var tbody = $('<tbody/>').appendTo( nTable );
33327		var container = $(
33328			'<div class="'+dt.oClasses.sWrapper+' DTS">'+
33329				'<div class="'+dt.oClasses.sScrollWrapper+'">'+
33330					'<div class="'+dt.oClasses.sScrollBody+'"></div>'+
33331				'</div>'+
33332			'</div>'
33333		);
33334
33335		// Want 3 rows in the sizing table so :first-child and :last-child
33336		// CSS styles don't come into play - take the size of the middle row
33337		$('tbody tr:lt(4)', origTable).clone().appendTo( tbody );
33338		while( $('tr', tbody).length < 3 ) {
33339			tbody.append( '<tr><td>&nbsp;</td></tr>' );
33340		}
33341
33342		$('div.'+dt.oClasses.sScrollBody, container).append( nTable );
33343
33344		// If initialised using `dom`, use the holding element as the insert point
33345		var insertEl = this.s.dt.nHolding || origTable.parentNode;
33346
33347		if ( ! $(insertEl).is(':visible') ) {
33348			insertEl = 'body';
33349		}
33350
33351		container.appendTo( insertEl );
33352		this.s.heights.row = $('tr', tbody).eq(1).outerHeight();
33353
33354		container.remove();
33355	},
33356
33357
33358	/**
33359	 * Update any information elements that are controlled by the DataTable based on the scrolling
33360	 * viewport and what rows are visible in it. This function basically acts in the same way as
33361	 * _fnUpdateInfo in DataTables, and effectively replaces that function.
33362	 *  @returns {void}
33363	 *  @private
33364	 */
33365	"_fnInfo": function ()
33366	{
33367		if ( !this.s.dt.oFeatures.bInfo )
33368		{
33369			return;
33370		}
33371
33372		var
33373			dt = this.s.dt,
33374			language = dt.oLanguage,
33375			iScrollTop = this.dom.scroller.scrollTop,
33376			iStart = Math.floor( this.fnPixelsToRow(iScrollTop, false, this.s.ani)+1 ),
33377			iMax = dt.fnRecordsTotal(),
33378			iTotal = dt.fnRecordsDisplay(),
33379			iPossibleEnd = Math.ceil( this.fnPixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ),
33380			iEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd,
33381			sStart = dt.fnFormatNumber( iStart ),
33382			sEnd = dt.fnFormatNumber( iEnd ),
33383			sMax = dt.fnFormatNumber( iMax ),
33384			sTotal = dt.fnFormatNumber( iTotal ),
33385			sOut;
33386
33387		if ( dt.fnRecordsDisplay() === 0 &&
33388			   dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
33389		{
33390			/* Empty record set */
33391			sOut = language.sInfoEmpty+ language.sInfoPostFix;
33392		}
33393		else if ( dt.fnRecordsDisplay() === 0 )
33394		{
33395			/* Empty record set after filtering */
33396			sOut = language.sInfoEmpty +' '+
33397				language.sInfoFiltered.replace('_MAX_', sMax)+
33398					language.sInfoPostFix;
33399		}
33400		else if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
33401		{
33402			/* Normal record set */
33403			sOut = language.sInfo.
33404					replace('_START_', sStart).
33405					replace('_END_',   sEnd).
33406					replace('_MAX_',   sMax).
33407					replace('_TOTAL_', sTotal)+
33408				language.sInfoPostFix;
33409		}
33410		else
33411		{
33412			/* Record set after filtering */
33413			sOut = language.sInfo.
33414					replace('_START_', sStart).
33415					replace('_END_',   sEnd).
33416					replace('_MAX_',   sMax).
33417					replace('_TOTAL_', sTotal) +' '+
33418				language.sInfoFiltered.replace(
33419					'_MAX_',
33420					dt.fnFormatNumber(dt.fnRecordsTotal())
33421				)+
33422				language.sInfoPostFix;
33423		}
33424
33425		var callback = language.fnInfoCallback;
33426		if ( callback ) {
33427			sOut = callback.call( dt.oInstance,
33428				dt, iStart, iEnd, iMax, iTotal, sOut
33429			);
33430		}
33431
33432		var n = dt.aanFeatures.i;
33433		if ( typeof n != 'undefined' )
33434		{
33435			for ( var i=0, iLen=n.length ; i<iLen ; i++ )
33436			{
33437				$(n[i]).html( sOut );
33438			}
33439		}
33440
33441		// DT doesn't actually (yet) trigger this event, but it will in future
33442		$(dt.nTable).triggerHandler( 'info.dt' );
33443	}
33444} );
33445
33446
33447
33448/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
33449 * Statics
33450 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
33451
33452
33453/**
33454 * Scroller default settings for initialisation
33455 *  @namespace
33456 *  @name Scroller.defaults
33457 *  @static
33458 */
33459Scroller.defaults = /** @lends Scroller.defaults */{
33460	/**
33461	 * Indicate if Scroller show show trace information on the console or not. This can be
33462	 * useful when debugging Scroller or if just curious as to what it is doing, but should
33463	 * be turned off for production.
33464	 *  @type     bool
33465	 *  @default  false
33466	 *  @static
33467	 *  @example
33468	 *    var oTable = $('#example').dataTable( {
33469	 *        "sScrollY": "200px",
33470	 *        "sDom": "frtiS",
33471	 *        "bDeferRender": true,
33472	 *        "oScroller": {
33473	 *          "trace": true
33474	 *        }
33475	 *    } );
33476	 */
33477	"trace": false,
33478
33479	/**
33480	 * Scroller will attempt to automatically calculate the height of rows for it's internal
33481	 * calculations. However the height that is used can be overridden using this parameter.
33482	 *  @type     int|string
33483	 *  @default  auto
33484	 *  @static
33485	 *  @example
33486	 *    var oTable = $('#example').dataTable( {
33487	 *        "sScrollY": "200px",
33488	 *        "sDom": "frtiS",
33489	 *        "bDeferRender": true,
33490	 *        "oScroller": {
33491	 *          "rowHeight": 30
33492	 *        }
33493	 *    } );
33494	 */
33495	"rowHeight": "auto",
33496
33497	/**
33498	 * When using server-side processing, Scroller will wait a small amount of time to allow
33499	 * the scrolling to finish before requesting more data from the server. This prevents
33500	 * you from DoSing your own server! The wait time can be configured by this parameter.
33501	 *  @type     int
33502	 *  @default  200
33503	 *  @static
33504	 *  @example
33505	 *    var oTable = $('#example').dataTable( {
33506	 *        "sScrollY": "200px",
33507	 *        "sDom": "frtiS",
33508	 *        "bDeferRender": true,
33509	 *        "oScroller": {
33510	 *          "serverWait": 100
33511	 *        }
33512	 *    } );
33513	 */
33514	"serverWait": 200,
33515
33516	/**
33517	 * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch
33518	 * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch
33519	 * rows that will be shown in "near scrolling" (i.e. just beyond the current display area).
33520	 * The value is based upon the number of rows that can be displayed in the viewport (i.e.
33521	 * a value of 1), and will apply the display range to records before before and after the
33522	 * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth
33523	 * of rows before the current viewport, the current viewport's rows and 1 viewport's worth
33524	 * of rows after the current viewport. Adjusting this value can be useful for ensuring
33525	 * smooth scrolling based on your data set.
33526	 *  @type     int
33527	 *  @default  7
33528	 *  @static
33529	 *  @example
33530	 *    var oTable = $('#example').dataTable( {
33531	 *        "sScrollY": "200px",
33532	 *        "sDom": "frtiS",
33533	 *        "bDeferRender": true,
33534	 *        "oScroller": {
33535	 *          "displayBuffer": 10
33536	 *        }
33537	 *    } );
33538	 */
33539	"displayBuffer": 9,
33540
33541	/**
33542	 * Scroller uses the boundary scaling factor to decide when to redraw the table - which it
33543	 * typically does before you reach the end of the currently loaded data set (in order to
33544	 * allow the data to look continuous to a user scrolling through the data). If given as 0
33545	 * then the table will be redrawn whenever the viewport is scrolled, while 1 would not
33546	 * redraw the table until the currently loaded data has all been shown. You will want
33547	 * something in the middle - the default factor of 0.5 is usually suitable.
33548	 *  @type     float
33549	 *  @default  0.5
33550	 *  @static
33551	 *  @example
33552	 *    var oTable = $('#example').dataTable( {
33553	 *        "sScrollY": "200px",
33554	 *        "sDom": "frtiS",
33555	 *        "bDeferRender": true,
33556	 *        "oScroller": {
33557	 *          "boundaryScale": 0.75
33558	 *        }
33559	 *    } );
33560	 */
33561	"boundaryScale": 0.5,
33562
33563	/**
33564	 * Show (or not) the loading element in the background of the table. Note that you should
33565	 * include the dataTables.scroller.css file for this to be displayed correctly.
33566	 *  @type     boolean
33567	 *  @default  false
33568	 *  @static
33569	 *  @example
33570	 *    var oTable = $('#example').dataTable( {
33571	 *        "sScrollY": "200px",
33572	 *        "sDom": "frtiS",
33573	 *        "bDeferRender": true,
33574	 *        "oScroller": {
33575	 *          "loadingIndicator": true
33576	 *        }
33577	 *    } );
33578	 */
33579	"loadingIndicator": false
33580};
33581
33582Scroller.oDefaults = Scroller.defaults;
33583
33584
33585
33586/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
33587 * Constants
33588 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
33589
33590/**
33591 * Scroller version
33592 *  @type      String
33593 *  @default   See code
33594 *  @name      Scroller.version
33595 *  @static
33596 */
33597Scroller.version = "1.5.0";
33598
33599
33600
33601/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
33602 * Initialisation
33603 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
33604
33605// Legacy `dom` parameter initialisation support
33606if ( typeof $.fn.dataTable == "function" &&
33607     typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
33608     $.fn.dataTableExt.fnVersionCheck('1.10.0') )
33609{
33610	$.fn.dataTableExt.aoFeatures.push( {
33611		"fnInit": function( oDTSettings ) {
33612			var init = oDTSettings.oInit;
33613			var opts = init.scroller || init.oScroller || {};
33614			
33615			new Scroller( oDTSettings, opts );
33616		},
33617		"cFeature": "S",
33618		"sFeature": "Scroller"
33619	} );
33620}
33621else
33622{
33623	alert( "Warning: Scroller requires DataTables 1.10.0 or greater - www.datatables.net/download");
33624}
33625
33626// Attach a listener to the document which listens for DataTables initialisation
33627// events so we can automatically initialise
33628$(document).on( 'preInit.dt.dtscroller', function (e, settings) {
33629	if ( e.namespace !== 'dt' ) {
33630		return;
33631	}
33632
33633	var init = settings.oInit.scroller;
33634	var defaults = DataTable.defaults.scroller;
33635
33636	if ( init || defaults ) {
33637		var opts = $.extend( {}, init, defaults );
33638
33639		if ( init !== false ) {
33640			new Scroller( settings, opts  );
33641		}
33642	}
33643} );
33644
33645
33646// Attach Scroller to DataTables so it can be accessed as an 'extra'
33647$.fn.dataTable.Scroller = Scroller;
33648$.fn.DataTable.Scroller = Scroller;
33649
33650
33651// DataTables 1.10 API method aliases
33652var Api = $.fn.dataTable.Api;
33653
33654Api.register( 'scroller()', function () {
33655	return this;
33656} );
33657
33658// Undocumented and deprecated - is it actually useful at all?
33659Api.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {
33660	var ctx = this.context;
33661
33662	if ( ctx.length && ctx[0].oScroller ) {
33663		return ctx[0].oScroller.fnRowToPixels( rowIdx, intParse, virtual );
33664	}
33665	// undefined
33666} );
33667
33668// Undocumented and deprecated - is it actually useful at all?
33669Api.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {
33670	var ctx = this.context;
33671
33672	if ( ctx.length && ctx[0].oScroller ) {
33673		return ctx[0].oScroller.fnPixelsToRow( pixels, intParse, virtual );
33674	}
33675	// undefined
33676} );
33677
33678// `scroller().scrollToRow()` is undocumented and deprecated. Use `scroller.toPosition()
33679Api.register( ['scroller().scrollToRow()', 'scroller.toPosition()'], function ( idx, ani ) {
33680	this.iterator( 'table', function ( ctx ) {
33681		if ( ctx.oScroller ) {
33682			ctx.oScroller.fnScrollToRow( idx, ani );
33683		}
33684	} );
33685
33686	return this;
33687} );
33688
33689Api.register( 'row().scrollTo()', function ( ani ) {
33690	var that = this;
33691
33692	this.iterator( 'row', function ( ctx, rowIdx ) {
33693		if ( ctx.oScroller ) {
33694			var displayIdx = that
33695				.rows( { order: 'applied', search: 'applied' } )
33696				.indexes()
33697				.indexOf( rowIdx );
33698
33699			ctx.oScroller.fnScrollToRow( displayIdx, ani );
33700		}
33701	} );
33702
33703	return this;
33704} );
33705
33706Api.register( 'scroller.measure()', function ( redraw ) {
33707	this.iterator( 'table', function ( ctx ) {
33708		if ( ctx.oScroller ) {
33709			ctx.oScroller.fnMeasure( redraw );
33710		}
33711	} );
33712
33713	return this;
33714} );
33715
33716Api.register( 'scroller.page()', function() {
33717	var ctx = this.context;
33718
33719	if ( ctx.length && ctx[0].oScroller ) {
33720		return ctx[0].oScroller.fnPageInfo();
33721	}
33722	// undefined
33723} );
33724
33725return Scroller;
33726}));
33727
33728
33729/*! Select for DataTables 1.2.6
33730 * 2015-2018 SpryMedia Ltd - datatables.net/license/mit
33731 */
33732
33733/**
33734 * @summary     Select for DataTables
33735 * @description A collection of API methods, events and buttons for DataTables
33736 *   that provides selection options of the items in a DataTable
33737 * @version     1.2.6
33738 * @file        dataTables.select.js
33739 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
33740 * @contact     datatables.net/forums
33741 * @copyright   Copyright 2015-2018 SpryMedia Ltd.
33742 *
33743 * This source file is free software, available under the following license:
33744 *   MIT license - http://datatables.net/license/mit
33745 *
33746 * This source file is distributed in the hope that it will be useful, but
33747 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
33748 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
33749 *
33750 * For details please refer to: http://www.datatables.net/extensions/select
33751 */
33752(function( factory ){
33753	if ( typeof define === 'function' && define.amd ) {
33754		// AMD
33755		define( ['jquery', 'datatables.net'], function ( $ ) {
33756			return factory( $, window, document );
33757		} );
33758	}
33759	else if ( typeof exports === 'object' ) {
33760		// CommonJS
33761		module.exports = function (root, $) {
33762			if ( ! root ) {
33763				root = window;
33764			}
33765
33766			if ( ! $ || ! $.fn.dataTable ) {
33767				$ = require('datatables.net')(root, $).$;
33768			}
33769
33770			return factory( $, root, root.document );
33771		};
33772	}
33773	else {
33774		// Browser
33775		factory( jQuery, window, document );
33776	}
33777}(function( $, window, document, undefined ) {
33778'use strict';
33779var DataTable = $.fn.dataTable;
33780
33781
33782// Version information for debugger
33783DataTable.select = {};
33784
33785DataTable.select.version = '1.2.6';
33786
33787DataTable.select.init = function ( dt ) {
33788	var ctx = dt.settings()[0];
33789	var init = ctx.oInit.select;
33790	var defaults = DataTable.defaults.select;
33791	var opts = init === undefined ?
33792		defaults :
33793		init;
33794
33795	// Set defaults
33796	var items = 'row';
33797	var style = 'api';
33798	var blurable = false;
33799	var info = true;
33800	var selector = 'td, th';
33801	var className = 'selected';
33802	var setStyle = false;
33803
33804	ctx._select = {};
33805
33806	// Initialisation customisations
33807	if ( opts === true ) {
33808		style = 'os';
33809		setStyle = true;
33810	}
33811	else if ( typeof opts === 'string' ) {
33812		style = opts;
33813		setStyle = true;
33814	}
33815	else if ( $.isPlainObject( opts ) ) {
33816		if ( opts.blurable !== undefined ) {
33817			blurable = opts.blurable;
33818		}
33819
33820		if ( opts.info !== undefined ) {
33821			info = opts.info;
33822		}
33823
33824		if ( opts.items !== undefined ) {
33825			items = opts.items;
33826		}
33827
33828		if ( opts.style !== undefined ) {
33829			style = opts.style;
33830			setStyle = true;
33831		}
33832
33833		if ( opts.selector !== undefined ) {
33834			selector = opts.selector;
33835		}
33836
33837		if ( opts.className !== undefined ) {
33838			className = opts.className;
33839		}
33840	}
33841
33842	dt.select.selector( selector );
33843	dt.select.items( items );
33844	dt.select.style( style );
33845	dt.select.blurable( blurable );
33846	dt.select.info( info );
33847	ctx._select.className = className;
33848
33849
33850	// Sort table based on selected rows. Requires Select Datatables extension
33851	$.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
33852		return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
33853			if ( settings._select.items === 'row' ) {
33854				return $( td ).parent().hasClass( settings._select.className );
33855			} else if ( settings._select.items === 'cell' ) {
33856				return $( td ).hasClass( settings._select.className );
33857			}
33858			return false;
33859		});
33860	};
33861
33862	// If the init options haven't enabled select, but there is a selectable
33863	// class name, then enable
33864	if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
33865		dt.select.style( 'os' );
33866	}
33867};
33868
33869/*
33870
33871Select is a collection of API methods, event handlers, event emitters and
33872buttons (for the `Buttons` extension) for DataTables. It provides the following
33873features, with an overview of how they are implemented:
33874
33875## Selection of rows, columns and cells. Whether an item is selected or not is
33876   stored in:
33877
33878* rows: a `_select_selected` property which contains a boolean value of the
33879  DataTables' `aoData` object for each row
33880* columns: a `_select_selected` property which contains a boolean value of the
33881  DataTables' `aoColumns` object for each column
33882* cells: a `_selected_cells` property which contains an array of boolean values
33883  of the `aoData` object for each row. The array is the same length as the
33884  columns array, with each element of it representing a cell.
33885
33886This method of using boolean flags allows Select to operate when nodes have not
33887been created for rows / cells (DataTables' defer rendering feature).
33888
33889## API methods
33890
33891A range of API methods are available for triggering selection and de-selection
33892of rows. Methods are also available to configure the selection events that can
33893be triggered by an end user (such as which items are to be selected). To a large
33894extent, these of API methods *is* Select. It is basically a collection of helper
33895functions that can be used to select items in a DataTable.
33896
33897Configuration of select is held in the object `_select` which is attached to the
33898DataTables settings object on initialisation. Select being available on a table
33899is not optional when Select is loaded, but its default is for selection only to
33900be available via the API - so the end user wouldn't be able to select rows
33901without additional configuration.
33902
33903The `_select` object contains the following properties:
33904
33905```
33906{
33907	items:string     - Can be `rows`, `columns` or `cells`. Defines what item 
33908	                   will be selected if the user is allowed to activate row
33909	                   selection using the mouse.
33910	style:string     - Can be `none`, `single`, `multi` or `os`. Defines the
33911	                   interaction style when selecting items
33912	blurable:boolean - If row selection can be cleared by clicking outside of
33913	                   the table
33914	info:boolean     - If the selection summary should be shown in the table
33915	                   information elements
33916}
33917```
33918
33919In addition to the API methods, Select also extends the DataTables selector
33920options for rows, columns and cells adding a `selected` option to the selector
33921options object, allowing the developer to select only selected items or
33922unselected items.
33923
33924## Mouse selection of items
33925
33926Clicking on items can be used to select items. This is done by a simple event
33927handler that will select the items using the API methods.
33928
33929 */
33930
33931
33932/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
33933 * Local functions
33934 */
33935
33936/**
33937 * Add one or more cells to the selection when shift clicking in OS selection
33938 * style cell selection.
33939 *
33940 * Cell range is more complicated than row and column as we want to select
33941 * in the visible grid rather than by index in sequence. For example, if you
33942 * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
33943 * should also be selected (and not 1-3, 1-4. etc)
33944 * 
33945 * @param  {DataTable.Api} dt   DataTable
33946 * @param  {object}        idx  Cell index to select to
33947 * @param  {object}        last Cell index to select from
33948 * @private
33949 */
33950function cellRange( dt, idx, last )
33951{
33952	var indexes;
33953	var columnIndexes;
33954	var rowIndexes;
33955	var selectColumns = function ( start, end ) {
33956		if ( start > end ) {
33957			var tmp = end;
33958			end = start;
33959			start = tmp;
33960		}
33961		
33962		var record = false;
33963		return dt.columns( ':visible' ).indexes().filter( function (i) {
33964			if ( i === start ) {
33965				record = true;
33966			}
33967			
33968			if ( i === end ) { // not else if, as start might === end
33969				record = false;
33970				return true;
33971			}
33972
33973			return record;
33974		} );
33975	};
33976
33977	var selectRows = function ( start, end ) {
33978		var indexes = dt.rows( { search: 'applied' } ).indexes();
33979
33980		// Which comes first - might need to swap
33981		if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
33982			var tmp = end;
33983			end = start;
33984			start = tmp;
33985		}
33986
33987		var record = false;
33988		return indexes.filter( function (i) {
33989			if ( i === start ) {
33990				record = true;
33991			}
33992			
33993			if ( i === end ) {
33994				record = false;
33995				return true;
33996			}
33997
33998			return record;
33999		} );
34000	};
34001
34002	if ( ! dt.cells( { selected: true } ).any() && ! last ) {
34003		// select from the top left cell to this one
34004		columnIndexes = selectColumns( 0, idx.column );
34005		rowIndexes = selectRows( 0 , idx.row );
34006	}
34007	else {
34008		// Get column indexes between old and new
34009		columnIndexes = selectColumns( last.column, idx.column );
34010		rowIndexes = selectRows( last.row , idx.row );
34011	}
34012
34013	indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
34014
34015	if ( ! dt.cells( idx, { selected: true } ).any() ) {
34016		// Select range
34017		dt.cells( indexes ).select();
34018	}
34019	else {
34020		// Deselect range
34021		dt.cells( indexes ).deselect();
34022	}
34023}
34024
34025/**
34026 * Disable mouse selection by removing the selectors
34027 *
34028 * @param {DataTable.Api} dt DataTable to remove events from
34029 * @private
34030 */
34031function disableMouseSelection( dt )
34032{
34033	var ctx = dt.settings()[0];
34034	var selector = ctx._select.selector;
34035
34036	$( dt.table().container() )
34037		.off( 'mousedown.dtSelect', selector )
34038		.off( 'mouseup.dtSelect', selector )
34039		.off( 'click.dtSelect', selector );
34040
34041	$('body').off( 'click.dtSelect' + dt.table().node().id );
34042}
34043
34044/**
34045 * Attach mouse listeners to the table to allow mouse selection of items
34046 *
34047 * @param {DataTable.Api} dt DataTable to remove events from
34048 * @private
34049 */
34050function enableMouseSelection ( dt )
34051{
34052	var container = $( dt.table().container() );
34053	var ctx = dt.settings()[0];
34054	var selector = ctx._select.selector;
34055	var matchSelection;
34056
34057	container
34058		.on( 'mousedown.dtSelect', selector, function(e) {
34059			// Disallow text selection for shift clicking on the table so multi
34060			// element selection doesn't look terrible!
34061			if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
34062				container
34063					.css( '-moz-user-select', 'none' )
34064					.one('selectstart.dtSelect', selector, function () {
34065						return false;
34066					} );
34067			}
34068
34069			if ( window.getSelection ) {
34070				matchSelection = window.getSelection();
34071			}
34072		} )
34073		.on( 'mouseup.dtSelect', selector, function() {
34074			// Allow text selection to occur again, Mozilla style (tested in FF
34075			// 35.0.1 - still required)
34076			container.css( '-moz-user-select', '' );
34077		} )
34078		.on( 'click.dtSelect', selector, function ( e ) {
34079			var items = dt.select.items();
34080			var idx;
34081
34082			// If text was selected (click and drag), then we shouldn't change
34083			// the row's selected state
34084			if ( window.getSelection ) {
34085				var selection = window.getSelection();
34086
34087				// If the element that contains the selection is not in the table, we can ignore it
34088				// This can happen if the developer selects text from the click event
34089				if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
34090					if ( selection !== matchSelection ) {
34091						return;
34092					}
34093				}
34094			}
34095
34096			var ctx = dt.settings()[0];
34097			var wrapperClass = dt.settings()[0].oClasses.sWrapper.replace(/ /g, '.');
34098
34099			// Ignore clicks inside a sub-table
34100			if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {
34101				return;
34102			}
34103
34104			var cell = dt.cell( $(e.target).closest('td, th') );
34105
34106			// Check the cell actually belongs to the host DataTable (so child
34107			// rows, etc, are ignored)
34108			if ( ! cell.any() ) {
34109				return;
34110			}
34111
34112			var event = $.Event('user-select.dt');
34113			eventTrigger( dt, event, [ items, cell, e ] );
34114
34115			if ( event.isDefaultPrevented() ) {
34116				return;
34117			}
34118
34119			var cellIndex = cell.index();
34120			if ( items === 'row' ) {
34121				idx = cellIndex.row;
34122				typeSelect( e, dt, ctx, 'row', idx );
34123			}
34124			else if ( items === 'column' ) {
34125				idx = cell.index().column;
34126				typeSelect( e, dt, ctx, 'column', idx );
34127			}
34128			else if ( items === 'cell' ) {
34129				idx = cell.index();
34130				typeSelect( e, dt, ctx, 'cell', idx );
34131			}
34132
34133			ctx._select_lastCell = cellIndex;
34134		} );
34135
34136	// Blurable
34137	$('body').on( 'click.dtSelect' + dt.table().node().id, function ( e ) {
34138		if ( ctx._select.blurable ) {
34139			// If the click was inside the DataTables container, don't blur
34140			if ( $(e.target).parents().filter( dt.table().container() ).length ) {
34141				return;
34142			}
34143
34144			// Ignore elements which have been removed from the DOM (i.e. paging
34145			// buttons)
34146			if ( $(e.target).parents('html').length === 0 ) {
34147			 	return;
34148			}
34149
34150			// Don't blur in Editor form
34151			if ( $(e.target).parents('div.DTE').length ) {
34152				return;
34153			}
34154
34155			clear( ctx, true );
34156		}
34157	} );
34158}
34159
34160/**
34161 * Trigger an event on a DataTable
34162 *
34163 * @param {DataTable.Api} api      DataTable to trigger events on
34164 * @param  {boolean}      selected true if selected, false if deselected
34165 * @param  {string}       type     Item type acting on
34166 * @param  {boolean}      any      Require that there are values before
34167 *     triggering
34168 * @private
34169 */
34170function eventTrigger ( api, type, args, any )
34171{
34172	if ( any && ! api.flatten().length ) {
34173		return;
34174	}
34175
34176	if ( typeof type === 'string' ) {
34177		type = type +'.dt';
34178	}
34179
34180	args.unshift( api );
34181
34182	$(api.table().node()).trigger( type, args );
34183}
34184
34185/**
34186 * Update the information element of the DataTable showing information about the
34187 * items selected. This is done by adding tags to the existing text
34188 * 
34189 * @param {DataTable.Api} api DataTable to update
34190 * @private
34191 */
34192function info ( api )
34193{
34194	var ctx = api.settings()[0];
34195
34196	if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
34197		return;
34198	}
34199
34200	if ( api.select.style() === 'api' ) {
34201		return;
34202	}
34203
34204	var rows    = api.rows( { selected: true } ).flatten().length;
34205	var columns = api.columns( { selected: true } ).flatten().length;
34206	var cells   = api.cells( { selected: true } ).flatten().length;
34207
34208	var add = function ( el, name, num ) {
34209		el.append( $('<span class="select-item"/>').append( api.i18n(
34210			'select.'+name+'s',
34211			{ _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
34212			num
34213		) ) );
34214	};
34215
34216	// Internal knowledge of DataTables to loop over all information elements
34217	$.each( ctx.aanFeatures.i, function ( i, el ) {
34218		el = $(el);
34219
34220		var output  = $('<span class="select-info"/>');
34221		add( output, 'row', rows );
34222		add( output, 'column', columns );
34223		add( output, 'cell', cells  );
34224
34225		var exisiting = el.children('span.select-info');
34226		if ( exisiting.length ) {
34227			exisiting.remove();
34228		}
34229
34230		if ( output.text() !== '' ) {
34231			el.append( output );
34232		}
34233	} );
34234}
34235
34236/**
34237 * Initialisation of a new table. Attach event handlers and callbacks to allow
34238 * Select to operate correctly.
34239 *
34240 * This will occur _after_ the initial DataTables initialisation, although
34241 * before Ajax data is rendered, if there is ajax data
34242 *
34243 * @param  {DataTable.settings} ctx Settings object to operate on
34244 * @private
34245 */
34246function init ( ctx ) {
34247	var api = new DataTable.Api( ctx );
34248
34249	// Row callback so that classes can be added to rows and cells if the item
34250	// was selected before the element was created. This will happen with the
34251	// `deferRender` option enabled.
34252	// 
34253	// This method of attaching to `aoRowCreatedCallback` is a hack until
34254	// DataTables has proper events for row manipulation If you are reviewing
34255	// this code to create your own plug-ins, please do not do this!
34256	ctx.aoRowCreatedCallback.push( {
34257		fn: function ( row, data, index ) {
34258			var i, ien;
34259			var d = ctx.aoData[ index ];
34260
34261			// Row
34262			if ( d._select_selected ) {
34263				$( row ).addClass( ctx._select.className );
34264			}
34265
34266			// Cells and columns - if separated out, we would need to do two
34267			// loops, so it makes sense to combine them into a single one
34268			for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
34269				if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
34270					$(d.anCells[i]).addClass( ctx._select.className );
34271				}
34272			}
34273		},
34274		sName: 'select-deferRender'
34275	} );
34276
34277	// On Ajax reload we want to reselect all rows which are currently selected,
34278	// if there is an rowId (i.e. a unique value to identify each row with)
34279	api.on( 'preXhr.dt.dtSelect', function () {
34280		// note that column selection doesn't need to be cached and then
34281		// reselected, as they are already selected
34282		var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
34283			return d !== undefined;
34284		} );
34285
34286		var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
34287			var id = api.row( cellIdx.row ).id( true );
34288			return id ?
34289				{ row: id, column: cellIdx.column } :
34290				undefined;
34291		} ).filter( function ( d ) {
34292			return d !== undefined;
34293		} );
34294
34295		// On the next draw, reselect the currently selected items
34296		api.one( 'draw.dt.dtSelect', function () {
34297			api.rows( rows ).select();
34298
34299			// `cells` is not a cell index selector, so it needs a loop
34300			if ( cells.any() ) {
34301				cells.each( function ( id ) {
34302					api.cells( id.row, id.column ).select();
34303				} );
34304			}
34305		} );
34306	} );
34307
34308	// Update the table information element with selected item summary
34309	api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
34310		info( api );
34311	} );
34312
34313	// Clean up and release
34314	api.on( 'destroy.dtSelect', function () {
34315		disableMouseSelection( api );
34316		api.off( '.dtSelect' );
34317	} );
34318}
34319
34320/**
34321 * Add one or more items (rows or columns) to the selection when shift clicking
34322 * in OS selection style
34323 *
34324 * @param  {DataTable.Api} dt   DataTable
34325 * @param  {string}        type Row or column range selector
34326 * @param  {object}        idx  Item index to select to
34327 * @param  {object}        last Item index to select from
34328 * @private
34329 */
34330function rowColumnRange( dt, type, idx, last )
34331{
34332	// Add a range of rows from the last selected row to this one
34333	var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
34334	var idx1 = $.inArray( last, indexes );
34335	var idx2 = $.inArray( idx, indexes );
34336
34337	if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
34338		// select from top to here - slightly odd, but both Windows and Mac OS
34339		// do this
34340		indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
34341	}
34342	else {
34343		// reverse so we can shift click 'up' as well as down
34344		if ( idx1 > idx2 ) {
34345			var tmp = idx2;
34346			idx2 = idx1;
34347			idx1 = tmp;
34348		}
34349
34350		indexes.splice( idx2+1, indexes.length );
34351		indexes.splice( 0, idx1 );
34352	}
34353
34354	if ( ! dt[type]( idx, { selected: true } ).any() ) {
34355		// Select range
34356		dt[type+'s']( indexes ).select();
34357	}
34358	else {
34359		// Deselect range - need to keep the clicked on row selected
34360		indexes.splice( $.inArray( idx, indexes ), 1 );
34361		dt[type+'s']( indexes ).deselect();
34362	}
34363}
34364
34365/**
34366 * Clear all selected items
34367 *
34368 * @param  {DataTable.settings} ctx Settings object of the host DataTable
34369 * @param  {boolean} [force=false] Force the de-selection to happen, regardless
34370 *     of selection style
34371 * @private
34372 */
34373function clear( ctx, force )
34374{
34375	if ( force || ctx._select.style === 'single' ) {
34376		var api = new DataTable.Api( ctx );
34377		
34378		api.rows( { selected: true } ).deselect();
34379		api.columns( { selected: true } ).deselect();
34380		api.cells( { selected: true } ).deselect();
34381	}
34382}
34383
34384/**
34385 * Select items based on the current configuration for style and items.
34386 *
34387 * @param  {object}             e    Mouse event object
34388 * @param  {DataTables.Api}     dt   DataTable
34389 * @param  {DataTable.settings} ctx  Settings object of the host DataTable
34390 * @param  {string}             type Items to select
34391 * @param  {int|object}         idx  Index of the item to select
34392 * @private
34393 */
34394function typeSelect ( e, dt, ctx, type, idx )
34395{
34396	var style = dt.select.style();
34397	var isSelected = dt[type]( idx, { selected: true } ).any();
34398
34399	if ( style === 'os' ) {
34400		if ( e.ctrlKey || e.metaKey ) {
34401			// Add or remove from the selection
34402			dt[type]( idx ).select( ! isSelected );
34403		}
34404		else if ( e.shiftKey ) {
34405			if ( type === 'cell' ) {
34406				cellRange( dt, idx, ctx._select_lastCell || null );
34407			}
34408			else {
34409				rowColumnRange( dt, type, idx, ctx._select_lastCell ?
34410					ctx._select_lastCell[type] :
34411					null
34412				);
34413			}
34414		}
34415		else {
34416			// No cmd or shift click - deselect if selected, or select
34417			// this row only
34418			var selected = dt[type+'s']( { selected: true } );
34419
34420			if ( isSelected && selected.flatten().length === 1 ) {
34421				dt[type]( idx ).deselect();
34422			}
34423			else {
34424				selected.deselect();
34425				dt[type]( idx ).select();
34426			}
34427		}
34428	} else if ( style == 'multi+shift' ) {
34429		if ( e.shiftKey ) {
34430			if ( type === 'cell' ) {
34431				cellRange( dt, idx, ctx._select_lastCell || null );
34432			}
34433			else {
34434				rowColumnRange( dt, type, idx, ctx._select_lastCell ?
34435					ctx._select_lastCell[type] :
34436					null
34437				);
34438			}
34439		}
34440		else {
34441			dt[ type ]( idx ).select( ! isSelected );
34442		}
34443	}
34444	else {
34445		dt[ type ]( idx ).select( ! isSelected );
34446	}
34447}
34448
34449
34450
34451/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
34452 * DataTables selectors
34453 */
34454
34455// row and column are basically identical just assigned to different properties
34456// and checking a different array, so we can dynamically create the functions to
34457// reduce the code size
34458$.each( [
34459	{ type: 'row', prop: 'aoData' },
34460	{ type: 'column', prop: 'aoColumns' }
34461], function ( i, o ) {
34462	DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
34463		var selected = opts.selected;
34464		var data;
34465		var out = [];
34466
34467		if ( selected !== true && selected !== false ) {
34468			return indexes;
34469		}
34470
34471		for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
34472			data = settings[ o.prop ][ indexes[i] ];
34473
34474			if ( (selected === true && data._select_selected === true) ||
34475			     (selected === false && ! data._select_selected )
34476			) {
34477				out.push( indexes[i] );
34478			}
34479		}
34480
34481		return out;
34482	} );
34483} );
34484
34485DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
34486	var selected = opts.selected;
34487	var rowData;
34488	var out = [];
34489
34490	if ( selected === undefined ) {
34491		return cells;
34492	}
34493
34494	for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
34495		rowData = settings.aoData[ cells[i].row ];
34496
34497		if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
34498		     (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
34499		) {
34500			out.push( cells[i] );
34501		}
34502	}
34503
34504	return out;
34505} );
34506
34507
34508
34509/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
34510 * DataTables API
34511 *
34512 * For complete documentation, please refer to the docs/api directory or the
34513 * DataTables site
34514 */
34515
34516// Local variables to improve compression
34517var apiRegister = DataTable.Api.register;
34518var apiRegisterPlural = DataTable.Api.registerPlural;
34519
34520apiRegister( 'select()', function () {
34521	return this.iterator( 'table', function ( ctx ) {
34522		DataTable.select.init( new DataTable.Api( ctx ) );
34523	} );
34524} );
34525
34526apiRegister( 'select.blurable()', function ( flag ) {
34527	if ( flag === undefined ) {
34528		return this.context[0]._select.blurable;
34529	}
34530
34531	return this.iterator( 'table', function ( ctx ) {
34532		ctx._select.blurable = flag;
34533	} );
34534} );
34535
34536apiRegister( 'select.info()', function ( flag ) {
34537	if ( info === undefined ) {
34538		return this.context[0]._select.info;
34539	}
34540
34541	return this.iterator( 'table', function ( ctx ) {
34542		ctx._select.info = flag;
34543	} );
34544} );
34545
34546apiRegister( 'select.items()', function ( items ) {
34547	if ( items === undefined ) {
34548		return this.context[0]._select.items;
34549	}
34550
34551	return this.iterator( 'table', function ( ctx ) {
34552		ctx._select.items = items;
34553
34554		eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
34555	} );
34556} );
34557
34558// Takes effect from the _next_ selection. None disables future selection, but
34559// does not clear the current selection. Use the `deselect` methods for that
34560apiRegister( 'select.style()', function ( style ) {
34561	if ( style === undefined ) {
34562		return this.context[0]._select.style;
34563	}
34564
34565	return this.iterator( 'table', function ( ctx ) {
34566		ctx._select.style = style;
34567
34568		if ( ! ctx._select_init ) {
34569			init( ctx );
34570		}
34571
34572		// Add / remove mouse event handlers. They aren't required when only
34573		// API selection is available
34574		var dt = new DataTable.Api( ctx );
34575		disableMouseSelection( dt );
34576		
34577		if ( style !== 'api' ) {
34578			enableMouseSelection( dt );
34579		}
34580
34581		eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
34582	} );
34583} );
34584
34585apiRegister( 'select.selector()', function ( selector ) {
34586	if ( selector === undefined ) {
34587		return this.context[0]._select.selector;
34588	}
34589
34590	return this.iterator( 'table', function ( ctx ) {
34591		disableMouseSelection( new DataTable.Api( ctx ) );
34592
34593		ctx._select.selector = selector;
34594
34595		if ( ctx._select.style !== 'api' ) {
34596			enableMouseSelection( new DataTable.Api( ctx ) );
34597		}
34598	} );
34599} );
34600
34601
34602
34603apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
34604	var api = this;
34605
34606	if ( select === false ) {
34607		return this.deselect();
34608	}
34609
34610	this.iterator( 'row', function ( ctx, idx ) {
34611		clear( ctx );
34612
34613		ctx.aoData[ idx ]._select_selected = true;
34614		$( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
34615	} );
34616
34617	this.iterator( 'table', function ( ctx, i ) {
34618		eventTrigger( api, 'select', [ 'row', api[i] ], true );
34619	} );
34620
34621	return this;
34622} );
34623
34624apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
34625	var api = this;
34626
34627	if ( select === false ) {
34628		return this.deselect();
34629	}
34630
34631	this.iterator( 'column', function ( ctx, idx ) {
34632		clear( ctx );
34633
34634		ctx.aoColumns[ idx ]._select_selected = true;
34635
34636		var column = new DataTable.Api( ctx ).column( idx );
34637
34638		$( column.header() ).addClass( ctx._select.className );
34639		$( column.footer() ).addClass( ctx._select.className );
34640
34641		column.nodes().to$().addClass( ctx._select.className );
34642	} );
34643
34644	this.iterator( 'table', function ( ctx, i ) {
34645		eventTrigger( api, 'select', [ 'column', api[i] ], true );
34646	} );
34647
34648	return this;
34649} );
34650
34651apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
34652	var api = this;
34653
34654	if ( select === false ) {
34655		return this.deselect();
34656	}
34657
34658	this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
34659		clear( ctx );
34660
34661		var data = ctx.aoData[ rowIdx ];
34662
34663		if ( data._selected_cells === undefined ) {
34664			data._selected_cells = [];
34665		}
34666
34667		data._selected_cells[ colIdx ] = true;
34668
34669		if ( data.anCells ) {
34670			$( data.anCells[ colIdx ] ).addClass( ctx._select.className );
34671		}
34672	} );
34673
34674	this.iterator( 'table', function ( ctx, i ) {
34675		eventTrigger( api, 'select', [ 'cell', api[i] ], true );
34676	} );
34677
34678	return this;
34679} );
34680
34681
34682apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
34683	var api = this;
34684
34685	this.iterator( 'row', function ( ctx, idx ) {
34686		ctx.aoData[ idx ]._select_selected = false;
34687		$( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
34688	} );
34689
34690	this.iterator( 'table', function ( ctx, i ) {
34691		eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
34692	} );
34693
34694	return this;
34695} );
34696
34697apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
34698	var api = this;
34699
34700	this.iterator( 'column', function ( ctx, idx ) {
34701		ctx.aoColumns[ idx ]._select_selected = false;
34702
34703		var api = new DataTable.Api( ctx );
34704		var column = api.column( idx );
34705
34706		$( column.header() ).removeClass( ctx._select.className );
34707		$( column.footer() ).removeClass( ctx._select.className );
34708
34709		// Need to loop over each cell, rather than just using
34710		// `column().nodes()` as cells which are individually selected should
34711		// not have the `selected` class removed from them
34712		api.cells( null, idx ).indexes().each( function (cellIdx) {
34713			var data = ctx.aoData[ cellIdx.row ];
34714			var cellSelected = data._selected_cells;
34715
34716			if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
34717				$( data.anCells[ cellIdx.column  ] ).removeClass( ctx._select.className );
34718			}
34719		} );
34720	} );
34721
34722	this.iterator( 'table', function ( ctx, i ) {
34723		eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
34724	} );
34725
34726	return this;
34727} );
34728
34729apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
34730	var api = this;
34731
34732	this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
34733		var data = ctx.aoData[ rowIdx ];
34734
34735		data._selected_cells[ colIdx ] = false;
34736
34737		// Remove class only if the cells exist, and the cell is not column
34738		// selected, in which case the class should remain (since it is selected
34739		// in the column)
34740		if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
34741			$( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
34742		}
34743	} );
34744
34745	this.iterator( 'table', function ( ctx, i ) {
34746		eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
34747	} );
34748
34749	return this;
34750} );
34751
34752
34753
34754/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
34755 * Buttons
34756 */
34757function i18n( label, def ) {
34758	return function (dt) {
34759		return dt.i18n( 'buttons.'+label, def );
34760	};
34761}
34762
34763// Common events with suitable namespaces
34764function namespacedEvents ( config ) {
34765	var unique = config._eventNamespace;
34766
34767	return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
34768}
34769
34770function enabled ( dt, config ) {
34771	if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {
34772		return true;
34773	}
34774
34775	if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {
34776		return true;
34777	}
34778
34779	if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {
34780		return true;
34781	}
34782
34783	return false;
34784}
34785
34786var _buttonNamespace = 0;
34787
34788$.extend( DataTable.ext.buttons, {
34789	selected: {
34790		text: i18n( 'selected', 'Selected' ),
34791		className: 'buttons-selected',
34792		limitTo: [ 'rows', 'columns', 'cells' ],
34793		init: function ( dt, node, config ) {
34794			var that = this;
34795			config._eventNamespace = '.select'+(_buttonNamespace++);
34796
34797			// .DT namespace listeners are removed by DataTables automatically
34798			// on table destroy
34799			dt.on( namespacedEvents(config), function () {
34800				that.enable( enabled(dt, config) );
34801			} );
34802
34803			this.disable();
34804		},
34805		destroy: function ( dt, node, config ) {
34806			dt.off( config._eventNamespace );
34807		}
34808	},
34809	selectedSingle: {
34810		text: i18n( 'selectedSingle', 'Selected single' ),
34811		className: 'buttons-selected-single',
34812		init: function ( dt, node, config ) {
34813			var that = this;
34814			config._eventNamespace = '.select'+(_buttonNamespace++);
34815
34816			dt.on( namespacedEvents(config), function () {
34817				var count = dt.rows( { selected: true } ).flatten().length +
34818				            dt.columns( { selected: true } ).flatten().length +
34819				            dt.cells( { selected: true } ).flatten().length;
34820
34821				that.enable( count === 1 );
34822			} );
34823
34824			this.disable();
34825		},
34826		destroy: function ( dt, node, config ) {
34827			dt.off( config._eventNamespace );
34828		}
34829	},
34830	selectAll: {
34831		text: i18n( 'selectAll', 'Select all' ),
34832		className: 'buttons-select-all',
34833		action: function () {
34834			var items = this.select.items();
34835			this[ items+'s' ]().select();
34836		}
34837	},
34838	selectNone: {
34839		text: i18n( 'selectNone', 'Deselect all' ),
34840		className: 'buttons-select-none',
34841		action: function () {
34842			clear( this.settings()[0], true );
34843		},
34844		init: function ( dt, node, config ) {
34845			var that = this;
34846			config._eventNamespace = '.select'+(_buttonNamespace++);
34847
34848			dt.on( namespacedEvents(config), function () {
34849				var count = dt.rows( { selected: true } ).flatten().length +
34850				            dt.columns( { selected: true } ).flatten().length +
34851				            dt.cells( { selected: true } ).flatten().length;
34852
34853				that.enable( count > 0 );
34854			} );
34855
34856			this.disable();
34857		},
34858		destroy: function ( dt, node, config ) {
34859			dt.off( config._eventNamespace );
34860		}
34861	}
34862} );
34863
34864$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
34865	var lc = item.toLowerCase();
34866
34867	DataTable.ext.buttons[ 'select'+item+'s' ] = {
34868		text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
34869		className: 'buttons-select-'+lc+'s',
34870		action: function () {
34871			this.select.items( lc );
34872		},
34873		init: function ( dt ) {
34874			var that = this;
34875
34876			dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
34877				that.active( items === lc );
34878			} );
34879		}
34880	};
34881} );
34882
34883
34884
34885/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
34886 * Initialisation
34887 */
34888
34889// DataTables creation - check if select has been defined in the options. Note
34890// this required that the table be in the document! If it isn't then something
34891// needs to trigger this method unfortunately. The next major release of
34892// DataTables will rework the events and address this.
34893$(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
34894	if ( e.namespace !== 'dt' ) {
34895		return;
34896	}
34897
34898	DataTable.select.init( new DataTable.Api( ctx ) );
34899} );
34900
34901
34902return DataTable.select;
34903}));
34904
34905

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.