PageSourceSearch

https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Java…/global.js?v=5&nn=6942652c85ec843c18743a51

js reach-clp-biozid-helpdesk.de collected 2026-10-02 06:17:26 UTC 1,375,457 bytes, 44,197 lines download raw bytes

1var gsb = gsb || {};
2  /* Start variables_LABELS */
3      var PRINT_PAGE_TEXT = 'drucken';
4    var PRINT_TOOLTIP = 'Seite drucken (öffnet Dialog)';
5    var PRINT_BUTTON_TEXT = 'Datenblatt drucken';
6    var PRINT_BUTTON_TOOLTIP = 'Datenblatt drucken (öffnet Dialog)';
7    var TWOCLICKSHARE_TITLE = 'Inhalte teilen';
8    var TWOCLICKSHARE_FORMLINKTEXT = 'Freunden per E-Mail schicken';
9    var NAV_MOBILE_MENU = 'Menü';
10    var NAV_MOBILE_SEARCH = 'Suchen';
11    var SHOW_LESS = 'Weniger anzeigen';
12    var SHOW_MORE = 'Mehr anzeigen';
13    var SHOW_LESS_ARTICLE = 'Schließen';
14    var SHOW_MORE_ARTICLE = 'weiterlesen';
15    var CLOSE = 'Schließen';
16    var NEXT = 'Nächste Seite';
17    var BACK = 'Vorherige Seite';
18    var NEXT_INACTIVE = 'Keine nächste Seite';
19    var BACK_INACTIVE = 'Keine vorherige Seite';
20    var PLAY = 'Animation starten';
21    var PAUSE = 'Animation stoppen';
22    var PAGE = 'Seite';
23    var MOBILE_AURAL = 'Mobiles Menü';
24    var FIRST_BACK = 'zurück';
25    var BACK_BUTTON = 'zurück';
26    var BACKTOFIRST_BUTTON = 'zurück zu';
27    var HIDE_TD = 'Spalte ausblenden';
28    var PAGELINK = 'Zur Übersicht';
29    var DATEPICKER_TEXT = 'Datum auswählen';
30
31  /* Ende variables_LABELS */
32  /* Start variables_IMG */
33      var image_url_next = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/forward_active.svg?__blob=normal&v=1';
34    var image_url_back = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/back_active.svg?__blob=normal&v=1';
35    var image_url_back_g = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/back_inactive.svg?__blob=normal&v=1';
36    var image_url_next_g = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/forward_inactive.svg?__blob=normal&v=1';
37    var image_url_paused = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/pause.png?__blob=normal&v=1';
38    var image_url_play = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/play.svg?__blob=normal&v=1';
39    var image_url_mobile_back_button = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/navigation_back.svg?__blob=normal&v=1';
40    var image_url_mobile_backtofirst_button = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/navigation_backtofirst.svg?__blob=normal&v=1';
41    var image_url_hide_td = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/hide_td.svg?__blob=normal&v=1';
42    var image_url_calendar = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/calendar.svg?__blob=normal&v=1';
43    var image_url_logo_scrolled = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/logo-ohneuntertitel.svg?__blob=normal&v=1';
44    var image_url_mejs_controls = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/mediaelement/mejs-controls.svg?__blob=normal&v=2';
45
46  /* Ende variables_IMG */
47  /* Start variables_JSON */
48     var json_url_mobileMenu = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Modules/MobileNavigation/DE/MobileNavigation?view=renderMobileNavigation';
49   var json_url_mobileSearch = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Forms/Suche/DE/Servicesuche_Autosuggest_Formular?view=renderJSON';
50
51  /* Ende variables_JSON */
52gsb.jsComponents = {
53     config: {},
54     definitions: {
55       bundle_multimedia: {
56         scriptList: [ 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/JavaScript/init/bundle_multimedia.js?v=2' ]
57       },
58    }
59};
60   /* Start custom.modernizr */
61   /*! Modernizr 2.6.2 (Custom Build) | MIT & BSD
62 * Build: http://modernizr.com/download/#-inlinesvg-svg-svgclippaths-touch-shiv-mq-cssclasses-teststyles-prefixes-ie8compat-load
63 */
64;
65window.Modernizr = function(a, b, c) {
66        function y(a) {
67            j.cssText = a
68        }
69
70        function z(a, b) {
71            return y(m.join(a + ";") + (b || ""))
72        }
73
74        function A(a, b) {
75            return typeof a === b
76        }
77
78        function B(a, b) {
vendor: 6,574 bytes, lines 79-215
79            return !!~("" + a).indexOf(b)
80        }
81
82        function C(a, b, d) {
83            for (var e in a) {
84                var f = b[a[e]];
85                if (f !== c) return d === !1 ? a[e] : A(f, "function") ? f.bind(d || b) : f
86            }
87            return !1
88        }
89        var d = "2.6.2",
90            e = {},
91            f = !0,
92            g = b.documentElement,
93            h = "modernizr",
94            i = b.createElement(h),
95            j = i.style,
96            k, l = {}.toString,
97            m = " -webkit- -moz- -o- -ms- ".split(" "),
98            n = {
99                svg: "http://www.w3.org/2000/svg"
100            },
101            o = {},
102            p = {},
103            q = {},
104            r = [],
105            s = r.slice,
106            t, u = function(a, c, d, e) {
107                var f, i, j, k, l = b.createElement("div"),
108                    m = b.body,
109                    n = m || b.createElement("body");
110                if (parseInt(d, 10))
111                    while (d--) j = b.createElement("div"), j.id = e ? e[d] : h + (d + 1), l.appendChild(j);
112                return f = ["&#173;", '<style id="s', h, '">', a, "</style>"].join(""), l.id = h, (m ? l : n).innerHTML += f, n.appendChild(l), m || (n.style.background = "", n.style.overflow = "hidden", k = g.style.overflow, g.style.overflow = "hidden", g.appendChild(n)), i = c(l, a), m ? l.parentNode.removeChild(l) : (n.parentNode.removeChild(n), g.style.overflow = k), !!i
113            },
114            v = function(b) {
115                var c = a.matchMedia || a.msMatchMedia;
116                if (c) return c(b).matches;
117                var d;
118                return u("@media " + b + " { #" + h + " { position: absolute; } }", function(b) {
119                    d = (a.getComputedStyle ? getComputedStyle(b, null) : b.currentStyle)["position"] == "absolute"
120                }), d
121            },
122            w = {}.hasOwnProperty,
123            x;
124        !A(w, "undefined") && !A(w.call, "undefined") ? x = function(a, b) {
125            return w.call(a, b)
126        } : x = function(a, b) {
127            return b in a && A(a.constructor.prototype[b], "undefined")
128        }, Function.prototype.bind || (Function.prototype.bind = function(b) {
129            var c = this;
130            if (typeof c != "function") throw new TypeError;
131            var d = s.call(arguments, 1),
132                e = function() {
133                    if (this instanceof e) {
134                        var a = function() {};
135                        a.prototype = c.prototype;
136                        var f = new a,
137                            g = c.apply(f, d.concat(s.call(arguments)));
138                        return Object(g) === g ? g : f
139                    }
140                    return c.apply(b, d.concat(s.call(arguments)))
141                };
142            return e
143        }), o.touch = function() {
144            var c;
145            return "ontouchstart" in a || a.DocumentTouch && b instanceof DocumentTouch ? c = !0 : u(["@media (", m.join("touch-enabled),("), h, ")", "{#modernizr{top:9px;position:absolute}}"].join(""), function(a) {
146                c = a.offsetTop === 9
147            }), c
148        }, o.svg = function() {
149            return !!b.createElementNS && !!b.createElementNS(n.svg, "svg").createSVGRect
150        }, o.inlinesvg = function() {
151            var a = b.createElement("div");
152            return a.innerHTML = "<svg/>", (a.firstChild && a.firstChild.namespaceURI) == n.svg
153        }, o.svgclippaths = function() {
154            return !!b.createElementNS && /SVGClipPath/.test(l.call(b.createElementNS(n.svg, "clipPath")))
155        };
156        for (var D in o) x(o, D) && (t = D.toLowerCase(), e[t] = o[D](), r.push((e[t] ? "" : "no-") + t));
157        return e.addTest = function(a, b) {
158                if (typeof a == "object")
159                    for (var d in a) x(a, d) && e.addTest(d, a[d]);
160                else {
161                    a = a.toLowerCase();
162                    if (e[a] !== c) return e;
163                    b = typeof b == "function" ? b() : b, typeof f != "undefined" && f && (g.className += " " + (b ? "" : "no-") + a), e[a] = b
164                }
165                return e
166            }, y(""), i = k = null,
167            function(a, b) {
168                function k(a, b) {
169                    var c = a.createElement("p"),
170                        d = a.getElementsByTagName("head")[0] || a.documentElement;
171                    return c.innerHTML = "x<style>" + b + "</style>", d.insertBefore(c.lastChild, d.firstChild)
172                }
173
174                function l() {
175                    var a = r.elements;
176                    return typeof a == "string" ? a.split(" ") : a
177                }
178
179                function m(a) {
180                    var b = i[a[g]];
181                    return b || (b = {}, h++, a[g] = h, i[h] = b), b
182                }
183
184                function n(a, c, f) {
185                    c || (c = b);
186                    if (j) return c.createElement(a);
187                    f || (f = m(c));
188                    var g;
189                    return f.cache[a] ? g = f.cache[a].cloneNode() : e.test(a) ? g = (f.cache[a] = f.createElem(a)).cloneNode() : g = f.createElem(a), g.canHaveChildren && !d.test(a) ? f.frag.appendChild(g) : g
190                }
191
192                function o(a, c) {
193                    a || (a = b);
194                    if (j) return a.createDocumentFragment();
195                    c = c || m(a);
196                    var d = c.frag.cloneNode(),
197                        e = 0,
198                        f = l(),
199                        g = f.length;
200                    for (; e < g; e++) d.createElement(f[e]);
201                    return d
202                }
203
204                function p(a, b) {
205                    b.cache || (b.cache = {}, b.createElem = a.createElement, b.createFrag = a.createDocumentFragment, b.frag = b.createFrag()), a.createElement = function(c) {
206                        return r.shivMethods ? n(c, a, b) : b.createElem(c)
207                    }, a.createDocumentFragment = Function("h,f", "return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&(" + l().join().replace(/\w+/g, function(a) {
208                        return b.createElem(a), b.frag.createElement(a), 'c("' + a + '")'
209                    }) + ");return n}")(r, b.frag)
210                }
211
212                function q(a) {
213                    a || (a = b);
214                    var c = m(a);
215                    return r.shivCSS && !f && !c.hasCSS && (c.hasCSS = !!k(a, "article,aside,figcaption,figure,footer,header,hgroup,nav,section{dis
vendor: 12,571 bytes, lines 215-544
215play:block}mark{background:#FF0;color:#000}")), j || p(a, c), a
216                }
217                var c = a.html5 || {},
218                    d = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,
219                    e = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,
220                    f, g = "_html5shiv",
221                    h = 0,
222                    i = {},
223                    j;
224                (function() {
225                    try {
226                        var a = b.createElement("a");
227                        a.innerHTML = "<xyz></xyz>", f = "hidden" in a, j = a.childNodes.length == 1 || function() {
228                            b.createElement("a");
229                            var a = b.createDocumentFragment();
230                            return typeof a.cloneNode == "undefined" || typeof a.createDocumentFragment == "undefined" || typeof a.createElement == "undefined"
231                        }()
232                    } catch (c) {
233                        f = !0, j = !0
234                    }
235                })();
236                var r = {
237                    elements: c.elements || "abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",
238                    shivCSS: c.shivCSS !== !1,
239                    supportsUnknownElements: j,
240                    shivMethods: c.shivMethods !== !1,
241                    type: "default",
242                    shivDocument: q,
243                    createElement: n,
244                    createDocumentFragment: o
245                };
246                a.html5 = r, q(b)
247            }(this, b), e._version = d, e._prefixes = m, e.mq = v, e.testStyles = u, g.className = g.className.replace(/(^|\s)no-js(\s|$)/, "$1$2") + (f ? " js " + r.join(" ") : ""), e
248    }(this, this.document),
249    function(a, b, c) {
250        function d(a) {
251            return "[object Function]" == o.call(a)
252        }
253
254        function e(a) {
255            return "string" == typeof a
256        }
257
258        function f() {}
259
260        function g(a) {
261            return !a || "loaded" == a || "complete" == a || "uninitialized" == a
262        }
263
264        function h() {
265            var a = p.shift();
266            q = 1, a ? a.t ? m(function() {
267                ("c" == a.t ? B.injectCss : B.injectJs)(a.s, 0, a.a, a.x, a.e, 1)
268            }, 0) : (a(), h()) : q = 0
269        }
270
271        function i(a, c, d, e, f, i, j) {
272            function k(b) {
273                if (!o && g(l.readyState) && (u.r = o = 1, !q && h(), l.onload = l.onreadystatechange = null, b)) {
274                    "img" != a && m(function() {
275                        t.removeChild(l)
276                    }, 50);
277                    for (var d in y[c]) y[c].hasOwnProperty(d) && y[c][d].onload()
278                }
279            }
280            var j = j || B.errorTimeout,
281                l = b.createElement(a),
282                o = 0,
283                r = 0,
284                u = {
285                    t: d,
286                    s: c,
287                    e: f,
288                    a: i,
289                    x: j
290                };
291            1 === y[c] && (r = 1, y[c] = []), "object" == a ? l.data = c : (l.src = c, l.type = a), l.width = l.height = "0", l.onerror = l.onload = l.onreadystatechange = function() {
292                k.call(this, r)
293            }, p.splice(e, 0, u), "img" != a && (r || 2 === y[c] ? (t.insertBefore(l, s ? null : n), m(k, j)) : y[c].push(l))
294        }
295
296        function j(a, b, c, d, f) {
297            return q = 0, b = b || "j", e(a) ? i("c" == b ? v : u, a, b, this.i++, c, d, f) : (p.splice(this.i++, 0, a), 1 == p.length && h()), this
298        }
299
300        function k() {
301            var a = B;
302            return a.loader = {
303                load: j,
304                i: 0
305            }, a
306        }
307        var l = b.documentElement,
308            m = a.setTimeout,
309            n = b.getElementsByTagName("script")[0],
310            o = {}.toString,
311            p = [],
312            q = 0,
313            r = "MozAppearance" in l.style,
314            s = r && !!b.createRange().compareNode,
315            t = s ? l : n.parentNode,
316            l = a.opera && "[object Opera]" == o.call(a.opera),
317            l = !!b.attachEvent && !l,
318            u = r ? "object" : l ? "script" : "img",
319            v = l ? "script" : u,
320            w = Array.isArray || function(a) {
321                return "[object Array]" == o.call(a)
322            },
323            x = [],
324            y = {},
325            z = {
326                timeout: function(a, b) {
327                    return b.length && (a.timeout = b[0]), a
328                }
329            },
330            A, B;
331        B = function(a) {
332            function b(a) {
333                var a = a.split("!"),
334                    b = x.length,
335                    c = a.pop(),
336                    d = a.length,
337                    c = {
338                        url: c,
339                        origUrl: c,
340                        prefixes: a
341                    },
342                    e, f, g;
343                for (f = 0; f < d; f++) g = a[f].split("="), (e = z[g.shift()]) && (c = e(c, g));
344                for (f = 0; f < b; f++) c = x[f](c);
345                return c
346            }
347
348            function g(a, e, f, g, h) {
349                var i = b(a),
350                    j = i.autoCallback;
351                i.url.split(".").pop().split("?").shift(), i.bypass || (e && (e = d(e) ? e : e[a] || e[g] || e[a.split("/").pop().split("?")[0]]), i.instead ? i.instead(a, e, f, g, h) : (y[i.url] ? i.noexec = !0 : y[i.url] = 1, f.load(i.url, i.forceCSS || !i.forceJS && "css" == i.url.split(".").pop().split("?").shift() ? "c" : c, i.noexec, i.attrs, i.timeout), (d(e) || d(j)) && f.load(function() {
352                    k(), e && e(i.origUrl, h, g), j && j(i.origUrl, h, g), y[i.url] = 2
353                })))
354            }
355
356            function h(a, b) {
357                function c(a, c) {
358                    if (a) {
359                        if (e(a)) c || (j = function() {
360                            var a = [].slice.call(arguments);
361                            k.apply(this, a), l()
362                        }), g(a, j, b, 0, h);
363                        else if (Object(a) === a)
364                            for (n in m = function() {
365                                    var b = 0,
366                                        c;
367                                    for (c in a) a.hasOwnProperty(c) && b++;
368                                    return b
369                                }(), a) a.hasOwnProperty(n) && (!c && !--m && (d(j) ? j = function() {
370                                var a = [].slice.call(arguments);
371                                k.apply(this, a), l()
372                            } : j[n] = function(a) {
373                                return function() {
374                                    var b = [].slice.call(arguments);
375                                    a && a.apply(this, b), l()
376                                }
377                            }(k[n])), g(a[n], j, b, n, h))
378                    } else !c && l()
379                }
380                var h = !!a.test,
381                    i = a.load || a.both,
382                    j = a.callback || f,
383                    k = j,
384                    l = a.complete || f,
385                    m, n;
386                c(h ? a.yep : a.nope, !!i), i && c(i)
387            }
388            var i, j, l = this.yepnope.loader;
389            if (e(a)) g(a, 0, l, 0);
390            else if (w(a))
391                for (i = 0; i < a.length; i++) j = a[i], e(j) ? g(j, 0, l, 0) : w(j) ? B(j) : Object(j) === j && h(j, l);
392            else Object(a) === a && h(a, l)
393        }, B.addPrefix = function(a, b) {
394            z[a] = b
395        }, B.addFilter = function(a) {
396            x.push(a)
397        }, B.errorTimeout = 1e4, null == b.readyState && b.addEventListener && (b.readyState = "loading", b.addEventListener("DOMContentLoaded", A = function() {
398            b.removeEventListener("DOMContentLoaded", A, 0), b.readyState = "complete"
399        }, 0)), a.yepnope = k(), a.yepnope.executeStack = h, a.yepnope.injectJs = function(a, c, d, e, i, j) {
400            var k = b.createElement("script"),
401                l, o, e = e || B.errorTimeout;
402            k.src = a;
403            for (o in d) k.setAttribute(o, d[o]);
404            c = j ? h : c || f, k.onreadystatechange = k.onload = function() {
405                !l && g(k.readyState) && (l = 1, c(), k.onload = k.onreadystatechange = null)
406            }, m(function() {
407                l || (l = 1, c(1))
408            }, e), i ? k.onload() : n.parentNode.insertBefore(k, n)
409        }, a.yepnope.injectCss = function(a, c, d, e, g, i) {
410            var e = b.createElement("link"),
411                j, c = i ? h : c || f;
412            e.href = a, e.rel = "stylesheet", e.type = "text/css";
413            for (j in d) e.setAttribute(j, d[j]);
414            g || (n.parentNode.insertBefore(e, n), m(c, 0))
415        }
416    }(this, document), Modernizr.load = function() {
417        yepnope.apply(window, [].slice.call(arguments, 0))
418    }, Modernizr.addTest("ie8compat", function() {
419        return !window.addEventListener && document.documentMode && document.documentMode === 7
420    });
421   /* Ende custom.modernizr */
422   /* Start jquery */
423   /*!
424 * jQuery JavaScript Library v1.11.1
425 * http://jquery.com/
426 *
427 * Includes Sizzle.js
428 * http://sizzlejs.com/
429 *
430 * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
431 * Released under the MIT license
432 * http://jquery.org/license
433 *
434 * Date: 2014-05-01T17:42Z
435 */
436
437(function( global, factory ) {
438
439 if ( typeof module === "object" && typeof module.exports === "object" ) {
440  // For CommonJS and CommonJS-like environments where a proper window is present,
441  // execute the factory and get jQuery
442  // For environments that do not inherently posses a window with a document
443  // (such as Node.js), expose a jQuery-making factory as module.exports
444  // This accentuates the need for the creation of a real window
445  // e.g. var jQuery = require("jquery")(window);
446  // See ticket #14549 for more info
447  module.exports = global.document ?
448   factory( global, true ) :
449   function( w ) {
450    if ( !w.document ) {
451     throw new Error( "jQuery requires a window with a document" );
452    }
453    return factory( w );
454   };
455 } else {
456  factory( global );
457 }
458
459// Pass this if window is not defined yet
460}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
461
462// Can't do this because several apps including ASP.NET trace
463// the stack via arguments.caller.callee and Firefox dies if
464// you try to trace through "use strict" call chains. (#13335)
465// Support: Firefox 18+
466//
467
468var deletedIds = [];
469
470var slice = deletedIds.slice;
471
472var concat = deletedIds.concat;
473
474var push = deletedIds.push;
475
476var indexOf = deletedIds.indexOf;
477
478var class2type = {};
479
480var toString = class2type.toString;
481
482var hasOwn = class2type.hasOwnProperty;
483
484var support = {};
485
486var
487 version = "1.11.1",
488
489 // Define a local copy of jQuery
490 jQuery = function( selector, context ) {
491  // The jQuery object is actually just the init constructor 'enhanced'
492  // Need init if jQuery is called (just allow error to be thrown if not included)
493  return new jQuery.fn.init( selector, context );
494 },
495
496 // Support: Android<4.1, IE<9
497 // Make sure we trim BOM and NBSP
498 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
499
500 // Matches dashed string for camelizing
501 rmsPrefix = /^-ms-/,
502 rdashAlpha = /-([\da-z])/gi,
503
504 // Used by jQuery.camelCase as callback to replace()
505 fcamelCase = function( all, letter ) {
506  return letter.toUpperCase();
507 };
508
509jQuery.fn = jQuery.prototype = {
510 // The current version of jQuery being used
511 jquery: version,
512
513 constructor: jQuery,
514
515 // Start with an empty selector
516 selector: "",
517
518 // The default length of a jQuery object is 0
519 length: 0,
520
521 toArray: function() {
522  return slice.call( this );
523 },
524
525 // Get the Nth element in the matched element set OR
526 // Get the whole matched element set as a clean array
527 get: function( num ) {
528  return num != null ?
529
530   // Return just the one element from the set
531   ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
532
533   // Return all the elements in a clean array
534   slice.call( this );
535 },
536
537 // Take an array of elements and push it onto the stack
538 // (returning the new matched element set)
539 pushStack: function( elems ) {
540
541  // Build a new jQuery matched element set
542  var ret = jQuery.merge( this.constructor(), elems );
543
544  // Add the old object onto the stack (as a reference)
vendor: 278,655 bytes, lines 545-10591
545  ret.prevObject = this;
546  ret.context = this.context;
547
548  // Return the newly-formed element set
549  return ret;
550 },
551
552 // Execute a callback for every element in the matched set.
553 // (You can seed the arguments with an array of args, but this is
554 // only used internally.)
555 each: function( callback, args ) {
556  return jQuery.each( this, callback, args );
557 },
558
559 map: function( callback ) {
560  return this.pushStack( jQuery.map(this, function( elem, i ) {
561   return callback.call( elem, i, elem );
562  }));
563 },
564
565 slice: function() {
566  return this.pushStack( slice.apply( this, arguments ) );
567 },
568
569 first: function() {
570  return this.eq( 0 );
571 },
572
573 last: function() {
574  return this.eq( -1 );
575 },
576
577 eq: function( i ) {
578  var len = this.length,
579   j = +i + ( i < 0 ? len : 0 );
580  return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
581 },
582
583 end: function() {
584  return this.prevObject || this.constructor(null);
585 },
586
587 // For internal use only.
588 // Behaves like an Array's method, not like a jQuery method.
589 push: push,
590 sort: deletedIds.sort,
591 splice: deletedIds.splice
592};
593
594jQuery.extend = jQuery.fn.extend = function() {
595 var src, copyIsArray, copy, name, options, clone,
596  target = arguments[0] || {},
597  i = 1,
598  length = arguments.length,
599  deep = false;
600
601 // Handle a deep copy situation
602 if ( typeof target === "boolean" ) {
603  deep = target;
604
605  // skip the boolean and the target
606  target = arguments[ i ] || {};
607  i++;
608 }
609
610 // Handle case when target is a string or something (possible in deep copy)
611 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
612  target = {};
613 }
614
615 // extend jQuery itself if only one argument is passed
616 if ( i === length ) {
617  target = this;
618  i--;
619 }
620
621 for ( ; i < length; i++ ) {
622  // Only deal with non-null/undefined values
623  if ( (options = arguments[ i ]) != null ) {
624   // Extend the base object
625   for ( name in options ) {
626    src = target[ name ];
627    copy = options[ name ];
628
629    // Prevent never-ending loop
630    if ( target === copy ) {
631     continue;
632    }
633
634    // Recurse if we're merging plain objects or arrays
635    if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
636     if ( copyIsArray ) {
637      copyIsArray = false;
638      clone = src && jQuery.isArray(src) ? src : [];
639
640     } else {
641      clone = src && jQuery.isPlainObject(src) ? src : {};
642     }
643
644     // Never move original objects, clone them
645     target[ name ] = jQuery.extend( deep, clone, copy );
646
647    // Don't bring in undefined values
648    } else if ( copy !== undefined ) {
649     target[ name ] = copy;
650    }
651   }
652  }
653 }
654
655 // Return the modified object
656 return target;
657};
658
659jQuery.extend({
660 // Unique for each copy of jQuery on the page
661 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
662
663 // Assume jQuery is ready without the ready module
664 isReady: true,
665
666 error: function( msg ) {
667  throw new Error( msg );
668 },
669
670 noop: function() {},
671
672 // See test/unit/core.js for details concerning isFunction.
673 // Since version 1.3, DOM methods and functions like alert
674 // aren't supported. They return false on IE (#2968).
675 isFunction: function( obj ) {
676  return jQuery.type(obj) === "function";
677 },
678
679 isArray: Array.isArray || function( obj ) {
680  return jQuery.type(obj) === "array";
681 },
682
683 isWindow: function( obj ) {
684  /* jshint eqeqeq: false */
685  return obj != null && obj == obj.window;
686 },
687
688 isNumeric: function( obj ) {
689  // parseFloat NaNs numeric-cast false positives (null|true|false|"")
690  // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
691  // subtraction forces infinities to NaN
692  return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
693 },
694
695 isEmptyObject: function( obj ) {
696  var name;
697  for ( name in obj ) {
698   return false;
699  }
700  return true;
701 },
702
703 isPlainObject: function( obj ) {
704  var key;
705
706  // Must be an Object.
707  // Because of IE, we also have to check the presence of the constructor property.
708  // Make sure that DOM nodes and window objects don't pass through, as well
709  if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
710   return false;
711  }
712
713  try {
714   // Not own constructor property must be Object
715   if ( obj.constructor &&
716    !hasOwn.call(obj, "constructor") &&
717    !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
718    return false;
719   }
720  } catch ( e ) {
721   // IE8,9 Will throw exceptions on certain host objects #9897
722   return false;
723  }
724
725  // Support: IE<9
726  // Handle iteration over inherited properties before own properties.
727  if ( support.ownLast ) {
728   for ( key in obj ) {
729    return hasOwn.call( obj, key );
730   }
731  }
732
733  // Own properties are enumerated firstly, so to speed up,
734  // if last one is own, then all properties are own.
735  for ( key in obj ) {}
736
737  return key === undefined || hasOwn.call( obj, key );
738 },
739
740 type: function( obj ) {
741  if ( obj == null ) {
742   return obj + "";
743  }
744  return typeof obj === "object" || typeof obj === "function" ?
745   class2type[ toString.call(obj) ] || "object" :
746   typeof obj;
747 },
748
749 // Evaluates a script in a global context
750 // Workarounds based on findings by Jim Driscoll
751 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
752 globalEval: function( data ) {
753  if ( data && jQuery.trim( data ) ) {
754   // We use execScript on Internet Explorer
755   // We use an anonymous function so that context is window
756   // rather than jQuery in Firefox
757   ( window.execScript || function( data ) {
758    window[ "eval" ].call( window, data );
759   } )( data );
760  }
761 },
762
763 // Convert dashed to camelCase; used by the css and data modules
764 // Microsoft forgot to hump their vendor prefix (#9572)
765 camelCase: function( string ) {
766  return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
767 },
768
769 nodeName: function( elem, name ) {
770  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
771 },
772
773 // args is for internal usage only
774 each: function( obj, callback, args ) {
775  var value,
776   i = 0,
777   length = obj.length,
778   isArray = isArraylike( obj );
779
780  if ( args ) {
781   if ( isArray ) {
782    for ( ; i < length; i++ ) {
783     value = callback.apply( obj[ i ], args );
784
785     if ( value === false ) {
786      break;
787     }
788    }
789   } else {
790    for ( i in obj ) {
791     value = callback.apply( obj[ i ], args );
792
793     if ( value === false ) {
794      break;
795     }
796    }
797   }
798
799  // A special, fast, case for the most common use of each
800  } else {
801   if ( isArray ) {
802    for ( ; i < length; i++ ) {
803     value = callback.call( obj[ i ], i, obj[ i ] );
804
805     if ( value === false ) {
806      break;
807     }
808    }
809   } else {
810    for ( i in obj ) {
811     value = callback.call( obj[ i ], i, obj[ i ] );
812
813     if ( value === false ) {
814      break;
815     }
816    }
817   }
818  }
819
820  return obj;
821 },
822
823 // Support: Android<4.1, IE<9
824 trim: function( text ) {
825  return text == null ?
826   "" :
827   ( text + "" ).replace( rtrim, "" );
828 },
829
830 // results is for internal usage only
831 makeArray: function( arr, results ) {
832  var ret = results || [];
833
834  if ( arr != null ) {
835   if ( isArraylike( Object(arr) ) ) {
836    jQuery.merge( ret,
837     typeof arr === "string" ?
838     [ arr ] : arr
839    );
840   } else {
841    push.call( ret, arr );
842   }
843  }
844
845  return ret;
846 },
847
848 inArray: function( elem, arr, i ) {
849  var len;
850
851  if ( arr ) {
852   if ( indexOf ) {
853    return indexOf.call( arr, elem, i );
854   }
855
856   len = arr.length;
857   i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
858
859   for ( ; i < len; i++ ) {
860    // Skip accessing in sparse arrays
861    if ( i in arr && arr[ i ] === elem ) {
862     return i;
863    }
864   }
865  }
866
867  return -1;
868 },
869
870 merge: function( first, second ) {
871  var len = +second.length,
872   j = 0,
873   i = first.length;
874
875  while ( j < len ) {
876   first[ i++ ] = second[ j++ ];
877  }
878
879  // Support: IE<9
880  // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
881  if ( len !== len ) {
882   while ( second[j] !== undefined ) {
883    first[ i++ ] = second[ j++ ];
884   }
885  }
886
887  first.length = i;
888
889  return first;
890 },
891
892 grep: function( elems, callback, invert ) {
893  var callbackInverse,
894   matches = [],
895   i = 0,
896   length = elems.length,
897   callbackExpect = !invert;
898
899  // Go through the array, only saving the items
900  // that pass the validator function
901  for ( ; i < length; i++ ) {
902   callbackInverse = !callback( elems[ i ], i );
903   if ( callbackInverse !== callbackExpect ) {
904    matches.push( elems[ i ] );
905   }
906  }
907
908  return matches;
909 },
910
911 // arg is for internal usage only
912 map: function( elems, callback, arg ) {
913  var value,
914   i = 0,
915   length = elems.length,
916   isArray = isArraylike( elems ),
917   ret = [];
918
919  // Go through the array, translating each of the items to their new values
920  if ( isArray ) {
921   for ( ; i < length; i++ ) {
922    value = callback( elems[ i ], i, arg );
923
924    if ( value != null ) {
925     ret.push( value );
926    }
927   }
928
929  // Go through every key on the object,
930  } else {
931   for ( i in elems ) {
932    value = callback( elems[ i ], i, arg );
933
934    if ( value != null ) {
935     ret.push( value );
936    }
937   }
938  }
939
940  // Flatten any nested arrays
941  return concat.apply( [], ret );
942 },
943
944 // A global GUID counter for objects
945 guid: 1,
946
947 // Bind a function to a context, optionally partially applying any
948 // arguments.
949 proxy: function( fn, context ) {
950  var args, proxy, tmp;
951
952  if ( typeof context === "string" ) {
953   tmp = fn[ context ];
954   context = fn;
955   fn = tmp;
956  }
957
958  // Quick check to determine if target is callable, in the spec
959  // this throws a TypeError, but we will just return undefined.
960  if ( !jQuery.isFunction( fn ) ) {
961   return undefined;
962  }
963
964  // Simulated bind
965  args = slice.call( arguments, 2 );
966  proxy = function() {
967   return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
968  };
969
970  // Set the guid of unique handler to the same of original handler, so it can be removed
971  proxy.guid = fn.guid = fn.guid || jQuery.guid++;
972
973  return proxy;
974 },
975
976 now: function() {
977  return +( new Date() );
978 },
979
980 // jQuery.support is not used in Core but other projects attach their
981 // properties to it so it needs to exist.
982 support: support
983});
984
985// Populate the class2type map
986jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
987 class2type[ "[object " + name + "]" ] = name.toLowerCase();
988});
989
990function isArraylike( obj ) {
991 var length = obj.length,
992  type = jQuery.type( obj );
993
994 if ( type === "function" || jQuery.isWindow( obj ) ) {
995  return false;
996 }
997
998 if ( obj.nodeType === 1 && length ) {
999  return true;
1000 }
1001
1002 return type === "array" || length === 0 ||
1003  typeof length === "number" && length > 0 && ( length - 1 ) in obj;
1004}
1005var Sizzle =
1006/*!
1007 * Sizzle CSS Selector Engine v1.10.19
1008 * http://sizzlejs.com/
1009 *
1010 * Copyright 2013 jQuery Foundation, Inc. and other contributors
1011 * Released under the MIT license
1012 * http://jquery.org/license
1013 *
1014 * Date: 2014-04-18
1015 */
1016(function( window ) {
1017
1018var i,
1019 support,
1020 Expr,
1021 getText,
1022 isXML,
1023 tokenize,
1024 compile,
1025 select,
1026 outermostContext,
1027 sortInput,
1028 hasDuplicate,
1029
1030 // Local document vars
1031 setDocument,
1032 document,
1033 docElem,
1034 documentIsHTML,
1035 rbuggyQSA,
1036 rbuggyMatches,
1037 matches,
1038 contains,
1039
1040 // Instance-specific data
1041 expando = "sizzle" + -(new Date()),
1042 preferredDoc = window.document,
1043 dirruns = 0,
1044 done = 0,
1045 classCache = createCache(),
1046 tokenCache = createCache(),
1047 compilerCache = createCache(),
1048 sortOrder = function( a, b ) {
1049  if ( a === b ) {
1050   hasDuplicate = true;
1051  }
1052  return 0;
1053 },
1054
1055 // General-purpose constants
1056 strundefined = typeof undefined,
1057 MAX_NEGATIVE = 1 << 31,
1058
1059 // Instance methods
1060 hasOwn = ({}).hasOwnProperty,
1061 arr = [],
1062 pop = arr.pop,
1063 push_native = arr.push,
1064 push = arr.push,
1065 slice = arr.slice,
1066 // Use a stripped-down indexOf if we can't use a native one
1067 indexOf = arr.indexOf || function( elem ) {
1068  var i = 0,
1069   len = this.length;
1070  for ( ; i < len; i++ ) {
1071   if ( this[i] === elem ) {
1072    return i;
1073   }
1074  }
1075  return -1;
1076 },
1077
1078 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
1079
1080 // Regular expressions
1081
1082 // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
1083 whitespace = "[\\x20\\t\\r\\n\\f]",
1084 // http://www.w3.org/TR/css3-syntax/#characters
1085 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
1086
1087 // Loosely modeled on CSS identifier characters
1088 // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
1089 // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
1090 identifier = characterEncoding.replace( "w", "w#" ),
1091
1092 // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
1093 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
1094  // Operator (capture 2)
1095  "*([*^$|!~]?=)" + whitespace +
1096  // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
1097  "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
1098  "*\\]",
1099
1100 pseudos = ":(" + characterEncoding + ")(?:\\((" +
1101  // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
1102  // 1. quoted (capture 3; capture 4 or capture 5)
1103  "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
1104  // 2. simple (capture 6)
1105  "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
1106  // 3. anything else (capture 2)
1107  ".*" +
1108  ")\\)|)",
1109
1110 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
1111 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
1112
1113 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
1114 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
1115
1116 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
1117
1118 rpseudo = new RegExp( pseudos ),
1119 ridentifier = new RegExp( "^" + identifier + "$" ),
1120
1121 matchExpr = {
1122  "ID": new RegExp( "^#(" + characterEncoding + ")" ),
1123  "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
1124  "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
1125  "ATTR": new RegExp( "^" + attributes ),
1126  "PSEUDO": new RegExp( "^" + pseudos ),
1127  "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
1128   "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
1129   "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
1130  "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
1131  // For use in libraries implementing .is()
1132  // We use this for POS matching in `select`
1133  "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
1134   whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
1135 },
1136
1137 rinputs = /^(?:input|select|textarea|button)$/i,
1138 rheader = /^h\d$/i,
1139
1140 rnative = /^[^{]+\{\s*\[native \w/,
1141
1142 // Easily-parseable/retrievable ID or TAG or CLASS selectors
1143 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
1144
1145 rsibling = /[+~]/,
1146 rescape = /'|\\/g,
1147
1148 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
1149 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
1150 funescape = function( _, escaped, escapedWhitespace ) {
1151  var high = "0x" + escaped - 0x10000;
1152  // NaN means non-codepoint
1153  // Support: Firefox<24
1154  // Workaround erroneous numeric interpretation of +"0x"
1155  return high !== high || escapedWhitespace ?
1156   escaped :
1157   high < 0 ?
1158    // BMP codepoint
1159    String.fromCharCode( high + 0x10000 ) :
1160    // Supplemental Plane codepoint (surrogate pair)
1161    String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
1162 };
1163
1164// Optimize for push.apply( _, NodeList )
1165try {
1166 push.apply(
1167  (arr = slice.call( preferredDoc.childNodes )),
1168  preferredDoc.childNodes
1169 );
1170 // Support: Android<4.0
1171 // Detect silently failing push.apply
1172 arr[ preferredDoc.childNodes.length ].nodeType;
1173} catch ( e ) {
1174 push = { apply: arr.length ?
1175
1176  // Leverage slice if possible
1177  function( target, els ) {
1178   push_native.apply( target, slice.call(els) );
1179  } :
1180
1181  // Support: IE<9
1182  // Otherwise append directly
1183  function( target, els ) {
1184   var j = target.length,
1185    i = 0;
1186   // Can't trust NodeList.length
1187   while ( (target[j++] = els[i++]) ) {}
1188   target.length = j - 1;
1189  }
1190 };
1191}
1192
1193function Sizzle( selector, context, results, seed ) {
1194 var match, elem, m, nodeType,
1195  // QSA vars
1196  i, groups, old, nid, newContext, newSelector;
1197
1198 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
1199  setDocument( context );
1200 }
1201
1202 context = context || document;
1203 results = results || [];
1204
1205 if ( !selector || typeof selector !== "string" ) {
1206  return results;
1207 }
1208
1209 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
1210  return [];
1211 }
1212
1213 if ( documentIsHTML && !seed ) {
1214
1215  // Shortcuts
1216  if ( (match = rquickExpr.exec( selector )) ) {
1217   // Speed-up: Sizzle("#ID")
1218   if ( (m = match[1]) ) {
1219    if ( nodeType === 9 ) {
1220     elem = context.getElementById( m );
1221     // Check parentNode to catch when Blackberry 4.6 returns
1222     // nodes that are no longer in the document (jQuery #6963)
1223     if ( elem && elem.parentNode ) {
1224      // Handle the case where IE, Opera, and Webkit return items
1225      // by name instead of ID
1226      if ( elem.id === m ) {
1227       results.push( elem );
1228       return results;
1229      }
1230     } else {
1231      return results;
1232     }
1233    } else {
1234     // Context is not a document
1235     if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
1236      contains( context, elem ) && elem.id === m ) {
1237      results.push( elem );
1238      return results;
1239     }
1240    }
1241
1242   // Speed-up: Sizzle("TAG")
1243   } else if ( match[2] ) {
1244    push.apply( results, context.getElementsByTagName( selector ) );
1245    return results;
1246
1247   // Speed-up: Sizzle(".CLASS")
1248   } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
1249    push.apply( results, context.getElementsByClassName( m ) );
1250    return results;
1251   }
1252  }
1253
1254  // QSA path
1255  if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
1256   nid = old = expando;
1257   newContext = context;
1258   newSelector = nodeType === 9 && selector;
1259
1260   // qSA works strangely on Element-rooted queries
1261   // We can work around this by specifying an extra ID on the root
1262   // and working up from there (Thanks to Andrew Dupont for the technique)
1263   // IE 8 doesn't work on object elements
1264   if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
1265    groups = tokenize( selector );
1266
1267    if ( (old = context.getAttribute("id")) ) {
1268     nid = old.replace( rescape, "\\$&" );
1269    } else {
1270     context.setAttribute( "id", nid );
1271    }
1272    nid = "[id='" + nid + "'] ";
1273
1274    i = groups.length;
1275    while ( i-- ) {
1276     groups[i] = nid + toSelector( groups[i] );
1277    }
1278    newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
1279    newSelector = groups.join(",");
1280   }
1281
1282   if ( newSelector ) {
1283    try {
1284     push.apply( results,
1285      newContext.querySelectorAll( newSelector )
1286     );
1287     return results;
1288    } catch(qsaError) {
1289    } finally {
1290     if ( !old ) {
1291      context.removeAttribute("id");
1292     }
1293    }
1294   }
1295  }
1296 }
1297
1298 // All others
1299 return select( selector.replace( rtrim, "$1" ), context, results, seed );
1300}
1301
1302/**
1303 * Create key-value caches of limited size
1304 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
1305 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
1306 * deleting the oldest entry
1307 */
1308function createCache() {
1309 var keys = [];
1310
1311 function cache( key, value ) {
1312  // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
1313  if ( keys.push( key + " " ) > Expr.cacheLength ) {
1314   // Only keep the most recent entries
1315   delete cache[ keys.shift() ];
1316  }
1317  return (cache[ key + " " ] = value);
1318 }
1319 return cache;
1320}
1321
1322/**
1323 * Mark a function for special use by Sizzle
1324 * @param {Function} fn The function to mark
1325 */
1326function markFunction( fn ) {
1327 fn[ expando ] = true;
1328 return fn;
1329}
1330
1331/**
1332 * Support testing using an element
1333 * @param {Function} fn Passed the created div and expects a boolean result
1334 */
1335function assert( fn ) {
1336 var div = document.createElement("div");
1337
1338 try {
1339  return !!fn( div );
1340 } catch (e) {
1341  return false;
1342 } finally {
1343  // Remove from its parent by default
1344  if ( div.parentNode ) {
1345   div.parentNode.removeChild( div );
1346  }
1347  // release memory in IE
1348  div = null;
1349 }
1350}
1351
1352/**
1353 * Adds the same handler for all of the specified attrs
1354 * @param {String} attrs Pipe-separated list of attributes
1355 * @param {Function} handler The method that will be applied
1356 */
1357function addHandle( attrs, handler ) {
1358 var arr = attrs.split("|"),
1359  i = attrs.length;
1360
1361 while ( i-- ) {
1362  Expr.attrHandle[ arr[i] ] = handler;
1363 }
1364}
1365
1366/**
1367 * Checks document order of two siblings
1368 * @param {Element} a
1369 * @param {Element} b
1370 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
1371 */
1372function siblingCheck( a, b ) {
1373 var cur = b && a,
1374  diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
1375   ( ~b.sourceIndex || MAX_NEGATIVE ) -
1376   ( ~a.sourceIndex || MAX_NEGATIVE );
1377
1378 // Use IE sourceIndex if available on both nodes
1379 if ( diff ) {
1380  return diff;
1381 }
1382
1383 // Check if b follows a
1384 if ( cur ) {
1385  while ( (cur = cur.nextSibling) ) {
1386   if ( cur === b ) {
1387    return -1;
1388   }
1389  }
1390 }
1391
1392 return a ? 1 : -1;
1393}
1394
1395/**
1396 * Returns a function to use in pseudos for input types
1397 * @param {String} type
1398 */
1399function createInputPseudo( type ) {
1400 return function( elem ) {
1401  var name = elem.nodeName.toLowerCase();
1402  return name === "input" && elem.type === type;
1403 };
1404}
1405
1406/**
1407 * Returns a function to use in pseudos for buttons
1408 * @param {String} type
1409 */
1410function createButtonPseudo( type ) {
1411 return function( elem ) {
1412  var name = elem.nodeName.toLowerCase();
1413  return (name === "input" || name === "button") && elem.type === type;
1414 };
1415}
1416
1417/**
1418 * Returns a function to use in pseudos for positionals
1419 * @param {Function} fn
1420 */
1421function createPositionalPseudo( fn ) {
1422 return markFunction(function( argument ) {
1423  argument = +argument;
1424  return markFunction(function( seed, matches ) {
1425   var j,
1426    matchIndexes = fn( [], seed.length, argument ),
1427    i = matchIndexes.length;
1428
1429   // Match elements found at the specified indexes
1430   while ( i-- ) {
1431    if ( seed[ (j = matchIndexes[i]) ] ) {
1432     seed[j] = !(matches[j] = seed[j]);
1433    }
1434   }
1435  });
1436 });
1437}
1438
1439/**
1440 * Checks a node for validity as a Sizzle context
1441 * @param {Element|Object=} context
1442 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
1443 */
1444function testContext( context ) {
1445 return context && typeof context.getElementsByTagName !== strundefined && context;
1446}
1447
1448// Expose support vars for convenience
1449support = Sizzle.support = {};
1450
1451/**
1452 * Detects XML nodes
1453 * @param {Element|Object} elem An element or a document
1454 * @returns {Boolean} True iff elem is a non-HTML XML node
1455 */
1456isXML = Sizzle.isXML = function( elem ) {
1457 // documentElement is verified for cases where it doesn't yet exist
1458 // (such as loading iframes in IE - #4833)
1459 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1460 return documentElement ? documentElement.nodeName !== "HTML" : false;
1461};
1462
1463/**
1464 * Sets document-related variables once based on the current document
1465 * @param {Element|Object} [doc] An element or document object to use to set the document
1466 * @returns {Object} Returns the current document
1467 */
1468setDocument = Sizzle.setDocument = function( node ) {
1469 var hasCompare,
1470  doc = node ? node.ownerDocument || node : preferredDoc,
1471  parent = doc.defaultView;
1472
1473 // If no document and documentElement is available, return
1474 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1475  return document;
1476 }
1477
1478 // Set our document
1479 document = doc;
1480 docElem = doc.documentElement;
1481
1482 // Support tests
1483 documentIsHTML = !isXML( doc );
1484
1485 // Support: IE>8
1486 // If iframe document is assigned to "document" variable and if iframe has been reloaded,
1487 // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
1488 // IE6-8 do not support the defaultView property so parent will be undefined
1489 if ( parent && parent !== parent.top ) {
1490  // IE11 does not have attachEvent, so all must suffer
1491  if ( parent.addEventListener ) {
1492   parent.addEventListener( "unload", function() {
1493    setDocument();
1494   }, false );
1495  } else if ( parent.attachEvent ) {
1496   parent.attachEvent( "onunload", function() {
1497    setDocument();
1498   });
1499  }
1500 }
1501
1502 /* Attributes
1503 ---------------------------------------------------------------------- */
1504
1505 // Support: IE<8
1506 // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
1507 support.attributes = assert(function( div ) {
1508  div.className = "i";
1509  return !div.getAttribute("className");
1510 });
1511
1512 /* getElement(s)By*
1513 ---------------------------------------------------------------------- */
1514
1515 // Check if getElementsByTagName("*") returns only elements
1516 support.getElementsByTagName = assert(function( div ) {
1517  div.appendChild( doc.createComment("") );
1518  return !div.getElementsByTagName("*").length;
1519 });
1520
1521 // Check if getElementsByClassName can be trusted
1522 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
1523  div.innerHTML = "<div class='a'></div><div class='a i'></div>";
1524
1525  // Support: Safari<4
1526  // Catch class over-caching
1527  div.firstChild.className = "i";
1528  // Support: Opera<10
1529  // Catch gEBCN failure to find non-leading classes
1530  return div.getElementsByClassName("i").length === 2;
1531 });
1532
1533 // Support: IE<10
1534 // Check if getElementById returns elements by name
1535 // The broken getElementById methods don't pick up programatically-set names,
1536 // so use a roundabout getElementsByName test
1537 support.getById = assert(function( div ) {
1538  docElem.appendChild( div ).id = expando;
1539  return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
1540 });
1541
1542 // ID find and filter
1543 if ( support.getById ) {
1544  Expr.find["ID"] = function( id, context ) {
1545   if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
1546    var m = context.getElementById( id );
1547    // Check parentNode to catch when Blackberry 4.6 returns
1548    // nodes that are no longer in the document #6963
1549    return m && m.parentNode ? [ m ] : [];
1550   }
1551  };
1552  Expr.filter["ID"] = function( id ) {
1553   var attrId = id.replace( runescape, funescape );
1554   return function( elem ) {
1555    return elem.getAttribute("id") === attrId;
1556   };
1557  };
1558 } else {
1559  // Support: IE6/7
1560  // getElementById is not reliable as a find shortcut
1561  delete Expr.find["ID"];
1562
1563  Expr.filter["ID"] =  function( id ) {
1564   var attrId = id.replace( runescape, funescape );
1565   return function( elem ) {
1566    var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
1567    return node && node.value === attrId;
1568   };
1569  };
1570 }
1571
1572 // Tag
1573 Expr.find["TAG"] = support.getElementsByTagName ?
1574  function( tag, context ) {
1575   if ( typeof context.getElementsByTagName !== strundefined ) {
1576    return context.getElementsByTagName( tag );
1577   }
1578  } :
1579  function( tag, context ) {
1580   var elem,
1581    tmp = [],
1582    i = 0,
1583    results = context.getElementsByTagName( tag );
1584
1585   // Filter out possible comments
1586   if ( tag === "*" ) {
1587    while ( (elem = results[i++]) ) {
1588     if ( elem.nodeType === 1 ) {
1589      tmp.push( elem );
1590     }
1591    }
1592
1593    return tmp;
1594   }
1595   return results;
1596  };
1597
1598 // Class
1599 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1600  if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
1601   return context.getElementsByClassName( className );
1602  }
1603 };
1604
1605 /* QSA/matchesSelector
1606 ---------------------------------------------------------------------- */
1607
1608 // QSA and matchesSelector support
1609
1610 // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1611 rbuggyMatches = [];
1612
1613 // qSa(:focus) reports false when true (Chrome 21)
1614 // We allow this because of a bug in IE8/9 that throws an error
1615 // whenever `document.activeElement` is accessed on an iframe
1616 // So, we allow :focus to pass through QSA all the time to avoid the IE error
1617 // See http://bugs.jquery.com/ticket/13378
1618 rbuggyQSA = [];
1619
1620 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
1621  // Build QSA regex
1622  // Regex strategy adopted from Diego Perini
1623  assert(function( div ) {
1624   // Select is set to empty string on purpose
1625   // This is to test IE's treatment of not explicitly
1626   // setting a boolean content attribute,
1627   // since its presence should be enough
1628   // http://bugs.jquery.com/ticket/12359
1629   div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
1630
1631   // Support: IE8, Opera 11-12.16
1632   // Nothing should be selected when empty strings follow ^= or $= or *=
1633   // The test attribute must be unknown in Opera but "safe" for WinRT
1634   // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
1635   if ( div.querySelectorAll("[msallowclip^='']").length ) {
1636    rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1637   }
1638
1639   // Support: IE8
1640   // Boolean attributes and "value" are not treated correctly
1641   if ( !div.querySelectorAll("[selected]").length ) {
1642    rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1643   }
1644
1645   // Webkit/Opera - :checked should return selected option elements
1646   // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1647   // IE8 throws error here and will not see later tests
1648   if ( !div.querySelectorAll(":checked").length ) {
1649    rbuggyQSA.push(":checked");
1650   }
1651  });
1652
1653  assert(function( div ) {
1654   // Support: Windows 8 Native Apps
1655   // The type and name attributes are restricted during .innerHTML assignment
1656   var input = doc.createElement("input");
1657   input.setAttribute( "type", "hidden" );
1658   div.appendChild( input ).setAttribute( "name", "D" );
1659
1660   // Support: IE8
1661   // Enforce case-sensitivity of name attribute
1662   if ( div.querySelectorAll("[name=d]").length ) {
1663    rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
1664   }
1665
1666   // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1667   // IE8 throws error here and will not see later tests
1668   if ( !div.querySelectorAll(":enabled").length ) {
1669    rbuggyQSA.push( ":enabled", ":disabled" );
1670   }
1671
1672   // Opera 10-11 does not throw on post-comma invalid pseudos
1673   div.querySelectorAll("*,:x");
1674   rbuggyQSA.push(",.*:");
1675  });
1676 }
1677
1678 if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
1679  docElem.webkitMatchesSelector ||
1680  docElem.mozMatchesSelector ||
1681  docElem.oMatchesSelector ||
1682  docElem.msMatchesSelector) )) ) {
1683
1684  assert(function( div ) {
1685   // Check to see if it's possible to do matchesSelector
1686   // on a disconnected node (IE 9)
1687   support.disconnectedMatch = matches.call( div, "div" );
1688
1689   // This should fail with an exception
1690   // Gecko does not error, returns false instead
1691   matches.call( div, "[s!='']:x" );
1692   rbuggyMatches.push( "!=", pseudos );
1693  });
1694 }
1695
1696 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1697 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1698
1699 /* Contains
1700 ---------------------------------------------------------------------- */
1701 hasCompare = rnative.test( docElem.compareDocumentPosition );
1702
1703 // Element contains another
1704 // Purposefully does not implement inclusive descendent
1705 // As in, an element does not contain itself
1706 contains = hasCompare || rnative.test( docElem.contains ) ?
1707  function( a, b ) {
1708   var adown = a.nodeType === 9 ? a.documentElement : a,
1709    bup = b && b.parentNode;
1710   return a === bup || !!( bup && bup.nodeType === 1 && (
1711    adown.contains ?
1712     adown.contains( bup ) :
1713     a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1714   ));
1715  } :
1716  function( a, b ) {
1717   if ( b ) {
1718    while ( (b = b.parentNode) ) {
1719     if ( b === a ) {
1720      return true;
1721     }
1722    }
1723   }
1724   return false;
1725  };
1726
1727 /* Sorting
1728 ---------------------------------------------------------------------- */
1729
1730 // Document order sorting
1731 sortOrder = hasCompare ?
1732 function( a, b ) {
1733
1734  // Flag for duplicate removal
1735  if ( a === b ) {
1736   hasDuplicate = true;
1737   return 0;
1738  }
1739
1740  // Sort on method existence if only one input has compareDocumentPosition
1741  var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
1742  if ( compare ) {
1743   return compare;
1744  }
1745
1746  // Calculate position if both inputs belong to the same document
1747  compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
1748   a.compareDocumentPosition( b ) :
1749
1750   // Otherwise we know they are disconnected
1751   1;
1752
1753  // Disconnected nodes
1754  if ( compare & 1 ||
1755   (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1756
1757   // Choose the first element that is related to our preferred document
1758   if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
1759    return -1;
1760   }
1761   if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
1762    return 1;
1763   }
1764
1765   // Maintain original order
1766   return sortInput ?
1767    ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1768    0;
1769  }
1770
1771  return compare & 4 ? -1 : 1;
1772 } :
1773 function( a, b ) {
1774  // Exit early if the nodes are identical
1775  if ( a === b ) {
1776   hasDuplicate = true;
1777   return 0;
1778  }
1779
1780  var cur,
1781   i = 0,
1782   aup = a.parentNode,
1783   bup = b.parentNode,
1784   ap = [ a ],
1785   bp = [ b ];
1786
1787  // Parentless nodes are either documents or disconnected
1788  if ( !aup || !bup ) {
1789   return a === doc ? -1 :
1790    b === doc ? 1 :
1791    aup ? -1 :
1792    bup ? 1 :
1793    sortInput ?
1794    ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1795    0;
1796
1797  // If the nodes are siblings, we can do a quick check
1798  } else if ( aup === bup ) {
1799   return siblingCheck( a, b );
1800  }
1801
1802  // Otherwise we need full lists of their ancestors for comparison
1803  cur = a;
1804  while ( (cur = cur.parentNode) ) {
1805   ap.unshift( cur );
1806  }
1807  cur = b;
1808  while ( (cur = cur.parentNode) ) {
1809   bp.unshift( cur );
1810  }
1811
1812  // Walk down the tree looking for a discrepancy
1813  while ( ap[i] === bp[i] ) {
1814   i++;
1815  }
1816
1817  return i ?
1818   // Do a sibling check if the nodes have a common ancestor
1819   siblingCheck( ap[i], bp[i] ) :
1820
1821   // Otherwise nodes in our document sort first
1822   ap[i] === preferredDoc ? -1 :
1823   bp[i] === preferredDoc ? 1 :
1824   0;
1825 };
1826
1827 return doc;
1828};
1829
1830Sizzle.matches = function( expr, elements ) {
1831 return Sizzle( expr, null, null, elements );
1832};
1833
1834Sizzle.matchesSelector = function( elem, expr ) {
1835 // Set document vars if needed
1836 if ( ( elem.ownerDocument || elem ) !== document ) {
1837  setDocument( elem );
1838 }
1839
1840 // Make sure that attribute selectors are quoted
1841 expr = expr.replace( rattributeQuotes, "='$1']" );
1842
1843 if ( support.matchesSelector && documentIsHTML &&
1844  ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1845  ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
1846
1847  try {
1848   var ret = matches.call( elem, expr );
1849
1850   // IE 9's matchesSelector returns false on disconnected nodes
1851   if ( ret || support.disconnectedMatch ||
1852     // As well, disconnected nodes are said to be in a document
1853     // fragment in IE 9
1854     elem.document && elem.document.nodeType !== 11 ) {
1855    return ret;
1856   }
1857  } catch(e) {}
1858 }
1859
1860 return Sizzle( expr, document, null, [ elem ] ).length > 0;
1861};
1862
1863Sizzle.contains = function( context, elem ) {
1864 // Set document vars if needed
1865 if ( ( context.ownerDocument || context ) !== document ) {
1866  setDocument( context );
1867 }
1868 return contains( context, elem );
1869};
1870
1871Sizzle.attr = function( elem, name ) {
1872 // Set document vars if needed
1873 if ( ( elem.ownerDocument || elem ) !== document ) {
1874  setDocument( elem );
1875 }
1876
1877 var fn = Expr.attrHandle[ name.toLowerCase() ],
1878  // Don't get fooled by Object.prototype properties (jQuery #13807)
1879  val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1880   fn( elem, name, !documentIsHTML ) :
1881   undefined;
1882
1883 return val !== undefined ?
1884  val :
1885  support.attributes || !documentIsHTML ?
1886   elem.getAttribute( name ) :
1887   (val = elem.getAttributeNode(name)) && val.specified ?
1888    val.value :
1889    null;
1890};
1891
1892Sizzle.error = function( msg ) {
1893 throw new Error( "Syntax error, unrecognized expression: " + msg );
1894};
1895
1896/**
1897 * Document sorting and removing duplicates
1898 * @param {ArrayLike} results
1899 */
1900Sizzle.uniqueSort = function( results ) {
1901 var elem,
1902  duplicates = [],
1903  j = 0,
1904  i = 0;
1905
1906 // Unless we *know* we can detect duplicates, assume their presence
1907 hasDuplicate = !support.detectDuplicates;
1908 sortInput = !support.sortStable && results.slice( 0 );
1909 results.sort( sortOrder );
1910
1911 if ( hasDuplicate ) {
1912  while ( (elem = results[i++]) ) {
1913   if ( elem === results[ i ] ) {
1914    j = duplicates.push( i );
1915   }
1916  }
1917  while ( j-- ) {
1918   results.splice( duplicates[ j ], 1 );
1919  }
1920 }
1921
1922 // Clear input after sorting to release objects
1923 // See https://github.com/jquery/sizzle/pull/225
1924 sortInput = null;
1925
1926 return results;
1927};
1928
1929/**
1930 * Utility function for retrieving the text value of an array of DOM nodes
1931 * @param {Array|Element} elem
1932 */
1933getText = Sizzle.getText = function( elem ) {
1934 var node,
1935  ret = "",
1936  i = 0,
1937  nodeType = elem.nodeType;
1938
1939 if ( !nodeType ) {
1940  // If no nodeType, this is expected to be an array
1941  while ( (node = elem[i++]) ) {
1942   // Do not traverse comment nodes
1943   ret += getText( node );
1944  }
1945 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1946  // Use textContent for elements
1947  // innerText usage removed for consistency of new lines (jQuery #11153)
1948  if ( typeof elem.textContent === "string" ) {
1949   return elem.textContent;
1950  } else {
1951   // Traverse its children
1952   for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1953    ret += getText( elem );
1954   }
1955  }
1956 } else if ( nodeType === 3 || nodeType === 4 ) {
1957  return elem.nodeValue;
1958 }
1959 // Do not include comment or processing instruction nodes
1960
1961 return ret;
1962};
1963
1964Expr = Sizzle.selectors = {
1965
1966 // Can be adjusted by the user
1967 cacheLength: 50,
1968
1969 createPseudo: markFunction,
1970
1971 match: matchExpr,
1972
1973 attrHandle: {},
1974
1975 find: {},
1976
1977 relative: {
1978  ">": { dir: "parentNode", first: true },
1979  " ": { dir: "parentNode" },
1980  "+": { dir: "previousSibling", first: true },
1981  "~": { dir: "previousSibling" }
1982 },
1983
1984 preFilter: {
1985  "ATTR": function( match ) {
1986   match[1] = match[1].replace( runescape, funescape );
1987
1988   // Move the given value to match[3] whether quoted or unquoted
1989   match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
1990
1991   if ( match[2] === "~=" ) {
1992    match[3] = " " + match[3] + " ";
1993   }
1994
1995   return match.slice( 0, 4 );
1996  },
1997
1998  "CHILD": function( match ) {
1999   /* matches from matchExpr["CHILD"]
2000    1 type (only|nth|...)
2001    2 what (child|of-type)
2002    3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
2003    4 xn-component of xn+y argument ([+-]?\d*n|)
2004    5 sign of xn-component
2005    6 x of xn-component
2006    7 sign of y-component
2007    8 y of y-component
2008   */
2009   match[1] = match[1].toLowerCase();
2010
2011   if ( match[1].slice( 0, 3 ) === "nth" ) {
2012    // nth-* requires argument
2013    if ( !match[3] ) {
2014     Sizzle.error( match[0] );
2015    }
2016
2017    // numeric x and y parameters for Expr.filter.CHILD
2018    // remember that false/true cast respectively to 0/1
2019    match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
2020    match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
2021
2022   // other types prohibit arguments
2023   } else if ( match[3] ) {
2024    Sizzle.error( match[0] );
2025   }
2026
2027   return match;
2028  },
2029
2030  "PSEUDO": function( match ) {
2031   var excess,
2032    unquoted = !match[6] && match[2];
2033
2034   if ( matchExpr["CHILD"].test( match[0] ) ) {
2035    return null;
2036   }
2037
2038   // Accept quoted arguments as-is
2039   if ( match[3] ) {
2040    match[2] = match[4] || match[5] || "";
2041
2042   // Strip excess characters from unquoted arguments
2043   } else if ( unquoted && rpseudo.test( unquoted ) &&
2044    // Get excess from tokenize (recursively)
2045    (excess = tokenize( unquoted, true )) &&
2046    // advance to the next closing parenthesis
2047    (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
2048
2049    // excess is a negative index
2050    match[0] = match[0].slice( 0, excess );
2051    match[2] = unquoted.slice( 0, excess );
2052   }
2053
2054   // Return only captures needed by the pseudo filter method (type and argument)
2055   return match.slice( 0, 3 );
2056  }
2057 },
2058
2059 filter: {
2060
2061  "TAG": function( nodeNameSelector ) {
2062   var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
2063   return nodeNameSelector === "*" ?
2064    function() { return true; } :
2065    function( elem ) {
2066     return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
2067    };
2068  },
2069
2070  "CLASS": function( className ) {
2071   var pattern = classCache[ className + " " ];
2072
2073   return pattern ||
2074    (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
2075    classCache( className, function( elem ) {
2076     return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
2077    });
2078  },
2079
2080  "ATTR": function( name, operator, check ) {
2081   return function( elem ) {
2082    var result = Sizzle.attr( elem, name );
2083
2084    if ( result == null ) {
2085     return operator === "!=";
2086    }
2087    if ( !operator ) {
2088     return true;
2089    }
2090
2091    result += "";
2092
2093    return operator === "=" ? result === check :
2094     operator === "!=" ? result !== check :
2095     operator === "^=" ? check && result.indexOf( check ) === 0 :
2096     operator === "*=" ? check && result.indexOf( check ) > -1 :
2097     operator === "$=" ? check && result.slice( -check.length ) === check :
2098     operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
2099     operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
2100     false;
2101   };
2102  },
2103
2104  "CHILD": function( type, what, argument, first, last ) {
2105   var simple = type.slice( 0, 3 ) !== "nth",
2106    forward = type.slice( -4 ) !== "last",
2107    ofType = what === "of-type";
2108
2109   return first === 1 && last === 0 ?
2110
2111    // Shortcut for :nth-*(n)
2112    function( elem ) {
2113     return !!elem.parentNode;
2114    } :
2115
2116    function( elem, context, xml ) {
2117     var cache, outerCache, node, diff, nodeIndex, start,
2118      dir = simple !== forward ? "nextSibling" : "previousSibling",
2119      parent = elem.parentNode,
2120      name = ofType && elem.nodeName.toLowerCase(),
2121      useCache = !xml && !ofType;
2122
2123     if ( parent ) {
2124
2125      // :(first|last|only)-(child|of-type)
2126      if ( simple ) {
2127       while ( dir ) {
2128        node = elem;
2129        while ( (node = node[ dir ]) ) {
2130         if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
2131          return false;
2132         }
2133        }
2134        // Reverse direction for :only-* (if we haven't yet done so)
2135        start = dir = type === "only" && !start && "nextSibling";
2136       }
2137       return true;
2138      }
2139
2140      start = [ forward ? parent.firstChild : parent.lastChild ];
2141
2142      // non-xml :nth-child(...) stores cache data on `parent`
2143      if ( forward && useCache ) {
2144       // Seek `elem` from a previously-cached index
2145       outerCache = parent[ expando ] || (parent[ expando ] = {});
2146       cache = outerCache[ type ] || [];
2147       nodeIndex = cache[0] === dirruns && cache[1];
2148       diff = cache[0] === dirruns && cache[2];
2149       node = nodeIndex && parent.childNodes[ nodeIndex ];
2150
2151       while ( (node = ++nodeIndex && node && node[ dir ] ||
2152
2153        // Fallback to seeking `elem` from the start
2154        (diff = nodeIndex = 0) || start.pop()) ) {
2155
2156        // When found, cache indexes on `parent` and break
2157        if ( node.nodeType === 1 && ++diff && node === elem ) {
2158         outerCache[ type ] = [ dirruns, nodeIndex, diff ];
2159         break;
2160        }
2161       }
2162
2163      // Use previously-cached element index if available
2164      } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
2165       diff = cache[1];
2166
2167      // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
2168      } else {
2169       // Use the same loop as above to seek `elem` from the start
2170       while ( (node = ++nodeIndex && node && node[ dir ] ||
2171        (diff = nodeIndex = 0) || start.pop()) ) {
2172
2173        if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
2174         // Cache the index of each encountered element
2175         if ( useCache ) {
2176          (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
2177         }
2178
2179         if ( node === elem ) {
2180          break;
2181         }
2182        }
2183       }
2184      }
2185
2186      // Incorporate the offset, then check against cycle size
2187      diff -= last;
2188      return diff === first || ( diff % first === 0 && diff / first >= 0 );
2189     }
2190    };
2191  },
2192
2193  "PSEUDO": function( pseudo, argument ) {
2194   // pseudo-class names are case-insensitive
2195   // http://www.w3.org/TR/selectors/#pseudo-classes
2196   // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
2197   // Remember that setFilters inherits from pseudos
2198   var args,
2199    fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
2200     Sizzle.error( "unsupported pseudo: " + pseudo );
2201
2202   // The user may use createPseudo to indicate that
2203   // arguments are needed to create the filter function
2204   // just as Sizzle does
2205   if ( fn[ expando ] ) {
2206    return fn( argument );
2207   }
2208
2209   // But maintain support for old signatures
2210   if ( fn.length > 1 ) {
2211    args = [ pseudo, pseudo, "", argument ];
2212    return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
2213     markFunction(function( seed, matches ) {
2214      var idx,
2215       matched = fn( seed, argument ),
2216       i = matched.length;
2217      while ( i-- ) {
2218       idx = indexOf.call( seed, matched[i] );
2219       seed[ idx ] = !( matches[ idx ] = matched[i] );
2220      }
2221     }) :
2222     function( elem ) {
2223      return fn( elem, 0, args );
2224     };
2225   }
2226
2227   return fn;
2228  }
2229 },
2230
2231 pseudos: {
2232  // Potentially complex pseudos
2233  "not": markFunction(function( selector ) {
2234   // Trim the selector passed to compile
2235   // to avoid treating leading and trailing
2236   // spaces as combinators
2237   var input = [],
2238    results = [],
2239    matcher = compile( selector.replace( rtrim, "$1" ) );
2240
2241   return matcher[ expando ] ?
2242    markFunction(function( seed, matches, context, xml ) {
2243     var elem,
2244      unmatched = matcher( seed, null, xml, [] ),
2245      i = seed.length;
2246
2247     // Match elements unmatched by `matcher`
2248     while ( i-- ) {
2249      if ( (elem = unmatched[i]) ) {
2250       seed[i] = !(matches[i] = elem);
2251      }
2252     }
2253    }) :
2254    function( elem, context, xml ) {
2255     input[0] = elem;
2256     matcher( input, null, xml, results );
2257     return !results.pop();
2258    };
2259  }),
2260
2261  "has": markFunction(function( selector ) {
2262   return function( elem ) {
2263    return Sizzle( selector, elem ).length > 0;
2264   };
2265  }),
2266
2267  "contains": markFunction(function( text ) {
2268   return function( elem ) {
2269    return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
2270   };
2271  }),
2272
2273  // "Whether an element is represented by a :lang() selector
2274  // is based solely on the element's language value
2275  // being equal to the identifier C,
2276  // or beginning with the identifier C immediately followed by "-".
2277  // The matching of C against the element's language value is performed case-insensitively.
2278  // The identifier C does not have to be a valid language name."
2279  // http://www.w3.org/TR/selectors/#lang-pseudo
2280  "lang": markFunction( function( lang ) {
2281   // lang value must be a valid identifier
2282   if ( !ridentifier.test(lang || "") ) {
2283    Sizzle.error( "unsupported lang: " + lang );
2284   }
2285   lang = lang.replace( runescape, funescape ).toLowerCase();
2286   return function( elem ) {
2287    var elemLang;
2288    do {
2289     if ( (elemLang = documentIsHTML ?
2290      elem.lang :
2291      elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2292
2293      elemLang = elemLang.toLowerCase();
2294      return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2295     }
2296    } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2297    return false;
2298   };
2299  }),
2300
2301  // Miscellaneous
2302  "target": function( elem ) {
2303   var hash = window.location && window.location.hash;
2304   return hash && hash.slice( 1 ) === elem.id;
2305  },
2306
2307  "root": function( elem ) {
2308   return elem === docElem;
2309  },
2310
2311  "focus": function( elem ) {
2312   return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2313  },
2314
2315  // Boolean properties
2316  "enabled": function( elem ) {
2317   return elem.disabled === false;
2318  },
2319
2320  "disabled": function( elem ) {
2321   return elem.disabled === true;
2322  },
2323
2324  "checked": function( elem ) {
2325   // In CSS3, :checked should return both checked and selected elements
2326   // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2327   var nodeName = elem.nodeName.toLowerCase();
2328   return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2329  },
2330
2331  "selected": function( elem ) {
2332   // Accessing this property makes selected-by-default
2333   // options in Safari work properly
2334   if ( elem.parentNode ) {
2335    elem.parentNode.selectedIndex;
2336   }
2337
2338   return elem.selected === true;
2339  },
2340
2341  // Contents
2342  "empty": function( elem ) {
2343   // http://www.w3.org/TR/selectors/#empty-pseudo
2344   // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
2345   //   but not by others (comment: 8; processing instruction: 7; etc.)
2346   // nodeType < 6 works because attributes (2) do not appear as children
2347   for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2348    if ( elem.nodeType < 6 ) {
2349     return false;
2350    }
2351   }
2352   return true;
2353  },
2354
2355  "parent": function( elem ) {
2356   return !Expr.pseudos["empty"]( elem );
2357  },
2358
2359  // Element/input types
2360  "header": function( elem ) {
2361   return rheader.test( elem.nodeName );
2362  },
2363
2364  "input": function( elem ) {
2365   return rinputs.test( elem.nodeName );
2366  },
2367
2368  "button": function( elem ) {
2369   var name = elem.nodeName.toLowerCase();
2370   return name === "input" && elem.type === "button" || name === "button";
2371  },
2372
2373  "text": function( elem ) {
2374   var attr;
2375   return elem.nodeName.toLowerCase() === "input" &&
2376    elem.type === "text" &&
2377
2378    // Support: IE<8
2379    // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
2380    ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
2381  },
2382
2383  // Position-in-collection
2384  "first": createPositionalPseudo(function() {
2385   return [ 0 ];
2386  }),
2387
2388  "last": createPositionalPseudo(function( matchIndexes, length ) {
2389   return [ length - 1 ];
2390  }),
2391
2392  "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2393   return [ argument < 0 ? argument + length : argument ];
2394  }),
2395
2396  "even": createPositionalPseudo(function( matchIndexes, length ) {
2397   var i = 0;
2398   for ( ; i < length; i += 2 ) {
2399    matchIndexes.push( i );
2400   }
2401   return matchIndexes;
2402  }),
2403
2404  "odd": createPositionalPseudo(function( matchIndexes, length ) {
2405   var i = 1;
2406   for ( ; i < length; i += 2 ) {
2407    matchIndexes.push( i );
2408   }
2409   return matchIndexes;
2410  }),
2411
2412  "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2413   var i = argument < 0 ? argument + length : argument;
2414   for ( ; --i >= 0; ) {
2415    matchIndexes.push( i );
2416   }
2417   return matchIndexes;
2418  }),
2419
2420  "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2421   var i = argument < 0 ? argument + length : argument;
2422   for ( ; ++i < length; ) {
2423    matchIndexes.push( i );
2424   }
2425   return matchIndexes;
2426  })
2427 }
2428};
2429
2430Expr.pseudos["nth"] = Expr.pseudos["eq"];
2431
2432// Add button/input type pseudos
2433for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2434 Expr.pseudos[ i ] = createInputPseudo( i );
2435}
2436for ( i in { submit: true, reset: true } ) {
2437 Expr.pseudos[ i ] = createButtonPseudo( i );
2438}
2439
2440// Easy API for creating new setFilters
2441function setFilters() {}
2442setFilters.prototype = Expr.filters = Expr.pseudos;
2443Expr.setFilters = new setFilters();
2444
2445tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
2446 var matched, match, tokens, type,
2447  soFar, groups, preFilters,
2448  cached = tokenCache[ selector + " " ];
2449
2450 if ( cached ) {
2451  return parseOnly ? 0 : cached.slice( 0 );
2452 }
2453
2454 soFar = selector;
2455 groups = [];
2456 preFilters = Expr.preFilter;
2457
2458 while ( soFar ) {
2459
2460  // Comma and first run
2461  if ( !matched || (match = rcomma.exec( soFar )) ) {
2462   if ( match ) {
2463    // Don't consume trailing commas as valid
2464    soFar = soFar.slice( match[0].length ) || soFar;
2465   }
2466   groups.push( (tokens = []) );
2467  }
2468
2469  matched = false;
2470
2471  // Combinators
2472  if ( (match = rcombinators.exec( soFar )) ) {
2473   matched = match.shift();
2474   tokens.push({
2475    value: matched,
2476    // Cast descendant combinators to space
2477    type: match[0].replace( rtrim, " " )
2478   });
2479   soFar = soFar.slice( matched.length );
2480  }
2481
2482  // Filters
2483  for ( type in Expr.filter ) {
2484   if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2485    (match = preFilters[ type ]( match ))) ) {
2486    matched = match.shift();
2487    tokens.push({
2488     value: matched,
2489     type: type,
2490     matches: match
2491    });
2492    soFar = soFar.slice( matched.length );
2493   }
2494  }
2495
2496  if ( !matched ) {
2497   break;
2498  }
2499 }
2500
2501 // Return the length of the invalid excess
2502 // if we're just parsing
2503 // Otherwise, throw an error or return tokens
2504 return parseOnly ?
2505  soFar.length :
2506  soFar ?
2507   Sizzle.error( selector ) :
2508   // Cache the tokens
2509   tokenCache( selector, groups ).slice( 0 );
2510};
2511
2512function toSelector( tokens ) {
2513 var i = 0,
2514  len = tokens.length,
2515  selector = "";
2516 for ( ; i < len; i++ ) {
2517  selector += tokens[i].value;
2518 }
2519 return selector;
2520}
2521
2522function addCombinator( matcher, combinator, base ) {
2523 var dir = combinator.dir,
2524  checkNonElements = base && dir === "parentNode",
2525  doneName = done++;
2526
2527 return combinator.first ?
2528  // Check against closest ancestor/preceding element
2529  function( elem, context, xml ) {
2530   while ( (elem = elem[ dir ]) ) {
2531    if ( elem.nodeType === 1 || checkNonElements ) {
2532     return matcher( elem, context, xml );
2533    }
2534   }
2535  } :
2536
2537  // Check against all ancestor/preceding elements
2538  function( elem, context, xml ) {
2539   var oldCache, outerCache,
2540    newCache = [ dirruns, doneName ];
2541
2542   // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
2543   if ( xml ) {
2544    while ( (elem = elem[ dir ]) ) {
2545     if ( elem.nodeType === 1 || checkNonElements ) {
2546      if ( matcher( elem, context, xml ) ) {
2547       return true;
2548      }
2549     }
2550    }
2551   } else {
2552    while ( (elem = elem[ dir ]) ) {
2553     if ( elem.nodeType === 1 || checkNonElements ) {
2554      outerCache = elem[ expando ] || (elem[ expando ] = {});
2555      if ( (oldCache = outerCache[ dir ]) &&
2556       oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
2557
2558       // Assign to newCache so results back-propagate to previous elements
2559       return (newCache[ 2 ] = oldCache[ 2 ]);
2560      } else {
2561       // Reuse newcache so results back-propagate to previous elements
2562       outerCache[ dir ] = newCache;
2563
2564       // A match means we're done; a fail means we have to keep checking
2565       if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
2566        return true;
2567       }
2568      }
2569     }
2570    }
2571   }
2572  };
2573}
2574
2575function elementMatcher( matchers ) {
2576 return matchers.length > 1 ?
2577  function( elem, context, xml ) {
2578   var i = matchers.length;
2579   while ( i-- ) {
2580    if ( !matchers[i]( elem, context, xml ) ) {
2581     return false;
2582    }
2583   }
2584   return true;
2585  } :
2586  matchers[0];
2587}
2588
2589function multipleContexts( selector, contexts, results ) {
2590 var i = 0,
2591  len = contexts.length;
2592 for ( ; i < len; i++ ) {
2593  Sizzle( selector, contexts[i], results );
2594 }
2595 return results;
2596}
2597
2598function condense( unmatched, map, filter, context, xml ) {
2599 var elem,
2600  newUnmatched = [],
2601  i = 0,
2602  len = unmatched.length,
2603  mapped = map != null;
2604
2605 for ( ; i < len; i++ ) {
2606  if ( (elem = unmatched[i]) ) {
2607   if ( !filter || filter( elem, context, xml ) ) {
2608    newUnmatched.push( elem );
2609    if ( mapped ) {
2610     map.push( i );
2611    }
2612   }
2613  }
2614 }
2615
2616 return newUnmatched;
2617}
2618
2619function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2620 if ( postFilter && !postFilter[ expando ] ) {
2621  postFilter = setMatcher( postFilter );
2622 }
2623 if ( postFinder && !postFinder[ expando ] ) {
2624  postFinder = setMatcher( postFinder, postSelector );
2625 }
2626 return markFunction(function( seed, results, context, xml ) {
2627  var temp, i, elem,
2628   preMap = [],
2629   postMap = [],
2630   preexisting = results.length,
2631
2632   // Get initial elements from seed or context
2633   elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2634
2635   // Prefilter to get matcher input, preserving a map for seed-results synchronization
2636   matcherIn = preFilter && ( seed || !selector ) ?
2637    condense( elems, preMap, preFilter, context, xml ) :
2638    elems,
2639
2640   matcherOut = matcher ?
2641    // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2642    postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2643
2644     // ...intermediate processing is necessary
2645     [] :
2646
2647     // ...otherwise use results directly
2648     results :
2649    matcherIn;
2650
2651  // Find primary matches
2652  if ( matcher ) {
2653   matcher( matcherIn, matcherOut, context, xml );
2654  }
2655
2656  // Apply postFilter
2657  if ( postFilter ) {
2658   temp = condense( matcherOut, postMap );
2659   postFilter( temp, [], context, xml );
2660
2661   // Un-match failing elements by moving them back to matcherIn
2662   i = temp.length;
2663   while ( i-- ) {
2664    if ( (elem = temp[i]) ) {
2665     matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2666    }
2667   }
2668  }
2669
2670  if ( seed ) {
2671   if ( postFinder || preFilter ) {
2672    if ( postFinder ) {
2673     // Get the final matcherOut by condensing this intermediate into postFinder contexts
2674     temp = [];
2675     i = matcherOut.length;
2676     while ( i-- ) {
2677      if ( (elem = matcherOut[i]) ) {
2678       // Restore matcherIn since elem is not yet a final match
2679       temp.push( (matcherIn[i] = elem) );
2680      }
2681     }
2682     postFinder( null, (matcherOut = []), temp, xml );
2683    }
2684
2685    // Move matched elements from seed to results to keep them synchronized
2686    i = matcherOut.length;
2687    while ( i-- ) {
2688     if ( (elem = matcherOut[i]) &&
2689      (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
2690
2691      seed[temp] = !(results[temp] = elem);
2692     }
2693    }
2694   }
2695
2696  // Add elements to results, through postFinder if defined
2697  } else {
2698   matcherOut = condense(
2699    matcherOut === results ?
2700     matcherOut.splice( preexisting, matcherOut.length ) :
2701     matcherOut
2702   );
2703   if ( postFinder ) {
2704    postFinder( null, results, matcherOut, xml );
2705   } else {
2706    push.apply( results, matcherOut );
2707   }
2708  }
2709 });
2710}
2711
2712function matcherFromTokens( tokens ) {
2713 var checkContext, matcher, j,
2714  len = tokens.length,
2715  leadingRelative = Expr.relative[ tokens[0].type ],
2716  implicitRelative = leadingRelative || Expr.relative[" "],
2717  i = leadingRelative ? 1 : 0,
2718
2719  // The foundational matcher ensures that elements are reachable from top-level context(s)
2720  matchContext = addCombinator( function( elem ) {
2721   return elem === checkContext;
2722  }, implicitRelative, true ),
2723  matchAnyContext = addCombinator( function( elem ) {
2724   return indexOf.call( checkContext, elem ) > -1;
2725  }, implicitRelative, true ),
2726  matchers = [ function( elem, context, xml ) {
2727   return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2728    (checkContext = context).nodeType ?
2729     matchContext( elem, context, xml ) :
2730     matchAnyContext( elem, context, xml ) );
2731  } ];
2732
2733 for ( ; i < len; i++ ) {
2734  if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2735   matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2736  } else {
2737   matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2738
2739   // Return special upon seeing a positional matcher
2740   if ( matcher[ expando ] ) {
2741    // Find the next relative operator (if any) for proper handling
2742    j = ++i;
2743    for ( ; j < len; j++ ) {
2744     if ( Expr.relative[ tokens[j].type ] ) {
2745      break;
2746     }
2747    }
2748    return setMatcher(
2749     i > 1 && elementMatcher( matchers ),
2750     i > 1 && toSelector(
2751      // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2752      tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2753     ).replace( rtrim, "$1" ),
2754     matcher,
2755     i < j && matcherFromTokens( tokens.slice( i, j ) ),
2756     j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2757     j < len && toSelector( tokens )
2758    );
2759   }
2760   matchers.push( matcher );
2761  }
2762 }
2763
2764 return elementMatcher( matchers );
2765}
2766
2767function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2768 var bySet = setMatchers.length > 0,
2769  byElement = elementMatchers.length > 0,
2770  superMatcher = function( seed, context, xml, results, outermost ) {
2771   var elem, j, matcher,
2772    matchedCount = 0,
2773    i = "0",
2774    unmatched = seed && [],
2775    setMatched = [],
2776    contextBackup = outermostContext,
2777    // We must always have either seed elements or outermost context
2778    elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
2779    // Use integer dirruns iff this is the outermost matcher
2780    dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
2781    len = elems.length;
2782
2783   if ( outermost ) {
2784    outermostContext = context !== document && context;
2785   }
2786
2787   // Add elements passing elementMatchers directly to results
2788   // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
2789   // Support: IE<9, Safari
2790   // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
2791   for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
2792    if ( byElement && elem ) {
2793     j = 0;
2794     while ( (matcher = elementMatchers[j++]) ) {
2795      if ( matcher( elem, context, xml ) ) {
2796       results.push( elem );
2797       break;
2798      }
2799     }
2800     if ( outermost ) {
2801      dirruns = dirrunsUnique;
2802     }
2803    }
2804
2805    // Track unmatched elements for set filters
2806    if ( bySet ) {
2807     // They will have gone through all possible matchers
2808     if ( (elem = !matcher && elem) ) {
2809      matchedCount--;
2810     }
2811
2812     // Lengthen the array for every element, matched or not
2813     if ( seed ) {
2814      unmatched.push( elem );
2815     }
2816    }
2817   }
2818
2819   // Apply set filters to unmatched elements
2820   matchedCount += i;
2821   if ( bySet && i !== matchedCount ) {
2822    j = 0;
2823    while ( (matcher = setMatchers[j++]) ) {
2824     matcher( unmatched, setMatched, context, xml );
2825    }
2826
2827    if ( seed ) {
2828     // Reintegrate element matches to eliminate the need for sorting
2829     if ( matchedCount > 0 ) {
2830      while ( i-- ) {
2831       if ( !(unmatched[i] || setMatched[i]) ) {
2832        setMatched[i] = pop.call( results );
2833       }
2834      }
2835     }
2836
2837     // Discard index placeholder values to get only actual matches
2838     setMatched = condense( setMatched );
2839    }
2840
2841    // Add matches to results
2842    push.apply( results, setMatched );
2843
2844    // Seedless set matches succeeding multiple successful matchers stipulate sorting
2845    if ( outermost && !seed && setMatched.length > 0 &&
2846     ( matchedCount + setMatchers.length ) > 1 ) {
2847
2848     Sizzle.uniqueSort( results );
2849    }
2850   }
2851
2852   // Override manipulation of globals by nested matchers
2853   if ( outermost ) {
2854    dirruns = dirrunsUnique;
2855    outermostContext = contextBackup;
2856   }
2857
2858   return unmatched;
2859  };
2860
2861 return bySet ?
2862  markFunction( superMatcher ) :
2863  superMatcher;
2864}
2865
2866compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
2867 var i,
2868  setMatchers = [],
2869  elementMatchers = [],
2870  cached = compilerCache[ selector + " " ];
2871
2872 if ( !cached ) {
2873  // Generate a function of recursive functions that can be used to check each element
2874  if ( !match ) {
2875   match = tokenize( selector );
2876  }
2877  i = match.length;
2878  while ( i-- ) {
2879   cached = matcherFromTokens( match[i] );
2880   if ( cached[ expando ] ) {
2881    setMatchers.push( cached );
2882   } else {
2883    elementMatchers.push( cached );
2884   }
2885  }
2886
2887  // Cache the compiled function
2888  cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2889
2890  // Save selector and tokenization
2891  cached.selector = selector;
2892 }
2893 return cached;
2894};
2895
2896/**
2897 * A low-level selection function that works with Sizzle's compiled
2898 *  selector functions
2899 * @param {String|Function} selector A selector or a pre-compiled
2900 *  selector function built with Sizzle.compile
2901 * @param {Element} context
2902 * @param {Array} [results]
2903 * @param {Array} [seed] A set of elements to match against
2904 */
2905select = Sizzle.select = function( selector, context, results, seed ) {
2906 var i, tokens, token, type, find,
2907  compiled = typeof selector === "function" && selector,
2908  match = !seed && tokenize( (selector = compiled.selector || selector) );
2909
2910 results = results || [];
2911
2912 // Try to minimize operations if there is no seed and only one group
2913 if ( match.length === 1 ) {
2914
2915  // Take a shortcut and set the context if the root selector is an ID
2916  tokens = match[0] = match[0].slice( 0 );
2917  if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2918    support.getById && context.nodeType === 9 && documentIsHTML &&
2919    Expr.relative[ tokens[1].type ] ) {
2920
2921   context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2922   if ( !context ) {
2923    return results;
2924
2925   // Precompiled matchers will still verify ancestry, so step up a level
2926   } else if ( compiled ) {
2927    context = context.parentNode;
2928   }
2929
2930   selector = selector.slice( tokens.shift().value.length );
2931  }
2932
2933  // Fetch a seed set for right-to-left matching
2934  i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2935  while ( i-- ) {
2936   token = tokens[i];
2937
2938   // Abort if we hit a combinator
2939   if ( Expr.relative[ (type = token.type) ] ) {
2940    break;
2941   }
2942   if ( (find = Expr.find[ type ]) ) {
2943    // Search, expanding context for leading sibling combinators
2944    if ( (seed = find(
2945     token.matches[0].replace( runescape, funescape ),
2946     rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
2947    )) ) {
2948
2949     // If seed is empty or no tokens remain, we can return early
2950     tokens.splice( i, 1 );
2951     selector = seed.length && toSelector( tokens );
2952     if ( !selector ) {
2953      push.apply( results, seed );
2954      return results;
2955     }
2956
2957     break;
2958    }
2959   }
2960  }
2961 }
2962
2963 // Compile and execute a filtering function if one is not provided
2964 // Provide `match` to avoid retokenization if we modified the selector above
2965 ( compiled || compile( selector, match ) )(
2966  seed,
2967  context,
2968  !documentIsHTML,
2969  results,
2970  rsibling.test( selector ) && testContext( context.parentNode ) || context
2971 );
2972 return results;
2973};
2974
2975// One-time assignments
2976
2977// Sort stability
2978support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2979
2980// Support: Chrome<14
2981// Always assume duplicates if they aren't passed to the comparison function
2982support.detectDuplicates = !!hasDuplicate;
2983
2984// Initialize against the default document
2985setDocument();
2986
2987// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2988// Detached nodes confoundingly follow *each other*
2989support.sortDetached = assert(function( div1 ) {
2990 // Should return 1, but returns 4 (following)
2991 return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2992});
2993
2994// Support: IE<8
2995// Prevent attribute/property "interpolation"
2996// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2997if ( !assert(function( div ) {
2998 div.innerHTML = "<a href='#'></a>";
2999 return div.firstChild.getAttribute("href") === "#" ;
3000}) ) {
3001 addHandle( "type|href|height|width", function( elem, name, isXML ) {
3002  if ( !isXML ) {
3003   return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
3004  }
3005 });
3006}
3007
3008// Support: IE<9
3009// Use defaultValue in place of getAttribute("value")
3010if ( !support.attributes || !assert(function( div ) {
3011 div.innerHTML = "<input/>";
3012 div.firstChild.setAttribute( "value", "" );
3013 return div.firstChild.getAttribute( "value" ) === "";
3014}) ) {
3015 addHandle( "value", function( elem, name, isXML ) {
3016  if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
3017   return elem.defaultValue;
3018  }
3019 });
3020}
3021
3022// Support: IE<9
3023// Use getAttributeNode to fetch booleans when getAttribute lies
3024if ( !assert(function( div ) {
3025 return div.getAttribute("disabled") == null;
3026}) ) {
3027 addHandle( booleans, function( elem, name, isXML ) {
3028  var val;
3029  if ( !isXML ) {
3030   return elem[ name ] === true ? name.toLowerCase() :
3031     (val = elem.getAttributeNode( name )) && val.specified ?
3032     val.value :
3033    null;
3034  }
3035 });
3036}
3037
3038return Sizzle;
3039
3040})( window );
3041
3042jQuery.find = Sizzle;
3043jQuery.expr = Sizzle.selectors;
3044jQuery.expr[":"] = jQuery.expr.pseudos;
3045jQuery.unique = Sizzle.uniqueSort;
3046jQuery.text = Sizzle.getText;
3047jQuery.isXMLDoc = Sizzle.isXML;
3048jQuery.contains = Sizzle.contains;
3049
3050var rneedsContext = jQuery.expr.match.needsContext;
3051
3052var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
3053
3054var risSimple = /^.[^:#\[\.,]*$/;
3055
3056// Implement the identical functionality for filter and not
3057function winnow( elements, qualifier, not ) {
3058 if ( jQuery.isFunction( qualifier ) ) {
3059  return jQuery.grep( elements, function( elem, i ) {
3060   /* jshint -W018 */
3061   return !!qualifier.call( elem, i, elem ) !== not;
3062  });
3063
3064 }
3065
3066 if ( qualifier.nodeType ) {
3067  return jQuery.grep( elements, function( elem ) {
3068   return ( elem === qualifier ) !== not;
3069  });
3070
3071 }
3072
3073 if ( typeof qualifier === "string" ) {
3074  if ( risSimple.test( qualifier ) ) {
3075   return jQuery.filter( qualifier, elements, not );
3076  }
3077
3078  qualifier = jQuery.filter( qualifier, elements );
3079 }
3080
3081 return jQuery.grep( elements, function( elem ) {
3082  return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
3083 });
3084}
3085
3086jQuery.filter = function( expr, elems, not ) {
3087 var elem = elems[ 0 ];
3088
3089 if ( not ) {
3090  expr = ":not(" + expr + ")";
3091 }
3092
3093 return elems.length === 1 && elem.nodeType === 1 ?
3094  jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
3095  jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
3096   return elem.nodeType === 1;
3097  }));
3098};
3099
3100jQuery.fn.extend({
3101 find: function( selector ) {
3102  var i,
3103   ret = [],
3104   self = this,
3105   len = self.length;
3106
3107  if ( typeof selector !== "string" ) {
3108   return this.pushStack( jQuery( selector ).filter(function() {
3109    for ( i = 0; i < len; i++ ) {
3110     if ( jQuery.contains( self[ i ], this ) ) {
3111      return true;
3112     }
3113    }
3114   }) );
3115  }
3116
3117  for ( i = 0; i < len; i++ ) {
3118   jQuery.find( selector, self[ i ], ret );
3119  }
3120
3121  // Needed because $( selector, context ) becomes $( context ).find( selector )
3122  ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
3123  ret.selector = this.selector ? this.selector + " " + selector : selector;
3124  return ret;
3125 },
3126 filter: function( selector ) {
3127  return this.pushStack( winnow(this, selector || [], false) );
3128 },
3129 not: function( selector ) {
3130  return this.pushStack( winnow(this, selector || [], true) );
3131 },
3132 is: function( selector ) {
3133  return !!winnow(
3134   this,
3135
3136   // If this is a positional/relative selector, check membership in the returned set
3137   // so $("p:first").is("p:last") won't return true for a doc with two "p".
3138   typeof selector === "string" && rneedsContext.test( selector ) ?
3139    jQuery( selector ) :
3140    selector || [],
3141   false
3142  ).length;
3143 }
3144});
3145
3146// Initialize a jQuery object
3147
3148// A central reference to the root jQuery(document)
3149var rootjQuery,
3150
3151 // Use the correct document accordingly with window argument (sandbox)
3152 document = window.document,
3153
3154 // A simple way to check for HTML strings
3155 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
3156 // Strict HTML recognition (#11290: must start with <)
3157 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
3158
3159 init = jQuery.fn.init = function( selector, context ) {
3160  var match, elem;
3161
3162  // HANDLE: $(""), $(null), $(undefined), $(false)
3163  if ( !selector ) {
3164   return this;
3165  }
3166
3167  // Handle HTML strings
3168  if ( typeof selector === "string" ) {
3169   if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
3170    // Assume that strings that start and end with <> are HTML and skip the regex check
3171    match = [ null, selector, null ];
3172
3173   } else {
3174    match = rquickExpr.exec( selector );
3175   }
3176
3177   // Match html or make sure no context is specified for #id
3178   if ( match && (match[1] || !context) ) {
3179
3180    // HANDLE: $(html) -> $(array)
3181    if ( match[1] ) {
3182     context = context instanceof jQuery ? context[0] : context;
3183
3184     // scripts is true for back-compat
3185     // Intentionally let the error be thrown if parseHTML is not present
3186     jQuery.merge( this, jQuery.parseHTML(
3187      match[1],
3188      context && context.nodeType ? context.ownerDocument || context : document,
3189      true
3190     ) );
3191
3192     // HANDLE: $(html, props)
3193     if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
3194      for ( match in context ) {
3195       // Properties of context are called as methods if possible
3196       if ( jQuery.isFunction( this[ match ] ) ) {
3197        this[ match ]( context[ match ] );
3198
3199       // ...and otherwise set as attributes
3200       } else {
3201        this.attr( match, context[ match ] );
3202       }
3203      }
3204     }
3205
3206     return this;
3207
3208    // HANDLE: $(#id)
3209    } else {
3210     elem = document.getElementById( match[2] );
3211
3212     // Check parentNode to catch when Blackberry 4.6 returns
3213     // nodes that are no longer in the document #6963
3214     if ( elem && elem.parentNode ) {
3215      // Handle the case where IE and Opera return items
3216      // by name instead of ID
3217      if ( elem.id !== match[2] ) {
3218       return rootjQuery.find( selector );
3219      }
3220
3221      // Otherwise, we inject the element directly into the jQuery object
3222      this.length = 1;
3223      this[0] = elem;
3224     }
3225
3226     this.context = document;
3227     this.selector = selector;
3228     return this;
3229    }
3230
3231   // HANDLE: $(expr, $(...))
3232   } else if ( !context || context.jquery ) {
3233    return ( context || rootjQuery ).find( selector );
3234
3235   // HANDLE: $(expr, context)
3236   // (which is just equivalent to: $(context).find(expr)
3237   } else {
3238    return this.constructor( context ).find( selector );
3239   }
3240
3241  // HANDLE: $(DOMElement)
3242  } else if ( selector.nodeType ) {
3243   this.context = this[0] = selector;
3244   this.length = 1;
3245   return this;
3246
3247  // HANDLE: $(function)
3248  // Shortcut for document ready
3249  } else if ( jQuery.isFunction( selector ) ) {
3250   return typeof rootjQuery.ready !== "undefined" ?
3251    rootjQuery.ready( selector ) :
3252    // Execute immediately if ready is not present
3253    selector( jQuery );
3254  }
3255
3256  if ( selector.selector !== undefined ) {
3257   this.selector = selector.selector;
3258   this.context = selector.context;
3259  }
3260
3261  return jQuery.makeArray( selector, this );
3262 };
3263
3264// Give the init function the jQuery prototype for later instantiation
3265init.prototype = jQuery.fn;
3266
3267// Initialize central reference
3268rootjQuery = jQuery( document );
3269
3270var rparentsprev = /^(?:parents|prev(?:Until|All))/,
3271 // methods guaranteed to produce a unique set when starting from a unique set
3272 guaranteedUnique = {
3273  children: true,
3274  contents: true,
3275  next: true,
3276  prev: true
3277 };
3278
3279jQuery.extend({
3280 dir: function( elem, dir, until ) {
3281  var matched = [],
3282   cur = elem[ dir ];
3283
3284  while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
3285   if ( cur.nodeType === 1 ) {
3286    matched.push( cur );
3287   }
3288   cur = cur[dir];
3289  }
3290  return matched;
3291 },
3292
3293 sibling: function( n, elem ) {
3294  var r = [];
3295
3296  for ( ; n; n = n.nextSibling ) {
3297   if ( n.nodeType === 1 && n !== elem ) {
3298    r.push( n );
3299   }
3300  }
3301
3302  return r;
3303 }
3304});
3305
3306jQuery.fn.extend({
3307 has: function( target ) {
3308  var i,
3309   targets = jQuery( target, this ),
3310   len = targets.length;
3311
3312  return this.filter(function() {
3313   for ( i = 0; i < len; i++ ) {
3314    if ( jQuery.contains( this, targets[i] ) ) {
3315     return true;
3316    }
3317   }
3318  });
3319 },
3320
3321 closest: function( selectors, context ) {
3322  var cur,
3323   i = 0,
3324   l = this.length,
3325   matched = [],
3326   pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
3327    jQuery( selectors, context || this.context ) :
3328    0;
3329
3330  for ( ; i < l; i++ ) {
3331   for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
3332    // Always skip document fragments
3333    if ( cur.nodeType < 11 && (pos ?
3334     pos.index(cur) > -1 :
3335
3336     // Don't pass non-elements to Sizzle
3337     cur.nodeType === 1 &&
3338      jQuery.find.matchesSelector(cur, selectors)) ) {
3339
3340     matched.push( cur );
3341     break;
3342    }
3343   }
3344  }
3345
3346  return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
3347 },
3348
3349 // Determine the position of an element within
3350 // the matched set of elements
3351 index: function( elem ) {
3352
3353  // No argument, return index in parent
3354  if ( !elem ) {
3355   return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
3356  }
3357
3358  // index in selector
3359  if ( typeof elem === "string" ) {
3360   return jQuery.inArray( this[0], jQuery( elem ) );
3361  }
3362
3363  // Locate the position of the desired element
3364  return jQuery.inArray(
3365   // If it receives a jQuery object, the first element is used
3366   elem.jquery ? elem[0] : elem, this );
3367 },
3368
3369 add: function( selector, context ) {
3370  return this.pushStack(
3371   jQuery.unique(
3372    jQuery.merge( this.get(), jQuery( selector, context ) )
3373   )
3374  );
3375 },
3376
3377 addBack: function( selector ) {
3378  return this.add( selector == null ?
3379   this.prevObject : this.prevObject.filter(selector)
3380  );
3381 }
3382});
3383
3384function sibling( cur, dir ) {
3385 do {
3386  cur = cur[ dir ];
3387 } while ( cur && cur.nodeType !== 1 );
3388
3389 return cur;
3390}
3391
3392jQuery.each({
3393 parent: function( elem ) {
3394  var parent = elem.parentNode;
3395  return parent && parent.nodeType !== 11 ? parent : null;
3396 },
3397 parents: function( elem ) {
3398  return jQuery.dir( elem, "parentNode" );
3399 },
3400 parentsUntil: function( elem, i, until ) {
3401  return jQuery.dir( elem, "parentNode", until );
3402 },
3403 next: function( elem ) {
3404  return sibling( elem, "nextSibling" );
3405 },
3406 prev: function( elem ) {
3407  return sibling( elem, "previousSibling" );
3408 },
3409 nextAll: function( elem ) {
3410  return jQuery.dir( elem, "nextSibling" );
3411 },
3412 prevAll: function( elem ) {
3413  return jQuery.dir( elem, "previousSibling" );
3414 },
3415 nextUntil: function( elem, i, until ) {
3416  return jQuery.dir( elem, "nextSibling", until );
3417 },
3418 prevUntil: function( elem, i, until ) {
3419  return jQuery.dir( elem, "previousSibling", until );
3420 },
3421 siblings: function( elem ) {
3422  return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
3423 },
3424 children: function( elem ) {
3425  return jQuery.sibling( elem.firstChild );
3426 },
3427 contents: function( elem ) {
3428  return jQuery.nodeName( elem, "iframe" ) ?
3429   elem.contentDocument || elem.contentWindow.document :
3430   jQuery.merge( [], elem.childNodes );
3431 }
3432}, function( name, fn ) {
3433 jQuery.fn[ name ] = function( until, selector ) {
3434  var ret = jQuery.map( this, fn, until );
3435
3436  if ( name.slice( -5 ) !== "Until" ) {
3437   selector = until;
3438  }
3439
3440  if ( selector && typeof selector === "string" ) {
3441   ret = jQuery.filter( selector, ret );
3442  }
3443
3444  if ( this.length > 1 ) {
3445   // Remove duplicates
3446   if ( !guaranteedUnique[ name ] ) {
3447    ret = jQuery.unique( ret );
3448   }
3449
3450   // Reverse order for parents* and prev-derivatives
3451   if ( rparentsprev.test( name ) ) {
3452    ret = ret.reverse();
3453   }
3454  }
3455
3456  return this.pushStack( ret );
3457 };
3458});
3459var rnotwhite = (/\S+/g);
3460
3461// String to Object options format cache
3462var optionsCache = {};
3463
3464// Convert String-formatted options into Object-formatted ones and store in cache
3465function createOptions( options ) {
3466 var object = optionsCache[ options ] = {};
3467 jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
3468  object[ flag ] = true;
3469 });
3470 return object;
3471}
3472
3473/*
3474 * Create a callback list using the following parameters:
3475 *
3476 * options: an optional list of space-separated options that will change how
3477 *   the callback list behaves or a more traditional option object
3478 *
3479 * By default a callback list will act like an event callback list and can be
3480 * "fired" multiple times.
3481 *
3482 * Possible options:
3483 *
3484 * once:   will ensure the callback list can only be fired once (like a Deferred)
3485 *
3486 * memory:   will keep track of previous values and will call any callback added
3487 *     after the list has been fired right away with the latest "memorized"
3488 *     values (like a Deferred)
3489 *
3490 * unique:   will ensure a callback can only be added once (no duplicate in the list)
3491 *
3492 * stopOnFalse: interrupt callings when a callback returns false
3493 *
3494 */
3495jQuery.Callbacks = function( options ) {
3496
3497 // Convert options from String-formatted to Object-formatted if needed
3498 // (we check in cache first)
3499 options = typeof options === "string" ?
3500  ( optionsCache[ options ] || createOptions( options ) ) :
3501  jQuery.extend( {}, options );
3502
3503 var // Flag to know if list is currently firing
3504  firing,
3505  // Last fire value (for non-forgettable lists)
3506  memory,
3507  // Flag to know if list was already fired
3508  fired,
3509  // End of the loop when firing
3510  firingLength,
3511  // Index of currently firing callback (modified by remove if needed)
3512  firingIndex,
3513  // First callback to fire (used internally by add and fireWith)
3514  firingStart,
3515  // Actual callback list
3516  list = [],
3517  // Stack of fire calls for repeatable lists
3518  stack = !options.once && [],
3519  // Fire callbacks
3520  fire = function( data ) {
3521   memory = options.memory && data;
3522   fired = true;
3523   firingIndex = firingStart || 0;
3524   firingStart = 0;
3525   firingLength = list.length;
3526   firing = true;
3527   for ( ; list && firingIndex < firingLength; firingIndex++ ) {
3528    if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
3529     memory = false; // To prevent further calls using add
3530     break;
3531    }
3532   }
3533   firing = false;
3534   if ( list ) {
3535    if ( stack ) {
3536     if ( stack.length ) {
3537      fire( stack.shift() );
3538     }
3539    } else if ( memory ) {
3540     list = [];
3541    } else {
3542     self.disable();
3543    }
3544   }
3545  },
3546  // Actual Callbacks object
3547  self = {
3548   // Add a callback or a collection of callbacks to the list
3549   add: function() {
3550    if ( list ) {
3551     // First, we save the current length
3552     var start = list.length;
3553     (function add( args ) {
3554      jQuery.each( args, function( _, arg ) {
3555       var type = jQuery.type( arg );
3556       if ( type === "function" ) {
3557        if ( !options.unique || !self.has( arg ) ) {
3558         list.push( arg );
3559        }
3560       } else if ( arg && arg.length && type !== "string" ) {
3561        // Inspect recursively
3562        add( arg );
3563       }
3564      });
3565     })( arguments );
3566     // Do we need to add the callbacks to the
3567     // current firing batch?
3568     if ( firing ) {
3569      firingLength = list.length;
3570     // With memory, if we're not firing then
3571     // we should call right away
3572     } else if ( memory ) {
3573      firingStart = start;
3574      fire( memory );
3575     }
3576    }
3577    return this;
3578   },
3579   // Remove a callback from the list
3580   remove: function() {
3581    if ( list ) {
3582     jQuery.each( arguments, function( _, arg ) {
3583      var index;
3584      while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3585       list.splice( index, 1 );
3586       // Handle firing indexes
3587       if ( firing ) {
3588        if ( index <= firingLength ) {
3589         firingLength--;
3590        }
3591        if ( index <= firingIndex ) {
3592         firingIndex--;
3593        }
3594       }
3595      }
3596     });
3597    }
3598    return this;
3599   },
3600   // Check if a given callback is in the list.
3601   // If no argument is given, return whether or not list has callbacks attached.
3602   has: function( fn ) {
3603    return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
3604   },
3605   // Remove all callbacks from the list
3606   empty: function() {
3607    list = [];
3608    firingLength = 0;
3609    return this;
3610   },
3611   // Have the list do nothing anymore
3612   disable: function() {
3613    list = stack = memory = undefined;
3614    return this;
3615   },
3616   // Is it disabled?
3617   disabled: function() {
3618    return !list;
3619   },
3620   // Lock the list in its current state
3621   lock: function() {
3622    stack = undefined;
3623    if ( !memory ) {
3624     self.disable();
3625    }
3626    return this;
3627   },
3628   // Is it locked?
3629   locked: function() {
3630    return !stack;
3631   },
3632   // Call all callbacks with the given context and arguments
3633   fireWith: function( context, args ) {
3634    if ( list && ( !fired || stack ) ) {
3635     args = args || [];
3636     args = [ context, args.slice ? args.slice() : args ];
3637     if ( firing ) {
3638      stack.push( args );
3639     } else {
3640      fire( args );
3641     }
3642    }
3643    return this;
3644   },
3645   // Call all the callbacks with the given arguments
3646   fire: function() {
3647    self.fireWith( this, arguments );
3648    return this;
3649   },
3650   // To know if the callbacks have already been called at least once
3651   fired: function() {
3652    return !!fired;
3653   }
3654  };
3655
3656 return self;
3657};
3658
3659jQuery.extend({
3660
3661 Deferred: function( func ) {
3662  var tuples = [
3663    // action, add listener, listener list, final state
3664    [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
3665    [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
3666    [ "notify", "progress", jQuery.Callbacks("memory") ]
3667   ],
3668   state = "pending",
3669   promise = {
3670    state: function() {
3671     return state;
3672    },
3673    always: function() {
3674     deferred.done( arguments ).fail( arguments );
3675     return this;
3676    },
3677    then: function( /* fnDone, fnFail, fnProgress */ ) {
3678     var fns = arguments;
3679     return jQuery.Deferred(function( newDefer ) {
3680      jQuery.each( tuples, function( i, tuple ) {
3681       var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3682       // deferred[ done | fail | progress ] for forwarding actions to newDefer
3683       deferred[ tuple[1] ](function() {
3684        var returned = fn && fn.apply( this, arguments );
3685        if ( returned && jQuery.isFunction( returned.promise ) ) {
3686         returned.promise()
3687          .done( newDefer.resolve )
3688          .fail( newDefer.reject )
3689          .progress( newDefer.notify );
3690        } else {
3691         newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
3692        }
3693       });
3694      });
3695      fns = null;
3696     }).promise();
3697    },
3698    // Get a promise for this deferred
3699    // If obj is provided, the promise aspect is added to the object
3700    promise: function( obj ) {
3701     return obj != null ? jQuery.extend( obj, promise ) : promise;
3702    }
3703   },
3704   deferred = {};
3705
3706  // Keep pipe for back-compat
3707  promise.pipe = promise.then;
3708
3709  // Add list-specific methods
3710  jQuery.each( tuples, function( i, tuple ) {
3711   var list = tuple[ 2 ],
3712    stateString = tuple[ 3 ];
3713
3714   // promise[ done | fail | progress ] = list.add
3715   promise[ tuple[1] ] = list.add;
3716
3717   // Handle state
3718   if ( stateString ) {
3719    list.add(function() {
3720     // state = [ resolved | rejected ]
3721     state = stateString;
3722
3723    // [ reject_list | resolve_list ].disable; progress_list.lock
3724    }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3725   }
3726
3727   // deferred[ resolve | reject | notify ]
3728   deferred[ tuple[0] ] = function() {
3729    deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
3730    return this;
3731   };
3732   deferred[ tuple[0] + "With" ] = list.fireWith;
3733  });
3734
3735  // Make the deferred a promise
3736  promise.promise( deferred );
3737
3738  // Call given func if any
3739  if ( func ) {
3740   func.call( deferred, deferred );
3741  }
3742
3743  // All done!
3744  return deferred;
3745 },
3746
3747 // Deferred helper
3748 when: function( subordinate /* , ..., subordinateN */ ) {
3749  var i = 0,
3750   resolveValues = slice.call( arguments ),
3751   length = resolveValues.length,
3752
3753   // the count of uncompleted subordinates
3754   remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3755
3756   // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
3757   deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3758
3759   // Update function for both resolve and progress values
3760   updateFunc = function( i, contexts, values ) {
3761    return function( value ) {
3762     contexts[ i ] = this;
3763     values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
3764     if ( values === progressValues ) {
3765      deferred.notifyWith( contexts, values );
3766
3767     } else if ( !(--remaining) ) {
3768      deferred.resolveWith( contexts, values );
3769     }
3770    };
3771   },
3772
3773   progressValues, progressContexts, resolveContexts;
3774
3775  // add listeners to Deferred subordinates; treat others as resolved
3776  if ( length > 1 ) {
3777   progressValues = new Array( length );
3778   progressContexts = new Array( length );
3779   resolveContexts = new Array( length );
3780   for ( ; i < length; i++ ) {
3781    if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3782     resolveValues[ i ].promise()
3783      .done( updateFunc( i, resolveContexts, resolveValues ) )
3784      .fail( deferred.reject )
3785      .progress( updateFunc( i, progressContexts, progressValues ) );
3786    } else {
3787     --remaining;
3788    }
3789   }
3790  }
3791
3792  // if we're not waiting on anything, resolve the master
3793  if ( !remaining ) {
3794   deferred.resolveWith( resolveContexts, resolveValues );
3795  }
3796
3797  return deferred.promise();
3798 }
3799});
3800
3801// The deferred used on DOM ready
3802var readyList;
3803
3804jQuery.fn.ready = function( fn ) {
3805 // Add the callback
3806 jQuery.ready.promise().done( fn );
3807
3808 return this;
3809};
3810
3811jQuery.extend({
3812 // Is the DOM ready to be used? Set to true once it occurs.
3813 isReady: false,
3814
3815 // A counter to track how many items to wait for before
3816 // the ready event fires. See #6781
3817 readyWait: 1,
3818
3819 // Hold (or release) the ready event
3820 holdReady: function( hold ) {
3821  if ( hold ) {
3822   jQuery.readyWait++;
3823  } else {
3824   jQuery.ready( true );
3825  }
3826 },
3827
3828 // Handle when the DOM is ready
3829 ready: function( wait ) {
3830
3831  // Abort if there are pending holds or we're already ready
3832  if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
3833   return;
3834  }
3835
3836  // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
3837  if ( !document.body ) {
3838   return setTimeout( jQuery.ready );
3839  }
3840
3841  // Remember that the DOM is ready
3842  jQuery.isReady = true;
3843
3844  // If a normal DOM Ready event fired, decrement, and wait if need be
3845  if ( wait !== true && --jQuery.readyWait > 0 ) {
3846   return;
3847  }
3848
3849  // If there are functions bound, to execute
3850  readyList.resolveWith( document, [ jQuery ] );
3851
3852  // Trigger any bound ready events
3853  if ( jQuery.fn.triggerHandler ) {
3854   jQuery( document ).triggerHandler( "ready" );
3855   jQuery( document ).off( "ready" );
3856  }
3857 }
3858});
3859
3860/**
3861 * Clean-up method for dom ready events
3862 */
3863function detach() {
3864 if ( document.addEventListener ) {
3865  document.removeEventListener( "DOMContentLoaded", completed, false );
3866  window.removeEventListener( "load", completed, false );
3867
3868 } else {
3869  document.detachEvent( "onreadystatechange", completed );
3870  window.detachEvent( "onload", completed );
3871 }
3872}
3873
3874/**
3875 * The ready event handler and self cleanup method
3876 */
3877function completed() {
3878 // readyState === "complete" is good enough for us to call the dom ready in oldIE
3879 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
3880  detach();
3881  jQuery.ready();
3882 }
3883}
3884
3885jQuery.ready.promise = function( obj ) {
3886 if ( !readyList ) {
3887
3888  readyList = jQuery.Deferred();
3889
3890  // Catch cases where $(document).ready() is called after the browser event has already occurred.
3891  // we once tried to use readyState "interactive" here, but it caused issues like the one
3892  // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
3893  if ( document.readyState === "complete" ) {
3894   // Handle it asynchronously to allow scripts the opportunity to delay ready
3895   setTimeout( jQuery.ready );
3896
3897  // Standards-based browsers support DOMContentLoaded
3898  } else if ( document.addEventListener ) {
3899   // Use the handy event callback
3900   document.addEventListener( "DOMContentLoaded", completed, false );
3901
3902   // A fallback to window.onload, that will always work
3903   window.addEventListener( "load", completed, false );
3904
3905  // If IE event model is used
3906  } else {
3907   // Ensure firing before onload, maybe late but safe also for iframes
3908   document.attachEvent( "onreadystatechange", completed );
3909
3910   // A fallback to window.onload, that will always work
3911   window.attachEvent( "onload", completed );
3912
3913   // If IE and not a frame
3914   // continually check to see if the document is ready
3915   var top = false;
3916
3917   try {
3918    top = window.frameElement == null && document.documentElement;
3919   } catch(e) {}
3920
3921   if ( top && top.doScroll ) {
3922    (function doScrollCheck() {
3923     if ( !jQuery.isReady ) {
3924
3925      try {
3926       // Use the trick by Diego Perini
3927       // http://javascript.nwbox.com/IEContentLoaded/
3928       top.doScroll("left");
3929      } catch(e) {
3930       return setTimeout( doScrollCheck, 50 );
3931      }
3932
3933      // detach all dom ready events
3934      detach();
3935
3936      // and execute any waiting functions
3937      jQuery.ready();
3938     }
3939    })();
3940   }
3941  }
3942 }
3943 return readyList.promise( obj );
3944};
3945
3946var strundefined = typeof undefined;
3947
3948// Support: IE<9
3949// Iteration over object's inherited properties before its own
3950var i;
3951for ( i in jQuery( support ) ) {
3952 break;
3953}
3954support.ownLast = i !== "0";
3955
3956// Note: most support tests are defined in their respective modules.
3957// false until the test is run
3958support.inlineBlockNeedsLayout = false;
3959
3960// Execute ASAP in case we need to set body.style.zoom
3961jQuery(function() {
3962 // Minified: var a,b,c,d
3963 var val, div, body, container;
3964
3965 body = document.getElementsByTagName( "body" )[ 0 ];
3966 if ( !body || !body.style ) {
3967  // Return for frameset docs that don't have a body
3968  return;
3969 }
3970
3971 // Setup
3972 div = document.createElement( "div" );
3973 container = document.createElement( "div" );
3974 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
3975 body.appendChild( container ).appendChild( div );
3976
3977 if ( typeof div.style.zoom !== strundefined ) {
3978  // Support: IE<8
3979  // Check if natively block-level elements act like inline-block
3980  // elements when setting their display to 'inline' and giving
3981  // them layout
3982  div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
3983
3984  support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
3985  if ( val ) {
3986   // Prevent IE 6 from affecting layout for positioned elements #11048
3987   // Prevent IE from shrinking the body in IE 7 mode #12869
3988   // Support: IE<8
3989   body.style.zoom = 1;
3990  }
3991 }
3992
3993 body.removeChild( container );
3994});
3995
3996(function() {
3997 var div = document.createElement( "div" );
3998
3999 // Execute the test only if not already executed in another module.
4000 if (support.deleteExpando == null) {
4001  // Support: IE<9
4002  support.deleteExpando = true;
4003  try {
4004   delete div.test;
4005  } catch( e ) {
4006   support.deleteExpando = false;
4007  }
4008 }
4009
4010 // Null elements to avoid leaks in IE.
4011 div = null;
4012})();
4013
4014/**
4015 * Determines whether an object can have data
4016 */
4017jQuery.acceptData = function( elem ) {
4018 var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
4019  nodeType = +elem.nodeType || 1;
4020
4021 // Do not set data on non-element DOM nodes because it will not be cleared (#8335).
4022 return nodeType !== 1 && nodeType !== 9 ?
4023  false :
4024
4025  // Nodes accept data unless otherwise specified; rejection can be conditional
4026  !noData || noData !== true && elem.getAttribute("classid") === noData;
4027};
4028
4029var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
4030 rmultiDash = /([A-Z])/g;
4031
4032function dataAttr( elem, key, data ) {
4033 // If nothing was found internally, try to fetch any
4034 // data from the HTML5 data-* attribute
4035 if ( data === undefined && elem.nodeType === 1 ) {
4036
4037  var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
4038
4039  data = elem.getAttribute( name );
4040
4041  if ( typeof data === "string" ) {
4042   try {
4043    data = data === "true" ? true :
4044     data === "false" ? false :
4045     data === "null" ? null :
4046     // Only convert to a number if it doesn't change the string
4047     +data + "" === data ? +data :
4048     rbrace.test( data ) ? jQuery.parseJSON( data ) :
4049     data;
4050   } catch( e ) {}
4051
4052   // Make sure we set the data so it isn't changed later
4053   jQuery.data( elem, key, data );
4054
4055  } else {
4056   data = undefined;
4057  }
4058 }
4059
4060 return data;
4061}
4062
4063// checks a cache object for emptiness
4064function isEmptyDataObject( obj ) {
4065 var name;
4066 for ( name in obj ) {
4067
4068  // if the public data object is empty, the private is still empty
4069  if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
4070   continue;
4071  }
4072  if ( name !== "toJSON" ) {
4073   return false;
4074  }
4075 }
4076
4077 return true;
4078}
4079
4080function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
4081 if ( !jQuery.acceptData( elem ) ) {
4082  return;
4083 }
4084
4085 var ret, thisCache,
4086  internalKey = jQuery.expando,
4087
4088  // We have to handle DOM nodes and JS objects differently because IE6-7
4089  // can't GC object references properly across the DOM-JS boundary
4090  isNode = elem.nodeType,
4091
4092  // Only DOM nodes need the global jQuery cache; JS object data is
4093  // attached directly to the object so GC can occur automatically
4094  cache = isNode ? jQuery.cache : elem,
4095
4096  // Only defining an ID for JS objects if its cache already exists allows
4097  // the code to shortcut on the same path as a DOM node with no cache
4098  id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
4099
4100 // Avoid doing any more work than we need to when trying to get data on an
4101 // object that has no data at all
4102 if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
4103  return;
4104 }
4105
4106 if ( !id ) {
4107  // Only DOM nodes need a new unique ID for each element since their data
4108  // ends up in the global cache
4109  if ( isNode ) {
4110   id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
4111  } else {
4112   id = internalKey;
4113  }
4114 }
4115
4116 if ( !cache[ id ] ) {
4117  // Avoid exposing jQuery metadata on plain JS objects when the object
4118  // is serialized using JSON.stringify
4119  cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
4120 }
4121
4122 // An object can be passed to jQuery.data instead of a key/value pair; this gets
4123 // shallow copied over onto the existing cache
4124 if ( typeof name === "object" || typeof name === "function" ) {
4125  if ( pvt ) {
4126   cache[ id ] = jQuery.extend( cache[ id ], name );
4127  } else {
4128   cache[ id ].data = jQuery.extend( cache[ id ].data, name );
4129  }
4130 }
4131
4132 thisCache = cache[ id ];
4133
4134 // jQuery data() is stored in a separate object inside the object's internal data
4135 // cache in order to avoid key collisions between internal data and user-defined
4136 // data.
4137 if ( !pvt ) {
4138  if ( !thisCache.data ) {
4139   thisCache.data = {};
4140  }
4141
4142  thisCache = thisCache.data;
4143 }
4144
4145 if ( data !== undefined ) {
4146  thisCache[ jQuery.camelCase( name ) ] = data;
4147 }
4148
4149 // Check for both converted-to-camel and non-converted data property names
4150 // If a data property was specified
4151 if ( typeof name === "string" ) {
4152
4153  // First Try to find as-is property data
4154  ret = thisCache[ name ];
4155
4156  // Test for null|undefined property data
4157  if ( ret == null ) {
4158
4159   // Try to find the camelCased property
4160   ret = thisCache[ jQuery.camelCase( name ) ];
4161  }
4162 } else {
4163  ret = thisCache;
4164 }
4165
4166 return ret;
4167}
4168
4169function internalRemoveData( elem, name, pvt ) {
4170 if ( !jQuery.acceptData( elem ) ) {
4171  return;
4172 }
4173
4174 var thisCache, i,
4175  isNode = elem.nodeType,
4176
4177  // See jQuery.data for more information
4178  cache = isNode ? jQuery.cache : elem,
4179  id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
4180
4181 // If there is already no cache entry for this object, there is no
4182 // purpose in continuing
4183 if ( !cache[ id ] ) {
4184  return;
4185 }
4186
4187 if ( name ) {
4188
4189  thisCache = pvt ? cache[ id ] : cache[ id ].data;
4190
4191  if ( thisCache ) {
4192
4193   // Support array or space separated string names for data keys
4194   if ( !jQuery.isArray( name ) ) {
4195
4196    // try the string as a key before any manipulation
4197    if ( name in thisCache ) {
4198     name = [ name ];
4199    } else {
4200
4201     // split the camel cased version by spaces unless a key with the spaces exists
4202     name = jQuery.camelCase( name );
4203     if ( name in thisCache ) {
4204      name = [ name ];
4205     } else {
4206      name = name.split(" ");
4207     }
4208    }
4209   } else {
4210    // If "name" is an array of keys...
4211    // When data is initially created, via ("key", "val") signature,
4212    // keys will be converted to camelCase.
4213    // Since there is no way to tell _how_ a key was added, remove
4214    // both plain key and camelCase key. #12786
4215    // This will only penalize the array argument path.
4216    name = name.concat( jQuery.map( name, jQuery.camelCase ) );
4217   }
4218
4219   i = name.length;
4220   while ( i-- ) {
4221    delete thisCache[ name[i] ];
4222   }
4223
4224   // If there is no data left in the cache, we want to continue
4225   // and let the cache object itself get destroyed
4226   if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
4227    return;
4228   }
4229  }
4230 }
4231
4232 // See jQuery.data for more information
4233 if ( !pvt ) {
4234  delete cache[ id ].data;
4235
4236  // Don't destroy the parent cache unless the internal data object
4237  // had been the only thing left in it
4238  if ( !isEmptyDataObject( cache[ id ] ) ) {
4239   return;
4240  }
4241 }
4242
4243 // Destroy the cache
4244 if ( isNode ) {
4245  jQuery.cleanData( [ elem ], true );
4246
4247 // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
4248 /* jshint eqeqeq: false */
4249 } else if ( support.deleteExpando || cache != cache.window ) {
4250  /* jshint eqeqeq: true */
4251  delete cache[ id ];
4252
4253 // When all else fails, null
4254 } else {
4255  cache[ id ] = null;
4256 }
4257}
4258
4259jQuery.extend({
4260 cache: {},
4261
4262 // The following elements (space-suffixed to avoid Object.prototype collisions)
4263 // throw uncatchable exceptions if you attempt to set expando properties
4264 noData: {
4265  "applet ": true,
4266  "embed ": true,
4267  // ...but Flash objects (which have this classid) *can* handle expandos
4268  "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
4269 },
4270
4271 hasData: function( elem ) {
4272  elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
4273  return !!elem && !isEmptyDataObject( elem );
4274 },
4275
4276 data: function( elem, name, data ) {
4277  return internalData( elem, name, data );
4278 },
4279
4280 removeData: function( elem, name ) {
4281  return internalRemoveData( elem, name );
4282 },
4283
4284 // For internal use only.
4285 _data: function( elem, name, data ) {
4286  return internalData( elem, name, data, true );
4287 },
4288
4289 _removeData: function( elem, name ) {
4290  return internalRemoveData( elem, name, true );
4291 }
4292});
4293
4294jQuery.fn.extend({
4295 data: function( key, value ) {
4296  var i, name, data,
4297   elem = this[0],
4298   attrs = elem && elem.attributes;
4299
4300  // Special expections of .data basically thwart jQuery.access,
4301  // so implement the relevant behavior ourselves
4302
4303  // Gets all values
4304  if ( key === undefined ) {
4305   if ( this.length ) {
4306    data = jQuery.data( elem );
4307
4308    if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
4309     i = attrs.length;
4310     while ( i-- ) {
4311
4312      // Support: IE11+
4313      // The attrs elements can be null (#14894)
4314      if ( attrs[ i ] ) {
4315       name = attrs[ i ].name;
4316       if ( name.indexOf( "data-" ) === 0 ) {
4317        name = jQuery.camelCase( name.slice(5) );
4318        dataAttr( elem, name, data[ name ] );
4319       }
4320      }
4321     }
4322     jQuery._data( elem, "parsedAttrs", true );
4323    }
4324   }
4325
4326   return data;
4327  }
4328
4329  // Sets multiple values
4330  if ( typeof key === "object" ) {
4331   return this.each(function() {
4332    jQuery.data( this, key );
4333   });
4334  }
4335
4336  return arguments.length > 1 ?
4337
4338   // Sets one value
4339   this.each(function() {
4340    jQuery.data( this, key, value );
4341   }) :
4342
4343   // Gets one value
4344   // Try to fetch any internally stored data first
4345   elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
4346 },
4347
4348 removeData: function( key ) {
4349  return this.each(function() {
4350   jQuery.removeData( this, key );
4351  });
4352 }
4353});
4354
4355jQuery.extend({
4356 queue: function( elem, type, data ) {
4357  var queue;
4358
4359  if ( elem ) {
4360   type = ( type || "fx" ) + "queue";
4361   queue = jQuery._data( elem, type );
4362
4363   // Speed up dequeue by getting out quickly if this is just a lookup
4364   if ( data ) {
4365    if ( !queue || jQuery.isArray(data) ) {
4366     queue = jQuery._data( elem, type, jQuery.makeArray(data) );
4367    } else {
4368     queue.push( data );
4369    }
4370   }
4371   return queue || [];
4372  }
4373 },
4374
4375 dequeue: function( elem, type ) {
4376  type = type || "fx";
4377
4378  var queue = jQuery.queue( elem, type ),
4379   startLength = queue.length,
4380   fn = queue.shift(),
4381   hooks = jQuery._queueHooks( elem, type ),
4382   next = function() {
4383    jQuery.dequeue( elem, type );
4384   };
4385
4386  // If the fx queue is dequeued, always remove the progress sentinel
4387  if ( fn === "inprogress" ) {
4388   fn = queue.shift();
4389   startLength--;
4390  }
4391
4392  if ( fn ) {
4393
4394   // Add a progress sentinel to prevent the fx queue from being
4395   // automatically dequeued
4396   if ( type === "fx" ) {
4397    queue.unshift( "inprogress" );
4398   }
4399
4400   // clear up the last queue stop function
4401   delete hooks.stop;
4402   fn.call( elem, next, hooks );
4403  }
4404
4405  if ( !startLength && hooks ) {
4406   hooks.empty.fire();
4407  }
4408 },
4409
4410 // not intended for public consumption - generates a queueHooks object, or returns the current one
4411 _queueHooks: function( elem, type ) {
4412  var key = type + "queueHooks";
4413  return jQuery._data( elem, key ) || jQuery._data( elem, key, {
4414   empty: jQuery.Callbacks("once memory").add(function() {
4415    jQuery._removeData( elem, type + "queue" );
4416    jQuery._removeData( elem, key );
4417   })
4418  });
4419 }
4420});
4421
4422jQuery.fn.extend({
4423 queue: function( type, data ) {
4424  var setter = 2;
4425
4426  if ( typeof type !== "string" ) {
4427   data = type;
4428   type = "fx";
4429   setter--;
4430  }
4431
4432  if ( arguments.length < setter ) {
4433   return jQuery.queue( this[0], type );
4434  }
4435
4436  return data === undefined ?
4437   this :
4438   this.each(function() {
4439    var queue = jQuery.queue( this, type, data );
4440
4441    // ensure a hooks for this queue
4442    jQuery._queueHooks( this, type );
4443
4444    if ( type === "fx" && queue[0] !== "inprogress" ) {
4445     jQuery.dequeue( this, type );
4446    }
4447   });
4448 },
4449 dequeue: function( type ) {
4450  return this.each(function() {
4451   jQuery.dequeue( this, type );
4452  });
4453 },
4454 clearQueue: function( type ) {
4455  return this.queue( type || "fx", [] );
4456 },
4457 // Get a promise resolved when queues of a certain type
4458 // are emptied (fx is the type by default)
4459 promise: function( type, obj ) {
4460  var tmp,
4461   count = 1,
4462   defer = jQuery.Deferred(),
4463   elements = this,
4464   i = this.length,
4465   resolve = function() {
4466    if ( !( --count ) ) {
4467     defer.resolveWith( elements, [ elements ] );
4468    }
4469   };
4470
4471  if ( typeof type !== "string" ) {
4472   obj = type;
4473   type = undefined;
4474  }
4475  type = type || "fx";
4476
4477  while ( i-- ) {
4478   tmp = jQuery._data( elements[ i ], type + "queueHooks" );
4479   if ( tmp && tmp.empty ) {
4480    count++;
4481    tmp.empty.add( resolve );
4482   }
4483  }
4484  resolve();
4485  return defer.promise( obj );
4486 }
4487});
4488var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
4489
4490var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
4491
4492var isHidden = function( elem, el ) {
4493  // isHidden might be called from jQuery#filter function;
4494  // in that case, element will be second argument
4495  elem = el || elem;
4496  return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
4497 };
4498
4499// Multifunctional method to get and set values of a collection
4500// The value/s can optionally be executed if it's a function
4501var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
4502 var i = 0,
4503  length = elems.length,
4504  bulk = key == null;
4505
4506 // Sets many values
4507 if ( jQuery.type( key ) === "object" ) {
4508  chainable = true;
4509  for ( i in key ) {
4510   jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
4511  }
4512
4513 // Sets one value
4514 } else if ( value !== undefined ) {
4515  chainable = true;
4516
4517  if ( !jQuery.isFunction( value ) ) {
4518   raw = true;
4519  }
4520
4521  if ( bulk ) {
4522   // Bulk operations run against the entire set
4523   if ( raw ) {
4524    fn.call( elems, value );
4525    fn = null;
4526
4527   // ...except when executing function values
4528   } else {
4529    bulk = fn;
4530    fn = function( elem, key, value ) {
4531     return bulk.call( jQuery( elem ), value );
4532    };
4533   }
4534  }
4535
4536  if ( fn ) {
4537   for ( ; i < length; i++ ) {
4538    fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
4539   }
4540  }
4541 }
4542
4543 return chainable ?
4544  elems :
4545
4546  // Gets
4547  bulk ?
4548   fn.call( elems ) :
4549   length ? fn( elems[0], key ) : emptyGet;
4550};
4551var rcheckableType = (/^(?:checkbox|radio)$/i);
4552
4553(function() {
4554 // Minified: var a,b,c
4555 var input = document.createElement( "input" ),
4556  div = document.createElement( "div" ),
4557  fragment = document.createDocumentFragment();
4558
4559 // Setup
4560 div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
4561
4562 // IE strips leading whitespace when .innerHTML is used
4563 support.leadingWhitespace = div.firstChild.nodeType === 3;
4564
4565 // Make sure that tbody elements aren't automatically inserted
4566 // IE will insert them into empty tables
4567 support.tbody = !div.getElementsByTagName( "tbody" ).length;
4568
4569 // Make sure that link elements get serialized correctly by innerHTML
4570 // This requires a wrapper element in IE
4571 support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
4572
4573 // Makes sure cloning an html5 element does not cause problems
4574 // Where outerHTML is undefined, this still works
4575 support.html5Clone =
4576  document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
4577
4578 // Check if a disconnected checkbox will retain its checked
4579 // value of true after appended to the DOM (IE6/7)
4580 input.type = "checkbox";
4581 input.checked = true;
4582 fragment.appendChild( input );
4583 support.appendChecked = input.checked;
4584
4585 // Make sure textarea (and checkbox) defaultValue is properly cloned
4586 // Support: IE6-IE11+
4587 div.innerHTML = "<textarea>x</textarea>";
4588 support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
4589
4590 // #11217 - WebKit loses check when the name is after the checked attribute
4591 fragment.appendChild( div );
4592 div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
4593
4594 // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
4595 // old WebKit doesn't clone checked state correctly in fragments
4596 support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
4597
4598 // Support: IE<9
4599 // Opera does not clone events (and typeof div.attachEvent === undefined).
4600 // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
4601 support.noCloneEvent = true;
4602 if ( div.attachEvent ) {
4603  div.attachEvent( "onclick", function() {
4604   support.noCloneEvent = false;
4605  });
4606
4607  div.cloneNode( true ).click();
4608 }
4609
4610 // Execute the test only if not already executed in another module.
4611 if (support.deleteExpando == null) {
4612  // Support: IE<9
4613  support.deleteExpando = true;
4614  try {
4615   delete div.test;
4616  } catch( e ) {
4617   support.deleteExpando = false;
4618  }
4619 }
4620})();
4621
4622(function() {
4623 var i, eventName,
4624  div = document.createElement( "div" );
4625
4626 // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
4627 for ( i in { submit: true, change: true, focusin: true }) {
4628  eventName = "on" + i;
4629
4630  if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
4631   // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
4632   div.setAttribute( eventName, "t" );
4633   support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
4634  }
4635 }
4636
4637 // Null elements to avoid leaks in IE.
4638 div = null;
4639})();
4640
4641var rformElems = /^(?:input|select|textarea)$/i,
4642 rkeyEvent = /^key/,
4643 rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
4644 rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
4645 rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
4646
4647function returnTrue() {
4648 return true;
4649}
4650
4651function returnFalse() {
4652 return false;
4653}
4654
4655function safeActiveElement() {
4656 try {
4657  return document.activeElement;
4658 } catch ( err ) { }
4659}
4660
4661/*
4662 * Helper functions for managing events -- not part of the public interface.
4663 * Props to Dean Edwards' addEvent library for many of the ideas.
4664 */
4665jQuery.event = {
4666
4667 global: {},
4668
4669 add: function( elem, types, handler, data, selector ) {
4670  var tmp, events, t, handleObjIn,
4671   special, eventHandle, handleObj,
4672   handlers, type, namespaces, origType,
4673   elemData = jQuery._data( elem );
4674
4675  // Don't attach events to noData or text/comment nodes (but allow plain objects)
4676  if ( !elemData ) {
4677   return;
4678  }
4679
4680  // Caller can pass in an object of custom data in lieu of the handler
4681  if ( handler.handler ) {
4682   handleObjIn = handler;
4683   handler = handleObjIn.handler;
4684   selector = handleObjIn.selector;
4685  }
4686
4687  // Make sure that the handler has a unique ID, used to find/remove it later
4688  if ( !handler.guid ) {
4689   handler.guid = jQuery.guid++;
4690  }
4691
4692  // Init the element's event structure and main handler, if this is the first
4693  if ( !(events = elemData.events) ) {
4694   events = elemData.events = {};
4695  }
4696  if ( !(eventHandle = elemData.handle) ) {
4697   eventHandle = elemData.handle = function( e ) {
4698    // Discard the second event of a jQuery.event.trigger() and
4699    // when an event is called after a page has unloaded
4700    return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
4701     jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
4702     undefined;
4703   };
4704   // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
4705   eventHandle.elem = elem;
4706  }
4707
4708  // Handle multiple events separated by a space
4709  types = ( types || "" ).match( rnotwhite ) || [ "" ];
4710  t = types.length;
4711  while ( t-- ) {
4712   tmp = rtypenamespace.exec( types[t] ) || [];
4713   type = origType = tmp[1];
4714   namespaces = ( tmp[2] || "" ).split( "." ).sort();
4715
4716   // There *must* be a type, no attaching namespace-only handlers
4717   if ( !type ) {
4718    continue;
4719   }
4720
4721   // If event changes its type, use the special event handlers for the changed type
4722   special = jQuery.event.special[ type ] || {};
4723
4724   // If selector defined, determine special event api type, otherwise given type
4725   type = ( selector ? special.delegateType : special.bindType ) || type;
4726
4727   // Update special based on newly reset type
4728   special = jQuery.event.special[ type ] || {};
4729
4730   // handleObj is passed to all event handlers
4731   handleObj = jQuery.extend({
4732    type: type,
4733    origType: origType,
4734    data: data,
4735    handler: handler,
4736    guid: handler.guid,
4737    selector: selector,
4738    needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4739    namespace: namespaces.join(".")
4740   }, handleObjIn );
4741
4742   // Init the event handler queue if we're the first
4743   if ( !(handlers = events[ type ]) ) {
4744    handlers = events[ type ] = [];
4745    handlers.delegateCount = 0;
4746
4747    // Only use addEventListener/attachEvent if the special events handler returns false
4748    if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4749     // Bind the global event handler to the element
4750     if ( elem.addEventListener ) {
4751      elem.addEventListener( type, eventHandle, false );
4752
4753     } else if ( elem.attachEvent ) {
4754      elem.attachEvent( "on" + type, eventHandle );
4755     }
4756    }
4757   }
4758
4759   if ( special.add ) {
4760    special.add.call( elem, handleObj );
4761
4762    if ( !handleObj.handler.guid ) {
4763     handleObj.handler.guid = handler.guid;
4764    }
4765   }
4766
4767   // Add to the element's handler list, delegates in front
4768   if ( selector ) {
4769    handlers.splice( handlers.delegateCount++, 0, handleObj );
4770   } else {
4771    handlers.push( handleObj );
4772   }
4773
4774   // Keep track of which events have ever been used, for event optimization
4775   jQuery.event.global[ type ] = true;
4776  }
4777
4778  // Nullify elem to prevent memory leaks in IE
4779  elem = null;
4780 },
4781
4782 // Detach an event or set of events from an element
4783 remove: function( elem, types, handler, selector, mappedTypes ) {
4784  var j, handleObj, tmp,
4785   origCount, t, events,
4786   special, handlers, type,
4787   namespaces, origType,
4788   elemData = jQuery.hasData( elem ) && jQuery._data( elem );
4789
4790  if ( !elemData || !(events = elemData.events) ) {
4791   return;
4792  }
4793
4794  // Once for each type.namespace in types; type may be omitted
4795  types = ( types || "" ).match( rnotwhite ) || [ "" ];
4796  t = types.length;
4797  while ( t-- ) {
4798   tmp = rtypenamespace.exec( types[t] ) || [];
4799   type = origType = tmp[1];
4800   namespaces = ( tmp[2] || "" ).split( "." ).sort();
4801
4802   // Unbind all events (on this namespace, if provided) for the element
4803   if ( !type ) {
4804    for ( type in events ) {
4805     jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4806    }
4807    continue;
4808   }
4809
4810   special = jQuery.event.special[ type ] || {};
4811   type = ( selector ? special.delegateType : special.bindType ) || type;
4812   handlers = events[ type ] || [];
4813   tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
4814
4815   // Remove matching events
4816   origCount = j = handlers.length;
4817   while ( j-- ) {
4818    handleObj = handlers[ j ];
4819
4820    if ( ( mappedTypes || origType === handleObj.origType ) &&
4821     ( !handler || handler.guid === handleObj.guid ) &&
4822     ( !tmp || tmp.test( handleObj.namespace ) ) &&
4823     ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
4824     handlers.splice( j, 1 );
4825
4826     if ( handleObj.selector ) {
4827      handlers.delegateCount--;
4828     }
4829     if ( special.remove ) {
4830      special.remove.call( elem, handleObj );
4831     }
4832    }
4833   }
4834
4835   // Remove generic event handler if we removed something and no more handlers exist
4836   // (avoids potential for endless recursion during removal of special event handlers)
4837   if ( origCount && !handlers.length ) {
4838    if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4839     jQuery.removeEvent( elem, type, elemData.handle );
4840    }
4841
4842    delete events[ type ];
4843   }
4844  }
4845
4846  // Remove the expando if it's no longer used
4847  if ( jQuery.isEmptyObject( events ) ) {
4848   delete elemData.handle;
4849
4850   // removeData also checks for emptiness and clears the expando if empty
4851   // so use it instead of delete
4852   jQuery._removeData( elem, "events" );
4853  }
4854 },
4855
4856 trigger: function( event, data, elem, onlyHandlers ) {
4857  var handle, ontype, cur,
4858   bubbleType, special, tmp, i,
4859   eventPath = [ elem || document ],
4860   type = hasOwn.call( event, "type" ) ? event.type : event,
4861   namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
4862
4863  cur = tmp = elem = elem || document;
4864
4865  // Don't do events on text and comment nodes
4866  if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
4867   return;
4868  }
4869
4870  // focus/blur morphs to focusin/out; ensure we're not firing them right now
4871  if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
4872   return;
4873  }
4874
4875  if ( type.indexOf(".") >= 0 ) {
4876   // Namespaced trigger; create a regexp to match event type in handle()
4877   namespaces = type.split(".");
4878   type = namespaces.shift();
4879   namespaces.sort();
4880  }
4881  ontype = type.indexOf(":") < 0 && "on" + type;
4882
4883  // Caller can pass in a jQuery.Event object, Object, or just an event type string
4884  event = event[ jQuery.expando ] ?
4885   event :
4886   new jQuery.Event( type, typeof event === "object" && event );
4887
4888  // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
4889  event.isTrigger = onlyHandlers ? 2 : 3;
4890  event.namespace = namespaces.join(".");
4891  event.namespace_re = event.namespace ?
4892   new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
4893   null;
4894
4895  // Clean up the event in case it is being reused
4896  event.result = undefined;
4897  if ( !event.target ) {
4898   event.target = elem;
4899  }
4900
4901  // Clone any incoming data and prepend the event, creating the handler arg list
4902  data = data == null ?
4903   [ event ] :
4904   jQuery.makeArray( data, [ event ] );
4905
4906  // Allow special events to draw outside the lines
4907  special = jQuery.event.special[ type ] || {};
4908  if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
4909   return;
4910  }
4911
4912  // Determine event propagation path in advance, per W3C events spec (#9951)
4913  // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
4914  if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
4915
4916   bubbleType = special.delegateType || type;
4917   if ( !rfocusMorph.test( bubbleType + type ) ) {
4918    cur = cur.parentNode;
4919   }
4920   for ( ; cur; cur = cur.parentNode ) {
4921    eventPath.push( cur );
4922    tmp = cur;
4923   }
4924
4925   // Only add window if we got to document (e.g., not plain obj or detached DOM)
4926   if ( tmp === (elem.ownerDocument || document) ) {
4927    eventPath.push( tmp.defaultView || tmp.parentWindow || window );
4928   }
4929  }
4930
4931  // Fire handlers on the event path
4932  i = 0;
4933  while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
4934
4935   event.type = i > 1 ?
4936    bubbleType :
4937    special.bindType || type;
4938
4939   // jQuery handler
4940   handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
4941   if ( handle ) {
4942    handle.apply( cur, data );
4943   }
4944
4945   // Native handler
4946   handle = ontype && cur[ ontype ];
4947   if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
4948    event.result = handle.apply( cur, data );
4949    if ( event.result === false ) {
4950     event.preventDefault();
4951    }
4952   }
4953  }
4954  event.type = type;
4955
4956  // If nobody prevented the default action, do it now
4957  if ( !onlyHandlers && !event.isDefaultPrevented() ) {
4958
4959   if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
4960    jQuery.acceptData( elem ) ) {
4961
4962    // Call a native DOM method on the target with the same name name as the event.
4963    // Can't use an .isFunction() check here because IE6/7 fails that test.
4964    // Don't do default actions on window, that's where global variables be (#6170)
4965    if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
4966
4967     // Don't re-trigger an onFOO event when we call its FOO() method
4968     tmp = elem[ ontype ];
4969
4970     if ( tmp ) {
4971      elem[ ontype ] = null;
4972     }
4973
4974     // Prevent re-triggering of the same event, since we already bubbled it above
4975     jQuery.event.triggered = type;
4976     try {
4977      elem[ type ]();
4978     } catch ( e ) {
4979      // IE<9 dies on focus/blur to hidden element (#1486,#12518)
4980      // only reproducible on winXP IE8 native, not IE9 in IE8 mode
4981     }
4982     jQuery.event.triggered = undefined;
4983
4984     if ( tmp ) {
4985      elem[ ontype ] = tmp;
4986     }
4987    }
4988   }
4989  }
4990
4991  return event.result;
4992 },
4993
4994 dispatch: function( event ) {
4995
4996  // Make a writable jQuery.Event from the native event object
4997  event = jQuery.event.fix( event );
4998
4999  var i, ret, handleObj, matched, j,
5000   handlerQueue = [],
5001   args = slice.call( arguments ),
5002   handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
5003   special = jQuery.event.special[ event.type ] || {};
5004
5005  // Use the fix-ed jQuery.Event rather than the (read-only) native event
5006  args[0] = event;
5007  event.delegateTarget = this;
5008
5009  // Call the preDispatch hook for the mapped type, and let it bail if desired
5010  if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
5011   return;
5012  }
5013
5014  // Determine handlers
5015  handlerQueue = jQuery.event.handlers.call( this, event, handlers );
5016
5017  // Run delegates first; they may want to stop propagation beneath us
5018  i = 0;
5019  while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
5020   event.currentTarget = matched.elem;
5021
5022   j = 0;
5023   while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
5024
5025    // Triggered event must either 1) have no namespace, or
5026    // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
5027    if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
5028
5029     event.handleObj = handleObj;
5030     event.data = handleObj.data;
5031
5032     ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
5033       .apply( matched.elem, args );
5034
5035     if ( ret !== undefined ) {
5036      if ( (event.result = ret) === false ) {
5037       event.preventDefault();
5038       event.stopPropagation();
5039      }
5040     }
5041    }
5042   }
5043  }
5044
5045  // Call the postDispatch hook for the mapped type
5046  if ( special.postDispatch ) {
5047   special.postDispatch.call( this, event );
5048  }
5049
5050  return event.result;
5051 },
5052
5053 handlers: function( event, handlers ) {
5054  var sel, handleObj, matches, i,
5055   handlerQueue = [],
5056   delegateCount = handlers.delegateCount,
5057   cur = event.target;
5058
5059  // Find delegate handlers
5060  // Black-hole SVG <use> instance trees (#13180)
5061  // Avoid non-left-click bubbling in Firefox (#3861)
5062  if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
5063
5064   /* jshint eqeqeq: false */
5065   for ( ; cur != this; cur = cur.parentNode || this ) {
5066    /* jshint eqeqeq: true */
5067
5068    // Don't check non-elements (#13208)
5069    // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
5070    if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
5071     matches = [];
5072     for ( i = 0; i < delegateCount; i++ ) {
5073      handleObj = handlers[ i ];
5074
5075      // Don't conflict with Object.prototype properties (#13203)
5076      sel = handleObj.selector + " ";
5077
5078      if ( matches[ sel ] === undefined ) {
5079       matches[ sel ] = handleObj.needsContext ?
5080        jQuery( sel, this ).index( cur ) >= 0 :
5081        jQuery.find( sel, this, null, [ cur ] ).length;
5082      }
5083      if ( matches[ sel ] ) {
5084       matches.push( handleObj );
5085      }
5086     }
5087     if ( matches.length ) {
5088      handlerQueue.push({ elem: cur, handlers: matches });
5089     }
5090    }
5091   }
5092  }
5093
5094  // Add the remaining (directly-bound) handlers
5095  if ( delegateCount < handlers.length ) {
5096   handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
5097  }
5098
5099  return handlerQueue;
5100 },
5101
5102 fix: function( event ) {
5103  if ( event[ jQuery.expando ] ) {
5104   return event;
5105  }
5106
5107  // Create a writable copy of the event object and normalize some properties
5108  var i, prop, copy,
5109   type = event.type,
5110   originalEvent = event,
5111   fixHook = this.fixHooks[ type ];
5112
5113  if ( !fixHook ) {
5114   this.fixHooks[ type ] = fixHook =
5115    rmouseEvent.test( type ) ? this.mouseHooks :
5116    rkeyEvent.test( type ) ? this.keyHooks :
5117    {};
5118  }
5119  copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
5120
5121  event = new jQuery.Event( originalEvent );
5122
5123  i = copy.length;
5124  while ( i-- ) {
5125   prop = copy[ i ];
5126   event[ prop ] = originalEvent[ prop ];
5127  }
5128
5129  // Support: IE<9
5130  // Fix target property (#1925)
5131  if ( !event.target ) {
5132   event.target = originalEvent.srcElement || document;
5133  }
5134
5135  // Support: Chrome 23+, Safari?
5136  // Target should not be a text node (#504, #13143)
5137  if ( event.target.nodeType === 3 ) {
5138   event.target = event.target.parentNode;
5139  }
5140
5141  // Support: IE<9
5142  // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
5143  event.metaKey = !!event.metaKey;
5144
5145  return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
5146 },
5147
5148 // Includes some event props shared by KeyEvent and MouseEvent
5149 props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
5150
5151 fixHooks: {},
5152
5153 keyHooks: {
5154  props: "char charCode key keyCode".split(" "),
5155  filter: function( event, original ) {
5156
5157   // Add which for key events
5158   if ( event.which == null ) {
5159    event.which = original.charCode != null ? original.charCode : original.keyCode;
5160   }
5161
5162   return event;
5163  }
5164 },
5165
5166 mouseHooks: {
5167  props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
5168  filter: function( event, original ) {
5169   var body, eventDoc, doc,
5170    button = original.button,
5171    fromElement = original.fromElement;
5172
5173   // Calculate pageX/Y if missing and clientX/Y available
5174   if ( event.pageX == null && original.clientX != null ) {
5175    eventDoc = event.target.ownerDocument || document;
5176    doc = eventDoc.documentElement;
5177    body = eventDoc.body;
5178
5179    event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
5180    event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
5181   }
5182
5183   // Add relatedTarget, if necessary
5184   if ( !event.relatedTarget && fromElement ) {
5185    event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
5186   }
5187
5188   // Add which for click: 1 === left; 2 === middle; 3 === right
5189   // Note: button is not normalized, so don't use it
5190   if ( !event.which && button !== undefined ) {
5191    event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
5192   }
5193
5194   return event;
5195  }
5196 },
5197
5198 special: {
5199  load: {
5200   // Prevent triggered image.load events from bubbling to window.load
5201   noBubble: true
5202  },
5203  focus: {
5204   // Fire native event if possible so blur/focus sequence is correct
5205   trigger: function() {
5206    if ( this !== safeActiveElement() && this.focus ) {
5207     try {
5208      this.focus();
5209      return false;
5210     } catch ( e ) {
5211      // Support: IE<9
5212      // If we error on focus to hidden element (#1486, #12518),
5213      // let .trigger() run the handlers
5214     }
5215    }
5216   },
5217   delegateType: "focusin"
5218  },
5219  blur: {
5220   trigger: function() {
5221    if ( this === safeActiveElement() && this.blur ) {
5222     this.blur();
5223     return false;
5224    }
5225   },
5226   delegateType: "focusout"
5227  },
5228  click: {
5229   // For checkbox, fire native event so checked state will be right
5230   trigger: function() {
5231    if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
5232     this.click();
5233     return false;
5234    }
5235   },
5236
5237   // For cross-browser consistency, don't fire native .click() on links
5238   _default: function( event ) {
5239    return jQuery.nodeName( event.target, "a" );
5240   }
5241  },
5242
5243  beforeunload: {
5244   postDispatch: function( event ) {
5245
5246    // Support: Firefox 20+
5247    // Firefox doesn't alert if the returnValue field is not set.
5248    if ( event.result !== undefined && event.originalEvent ) {
5249     event.originalEvent.returnValue = event.result;
5250    }
5251   }
5252  }
5253 },
5254
5255 simulate: function( type, elem, event, bubble ) {
5256  // Piggyback on a donor event to simulate a different one.
5257  // Fake originalEvent to avoid donor's stopPropagation, but if the
5258  // simulated event prevents default then we do the same on the donor.
5259  var e = jQuery.extend(
5260   new jQuery.Event(),
5261   event,
5262   {
5263    type: type,
5264    isSimulated: true,
5265    originalEvent: {}
5266   }
5267  );
5268  if ( bubble ) {
5269   jQuery.event.trigger( e, null, elem );
5270  } else {
5271   jQuery.event.dispatch.call( elem, e );
5272  }
5273  if ( e.isDefaultPrevented() ) {
5274   event.preventDefault();
5275  }
5276 }
5277};
5278
5279jQuery.removeEvent = document.removeEventListener ?
5280 function( elem, type, handle ) {
5281  if ( elem.removeEventListener ) {
5282   elem.removeEventListener( type, handle, false );
5283  }
5284 } :
5285 function( elem, type, handle ) {
5286  var name = "on" + type;
5287
5288  if ( elem.detachEvent ) {
5289
5290   // #8545, #7054, preventing memory leaks for custom events in IE6-8
5291   // detachEvent needed property on element, by name of that event, to properly expose it to GC
5292   if ( typeof elem[ name ] === strundefined ) {
5293    elem[ name ] = null;
5294   }
5295
5296   elem.detachEvent( name, handle );
5297  }
5298 };
5299
5300jQuery.Event = function( src, props ) {
5301 // Allow instantiation without the 'new' keyword
5302 if ( !(this instanceof jQuery.Event) ) {
5303  return new jQuery.Event( src, props );
5304 }
5305
5306 // Event object
5307 if ( src && src.type ) {
5308  this.originalEvent = src;
5309  this.type = src.type;
5310
5311  // Events bubbling up the document may have been marked as prevented
5312  // by a handler lower down the tree; reflect the correct value.
5313  this.isDefaultPrevented = src.defaultPrevented ||
5314    src.defaultPrevented === undefined &&
5315    // Support: IE < 9, Android < 4.0
5316    src.returnValue === false ?
5317   returnTrue :
5318   returnFalse;
5319
5320 // Event type
5321 } else {
5322  this.type = src;
5323 }
5324
5325 // Put explicitly provided properties onto the event object
5326 if ( props ) {
5327  jQuery.extend( this, props );
5328 }
5329
5330 // Create a timestamp if incoming event doesn't have one
5331 this.timeStamp = src && src.timeStamp || jQuery.now();
5332
5333 // Mark it as fixed
5334 this[ jQuery.expando ] = true;
5335};
5336
5337// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
5338// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
5339jQuery.Event.prototype = {
5340 isDefaultPrevented: returnFalse,
5341 isPropagationStopped: returnFalse,
5342 isImmediatePropagationStopped: returnFalse,
5343
5344 preventDefault: function() {
5345  var e = this.originalEvent;
5346
5347  this.isDefaultPrevented = returnTrue;
5348  if ( !e ) {
5349   return;
5350  }
5351
5352  // If preventDefault exists, run it on the original event
5353  if ( e.preventDefault ) {
5354   e.preventDefault();
5355
5356  // Support: IE
5357  // Otherwise set the returnValue property of the original event to false
5358  } else {
5359   e.returnValue = false;
5360  }
5361 },
5362 stopPropagation: function() {
5363  var e = this.originalEvent;
5364
5365  this.isPropagationStopped = returnTrue;
5366  if ( !e ) {
5367   return;
5368  }
5369  // If stopPropagation exists, run it on the original event
5370  if ( e.stopPropagation ) {
5371   e.stopPropagation();
5372  }
5373
5374  // Support: IE
5375  // Set the cancelBubble property of the original event to true
5376  e.cancelBubble = true;
5377 },
5378 stopImmediatePropagation: function() {
5379  var e = this.originalEvent;
5380
5381  this.isImmediatePropagationStopped = returnTrue;
5382
5383  if ( e && e.stopImmediatePropagation ) {
5384   e.stopImmediatePropagation();
5385  }
5386
5387  this.stopPropagation();
5388 }
5389};
5390
5391// Create mouseenter/leave events using mouseover/out and event-time checks
5392jQuery.each({
5393 mouseenter: "mouseover",
5394 mouseleave: "mouseout",
5395 pointerenter: "pointerover",
5396 pointerleave: "pointerout"
5397}, function( orig, fix ) {
5398 jQuery.event.special[ orig ] = {
5399  delegateType: fix,
5400  bindType: fix,
5401
5402  handle: function( event ) {
5403   var ret,
5404    target = this,
5405    related = event.relatedTarget,
5406    handleObj = event.handleObj;
5407
5408   // For mousenter/leave call the handler if related is outside the target.
5409   // NB: No relatedTarget if the mouse left/entered the browser window
5410   if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
5411    event.type = handleObj.origType;
5412    ret = handleObj.handler.apply( this, arguments );
5413    event.type = fix;
5414   }
5415   return ret;
5416  }
5417 };
5418});
5419
5420// IE submit delegation
5421if ( !support.submitBubbles ) {
5422
5423 jQuery.event.special.submit = {
5424  setup: function() {
5425   // Only need this for delegated form submit events
5426   if ( jQuery.nodeName( this, "form" ) ) {
5427    return false;
5428   }
5429
5430   // Lazy-add a submit handler when a descendant form may potentially be submitted
5431   jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
5432    // Node name check avoids a VML-related crash in IE (#9807)
5433    var elem = e.target,
5434     form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
5435    if ( form && !jQuery._data( form, "submitBubbles" ) ) {
5436     jQuery.event.add( form, "submit._submit", function( event ) {
5437      event._submit_bubble = true;
5438     });
5439     jQuery._data( form, "submitBubbles", true );
5440    }
5441   });
5442   // return undefined since we don't need an event listener
5443  },
5444
5445  postDispatch: function( event ) {
5446   // If form was submitted by the user, bubble the event up the tree
5447   if ( event._submit_bubble ) {
5448    delete event._submit_bubble;
5449    if ( this.parentNode && !event.isTrigger ) {
5450     jQuery.event.simulate( "submit", this.parentNode, event, true );
5451    }
5452   }
5453  },
5454
5455  teardown: function() {
5456   // Only need this for delegated form submit events
5457   if ( jQuery.nodeName( this, "form" ) ) {
5458    return false;
5459   }
5460
5461   // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
5462   jQuery.event.remove( this, "._submit" );
5463  }
5464 };
5465}
5466
5467// IE change delegation and checkbox/radio fix
5468if ( !support.changeBubbles ) {
5469
5470 jQuery.event.special.change = {
5471
5472  setup: function() {
5473
5474   if ( rformElems.test( this.nodeName ) ) {
5475    // IE doesn't fire change on a check/radio until blur; trigger it on click
5476    // after a propertychange. Eat the blur-change in special.change.handle.
5477    // This still fires onchange a second time for check/radio after blur.
5478    if ( this.type === "checkbox" || this.type === "radio" ) {
5479     jQuery.event.add( this, "propertychange._change", function( event ) {
5480      if ( event.originalEvent.propertyName === "checked" ) {
5481       this._just_changed = true;
5482      }
5483     });
5484     jQuery.event.add( this, "click._change", function( event ) {
5485      if ( this._just_changed && !event.isTrigger ) {
5486       this._just_changed = false;
5487      }
5488      // Allow triggered, simulated change events (#11500)
5489      jQuery.event.simulate( "change", this, event, true );
5490     });
5491    }
5492    return false;
5493   }
5494   // Delegated event; lazy-add a change handler on descendant inputs
5495   jQuery.event.add( this, "beforeactivate._change", function( e ) {
5496    var elem = e.target;
5497
5498    if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
5499     jQuery.event.add( elem, "change._change", function( event ) {
5500      if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
5501       jQuery.event.simulate( "change", this.parentNode, event, true );
5502      }
5503     });
5504     jQuery._data( elem, "changeBubbles", true );
5505    }
5506   });
5507  },
5508
5509  handle: function( event ) {
5510   var elem = event.target;
5511
5512   // Swallow native change events from checkbox/radio, we already triggered them above
5513   if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
5514    return event.handleObj.handler.apply( this, arguments );
5515   }
5516  },
5517
5518  teardown: function() {
5519   jQuery.event.remove( this, "._change" );
5520
5521   return !rformElems.test( this.nodeName );
5522  }
5523 };
5524}
5525
5526// Create "bubbling" focus and blur events
5527if ( !support.focusinBubbles ) {
5528 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
5529
5530  // Attach a single capturing handler on the document while someone wants focusin/focusout
5531  var handler = function( event ) {
5532    jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
5533   };
5534
5535  jQuery.event.special[ fix ] = {
5536   setup: function() {
5537    var doc = this.ownerDocument || this,
5538     attaches = jQuery._data( doc, fix );
5539
5540    if ( !attaches ) {
5541     doc.addEventListener( orig, handler, true );
5542    }
5543    jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
5544   },
5545   teardown: function() {
5546    var doc = this.ownerDocument || this,
5547     attaches = jQuery._data( doc, fix ) - 1;
5548
5549    if ( !attaches ) {
5550     doc.removeEventListener( orig, handler, true );
5551     jQuery._removeData( doc, fix );
5552    } else {
5553     jQuery._data( doc, fix, attaches );
5554    }
5555   }
5556  };
5557 });
5558}
5559
5560jQuery.fn.extend({
5561
5562 on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
5563  var type, origFn;
5564
5565  // Types can be a map of types/handlers
5566  if ( typeof types === "object" ) {
5567   // ( types-Object, selector, data )
5568   if ( typeof selector !== "string" ) {
5569    // ( types-Object, data )
5570    data = data || selector;
5571    selector = undefined;
5572   }
5573   for ( type in types ) {
5574    this.on( type, selector, data, types[ type ], one );
5575   }
5576   return this;
5577  }
5578
5579  if ( data == null && fn == null ) {
5580   // ( types, fn )
5581   fn = selector;
5582   data = selector = undefined;
5583  } else if ( fn == null ) {
5584   if ( typeof selector === "string" ) {
5585    // ( types, selector, fn )
5586    fn = data;
5587    data = undefined;
5588   } else {
5589    // ( types, data, fn )
5590    fn = data;
5591    data = selector;
5592    selector = undefined;
5593   }
5594  }
5595  if ( fn === false ) {
5596   fn = returnFalse;
5597  } else if ( !fn ) {
5598   return this;
5599  }
5600
5601  if ( one === 1 ) {
5602   origFn = fn;
5603   fn = function( event ) {
5604    // Can use an empty set, since event contains the info
5605    jQuery().off( event );
5606    return origFn.apply( this, arguments );
5607   };
5608   // Use same guid so caller can remove using origFn
5609   fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
5610  }
5611  return this.each( function() {
5612   jQuery.event.add( this, types, fn, data, selector );
5613  });
5614 },
5615 one: function( types, selector, data, fn ) {
5616  return this.on( types, selector, data, fn, 1 );
5617 },
5618 off: function( types, selector, fn ) {
5619  var handleObj, type;
5620  if ( types && types.preventDefault && types.handleObj ) {
5621   // ( event )  dispatched jQuery.Event
5622   handleObj = types.handleObj;
5623   jQuery( types.delegateTarget ).off(
5624    handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
5625    handleObj.selector,
5626    handleObj.handler
5627   );
5628   return this;
5629  }
5630  if ( typeof types === "object" ) {
5631   // ( types-object [, selector] )
5632   for ( type in types ) {
5633    this.off( type, selector, types[ type ] );
5634   }
5635   return this;
5636  }
5637  if ( selector === false || typeof selector === "function" ) {
5638   // ( types [, fn] )
5639   fn = selector;
5640   selector = undefined;
5641  }
5642  if ( fn === false ) {
5643   fn = returnFalse;
5644  }
5645  return this.each(function() {
5646   jQuery.event.remove( this, types, fn, selector );
5647  });
5648 },
5649
5650 trigger: function( type, data ) {
5651  return this.each(function() {
5652   jQuery.event.trigger( type, data, this );
5653  });
5654 },
5655 triggerHandler: function( type, data ) {
5656  var elem = this[0];
5657  if ( elem ) {
5658   return jQuery.event.trigger( type, data, elem, true );
5659  }
5660 }
5661});
5662
5663function createSafeFragment( document ) {
5664 var list = nodeNames.split( "|" ),
5665  safeFrag = document.createDocumentFragment();
5666
5667 if ( safeFrag.createElement ) {
5668  while ( list.length ) {
5669   safeFrag.createElement(
5670    list.pop()
5671   );
5672  }
5673 }
5674 return safeFrag;
5675}
5676
5677var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
5678  "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
5679 rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
5680 rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
5681 rleadingWhitespace = /^\s+/,
5682 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
5683 rtagName = /<([\w:]+)/,
5684 rtbody = /<tbody/i,
5685 rhtml = /<|&#?\w+;/,
5686 rnoInnerhtml = /<(?:script|style|link)/i,
5687 // checked="checked" or checked
5688 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
5689 rscriptType = /^$|\/(?:java|ecma)script/i,
5690 rscriptTypeMasked = /^true\/(.*)/,
5691 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
5692
5693 // We have to close these tags to support XHTML (#13200)
5694 wrapMap = {
5695  option: [ 1, "<select multiple='multiple'>", "</select>" ],
5696  legend: [ 1, "<fieldset>", "</fieldset>" ],
5697  area: [ 1, "<map>", "</map>" ],
5698  param: [ 1, "<object>", "</object>" ],
5699  thead: [ 1, "<table>", "</table>" ],
5700  tr: [ 2, "<table><tbody>", "</tbody></table>" ],
5701  col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
5702  td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
5703
5704  // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
5705  // unless wrapped in a div with non-breaking characters in front of it.
5706  _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>"  ]
5707 },
5708 safeFragment = createSafeFragment( document ),
5709 fragmentDiv = safeFragment.appendChild( document.createElement("div") );
5710
5711wrapMap.optgroup = wrapMap.option;
5712wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
5713wrapMap.th = wrapMap.td;
5714
5715function getAll( context, tag ) {
5716 var elems, elem,
5717  i = 0,
5718  found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
5719   typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
5720   undefined;
5721
5722 if ( !found ) {
5723  for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
5724   if ( !tag || jQuery.nodeName( elem, tag ) ) {
5725    found.push( elem );
5726   } else {
5727    jQuery.merge( found, getAll( elem, tag ) );
5728   }
5729  }
5730 }
5731
5732 return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
5733  jQuery.merge( [ context ], found ) :
5734  found;
5735}
5736
5737// Used in buildFragment, fixes the defaultChecked property
5738function fixDefaultChecked( elem ) {
5739 if ( rcheckableType.test( elem.type ) ) {
5740  elem.defaultChecked = elem.checked;
5741 }
5742}
5743
5744// Support: IE<8
5745// Manipulating tables requires a tbody
5746function manipulationTarget( elem, content ) {
5747 return jQuery.nodeName( elem, "table" ) &&
5748  jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
5749
5750  elem.getElementsByTagName("tbody")[0] ||
5751   elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
5752  elem;
5753}
5754
5755// Replace/restore the type attribute of script elements for safe DOM manipulation
5756function disableScript( elem ) {
5757 elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
5758 return elem;
5759}
5760function restoreScript( elem ) {
5761 var match = rscriptTypeMasked.exec( elem.type );
5762 if ( match ) {
5763  elem.type = match[1];
5764 } else {
5765  elem.removeAttribute("type");
5766 }
5767 return elem;
5768}
5769
5770// Mark scripts as having already been evaluated
5771function setGlobalEval( elems, refElements ) {
5772 var elem,
5773  i = 0;
5774 for ( ; (elem = elems[i]) != null; i++ ) {
5775  jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
5776 }
5777}
5778
5779function cloneCopyEvent( src, dest ) {
5780
5781 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
5782  return;
5783 }
5784
5785 var type, i, l,
5786  oldData = jQuery._data( src ),
5787  curData = jQuery._data( dest, oldData ),
5788  events = oldData.events;
5789
5790 if ( events ) {
5791  delete curData.handle;
5792  curData.events = {};
5793
5794  for ( type in events ) {
5795   for ( i = 0, l = events[ type ].length; i < l; i++ ) {
5796    jQuery.event.add( dest, type, events[ type ][ i ] );
5797   }
5798  }
5799 }
5800
5801 // make the cloned public data object a copy from the original
5802 if ( curData.data ) {
5803  curData.data = jQuery.extend( {}, curData.data );
5804 }
5805}
5806
5807function fixCloneNodeIssues( src, dest ) {
5808 var nodeName, e, data;
5809
5810 // We do not need to do anything for non-Elements
5811 if ( dest.nodeType !== 1 ) {
5812  return;
5813 }
5814
5815 nodeName = dest.nodeName.toLowerCase();
5816
5817 // IE6-8 copies events bound via attachEvent when using cloneNode.
5818 if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
5819  data = jQuery._data( dest );
5820
5821  for ( e in data.events ) {
5822   jQuery.removeEvent( dest, e, data.handle );
5823  }
5824
5825  // Event data gets referenced instead of copied if the expando gets copied too
5826  dest.removeAttribute( jQuery.expando );
5827 }
5828
5829 // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
5830 if ( nodeName === "script" && dest.text !== src.text ) {
5831  disableScript( dest ).text = src.text;
5832  restoreScript( dest );
5833
5834 // IE6-10 improperly clones children of object elements using classid.
5835 // IE10 throws NoModificationAllowedError if parent is null, #12132.
5836 } else if ( nodeName === "object" ) {
5837  if ( dest.parentNode ) {
5838   dest.outerHTML = src.outerHTML;
5839  }
5840
5841  // This path appears unavoidable for IE9. When cloning an object
5842  // element in IE9, the outerHTML strategy above is not sufficient.
5843  // If the src has innerHTML and the destination does not,
5844  // copy the src.innerHTML into the dest.innerHTML. #10324
5845  if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
5846   dest.innerHTML = src.innerHTML;
5847  }
5848
5849 } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
5850  // IE6-8 fails to persist the checked state of a cloned checkbox
5851  // or radio button. Worse, IE6-7 fail to give the cloned element
5852  // a checked appearance if the defaultChecked value isn't also set
5853
5854  dest.defaultChecked = dest.checked = src.checked;
5855
5856  // IE6-7 get confused and end up setting the value of a cloned
5857  // checkbox/radio button to an empty string instead of "on"
5858  if ( dest.value !== src.value ) {
5859   dest.value = src.value;
5860  }
5861
5862 // IE6-8 fails to return the selected option to the default selected
5863 // state when cloning options
5864 } else if ( nodeName === "option" ) {
5865  dest.defaultSelected = dest.selected = src.defaultSelected;
5866
5867 // IE6-8 fails to set the defaultValue to the correct value when
5868 // cloning other types of input fields
5869 } else if ( nodeName === "input" || nodeName === "textarea" ) {
5870  dest.defaultValue = src.defaultValue;
5871 }
5872}
5873
5874jQuery.extend({
5875 clone: function( elem, dataAndEvents, deepDataAndEvents ) {
5876  var destElements, node, clone, i, srcElements,
5877   inPage = jQuery.contains( elem.ownerDocument, elem );
5878
5879  if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
5880   clone = elem.cloneNode( true );
5881
5882  // IE<=8 does not properly clone detached, unknown element nodes
5883  } else {
5884   fragmentDiv.innerHTML = elem.outerHTML;
5885   fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
5886  }
5887
5888  if ( (!support.noCloneEvent || !support.noCloneChecked) &&
5889    (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
5890
5891   // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
5892   destElements = getAll( clone );
5893   srcElements = getAll( elem );
5894
5895   // Fix all IE cloning issues
5896   for ( i = 0; (node = srcElements[i]) != null; ++i ) {
5897    // Ensure that the destination node is not null; Fixes #9587
5898    if ( destElements[i] ) {
5899     fixCloneNodeIssues( node, destElements[i] );
5900    }
5901   }
5902  }
5903
5904  // Copy the events from the original to the clone
5905  if ( dataAndEvents ) {
5906   if ( deepDataAndEvents ) {
5907    srcElements = srcElements || getAll( elem );
5908    destElements = destElements || getAll( clone );
5909
5910    for ( i = 0; (node = srcElements[i]) != null; i++ ) {
5911     cloneCopyEvent( node, destElements[i] );
5912    }
5913   } else {
5914    cloneCopyEvent( elem, clone );
5915   }
5916  }
5917
5918  // Preserve script evaluation history
5919  destElements = getAll( clone, "script" );
5920  if ( destElements.length > 0 ) {
5921   setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
5922  }
5923
5924  destElements = srcElements = node = null;
5925
5926  // Return the cloned set
5927  return clone;
5928 },
5929
5930 buildFragment: function( elems, context, scripts, selection ) {
5931  var j, elem, contains,
5932   tmp, tag, tbody, wrap,
5933   l = elems.length,
5934
5935   // Ensure a safe fragment
5936   safe = createSafeFragment( context ),
5937
5938   nodes = [],
5939   i = 0;
5940
5941  for ( ; i < l; i++ ) {
5942   elem = elems[ i ];
5943
5944   if ( elem || elem === 0 ) {
5945
5946    // Add nodes directly
5947    if ( jQuery.type( elem ) === "object" ) {
5948     jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
5949
5950    // Convert non-html into a text node
5951    } else if ( !rhtml.test( elem ) ) {
5952     nodes.push( context.createTextNode( elem ) );
5953
5954    // Convert html into DOM nodes
5955    } else {
5956     tmp = tmp || safe.appendChild( context.createElement("div") );
5957
5958     // Deserialize a standard representation
5959     tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
5960     wrap = wrapMap[ tag ] || wrapMap._default;
5961
5962     tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
5963
5964     // Descend through wrappers to the right content
5965     j = wrap[0];
5966     while ( j-- ) {
5967      tmp = tmp.lastChild;
5968     }
5969
5970     // Manually add leading whitespace removed by IE
5971     if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
5972      nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
5973     }
5974
5975     // Remove IE's autoinserted <tbody> from table fragments
5976     if ( !support.tbody ) {
5977
5978      // String was a <table>, *may* have spurious <tbody>
5979      elem = tag === "table" && !rtbody.test( elem ) ?
5980       tmp.firstChild :
5981
5982       // String was a bare <thead> or <tfoot>
5983       wrap[1] === "<table>" && !rtbody.test( elem ) ?
5984        tmp :
5985        0;
5986
5987      j = elem && elem.childNodes.length;
5988      while ( j-- ) {
5989       if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
5990        elem.removeChild( tbody );
5991       }
5992      }
5993     }
5994
5995     jQuery.merge( nodes, tmp.childNodes );
5996
5997     // Fix #12392 for WebKit and IE > 9
5998     tmp.textContent = "";
5999
6000     // Fix #12392 for oldIE
6001     while ( tmp.firstChild ) {
6002      tmp.removeChild( tmp.firstChild );
6003     }
6004
6005     // Remember the top-level container for proper cleanup
6006     tmp = safe.lastChild;
6007    }
6008   }
6009  }
6010
6011  // Fix #11356: Clear elements from fragment
6012  if ( tmp ) {
6013   safe.removeChild( tmp );
6014  }
6015
6016  // Reset defaultChecked for any radios and checkboxes
6017  // about to be appended to the DOM in IE 6/7 (#8060)
6018  if ( !support.appendChecked ) {
6019   jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
6020  }
6021
6022  i = 0;
6023  while ( (elem = nodes[ i++ ]) ) {
6024
6025   // #4087 - If origin and destination elements are the same, and this is
6026   // that element, do not do anything
6027   if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
6028    continue;
6029   }
6030
6031   contains = jQuery.contains( elem.ownerDocument, elem );
6032
6033   // Append to fragment
6034   tmp = getAll( safe.appendChild( elem ), "script" );
6035
6036   // Preserve script evaluation history
6037   if ( contains ) {
6038    setGlobalEval( tmp );
6039   }
6040
6041   // Capture executables
6042   if ( scripts ) {
6043    j = 0;
6044    while ( (elem = tmp[ j++ ]) ) {
6045     if ( rscriptType.test( elem.type || "" ) ) {
6046      scripts.push( elem );
6047     }
6048    }
6049   }
6050  }
6051
6052  tmp = null;
6053
6054  return safe;
6055 },
6056
6057 cleanData: function( elems, /* internal */ acceptData ) {
6058  var elem, type, id, data,
6059   i = 0,
6060   internalKey = jQuery.expando,
6061   cache = jQuery.cache,
6062   deleteExpando = support.deleteExpando,
6063   special = jQuery.event.special;
6064
6065  for ( ; (elem = elems[i]) != null; i++ ) {
6066   if ( acceptData || jQuery.acceptData( elem ) ) {
6067
6068    id = elem[ internalKey ];
6069    data = id && cache[ id ];
6070
6071    if ( data ) {
6072     if ( data.events ) {
6073      for ( type in data.events ) {
6074       if ( special[ type ] ) {
6075        jQuery.event.remove( elem, type );
6076
6077       // This is a shortcut to avoid jQuery.event.remove's overhead
6078       } else {
6079        jQuery.removeEvent( elem, type, data.handle );
6080       }
6081      }
6082     }
6083
6084     // Remove cache only if it was not already removed by jQuery.event.remove
6085     if ( cache[ id ] ) {
6086
6087      delete cache[ id ];
6088
6089      // IE does not allow us to delete expando properties from nodes,
6090      // nor does it have a removeAttribute function on Document nodes;
6091      // we must handle all of these cases
6092      if ( deleteExpando ) {
6093       delete elem[ internalKey ];
6094
6095      } else if ( typeof elem.removeAttribute !== strundefined ) {
6096       elem.removeAttribute( internalKey );
6097
6098      } else {
6099       elem[ internalKey ] = null;
6100      }
6101
6102      deletedIds.push( id );
6103     }
6104    }
6105   }
6106  }
6107 }
6108});
6109
6110jQuery.fn.extend({
6111 text: function( value ) {
6112  return access( this, function( value ) {
6113   return value === undefined ?
6114    jQuery.text( this ) :
6115    this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
6116  }, null, value, arguments.length );
6117 },
6118
6119 append: function() {
6120  return this.domManip( arguments, function( elem ) {
6121   if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6122    var target = manipulationTarget( this, elem );
6123    target.appendChild( elem );
6124   }
6125  });
6126 },
6127
6128 prepend: function() {
6129  return this.domManip( arguments, function( elem ) {
6130   if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6131    var target = manipulationTarget( this, elem );
6132    target.insertBefore( elem, target.firstChild );
6133   }
6134  });
6135 },
6136
6137 before: function() {
6138  return this.domManip( arguments, function( elem ) {
6139   if ( this.parentNode ) {
6140    this.parentNode.insertBefore( elem, this );
6141   }
6142  });
6143 },
6144
6145 after: function() {
6146  return this.domManip( arguments, function( elem ) {
6147   if ( this.parentNode ) {
6148    this.parentNode.insertBefore( elem, this.nextSibling );
6149   }
6150  });
6151 },
6152
6153 remove: function( selector, keepData /* Internal Use Only */ ) {
6154  var elem,
6155   elems = selector ? jQuery.filter( selector, this ) : this,
6156   i = 0;
6157
6158  for ( ; (elem = elems[i]) != null; i++ ) {
6159
6160   if ( !keepData && elem.nodeType === 1 ) {
6161    jQuery.cleanData( getAll( elem ) );
6162   }
6163
6164   if ( elem.parentNode ) {
6165    if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
6166     setGlobalEval( getAll( elem, "script" ) );
6167    }
6168    elem.parentNode.removeChild( elem );
6169   }
6170  }
6171
6172  return this;
6173 },
6174
6175 empty: function() {
6176  var elem,
6177   i = 0;
6178
6179  for ( ; (elem = this[i]) != null; i++ ) {
6180   // Remove element nodes and prevent memory leaks
6181   if ( elem.nodeType === 1 ) {
6182    jQuery.cleanData( getAll( elem, false ) );
6183   }
6184
6185   // Remove any remaining nodes
6186   while ( elem.firstChild ) {
6187    elem.removeChild( elem.firstChild );
6188   }
6189
6190   // If this is a select, ensure that it displays empty (#12336)
6191   // Support: IE<9
6192   if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
6193    elem.options.length = 0;
6194   }
6195  }
6196
6197  return this;
6198 },
6199
6200 clone: function( dataAndEvents, deepDataAndEvents ) {
6201  dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6202  deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6203
6204  return this.map(function() {
6205   return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6206  });
6207 },
6208
6209 html: function( value ) {
6210  return access( this, function( value ) {
6211   var elem = this[ 0 ] || {},
6212    i = 0,
6213    l = this.length;
6214
6215   if ( value === undefined ) {
6216    return elem.nodeType === 1 ?
6217     elem.innerHTML.replace( rinlinejQuery, "" ) :
6218     undefined;
6219   }
6220
6221   // See if we can take a shortcut and just use innerHTML
6222   if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6223    ( support.htmlSerialize || !rnoshimcache.test( value )  ) &&
6224    ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
6225    !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
6226
6227    value = value.replace( rxhtmlTag, "<$1></$2>" );
6228
6229    try {
6230     for (; i < l; i++ ) {
6231      // Remove element nodes and prevent memory leaks
6232      elem = this[i] || {};
6233      if ( elem.nodeType === 1 ) {
6234       jQuery.cleanData( getAll( elem, false ) );
6235       elem.innerHTML = value;
6236      }
6237     }
6238
6239     elem = 0;
6240
6241    // If using innerHTML throws an exception, use the fallback method
6242    } catch(e) {}
6243   }
6244
6245   if ( elem ) {
6246    this.empty().append( value );
6247   }
6248  }, null, value, arguments.length );
6249 },
6250
6251 replaceWith: function() {
6252  var arg = arguments[ 0 ];
6253
6254  // Make the changes, replacing each context element with the new content
6255  this.domManip( arguments, function( elem ) {
6256   arg = this.parentNode;
6257
6258   jQuery.cleanData( getAll( this ) );
6259
6260   if ( arg ) {
6261    arg.replaceChild( elem, this );
6262   }
6263  });
6264
6265  // Force removal if there was no new content (e.g., from empty arguments)
6266  return arg && (arg.length || arg.nodeType) ? this : this.remove();
6267 },
6268
6269 detach: function( selector ) {
6270  return this.remove( selector, true );
6271 },
6272
6273 domManip: function( args, callback ) {
6274
6275  // Flatten any nested arrays
6276  args = concat.apply( [], args );
6277
6278  var first, node, hasScripts,
6279   scripts, doc, fragment,
6280   i = 0,
6281   l = this.length,
6282   set = this,
6283   iNoClone = l - 1,
6284   value = args[0],
6285   isFunction = jQuery.isFunction( value );
6286
6287  // We can't cloneNode fragments that contain checked, in WebKit
6288  if ( isFunction ||
6289    ( l > 1 && typeof value === "string" &&
6290     !support.checkClone && rchecked.test( value ) ) ) {
6291   return this.each(function( index ) {
6292    var self = set.eq( index );
6293    if ( isFunction ) {
6294     args[0] = value.call( this, index, self.html() );
6295    }
6296    self.domManip( args, callback );
6297   });
6298  }
6299
6300  if ( l ) {
6301   fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
6302   first = fragment.firstChild;
6303
6304   if ( fragment.childNodes.length === 1 ) {
6305    fragment = first;
6306   }
6307
6308   if ( first ) {
6309    scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
6310    hasScripts = scripts.length;
6311
6312    // Use the original fragment for the last item instead of the first because it can end up
6313    // being emptied incorrectly in certain situations (#8070).
6314    for ( ; i < l; i++ ) {
6315     node = fragment;
6316
6317     if ( i !== iNoClone ) {
6318      node = jQuery.clone( node, true, true );
6319
6320      // Keep references to cloned scripts for later restoration
6321      if ( hasScripts ) {
6322       jQuery.merge( scripts, getAll( node, "script" ) );
6323      }
6324     }
6325
6326     callback.call( this[i], node, i );
6327    }
6328
6329    if ( hasScripts ) {
6330     doc = scripts[ scripts.length - 1 ].ownerDocument;
6331
6332     // Reenable scripts
6333     jQuery.map( scripts, restoreScript );
6334
6335     // Evaluate executable scripts on first document insertion
6336     for ( i = 0; i < hasScripts; i++ ) {
6337      node = scripts[ i ];
6338      if ( rscriptType.test( node.type || "" ) &&
6339       !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
6340
6341       if ( node.src ) {
6342        // Optional AJAX dependency, but won't run scripts if not present
6343        if ( jQuery._evalUrl ) {
6344         jQuery._evalUrl( node.src );
6345        }
6346       } else {
6347        jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
6348       }
6349      }
6350     }
6351    }
6352
6353    // Fix #11809: Avoid leaking memory
6354    fragment = first = null;
6355   }
6356  }
6357
6358  return this;
6359 }
6360});
6361
6362jQuery.each({
6363 appendTo: "append",
6364 prependTo: "prepend",
6365 insertBefore: "before",
6366 insertAfter: "after",
6367 replaceAll: "replaceWith"
6368}, function( name, original ) {
6369 jQuery.fn[ name ] = function( selector ) {
6370  var elems,
6371   i = 0,
6372   ret = [],
6373   insert = jQuery( selector ),
6374   last = insert.length - 1;
6375
6376  for ( ; i <= last; i++ ) {
6377   elems = i === last ? this : this.clone(true);
6378   jQuery( insert[i] )[ original ]( elems );
6379
6380   // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
6381   push.apply( ret, elems.get() );
6382  }
6383
6384  return this.pushStack( ret );
6385 };
6386});
6387
6388var iframe,
6389 elemdisplay = {};
6390
6391/**
6392 * Retrieve the actual display of a element
6393 * @param {String} name nodeName of the element
6394 * @param {Object} doc Document object
6395 */
6396// Called only from within defaultDisplay
6397function actualDisplay( name, doc ) {
6398 var style,
6399  elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
6400
6401  // getDefaultComputedStyle might be reliably used only on attached element
6402  display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
6403
6404   // Use of this method is a temporary fix (more like optmization) until something better comes along,
6405   // since it was removed from specification and supported only in FF
6406   style.display : jQuery.css( elem[ 0 ], "display" );
6407
6408 // We don't have any data stored on the element,
6409 // so use "detach" method as fast way to get rid of the element
6410 elem.detach();
6411
6412 return display;
6413}
6414
6415/**
6416 * Try to determine the default display value of an element
6417 * @param {String} nodeName
6418 */
6419function defaultDisplay( nodeName ) {
6420 var doc = document,
6421  display = elemdisplay[ nodeName ];
6422
6423 if ( !display ) {
6424  display = actualDisplay( nodeName, doc );
6425
6426  // If the simple way fails, read from inside an iframe
6427  if ( display === "none" || !display ) {
6428
6429   // Use the already-created iframe if possible
6430   iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
6431
6432   // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
6433   doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
6434
6435   // Support: IE
6436   doc.write();
6437   doc.close();
6438
6439   display = actualDisplay( nodeName, doc );
6440   iframe.detach();
6441  }
6442
6443  // Store the correct default display
6444  elemdisplay[ nodeName ] = display;
6445 }
6446
6447 return display;
6448}
6449
6450(function() {
6451 var shrinkWrapBlocksVal;
6452
6453 support.shrinkWrapBlocks = function() {
6454  if ( shrinkWrapBlocksVal != null ) {
6455   return shrinkWrapBlocksVal;
6456  }
6457
6458  // Will be changed later if needed.
6459  shrinkWrapBlocksVal = false;
6460
6461  // Minified: var b,c,d
6462  var div, body, container;
6463
6464  body = document.getElementsByTagName( "body" )[ 0 ];
6465  if ( !body || !body.style ) {
6466   // Test fired too early or in an unsupported environment, exit.
6467   return;
6468  }
6469
6470  // Setup
6471  div = document.createElement( "div" );
6472  container = document.createElement( "div" );
6473  container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
6474  body.appendChild( container ).appendChild( div );
6475
6476  // Support: IE6
6477  // Check if elements with layout shrink-wrap their children
6478  if ( typeof div.style.zoom !== strundefined ) {
6479   // Reset CSS: box-sizing; display; margin; border
6480   div.style.cssText =
6481    // Support: Firefox<29, Android 2.3
6482    // Vendor-prefix box-sizing
6483    "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
6484    "box-sizing:content-box;display:block;margin:0;border:0;" +
6485    "padding:1px;width:1px;zoom:1";
6486   div.appendChild( document.createElement( "div" ) ).style.width = "5px";
6487   shrinkWrapBlocksVal = div.offsetWidth !== 3;
6488  }
6489
6490  body.removeChild( container );
6491
6492  return shrinkWrapBlocksVal;
6493 };
6494
6495})();
6496var rmargin = (/^margin/);
6497
6498var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
6499
6500var getStyles, curCSS,
6501 rposition = /^(top|right|bottom|left)$/;
6502
6503if ( window.getComputedStyle ) {
6504 getStyles = function( elem ) {
6505  return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
6506 };
6507
6508 curCSS = function( elem, name, computed ) {
6509  var width, minWidth, maxWidth, ret,
6510   style = elem.style;
6511
6512  computed = computed || getStyles( elem );
6513
6514  // getPropertyValue is only needed for .css('filter') in IE9, see #12537
6515  ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
6516
6517  if ( computed ) {
6518
6519   if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
6520    ret = jQuery.style( elem, name );
6521   }
6522
6523   // A tribute to the "awesome hack by Dean Edwards"
6524   // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
6525   // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
6526   // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
6527   if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
6528
6529    // Remember the original values
6530    width = style.width;
6531    minWidth = style.minWidth;
6532    maxWidth = style.maxWidth;
6533
6534    // Put in the new values to get a computed value out
6535    style.minWidth = style.maxWidth = style.width = ret;
6536    ret = computed.width;
6537
6538    // Revert the changed values
6539    style.width = width;
6540    style.minWidth = minWidth;
6541    style.maxWidth = maxWidth;
6542   }
6543  }
6544
6545  // Support: IE
6546  // IE returns zIndex value as an integer.
6547  return ret === undefined ?
6548   ret :
6549   ret + "";
6550 };
6551} else if ( document.documentElement.currentStyle ) {
6552 getStyles = function( elem ) {
6553  return elem.currentStyle;
6554 };
6555
6556 curCSS = function( elem, name, computed ) {
6557  var left, rs, rsLeft, ret,
6558   style = elem.style;
6559
6560  computed = computed || getStyles( elem );
6561  ret = computed ? computed[ name ] : undefined;
6562
6563  // Avoid setting ret to empty string here
6564  // so we don't default to auto
6565  if ( ret == null && style && style[ name ] ) {
6566   ret = style[ name ];
6567  }
6568
6569  // From the awesome hack by Dean Edwards
6570  // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
6571
6572  // If we're not dealing with a regular pixel number
6573  // but a number that has a weird ending, we need to convert it to pixels
6574  // but not position css attributes, as those are proportional to the parent element instead
6575  // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
6576  if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
6577
6578   // Remember the original values
6579   left = style.left;
6580   rs = elem.runtimeStyle;
6581   rsLeft = rs && rs.left;
6582
6583   // Put in the new values to get a computed value out
6584   if ( rsLeft ) {
6585    rs.left = elem.currentStyle.left;
6586   }
6587   style.left = name === "fontSize" ? "1em" : ret;
6588   ret = style.pixelLeft + "px";
6589
6590   // Revert the changed values
6591   style.left = left;
6592   if ( rsLeft ) {
6593    rs.left = rsLeft;
6594   }
6595  }
6596
6597  // Support: IE
6598  // IE returns zIndex value as an integer.
6599  return ret === undefined ?
6600   ret :
6601   ret + "" || "auto";
6602 };
6603}
6604
6605function addGetHookIf( conditionFn, hookFn ) {
6606 // Define the hook, we'll check on the first run if it's really needed.
6607 return {
6608  get: function() {
6609   var condition = conditionFn();
6610
6611   if ( condition == null ) {
6612    // The test was not ready at this point; screw the hook this time
6613    // but check again when needed next time.
6614    return;
6615   }
6616
6617   if ( condition ) {
6618    // Hook not needed (or it's not possible to use it due to missing dependency),
6619    // remove it.
6620    // Since there are no other hooks for marginRight, remove the whole object.
6621    delete this.get;
6622    return;
6623   }
6624
6625   // Hook needed; redefine it so that the support test is not executed again.
6626
6627   return (this.get = hookFn).apply( this, arguments );
6628  }
6629 };
6630}
6631
6632(function() {
6633 // Minified: var b,c,d,e,f,g, h,i
6634 var div, style, a, pixelPositionVal, boxSizingReliableVal,
6635  reliableHiddenOffsetsVal, reliableMarginRightVal;
6636
6637 // Setup
6638 div = document.createElement( "div" );
6639 div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
6640 a = div.getElementsByTagName( "a" )[ 0 ];
6641 style = a && a.style;
6642
6643 // Finish early in limited (non-browser) environments
6644 if ( !style ) {
6645  return;
6646 }
6647
6648 style.cssText = "float:left;opacity:.5";
6649
6650 // Support: IE<9
6651 // Make sure that element opacity exists (as opposed to filter)
6652 support.opacity = style.opacity === "0.5";
6653
6654 // Verify style float existence
6655 // (IE uses styleFloat instead of cssFloat)
6656 support.cssFloat = !!style.cssFloat;
6657
6658 div.style.backgroundClip = "content-box";
6659 div.cloneNode( true ).style.backgroundClip = "";
6660 support.clearCloneStyle = div.style.backgroundClip === "content-box";
6661
6662 // Support: Firefox<29, Android 2.3
6663 // Vendor-prefix box-sizing
6664 support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" ||
6665  style.WebkitBoxSizing === "";
6666
6667 jQuery.extend(support, {
6668  reliableHiddenOffsets: function() {
6669   if ( reliableHiddenOffsetsVal == null ) {
6670    computeStyleTests();
6671   }
6672   return reliableHiddenOffsetsVal;
6673  },
6674
6675  boxSizingReliable: function() {
6676   if ( boxSizingReliableVal == null ) {
6677    computeStyleTests();
6678   }
6679   return boxSizingReliableVal;
6680  },
6681
6682  pixelPosition: function() {
6683   if ( pixelPositionVal == null ) {
6684    computeStyleTests();
6685   }
6686   return pixelPositionVal;
6687  },
6688
6689  // Support: Android 2.3
6690  reliableMarginRight: function() {
6691   if ( reliableMarginRightVal == null ) {
6692    computeStyleTests();
6693   }
6694   return reliableMarginRightVal;
6695  }
6696 });
6697
6698 function computeStyleTests() {
6699  // Minified: var b,c,d,j
6700  var div, body, container, contents;
6701
6702  body = document.getElementsByTagName( "body" )[ 0 ];
6703  if ( !body || !body.style ) {
6704   // Test fired too early or in an unsupported environment, exit.
6705   return;
6706  }
6707
6708  // Setup
6709  div = document.createElement( "div" );
6710  container = document.createElement( "div" );
6711  container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
6712  body.appendChild( container ).appendChild( div );
6713
6714  div.style.cssText =
6715   // Support: Firefox<29, Android 2.3
6716   // Vendor-prefix box-sizing
6717   "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
6718   "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
6719   "border:1px;padding:1px;width:4px;position:absolute";
6720
6721  // Support: IE<9
6722  // Assume reasonable values in the absence of getComputedStyle
6723  pixelPositionVal = boxSizingReliableVal = false;
6724  reliableMarginRightVal = true;
6725
6726  // Check for getComputedStyle so that this code is not run in IE<9.
6727  if ( window.getComputedStyle ) {
6728   pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
6729   boxSizingReliableVal =
6730    ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
6731
6732   // Support: Android 2.3
6733   // Div with explicit width and no margin-right incorrectly
6734   // gets computed margin-right based on width of container (#3333)
6735   // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
6736   contents = div.appendChild( document.createElement( "div" ) );
6737
6738   // Reset CSS: box-sizing; display; margin; border; padding
6739   contents.style.cssText = div.style.cssText =
6740    // Support: Firefox<29, Android 2.3
6741    // Vendor-prefix box-sizing
6742    "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
6743    "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
6744   contents.style.marginRight = contents.style.width = "0";
6745   div.style.width = "1px";
6746
6747   reliableMarginRightVal =
6748    !parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
6749  }
6750
6751  // Support: IE8
6752  // Check if table cells still have offsetWidth/Height when they are set
6753  // to display:none and there are still other visible table cells in a
6754  // table row; if so, offsetWidth/Height are not reliable for use when
6755  // determining if an element has been hidden directly using
6756  // display:none (it is still safe to use offsets if a parent element is
6757  // hidden; don safety goggles and see bug #4512 for more information).
6758  div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
6759  contents = div.getElementsByTagName( "td" );
6760  contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
6761  reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
6762  if ( reliableHiddenOffsetsVal ) {
6763   contents[ 0 ].style.display = "";
6764   contents[ 1 ].style.display = "none";
6765   reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
6766  }
6767
6768  body.removeChild( container );
6769 }
6770
6771})();
6772
6773// A method for quickly swapping in/out CSS properties to get correct calculations.
6774jQuery.swap = function( elem, options, callback, args ) {
6775 var ret, name,
6776  old = {};
6777
6778 // Remember the old values, and insert the new ones
6779 for ( name in options ) {
6780  old[ name ] = elem.style[ name ];
6781  elem.style[ name ] = options[ name ];
6782 }
6783
6784 ret = callback.apply( elem, args || [] );
6785
6786 // Revert the old values
6787 for ( name in options ) {
6788  elem.style[ name ] = old[ name ];
6789 }
6790
6791 return ret;
6792};
6793
6794var
6795  ralpha = /alpha\([^)]*\)/i,
6796 ropacity = /opacity\s*=\s*([^)]*)/,
6797
6798 // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
6799 // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6800 rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6801 rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
6802 rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
6803
6804 cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6805 cssNormalTransform = {
6806  letterSpacing: "0",
6807  fontWeight: "400"
6808 },
6809
6810 cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
6811
6812// return a css property mapped to a potentially vendor prefixed property
6813function vendorPropName( style, name ) {
6814
6815 // shortcut for names that are not vendor prefixed
6816 if ( name in style ) {
6817  return name;
6818 }
6819
6820 // check for vendor prefixed names
6821 var capName = name.charAt(0).toUpperCase() + name.slice(1),
6822  origName = name,
6823  i = cssPrefixes.length;
6824
6825 while ( i-- ) {
6826  name = cssPrefixes[ i ] + capName;
6827  if ( name in style ) {
6828   return name;
6829  }
6830 }
6831
6832 return origName;
6833}
6834
6835function showHide( elements, show ) {
6836 var display, elem, hidden,
6837  values = [],
6838  index = 0,
6839  length = elements.length;
6840
6841 for ( ; index < length; index++ ) {
6842  elem = elements[ index ];
6843  if ( !elem.style ) {
6844   continue;
6845  }
6846
6847  values[ index ] = jQuery._data( elem, "olddisplay" );
6848  display = elem.style.display;
6849  if ( show ) {
6850   // Reset the inline display of this element to learn if it is
6851   // being hidden by cascaded rules or not
6852   if ( !values[ index ] && display === "none" ) {
6853    elem.style.display = "";
6854   }
6855
6856   // Set elements which have been overridden with display: none
6857   // in a stylesheet to whatever the default browser style is
6858   // for such an element
6859   if ( elem.style.display === "" && isHidden( elem ) ) {
6860    values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
6861   }
6862  } else {
6863   hidden = isHidden( elem );
6864
6865   if ( display && display !== "none" || !hidden ) {
6866    jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
6867   }
6868  }
6869 }
6870
6871 // Set the display of most of the elements in a second loop
6872 // to avoid the constant reflow
6873 for ( index = 0; index < length; index++ ) {
6874  elem = elements[ index ];
6875  if ( !elem.style ) {
6876   continue;
6877  }
6878  if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6879   elem.style.display = show ? values[ index ] || "" : "none";
6880  }
6881 }
6882
6883 return elements;
6884}
6885
6886function setPositiveNumber( elem, value, subtract ) {
6887 var matches = rnumsplit.exec( value );
6888 return matches ?
6889  // Guard against undefined "subtract", e.g., when used as in cssHooks
6890  Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
6891  value;
6892}
6893
6894function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
6895 var i = extra === ( isBorderBox ? "border" : "content" ) ?
6896  // If we already have the right measurement, avoid augmentation
6897  4 :
6898  // Otherwise initialize for horizontal or vertical properties
6899  name === "width" ? 1 : 0,
6900
6901  val = 0;
6902
6903 for ( ; i < 4; i += 2 ) {
6904  // both box models exclude margin, so add it if we want it
6905  if ( extra === "margin" ) {
6906   val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
6907  }
6908
6909  if ( isBorderBox ) {
6910   // border-box includes padding, so remove it if we want content
6911   if ( extra === "content" ) {
6912    val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6913   }
6914
6915   // at this point, extra isn't border nor margin, so remove border
6916   if ( extra !== "margin" ) {
6917    val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6918   }
6919  } else {
6920   // at this point, extra isn't content, so add padding
6921   val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6922
6923   // at this point, extra isn't content nor padding, so add border
6924   if ( extra !== "padding" ) {
6925    val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6926   }
6927  }
6928 }
6929
6930 return val;
6931}
6932
6933function getWidthOrHeight( elem, name, extra ) {
6934
6935 // Start with offset property, which is equivalent to the border-box value
6936 var valueIsBorderBox = true,
6937  val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
6938  styles = getStyles( elem ),
6939  isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
6940
6941 // some non-html elements return undefined for offsetWidth, so check for null/undefined
6942 // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
6943 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
6944 if ( val <= 0 || val == null ) {
6945  // Fall back to computed then uncomputed css if necessary
6946  val = curCSS( elem, name, styles );
6947  if ( val < 0 || val == null ) {
6948   val = elem.style[ name ];
6949  }
6950
6951  // Computed unit is not pixels. Stop here and return.
6952  if ( rnumnonpx.test(val) ) {
6953   return val;
6954  }
6955
6956  // we need the check for style in case a browser which returns unreliable values
6957  // for getComputedStyle silently falls back to the reliable elem.style
6958  valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
6959
6960  // Normalize "", auto, and prepare for extra
6961  val = parseFloat( val ) || 0;
6962 }
6963
6964 // use the active box-sizing model to add/subtract irrelevant styles
6965 return ( val +
6966  augmentWidthOrHeight(
6967   elem,
6968   name,
6969   extra || ( isBorderBox ? "border" : "content" ),
6970   valueIsBorderBox,
6971   styles
6972  )
6973 ) + "px";
6974}
6975
6976jQuery.extend({
6977 // Add in style property hooks for overriding the default
6978 // behavior of getting and setting a style property
6979 cssHooks: {
6980  opacity: {
6981   get: function( elem, computed ) {
6982    if ( computed ) {
6983     // We should always get a number back from opacity
6984     var ret = curCSS( elem, "opacity" );
6985     return ret === "" ? "1" : ret;
6986    }
6987   }
6988  }
6989 },
6990
6991 // Don't automatically add "px" to these possibly-unitless properties
6992 cssNumber: {
6993  "columnCount": true,
6994  "fillOpacity": true,
6995  "flexGrow": true,
6996  "flexShrink": true,
6997  "fontWeight": true,
6998  "lineHeight": true,
6999  "opacity": true,
7000  "order": true,
7001  "orphans": true,
7002  "widows": true,
7003  "zIndex": true,
7004  "zoom": true
7005 },
7006
7007 // Add in properties whose names you wish to fix before
7008 // setting or getting the value
7009 cssProps: {
7010  // normalize float css property
7011  "float": support.cssFloat ? "cssFloat" : "styleFloat"
7012 },
7013
7014 // Get and set the style property on a DOM Node
7015 style: function( elem, name, value, extra ) {
7016  // Don't set styles on text and comment nodes
7017  if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
7018   return;
7019  }
7020
7021  // Make sure that we're working with the right name
7022  var ret, type, hooks,
7023   origName = jQuery.camelCase( name ),
7024   style = elem.style;
7025
7026  name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
7027
7028  // gets hook for the prefixed version
7029  // followed by the unprefixed version
7030  hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
7031
7032  // Check if we're setting a value
7033  if ( value !== undefined ) {
7034   type = typeof value;
7035
7036   // convert relative number strings (+= or -=) to relative numbers. #7345
7037   if ( type === "string" && (ret = rrelNum.exec( value )) ) {
7038    value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
7039    // Fixes bug #9237
7040    type = "number";
7041   }
7042
7043   // Make sure that null and NaN values aren't set. See: #7116
7044   if ( value == null || value !== value ) {
7045    return;
7046   }
7047
7048   // If a number was passed in, add 'px' to the (except for certain CSS properties)
7049   if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
7050    value += "px";
7051   }
7052
7053   // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
7054   // but it would mean to define eight (for every problematic property) identical functions
7055   if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
7056    style[ name ] = "inherit";
7057   }
7058
7059   // If a hook was provided, use that value, otherwise just set the specified value
7060   if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
7061
7062    // Support: IE
7063    // Swallow errors from 'invalid' CSS values (#5509)
7064    try {
7065     style[ name ] = value;
7066    } catch(e) {}
7067   }
7068
7069  } else {
7070   // If a hook was provided get the non-computed value from there
7071   if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
7072    return ret;
7073   }
7074
7075   // Otherwise just get the value from the style object
7076   return style[ name ];
7077  }
7078 },
7079
7080 css: function( elem, name, extra, styles ) {
7081  var num, val, hooks,
7082   origName = jQuery.camelCase( name );
7083
7084  // Make sure that we're working with the right name
7085  name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
7086
7087  // gets hook for the prefixed version
7088  // followed by the unprefixed version
7089  hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
7090
7091  // If a hook was provided get the computed value from there
7092  if ( hooks && "get" in hooks ) {
7093   val = hooks.get( elem, true, extra );
7094  }
7095
7096  // Otherwise, if a way to get the computed value exists, use that
7097  if ( val === undefined ) {
7098   val = curCSS( elem, name, styles );
7099  }
7100
7101  //convert "normal" to computed value
7102  if ( val === "normal" && name in cssNormalTransform ) {
7103   val = cssNormalTransform[ name ];
7104  }
7105
7106  // Return, converting to number if forced or a qualifier was provided and val looks numeric
7107  if ( extra === "" || extra ) {
7108   num = parseFloat( val );
7109   return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
7110  }
7111  return val;
7112 }
7113});
7114
7115jQuery.each([ "height", "width" ], function( i, name ) {
7116 jQuery.cssHooks[ name ] = {
7117  get: function( elem, computed, extra ) {
7118   if ( computed ) {
7119    // certain elements can have dimension info if we invisibly show them
7120    // however, it must have a current display style that would benefit from this
7121    return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
7122     jQuery.swap( elem, cssShow, function() {
7123      return getWidthOrHeight( elem, name, extra );
7124     }) :
7125     getWidthOrHeight( elem, name, extra );
7126   }
7127  },
7128
7129  set: function( elem, value, extra ) {
7130   var styles = extra && getStyles( elem );
7131   return setPositiveNumber( elem, value, extra ?
7132    augmentWidthOrHeight(
7133     elem,
7134     name,
7135     extra,
7136     support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
7137     styles
7138    ) : 0
7139   );
7140  }
7141 };
7142});
7143
7144if ( !support.opacity ) {
7145 jQuery.cssHooks.opacity = {
7146  get: function( elem, computed ) {
7147   // IE uses filters for opacity
7148   return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
7149    ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
7150    computed ? "1" : "";
7151  },
7152
7153  set: function( elem, value ) {
7154   var style = elem.style,
7155    currentStyle = elem.currentStyle,
7156    opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
7157    filter = currentStyle && currentStyle.filter || style.filter || "";
7158
7159   // IE has trouble with opacity if it does not have layout
7160   // Force it by setting the zoom level
7161   style.zoom = 1;
7162
7163   // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
7164   // if value === "", then remove inline opacity #12685
7165   if ( ( value >= 1 || value === "" ) &&
7166     jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
7167     style.removeAttribute ) {
7168
7169    // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
7170    // if "filter:" is present at all, clearType is disabled, we want to avoid this
7171    // style.removeAttribute is IE Only, but so apparently is this code path...
7172    style.removeAttribute( "filter" );
7173
7174    // if there is no filter style applied in a css rule or unset inline opacity, we are done
7175    if ( value === "" || currentStyle && !currentStyle.filter ) {
7176     return;
7177    }
7178   }
7179
7180   // otherwise, set new filter values
7181   style.filter = ralpha.test( filter ) ?
7182    filter.replace( ralpha, opacity ) :
7183    filter + " " + opacity;
7184  }
7185 };
7186}
7187
7188jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
7189 function( elem, computed ) {
7190  if ( computed ) {
7191   // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
7192   // Work around by temporarily setting element display to inline-block
7193   return jQuery.swap( elem, { "display": "inline-block" },
7194    curCSS, [ elem, "marginRight" ] );
7195  }
7196 }
7197);
7198
7199// These hooks are used by animate to expand properties
7200jQuery.each({
7201 margin: "",
7202 padding: "",
7203 border: "Width"
7204}, function( prefix, suffix ) {
7205 jQuery.cssHooks[ prefix + suffix ] = {
7206  expand: function( value ) {
7207   var i = 0,
7208    expanded = {},
7209
7210    // assumes a single number if not a string
7211    parts = typeof value === "string" ? value.split(" ") : [ value ];
7212
7213   for ( ; i < 4; i++ ) {
7214    expanded[ prefix + cssExpand[ i ] + suffix ] =
7215     parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
7216   }
7217
7218   return expanded;
7219  }
7220 };
7221
7222 if ( !rmargin.test( prefix ) ) {
7223  jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
7224 }
7225});
7226
7227jQuery.fn.extend({
7228 css: function( name, value ) {
7229  return access( this, function( elem, name, value ) {
7230   var styles, len,
7231    map = {},
7232    i = 0;
7233
7234   if ( jQuery.isArray( name ) ) {
7235    styles = getStyles( elem );
7236    len = name.length;
7237
7238    for ( ; i < len; i++ ) {
7239     map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
7240    }
7241
7242    return map;
7243   }
7244
7245   return value !== undefined ?
7246    jQuery.style( elem, name, value ) :
7247    jQuery.css( elem, name );
7248  }, name, value, arguments.length > 1 );
7249 },
7250 show: function() {
7251  return showHide( this, true );
7252 },
7253 hide: function() {
7254  return showHide( this );
7255 },
7256 toggle: function( state ) {
7257  if ( typeof state === "boolean" ) {
7258   return state ? this.show() : this.hide();
7259  }
7260
7261  return this.each(function() {
7262   if ( isHidden( this ) ) {
7263    jQuery( this ).show();
7264   } else {
7265    jQuery( this ).hide();
7266   }
7267  });
7268 }
7269});
7270
7271function Tween( elem, options, prop, end, easing ) {
7272 return new Tween.prototype.init( elem, options, prop, end, easing );
7273}
7274jQuery.Tween = Tween;
7275
7276Tween.prototype = {
7277 constructor: Tween,
7278 init: function( elem, options, prop, end, easing, unit ) {
7279  this.elem = elem;
7280  this.prop = prop;
7281  this.easing = easing || "swing";
7282  this.options = options;
7283  this.start = this.now = this.cur();
7284  this.end = end;
7285  this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
7286 },
7287 cur: function() {
7288  var hooks = Tween.propHooks[ this.prop ];
7289
7290  return hooks && hooks.get ?
7291   hooks.get( this ) :
7292   Tween.propHooks._default.get( this );
7293 },
7294 run: function( percent ) {
7295  var eased,
7296   hooks = Tween.propHooks[ this.prop ];
7297
7298  if ( this.options.duration ) {
7299   this.pos = eased = jQuery.easing[ this.easing ](
7300    percent, this.options.duration * percent, 0, 1, this.options.duration
7301   );
7302  } else {
7303   this.pos = eased = percent;
7304  }
7305  this.now = ( this.end - this.start ) * eased + this.start;
7306
7307  if ( this.options.step ) {
7308   this.options.step.call( this.elem, this.now, this );
7309  }
7310
7311  if ( hooks && hooks.set ) {
7312   hooks.set( this );
7313  } else {
7314   Tween.propHooks._default.set( this );
7315  }
7316  return this;
7317 }
7318};
7319
7320Tween.prototype.init.prototype = Tween.prototype;
7321
7322Tween.propHooks = {
7323 _default: {
7324  get: function( tween ) {
7325   var result;
7326
7327   if ( tween.elem[ tween.prop ] != null &&
7328    (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
7329    return tween.elem[ tween.prop ];
7330   }
7331
7332   // passing an empty string as a 3rd parameter to .css will automatically
7333   // attempt a parseFloat and fallback to a string if the parse fails
7334   // so, simple values such as "10px" are parsed to Float.
7335   // complex values such as "rotate(1rad)" are returned as is.
7336   result = jQuery.css( tween.elem, tween.prop, "" );
7337   // Empty strings, null, undefined and "auto" are converted to 0.
7338   return !result || result === "auto" ? 0 : result;
7339  },
7340  set: function( tween ) {
7341   // use step hook for back compat - use cssHook if its there - use .style if its
7342   // available and use plain properties where available
7343   if ( jQuery.fx.step[ tween.prop ] ) {
7344    jQuery.fx.step[ tween.prop ]( tween );
7345   } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
7346    jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
7347   } else {
7348    tween.elem[ tween.prop ] = tween.now;
7349   }
7350  }
7351 }
7352};
7353
7354// Support: IE <=9
7355// Panic based approach to setting things on disconnected nodes
7356
7357Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
7358 set: function( tween ) {
7359  if ( tween.elem.nodeType && tween.elem.parentNode ) {
7360   tween.elem[ tween.prop ] = tween.now;
7361  }
7362 }
7363};
7364
7365jQuery.easing = {
7366 linear: function( p ) {
7367  return p;
7368 },
7369 swing: function( p ) {
7370  return 0.5 - Math.cos( p * Math.PI ) / 2;
7371 }
7372};
7373
7374jQuery.fx = Tween.prototype.init;
7375
7376// Back Compat <1.8 extension point
7377jQuery.fx.step = {};
7378
7379var
7380 fxNow, timerId,
7381 rfxtypes = /^(?:toggle|show|hide)$/,
7382 rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
7383 rrun = /queueHooks$/,
7384 animationPrefilters = [ defaultPrefilter ],
7385 tweeners = {
7386  "*": [ function( prop, value ) {
7387   var tween = this.createTween( prop, value ),
7388    target = tween.cur(),
7389    parts = rfxnum.exec( value ),
7390    unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
7391
7392    // Starting value computation is required for potential unit mismatches
7393    start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
7394     rfxnum.exec( jQuery.css( tween.elem, prop ) ),
7395    scale = 1,
7396    maxIterations = 20;
7397
7398   if ( start && start[ 3 ] !== unit ) {
7399    // Trust units reported by jQuery.css
7400    unit = unit || start[ 3 ];
7401
7402    // Make sure we update the tween properties later on
7403    parts = parts || [];
7404
7405    // Iteratively approximate from a nonzero starting point
7406    start = +target || 1;
7407
7408    do {
7409     // If previous iteration zeroed out, double until we get *something*
7410     // Use a string for doubling factor so we don't accidentally see scale as unchanged below
7411     scale = scale || ".5";
7412
7413     // Adjust and apply
7414     start = start / scale;
7415     jQuery.style( tween.elem, prop, start + unit );
7416
7417    // Update scale, tolerating zero or NaN from tween.cur()
7418    // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
7419    } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
7420   }
7421
7422   // Update tween properties
7423   if ( parts ) {
7424    start = tween.start = +start || +target || 0;
7425    tween.unit = unit;
7426    // If a +=/-= token was provided, we're doing a relative animation
7427    tween.end = parts[ 1 ] ?
7428     start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
7429     +parts[ 2 ];
7430   }
7431
7432   return tween;
7433  } ]
7434 };
7435
7436// Animations created synchronously will run synchronously
7437function createFxNow() {
7438 setTimeout(function() {
7439  fxNow = undefined;
7440 });
7441 return ( fxNow = jQuery.now() );
7442}
7443
7444// Generate parameters to create a standard animation
7445function genFx( type, includeWidth ) {
7446 var which,
7447  attrs = { height: type },
7448  i = 0;
7449
7450 // if we include width, step value is 1 to do all cssExpand values,
7451 // if we don't include width, step value is 2 to skip over Left and Right
7452 includeWidth = includeWidth ? 1 : 0;
7453 for ( ; i < 4 ; i += 2 - includeWidth ) {
7454  which = cssExpand[ i ];
7455  attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
7456 }
7457
7458 if ( includeWidth ) {
7459  attrs.opacity = attrs.width = type;
7460 }
7461
7462 return attrs;
7463}
7464
7465function createTween( value, prop, animation ) {
7466 var tween,
7467  collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
7468  index = 0,
7469  length = collection.length;
7470 for ( ; index < length; index++ ) {
7471  if ( (tween = collection[ index ].call( animation, prop, value )) ) {
7472
7473   // we're done with this property
7474   return tween;
7475  }
7476 }
7477}
7478
7479function defaultPrefilter( elem, props, opts ) {
7480 /* jshint validthis: true */
7481 var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
7482  anim = this,
7483  orig = {},
7484  style = elem.style,
7485  hidden = elem.nodeType && isHidden( elem ),
7486  dataShow = jQuery._data( elem, "fxshow" );
7487
7488 // handle queue: false promises
7489 if ( !opts.queue ) {
7490  hooks = jQuery._queueHooks( elem, "fx" );
7491  if ( hooks.unqueued == null ) {
7492   hooks.unqueued = 0;
7493   oldfire = hooks.empty.fire;
7494   hooks.empty.fire = function() {
7495    if ( !hooks.unqueued ) {
7496     oldfire();
7497    }
7498   };
7499  }
7500  hooks.unqueued++;
7501
7502  anim.always(function() {
7503   // doing this makes sure that the complete handler will be called
7504   // before this completes
7505   anim.always(function() {
7506    hooks.unqueued--;
7507    if ( !jQuery.queue( elem, "fx" ).length ) {
7508     hooks.empty.fire();
7509    }
7510   });
7511  });
7512 }
7513
7514 // height/width overflow pass
7515 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
7516  // Make sure that nothing sneaks out
7517  // Record all 3 overflow attributes because IE does not
7518  // change the overflow attribute when overflowX and
7519  // overflowY are set to the same value
7520  opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
7521
7522  // Set display property to inline-block for height/width
7523  // animations on inline elements that are having width/height animated
7524  display = jQuery.css( elem, "display" );
7525
7526  // Test default display if display is currently "none"
7527  checkDisplay = display === "none" ?
7528   jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
7529
7530  if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
7531
7532   // inline-level elements accept inline-block;
7533   // block-level elements need to be inline with layout
7534   if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
7535    style.display = "inline-block";
7536   } else {
7537    style.zoom = 1;
7538   }
7539  }
7540 }
7541
7542 if ( opts.overflow ) {
7543  style.overflow = "hidden";
7544  if ( !support.shrinkWrapBlocks() ) {
7545   anim.always(function() {
7546    style.overflow = opts.overflow[ 0 ];
7547    style.overflowX = opts.overflow[ 1 ];
7548    style.overflowY = opts.overflow[ 2 ];
7549   });
7550  }
7551 }
7552
7553 // show/hide pass
7554 for ( prop in props ) {
7555  value = props[ prop ];
7556  if ( rfxtypes.exec( value ) ) {
7557   delete props[ prop ];
7558   toggle = toggle || value === "toggle";
7559   if ( value === ( hidden ? "hide" : "show" ) ) {
7560
7561    // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
7562    if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
7563     hidden = true;
7564    } else {
7565     continue;
7566    }
7567   }
7568   orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
7569
7570  // Any non-fx value stops us from restoring the original display value
7571  } else {
7572   display = undefined;
7573  }
7574 }
7575
7576 if ( !jQuery.isEmptyObject( orig ) ) {
7577  if ( dataShow ) {
7578   if ( "hidden" in dataShow ) {
7579    hidden = dataShow.hidden;
7580   }
7581  } else {
7582   dataShow = jQuery._data( elem, "fxshow", {} );
7583  }
7584
7585  // store state if its toggle - enables .stop().toggle() to "reverse"
7586  if ( toggle ) {
7587   dataShow.hidden = !hidden;
7588  }
7589  if ( hidden ) {
7590   jQuery( elem ).show();
7591  } else {
7592   anim.done(function() {
7593    jQuery( elem ).hide();
7594   });
7595  }
7596  anim.done(function() {
7597   var prop;
7598   jQuery._removeData( elem, "fxshow" );
7599   for ( prop in orig ) {
7600    jQuery.style( elem, prop, orig[ prop ] );
7601   }
7602  });
7603  for ( prop in orig ) {
7604   tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
7605
7606   if ( !( prop in dataShow ) ) {
7607    dataShow[ prop ] = tween.start;
7608    if ( hidden ) {
7609     tween.end = tween.start;
7610     tween.start = prop === "width" || prop === "height" ? 1 : 0;
7611    }
7612   }
7613  }
7614
7615 // If this is a noop like .hide().hide(), restore an overwritten display value
7616 } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
7617  style.display = display;
7618 }
7619}
7620
7621function propFilter( props, specialEasing ) {
7622 var index, name, easing, value, hooks;
7623
7624 // camelCase, specialEasing and expand cssHook pass
7625 for ( index in props ) {
7626  name = jQuery.camelCase( index );
7627  easing = specialEasing[ name ];
7628  value = props[ index ];
7629  if ( jQuery.isArray( value ) ) {
7630   easing = value[ 1 ];
7631   value = props[ index ] = value[ 0 ];
7632  }
7633
7634  if ( index !== name ) {
7635   props[ name ] = value;
7636   delete props[ index ];
7637  }
7638
7639  hooks = jQuery.cssHooks[ name ];
7640  if ( hooks && "expand" in hooks ) {
7641   value = hooks.expand( value );
7642   delete props[ name ];
7643
7644   // not quite $.extend, this wont overwrite keys already present.
7645   // also - reusing 'index' from above because we have the correct "name"
7646   for ( index in value ) {
7647    if ( !( index in props ) ) {
7648     props[ index ] = value[ index ];
7649     specialEasing[ index ] = easing;
7650    }
7651   }
7652  } else {
7653   specialEasing[ name ] = easing;
7654  }
7655 }
7656}
7657
7658function Animation( elem, properties, options ) {
7659 var result,
7660  stopped,
7661  index = 0,
7662  length = animationPrefilters.length,
7663  deferred = jQuery.Deferred().always( function() {
7664   // don't match elem in the :animated selector
7665   delete tick.elem;
7666  }),
7667  tick = function() {
7668   if ( stopped ) {
7669    return false;
7670   }
7671   var currentTime = fxNow || createFxNow(),
7672    remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
7673    // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
7674    temp = remaining / animation.duration || 0,
7675    percent = 1 - temp,
7676    index = 0,
7677    length = animation.tweens.length;
7678
7679   for ( ; index < length ; index++ ) {
7680    animation.tweens[ index ].run( percent );
7681   }
7682
7683   deferred.notifyWith( elem, [ animation, percent, remaining ]);
7684
7685   if ( percent < 1 && length ) {
7686    return remaining;
7687   } else {
7688    deferred.resolveWith( elem, [ animation ] );
7689    return false;
7690   }
7691  },
7692  animation = deferred.promise({
7693   elem: elem,
7694   props: jQuery.extend( {}, properties ),
7695   opts: jQuery.extend( true, { specialEasing: {} }, options ),
7696   originalProperties: properties,
7697   originalOptions: options,
7698   startTime: fxNow || createFxNow(),
7699   duration: options.duration,
7700   tweens: [],
7701   createTween: function( prop, end ) {
7702    var tween = jQuery.Tween( elem, animation.opts, prop, end,
7703      animation.opts.specialEasing[ prop ] || animation.opts.easing );
7704    animation.tweens.push( tween );
7705    return tween;
7706   },
7707   stop: function( gotoEnd ) {
7708    var index = 0,
7709     // if we are going to the end, we want to run all the tweens
7710     // otherwise we skip this part
7711     length = gotoEnd ? animation.tweens.length : 0;
7712    if ( stopped ) {
7713     return this;
7714    }
7715    stopped = true;
7716    for ( ; index < length ; index++ ) {
7717     animation.tweens[ index ].run( 1 );
7718    }
7719
7720    // resolve when we played the last frame
7721    // otherwise, reject
7722    if ( gotoEnd ) {
7723     deferred.resolveWith( elem, [ animation, gotoEnd ] );
7724    } else {
7725     deferred.rejectWith( elem, [ animation, gotoEnd ] );
7726    }
7727    return this;
7728   }
7729  }),
7730  props = animation.props;
7731
7732 propFilter( props, animation.opts.specialEasing );
7733
7734 for ( ; index < length ; index++ ) {
7735  result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
7736  if ( result ) {
7737   return result;
7738  }
7739 }
7740
7741 jQuery.map( props, createTween, animation );
7742
7743 if ( jQuery.isFunction( animation.opts.start ) ) {
7744  animation.opts.start.call( elem, animation );
7745 }
7746
7747 jQuery.fx.timer(
7748  jQuery.extend( tick, {
7749   elem: elem,
7750   anim: animation,
7751   queue: animation.opts.queue
7752  })
7753 );
7754
7755 // attach callbacks from options
7756 return animation.progress( animation.opts.progress )
7757  .done( animation.opts.done, animation.opts.complete )
7758  .fail( animation.opts.fail )
7759  .always( animation.opts.always );
7760}
7761
7762jQuery.Animation = jQuery.extend( Animation, {
7763 tweener: function( props, callback ) {
7764  if ( jQuery.isFunction( props ) ) {
7765   callback = props;
7766   props = [ "*" ];
7767  } else {
7768   props = props.split(" ");
7769  }
7770
7771  var prop,
7772   index = 0,
7773   length = props.length;
7774
7775  for ( ; index < length ; index++ ) {
7776   prop = props[ index ];
7777   tweeners[ prop ] = tweeners[ prop ] || [];
7778   tweeners[ prop ].unshift( callback );
7779  }
7780 },
7781
7782 prefilter: function( callback, prepend ) {
7783  if ( prepend ) {
7784   animationPrefilters.unshift( callback );
7785  } else {
7786   animationPrefilters.push( callback );
7787  }
7788 }
7789});
7790
7791jQuery.speed = function( speed, easing, fn ) {
7792 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
7793  complete: fn || !fn && easing ||
7794   jQuery.isFunction( speed ) && speed,
7795  duration: speed,
7796  easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
7797 };
7798
7799 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
7800  opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
7801
7802 // normalize opt.queue - true/undefined/null -> "fx"
7803 if ( opt.queue == null || opt.queue === true ) {
7804  opt.queue = "fx";
7805 }
7806
7807 // Queueing
7808 opt.old = opt.complete;
7809
7810 opt.complete = function() {
7811  if ( jQuery.isFunction( opt.old ) ) {
7812   opt.old.call( this );
7813  }
7814
7815  if ( opt.queue ) {
7816   jQuery.dequeue( this, opt.queue );
7817  }
7818 };
7819
7820 return opt;
7821};
7822
7823jQuery.fn.extend({
7824 fadeTo: function( speed, to, easing, callback ) {
7825
7826  // show any hidden elements after setting opacity to 0
7827  return this.filter( isHidden ).css( "opacity", 0 ).show()
7828
7829   // animate to the value specified
7830   .end().animate({ opacity: to }, speed, easing, callback );
7831 },
7832 animate: function( prop, speed, easing, callback ) {
7833  var empty = jQuery.isEmptyObject( prop ),
7834   optall = jQuery.speed( speed, easing, callback ),
7835   doAnimation = function() {
7836    // Operate on a copy of prop so per-property easing won't be lost
7837    var anim = Animation( this, jQuery.extend( {}, prop ), optall );
7838
7839    // Empty animations, or finishing resolves immediately
7840    if ( empty || jQuery._data( this, "finish" ) ) {
7841     anim.stop( true );
7842    }
7843   };
7844   doAnimation.finish = doAnimation;
7845
7846  return empty || optall.queue === false ?
7847   this.each( doAnimation ) :
7848   this.queue( optall.queue, doAnimation );
7849 },
7850 stop: function( type, clearQueue, gotoEnd ) {
7851  var stopQueue = function( hooks ) {
7852   var stop = hooks.stop;
7853   delete hooks.stop;
7854   stop( gotoEnd );
7855  };
7856
7857  if ( typeof type !== "string" ) {
7858   gotoEnd = clearQueue;
7859   clearQueue = type;
7860   type = undefined;
7861  }
7862  if ( clearQueue && type !== false ) {
7863   this.queue( type || "fx", [] );
7864  }
7865
7866  return this.each(function() {
7867   var dequeue = true,
7868    index = type != null && type + "queueHooks",
7869    timers = jQuery.timers,
7870    data = jQuery._data( this );
7871
7872   if ( index ) {
7873    if ( data[ index ] && data[ index ].stop ) {
7874     stopQueue( data[ index ] );
7875    }
7876   } else {
7877    for ( index in data ) {
7878     if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
7879      stopQueue( data[ index ] );
7880     }
7881    }
7882   }
7883
7884   for ( index = timers.length; index--; ) {
7885    if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
7886     timers[ index ].anim.stop( gotoEnd );
7887     dequeue = false;
7888     timers.splice( index, 1 );
7889    }
7890   }
7891
7892   // start the next in the queue if the last step wasn't forced
7893   // timers currently will call their complete callbacks, which will dequeue
7894   // but only if they were gotoEnd
7895   if ( dequeue || !gotoEnd ) {
7896    jQuery.dequeue( this, type );
7897   }
7898  });
7899 },
7900 finish: function( type ) {
7901  if ( type !== false ) {
7902   type = type || "fx";
7903  }
7904  return this.each(function() {
7905   var index,
7906    data = jQuery._data( this ),
7907    queue = data[ type + "queue" ],
7908    hooks = data[ type + "queueHooks" ],
7909    timers = jQuery.timers,
7910    length = queue ? queue.length : 0;
7911
7912   // enable finishing flag on private data
7913   data.finish = true;
7914
7915   // empty the queue first
7916   jQuery.queue( this, type, [] );
7917
7918   if ( hooks && hooks.stop ) {
7919    hooks.stop.call( this, true );
7920   }
7921
7922   // look for any active animations, and finish them
7923   for ( index = timers.length; index--; ) {
7924    if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
7925     timers[ index ].anim.stop( true );
7926     timers.splice( index, 1 );
7927    }
7928   }
7929
7930   // look for any animations in the old queue and finish them
7931   for ( index = 0; index < length; index++ ) {
7932    if ( queue[ index ] && queue[ index ].finish ) {
7933     queue[ index ].finish.call( this );
7934    }
7935   }
7936
7937   // turn off finishing flag
7938   delete data.finish;
7939  });
7940 }
7941});
7942
7943jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
7944 var cssFn = jQuery.fn[ name ];
7945 jQuery.fn[ name ] = function( speed, easing, callback ) {
7946  return speed == null || typeof speed === "boolean" ?
7947   cssFn.apply( this, arguments ) :
7948   this.animate( genFx( name, true ), speed, easing, callback );
7949 };
7950});
7951
7952// Generate shortcuts for custom animations
7953jQuery.each({
7954 slideDown: genFx("show"),
7955 slideUp: genFx("hide"),
7956 slideToggle: genFx("toggle"),
7957 fadeIn: { opacity: "show" },
7958 fadeOut: { opacity: "hide" },
7959 fadeToggle: { opacity: "toggle" }
7960}, function( name, props ) {
7961 jQuery.fn[ name ] = function( speed, easing, callback ) {
7962  return this.animate( props, speed, easing, callback );
7963 };
7964});
7965
7966jQuery.timers = [];
7967jQuery.fx.tick = function() {
7968 var timer,
7969  timers = jQuery.timers,
7970  i = 0;
7971
7972 fxNow = jQuery.now();
7973
7974 for ( ; i < timers.length; i++ ) {
7975  timer = timers[ i ];
7976  // Checks the timer has not already been removed
7977  if ( !timer() && timers[ i ] === timer ) {
7978   timers.splice( i--, 1 );
7979  }
7980 }
7981
7982 if ( !timers.length ) {
7983  jQuery.fx.stop();
7984 }
7985 fxNow = undefined;
7986};
7987
7988jQuery.fx.timer = function( timer ) {
7989 jQuery.timers.push( timer );
7990 if ( timer() ) {
7991  jQuery.fx.start();
7992 } else {
7993  jQuery.timers.pop();
7994 }
7995};
7996
7997jQuery.fx.interval = 13;
7998
7999jQuery.fx.start = function() {
8000 if ( !timerId ) {
8001  timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
8002 }
8003};
8004
8005jQuery.fx.stop = function() {
8006 clearInterval( timerId );
8007 timerId = null;
8008};
8009
8010jQuery.fx.speeds = {
8011 slow: 600,
8012 fast: 200,
8013 // Default speed
8014 _default: 400
8015};
8016
8017// Based off of the plugin by Clint Helfers, with permission.
8018// http://blindsignals.com/index.php/2009/07/jquery-delay/
8019jQuery.fn.delay = function( time, type ) {
8020 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
8021 type = type || "fx";
8022
8023 return this.queue( type, function( next, hooks ) {
8024  var timeout = setTimeout( next, time );
8025  hooks.stop = function() {
8026   clearTimeout( timeout );
8027  };
8028 });
8029};
8030
8031(function() {
8032 // Minified: var a,b,c,d,e
8033 var input, div, select, a, opt;
8034
8035 // Setup
8036 div = document.createElement( "div" );
8037 div.setAttribute( "className", "t" );
8038 div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
8039 a = div.getElementsByTagName("a")[ 0 ];
8040
8041 // First batch of tests.
8042 select = document.createElement("select");
8043 opt = select.appendChild( document.createElement("option") );
8044 input = div.getElementsByTagName("input")[ 0 ];
8045
8046 a.style.cssText = "top:1px";
8047
8048 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
8049 support.getSetAttribute = div.className !== "t";
8050
8051 // Get the style information from getAttribute
8052 // (IE uses .cssText instead)
8053 support.style = /top/.test( a.getAttribute("style") );
8054
8055 // Make sure that URLs aren't manipulated
8056 // (IE normalizes it by default)
8057 support.hrefNormalized = a.getAttribute("href") === "/a";
8058
8059 // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
8060 support.checkOn = !!input.value;
8061
8062 // Make sure that a selected-by-default option has a working selected property.
8063 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
8064 support.optSelected = opt.selected;
8065
8066 // Tests for enctype support on a form (#6743)
8067 support.enctype = !!document.createElement("form").enctype;
8068
8069 // Make sure that the options inside disabled selects aren't marked as disabled
8070 // (WebKit marks them as disabled)
8071 select.disabled = true;
8072 support.optDisabled = !opt.disabled;
8073
8074 // Support: IE8 only
8075 // Check if we can trust getAttribute("value")
8076 input = document.createElement( "input" );
8077 input.setAttribute( "value", "" );
8078 support.input = input.getAttribute( "value" ) === "";
8079
8080 // Check if an input maintains its value after becoming a radio
8081 input.value = "t";
8082 input.setAttribute( "type", "radio" );
8083 support.radioValue = input.value === "t";
8084})();
8085
8086var rreturn = /\r/g;
8087
8088jQuery.fn.extend({
8089 val: function( value ) {
8090  var hooks, ret, isFunction,
8091   elem = this[0];
8092
8093  if ( !arguments.length ) {
8094   if ( elem ) {
8095    hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
8096
8097    if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
8098     return ret;
8099    }
8100
8101    ret = elem.value;
8102
8103    return typeof ret === "string" ?
8104     // handle most common string cases
8105     ret.replace(rreturn, "") :
8106     // handle cases where value is null/undef or number
8107     ret == null ? "" : ret;
8108   }
8109
8110   return;
8111  }
8112
8113  isFunction = jQuery.isFunction( value );
8114
8115  return this.each(function( i ) {
8116   var val;
8117
8118   if ( this.nodeType !== 1 ) {
8119    return;
8120   }
8121
8122   if ( isFunction ) {
8123    val = value.call( this, i, jQuery( this ).val() );
8124   } else {
8125    val = value;
8126   }
8127
8128   // Treat null/undefined as ""; convert numbers to string
8129   if ( val == null ) {
8130    val = "";
8131   } else if ( typeof val === "number" ) {
8132    val += "";
8133   } else if ( jQuery.isArray( val ) ) {
8134    val = jQuery.map( val, function( value ) {
8135     return value == null ? "" : value + "";
8136    });
8137   }
8138
8139   hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
8140
8141   // If set returns undefined, fall back to normal setting
8142   if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
8143    this.value = val;
8144   }
8145  });
8146 }
8147});
8148
8149jQuery.extend({
8150 valHooks: {
8151  option: {
8152   get: function( elem ) {
8153    var val = jQuery.find.attr( elem, "value" );
8154    return val != null ?
8155     val :
8156     // Support: IE10-11+
8157     // option.text throws exceptions (#14686, #14858)
8158     jQuery.trim( jQuery.text( elem ) );
8159   }
8160  },
8161  select: {
8162   get: function( elem ) {
8163    var value, option,
8164     options = elem.options,
8165     index = elem.selectedIndex,
8166     one = elem.type === "select-one" || index < 0,
8167     values = one ? null : [],
8168     max = one ? index + 1 : options.length,
8169     i = index < 0 ?
8170      max :
8171      one ? index : 0;
8172
8173    // Loop through all the selected options
8174    for ( ; i < max; i++ ) {
8175     option = options[ i ];
8176
8177     // oldIE doesn't update selected after form reset (#2551)
8178     if ( ( option.selected || i === index ) &&
8179       // Don't return options that are disabled or in a disabled optgroup
8180       ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
8181       ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
8182
8183      // Get the specific value for the option
8184      value = jQuery( option ).val();
8185
8186      // We don't need an array for one selects
8187      if ( one ) {
8188       return value;
8189      }
8190
8191      // Multi-Selects return an array
8192      values.push( value );
8193     }
8194    }
8195
8196    return values;
8197   },
8198
8199   set: function( elem, value ) {
8200    var optionSet, option,
8201     options = elem.options,
8202     values = jQuery.makeArray( value ),
8203     i = options.length;
8204
8205    while ( i-- ) {
8206     option = options[ i ];
8207
8208     if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
8209
8210      // Support: IE6
8211      // When new option element is added to select box we need to
8212      // force reflow of newly added node in order to workaround delay
8213      // of initialization properties
8214      try {
8215       option.selected = optionSet = true;
8216
8217      } catch ( _ ) {
8218
8219       // Will be executed only in IE6
8220       option.scrollHeight;
8221      }
8222
8223     } else {
8224      option.selected = false;
8225     }
8226    }
8227
8228    // Force browsers to behave consistently when non-matching value is set
8229    if ( !optionSet ) {
8230     elem.selectedIndex = -1;
8231    }
8232
8233    return options;
8234   }
8235  }
8236 }
8237});
8238
8239// Radios and checkboxes getter/setter
8240jQuery.each([ "radio", "checkbox" ], function() {
8241 jQuery.valHooks[ this ] = {
8242  set: function( elem, value ) {
8243   if ( jQuery.isArray( value ) ) {
8244    return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
8245   }
8246  }
8247 };
8248 if ( !support.checkOn ) {
8249  jQuery.valHooks[ this ].get = function( elem ) {
8250   // Support: Webkit
8251   // "" is returned instead of "on" if a value isn't specified
8252   return elem.getAttribute("value") === null ? "on" : elem.value;
8253  };
8254 }
8255});
8256
8257var nodeHook, boolHook,
8258 attrHandle = jQuery.expr.attrHandle,
8259 ruseDefault = /^(?:checked|selected)$/i,
8260 getSetAttribute = support.getSetAttribute,
8261 getSetInput = support.input;
8262
8263jQuery.fn.extend({
8264 attr: function( name, value ) {
8265  return access( this, jQuery.attr, name, value, arguments.length > 1 );
8266 },
8267
8268 removeAttr: function( name ) {
8269  return this.each(function() {
8270   jQuery.removeAttr( this, name );
8271  });
8272 }
8273});
8274
8275jQuery.extend({
8276 attr: function( elem, name, value ) {
8277  var hooks, ret,
8278   nType = elem.nodeType;
8279
8280  // don't get/set attributes on text, comment and attribute nodes
8281  if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
8282   return;
8283  }
8284
8285  // Fallback to prop when attributes are not supported
8286  if ( typeof elem.getAttribute === strundefined ) {
8287   return jQuery.prop( elem, name, value );
8288  }
8289
8290  // All attributes are lowercase
8291  // Grab necessary hook if one is defined
8292  if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
8293   name = name.toLowerCase();
8294   hooks = jQuery.attrHooks[ name ] ||
8295    ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
8296  }
8297
8298  if ( value !== undefined ) {
8299
8300   if ( value === null ) {
8301    jQuery.removeAttr( elem, name );
8302
8303   } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
8304    return ret;
8305
8306   } else {
8307    elem.setAttribute( name, value + "" );
8308    return value;
8309   }
8310
8311  } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
8312   return ret;
8313
8314  } else {
8315   ret = jQuery.find.attr( elem, name );
8316
8317   // Non-existent attributes return null, we normalize to undefined
8318   return ret == null ?
8319    undefined :
8320    ret;
8321  }
8322 },
8323
8324 removeAttr: function( elem, value ) {
8325  var name, propName,
8326   i = 0,
8327   attrNames = value && value.match( rnotwhite );
8328
8329  if ( attrNames && elem.nodeType === 1 ) {
8330   while ( (name = attrNames[i++]) ) {
8331    propName = jQuery.propFix[ name ] || name;
8332
8333    // Boolean attributes get special treatment (#10870)
8334    if ( jQuery.expr.match.bool.test( name ) ) {
8335     // Set corresponding property to false
8336     if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
8337      elem[ propName ] = false;
8338     // Support: IE<9
8339     // Also clear defaultChecked/defaultSelected (if appropriate)
8340     } else {
8341      elem[ jQuery.camelCase( "default-" + name ) ] =
8342       elem[ propName ] = false;
8343     }
8344
8345    // See #9699 for explanation of this approach (setting first, then removal)
8346    } else {
8347     jQuery.attr( elem, name, "" );
8348    }
8349
8350    elem.removeAttribute( getSetAttribute ? name : propName );
8351   }
8352  }
8353 },
8354
8355 attrHooks: {
8356  type: {
8357   set: function( elem, value ) {
8358    if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
8359     // Setting the type on a radio button after the value resets the value in IE6-9
8360     // Reset value to default in case type is set after value during creation
8361     var val = elem.value;
8362     elem.setAttribute( "type", value );
8363     if ( val ) {
8364      elem.value = val;
8365     }
8366     return value;
8367    }
8368   }
8369  }
8370 }
8371});
8372
8373// Hook for boolean attributes
8374boolHook = {
8375 set: function( elem, value, name ) {
8376  if ( value === false ) {
8377   // Remove boolean attributes when set to false
8378   jQuery.removeAttr( elem, name );
8379  } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
8380   // IE<8 needs the *property* name
8381   elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
8382
8383  // Use defaultChecked and defaultSelected for oldIE
8384  } else {
8385   elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
8386  }
8387
8388  return name;
8389 }
8390};
8391
8392// Retrieve booleans specially
8393jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
8394
8395 var getter = attrHandle[ name ] || jQuery.find.attr;
8396
8397 attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
8398  function( elem, name, isXML ) {
8399   var ret, handle;
8400   if ( !isXML ) {
8401    // Avoid an infinite loop by temporarily removing this function from the getter
8402    handle = attrHandle[ name ];
8403    attrHandle[ name ] = ret;
8404    ret = getter( elem, name, isXML ) != null ?
8405     name.toLowerCase() :
8406     null;
8407    attrHandle[ name ] = handle;
8408   }
8409   return ret;
8410  } :
8411  function( elem, name, isXML ) {
8412   if ( !isXML ) {
8413    return elem[ jQuery.camelCase( "default-" + name ) ] ?
8414     name.toLowerCase() :
8415     null;
8416   }
8417  };
8418});
8419
8420// fix oldIE attroperties
8421if ( !getSetInput || !getSetAttribute ) {
8422 jQuery.attrHooks.value = {
8423  set: function( elem, value, name ) {
8424   if ( jQuery.nodeName( elem, "input" ) ) {
8425    // Does not return so that setAttribute is also used
8426    elem.defaultValue = value;
8427   } else {
8428    // Use nodeHook if defined (#1954); otherwise setAttribute is fine
8429    return nodeHook && nodeHook.set( elem, value, name );
8430   }
8431  }
8432 };
8433}
8434
8435// IE6/7 do not support getting/setting some attributes with get/setAttribute
8436if ( !getSetAttribute ) {
8437
8438 // Use this for any attribute in IE6/7
8439 // This fixes almost every IE6/7 issue
8440 nodeHook = {
8441  set: function( elem, value, name ) {
8442   // Set the existing or create a new attribute node
8443   var ret = elem.getAttributeNode( name );
8444   if ( !ret ) {
8445    elem.setAttributeNode(
8446     (ret = elem.ownerDocument.createAttribute( name ))
8447    );
8448   }
8449
8450   ret.value = value += "";
8451
8452   // Break association with cloned elements by also using setAttribute (#9646)
8453   if ( name === "value" || value === elem.getAttribute( name ) ) {
8454    return value;
8455   }
8456  }
8457 };
8458
8459 // Some attributes are constructed with empty-string values when not defined
8460 attrHandle.id = attrHandle.name = attrHandle.coords =
8461  function( elem, name, isXML ) {
8462   var ret;
8463   if ( !isXML ) {
8464    return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
8465     ret.value :
8466     null;
8467   }
8468  };
8469
8470 // Fixing value retrieval on a button requires this module
8471 jQuery.valHooks.button = {
8472  get: function( elem, name ) {
8473   var ret = elem.getAttributeNode( name );
8474   if ( ret && ret.specified ) {
8475    return ret.value;
8476   }
8477  },
8478  set: nodeHook.set
8479 };
8480
8481 // Set contenteditable to false on removals(#10429)
8482 // Setting to empty string throws an error as an invalid value
8483 jQuery.attrHooks.contenteditable = {
8484  set: function( elem, value, name ) {
8485   nodeHook.set( elem, value === "" ? false : value, name );
8486  }
8487 };
8488
8489 // Set width and height to auto instead of 0 on empty string( Bug #8150 )
8490 // This is for removals
8491 jQuery.each([ "width", "height" ], function( i, name ) {
8492  jQuery.attrHooks[ name ] = {
8493   set: function( elem, value ) {
8494    if ( value === "" ) {
8495     elem.setAttribute( name, "auto" );
8496     return value;
8497    }
8498   }
8499  };
8500 });
8501}
8502
8503if ( !support.style ) {
8504 jQuery.attrHooks.style = {
8505  get: function( elem ) {
8506   // Return undefined in the case of empty string
8507   // Note: IE uppercases css property names, but if we were to .toLowerCase()
8508   // .cssText, that would destroy case senstitivity in URL's, like in "background"
8509   return elem.style.cssText || undefined;
8510  },
8511  set: function( elem, value ) {
8512   return ( elem.style.cssText = value + "" );
8513  }
8514 };
8515}
8516
8517var rfocusable = /^(?:input|select|textarea|button|object)$/i,
8518 rclickable = /^(?:a|area)$/i;
8519
8520jQuery.fn.extend({
8521 prop: function( name, value ) {
8522  return access( this, jQuery.prop, name, value, arguments.length > 1 );
8523 },
8524
8525 removeProp: function( name ) {
8526  name = jQuery.propFix[ name ] || name;
8527  return this.each(function() {
8528   // try/catch handles cases where IE balks (such as removing a property on window)
8529   try {
8530    this[ name ] = undefined;
8531    delete this[ name ];
8532   } catch( e ) {}
8533  });
8534 }
8535});
8536
8537jQuery.extend({
8538 propFix: {
8539  "for": "htmlFor",
8540  "class": "className"
8541 },
8542
8543 prop: function( elem, name, value ) {
8544  var ret, hooks, notxml,
8545   nType = elem.nodeType;
8546
8547  // don't get/set properties on text, comment and attribute nodes
8548  if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
8549   return;
8550  }
8551
8552  notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
8553
8554  if ( notxml ) {
8555   // Fix name and attach hooks
8556   name = jQuery.propFix[ name ] || name;
8557   hooks = jQuery.propHooks[ name ];
8558  }
8559
8560  if ( value !== undefined ) {
8561   return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
8562    ret :
8563    ( elem[ name ] = value );
8564
8565  } else {
8566   return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
8567    ret :
8568    elem[ name ];
8569  }
8570 },
8571
8572 propHooks: {
8573  tabIndex: {
8574   get: function( elem ) {
8575    // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
8576    // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
8577    // Use proper attribute retrieval(#12072)
8578    var tabindex = jQuery.find.attr( elem, "tabindex" );
8579
8580    return tabindex ?
8581     parseInt( tabindex, 10 ) :
8582     rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
8583      0 :
8584      -1;
8585   }
8586  }
8587 }
8588});
8589
8590// Some attributes require a special call on IE
8591// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
8592if ( !support.hrefNormalized ) {
8593 // href/src property should get the full normalized URL (#10299/#12915)
8594 jQuery.each([ "href", "src" ], function( i, name ) {
8595  jQuery.propHooks[ name ] = {
8596   get: function( elem ) {
8597    return elem.getAttribute( name, 4 );
8598   }
8599  };
8600 });
8601}
8602
8603// Support: Safari, IE9+
8604// mis-reports the default selected property of an option
8605// Accessing the parent's selectedIndex property fixes it
8606if ( !support.optSelected ) {
8607 jQuery.propHooks.selected = {
8608  get: function( elem ) {
8609   var parent = elem.parentNode;
8610
8611   if ( parent ) {
8612    parent.selectedIndex;
8613
8614    // Make sure that it also works with optgroups, see #5701
8615    if ( parent.parentNode ) {
8616     parent.parentNode.selectedIndex;
8617    }
8618   }
8619   return null;
8620  }
8621 };
8622}
8623
8624jQuery.each([
8625 "tabIndex",
8626 "readOnly",
8627 "maxLength",
8628 "cellSpacing",
8629 "cellPadding",
8630 "rowSpan",
8631 "colSpan",
8632 "useMap",
8633 "frameBorder",
8634 "contentEditable"
8635], function() {
8636 jQuery.propFix[ this.toLowerCase() ] = this;
8637});
8638
8639// IE6/7 call enctype encoding
8640if ( !support.enctype ) {
8641 jQuery.propFix.enctype = "encoding";
8642}
8643
8644var rclass = /[\t\r\n\f]/g;
8645
8646jQuery.fn.extend({
8647 addClass: function( value ) {
8648  var classes, elem, cur, clazz, j, finalValue,
8649   i = 0,
8650   len = this.length,
8651   proceed = typeof value === "string" && value;
8652
8653  if ( jQuery.isFunction( value ) ) {
8654   return this.each(function( j ) {
8655    jQuery( this ).addClass( value.call( this, j, this.className ) );
8656   });
8657  }
8658
8659  if ( proceed ) {
8660   // The disjunction here is for better compressibility (see removeClass)
8661   classes = ( value || "" ).match( rnotwhite ) || [];
8662
8663   for ( ; i < len; i++ ) {
8664    elem = this[ i ];
8665    cur = elem.nodeType === 1 && ( elem.className ?
8666     ( " " + elem.className + " " ).replace( rclass, " " ) :
8667     " "
8668    );
8669
8670    if ( cur ) {
8671     j = 0;
8672     while ( (clazz = classes[j++]) ) {
8673      if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
8674       cur += clazz + " ";
8675      }
8676     }
8677
8678     // only assign if different to avoid unneeded rendering.
8679     finalValue = jQuery.trim( cur );
8680     if ( elem.className !== finalValue ) {
8681      elem.className = finalValue;
8682     }
8683    }
8684   }
8685  }
8686
8687  return this;
8688 },
8689
8690 removeClass: function( value ) {
8691  var classes, elem, cur, clazz, j, finalValue,
8692   i = 0,
8693   len = this.length,
8694   proceed = arguments.length === 0 || typeof value === "string" && value;
8695
8696  if ( jQuery.isFunction( value ) ) {
8697   return this.each(function( j ) {
8698    jQuery( this ).removeClass( value.call( this, j, this.className ) );
8699   });
8700  }
8701  if ( proceed ) {
8702   classes = ( value || "" ).match( rnotwhite ) || [];
8703
8704   for ( ; i < len; i++ ) {
8705    elem = this[ i ];
8706    // This expression is here for better compressibility (see addClass)
8707    cur = elem.nodeType === 1 && ( elem.className ?
8708     ( " " + elem.className + " " ).replace( rclass, " " ) :
8709     ""
8710    );
8711
8712    if ( cur ) {
8713     j = 0;
8714     while ( (clazz = classes[j++]) ) {
8715      // Remove *all* instances
8716      while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
8717       cur = cur.replace( " " + clazz + " ", " " );
8718      }
8719     }
8720
8721     // only assign if different to avoid unneeded rendering.
8722     finalValue = value ? jQuery.trim( cur ) : "";
8723     if ( elem.className !== finalValue ) {
8724      elem.className = finalValue;
8725     }
8726    }
8727   }
8728  }
8729
8730  return this;
8731 },
8732
8733 toggleClass: function( value, stateVal ) {
8734  var type = typeof value;
8735
8736  if ( typeof stateVal === "boolean" && type === "string" ) {
8737   return stateVal ? this.addClass( value ) : this.removeClass( value );
8738  }
8739
8740  if ( jQuery.isFunction( value ) ) {
8741   return this.each(function( i ) {
8742    jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
8743   });
8744  }
8745
8746  return this.each(function() {
8747   if ( type === "string" ) {
8748    // toggle individual class names
8749    var className,
8750     i = 0,
8751     self = jQuery( this ),
8752     classNames = value.match( rnotwhite ) || [];
8753
8754    while ( (className = classNames[ i++ ]) ) {
8755     // check each className given, space separated list
8756     if ( self.hasClass( className ) ) {
8757      self.removeClass( className );
8758     } else {
8759      self.addClass( className );
8760     }
8761    }
8762
8763   // Toggle whole class name
8764   } else if ( type === strundefined || type === "boolean" ) {
8765    if ( this.className ) {
8766     // store className if set
8767     jQuery._data( this, "__className__", this.className );
8768    }
8769
8770    // If the element has a class name or if we're passed "false",
8771    // then remove the whole classname (if there was one, the above saved it).
8772    // Otherwise bring back whatever was previously saved (if anything),
8773    // falling back to the empty string if nothing was stored.
8774    this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
8775   }
8776  });
8777 },
8778
8779 hasClass: function( selector ) {
8780  var className = " " + selector + " ",
8781   i = 0,
8782   l = this.length;
8783  for ( ; i < l; i++ ) {
8784   if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
8785    return true;
8786   }
8787  }
8788
8789  return false;
8790 }
8791});
8792
8793// Return jQuery for attributes-only inclusion
8794
8795jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
8796 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
8797 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
8798
8799 // Handle event binding
8800 jQuery.fn[ name ] = function( data, fn ) {
8801  return arguments.length > 0 ?
8802   this.on( name, null, data, fn ) :
8803   this.trigger( name );
8804 };
8805});
8806
8807jQuery.fn.extend({
8808 hover: function( fnOver, fnOut ) {
8809  return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
8810 },
8811
8812 bind: function( types, data, fn ) {
8813  return this.on( types, null, data, fn );
8814 },
8815 unbind: function( types, fn ) {
8816  return this.off( types, null, fn );
8817 },
8818
8819 delegate: function( selector, types, data, fn ) {
8820  return this.on( types, selector, data, fn );
8821 },
8822 undelegate: function( selector, types, fn ) {
8823  // ( namespace ) or ( selector, types [, fn] )
8824  return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
8825 }
8826});
8827
8828var nonce = jQuery.now();
8829
8830var rquery = (/\?/);
8831
8832var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
8833
8834jQuery.parseJSON = function( data ) {
8835 // Attempt to parse using the native JSON parser first
8836 if ( window.JSON && window.JSON.parse ) {
8837  // Support: Android 2.3
8838  // Workaround failure to string-cast null input
8839  return window.JSON.parse( data + "" );
8840 }
8841
8842 var requireNonComma,
8843  depth = null,
8844  str = jQuery.trim( data + "" );
8845
8846 // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
8847 // after removing valid tokens
8848 return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
8849
8850  // Force termination if we see a misplaced comma
8851  if ( requireNonComma && comma ) {
8852   depth = 0;
8853  }
8854
8855  // Perform no more replacements after returning to outermost depth
8856  if ( depth === 0 ) {
8857   return token;
8858  }
8859
8860  // Commas must not follow "[", "{", or ","
8861  requireNonComma = open || comma;
8862
8863  // Determine new depth
8864  // array/object open ("[" or "{"): depth += true - false (increment)
8865  // array/object close ("]" or "}"): depth += false - true (decrement)
8866  // other cases ("," or primitive): depth += true - true (numeric cast)
8867  depth += !close - !open;
8868
8869  // Remove this token
8870  return "";
8871 }) ) ?
8872  ( Function( "return " + str ) )() :
8873  jQuery.error( "Invalid JSON: " + data );
8874};
8875
8876// Cross-browser xml parsing
8877jQuery.parseXML = function( data ) {
8878 var xml, tmp;
8879 if ( !data || typeof data !== "string" ) {
8880  return null;
8881 }
8882 try {
8883  if ( window.DOMParser ) { // Standard
8884   tmp = new DOMParser();
8885   xml = tmp.parseFromString( data, "text/xml" );
8886  } else { // IE
8887   xml = new ActiveXObject( "Microsoft.XMLDOM" );
8888   xml.async = "false";
8889   xml.loadXML( data );
8890  }
8891 } catch( e ) {
8892  xml = undefined;
8893 }
8894 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
8895  jQuery.error( "Invalid XML: " + data );
8896 }
8897 return xml;
8898};
8899
8900var
8901 // Document location
8902 ajaxLocParts,
8903 ajaxLocation,
8904
8905 rhash = /#.*$/,
8906 rts = /([?&])_=[^&]*/,
8907 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
8908 // #7653, #8125, #8152: local protocol detection
8909 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
8910 rnoContent = /^(?:GET|HEAD)$/,
8911 rprotocol = /^\/\//,
8912 rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
8913
8914 /* Prefilters
8915  * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
8916  * 2) These are called:
8917  *    - BEFORE asking for a transport
8918  *    - AFTER param serialization (s.data is a string if s.processData is true)
8919  * 3) key is the dataType
8920  * 4) the catchall symbol "*" can be used
8921  * 5) execution will start with transport dataType and THEN continue down to "*" if needed
8922  */
8923 prefilters = {},
8924
8925 /* Transports bindings
8926  * 1) key is the dataType
8927  * 2) the catchall symbol "*" can be used
8928  * 3) selection will start with transport dataType and THEN go to "*" if needed
8929  */
8930 transports = {},
8931
8932 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
8933 allTypes = "*/".concat("*");
8934
8935// #8138, IE may throw an exception when accessing
8936// a field from window.location if document.domain has been set
8937try {
8938 ajaxLocation = location.href;
8939} catch( e ) {
8940 // Use the href attribute of an A element
8941 // since IE will modify it given document.location
8942 ajaxLocation = document.createElement( "a" );
8943 ajaxLocation.href = "";
8944 ajaxLocation = ajaxLocation.href;
8945}
8946
8947// Segment location into parts
8948ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
8949
8950// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
8951function addToPrefiltersOrTransports( structure ) {
8952
8953 // dataTypeExpression is optional and defaults to "*"
8954 return function( dataTypeExpression, func ) {
8955
8956  if ( typeof dataTypeExpression !== "string" ) {
8957   func = dataTypeExpression;
8958   dataTypeExpression = "*";
8959  }
8960
8961  var dataType,
8962   i = 0,
8963   dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
8964
8965  if ( jQuery.isFunction( func ) ) {
8966   // For each dataType in the dataTypeExpression
8967   while ( (dataType = dataTypes[i++]) ) {
8968    // Prepend if requested
8969    if ( dataType.charAt( 0 ) === "+" ) {
8970     dataType = dataType.slice( 1 ) || "*";
8971     (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
8972
8973    // Otherwise append
8974    } else {
8975     (structure[ dataType ] = structure[ dataType ] || []).push( func );
8976    }
8977   }
8978  }
8979 };
8980}
8981
8982// Base inspection function for prefilters and transports
8983function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
8984
8985 var inspected = {},
8986  seekingTransport = ( structure === transports );
8987
8988 function inspect( dataType ) {
8989  var selected;
8990  inspected[ dataType ] = true;
8991  jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
8992   var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
8993   if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
8994    options.dataTypes.unshift( dataTypeOrTransport );
8995    inspect( dataTypeOrTransport );
8996    return false;
8997   } else if ( seekingTransport ) {
8998    return !( selected = dataTypeOrTransport );
8999   }
9000  });
9001  return selected;
9002 }
9003
9004 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
9005}
9006
9007// A special extend for ajax options
9008// that takes "flat" options (not to be deep extended)
9009// Fixes #9887
9010function ajaxExtend( target, src ) {
9011 var deep, key,
9012  flatOptions = jQuery.ajaxSettings.flatOptions || {};
9013
9014 for ( key in src ) {
9015  if ( src[ key ] !== undefined ) {
9016   ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
9017  }
9018 }
9019 if ( deep ) {
9020  jQuery.extend( true, target, deep );
9021 }
9022
9023 return target;
9024}
9025
9026/* Handles responses to an ajax request:
9027 * - finds the right dataType (mediates between content-type and expected dataType)
9028 * - returns the corresponding response
9029 */
9030function ajaxHandleResponses( s, jqXHR, responses ) {
9031 var firstDataType, ct, finalDataType, type,
9032  contents = s.contents,
9033  dataTypes = s.dataTypes;
9034
9035 // Remove auto dataType and get content-type in the process
9036 while ( dataTypes[ 0 ] === "*" ) {
9037  dataTypes.shift();
9038  if ( ct === undefined ) {
9039   ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
9040  }
9041 }
9042
9043 // Check if we're dealing with a known content-type
9044 if ( ct ) {
9045  for ( type in contents ) {
9046   if ( contents[ type ] && contents[ type ].test( ct ) ) {
9047    dataTypes.unshift( type );
9048    break;
9049   }
9050  }
9051 }
9052
9053 // Check to see if we have a response for the expected dataType
9054 if ( dataTypes[ 0 ] in responses ) {
9055  finalDataType = dataTypes[ 0 ];
9056 } else {
9057  // Try convertible dataTypes
9058  for ( type in responses ) {
9059   if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
9060    finalDataType = type;
9061    break;
9062   }
9063   if ( !firstDataType ) {
9064    firstDataType = type;
9065   }
9066  }
9067  // Or just use first one
9068  finalDataType = finalDataType || firstDataType;
9069 }
9070
9071 // If we found a dataType
9072 // We add the dataType to the list if needed
9073 // and return the corresponding response
9074 if ( finalDataType ) {
9075  if ( finalDataType !== dataTypes[ 0 ] ) {
9076   dataTypes.unshift( finalDataType );
9077  }
9078  return responses[ finalDataType ];
9079 }
9080}
9081
9082/* Chain conversions given the request and the original response
9083 * Also sets the responseXXX fields on the jqXHR instance
9084 */
9085function ajaxConvert( s, response, jqXHR, isSuccess ) {
9086 var conv2, current, conv, tmp, prev,
9087  converters = {},
9088  // Work with a copy of dataTypes in case we need to modify it for conversion
9089  dataTypes = s.dataTypes.slice();
9090
9091 // Create converters map with lowercased keys
9092 if ( dataTypes[ 1 ] ) {
9093  for ( conv in s.converters ) {
9094   converters[ conv.toLowerCase() ] = s.converters[ conv ];
9095  }
9096 }
9097
9098 current = dataTypes.shift();
9099
9100 // Convert to each sequential dataType
9101 while ( current ) {
9102
9103  if ( s.responseFields[ current ] ) {
9104   jqXHR[ s.responseFields[ current ] ] = response;
9105  }
9106
9107  // Apply the dataFilter if provided
9108  if ( !prev && isSuccess && s.dataFilter ) {
9109   response = s.dataFilter( response, s.dataType );
9110  }
9111
9112  prev = current;
9113  current = dataTypes.shift();
9114
9115  if ( current ) {
9116
9117   // There's only work to do if current dataType is non-auto
9118   if ( current === "*" ) {
9119
9120    current = prev;
9121
9122   // Convert response if prev dataType is non-auto and differs from current
9123   } else if ( prev !== "*" && prev !== current ) {
9124
9125    // Seek a direct converter
9126    conv = converters[ prev + " " + current ] || converters[ "* " + current ];
9127
9128    // If none found, seek a pair
9129    if ( !conv ) {
9130     for ( conv2 in converters ) {
9131
9132      // If conv2 outputs current
9133      tmp = conv2.split( " " );
9134      if ( tmp[ 1 ] === current ) {
9135
9136       // If prev can be converted to accepted input
9137       conv = converters[ prev + " " + tmp[ 0 ] ] ||
9138        converters[ "* " + tmp[ 0 ] ];
9139       if ( conv ) {
9140        // Condense equivalence converters
9141        if ( conv === true ) {
9142         conv = converters[ conv2 ];
9143
9144        // Otherwise, insert the intermediate dataType
9145        } else if ( converters[ conv2 ] !== true ) {
9146         current = tmp[ 0 ];
9147         dataTypes.unshift( tmp[ 1 ] );
9148        }
9149        break;
9150       }
9151      }
9152     }
9153    }
9154
9155    // Apply converter (if not an equivalence)
9156    if ( conv !== true ) {
9157
9158     // Unless errors are allowed to bubble, catch and return them
9159     if ( conv && s[ "throws" ] ) {
9160      response = conv( response );
9161     } else {
9162      try {
9163       response = conv( response );
9164      } catch ( e ) {
9165       return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
9166      }
9167     }
9168    }
9169   }
9170  }
9171 }
9172
9173 return { state: "success", data: response };
9174}
9175
9176jQuery.extend({
9177
9178 // Counter for holding the number of active queries
9179 active: 0,
9180
9181 // Last-Modified header cache for next request
9182 lastModified: {},
9183 etag: {},
9184
9185 ajaxSettings: {
9186  url: ajaxLocation,
9187  type: "GET",
9188  isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
9189  global: true,
9190  processData: true,
9191  async: true,
9192  contentType: "application/x-www-form-urlencoded; charset=UTF-8",
9193  /*
9194  timeout: 0,
9195  data: null,
9196  dataType: null,
9197  username: null,
9198  password: null,
9199  cache: null,
9200  throws: false,
9201  traditional: false,
9202  headers: {},
9203  */
9204
9205  accepts: {
9206   "*": allTypes,
9207   text: "text/plain",
9208   html: "text/html",
9209   xml: "application/xml, text/xml",
9210   json: "application/json, text/javascript"
9211  },
9212
9213  contents: {
9214   xml: /xml/,
9215   html: /html/,
9216   json: /json/
9217  },
9218
9219  responseFields: {
9220   xml: "responseXML",
9221   text: "responseText",
9222   json: "responseJSON"
9223  },
9224
9225  // Data converters
9226  // Keys separate source (or catchall "*") and destination types with a single space
9227  converters: {
9228
9229   // Convert anything to text
9230   "* text": String,
9231
9232   // Text to html (true = no transformation)
9233   "text html": true,
9234
9235   // Evaluate text as a json expression
9236   "text json": jQuery.parseJSON,
9237
9238   // Parse text as xml
9239   "text xml": jQuery.parseXML
9240  },
9241
9242  // For options that shouldn't be deep extended:
9243  // you can add your own custom options here if
9244  // and when you create one that shouldn't be
9245  // deep extended (see ajaxExtend)
9246  flatOptions: {
9247   url: true,
9248   context: true
9249  }
9250 },
9251
9252 // Creates a full fledged settings object into target
9253 // with both ajaxSettings and settings fields.
9254 // If target is omitted, writes into ajaxSettings.
9255 ajaxSetup: function( target, settings ) {
9256  return settings ?
9257
9258   // Building a settings object
9259   ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
9260
9261   // Extending ajaxSettings
9262   ajaxExtend( jQuery.ajaxSettings, target );
9263 },
9264
9265 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
9266 ajaxTransport: addToPrefiltersOrTransports( transports ),
9267
9268 // Main method
9269 ajax: function( url, options ) {
9270
9271  // If url is an object, simulate pre-1.5 signature
9272  if ( typeof url === "object" ) {
9273   options = url;
9274   url = undefined;
9275  }
9276
9277  // Force options to be an object
9278  options = options || {};
9279
9280  var // Cross-domain detection vars
9281   parts,
9282   // Loop variable
9283   i,
9284   // URL without anti-cache param
9285   cacheURL,
9286   // Response headers as string
9287   responseHeadersString,
9288   // timeout handle
9289   timeoutTimer,
9290
9291   // To know if global events are to be dispatched
9292   fireGlobals,
9293
9294   transport,
9295   // Response headers
9296   responseHeaders,
9297   // Create the final options object
9298   s = jQuery.ajaxSetup( {}, options ),
9299   // Callbacks context
9300   callbackContext = s.context || s,
9301   // Context for global events is callbackContext if it is a DOM node or jQuery collection
9302   globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
9303    jQuery( callbackContext ) :
9304    jQuery.event,
9305   // Deferreds
9306   deferred = jQuery.Deferred(),
9307   completeDeferred = jQuery.Callbacks("once memory"),
9308   // Status-dependent callbacks
9309   statusCode = s.statusCode || {},
9310   // Headers (they are sent all at once)
9311   requestHeaders = {},
9312   requestHeadersNames = {},
9313   // The jqXHR state
9314   state = 0,
9315   // Default abort message
9316   strAbort = "canceled",
9317   // Fake xhr
9318   jqXHR = {
9319    readyState: 0,
9320
9321    // Builds headers hashtable if needed
9322    getResponseHeader: function( key ) {
9323     var match;
9324     if ( state === 2 ) {
9325      if ( !responseHeaders ) {
9326       responseHeaders = {};
9327       while ( (match = rheaders.exec( responseHeadersString )) ) {
9328        responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
9329       }
9330      }
9331      match = responseHeaders[ key.toLowerCase() ];
9332     }
9333     return match == null ? null : match;
9334    },
9335
9336    // Raw string
9337    getAllResponseHeaders: function() {
9338     return state === 2 ? responseHeadersString : null;
9339    },
9340
9341    // Caches the header
9342    setRequestHeader: function( name, value ) {
9343     var lname = name.toLowerCase();
9344     if ( !state ) {
9345      name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
9346      requestHeaders[ name ] = value;
9347     }
9348     return this;
9349    },
9350
9351    // Overrides response content-type header
9352    overrideMimeType: function( type ) {
9353     if ( !state ) {
9354      s.mimeType = type;
9355     }
9356     return this;
9357    },
9358
9359    // Status-dependent callbacks
9360    statusCode: function( map ) {
9361     var code;
9362     if ( map ) {
9363      if ( state < 2 ) {
9364       for ( code in map ) {
9365        // Lazy-add the new callback in a way that preserves old ones
9366        statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
9367       }
9368      } else {
9369       // Execute the appropriate callbacks
9370       jqXHR.always( map[ jqXHR.status ] );
9371      }
9372     }
9373     return this;
9374    },
9375
9376    // Cancel the request
9377    abort: function( statusText ) {
9378     var finalText = statusText || strAbort;
9379     if ( transport ) {
9380      transport.abort( finalText );
9381     }
9382     done( 0, finalText );
9383     return this;
9384    }
9385   };
9386
9387  // Attach deferreds
9388  deferred.promise( jqXHR ).complete = completeDeferred.add;
9389  jqXHR.success = jqXHR.done;
9390  jqXHR.error = jqXHR.fail;
9391
9392  // Remove hash character (#7531: and string promotion)
9393  // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
9394  // Handle falsy url in the settings object (#10093: consistency with old signature)
9395  // We also use the url parameter if available
9396  s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
9397
9398  // Alias method option to type as per ticket #12004
9399  s.type = options.method || options.type || s.method || s.type;
9400
9401  // Extract dataTypes list
9402  s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
9403
9404  // A cross-domain request is in order when we have a protocol:host:port mismatch
9405  if ( s.crossDomain == null ) {
9406   parts = rurl.exec( s.url.toLowerCase() );
9407   s.crossDomain = !!( parts &&
9408    ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
9409     ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
9410      ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
9411   );
9412  }
9413
9414  // Convert data if not already a string
9415  if ( s.data && s.processData && typeof s.data !== "string" ) {
9416   s.data = jQuery.param( s.data, s.traditional );
9417  }
9418
9419  // Apply prefilters
9420  inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
9421
9422  // If request was aborted inside a prefilter, stop there
9423  if ( state === 2 ) {
9424   return jqXHR;
9425  }
9426
9427  // We can fire global events as of now if asked to
9428  fireGlobals = s.global;
9429
9430  // Watch for a new set of requests
9431  if ( fireGlobals && jQuery.active++ === 0 ) {
9432   jQuery.event.trigger("ajaxStart");
9433  }
9434
9435  // Uppercase the type
9436  s.type = s.type.toUpperCase();
9437
9438  // Determine if request has content
9439  s.hasContent = !rnoContent.test( s.type );
9440
9441  // Save the URL in case we're toying with the If-Modified-Since
9442  // and/or If-None-Match header later on
9443  cacheURL = s.url;
9444
9445  // More options handling for requests with no content
9446  if ( !s.hasContent ) {
9447
9448   // If data is available, append data to url
9449   if ( s.data ) {
9450    cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
9451    // #9682: remove data so that it's not used in an eventual retry
9452    delete s.data;
9453   }
9454
9455   // Add anti-cache in url if needed
9456   if ( s.cache === false ) {
9457    s.url = rts.test( cacheURL ) ?
9458
9459     // If there is already a '_' parameter, set its value
9460     cacheURL.replace( rts, "$1_=" + nonce++ ) :
9461
9462     // Otherwise add one to the end
9463     cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
9464   }
9465  }
9466
9467  // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
9468  if ( s.ifModified ) {
9469   if ( jQuery.lastModified[ cacheURL ] ) {
9470    jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
9471   }
9472   if ( jQuery.etag[ cacheURL ] ) {
9473    jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
9474   }
9475  }
9476
9477  // Set the correct header, if data is being sent
9478  if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
9479   jqXHR.setRequestHeader( "Content-Type", s.contentType );
9480  }
9481
9482  // Set the Accepts header for the server, depending on the dataType
9483  jqXHR.setRequestHeader(
9484   "Accept",
9485   s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
9486    s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
9487    s.accepts[ "*" ]
9488  );
9489
9490  // Check for headers option
9491  for ( i in s.headers ) {
9492   jqXHR.setRequestHeader( i, s.headers[ i ] );
9493  }
9494
9495  // Allow custom headers/mimetypes and early abort
9496  if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
9497   // Abort if not done already and return
9498   return jqXHR.abort();
9499  }
9500
9501  // aborting is no longer a cancellation
9502  strAbort = "abort";
9503
9504  // Install callbacks on deferreds
9505  for ( i in { success: 1, error: 1, complete: 1 } ) {
9506   jqXHR[ i ]( s[ i ] );
9507  }
9508
9509  // Get transport
9510  transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
9511
9512  // If no transport, we auto-abort
9513  if ( !transport ) {
9514   done( -1, "No Transport" );
9515  } else {
9516   jqXHR.readyState = 1;
9517
9518   // Send global event
9519   if ( fireGlobals ) {
9520    globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
9521   }
9522   // Timeout
9523   if ( s.async && s.timeout > 0 ) {
9524    timeoutTimer = setTimeout(function() {
9525     jqXHR.abort("timeout");
9526    }, s.timeout );
9527   }
9528
9529   try {
9530    state = 1;
9531    transport.send( requestHeaders, done );
9532   } catch ( e ) {
9533    // Propagate exception as error if not done
9534    if ( state < 2 ) {
9535     done( -1, e );
9536    // Simply rethrow otherwise
9537    } else {
9538     throw e;
9539    }
9540   }
9541  }
9542
9543  // Callback for when everything is done
9544  function done( status, nativeStatusText, responses, headers ) {
9545   var isSuccess, success, error, response, modified,
9546    statusText = nativeStatusText;
9547
9548   // Called once
9549   if ( state === 2 ) {
9550    return;
9551   }
9552
9553   // State is "done" now
9554   state = 2;
9555
9556   // Clear timeout if it exists
9557   if ( timeoutTimer ) {
9558    clearTimeout( timeoutTimer );
9559   }
9560
9561   // Dereference transport for early garbage collection
9562   // (no matter how long the jqXHR object will be used)
9563   transport = undefined;
9564
9565   // Cache response headers
9566   responseHeadersString = headers || "";
9567
9568   // Set readyState
9569   jqXHR.readyState = status > 0 ? 4 : 0;
9570
9571   // Determine if successful
9572   isSuccess = status >= 200 && status < 300 || status === 304;
9573
9574   // Get response data
9575   if ( responses ) {
9576    response = ajaxHandleResponses( s, jqXHR, responses );
9577   }
9578
9579   // Convert no matter what (that way responseXXX fields are always set)
9580   response = ajaxConvert( s, response, jqXHR, isSuccess );
9581
9582   // If successful, handle type chaining
9583   if ( isSuccess ) {
9584
9585    // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
9586    if ( s.ifModified ) {
9587     modified = jqXHR.getResponseHeader("Last-Modified");
9588     if ( modified ) {
9589      jQuery.lastModified[ cacheURL ] = modified;
9590     }
9591     modified = jqXHR.getResponseHeader("etag");
9592     if ( modified ) {
9593      jQuery.etag[ cacheURL ] = modified;
9594     }
9595    }
9596
9597    // if no content
9598    if ( status === 204 || s.type === "HEAD" ) {
9599     statusText = "nocontent";
9600
9601    // if not modified
9602    } else if ( status === 304 ) {
9603     statusText = "notmodified";
9604
9605    // If we have data, let's convert it
9606    } else {
9607     statusText = response.state;
9608     success = response.data;
9609     error = response.error;
9610     isSuccess = !error;
9611    }
9612   } else {
9613    // We extract error from statusText
9614    // then normalize statusText and status for non-aborts
9615    error = statusText;
9616    if ( status || !statusText ) {
9617     statusText = "error";
9618     if ( status < 0 ) {
9619      status = 0;
9620     }
9621    }
9622   }
9623
9624   // Set data for the fake xhr object
9625   jqXHR.status = status;
9626   jqXHR.statusText = ( nativeStatusText || statusText ) + "";
9627
9628   // Success/Error
9629   if ( isSuccess ) {
9630    deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
9631   } else {
9632    deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
9633   }
9634
9635   // Status-dependent callbacks
9636   jqXHR.statusCode( statusCode );
9637   statusCode = undefined;
9638
9639   if ( fireGlobals ) {
9640    globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
9641     [ jqXHR, s, isSuccess ? success : error ] );
9642   }
9643
9644   // Complete
9645   completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
9646
9647   if ( fireGlobals ) {
9648    globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
9649    // Handle the global AJAX counter
9650    if ( !( --jQuery.active ) ) {
9651     jQuery.event.trigger("ajaxStop");
9652    }
9653   }
9654  }
9655
9656  return jqXHR;
9657 },
9658
9659 getJSON: function( url, data, callback ) {
9660  return jQuery.get( url, data, callback, "json" );
9661 },
9662
9663 getScript: function( url, callback ) {
9664  return jQuery.get( url, undefined, callback, "script" );
9665 }
9666});
9667
9668jQuery.each( [ "get", "post" ], function( i, method ) {
9669 jQuery[ method ] = function( url, data, callback, type ) {
9670  // shift arguments if data argument was omitted
9671  if ( jQuery.isFunction( data ) ) {
9672   type = type || callback;
9673   callback = data;
9674   data = undefined;
9675  }
9676
9677  return jQuery.ajax({
9678   url: url,
9679   type: method,
9680   dataType: type,
9681   data: data,
9682   success: callback
9683  });
9684 };
9685});
9686
9687// Attach a bunch of functions for handling common AJAX events
9688jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
9689 jQuery.fn[ type ] = function( fn ) {
9690  return this.on( type, fn );
9691 };
9692});
9693
9694jQuery._evalUrl = function( url ) {
9695 return jQuery.ajax({
9696  url: url,
9697  type: "GET",
9698  dataType: "script",
9699  async: false,
9700  global: false,
9701  "throws": true
9702 });
9703};
9704
9705jQuery.fn.extend({
9706 wrapAll: function( html ) {
9707  if ( jQuery.isFunction( html ) ) {
9708   return this.each(function(i) {
9709    jQuery(this).wrapAll( html.call(this, i) );
9710   });
9711  }
9712
9713  if ( this[0] ) {
9714   // The elements to wrap the target around
9715   var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
9716
9717   if ( this[0].parentNode ) {
9718    wrap.insertBefore( this[0] );
9719   }
9720
9721   wrap.map(function() {
9722    var elem = this;
9723
9724    while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
9725     elem = elem.firstChild;
9726    }
9727
9728    return elem;
9729   }).append( this );
9730  }
9731
9732  return this;
9733 },
9734
9735 wrapInner: function( html ) {
9736  if ( jQuery.isFunction( html ) ) {
9737   return this.each(function(i) {
9738    jQuery(this).wrapInner( html.call(this, i) );
9739   });
9740  }
9741
9742  return this.each(function() {
9743   var self = jQuery( this ),
9744    contents = self.contents();
9745
9746   if ( contents.length ) {
9747    contents.wrapAll( html );
9748
9749   } else {
9750    self.append( html );
9751   }
9752  });
9753 },
9754
9755 wrap: function( html ) {
9756  var isFunction = jQuery.isFunction( html );
9757
9758  return this.each(function(i) {
9759   jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
9760  });
9761 },
9762
9763 unwrap: function() {
9764  return this.parent().each(function() {
9765   if ( !jQuery.nodeName( this, "body" ) ) {
9766    jQuery( this ).replaceWith( this.childNodes );
9767   }
9768  }).end();
9769 }
9770});
9771
9772jQuery.expr.filters.hidden = function( elem ) {
9773 // Support: Opera <= 12.12
9774 // Opera reports offsetWidths and offsetHeights less than zero on some elements
9775 return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
9776  (!support.reliableHiddenOffsets() &&
9777   ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
9778};
9779
9780jQuery.expr.filters.visible = function( elem ) {
9781 return !jQuery.expr.filters.hidden( elem );
9782};
9783
9784var r20 = /%20/g,
9785 rbracket = /\[\]$/,
9786 rCRLF = /\r?\n/g,
9787 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
9788 rsubmittable = /^(?:input|select|textarea|keygen)/i;
9789
9790function buildParams( prefix, obj, traditional, add ) {
9791 var name;
9792
9793 if ( jQuery.isArray( obj ) ) {
9794  // Serialize array item.
9795  jQuery.each( obj, function( i, v ) {
9796   if ( traditional || rbracket.test( prefix ) ) {
9797    // Treat each array item as a scalar.
9798    add( prefix, v );
9799
9800   } else {
9801    // Item is non-scalar (array or object), encode its numeric index.
9802    buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
9803   }
9804  });
9805
9806 } else if ( !traditional && jQuery.type( obj ) === "object" ) {
9807  // Serialize object item.
9808  for ( name in obj ) {
9809   buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
9810  }
9811
9812 } else {
9813  // Serialize scalar item.
9814  add( prefix, obj );
9815 }
9816}
9817
9818// Serialize an array of form elements or a set of
9819// key/values into a query string
9820jQuery.param = function( a, traditional ) {
9821 var prefix,
9822  s = [],
9823  add = function( key, value ) {
9824   // If value is a function, invoke it and return its value
9825   value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
9826   s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
9827  };
9828
9829 // Set traditional to true for jQuery <= 1.3.2 behavior.
9830 if ( traditional === undefined ) {
9831  traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
9832 }
9833
9834 // If an array was passed in, assume that it is an array of form elements.
9835 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
9836  // Serialize the form elements
9837  jQuery.each( a, function() {
9838   add( this.name, this.value );
9839  });
9840
9841 } else {
9842  // If traditional, encode the "old" way (the way 1.3.2 or older
9843  // did it), otherwise encode params recursively.
9844  for ( prefix in a ) {
9845   buildParams( prefix, a[ prefix ], traditional, add );
9846  }
9847 }
9848
9849 // Return the resulting serialization
9850 return s.join( "&" ).replace( r20, "+" );
9851};
9852
9853jQuery.fn.extend({
9854 serialize: function() {
9855  return jQuery.param( this.serializeArray() );
9856 },
9857 serializeArray: function() {
9858  return this.map(function() {
9859   // Can add propHook for "elements" to filter or add form elements
9860   var elements = jQuery.prop( this, "elements" );
9861   return elements ? jQuery.makeArray( elements ) : this;
9862  })
9863  .filter(function() {
9864   var type = this.type;
9865   // Use .is(":disabled") so that fieldset[disabled] works
9866   return this.name && !jQuery( this ).is( ":disabled" ) &&
9867    rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
9868    ( this.checked || !rcheckableType.test( type ) );
9869  })
9870  .map(function( i, elem ) {
9871   var val = jQuery( this ).val();
9872
9873   return val == null ?
9874    null :
9875    jQuery.isArray( val ) ?
9876     jQuery.map( val, function( val ) {
9877      return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
9878     }) :
9879     { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
9880  }).get();
9881 }
9882});
9883
9884// Create the request object
9885// (This is still attached to ajaxSettings for backward compatibility)
9886jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
9887 // Support: IE6+
9888 function() {
9889
9890  // XHR cannot access local files, always use ActiveX for that case
9891  return !this.isLocal &&
9892
9893   // Support: IE7-8
9894   // oldIE XHR does not support non-RFC2616 methods (#13240)
9895   // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
9896   // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
9897   // Although this check for six methods instead of eight
9898   // since IE also does not support "trace" and "connect"
9899   /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
9900
9901   createStandardXHR() || createActiveXHR();
9902 } :
9903 // For all other browsers, use the standard XMLHttpRequest object
9904 createStandardXHR;
9905
9906var xhrId = 0,
9907 xhrCallbacks = {},
9908 xhrSupported = jQuery.ajaxSettings.xhr();
9909
9910// Support: IE<10
9911// Open requests must be manually aborted on unload (#5280)
9912if ( window.ActiveXObject ) {
9913 jQuery( window ).on( "unload", function() {
9914  for ( var key in xhrCallbacks ) {
9915   xhrCallbacks[ key ]( undefined, true );
9916  }
9917 });
9918}
9919
9920// Determine support properties
9921support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
9922xhrSupported = support.ajax = !!xhrSupported;
9923
9924// Create transport if the browser can provide an xhr
9925if ( xhrSupported ) {
9926
9927 jQuery.ajaxTransport(function( options ) {
9928  // Cross domain only allowed if supported through XMLHttpRequest
9929  if ( !options.crossDomain || support.cors ) {
9930
9931   var callback;
9932
9933   return {
9934    send: function( headers, complete ) {
9935     var i,
9936      xhr = options.xhr(),
9937      id = ++xhrId;
9938
9939     // Open the socket
9940     xhr.open( options.type, options.url, options.async, options.username, options.password );
9941
9942     // Apply custom fields if provided
9943     if ( options.xhrFields ) {
9944      for ( i in options.xhrFields ) {
9945       xhr[ i ] = options.xhrFields[ i ];
9946      }
9947     }
9948
9949     // Override mime type if needed
9950     if ( options.mimeType && xhr.overrideMimeType ) {
9951      xhr.overrideMimeType( options.mimeType );
9952     }
9953
9954     // X-Requested-With header
9955     // For cross-domain requests, seeing as conditions for a preflight are
9956     // akin to a jigsaw puzzle, we simply never set it to be sure.
9957     // (it can always be set on a per-request basis or even using ajaxSetup)
9958     // For same-domain requests, won't change header if already provided.
9959     if ( !options.crossDomain && !headers["X-Requested-With"] ) {
9960      headers["X-Requested-With"] = "XMLHttpRequest";
9961     }
9962
9963     // Set headers
9964     for ( i in headers ) {
9965      // Support: IE<9
9966      // IE's ActiveXObject throws a 'Type Mismatch' exception when setting
9967      // request header to a null-value.
9968      //
9969      // To keep consistent with other XHR implementations, cast the value
9970      // to string and ignore `undefined`.
9971      if ( headers[ i ] !== undefined ) {
9972       xhr.setRequestHeader( i, headers[ i ] + "" );
9973      }
9974     }
9975
9976     // Do send the request
9977     // This may raise an exception which is actually
9978     // handled in jQuery.ajax (so no try/catch here)
9979     xhr.send( ( options.hasContent && options.data ) || null );
9980
9981     // Listener
9982     callback = function( _, isAbort ) {
9983      var status, statusText, responses;
9984
9985      // Was never called and is aborted or complete
9986      if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
9987       // Clean up
9988       delete xhrCallbacks[ id ];
9989       callback = undefined;
9990       xhr.onreadystatechange = jQuery.noop;
9991
9992       // Abort manually if needed
9993       if ( isAbort ) {
9994        if ( xhr.readyState !== 4 ) {
9995         xhr.abort();
9996        }
9997       } else {
9998        responses = {};
9999        status = xhr.status;
10000
10001        // Support: IE<10
10002        // Accessing binary-data responseText throws an exception
10003        // (#11426)
10004        if ( typeof xhr.responseText === "string" ) {
10005         responses.text = xhr.responseText;
10006        }
10007
10008        // Firefox throws an exception when accessing
10009        // statusText for faulty cross-domain requests
10010        try {
10011         statusText = xhr.statusText;
10012        } catch( e ) {
10013         // We normalize with Webkit giving an empty statusText
10014         statusText = "";
10015        }
10016
10017        // Filter status for non standard behaviors
10018
10019        // If the request is local and we have data: assume a success
10020        // (success with no data won't get notified, that's the best we
10021        // can do given current implementations)
10022        if ( !status && options.isLocal && !options.crossDomain ) {
10023         status = responses.text ? 200 : 404;
10024        // IE - #1450: sometimes returns 1223 when it should be 204
10025        } else if ( status === 1223 ) {
10026         status = 204;
10027        }
10028       }
10029      }
10030
10031      // Call complete if needed
10032      if ( responses ) {
10033       complete( status, statusText, responses, xhr.getAllResponseHeaders() );
10034      }
10035     };
10036
10037     if ( !options.async ) {
10038      // if we're in sync mode we fire the callback
10039      callback();
10040     } else if ( xhr.readyState === 4 ) {
10041      // (IE6 & IE7) if it's in cache and has been
10042      // retrieved directly we need to fire the callback
10043      setTimeout( callback );
10044     } else {
10045      // Add to the list of active xhr callbacks
10046      xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
10047     }
10048    },
10049
10050    abort: function() {
10051     if ( callback ) {
10052      callback( undefined, true );
10053     }
10054    }
10055   };
10056  }
10057 });
10058}
10059
10060// Functions to create xhrs
10061function createStandardXHR() {
10062 try {
10063  return new window.XMLHttpRequest();
10064 } catch( e ) {}
10065}
10066
10067function createActiveXHR() {
10068 try {
10069  return new window.ActiveXObject( "Microsoft.XMLHTTP" );
10070 } catch( e ) {}
10071}
10072
10073// Install script dataType
10074jQuery.ajaxSetup({
10075 accepts: {
10076  script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
10077 },
10078 contents: {
10079  script: /(?:java|ecma)script/
10080 },
10081 converters: {
10082  "text script": function( text ) {
10083   jQuery.globalEval( text );
10084   return text;
10085  }
10086 }
10087});
10088
10089// Handle cache's special case and global
10090jQuery.ajaxPrefilter( "script", function( s ) {
10091 if ( s.cache === undefined ) {
10092  s.cache = false;
10093 }
10094 if ( s.crossDomain ) {
10095  s.type = "GET";
10096  s.global = false;
10097 }
10098});
10099
10100// Bind script tag hack transport
10101jQuery.ajaxTransport( "script", function(s) {
10102
10103 // This transport only deals with cross domain requests
10104 if ( s.crossDomain ) {
10105
10106  var script,
10107   head = document.head || jQuery("head")[0] || document.documentElement;
10108
10109  return {
10110
10111   send: function( _, callback ) {
10112
10113    script = document.createElement("script");
10114
10115    script.async = true;
10116
10117    if ( s.scriptCharset ) {
10118     script.charset = s.scriptCharset;
10119    }
10120
10121    script.src = s.url;
10122
10123    // Attach handlers for all browsers
10124    script.onload = script.onreadystatechange = function( _, isAbort ) {
10125
10126     if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
10127
10128      // Handle memory leak in IE
10129      script.onload = script.onreadystatechange = null;
10130
10131      // Remove the script
10132      if ( script.parentNode ) {
10133       script.parentNode.removeChild( script );
10134      }
10135
10136      // Dereference the script
10137      script = null;
10138
10139      // Callback if not abort
10140      if ( !isAbort ) {
10141       callback( 200, "success" );
10142      }
10143     }
10144    };
10145
10146    // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
10147    // Use native DOM manipulation to avoid our domManip AJAX trickery
10148    head.insertBefore( script, head.firstChild );
10149   },
10150
10151   abort: function() {
10152    if ( script ) {
10153     script.onload( undefined, true );
10154    }
10155   }
10156  };
10157 }
10158});
10159
10160var oldCallbacks = [],
10161 rjsonp = /(=)\?(?=&|$)|\?\?/;
10162
10163// Default jsonp settings
10164jQuery.ajaxSetup({
10165 jsonp: "callback",
10166 jsonpCallback: function() {
10167  var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
10168  this[ callback ] = true;
10169  return callback;
10170 }
10171});
10172
10173// Detect, normalize options and install callbacks for jsonp requests
10174jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
10175
10176 var callbackName, overwritten, responseContainer,
10177  jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
10178   "url" :
10179   typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
10180  );
10181
10182 // Handle iff the expected data type is "jsonp" or we have a parameter to set
10183 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
10184
10185  // Get callback name, remembering preexisting value associated with it
10186  callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
10187   s.jsonpCallback() :
10188   s.jsonpCallback;
10189
10190  // Insert callback into url or form data
10191  if ( jsonProp ) {
10192   s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
10193  } else if ( s.jsonp !== false ) {
10194   s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
10195  }
10196
10197  // Use data converter to retrieve json after script execution
10198  s.converters["script json"] = function() {
10199   if ( !responseContainer ) {
10200    jQuery.error( callbackName + " was not called" );
10201   }
10202   return responseContainer[ 0 ];
10203  };
10204
10205  // force json dataType
10206  s.dataTypes[ 0 ] = "json";
10207
10208  // Install callback
10209  overwritten = window[ callbackName ];
10210  window[ callbackName ] = function() {
10211   responseContainer = arguments;
10212  };
10213
10214  // Clean-up function (fires after converters)
10215  jqXHR.always(function() {
10216   // Restore preexisting value
10217   window[ callbackName ] = overwritten;
10218
10219   // Save back as free
10220   if ( s[ callbackName ] ) {
10221    // make sure that re-using the options doesn't screw things around
10222    s.jsonpCallback = originalSettings.jsonpCallback;
10223
10224    // save the callback name for future use
10225    oldCallbacks.push( callbackName );
10226   }
10227
10228   // Call if it was a function and we have a response
10229   if ( responseContainer && jQuery.isFunction( overwritten ) ) {
10230    overwritten( responseContainer[ 0 ] );
10231   }
10232
10233   responseContainer = overwritten = undefined;
10234  });
10235
10236  // Delegate to script
10237  return "script";
10238 }
10239});
10240
10241// data: string of html
10242// context (optional): If specified, the fragment will be created in this context, defaults to document
10243// keepScripts (optional): If true, will include scripts passed in the html string
10244jQuery.parseHTML = function( data, context, keepScripts ) {
10245 if ( !data || typeof data !== "string" ) {
10246  return null;
10247 }
10248 if ( typeof context === "boolean" ) {
10249  keepScripts = context;
10250  context = false;
10251 }
10252 context = context || document;
10253
10254 var parsed = rsingleTag.exec( data ),
10255  scripts = !keepScripts && [];
10256
10257 // Single tag
10258 if ( parsed ) {
10259  return [ context.createElement( parsed[1] ) ];
10260 }
10261
10262 parsed = jQuery.buildFragment( [ data ], context, scripts );
10263
10264 if ( scripts && scripts.length ) {
10265  jQuery( scripts ).remove();
10266 }
10267
10268 return jQuery.merge( [], parsed.childNodes );
10269};
10270
10271// Keep a copy of the old load method
10272var _load = jQuery.fn.load;
10273
10274/**
10275 * Load a url into a page
10276 */
10277jQuery.fn.load = function( url, params, callback ) {
10278 if ( typeof url !== "string" && _load ) {
10279  return _load.apply( this, arguments );
10280 }
10281
10282 var selector, response, type,
10283  self = this,
10284  off = url.indexOf(" ");
10285
10286 if ( off >= 0 ) {
10287  selector = jQuery.trim( url.slice( off, url.length ) );
10288  url = url.slice( 0, off );
10289 }
10290
10291 // If it's a function
10292 if ( jQuery.isFunction( params ) ) {
10293
10294  // We assume that it's the callback
10295  callback = params;
10296  params = undefined;
10297
10298 // Otherwise, build a param string
10299 } else if ( params && typeof params === "object" ) {
10300  type = "POST";
10301 }
10302
10303 // If we have elements to modify, make the request
10304 if ( self.length > 0 ) {
10305  jQuery.ajax({
10306   url: url,
10307
10308   // if "type" variable is undefined, then "GET" method will be used
10309   type: type,
10310   dataType: "html",
10311   data: params
10312  }).done(function( responseText ) {
10313
10314   // Save response for use in complete callback
10315   response = arguments;
10316
10317   self.html( selector ?
10318
10319    // If a selector was specified, locate the right elements in a dummy div
10320    // Exclude scripts to avoid IE 'Permission Denied' errors
10321    jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
10322
10323    // Otherwise use the full result
10324    responseText );
10325
10326  }).complete( callback && function( jqXHR, status ) {
10327   self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
10328  });
10329 }
10330
10331 return this;
10332};
10333
10334jQuery.expr.filters.animated = function( elem ) {
10335 return jQuery.grep(jQuery.timers, function( fn ) {
10336  return elem === fn.elem;
10337 }).length;
10338};
10339
10340var docElem = window.document.documentElement;
10341
10342/**
10343 * Gets a window from an element
10344 */
10345function getWindow( elem ) {
10346 return jQuery.isWindow( elem ) ?
10347  elem :
10348  elem.nodeType === 9 ?
10349   elem.defaultView || elem.parentWindow :
10350   false;
10351}
10352
10353jQuery.offset = {
10354 setOffset: function( elem, options, i ) {
10355  var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
10356   position = jQuery.css( elem, "position" ),
10357   curElem = jQuery( elem ),
10358   props = {};
10359
10360  // set position first, in-case top/left are set even on static elem
10361  if ( position === "static" ) {
10362   elem.style.position = "relative";
10363  }
10364
10365  curOffset = curElem.offset();
10366  curCSSTop = jQuery.css( elem, "top" );
10367  curCSSLeft = jQuery.css( elem, "left" );
10368  calculatePosition = ( position === "absolute" || position === "fixed" ) &&
10369   jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
10370
10371  // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
10372  if ( calculatePosition ) {
10373   curPosition = curElem.position();
10374   curTop = curPosition.top;
10375   curLeft = curPosition.left;
10376  } else {
10377   curTop = parseFloat( curCSSTop ) || 0;
10378   curLeft = parseFloat( curCSSLeft ) || 0;
10379  }
10380
10381  if ( jQuery.isFunction( options ) ) {
10382   options = options.call( elem, i, curOffset );
10383  }
10384
10385  if ( options.top != null ) {
10386   props.top = ( options.top - curOffset.top ) + curTop;
10387  }
10388  if ( options.left != null ) {
10389   props.left = ( options.left - curOffset.left ) + curLeft;
10390  }
10391
10392  if ( "using" in options ) {
10393   options.using.call( elem, props );
10394  } else {
10395   curElem.css( props );
10396  }
10397 }
10398};
10399
10400jQuery.fn.extend({
10401 offset: function( options ) {
10402  if ( arguments.length ) {
10403   return options === undefined ?
10404    this :
10405    this.each(function( i ) {
10406     jQuery.offset.setOffset( this, options, i );
10407    });
10408  }
10409
10410  var docElem, win,
10411   box = { top: 0, left: 0 },
10412   elem = this[ 0 ],
10413   doc = elem && elem.ownerDocument;
10414
10415  if ( !doc ) {
10416   return;
10417  }
10418
10419  docElem = doc.documentElement;
10420
10421  // Make sure it's not a disconnected DOM node
10422  if ( !jQuery.contains( docElem, elem ) ) {
10423   return box;
10424  }
10425
10426  // If we don't have gBCR, just use 0,0 rather than error
10427  // BlackBerry 5, iOS 3 (original iPhone)
10428  if ( typeof elem.getBoundingClientRect !== strundefined ) {
10429   box = elem.getBoundingClientRect();
10430  }
10431  win = getWindow( doc );
10432  return {
10433   top: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),
10434   left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
10435  };
10436 },
10437
10438 position: function() {
10439  if ( !this[ 0 ] ) {
10440   return;
10441  }
10442
10443  var offsetParent, offset,
10444   parentOffset = { top: 0, left: 0 },
10445   elem = this[ 0 ];
10446
10447  // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
10448  if ( jQuery.css( elem, "position" ) === "fixed" ) {
10449   // we assume that getBoundingClientRect is available when computed position is fixed
10450   offset = elem.getBoundingClientRect();
10451  } else {
10452   // Get *real* offsetParent
10453   offsetParent = this.offsetParent();
10454
10455   // Get correct offsets
10456   offset = this.offset();
10457   if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
10458    parentOffset = offsetParent.offset();
10459   }
10460
10461   // Add offsetParent borders
10462   parentOffset.top  += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
10463   parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
10464  }
10465
10466  // Subtract parent offsets and element margins
10467  // note: when an element has margin: auto the offsetLeft and marginLeft
10468  // are the same in Safari causing offset.left to incorrectly be 0
10469  return {
10470   top:  offset.top  - parentOffset.top - jQuery.css( elem, "marginTop", true ),
10471   left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
10472  };
10473 },
10474
10475 offsetParent: function() {
10476  return this.map(function() {
10477   var offsetParent = this.offsetParent || docElem;
10478
10479   while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
10480    offsetParent = offsetParent.offsetParent;
10481   }
10482   return offsetParent || docElem;
10483  });
10484 }
10485});
10486
10487// Create scrollLeft and scrollTop methods
10488jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
10489 var top = /Y/.test( prop );
10490
10491 jQuery.fn[ method ] = function( val ) {
10492  return access( this, function( elem, method, val ) {
10493   var win = getWindow( elem );
10494
10495   if ( val === undefined ) {
10496    return win ? (prop in win) ? win[ prop ] :
10497     win.document.documentElement[ method ] :
10498     elem[ method ];
10499   }
10500
10501   if ( win ) {
10502    win.scrollTo(
10503     !top ? val : jQuery( win ).scrollLeft(),
10504     top ? val : jQuery( win ).scrollTop()
10505    );
10506
10507   } else {
10508    elem[ method ] = val;
10509   }
10510  }, method, val, arguments.length, null );
10511 };
10512});
10513
10514// Add the top/left cssHooks using jQuery.fn.position
10515// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
10516// getComputedStyle returns percent when specified for top/left/bottom/right
10517// rather than make the css module depend on the offset module, we just check for it here
10518jQuery.each( [ "top", "left" ], function( i, prop ) {
10519 jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
10520  function( elem, computed ) {
10521   if ( computed ) {
10522    computed = curCSS( elem, prop );
10523    // if curCSS returns percentage, fallback to offset
10524    return rnumnonpx.test( computed ) ?
10525     jQuery( elem ).position()[ prop ] + "px" :
10526     computed;
10527   }
10528  }
10529 );
10530});
10531
10532// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
10533jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
10534 jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
10535  // margin is only for outerHeight, outerWidth
10536  jQuery.fn[ funcName ] = function( margin, value ) {
10537   var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
10538    extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
10539
10540   return access( this, function( elem, type, value ) {
10541    var doc;
10542
10543    if ( jQuery.isWindow( elem ) ) {
10544     // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
10545     // isn't a whole lot we can do. See pull request at this URL for discussion:
10546     // https://github.com/jquery/jquery/pull/764
10547     return elem.document.documentElement[ "client" + name ];
10548    }
10549
10550    // Get document width or height
10551    if ( elem.nodeType === 9 ) {
10552     doc = elem.documentElement;
10553
10554     // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
10555     // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
10556     return Math.max(
10557      elem.body[ "scroll" + name ], doc[ "scroll" + name ],
10558      elem.body[ "offset" + name ], doc[ "offset" + name ],
10559      doc[ "client" + name ]
10560     );
10561    }
10562
10563    return value === undefined ?
10564     // Get width or height on the element, requesting but not forcing parseFloat
10565     jQuery.css( elem, type, extra ) :
10566
10567     // Set width or height on the element
10568     jQuery.style( elem, type, value, extra );
10569   }, type, chainable ? margin : undefined, chainable, null );
10570  };
10571 });
10572});
10573
10574// The number of elements contained in the matched element set
10575jQuery.fn.size = function() {
10576 return this.length;
10577};
10578
10579jQuery.fn.andSelf = jQuery.fn.addBack;
10580
10581// Register as a named AMD module, since jQuery can be concatenated with other
10582// files that may use define, but not via a proper concatenation script that
10583// understands anonymous AMD modules. A named AMD is safest and most robust
10584// way to register. Lowercase jquery is used because AMD module names are
10585// derived from file names, and jQuery is normally delivered in a lowercase
10586// file name. Do this after creating the global so that if an AMD module wants
10587// to call noConflict to hide this version of jQuery, it will work.
10588
10589// Note that for maximum portability, libraries that are not jQuery should
10590// declare themselves as anonymous modules, and avoid setting a global if an
10591// AMD loader is present. jQuery is a special case. For more information, see
10592// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
10593
10594if ( typeof define === "function" && define.amd ) {
10595 define( "jquery", [], function() {
10596  return jQuery;
10597 });
10598}
10599
10600var
10601 // Map over jQuery in case of overwrite
10602 _jQuery = window.jQuery,
10603
10604 // Map over the $ in case of overwrite
10605 _$ = window.$;
10606
10607jQuery.noConflict = function( deep ) {
10608 if ( window.$ === jQuery ) {
10609  window.$ = _$;
10610 }
10611
10612 if ( deep && window.jQuery === jQuery ) {
10613  window.jQuery = _jQuery;
10614 }
10615
10616 return jQuery;
10617};
10618
10619// Expose jQuery and $ identifiers, even in
10620// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
10621// and CommonJS for browser emulators (#13566)
10622if ( typeof noGlobal === strundefined ) {
10623 window.jQuery = window.$ = jQuery;
10624}
10625
10626return jQuery;
10627
10628}));
10629   /* Ende jquery */
10630   /* Start gsb_makeGSBModule */
10631   /*!
10632   @author rkrusenb
10633   @license MIT
10634*/
10635var gsb;
10636gsb = gsb || {};
10637(function($, gsb){
10638
10639  /* @example
10640   * function module(){}
10641   * var $;
10642   * set($, ['gsb', 'foo', 'bar'], module);
10643   * $.gsb && $.gsb.foo && $.gsb.foo.bar === module //true
10644   */
10645  function set(object, namespace, value){
10646    var i, l = namespace.length - 1,
10647      property, last = namespace[l];
10648    for(i = 0; i < l; i++){
10649      property = namespace[i];
10650      object[property] = object[property] || {};
10651      object = object[property];
10652    }
10653    object[last] = value;
10654  }
10655  /* @example
10656   * var $ = {
10657   *   gsb: {
10658   *     foo: {
10659   *       bar: function(x){
10660   *         return x;
10661   *       }
10662   *     }
10663   *   }
10664   * };
10665   * apply($, ['gsb', 'foo', 'bar'], ['baz']) === 'baz' //true
10666   */
10667  function apply(object, namespace, args){
10668    var i, l = namespace.length - 1,
10669      property, last = namespace[l];
10670    for(i = 0; i < l; i++){
10671      property = namespace[i];
10672      object = object && object[property];
10673    }
10674    if(typeof object[last] === "function") {
10675      object[last].apply(object, args);
10676    }
10677  }
10678  function enhance(fullName, namespace, template){ //returns an "enhanced" copy of a template
10679    return $.extend({
10680      eventName: namespace.slice().reverse().join('.'),
10681      moduleName: fullName
10682    }, template);
10683  }
10684  gsb.makeGSBModule = function makeGSBModule(fullName, template){
10685    var namespace = fullName.split('.');
10686
10687    function module(el, userOptions, ...additionalParameters){
10688      var base = $.extend({}, template);
10689      base.el = el;
10690      base.$el = $(el);
10691      base.options = $.extend(true, {}, template.defaultOptions, userOptions);
10692      base.$el.data(namespace.join('.'), base);
10693      base.init(el, userOptions, ...additionalParameters);
10694    }
10695
10696    template = enhance(fullName, namespace, template);
10697
10698    module.defaultOptions = template.defaultOptions || {};
10699
10700    set($, namespace, module);
10701
10702    $.fn[namespace.join('_')] = function(userOptions, ...additionalParameters){
10703      $(this).each(function(i, el){
10704        if(!$(el).data( namespace.join('.') ) || (userOptions && userOptions.force)) {
10705          apply($, namespace, [el, userOptions, ...additionalParameters]);
10706        }
10707      });
10708      return this;
10709    };
10710  };
10711})(jQuery, gsb);
10712   /* Ende gsb_makeGSBModule */
10713   /* Start gsb_requireGSBComponent */
10714   var gsb;
10715gsb = gsb || {};
10716(function ($, gsb) {
10717  const state = {
10718    instanceCount: 0,
10719    promises: {}
10720  };
10721
10722  function requireGenericGSBComponent(componentName, instanceName) {
10723    const promiseArray = createScriptTags(gsb.jsComponents.definitions[componentName].scriptList, instanceName);
10724    return Promise.all(promiseArray);
10725  }
10726
10727  function createScriptTags(scriptList, instanceName) {
10728    const promiseArray = [];
10729    scriptList.forEach((scriptPath) => {
10730      promiseArray.push(createScriptTag(scriptPath));
10731    });
10732    return promiseArray;
10733  }
10734
10735  /**
10736   * Creates a Script Tag, appends and executes it.
10737   * While creating a new Promise or waiting for a previou Promise the Script has already been requested.
10738   *
10739   * @param scriptPath the Path of the script used for the src Attribute
10740   * @param instanceName the name of this instance used for logging
10741   * @returns {Promise<unknown>} a promise that ensures that the Script is ready to use when resolved
10742   */
10743  function createScriptTag(scriptPath, instanceName) {
10744    let promise;
10745    if (state.promises[scriptPath]) {
10746      promise = state.promises[scriptPath];
10747    } else {
10748      promise = new Promise(function (resolve, reject) {
10749        const $script = $('<script></script>').attr('src', scriptPath).attr('charSet', 'UTF-8');
10750        $script
10751            .prop('async', false)
10752            .on('load', function () {
10753              resolve({scriptPath, action: 'DOM load'});
10754            });
10755        document.body.appendChild($script[0]);
10756
10757      });
10758      state.promises[scriptPath] = promise;
10759    }
10760    return promise;
10761  }
10762
10763  gsb.requireGSBComponent = function (componentName, $el) {
10764    const instanceName = 'gsb.requireGSBComponent-' + state.instanceCount++;
10765    const deferred = $.Deferred();
10766    let error;
10767
10768    if (gsb.jsComponents.definitions[componentName]) {
10769      if (!$el || !$el.length) {
10770        error = new Error('Elemente nicht im DOM gefunden. GSB-Komponente wird nicht geladen');
10771        deferred.reject(error);
10772      } else {
10773        requireGenericGSBComponent(componentName, instanceName)
10774            .then(() => deferred.resolve($el))
10775            .catch((err) => {
10776              deferred.reject(err);
10777              console.error(instanceName, `GSB-Komponente ${componentName} für Elemente`, $el,
10778                  'konnte nicht eingebunden werden, es gab folgenden Fehler', err);
10779            });
10780      }
10781    } else {
10782      console.error(instanceName, `GSB-Komponente ${componentName} ist nicht definiert, und kann daher nicht eingebunden werden`);
10783    }
10784
10785    return deferred;
10786  };
10787
10788})(jQuery, gsb);
10789   /* Ende gsb_requireGSBComponent */
10790   /* Start jquery.datatables */
10791   /*! DataTables 1.10.12
10792 * ©2008-2015 SpryMedia Ltd - datatables.net/license
10793 */
10794/**
10795 * @summary     DataTables
10796 * @description Paginate, search and order HTML tables
10797 * @version     1.10.12
10798 * @file        jquery.dataTables.js
10799 * @author      SpryMedia Ltd (www.sprymedia.co.uk)
10800 * @contact     www.sprymedia.co.uk/contact
10801 * @copyright   Copyright 2008-2015 SpryMedia Ltd.
10802 *
10803 * This source file is free software, available under the following license:
10804 *   MIT license - http://datatables.net/license
10805 *
10806 * This source file is distributed in the hope that it will be useful, but
10807 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10808 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
10809 *
10810 * For details please refer to: http://www.datatables.net
10811 */
10812/*jslint evil: true, undef: true, browser: true */
10813/*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,_plu
10813ck_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*/
10814(function( factory ) {
10815 "use strict";
10816 if ( typeof define === 'function' && define.amd ) {
10817  // AMD
10818  define( ['jquery'], function ( $ ) {
10819   return factory( $, window, document );
10820  } );
10821 }
10822 else if ( typeof exports === 'object' ) {
10823  // CommonJS
10824  module.exports = function (root, $) {
10825   if ( ! root ) {
10826    // CommonJS environments without a window global must pass a
10827    // root. This will give an error otherwise
10828    root = window;
10829   }
10830   if ( ! $ ) {
10831    $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
10832     require('jquery') :
10833     require('jquery')( root );
10834   }
10835   return factory( $, root, root.document );
10836  };
10837 }
10838 else {
10839  // Browser
10840  factory( jQuery, window, document );
10841 }
10842}
10843(function( $, window, document, undefined ) {
10844 "use strict";
10845 /**
10846  * DataTables is a plug-in for the jQuery Javascript library. It is a highly
10847  * flexible tool, based upon the foundations of progressive enhancement,
10848  * which will add advanced interaction controls to any HTML table. For a
10849  * full list of features please refer to
10850  * [DataTables.net](href="http://datatables.net).
10851  *
10852  * Note that the `DataTable` object is not a global variable but is aliased
10853  * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
10854  * be  accessed.
10855  *
10856  *  @class
10857  *  @param {object} [init={}] Configuration object for DataTables. Options
10858  *    are defined by {@link DataTable.defaults}
10859  *  @requires jQuery 1.7+
10860  *
10861  *  @example
10862  *    // Basic initialisation
10863  *    $(document).ready( function {
10864  *      $('#example').dataTable();
10865  *    } );
10866  *
10867  *  @example
10868  *    // Initialisation with configuration options - in this case, disable
10869  *    // pagination and sorting.
10870  *    $(document).ready( function {
10871  *      $('#example').dataTable( {
10872  *        "paginate": false,
10873  *        "sort": false
10874  *      } );
10875  *    } );
10876  */
10877 var DataTable = function ( options )
10878 {
10879  /**
10880   * Perform a jQuery selector action on the table's TR elements (from the tbody) and
10881   * return the resulting jQuery object.
10882   *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
10883   *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
10884   *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
10885   *    criterion ("applied") or all TR elements (i.e. no filter).
10886   *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
10887   *    Can be either 'current', whereby the current sorting of the table is used, or
10888   *    'original' whereby the original order the data was read into the table is used.
10889   *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
10890   *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
10891   *    'current' and filter is 'applied', regardless of what they might be given as.
10892   *  @returns {object} jQuery object, filtered by the given selector.
10893   *  @dtopt API
10894   *  @deprecated Since v1.10
10895   *
10896   *  @example
10897   *    $(document).ready(function() {
10898   *      var oTable = $('#example').dataTable();
10899   *
10900   *      // Highlight every second row
10901   *      oTable.$('tr:odd').css('backgroundColor', 'blue');
10902   *    } );
10903   *
10904   *  @example
10905   *    $(document).ready(function() {
10906   *      var oTable = $('#example').dataTable();
10907   *
10908   *      // Filter to rows with 'Webkit' in them, add a background colour and then
10909   *      // remove the filter, thus highlighting the 'Webkit' rows only.
10910   *      oTable.fnFilter('Webkit');
10911   *      oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
10912   *      oTable.fnFilter('');
10913   *    } );
10914   */
10915  this.$ = function ( sSelector, oOpts )
10916  {
10917   return this.api(true).$( sSelector, oOpts );
10918  };
10919  
10920  
10921  /**
10922   * Almost identical to $ in operation, but in this case returns the data for the matched
10923   * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
10924   * rather than any descendants, so the data can be obtained for the row/cell. If matching
10925   * rows are found, the data returned is the original data array/object that was used to
10926   * create the row (or a generated array if from a DOM source).
10927   *
10928   * This method is often useful in-combination with $ where both functions are given the
10929   * same parameters and the array indexes will match identically.
10930   *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
10931   *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
10932   *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
10933   *    criterion ("applied") or all elements (i.e. no filter).
10934   *  @param {string} [oOpts.order=current] Order of the data in the processed array.
10935   *    Can be either 'current', whereby the current sorting of the table is used, or
10936   *    'original' whereby the original order the data was read into the table is used.
10937   *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
10938   *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
10939   *    'current' and filter is 'applied', regardless of what they might be given as.
10940   *  @returns {array} Data for the matched elements. If any elements, as a result of the
10941   *    selector, were not TR, TD or TH elements in the DataTable, they will have a null
10942   *    entry in the array.
10943   *  @dtopt API
10944   *  @deprecated Since v1.10
10945   *
10946   *  @example
10947   *    $(document).ready(function() {
10948   *      var oTable = $('#example').dataTable();
10949   *
10950   *      // Get the data from the first row in the table
10951   *      var data = oTable._('tr:first');
10952   *
10953   *      // Do something useful with the data
10954   *      alert( "First cell is: "+data[0] );
10955   *    } );
10956   *
10957   *  @example
10958   *    $(document).ready(function() {
10959   *      var oTable = $('#example').dataTable();
10960   *
10961   *      // Filter to 'Webkit' and get all data for
10962   *      oTable.fnFilter('Webkit');
10963   *      var data = oTable._('tr', {"search": "applied"});
10964   *
10965   *      // Do something with the data
10966   *      alert( data.length+" rows matched the search" );
10967   *    } );
10968   */
10969  this._ = function ( sSelector, oOpts )
10970  {
10971   return this.api(true).rows( sSelector, oOpts ).data();
10972  };
10973  
10974  
10975  /**
10976   * Create a DataTables Api instance, with the currently selected tables for
10977   * the Api's context.
10978   * @param {boolean} [traditional=false] Set the API instance's context to be
10979   *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was
10980   *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),
10981   *   or if all tables captured in the jQuery object should be used.
10982   * @return {DataTables.Api}
10983   */
10984  this.api = function ( traditional )
10985  {
10986   return traditional ?
10987    new _Api(
10988     _fnSettingsFromNode( this[ _ext.iApiIndex ] )
10989    ) :
10990    new _Api( this );
10991  };
10992  
10993  
10994  /**
10995   * Add a single new row or multiple rows of data to the table. Please note
10996   * that this is suitable for client-side processing only - if you are using
10997   * server-side processing (i.e. "bServerSide": true), then to add data, you
10998   * must add it to the data source, i.e. the server-side, through an Ajax call.
10999   *  @param {array|object} data The data to be added to the table. This can be:
11000   *    <ul>
11001   *      <li>1D array of data - add a single row with the data provided</li>
11002   *      <li>2D array of arrays - add multiple rows in a single call</li>
11003   *      <li>object - data object when using <i>mData</i></li>
11004   *      <li>array of objects - multiple data objects when using <i>mData</i></li>
11005   *    </ul>
11006   *  @param {bool} [redraw=true] redraw the table or not
11007   *  @returns {array} An array of integers, representing the list of indexes in
11008   *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
11009   *    the table.
11010   *  @dtopt API
11011   *  @deprecated Since v1.10
11012   *
11013   *  @example
11014   *    // Global var for counter
11015   *    var giCount = 2;
11016   *
11017   *    $(document).ready(function() {
11018   *      $('#example').dataTable();
11019   *    } );
11020   *
11021   *    function fnClickAddRow() {
11022   *      $('#example').dataTable().fnAddData( [
11023   *        giCount+".1",
11024   *        giCount+".2",
11025   *        giCount+".3",
11026   *        giCount+".4" ]
11027   *      );
11028   *
11029   *      giCount++;
11030   *    }
11031   */
11032  this.fnAddData = function( data, redraw )
11033  {
11034   var api = this.api( true );
11035  
11036   /* Check if we want to add multiple rows or not */
11037   var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
11038    api.rows.add( data ) :
11039    api.row.add( data );
11040  
11041   if ( redraw === undefined || redraw ) {
11042    api.draw();
11043   }
11044  
11045   return rows.flatten().toArray();
11046  };
11047  
11048  
11049  /**
11050   * This function will make DataTables recalculate the column sizes, based on the data
11051   * contained in the table and the sizes applied to the columns (in the DOM, CSS or
11052   * through the sWidth parameter). This can be useful when the width of the table's
11053   * parent element changes (for example a window resize).
11054   *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
11055   *  @dtopt API
11056   *  @deprecated Since v1.10
11057   *
11058   *  @example
11059   *    $(document).ready(function() {
11060   *      var oTable = $('#example').dataTable( {
11061   *        "sScrollY": "200px",
11062   *        "bPaginate": false
11063   *      } );
11064   *
11065   *      $(window).bind('resize', function () {
11066   *        oTable.fnAdjustColumnSizing();
11067   *      } );
11068   *    } );
11069   */
11070  this.fnAdjustColumnSizing = function ( bRedraw )
11071  {
11072   var api = this.api( true ).columns.adjust();
11073   var settings = api.settings()[0];
11074   var scroll = settings.oScroll;
11075  
11076   if ( bRedraw === undefined || bRedraw ) {
11077    api.draw( false );
11078   }
11079   else if ( scroll.sX !== "" || scroll.sY !== "" ) {
11080    /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
11081    _fnScrollDraw( settings );
11082   }
11083  };
11084  
11085  
11086  /**
11087   * Quickly and simply clear a table
11088   *  @param {bool} [bRedraw=true] redraw the table or not
11089   *  @dtopt API
11090   *  @deprecated Since v1.10
11091   *
11092   *  @example
11093   *    $(document).ready(function() {
11094   *      var oTable = $('#example').dataTable();
11095   *
11096   *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
11097   *      oTable.fnClearTable();
11098   *    } );
11099   */
11100  this.fnClearTable = function( bRedraw )
11101  {
11102   var api = this.api( true ).clear();
11103  
11104   if ( bRedraw === undefined || bRedraw ) {
11105    api.draw();
11106   }
11107  };
11108  
11109  
11110  /**
11111   * The exact opposite of 'opening' a row, this function will close any rows which
11112   * are currently 'open'.
11113   *  @param {node} nTr the table row to 'close'
11114   *  @returns {int} 0 on success, or 1 if failed (can't find the row)
11115   *  @dtopt API
11116   *  @deprecated Since v1.10
11117   *
11118   *  @example
11119   *    $(document).ready(function() {
11120   *      var oTable;
11121   *
11122   *      // 'open' an information row when a row is clicked on
11123   *      $('#example tbody tr').click( function () {
11124   *        if ( oTable.fnIsOpen(this) ) {
11125   *          oTable.fnClose( this );
11126   *        } else {
11127   *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
11128   *        }
11129   *      } );
11130   *
11131   *      oTable = $('#example').dataTable();
11132   *    } );
11133   */
11134  this.fnClose = function( nTr )
11135  {
11136   this.api( true ).row( nTr ).child.hide();
11137  };
11138  
11139  
11140  /**
11141   * Remove a row for the table
11142   *  @param {mixed} target The index of the row from aoData to be deleted, or
11143   *    the TR element you want to delete
11144   *  @param {function|null} [callBack] Callback function
11145   *  @param {bool} [redraw=true] Redraw the table or not
11146   *  @returns {array} The row that was deleted
11147   *  @dtopt API
11148   *  @deprecated Since v1.10
11149   *
11150   *  @example
11151   *    $(document).ready(function() {
11152   *      var oTable = $('#example').dataTable();
11153   *
11154   *      // Immediately remove the first row
11155   *      oTable.fnDeleteRow( 0 );
11156   *    } );
11157   */
11158  this.fnDeleteRow = function( target, callback, redraw )
11159  {
11160   var api = this.api( true );
11161   var rows = api.rows( target );
11162   var settings = rows.settings()[0];
11163   var data = settings.aoData[ rows[0][0] ];
11164  
11165   rows.remove();
11166  
11167   if ( callback ) {
11168    callback.call( this, settings, data );
11169   }
11170  
11171   if ( redraw === undefined || redraw ) {
11172    api.draw();
11173   }
11174  
11175   return data;
11176  };
11177  
11178  
11179  /**
11180   * Restore the table to it's original state in the DOM by removing all of DataTables
11181   * enhancements, alterations to the DOM structure of the table and event listeners.
11182   *  @param {boolean} [remove=false] Completely remove the table from the DOM
11183   *  @dtopt API
11184   *  @deprecated Since v1.10
11185   *
11186   *  @example
11187   *    $(document).ready(function() {
11188   *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
11189   *      var oTable = $('#example').dataTable();
11190   *      oTable.fnDestroy();
11191   *    } );
11192   */
11193  this.fnDestroy = function ( remove )
11194  {
11195   this.api( true ).destroy( remove );
11196  };
11197  
11198  
11199  /**
11200   * Redraw the table
11201   *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
11202   *  @dtopt API
11203   *  @deprecated Since v1.10
11204   *
11205   *  @example
11206   *    $(document).ready(function() {
11207   *      var oTable = $('#example').dataTable();
11208   *
11209   *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
11210   *      oTable.fnDraw();
11211   *    } );
11212   */
11213  this.fnDraw = function( complete )
11214  {
11215   // Note that this isn't an exact match to the old call to _fnDraw - it takes
11216   // into account the new data, but can hold position.
11217   this.api( true ).draw( complete );
11218  };
11219  
11220  
11221  /**
11222   * Filter the input based on data
11223   *  @param {string} sInput String to filter the table on
11224   *  @param {int|null} [iColumn] Column to limit filtering to
11225   *  @param {bool} [bRegex=false] Treat as regular expression or not
11226   *  @param {bool} [bSmart=true] Perform smart filtering or not
11227   *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
11228   *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
11229   *  @dtopt API
11230   *  @deprecated Since v1.10
11231   *
11232   *  @example
11233   *    $(document).ready(function() {
11234   *      var oTable = $('#example').dataTable();
11235   *
11236   *      // Sometime later - filter...
11237   *      oTable.fnFilter( 'test string' );
11238   *    } );
11239   */
11240  this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
11241  {
11242   var api = this.api( true );
11243  
11244   if ( iColumn === null || iColumn === undefined ) {
11245    api.search( sInput, bRegex, bSmart, bCaseInsensitive );
11246   }
11247   else {
11248    api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
11249   }
11250  
11251   api.draw();
11252  };
11253  
11254  
11255  /**
11256   * Get the data for the whole table, an individual row or an individual cell based on the
11257   * provided parameters.
11258   *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
11259   *    a TR node then the data source for the whole row will be returned. If given as a
11260   *    TD/TH cell node then iCol will be automatically calculated and the data for the
11261   *    cell returned. If given as an integer, then this is treated as the aoData internal
11262   *    data index for the row (see fnGetPosition) and the data for that row used.
11263   *  @param {int} [col] Optional column index that you want the data of.
11264   *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
11265   *    returned. If mRow is defined, just data for that row, and is iCol is
11266   *    defined, only data for the designated cell is returned.
11267   *  @dtopt API
11268   *  @deprecated Since v1.10
11269   *
11270   *  @example
11271   *    // Row data
11272   *    $(document).ready(function() {
11273   *      oTable = $('#example').dataTable();
11274   *
11275   *      oTable.$('tr').click( function () {
11276   *        var data = oTable.fnGetData( this );
11277   *        // ... do something with the array / object of data for the row
11278   *      } );
11279   *    } );
11280   *
11281   *  @example
11282   *    // Individual cell data
11283   *    $(document).ready(function() {
11284   *      oTable = $('#example').dataTable();
11285   *
11286   *      oTable.$('td').click( function () {
11287   *        var sData = oTable.fnGetData( this );
11288   *        alert( 'The cell clicked on had the value of '+sData );
11289   *      } );
11290   *    } );
11291   */
11292  this.fnGetData = function( src, col )
11293  {
11294   var api = this.api( true );
11295  
11296   if ( src !== undefined ) {
11297    var type = src.nodeName ? src.nodeName.toLowerCase() : '';
11298  
vendor: 15,635 bytes, lines 11299-11809
11299    return col !== undefined || type == 'td' || type == 'th' ?
11300     api.cell( src, col ).data() :
11301     api.row( src ).data() || null;
11302   }
11303  
11304   return api.data().toArray();
11305  };
11306  
11307  
11308  /**
11309   * Get an array of the TR nodes that are used in the table's body. Note that you will
11310   * typically want to use the '$' API method in preference to this as it is more
11311   * flexible.
11312   *  @param {int} [iRow] Optional row index for the TR element you want
11313   *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
11314   *    in the table's body, or iRow is defined, just the TR element requested.
11315   *  @dtopt API
11316   *  @deprecated Since v1.10
11317   *
11318   *  @example
11319   *    $(document).ready(function() {
11320   *      var oTable = $('#example').dataTable();
11321   *
11322   *      // Get the nodes from the table
11323   *      var nNodes = oTable.fnGetNodes( );
11324   *    } );
11325   */
11326  this.fnGetNodes = function( iRow )
11327  {
11328   var api = this.api( true );
11329  
11330   return iRow !== undefined ?
11331    api.row( iRow ).node() :
11332    api.rows().nodes().flatten().toArray();
11333  };
11334  
11335  
11336  /**
11337   * Get the array indexes of a particular cell from it's DOM element
11338   * and column index including hidden columns
11339   *  @param {node} node this can either be a TR, TD or TH in the table's body
11340   *  @returns {int} If nNode is given as a TR, then a single index is returned, or
11341   *    if given as a cell, an array of [row index, column index (visible),
11342   *    column index (all)] is given.
11343   *  @dtopt API
11344   *  @deprecated Since v1.10
11345   *
11346   *  @example
11347   *    $(document).ready(function() {
11348   *      $('#example tbody td').click( function () {
11349   *        // Get the position of the current data from the node
11350   *        var aPos = oTable.fnGetPosition( this );
11351   *
11352   *        // Get the data array for this row
11353   *        var aData = oTable.fnGetData( aPos[0] );
11354   *
11355   *        // Update the data array and return the value
11356   *        aData[ aPos[1] ] = 'clicked';
11357   *        this.innerHTML = 'clicked';
11358   *      } );
11359   *
11360   *      // Init DataTables
11361   *      oTable = $('#example').dataTable();
11362   *    } );
11363   */
11364  this.fnGetPosition = function( node )
11365  {
11366   var api = this.api( true );
11367   var nodeName = node.nodeName.toUpperCase();
11368  
11369   if ( nodeName == 'TR' ) {
11370    return api.row( node ).index();
11371   }
11372   else if ( nodeName == 'TD' || nodeName == 'TH' ) {
11373    var cell = api.cell( node ).index();
11374  
11375    return [
11376     cell.row,
11377     cell.columnVisible,
11378     cell.column
11379    ];
11380   }
11381   return null;
11382  };
11383  
11384  
11385  /**
11386   * Check to see if a row is 'open' or not.
11387   *  @param {node} nTr the table row to check
11388   *  @returns {boolean} true if the row is currently open, false otherwise
11389   *  @dtopt API
11390   *  @deprecated Since v1.10
11391   *
11392   *  @example
11393   *    $(document).ready(function() {
11394   *      var oTable;
11395   *
11396   *      // 'open' an information row when a row is clicked on
11397   *      $('#example tbody tr').click( function () {
11398   *        if ( oTable.fnIsOpen(this) ) {
11399   *          oTable.fnClose( this );
11400   *        } else {
11401   *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
11402   *        }
11403   *      } );
11404   *
11405   *      oTable = $('#example').dataTable();
11406   *    } );
11407   */
11408  this.fnIsOpen = function( nTr )
11409  {
11410   return this.api( true ).row( nTr ).child.isShown();
11411  };
11412  
11413  
11414  /**
11415   * This function will place a new row directly after a row which is currently
11416   * on display on the page, with the HTML contents that is passed into the
11417   * function. This can be used, for example, to ask for confirmation that a
11418   * particular record should be deleted.
11419   *  @param {node} nTr The table row to 'open'
11420   *  @param {string|node|jQuery} mHtml The HTML to put into the row
11421   *  @param {string} sClass Class to give the new TD cell
11422   *  @returns {node} The row opened. Note that if the table row passed in as the
11423   *    first parameter, is not found in the table, this method will silently
11424   *    return.
11425   *  @dtopt API
11426   *  @deprecated Since v1.10
11427   *
11428   *  @example
11429   *    $(document).ready(function() {
11430   *      var oTable;
11431   *
11432   *      // 'open' an information row when a row is clicked on
11433   *      $('#example tbody tr').click( function () {
11434   *        if ( oTable.fnIsOpen(this) ) {
11435   *          oTable.fnClose( this );
11436   *        } else {
11437   *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
11438   *        }
11439   *      } );
11440   *
11441   *      oTable = $('#example').dataTable();
11442   *    } );
11443   */
11444  this.fnOpen = function( nTr, mHtml, sClass )
11445  {
11446   return this.api( true )
11447    .row( nTr )
11448    .child( mHtml, sClass )
11449    .show()
11450    .child()[0];
11451  };
11452  
11453  
11454  /**
11455   * Change the pagination - provides the internal logic for pagination in a simple API
11456   * function. With this function you can have a DataTables table go to the next,
11457   * previous, first or last pages.
11458   *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
11459   *    or page number to jump to (integer), note that page 0 is the first page.
11460   *  @param {bool} [bRedraw=true] Redraw the table or not
11461   *  @dtopt API
11462   *  @deprecated Since v1.10
11463   *
11464   *  @example
11465   *    $(document).ready(function() {
11466   *      var oTable = $('#example').dataTable();
11467   *      oTable.fnPageChange( 'next' );
11468   *    } );
11469   */
11470  this.fnPageChange = function ( mAction, bRedraw )
11471  {
11472   var api = this.api( true ).page( mAction );
11473  
11474   if ( bRedraw === undefined || bRedraw ) {
11475    api.draw(false);
11476   }
11477  };
11478  
11479  
11480  /**
11481   * Show a particular column
11482   *  @param {int} iCol The column whose display should be changed
11483   *  @param {bool} bShow Show (true) or hide (false) the column
11484   *  @param {bool} [bRedraw=true] Redraw the table or not
11485   *  @dtopt API
11486   *  @deprecated Since v1.10
11487   *
11488   *  @example
11489   *    $(document).ready(function() {
11490   *      var oTable = $('#example').dataTable();
11491   *
11492   *      // Hide the second column after initialisation
11493   *      oTable.fnSetColumnVis( 1, false );
11494   *    } );
11495   */
11496  this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
11497  {
11498   var api = this.api( true ).column( iCol ).visible( bShow );
11499  
11500   if ( bRedraw === undefined || bRedraw ) {
11501    api.columns.adjust().draw();
11502   }
11503  };
11504  
11505  
11506  /**
11507   * Get the settings for a particular table for external manipulation
11508   *  @returns {object} DataTables settings object. See
11509   *    {@link DataTable.models.oSettings}
11510   *  @dtopt API
11511   *  @deprecated Since v1.10
11512   *
11513   *  @example
11514   *    $(document).ready(function() {
11515   *      var oTable = $('#example').dataTable();
11516   *      var oSettings = oTable.fnSettings();
11517   *
11518   *      // Show an example parameter from the settings
11519   *      alert( oSettings._iDisplayStart );
11520   *    } );
11521   */
11522  this.fnSettings = function()
11523  {
11524   return _fnSettingsFromNode( this[_ext.iApiIndex] );
11525  };
11526  
11527  
11528  /**
11529   * Sort the table by a particular column
11530   *  @param {int} iCol the data index to sort on. Note that this will not match the
11531   *    'display index' if you have hidden data entries
11532   *  @dtopt API
11533   *  @deprecated Since v1.10
11534   *
11535   *  @example
11536   *    $(document).ready(function() {
11537   *      var oTable = $('#example').dataTable();
11538   *
11539   *      // Sort immediately with columns 0 and 1
11540   *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
11541   *    } );
11542   */
11543  this.fnSort = function( aaSort )
11544  {
11545   this.api( true ).order( aaSort ).draw();
11546  };
11547  
11548  
11549  /**
11550   * Attach a sort listener to an element for a given column
11551   *  @param {node} nNode the element to attach the sort listener to
11552   *  @param {int} iColumn the column that a click on this node will sort on
11553   *  @param {function} [fnCallback] callback function when sort is run
11554   *  @dtopt API
11555   *  @deprecated Since v1.10
11556   *
11557   *  @example
11558   *    $(document).ready(function() {
11559   *      var oTable = $('#example').dataTable();
11560   *
11561   *      // Sort on column 1, when 'sorter' is clicked on
11562   *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
11563   *    } );
11564   */
11565  this.fnSortListener = function( nNode, iColumn, fnCallback )
11566  {
11567   this.api( true ).order.listener( nNode, iColumn, fnCallback );
11568  };
11569  
11570  
11571  /**
11572   * Update a table cell or row - this method will accept either a single value to
11573   * update the cell with, an array of values with one element for each column or
11574   * an object in the same format as the original data source. The function is
11575   * self-referencing in order to make the multi column updates easier.
11576   *  @param {object|array|string} mData Data to update the cell/row with
11577   *  @param {node|int} mRow TR element you want to update or the aoData index
11578   *  @param {int} [iColumn] The column to update, give as null or undefined to
11579   *    update a whole row.
11580   *  @param {bool} [bRedraw=true] Redraw the table or not
11581   *  @param {bool} [bAction=true] Perform pre-draw actions or not
11582   *  @returns {int} 0 on success, 1 on error
11583   *  @dtopt API
11584   *  @deprecated Since v1.10
11585   *
11586   *  @example
11587   *    $(document).ready(function() {
11588   *      var oTable = $('#example').dataTable();
11589   *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
11590   *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
11591   *    } );
11592   */
11593  this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
11594  {
11595   var api = this.api( true );
11596  
11597   if ( iColumn === undefined || iColumn === null ) {
11598    api.row( mRow ).data( mData );
11599   }
11600   else {
11601    api.cell( mRow, iColumn ).data( mData );
11602   }
11603  
11604   if ( bAction === undefined || bAction ) {
11605    api.columns.adjust();
11606   }
11607  
11608   if ( bRedraw === undefined || bRedraw ) {
11609    api.draw();
11610   }
11611   return 0;
11612  };
11613  
11614  
11615  /**
11616   * Provide a common method for plug-ins to check the version of DataTables being used, in order
11617   * to ensure compatibility.
11618   *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
11619   *    formats "X" and "X.Y" are also acceptable.
11620   *  @returns {boolean} true if this version of DataTables is greater or equal to the required
11621   *    version, or false if this version of DataTales is not suitable
11622   *  @method
11623   *  @dtopt API
11624   *  @deprecated Since v1.10
11625   *
11626   *  @example
11627   *    $(document).ready(function() {
11628   *      var oTable = $('#example').dataTable();
11629   *      alert( oTable.fnVersionCheck( '1.9.0' ) );
11630   *    } );
11631   */
11632  this.fnVersionCheck = _ext.fnVersionCheck;
11633  
11634  var _that = this;
11635  var emptyInit = options === undefined;
11636  var len = this.length;
11637  if ( emptyInit ) {
11638   options = {};
11639  }
11640  this.oApi = this.internal = _ext.internal;
11641  // Extend with old style plug-in API methods
11642  for ( var fn in DataTable.ext.internal ) {
11643   if ( fn ) {
11644    this[fn] = _fnExternApiFunc(fn);
11645   }
11646  }
11647  this.each(function() {
11648   // For each initialisation we want to give it a clean initialisation
11649   // object that can be bashed around
11650   var o = {};
11651   var oInit = len > 1 ? // optimisation for single table case
11652    _fnExtend( o, options, true ) :
11653    options;
11654   /*global oInit,_that,emptyInit*/
11655   var i=0, iLen, j, jLen, k, kLen;
11656   var sId = this.getAttribute( 'id' );
11657   var bInitHandedOff = false;
11658   var defaults = DataTable.defaults;
11659   var $this = $(this);
11660   
11661   
11662   /* Sanity check */
11663   if ( this.nodeName.toLowerCase() != 'table' )
11664   {
11665    _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
11666    return;
11667   }
11668   
11669   /* Backwards compatibility for the defaults */
11670   _fnCompatOpts( defaults );
11671   _fnCompatCols( defaults.column );
11672   
11673   /* Convert the camel-case defaults to Hungarian */
11674   _fnCamelToHungarian( defaults, defaults, true );
11675   _fnCamelToHungarian( defaults.column, defaults.column, true );
11676   
11677   /* Setting up the initialisation object */
11678   _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
11679   
11680   
11681   
11682   /* Check to see if we are re-initialising a table */
11683   var allSettings = DataTable.settings;
11684   for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
11685   {
11686    var s = allSettings[i];
11687   
11688    /* Base check on table node */
11689    if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
11690    {
11691     var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
11692     var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
11693   
11694     if ( emptyInit || bRetrieve )
11695     {
11696      return s.oInstance;
11697     }
11698     else if ( bDestroy )
11699     {
11700      s.oInstance.fnDestroy();
11701      break;
11702     }
11703     else
11704     {
11705      _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
11706      return;
11707     }
11708    }
11709   
11710    /* If the element we are initialising has the same ID as a table which was previously
11711     * initialised, but the table nodes don't match (from before) then we destroy the old
11712     * instance by simply deleting it. This is under the assumption that the table has been
11713     * destroyed by other methods. Anyone using non-id selectors will need to do this manually
11714     */
11715    if ( s.sTableId == this.id )
11716    {
11717     allSettings.splice( i, 1 );
11718     break;
11719    }
11720   }
11721   
11722   /* Ensure the table has an ID - required for accessibility */
11723   if ( sId === null || sId === "" )
11724   {
11725    sId = "DataTables_Table_"+(DataTable.ext._unique++);
11726    this.id = sId;
11727   }
11728   
11729   /* Create the settings object for this table and set some of the default parameters */
11730   var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
11731    "sDestroyWidth": $this[0].style.width,
11732    "sInstance":     sId,
11733    "sTableId":      sId
11734   } );
11735   oSettings.nTable = this;
11736   oSettings.oApi   = _that.internal;
11737   oSettings.oInit  = oInit;
11738   
11739   allSettings.push( oSettings );
11740   
11741   // Need to add the instance after the instance after the settings object has been added
11742   // to the settings array, so we can self reference the table instance if more than one
11743   oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
11744   
11745   // Backwards compatibility, before we apply all the defaults
11746   _fnCompatOpts( oInit );
11747   
11748   if ( oInit.oLanguage )
11749   {
11750    _fnLanguageCompat( oInit.oLanguage );
11751   }
11752   
11753   // If the length menu is given, but the init display length is not, use the length menu
11754   if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
11755   {
11756    oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
11757     oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
11758   }
11759   
11760   // Apply the defaults and init options to make a single init object will all
11761   // options defined from defaults and instance options.
11762   oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
11763   
11764   
11765   // Map the initialisation options onto the settings object
11766   _fnMap( oSettings.oFeatures, oInit, [
11767    "bPaginate",
11768    "bLengthChange",
11769    "bFilter",
11770    "bSort",
11771    "bSortMulti",
11772    "bInfo",
11773    "bProcessing",
11774    "bAutoWidth",
11775    "bSortClasses",
11776    "bServerSide",
11777    "bDeferRender"
11778   ] );
11779   _fnMap( oSettings, oInit, [
11780    "asStripeClasses",
11781    "ajax",
11782    "fnServerData",
11783    "fnFormatNumber",
11784    "sServerMethod",
11785    "aaSorting",
11786    "aaSortingFixed",
11787    "aLengthMenu",
11788    "sPaginationType",
11789    "sAjaxSource",
11790    "sAjaxDataProp",
11791    "iStateDuration",
11792    "sDom",
11793    "bSortCellsTop",
11794    "iTabIndex",
11795    "fnStateLoadCallback",
11796    "fnStateSaveCallback",
11797    "renderer",
11798    "searchDelay",
11799    "rowId",
11800    [ "iCookieDuration", "iStateDuration" ], // backwards compat
11801    [ "oSearch", "oPreviousSearch" ],
11802    [ "aoSearchCols", "aoPreSearchCols" ],
11803    [ "iDisplayLength", "_iDisplayLength" ],
11804    [ "bJQueryUI", "bJUI" ]
11805   ] );
11806   _fnMap( oSettings.oScroll, oInit, [
11807    [ "sScrollX", "sX" ],
11808    [ "sScrollXInner", "sXInner" ],
11809    [ "sScrollY", "sY" ],
11810    [ "bScrollCollapse", "bCollapse" ]
11811   ] );
11812   _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
11813   
11814   /* Callback functions which are array driven */
11815   _fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
11816   _fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
11817   _fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
11818   _fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
11819   _fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
11820   _fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
11821   _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
11822   _fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
11823   _fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
11824   _fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
11825   _fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
11826   
11827   oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
11828   
11829   /* Browser support detection */
11830   _fnBrowserDetect( oSettings );
11831   
11832   var oClasses = oSettings.oClasses;
11833   
11834   // @todo Remove in 1.11
11835   if ( oInit.bJQueryUI )
11836   {
11837    /* Use the JUI classes object for display. You could clone the oStdClasses object if
11838     * you want to have multiple tables with multiple independent classes
11839     */
11840    $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
11841   
11842    if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
11843    {
11844     /* Set the DOM to use a layout suitable for jQuery UI's theming */
11845     oSettings.sDom = '<"H"lfr>t<"F"ip>';
11846    }
11847   
11848    if ( ! oSettings.renderer ) {
11849     oSettings.renderer = 'jqueryui';
11850    }
11851    else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
11852     oSettings.renderer.header = 'jqueryui';
11853    }
11854   }
11855   else
11856   {
11857    $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
11858   }
11859   $this.addClass( oClasses.sTable );
11860   
11861   
11862   if ( oSettings.iInitDisplayStart === undefined )
11863   {
11864    /* Display start point, taking into account the save saving */
11865    oSettings.iInitDisplayStart = oInit.iDisplayStart;
11866    oSettings._iDisplayStart = oInit.iDisplayStart;
11867   }
11868   
11869   if ( oInit.iDeferLoading !== null )
11870   {
11871    oSettings.bDeferLoading = true;
11872    var tmp = $.isArray( oInit.iDeferLoading );
11873    oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
11874    oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
11875   }
11876   
11877   /* Language definitions */
11878   var oLanguage = oSettings.oLanguage;
11879   $.extend( true, oLanguage, oInit.oLanguage );
11880   
11881   if ( oLanguage.sUrl !== "" )
11882   {
11883    /* Get the language definitions from a file - because this Ajax call makes the language
11884     * get async to the remainder of this function we use bInitHandedOff to indicate that
11885     * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
11886     */
11887    $.ajax( {
11888     dataType: 'json',
11889     url: oLanguage.sUrl,
11890     success: function ( json ) {
11891      _fnLanguageCompat( json );
11892      _fnCamelToHungarian( defaults.oLanguage, json );
11893      $.extend( true, oLanguage, json );
11894      _fnInitialise( oSettings );
11895     },
11896     error: function () {
11897      // Error occurred loading language file, continue on as best we can
11898      _fnInitialise( oSettings );
11899     }
11900    } );
11901    bInitHandedOff = true;
11902   }
11903   
11904   /*
11905    * Stripes
11906    */
11907   if ( oInit.asStripeClasses === null )
11908   {
11909    oSettings.asStripeClasses =[
11910     oClasses.sStripeOdd,
11911     oClasses.sStripeEven
11912    ];
11913   }
11914   
11915   /* Remove row stripe classes if they are already on the table row */
11916   var stripeClasses = oSettings.asStripeClasses;
11917   var rowOne = $this.children('tbody').find('tr').eq(0);
11918   if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
11919    return rowOne.hasClass(el);
11920   } ) ) !== -1 ) {
11921    $('tbody tr', this).removeClass( stripeClasses.join(' ') );
11922    oSettings.asDestroyStripes = stripeClasses.slice();
11923   }
11924   
11925   /*
11926    * Columns
11927    * See if we should load columns automatically or use defined ones
11928    */
11929   var anThs = [];
11930   var aoColumnsInit;
11931   var nThead = this.getElementsByTagName('thead');
11932   if ( nThead.length !== 0 )
11933   {
11934    _fnDetectHeader( oSettings.aoHeader, nThead[0] );
11935    anThs = _fnGetUniqueThs( oSettings );
11936   }
11937   
11938   /* If not given a column array, generate one with nulls */
11939   if ( oInit.aoColumns === null )
11940   {
11941    aoColumnsInit = [];
11942    for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
11943    {
11944     aoColumnsInit.push( null );
11945    }
11946   }
11947   else
11948   {
11949    aoColumnsInit = oInit.aoColumns;
11950   }
11951   
11952   /* Add the columns */
11953   for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
11954   {
11955    _fnAddColumn( oSettings, anThs ? anThs[i] : null );
11956   }
11957   
11958   /* Apply the column definitions */
11959   _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
11960    _fnColumnOptions( oSettings, iCol, oDef );
11961   } );
11962   
11963   /* HTML5 attribute detection - build an mData object automatically if the
11964    * attributes are found
11965    */
11966   if ( rowOne.length ) {
11967    var a = function ( cell, name ) {
11968     return cell.getAttribute( 'data-'+name ) !== null ? name : null;
11969    };
11970   
11971    $( rowOne[0] ).children('th, td').each( function (i, cell) {
11972     var col = oSettings.aoColumns[i];
11973   
11974     if ( col.mData === i ) {
11975      var sort = a( cell, 'sort' ) || a( cell, 'order' );
11976      var filter = a( cell, 'filter' ) || a( cell, 'search' );
11977   
11978      if ( sort !== null || filter !== null ) {
11979       col.mData = {
11980        _:      i+'.display',
11981        sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
11982        type:   sort !== null   ? i+'.@data-'+sort   : undefined,
11983        filter: filter !== null ? i+'.@data-'+filter : undefined
11984       };
11985   
11986       _fnColumnOptions( oSettings, i );
11987      }
11988     }
11989    } );
11990   }
11991   
11992   var features = oSettings.oFeatures;
11993   
11994   /* Must be done after everything which can be overridden by the state saving! */
11995   if ( oInit.bStateSave )
11996   {
11997    features.bStateSave = true;
11998    _fnLoadState( oSettings, oInit );
11999    _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
12000   }
12001   
12002   
12003   /*
12004    * Sorting
12005    * @todo For modularisation (1.11) this needs to do into a sort start up handler
12006    */
12007   
12008   // If aaSorting is not defined, then we use the first indicator in asSorting
12009   // in case that has been altered, so the default sort reflects that option
12010   if ( oInit.aaSorting === undefined )
12011   {
12012    var sorting = oSettings.aaSorting;
12013    for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
12014    {
12015     sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
12016    }
12017   }
12018   
12019   /* Do a first pass on the sorting classes (allows any size changes to be taken into
12020    * account, and also will apply sorting disabled classes if disabled
12021    */
12022   _fnSortingClasses( oSettings );
12023   
12024   if ( features.bSort )
12025   {
12026    _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
12027     if ( oSettings.bSorted ) {
12028      var aSort = _fnSortFlatten( oSettings );
12029      var sortedColumns = {};
12030   
12031      $.each( aSort, function (i, val) {
12032       sortedColumns[ val.src ] = val.dir;
12033      } );
12034   
12035      _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
12036      _fnSortAria( oSettings );
12037     }
12038    } );
12039   }
12040   
12041   _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
12042    if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
12043     _fnSortingClasses( oSettings );
12044    }
12045   }, 'sc' );
12046   
12047   
12048   /*
12049    * Final init
12050    * Cache the header, body and footer as required, creating them if needed
12051    */
12052   
12053   // Work around for Webkit bug 83867 - store the caption-side before removing from doc
12054   var captions = $this.children('caption').each( function () {
12055    this._captionSide = $this.css('caption-side');
12056   } );
12057   
12058   var thead = $this.children('thead');
12059   if ( thead.length === 0 )
12060   {
12061    thead = $('<thead/>').appendTo(this);
12062   }
12063   oSettings.nTHead = thead[0];
12064   
12065   var tbody = $this.children('tbody');
12066   if ( tbody.length === 0 )
12067   {
12068    tbody = $('<tbody/>').appendTo(this);
12069   }
12070   oSettings.nTBody = tbody[0];
12071   
12072   var tfoot = $this.children('tfoot');
12073   if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
12074   {
12075    // If we are a scrolling table, and no footer has been given, then we need to create
12076    // a tfoot element for the caption element to be appended to
12077    tfoot = $('<tfoot/>').appendTo(this);
12078   }
12079   
12080   if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
vendor: 1,188 bytes, lines 12081-12123
12081    $this.addClass( oClasses.sNoFooter );
12082   }
12083   else if ( tfoot.length > 0 ) {
12084    oSettings.nTFoot = tfoot[0];
12085    _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
12086   }
12087   
12088   /* Check if there is data passing into the constructor */
12089   if ( oInit.aaData )
12090   {
12091    for ( i=0 ; i<oInit.aaData.length ; i++ )
12092    {
12093     _fnAddData( oSettings, oInit.aaData[ i ] );
12094    }
12095   }
12096   else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
12097   {
12098    /* Grab the data from the page - only do this when deferred loading or no Ajax
12099     * source since there is no point in reading the DOM data if we are then going
12100     * to replace it with Ajax data
12101     */
12102    _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
12103   }
12104   
12105   /* Copy the data index array */
12106   oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
12107   
12108   /* Initialisation complete - table can be drawn */
12109   oSettings.bInitialised = true;
12110   
12111   /* Check if we need to initialise the table (it might not have been handed off to the
12112    * language processor)
12113    */
12114   if ( bInitHandedOff === false )
12115   {
12116    _fnInitialise( oSettings );
12117   }
12118  } );
12119  _that = null;
12120  return this;
12121 };
12122 
12123 /*
12124  * It is useful to have variables which are scoped locally so only the
12125  * DataTables functions can access them and they don't leak into global space.
12126  * At the same time these functions are often useful over multiple files in the
12127  * core and API, so we list, or at least document, all variables which are used
12128  * by DataTables as private variables here. This also ensures that there is no
12129  * clashing of variable names and that they can easily referenced for reuse.
12130  */
12131 
12132 
12133 // Defined else where
12134 //  _selector_run
12135 //  _selector_opts
12136 //  _selector_first
12137 //  _selector_row_indexes
12138 
12139 var _ext; // DataTable.ext
12140 var _Api; // DataTable.Api
12141 var _api_register; // DataTable.Api.register
12142 var _api_registerPlural; // DataTable.Api.registerPlural
12143 
12144 var _re_dic = {};
12145 var _re_new_lines = /[\r\n]/g;
12146 var _re_html = /<.*?>/g;
12147 var _re_date_start = /^[\w\+\-]/;
12148 var _re_date_end = /[\w\+\-]$/;
12149 
12150 // Escape regular expression special characters
12151 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
12152 
12153 // http://en.wikipedia.org/wiki/Foreign_exchange_market
12154 // - \u20BD - Russian ruble.
12155 // - \u20a9 - South Korean Won
12156 // - \u20BA - Turkish Lira
12157 // - \u20B9 - Indian Rupee
12158 // - R - Brazil (R$) and South Africa
12159 // - fr - Swiss Franc
12160 // - kr - Swedish krona, Norwegian krone and Danish krone
12161 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
12162 //   standards as thousands separators.
12163 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
12164 
12165 
12166 var _empty = function ( d ) {
12167  return !d || d === true || d === '-' ? true : false;
12168 };
12169 
12170 
12171 var _intVal = function ( s ) {
12172  var integer = parseInt( s, 10 );
12173  return !isNaN(integer) && isFinite(s) ? integer : null;
12174 };
12175 
12176 // Convert from a formatted number with characters other than `.` as the
12177 // decimal place, to a Javascript number
12178 var _numToDecimal = function ( num, decimalPoint ) {
12179  // Cache created regular expressions for speed as this function is called often
12180  if ( ! _re_dic[ decimalPoint ] ) {
12181   _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
12182  }
12183  return typeof num === 'string' && decimalPoint !== '.' ?
12184   num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
12185   num;
12186 };
12187 
12188 
12189 var _isNumber = function ( d, decimalPoint, formatted ) {
12190  var strType = typeof d === 'string';
12191 
12192  // If empty return immediately so there must be a number if it is a
12193  // formatted string (this stops the string "k", or "kr", etc being detected
12194  // as a formatted number for currency
12195  if ( _empty( d ) ) {
12196   return true;
12197  }
12198 
12199  if ( decimalPoint && strType ) {
12200   d = _numToDecimal( d, decimalPoint );
12201  }
12202 
12203  if ( formatted && strType ) {
12204   d = d.replace( _re_formatted_numeric, '' );
12205  }
12206 
12207  return !isNaN( parseFloat(d) ) && isFinite( d );
12208 };
12209 
12210 
12211 // A string without HTML in it can be considered to be HTML still
12212 var _isHtml = function ( d ) {
12213  return _empty( d ) || typeof d === 'string';
12214 };
12215 
12216 
12217 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
12218  if ( _empty( d ) ) {
12219   return true;
12220  }
12221 
12222  var html = _isHtml( d );
12223  return ! html ?
12224   null :
12225   _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
12226    true :
12227    null;
12228 };
12229 
12230 
12231 var _pluck = function ( a, prop, prop2 ) {
12232  var out = [];
12233  var i=0, ien=a.length;
12234 
12235  // Could have the test in the loop for slightly smaller code, but speed
12236  // is essential here
12237  if ( prop2 !== undefined ) {
12238   for ( ; i<ien ; i++ ) {
12239    if ( a[i] && a[i][ prop ] ) {
12240     out.push( a[i][ prop ][ prop2 ] );
12241    }
12242   }
12243  }
12244  else {
12245   for ( ; i<ien ; i++ ) {
12246    if ( a[i] ) {
12247     out.push( a[i][ prop ] );
12248    }
12249   }
12250  }
12251 
12252  return out;
12253 };
12254 
12255 
12256 // Basically the same as _pluck, but rather than looping over `a` we use `order`
12257 // as the indexes to pick from `a`
12258 var _pluck_order = function ( a, order, prop, prop2 )
12259 {
12260  var out = [];
12261  var i=0, ien=order.length;
12262 
12263  // Could have the test in the loop for slightly smaller code, but speed
12264  // is essential here
12265  if ( prop2 !== undefined ) {
12266   for ( ; i<ien ; i++ ) {
12267    if ( a[ order[i] ][ prop ] ) {
12268     out.push( a[ order[i] ][ prop ][ prop2 ] );
12269    }
12270   }
12271  }
12272  else {
12273   for ( ; i<ien ; i++ ) {
12274    out.push( a[ order[i] ][ prop ] );
12275   }
12276  }
12277 
12278  return out;
12279 };
12280 
12281 
12282 var _range = function ( len, start )
12283 {
12284  var out = [];
12285  var end;
12286 
12287  if ( start === undefined ) {
12288   start = 0;
12289   end = len;
12290  }
12291  else {
12292   end = start;
12293   start = len;
12294  }
12295 
12296  for ( var i=start ; i<end ; i++ ) {
12297   out.push( i );
12298  }
12299 
12300  return out;
12301 };
12302 
12303 
12304 var _removeEmpty = function ( a )
12305 {
12306  var out = [];
12307 
12308  for ( var i=0, ien=a.length ; i<ien ; i++ ) {
12309   if ( a[i] ) { // careful - will remove all falsy values!
12310    out.push( a[i] );
12311   }
12312  }
12313 
12314  return out;
12315 };
12316 
12317 
12318 var _stripHtml = function ( d ) {
12319  return d.replace( _re_html, '' );
12320 };
12321 
12322 
12323 /**
12324  * Find the unique elements in a source array.
12325  *
12326  * @param  {array} src Source array
12327  * @return {array} Array of unique items
12328  * @ignore
12329  */
12330 var _unique = function ( src )
12331 {
vendor: 25,648 bytes, lines 12332-13241
12332  // A faster unique method is to use object keys to identify used values,
12333  // but this doesn't work with arrays or objects, which we must also
12334  // consider. See jsperf.com/compare-array-unique-versions/4 for more
12335  // information.
12336  var
12337   out = [],
12338   val,
12339   i, ien=src.length,
12340   j, k=0;
12341 
12342  again: for ( i=0 ; i<ien ; i++ ) {
12343   val = src[i];
12344 
12345   for ( j=0 ; j<k ; j++ ) {
12346    if ( out[j] === val ) {
12347     continue again;
12348    }
12349   }
12350 
12351   out.push( val );
12352   k++;
12353  }
12354 
12355  return out;
12356 };
12357 
12358 
12359 /**
12360  * DataTables utility methods
12361  * 
12362  * This namespace provides helper methods that DataTables uses internally to
12363  * create a DataTable, but which are not exclusively used only for DataTables.
12364  * These methods can be used by extension authors to save the duplication of
12365  * code.
12366  *
12367  *  @namespace
12368  */
12369 DataTable.util = {
12370  /**
12371   * Throttle the calls to a function. Arguments and context are maintained
12372   * for the throttled function.
12373   *
12374   * @param {function} fn Function to be called
12375   * @param {integer} freq Call frequency in mS
12376   * @return {function} Wrapped function
12377   */
12378  throttle: function ( fn, freq ) {
12379   var
12380    frequency = freq !== undefined ? freq : 200,
12381    last,
12382    timer;
12383 
12384   return function () {
12385    var
12386     that = this,
12387     now  = +new Date(),
12388     args = arguments;
12389 
12390    if ( last && now < last + frequency ) {
12391     clearTimeout( timer );
12392 
12393     timer = setTimeout( function () {
12394      last = undefined;
12395      fn.apply( that, args );
12396     }, frequency );
12397    }
12398    else {
12399     last = now;
12400     fn.apply( that, args );
12401    }
12402   };
12403  },
12404 
12405 
12406  /**
12407   * Escape a string such that it can be used in a regular expression
12408   *
12409   *  @param {string} val string to escape
12410   *  @returns {string} escaped string
12411   */
12412  escapeRegex: function ( val ) {
12413   return val.replace( _re_escape_regex, '\\$1' );
12414  }
12415 };
12416 
12417 
12418 
12419 /**
12420  * Create a mapping object that allows camel case parameters to be looked up
12421  * for their Hungarian counterparts. The mapping is stored in a private
12422  * parameter called `_hungarianMap` which can be accessed on the source object.
12423  *  @param {object} o
12424  *  @memberof DataTable#oApi
12425  */
12426 function _fnHungarianMap ( o )
12427 {
12428  var
12429   hungarian = 'a aa ai ao as b fn i m o s ',
12430   match,
12431   newKey,
12432   map = {};
12433 
12434  $.each( o, function (key, val) {
12435   match = key.match(/^([^A-Z]+?)([A-Z])/);
12436 
12437   if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
12438   {
12439    newKey = key.replace( match[0], match[2].toLowerCase() );
12440    map[ newKey ] = key;
12441 
12442    if ( match[1] === 'o' )
12443    {
12444     _fnHungarianMap( o[key] );
12445    }
12446   }
12447  } );
12448 
12449  o._hungarianMap = map;
12450 }
12451 
12452 
12453 /**
12454  * Convert from camel case parameters to Hungarian, based on a Hungarian map
12455  * created by _fnHungarianMap.
12456  *  @param {object} src The model object which holds all parameters that can be
12457  *    mapped.
12458  *  @param {object} user The object to convert from camel case to Hungarian.
12459  *  @param {boolean} force When set to `true`, properties which already have a
12460  *    Hungarian value in the `user` object will be overwritten. Otherwise they
12461  *    won't be.
12462  *  @memberof DataTable#oApi
12463  */
12464 function _fnCamelToHungarian ( src, user, force )
12465 {
12466  if ( ! src._hungarianMap ) {
12467   _fnHungarianMap( src );
12468  }
12469 
12470  var hungarianKey;
12471 
12472  $.each( user, function (key, val) {
12473   hungarianKey = src._hungarianMap[ key ];
12474 
12475   if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
12476   {
12477    // For objects, we need to buzz down into the object to copy parameters
12478    if ( hungarianKey.charAt(0) === 'o' )
12479    {
12480     // Copy the camelCase options over to the hungarian
12481     if ( ! user[ hungarianKey ] ) {
12482      user[ hungarianKey ] = {};
12483     }
12484     $.extend( true, user[hungarianKey], user[key] );
12485 
12486     _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
12487    }
12488    else {
12489     user[hungarianKey] = user[ key ];
12490    }
12491   }
12492  } );
12493 }
12494 
12495 
12496 /**
12497  * Language compatibility - when certain options are given, and others aren't, we
12498  * need to duplicate the values over, in order to provide backwards compatibility
12499  * with older language files.
12500  *  @param {object} oSettings dataTables settings object
12501  *  @memberof DataTable#oApi
12502  */
12503 function _fnLanguageCompat( lang )
12504 {
12505  var defaults = DataTable.defaults.oLanguage;
12506  var zeroRecords = lang.sZeroRecords;
12507 
12508  /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
12509   * sZeroRecords - assuming that is given.
12510   */
12511  if ( ! lang.sEmptyTable && zeroRecords &&
12512   defaults.sEmptyTable === "No data available in table" )
12513  {
12514   _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
12515  }
12516 
12517  /* Likewise with loading records */
12518  if ( ! lang.sLoadingRecords && zeroRecords &&
12519   defaults.sLoadingRecords === "Loading..." )
12520  {
12521   _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
12522  }
12523 
12524  // Old parameter name of the thousands separator mapped onto the new
12525  if ( lang.sInfoThousands ) {
12526   lang.sThousands = lang.sInfoThousands;
12527  }
12528 
12529  var decimal = lang.sDecimal;
12530  if ( decimal ) {
12531   _addNumericSort( decimal );
12532  }
12533 }
12534 
12535 
12536 /**
12537  * Map one parameter onto another
12538  *  @param {object} o Object to map
12539  *  @param {*} knew The new parameter name
12540  *  @param {*} old The old parameter name
12541  */
12542 var _fnCompatMap = function ( o, knew, old ) {
12543  if ( o[ knew ] !== undefined ) {
12544   o[ old ] = o[ knew ];
12545  }
12546 };
12547 
12548 
12549 /**
12550  * Provide backwards compatibility for the main DT options. Note that the new
12551  * options are mapped onto the old parameters, so this is an external interface
12552  * change only.
12553  *  @param {object} init Object to map
12554  */
12555 function _fnCompatOpts ( init )
12556 {
12557  _fnCompatMap( init, 'ordering',      'bSort' );
12558  _fnCompatMap( init, 'orderMulti',    'bSortMulti' );
12559  _fnCompatMap( init, 'orderClasses',  'bSortClasses' );
12560  _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
12561  _fnCompatMap( init, 'order',         'aaSorting' );
12562  _fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
12563  _fnCompatMap( init, 'paging',        'bPaginate' );
12564  _fnCompatMap( init, 'pagingType',    'sPaginationType' );
12565  _fnCompatMap( init, 'pageLength',    'iDisplayLength' );
12566  _fnCompatMap( init, 'searching',     'bFilter' );
12567 
12568  // Boolean initialisation of x-scrolling
12569  if ( typeof init.sScrollX === 'boolean' ) {
12570   init.sScrollX = init.sScrollX ? '100%' : '';
12571  }
12572  if ( typeof init.scrollX === 'boolean' ) {
12573   init.scrollX = init.scrollX ? '100%' : '';
12574  }
12575 
12576  // Column search objects are in an array, so it needs to be converted
12577  // element by element
12578  var searchCols = init.aoSearchCols;
12579 
12580  if ( searchCols ) {
12581   for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
12582    if ( searchCols[i] ) {
12583     _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
12584    }
12585   }
12586  }
12587 }
12588 
12589 
12590 /**
12591  * Provide backwards compatibility for column options. Note that the new options
12592  * are mapped onto the old parameters, so this is an external interface change
12593  * only.
12594  *  @param {object} init Object to map
12595  */
12596 function _fnCompatCols ( init )
12597 {
12598  _fnCompatMap( init, 'orderable',     'bSortable' );
12599  _fnCompatMap( init, 'orderData',     'aDataSort' );
12600  _fnCompatMap( init, 'orderSequence', 'asSorting' );
12601  _fnCompatMap( init, 'orderDataType', 'sortDataType' );
12602 
12603  // orderData can be given as an integer
12604  var dataSort = init.aDataSort;
12605  if ( dataSort && ! $.isArray( dataSort ) ) {
12606   init.aDataSort = [ dataSort ];
12607  }
12608 }
12609 
12610 
12611 /**
12612  * Browser feature detection for capabilities, quirks
12613  *  @param {object} settings dataTables settings object
12614  *  @memberof DataTable#oApi
12615  */
12616 function _fnBrowserDetect( settings )
12617 {
12618  // We don't need to do this every time DataTables is constructed, the values
12619  // calculated are specific to the browser and OS configuration which we
12620  // don't expect to change between initialisations
12621  if ( ! DataTable.__browser ) {
12622   var browser = {};
12623   DataTable.__browser = browser;
12624 
12625   // Scrolling feature / quirks detection
12626   var n = $('<div/>')
12627    .css( {
12628     position: 'fixed',
12629     top: 0,
12630     left: 0,
12631     height: 1,
12632     width: 1,
12633     overflow: 'hidden'
12634    } )
12635    .append(
12636     $('<div/>')
12637      .css( {
12638       position: 'absolute',
12639       top: 1,
12640       left: 1,
12641       width: 100,
12642       overflow: 'scroll'
12643      } )
12644      .append(
12645       $('<div/>')
12646        .css( {
12647         width: '100%',
12648         height: 10
12649        } )
12650      )
12651    )
12652    .appendTo( 'body' );
12653 
12654   var outer = n.children();
12655   var inner = outer.children();
12656 
12657   // Numbers below, in order, are:
12658   // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
12659   //
12660   // IE6 XP:                           100 100 100  83
12661   // IE7 Vista:                        100 100 100  83
12662   // IE 8+ Windows:                     83  83 100  83
12663   // Evergreen Windows:                 83  83 100  83
12664   // Evergreen Mac with scrollbars:     85  85 100  85
12665   // Evergreen Mac without scrollbars: 100 100 100 100
12666 
12667   // Get scrollbar width
12668   browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
12669 
12670   // IE6/7 will oversize a width 100% element inside a scrolling element, to
12671   // include the width of the scrollbar, while other browsers ensure the inner
12672   // element is contained without forcing scrolling
12673   browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
12674 
12675   // In rtl text layout, some browsers (most, but not all) will place the
12676   // scrollbar on the left, rather than the right.
12677   browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
12678 
12679   // IE8- don't provide height and width for getBoundingClientRect
12680   browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
12681 
12682   n.remove();
12683  }
12684 
12685  $.extend( settings.oBrowser, DataTable.__browser );
12686  settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
12687 }
12688 
12689 
12690 /**
12691  * Array.prototype reduce[Right] method, used for browsers which don't support
12692  * JS 1.6. Done this way to reduce code size, since we iterate either way
12693  *  @param {object} settings dataTables settings object
12694  *  @memberof DataTable#oApi
12695  */
12696 function _fnReduce ( that, fn, init, start, end, inc )
12697 {
12698  var
12699   i = start,
12700   value,
12701   isSet = false;
12702 
12703  if ( init !== undefined ) {
12704   value = init;
12705   isSet = true;
12706  }
12707 
12708  while ( i !== end ) {
12709   if ( ! that.hasOwnProperty(i) ) {
12710    continue;
12711   }
12712 
12713   value = isSet ?
12714    fn( value, that[i], i, that ) :
12715    that[i];
12716 
12717   isSet = true;
12718   i += inc;
12719  }
12720 
12721  return value;
12722 }
12723 
12724 /**
12725  * Add a column to the list used for the table with default values
12726  *  @param {object} oSettings dataTables settings object
12727  *  @param {node} nTh The th element for this column
12728  *  @memberof DataTable#oApi
12729  */
12730 function _fnAddColumn( oSettings, nTh )
12731 {
12732  // Add column to aoColumns array
12733  var oDefaults = DataTable.defaults.column;
12734  var iCol = oSettings.aoColumns.length;
12735  var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
12736   "nTh": nTh ? nTh : document.createElement('th'),
12737   "sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
12738   "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
12739   "mData": oDefaults.mData ? oDefaults.mData : iCol,
12740   idx: iCol
12741  } );
12742  oSettings.aoColumns.push( oCol );
12743 
12744  // Add search object for column specific search. Note that the `searchCols[ iCol ]`
12745  // passed into extend can be undefined. This allows the user to give a default
12746  // with only some of the parameters defined, and also not give a default
12747  var searchCols = oSettings.aoPreSearchCols;
12748  searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
12749 
12750  // Use the default column options function to initialise classes etc
12751  _fnColumnOptions( oSettings, iCol, $(nTh).data() );
12752 }
12753 
12754 
12755 /**
12756  * Apply options for a column
12757  *  @param {object} oSettings dataTables settings object
12758  *  @param {int} iCol column index to consider
12759  *  @param {object} oOptions object with sType, bVisible and bSearchable etc
12760  *  @memberof DataTable#oApi
12761  */
12762 function _fnColumnOptions( oSettings, iCol, oOptions )
12763 {
12764  var oCol = oSettings.aoColumns[ iCol ];
12765  var oClasses = oSettings.oClasses;
12766  var th = $(oCol.nTh);
12767 
12768  // Try to get width information from the DOM. We can't get it from CSS
12769  // as we'd need to parse the CSS stylesheet. `width` option can override
12770  if ( ! oCol.sWidthOrig ) {
12771   // Width attribute
12772   oCol.sWidthOrig = th.attr('width') || null;
12773 
12774   // Style attribute
12775   var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
12776   if ( t ) {
12777    oCol.sWidthOrig = t[1];
12778   }
12779  }
12780 
12781  /* User specified column options */
12782  if ( oOptions !== undefined && oOptions !== null )
12783  {
12784   // Backwards compatibility
12785   _fnCompatCols( oOptions );
12786 
12787   // Map camel case parameters to their Hungarian counterparts
12788   _fnCamelToHungarian( DataTable.defaults.column, oOptions );
12789 
12790   /* Backwards compatibility for mDataProp */
12791   if ( oOptions.mDataProp !== undefined && !oOptions.mData )
12792   {
12793    oOptions.mData = oOptions.mDataProp;
12794   }
12795 
12796   if ( oOptions.sType )
12797   {
12798    oCol._sManualType = oOptions.sType;
12799   }
12800 
12801   // `class` is a reserved word in Javascript, so we need to provide
12802   // the ability to use a valid name for the camel case input
12803   if ( oOptions.className && ! oOptions.sClass )
12804   {
12805    oOptions.sClass = oOptions.className;
12806   }
12807 
12808   $.extend( oCol, oOptions );
12809   _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
12810 
12811   /* iDataSort to be applied (backwards compatibility), but aDataSort will take
12812    * priority if defined
12813    */
12814   if ( oOptions.iDataSort !== undefined )
12815   {
12816    oCol.aDataSort = [ oOptions.iDataSort ];
12817   }
12818   _fnMap( oCol, oOptions, "aDataSort" );
12819  }
12820 
12821  /* Cache the data get and set functions for speed */
12822  var mDataSrc = oCol.mData;
12823  var mData = _fnGetObjectDataFn( mDataSrc );
12824  var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
12825 
12826  var attrTest = function( src ) {
12827   return typeof src === 'string' && src.indexOf('@') !== -1;
12828  };
12829  oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
12830   attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
12831  );
12832  oCol._setter = null;
12833 
12834  oCol.fnGetData = function (rowData, type, meta) {
12835   var innerData = mData( rowData, type, undefined, meta );
12836 
12837   return mRender && type ?
12838    mRender( innerData, type, rowData, meta ) :
12839    innerData;
12840  };
12841  oCol.fnSetData = function ( rowData, val, meta ) {
12842   return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
12843  };
12844 
12845  // Indicate if DataTables should read DOM data as an object or array
12846  // Used in _fnGetRowElements
12847  if ( typeof mDataSrc !== 'number' ) {
12848   oSettings._rowReadObject = true;
12849  }
12850 
12851  /* Feature sorting overrides column specific when off */
12852  if ( !oSettings.oFeatures.bSort )
12853  {
12854   oCol.bSortable = false;
12855   th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
12856  }
12857 
12858  /* Check that the class assignment is correct for sorting */
12859  var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
12860  var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
12861  if ( !oCol.bSortable || (!bAsc && !bDesc) )
12862  {
12863   oCol.sSortingClass = oClasses.sSortableNone;
12864   oCol.sSortingClassJUI = "";
12865  }
12866  else if ( bAsc && !bDesc )
12867  {
12868   oCol.sSortingClass = oClasses.sSortableAsc;
12869   oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
12870  }
12871  else if ( !bAsc && bDesc )
12872  {
12873   oCol.sSortingClass = oClasses.sSortableDesc;
12874   oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
12875  }
12876  else
12877  {
12878   oCol.sSortingClass = oClasses.sSortable;
12879   oCol.sSortingClassJUI = oClasses.sSortJUI;
12880  }
12881 }
12882 
12883 
12884 /**
12885  * Adjust the table column widths for new data. Note: you would probably want to
12886  * do a redraw after calling this function!
12887  *  @param {object} settings dataTables settings object
12888  *  @memberof DataTable#oApi
12889  */
12890 function _fnAdjustColumnSizing ( settings )
12891 {
12892  /* Not interested in doing column width calculation if auto-width is disabled */
12893  if ( settings.oFeatures.bAutoWidth !== false )
12894  {
12895   var columns = settings.aoColumns;
12896 
12897   _fnCalculateColumnWidths( settings );
12898   for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
12899   {
12900    columns[i].nTh.style.width = columns[i].sWidth;
12901   }
12902  }
12903 
12904  var scroll = settings.oScroll;
12905  if ( scroll.sY !== '' || scroll.sX !== '')
12906  {
12907   _fnScrollDraw( settings );
12908  }
12909 
12910  _fnCallbackFire( settings, null, 'column-sizing', [settings] );
12911 }
12912 
12913 
12914 /**
12915  * Covert the index of a visible column to the index in the data array (take account
12916  * of hidden columns)
12917  *  @param {object} oSettings dataTables settings object
12918  *  @param {int} iMatch Visible column index to lookup
12919  *  @returns {int} i the data index
12920  *  @memberof DataTable#oApi
12921  */
12922 function _fnVisibleToColumnIndex( oSettings, iMatch )
12923 {
12924  var aiVis = _fnGetColumns( oSettings, 'bVisible' );
12925 
12926  return typeof aiVis[iMatch] === 'number' ?
12927   aiVis[iMatch] :
12928   null;
12929 }
12930 
12931 
12932 /**
12933  * Covert the index of an index in the data array and convert it to the visible
12934  *   column index (take account of hidden columns)
12935  *  @param {int} iMatch Column index to lookup
12936  *  @param {object} oSettings dataTables settings object
12937  *  @returns {int} i the data index
12938  *  @memberof DataTable#oApi
12939  */
12940 function _fnColumnIndexToVisible( oSettings, iMatch )
12941 {
12942  var aiVis = _fnGetColumns( oSettings, 'bVisible' );
12943  var iPos = $.inArray( iMatch, aiVis );
12944 
12945  return iPos !== -1 ? iPos : null;
12946 }
12947 
12948 
12949 /**
12950  * Get the number of visible columns
12951  *  @param {object} oSettings dataTables settings object
12952  *  @returns {int} i the number of visible columns
12953  *  @memberof DataTable#oApi
12954  */
12955 function _fnVisbleColumns( oSettings )
12956 {
12957  var vis = 0;
12958 
12959  // No reduce in IE8, use a loop for now
12960  $.each( oSettings.aoColumns, function ( i, col ) {
12961   if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
12962    vis++;
12963   }
12964  } );
12965 
12966  return vis;
12967 }
12968 
12969 
12970 /**
12971  * Get an array of column indexes that match a given property
12972  *  @param {object} oSettings dataTables settings object
12973  *  @param {string} sParam Parameter in aoColumns to look for - typically
12974  *    bVisible or bSearchable
12975  *  @returns {array} Array of indexes with matched properties
12976  *  @memberof DataTable#oApi
12977  */
12978 function _fnGetColumns( oSettings, sParam )
12979 {
12980  var a = [];
12981 
12982  $.map( oSettings.aoColumns, function(val, i) {
12983   if ( val[sParam] ) {
12984    a.push( i );
12985   }
12986  } );
12987 
12988  return a;
12989 }
12990 
12991 
12992 /**
12993  * Calculate the 'type' of a column
12994  *  @param {object} settings dataTables settings object
12995  *  @memberof DataTable#oApi
12996  */
12997 function _fnColumnTypes ( settings )
12998 {
12999  var columns = settings.aoColumns;
13000  var data = settings.aoData;
13001  var types = DataTable.ext.type.detect;
13002  var i, ien, j, jen, k, ken;
13003  var col, cell, detectedType, cache;
13004 
13005  // For each column, spin over the 
13006  for ( i=0, ien=columns.length ; i<ien ; i++ ) {
13007   col = columns[i];
13008   cache = [];
13009 
13010   if ( ! col.sType && col._sManualType ) {
13011    col.sType = col._sManualType;
13012   }
13013   else if ( ! col.sType ) {
13014    for ( j=0, jen=types.length ; j<jen ; j++ ) {
13015     for ( k=0, ken=data.length ; k<ken ; k++ ) {
13016      // Use a cache array so we only need to get the type data
13017      // from the formatter once (when using multiple detectors)
13018      if ( cache[k] === undefined ) {
13019       cache[k] = _fnGetCellData( settings, k, i, 'type' );
13020      }
13021 
13022      detectedType = types[j]( cache[k], settings );
13023 
13024      // If null, then this type can't apply to this column, so
13025      // rather than testing all cells, break out. There is an
13026      // exception for the last type which is `html`. We need to
13027      // scan all rows since it is possible to mix string and HTML
13028      // types
13029      if ( ! detectedType && j !== types.length-1 ) {
13030       break;
13031      }
13032 
13033      // Only a single match is needed for html type since it is
13034      // bottom of the pile and very similar to string
13035      if ( detectedType === 'html' ) {
13036       break;
13037      }
13038     }
13039 
13040     // Type is valid for all data points in the column - use this
13041     // type
13042     if ( detectedType ) {
13043      col.sType = detectedType;
13044      break;
13045     }
13046    }
13047 
13048    // Fall back - if no type was detected, always use string
13049    if ( ! col.sType ) {
13050     col.sType = 'string';
13051    }
13052   }
13053  }
13054 }
13055 
13056 
13057 /**
13058  * Take the column definitions and static columns arrays and calculate how
13059  * they relate to column indexes. The callback function will then apply the
13060  * definition found for a column to a suitable configuration object.
13061  *  @param {object} oSettings dataTables settings object
13062  *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
13063  *  @param {array} aoCols The aoColumns array that defines columns individually
13064  *  @param {function} fn Callback function - takes two parameters, the calculated
13065  *    column index and the definition for that column.
13066  *  @memberof DataTable#oApi
13067  */
13068 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
13069 {
13070  var i, iLen, j, jLen, k, kLen, def;
13071  var columns = oSettings.aoColumns;
13072 
13073  // Column definitions with aTargets
13074  if ( aoColDefs )
13075  {
13076   /* Loop over the definitions array - loop in reverse so first instance has priority */
13077   for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
13078   {
13079    def = aoColDefs[i];
13080 
13081    /* Each definition can target multiple columns, as it is an array */
13082    var aTargets = def.targets !== undefined ?
13083     def.targets :
13084     def.aTargets;
13085 
13086    if ( ! $.isArray( aTargets ) )
13087    {
13088     aTargets = [ aTargets ];
13089    }
13090 
13091    for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
13092    {
13093     if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
13094     {
13095      /* Add columns that we don't yet know about */
13096      while( columns.length <= aTargets[j] )
13097      {
13098       _fnAddColumn( oSettings );
13099      }
13100 
13101      /* Integer, basic index */
13102      fn( aTargets[j], def );
13103     }
13104     else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
13105     {
13106      /* Negative integer, right to left column counting */
13107      fn( columns.length+aTargets[j], def );
13108     }
13109     else if ( typeof aTargets[j] === 'string' )
13110     {
13111      /* Class name matching on TH element */
13112      for ( k=0, kLen=columns.length ; k<kLen ; k++ )
13113      {
13114       if ( aTargets[j] == "_all" ||
13115            $(columns[k].nTh).hasClass( aTargets[j] ) )
13116       {
13117        fn( k, def );
13118       }
13119      }
13120     }
13121    }
13122   }
13123  }
13124 
13125  // Statically defined columns array
13126  if ( aoCols )
13127  {
13128   for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
13129   {
13130    fn( i, aoCols[i] );
13131   }
13132  }
13133 }
13134 
13135 /**
13136  * Add a data array to the table, creating DOM node etc. This is the parallel to
13137  * _fnGatherData, but for adding rows from a Javascript source, rather than a
13138  * DOM source.
13139  *  @param {object} oSettings dataTables settings object
13140  *  @param {array} aData data array to be added
13141  *  @param {node} [nTr] TR element to add to the table - optional. If not given,
13142  *    DataTables will create a row automatically
13143  *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
13144  *    if nTr is.
13145  *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
13146  *  @memberof DataTable#oApi
13147  */
13148 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
13149 {
13150  /* Create the object for storing information about this new row */
13151  var iRow = oSettings.aoData.length;
13152  var oData = $.extend( true, {}, DataTable.models.oRow, {
13153   src: nTr ? 'dom' : 'data',
13154   idx: iRow
13155  } );
13156 
13157  oData._aData = aDataIn;
13158  oSettings.aoData.push( oData );
13159 
13160  /* Create the cells */
13161  var nTd, sThisType;
13162  var columns = oSettings.aoColumns;
13163 
13164  // Invalidate the column types as the new data needs to be revalidated
13165  for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
13166  {
13167   columns[i].sType = null;
13168  }
13169 
13170  /* Add to the display array */
13171  oSettings.aiDisplayMaster.push( iRow );
13172 
13173  var id = oSettings.rowIdFn( aDataIn );
13174  if ( id !== undefined ) {
13175   oSettings.aIds[ id ] = oData;
13176  }
13177 
13178  /* Create the DOM information, or register it if already present */
13179  if ( nTr || ! oSettings.oFeatures.bDeferRender )
13180  {
13181   _fnCreateTr( oSettings, iRow, nTr, anTds );
13182  }
13183 
13184  return iRow;
13185 }
13186 
13187 
13188 /**
13189  * Add one or more TR elements to the table. Generally we'd expect to
13190  * use this for reading data from a DOM sourced table, but it could be
13191  * used for an TR element. Note that if a TR is given, it is used (i.e.
13192  * it is not cloned).
13193  *  @param {object} settings dataTables settings object
13194  *  @param {array|node|jQuery} trs The TR element(s) to add to the table
13195  *  @returns {array} Array of indexes for the added rows
13196  *  @memberof DataTable#oApi
13197  */
13198 function _fnAddTr( settings, trs )
13199 {
13200  var row;
13201 
13202  // Allow an individual node to be passed in
13203  if ( ! (trs instanceof $) ) {
13204   trs = $(trs);
13205  }
13206 
13207  return trs.map( function (i, el) {
13208   row = _fnGetRowElements( settings, el );
13209   return _fnAddData( settings, row.data, el, row.cells );
13210  } );
13211 }
13212 
13213 
13214 /**
13215  * Take a TR element and convert it to an index in aoData
13216  *  @param {object} oSettings dataTables settings object
13217  *  @param {node} n the TR element to find
13218  *  @returns {int} index if the node is found, null if not
13219  *  @memberof DataTable#oApi
13220  */
13221 function _fnNodeToDataIndex( oSettings, n )
13222 {
13223  return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
13224 }
13225 
13226 
13227 /**
13228  * Take a TD element and convert it into a column data index (not the visible index)
13229  *  @param {object} oSettings dataTables settings object
13230  *  @param {int} iRow The row number the TD/TH can be found in
13231  *  @param {node} n The TD/TH element to find
13232  *  @returns {int} index if the node is found, -1 if not
13233  *  @memberof DataTable#oApi
13234  */
13235 function _fnNodeToColumnIndex( oSettings, iRow, n )
13236 {
13237  return $.inArray( n, oSettings.aoData[ iRow ].anCells );
13238 }
13239 
13240 
13241 /**
13242  * Get the data for a given cell from the internal cache, taking into account data mapping
13243  *  @param {object} settings dataTables settings object
13244  *  @param {int} rowIdx aoData row id
13245  *  @param {int} colIdx Column index
13246  *  @param {string} type data get type ('display', 'type' 'filter' 'sort')
13247  *  @returns {*} Cell data
13248  *  @memberof DataTable#oApi
13249  */
13250 function _fnGetCellData( settings, rowIdx, colIdx, type )
13251 {
13252  var draw           = settings.iDraw;
13253  var col            = settings.aoColumns[colIdx];
13254  var rowData        = settings.aoData[rowIdx]._aData;
13255  var defaultContent = col.sDefaultContent;
13256  var cellData       = col.fnGetData( rowData, type, {
13257   settings: settings,
13258   row:      rowIdx,
13259   col:      colIdx
13260  } );
13261 
13262  if ( cellData === undefined ) {
13263   if ( settings.iDrawError != draw && defaultContent === null ) {
13264    _fnLog( settings, 0, "Requested unknown parameter "+
13265     (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
13266     " for row "+rowIdx+", column "+colIdx, 4 );
13267    settings.iDrawError = draw;
13268   }
13269   return defaultContent;
13270  }
13271 
13272  // When the data source is null and a specific data type is requested (i.e.
13273  // not the original data), we can use default column data
13274  if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
13275   cellData = defaultContent;
13276  }
13277  else if ( typeof cellData === 'function' ) {
13278   // If the data source is a function, then we run it and use the return,
13279   // executing in the scope of the data object (for instances)
13280   return cellData.call( rowData );
13281  }
13282 
13283  if ( cellData === null && type == 'display' ) {
13284   return '';
13285  }
13286  return cellData;
13287 }
13288 
13289 
13290 /**
13291  * Set the value for a specific cell, into the internal data cache
13292  *  @param {object} settings dataTables settings object
13293  *  @param {int} rowIdx aoData row id
13294  *  @param {int} colIdx Column index
13295  *  @param {*} val Value to set
13296  *  @memberof DataTable#oApi
13297  */
13298 function _fnSetCellData( settings, rowIdx, colIdx, val )
13299 {
13300  var col     = settings.aoColumns[colIdx];
13301  var rowData = settings.aoData[rowIdx]._aData;
13302 
13303  col.fnSetData( rowData, val, {
13304   settings: settings,
13305   row:      rowIdx,
13306   col:      colIdx
13307  }  );
13308 }
13309 
13310 
13311 // Private variable that is used to match action syntax in the data property object
13312 var __reArray = /\[.*?\]$/;
13313 var __reFn = /\(\)$/;
13314 
13315 /**
13316  * Split string on periods, taking into account escaped periods
13317  * @param  {string} str String to split
13318  * @return {array} Split string
13319  */
13320 function _fnSplitObjNotation( str )
13321 {
13322  return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
13323   return s.replace(/\\./g, '.');
13324  } );
13325 }
13326 
13327 
13328 /**
13329  * Return a function that can be used to get data from a source object, taking
13330  * into account the ability to use nested objects as a source
13331  *  @param {string|int|function} mSource The data source for the object
13332  *  @returns {function} Data get function
13333  *  @memberof DataTable#oApi
13334  */
13335 function _fnGetObjectDataFn( mSource )
13336 {
13337  if ( $.isPlainObject( mSource ) )
13338  {
13339   /* Build an object of get functions, and wrap them in a single call */
13340   var o = {};
13341   $.each( mSource, function (key, val) {
13342    if ( val ) {
13343     o[key] = _fnGetObjectDataFn( val );
13344    }
13345   } );
13346 
13347   return function (data, type, row, meta) {
13348    var t = o[type] || o._;
13349    return t !== undefined ?
13350     t(data, type, row, meta) :
13351     data;
13352   };
13353  }
13354  else if ( mSource === null )
13355  {
13356   /* Give an empty string for rendering / sorting etc */
13357   return function (data) { // type, row and meta also passed, but not used
13358    return data;
13359   };
13360  }
13361  else if ( typeof mSource === 'function' )
13362  {
13363   return function (data, type, row, meta) {
13364    return mSource( data, type, row, meta );
13365   };
13366  }
13367  else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
13368         mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
13369  {
13370   /* If there is a . in the source string then the data source is in a
13371    * nested object so we loop over the data for each level to get the next
13372    * level down. On each loop we test for undefined, and if found immediately
13373    * return. This allows entire objects to be missing and sDefaultContent to
13374    * be used if defined, rather than throwing an error
13375    */
vendor: 6,769 bytes, lines 13376-13629
13376   var fetchData = function (data, type, src) {
13377    var arrayNotation, funcNotation, out, innerSrc;
13378 
13379    if ( src !== "" )
13380    {
13381     var a = _fnSplitObjNotation( src );
13382 
13383     for ( var i=0, iLen=a.length ; i<iLen ; i++ )
13384     {
13385      // Check if we are dealing with special notation
13386      arrayNotation = a[i].match(__reArray);
13387      funcNotation = a[i].match(__reFn);
13388 
13389      if ( arrayNotation )
13390      {
13391       // Array notation
13392       a[i] = a[i].replace(__reArray, '');
13393 
13394       // Condition allows simply [] to be passed in
13395       if ( a[i] !== "" ) {
13396        data = data[ a[i] ];
13397       }
13398       out = [];
13399 
13400       // Get the remainder of the nested object to get
13401       a.splice( 0, i+1 );
13402       innerSrc = a.join('.');
13403 
13404       // Traverse each entry in the array getting the properties requested
13405       if ( $.isArray( data ) ) {
13406        for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
13407         out.push( fetchData( data[j], type, innerSrc ) );
13408        }
13409       }
13410 
13411       // If a string is given in between the array notation indicators, that
13412       // is used to join the strings together, otherwise an array is returned
13413       var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
13414       data = (join==="") ? out : out.join(join);
13415 
13416       // The inner call to fetchData has already traversed through the remainder
13417       // of the source requested, so we exit from the loop
13418       break;
13419      }
13420      else if ( funcNotation )
13421      {
13422       // Function call
13423       a[i] = a[i].replace(__reFn, '');
13424       data = data[ a[i] ]();
13425       continue;
13426      }
13427 
13428      if ( data === null || data[ a[i] ] === undefined )
13429      {
13430       return undefined;
13431      }
13432      data = data[ a[i] ];
13433     }
13434    }
13435 
13436    return data;
13437   };
13438 
13439   return function (data, type) { // row and meta also passed, but not used
13440    return fetchData( data, type, mSource );
13441   };
13442  }
13443  else
13444  {
13445   /* Array or flat object mapping */
13446   return function (data, type) { // row and meta also passed, but not used
13447    return data[mSource];
13448   };
13449  }
13450 }
13451 
13452 
13453 /**
13454  * Return a function that can be used to set data from a source object, taking
13455  * into account the ability to use nested objects as a source
13456  *  @param {string|int|function} mSource The data source for the object
13457  *  @returns {function} Data set function
13458  *  @memberof DataTable#oApi
13459  */
13460 function _fnSetObjectDataFn( mSource )
13461 {
13462  if ( $.isPlainObject( mSource ) )
13463  {
13464   /* Unlike get, only the underscore (global) option is used for for
13465    * setting data since we don't know the type here. This is why an object
13466    * option is not documented for `mData` (which is read/write), but it is
13467    * for `mRender` which is read only.
13468    */
13469   return _fnSetObjectDataFn( mSource._ );
13470  }
13471  else if ( mSource === null )
13472  {
13473   /* Nothing to do when the data source is null */
13474   return function () {};
13475  }
13476  else if ( typeof mSource === 'function' )
13477  {
13478   return function (data, val, meta) {
13479    mSource( data, 'set', val, meta );
13480   };
13481  }
13482  else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
13483         mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
13484  {
13485   /* Like the get, we need to get data from a nested object */
13486   var setData = function (data, val, src) {
13487    var a = _fnSplitObjNotation( src ), b;
13488    var aLast = a[a.length-1];
13489    var arrayNotation, funcNotation, o, innerSrc;
13490 
13491    for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
13492    {
13493     // Check if we are dealing with an array notation request
13494     arrayNotation = a[i].match(__reArray);
13495     funcNotation = a[i].match(__reFn);
13496 
13497     if ( arrayNotation )
13498     {
13499      a[i] = a[i].replace(__reArray, '');
13500      data[ a[i] ] = [];
13501 
13502      // Get the remainder of the nested object to set so we can recurse
13503      b = a.slice();
13504      b.splice( 0, i+1 );
13505      innerSrc = b.join('.');
13506 
13507      // Traverse each entry in the array setting the properties requested
13508      if ( $.isArray( val ) )
13509      {
13510       for ( var j=0, jLen=val.length ; j<jLen ; j++ )
13511       {
13512        o = {};
13513        setData( o, val[j], innerSrc );
13514        data[ a[i] ].push( o );
13515       }
13516      }
13517      else
13518      {
13519       // We've been asked to save data to an array, but it
13520       // isn't array data to be saved. Best that can be done
13521       // is to just save the value.
13522       data[ a[i] ] = val;
13523      }
13524 
13525      // The inner call to setData has already traversed through the remainder
13526      // of the source and has set the data, thus we can exit here
13527      return;
13528     }
13529     else if ( funcNotation )
13530     {
13531      // Function call
13532      a[i] = a[i].replace(__reFn, '');
13533      data = data[ a[i] ]( val );
13534     }
13535 
13536     // If the nested object doesn't currently exist - since we are
13537     // trying to set the value - create it
13538     if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
13539     {
13540      data[ a[i] ] = {};
13541     }
13542     data = data[ a[i] ];
13543    }
13544 
13545    // Last item in the input - i.e, the actual set
13546    if ( aLast.match(__reFn ) )
13547    {
13548     // Function call
13549     data = data[ aLast.replace(__reFn, '') ]( val );
13550    }
13551    else
13552    {
13553     // If array notation is used, we just want to strip it and use the property name
13554     // and assign the value. If it isn't used, then we get the result we want anyway
13555     data[ aLast.replace(__reArray, '') ] = val;
13556    }
13557   };
13558 
13559   return function (data, val) { // meta is also passed in, but not used
13560    return setData( data, val, mSource );
13561   };
13562  }
13563  else
13564  {
13565   /* Array or flat object mapping */
13566   return function (data, val) { // meta is also passed in, but not used
13567    data[mSource] = val;
13568   };
13569  }
13570 }
13571 
13572 
13573 /**
13574  * Return an array with the full table data
13575  *  @param {object} oSettings dataTables settings object
13576  *  @returns array {array} aData Master data array
13577  *  @memberof DataTable#oApi
13578  */
13579 function _fnGetDataMaster ( settings )
13580 {
13581  return _pluck( settings.aoData, '_aData' );
13582 }
13583 
13584 
13585 /**
13586  * Nuke the table
13587  *  @param {object} oSettings dataTables settings object
13588  *  @memberof DataTable#oApi
13589  */
13590 function _fnClearTable( settings )
13591 {
13592  settings.aoData.length = 0;
13593  settings.aiDisplayMaster.length = 0;
13594  settings.aiDisplay.length = 0;
13595  settings.aIds = {};
13596 }
13597 
13598 
13599  /**
13600  * Take an array of integers (index array) and remove a target integer (value - not
13601  * the key!)
13602  *  @param {array} a Index array to target
13603  *  @param {int} iTarget value to find
13604  *  @memberof DataTable#oApi
13605  */
13606 function _fnDeleteIndex( a, iTarget, splice )
13607 {
13608  var iTargetIndex = -1;
13609 
13610  for ( var i=0, iLen=a.length ; i<iLen ; i++ )
13611  {
13612   if ( a[i] == iTarget )
13613   {
13614    iTargetIndex = i;
13615   }
13616   else if ( a[i] > iTarget )
13617   {
13618    a[i]--;
13619   }
13620  }
13621 
13622  if ( iTargetIndex != -1 && splice === undefined )
13623  {
13624   a.splice( iTargetIndex, 1 );
13625  }
13626 }
13627 
13628 
13629 /**
13630  * Mark cached data as invalid such that a re-read of the data will occur when
13631  * the cached data is next requested. Also update from the data source object.
13632  *
13633  * @param {object} settings DataTables settings object
13634  * @param {int}    rowIdx   Row index to invalidate
13635  * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
13636  *     or 'data'
13637  * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
13638  *     row will be invalidated
13639  * @memberof DataTable#oApi
13640  *
13641  * @todo For the modularisation of v1.11 this will need to become a callback, so
13642  *   the sort and filter methods can subscribe to it. That will required
13643  *   initialisation options for sorting, which is why it is not already baked in
13644  */
13645 function _fnInvalidate( settings, rowIdx, src, colIdx )
13646 {
13647  var row = settings.aoData[ rowIdx ];
13648  var i, ien;
13649  var cellWrite = function ( cell, col ) {
13650   // This is very frustrating, but in IE if you just write directly
13651   // to innerHTML, and elements that are overwritten are GC'ed,
13652   // even if there is a reference to them elsewhere
13653   while ( cell.childNodes.length ) {
13654    cell.removeChild( cell.firstChild );
13655   }
13656 
13657   cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
13658  };
13659 
13660  // Are we reading last data from DOM or the data object?
13661  if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
13662   // Read the data from the DOM
13663   row._aData = _fnGetRowElements(
13664     settings, row, colIdx, colIdx === undefined ? undefined : row._aData
13665    )
13666    .data;
13667  }
13668  else {
13669   // Reading from data object, update the DOM
13670   var cells = row.anCells;
13671 
13672   if ( cells ) {
13673    if ( colIdx !== undefined ) {
13674     cellWrite( cells[colIdx], colIdx );
13675    }
13676    else {
13677     for ( i=0, ien=cells.length ; i<ien ; i++ ) {
13678      cellWrite( cells[i], i );
13679     }
13680    }
13681   }
13682  }
13683 
13684  // For both row and cell invalidation, the cached data for sorting and
13685  // filtering is nulled out
13686  row._aSortData = null;
13687  row._aFilterData = null;
13688 
13689  // Invalidate the type for a specific column (if given) or all columns since
13690  // the data might have changed
13691  var cols = settings.aoColumns;
13692  if ( colIdx !== undefined ) {
13693   cols[ colIdx ].sType = null;
13694  }
13695  else {
13696   for ( i=0, ien=cols.length ; i<ien ; i++ ) {
13697    cols[i].sType = null;
13698   }
13699 
13700   // Update DataTables special `DT_*` attributes for the row
13701   _fnRowAttributes( settings, row );
13702  }
13703 }
13704 
13705 
13706 /**
13707  * Build a data source object from an HTML row, reading the contents of the
13708  * cells that are in the row.
13709  *
13710  * @param {object} settings DataTables settings object
13711  * @param {node|object} TR element from which to read data or existing row
13712  *   object from which to re-read the data from the cells
13713  * @param {int} [colIdx] Optional column index
13714  * @param {array|object} [d] Data source object. If `colIdx` is given then this
13715  *   parameter should also be given and will be used to write the data into.
13716  *   Only the column in question will be written
13717  * @returns {object} Object with two parameters: `data` the data read, in
13718  *   document order, and `cells` and array of nodes (they can be useful to the
13719  *   caller, so rather than needing a second traversal to get them, just return
13720  *   them from here).
13721  * @memberof DataTable#oApi
13722  */
13723 function _fnGetRowElements( settings, row, colIdx, d )
13724 {
13725  var
13726   tds = [],
13727   td = row.firstChild,
13728   name, col, o, i=0, contents,
13729   columns = settings.aoColumns,
13730   objectRead = settings._rowReadObject;
13731 
13732  // Allow the data object to be passed in, or construct
13733  d = d !== undefined ?
13734   d :
13735   objectRead ?
13736    {} :
13737    [];
13738 
13739  var attr = function ( str, td  ) {
13740   if ( typeof str === 'string' ) {
13741    var idx = str.indexOf('@');
13742 
13743    if ( idx !== -1 ) {
13744     var attr = str.substring( idx+1 );
13745     var setter = _fnSetObjectDataFn( str );
13746     setter( d, td.getAttribute( attr ) );
13747    }
13748   }
13749  };
13750 
13751  // Read data from a cell and store into the data object
13752  var cellProcess = function ( cell ) {
13753   if ( colIdx === undefined || colIdx === i ) {
13754    col = columns[i];
13755    contents = $.trim(cell.innerHTML);
13756 
13757    if ( col && col._bAttrSrc ) {
13758     var setter = _fnSetObjectDataFn( col.mData._ );
13759     setter( d, contents );
13760 
13761     attr( col.mData.sort, cell );
13762     attr( col.mData.type, cell );
13763     attr( col.mData.filter, cell );
13764    }
13765    else {
13766     // Depending on the `data` option for the columns the data can
13767     // be read to either an object or an array.
vendor: 36,444 bytes, lines 13768-15084
13768     if ( objectRead ) {
13769      if ( ! col._setter ) {
13770       // Cache the setter function
13771       col._setter = _fnSetObjectDataFn( col.mData );
13772      }
13773      col._setter( d, contents );
13774     }
13775     else {
13776      d[i] = contents;
13777     }
13778    }
13779   }
13780 
13781   i++;
13782  };
13783 
13784  if ( td ) {
13785   // `tr` element was passed in
13786   while ( td ) {
13787    name = td.nodeName.toUpperCase();
13788 
13789    if ( name == "TD" || name == "TH" ) {
13790     cellProcess( td );
13791     tds.push( td );
13792    }
13793 
13794    td = td.nextSibling;
13795   }
13796  }
13797  else {
13798   // Existing row object passed in
13799   tds = row.anCells;
13800 
13801   for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
13802    cellProcess( tds[j] );
13803   }
13804  }
13805 
13806  // Read the ID from the DOM if present
13807  var rowNode = row.firstChild ? row : row.nTr;
13808 
13809  if ( rowNode ) {
13810   var id = rowNode.getAttribute( 'id' );
13811 
13812   if ( id ) {
13813    _fnSetObjectDataFn( settings.rowId )( d, id );
13814   }
13815  }
13816 
13817  return {
13818   data: d,
13819   cells: tds
13820  };
13821 }
13822 /**
13823  * Create a new TR element (and it's TD children) for a row
13824  *  @param {object} oSettings dataTables settings object
13825  *  @param {int} iRow Row to consider
13826  *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
13827  *    DataTables will create a row automatically
13828  *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
13829  *    if nTr is.
13830  *  @memberof DataTable#oApi
13831  */
13832 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
13833 {
13834  var
13835   row = oSettings.aoData[iRow],
13836   rowData = row._aData,
13837   cells = [],
13838   nTr, nTd, oCol,
13839   i, iLen;
13840 
13841  if ( row.nTr === null )
13842  {
13843   nTr = nTrIn || document.createElement('tr');
13844 
13845   row.nTr = nTr;
13846   row.anCells = cells;
13847 
13848   /* Use a private property on the node to allow reserve mapping from the node
13849    * to the aoData array for fast look up
13850    */
13851   nTr._DT_RowIndex = iRow;
13852 
13853   /* Special parameters can be given by the data source to be used on the row */
13854   _fnRowAttributes( oSettings, row );
13855 
13856   /* Process each column */
13857   for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
13858   {
13859    oCol = oSettings.aoColumns[i];
13860 
13861    nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
13862    nTd._DT_CellIndex = {
13863     row: iRow,
13864     column: i
13865    };
13866    
13867    cells.push( nTd );
13868 
13869    // Need to create the HTML if new, or if a rendering function is defined
13870    if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
13871      (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
13872    ) {
13873     nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
13874    }
13875 
13876    /* Add user defined class */
13877    if ( oCol.sClass )
13878    {
13879     nTd.className += ' '+oCol.sClass;
13880    }
13881 
13882    // Visibility - add or remove as required
13883    if ( oCol.bVisible && ! nTrIn )
13884    {
13885     nTr.appendChild( nTd );
13886    }
13887    else if ( ! oCol.bVisible && nTrIn )
13888    {
13889     nTd.parentNode.removeChild( nTd );
13890    }
13891 
13892    if ( oCol.fnCreatedCell )
13893    {
13894     oCol.fnCreatedCell.call( oSettings.oInstance,
13895      nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
13896     );
13897    }
13898   }
13899 
13900   _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
13901  }
13902 
13903  // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
13904  // and deployed
13905  row.nTr.setAttribute( 'role', 'row' );
13906 }
13907 
13908 
13909 /**
13910  * Add attributes to a row based on the special `DT_*` parameters in a data
13911  * source object.
13912  *  @param {object} settings DataTables settings object
13913  *  @param {object} DataTables row object for the row to be modified
13914  *  @memberof DataTable#oApi
13915  */
13916 function _fnRowAttributes( settings, row )
13917 {
13918  var tr = row.nTr;
13919  var data = row._aData;
13920 
13921  if ( tr ) {
13922   var id = settings.rowIdFn( data );
13923 
13924   if ( id ) {
13925    tr.id = id;
13926   }
13927 
13928   if ( data.DT_RowClass ) {
13929    // Remove any classes added by DT_RowClass before
13930    var a = data.DT_RowClass.split(' ');
13931    row.__rowc = row.__rowc ?
13932     _unique( row.__rowc.concat( a ) ) :
13933     a;
13934 
13935    $(tr)
13936     .removeClass( row.__rowc.join(' ') )
13937     .addClass( data.DT_RowClass );
13938   }
13939 
13940   if ( data.DT_RowAttr ) {
13941    $(tr).attr( data.DT_RowAttr );
13942   }
13943 
13944   if ( data.DT_RowData ) {
13945    $(tr).data( data.DT_RowData );
13946   }
13947  }
13948 }
13949 
13950 
13951 /**
13952  * Create the HTML header for the table
13953  *  @param {object} oSettings dataTables settings object
13954  *  @memberof DataTable#oApi
13955  */
13956 function _fnBuildHead( oSettings )
13957 {
13958  var i, ien, cell, row, column;
13959  var thead = oSettings.nTHead;
13960  var tfoot = oSettings.nTFoot;
13961  var createHeader = $('th, td', thead).length === 0;
13962  var classes = oSettings.oClasses;
13963  var columns = oSettings.aoColumns;
13964 
13965  if ( createHeader ) {
13966   row = $('<tr/>').appendTo( thead );
13967  }
13968 
13969  for ( i=0, ien=columns.length ; i<ien ; i++ ) {
13970   column = columns[i];
13971   cell = $( column.nTh ).addClass( column.sClass );
13972 
13973   if ( createHeader ) {
13974    cell.appendTo( row );
13975   }
13976 
13977   // 1.11 move into sorting
13978   if ( oSettings.oFeatures.bSort ) {
13979    cell.addClass( column.sSortingClass );
13980 
13981    if ( column.bSortable !== false ) {
13982     cell
13983      .attr( 'tabindex', oSettings.iTabIndex )
13984      .attr( 'aria-controls', oSettings.sTableId );
13985 
13986     _fnSortAttachListener( oSettings, column.nTh, i );
13987    }
13988   }
13989 
13990   if ( column.sTitle != cell[0].innerHTML ) {
13991    cell.html( column.sTitle );
13992   }
13993 
13994   _fnRenderer( oSettings, 'header' )(
13995    oSettings, cell, column, classes
13996   );
13997  }
13998 
13999  if ( createHeader ) {
14000   _fnDetectHeader( oSettings.aoHeader, thead );
14001  }
14002  
14003  /* ARIA role for the rows */
14004   $(thead).find('>tr').attr('role', 'row');
14005 
14006  /* Deal with the footer - add classes if required */
14007  $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
14008  $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
14009 
14010  // Cache the footer cells. Note that we only take the cells from the first
14011  // row in the footer. If there is more than one row the user wants to
14012  // interact with, they need to use the table().foot() method. Note also this
14013  // allows cells to be used for multiple columns using colspan
14014  if ( tfoot !== null ) {
14015   var cells = oSettings.aoFooter[0];
14016 
14017   for ( i=0, ien=cells.length ; i<ien ; i++ ) {
14018    column = columns[i];
14019    column.nTf = cells[i].cell;
14020 
14021    if ( column.sClass ) {
14022     $(column.nTf).addClass( column.sClass );
14023    }
14024   }
14025  }
14026 }
14027 
14028 
14029 /**
14030  * Draw the header (or footer) element based on the column visibility states. The
14031  * methodology here is to use the layout array from _fnDetectHeader, modified for
14032  * the instantaneous column visibility, to construct the new layout. The grid is
14033  * traversed over cell at a time in a rows x columns grid fashion, although each
14034  * cell insert can cover multiple elements in the grid - which is tracks using the
14035  * aApplied array. Cell inserts in the grid will only occur where there isn't
14036  * already a cell in that position.
14037  *  @param {object} oSettings dataTables settings object
14038  *  @param array {objects} aoSource Layout array from _fnDetectHeader
14039  *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
14040  *  @memberof DataTable#oApi
14041  */
14042 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
14043 {
14044  var i, iLen, j, jLen, k, kLen, n, nLocalTr;
14045  var aoLocal = [];
14046  var aApplied = [];
14047  var iColumns = oSettings.aoColumns.length;
14048  var iRowspan, iColspan;
14049 
14050  if ( ! aoSource )
14051  {
14052   return;
14053  }
14054 
14055  if (  bIncludeHidden === undefined )
14056  {
14057   bIncludeHidden = false;
14058  }
14059 
14060  /* Make a copy of the master layout array, but without the visible columns in it */
14061  for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
14062  {
14063   aoLocal[i] = aoSource[i].slice();
14064   aoLocal[i].nTr = aoSource[i].nTr;
14065 
14066   /* Remove any columns which are currently hidden */
14067   for ( j=iColumns-1 ; j>=0 ; j-- )
14068   {
14069    if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
14070    {
14071     aoLocal[i].splice( j, 1 );
14072    }
14073   }
14074 
14075   /* Prep the applied array - it needs an element for each row */
14076   aApplied.push( [] );
14077  }
14078 
14079  for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
14080  {
14081   nLocalTr = aoLocal[i].nTr;
14082 
14083   /* All cells are going to be replaced, so empty out the row */
14084   if ( nLocalTr )
14085   {
14086    while( (n = nLocalTr.firstChild) )
14087    {
14088     nLocalTr.removeChild( n );
14089    }
14090   }
14091 
14092   for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
14093   {
14094    iRowspan = 1;
14095    iColspan = 1;
14096 
14097    /* Check to see if there is already a cell (row/colspan) covering our target
14098     * insert point. If there is, then there is nothing to do.
14099     */
14100    if ( aApplied[i][j] === undefined )
14101    {
14102     nLocalTr.appendChild( aoLocal[i][j].cell );
14103     aApplied[i][j] = 1;
14104 
14105     /* Expand the cell to cover as many rows as needed */
14106     while ( aoLocal[i+iRowspan] !== undefined &&
14107             aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
14108     {
14109      aApplied[i+iRowspan][j] = 1;
14110      iRowspan++;
14111     }
14112 
14113     /* Expand the cell to cover as many columns as needed */
14114     while ( aoLocal[i][j+iColspan] !== undefined &&
14115             aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
14116     {
14117      /* Must update the applied array over the rows for the columns */
14118      for ( k=0 ; k<iRowspan ; k++ )
14119      {
14120       aApplied[i+k][j+iColspan] = 1;
14121      }
14122      iColspan++;
14123     }
14124 
14125     /* Do the actual expansion in the DOM */
14126     $(aoLocal[i][j].cell)
14127      .attr('rowspan', iRowspan)
14128      .attr('colspan', iColspan);
14129    }
14130   }
14131  }
14132 }
14133 
14134 
14135 /**
14136  * Insert the required TR nodes into the table for display
14137  *  @param {object} oSettings dataTables settings object
14138  *  @memberof DataTable#oApi
14139  */
14140 function _fnDraw( oSettings )
14141 {
14142  /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
14143  var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
14144  if ( $.inArray( false, aPreDraw ) !== -1 )
14145  {
14146   _fnProcessingDisplay( oSettings, false );
14147   return;
14148  }
14149 
14150  var i, iLen, n;
14151  var anRows = [];
14152  var iRowCount = 0;
14153  var asStripeClasses = oSettings.asStripeClasses;
14154  var iStripes = asStripeClasses.length;
14155  var iOpenRows = oSettings.aoOpenRows.length;
14156  var oLang = oSettings.oLanguage;
14157  var iInitDisplayStart = oSettings.iInitDisplayStart;
14158  var bServerSide = _fnDataSource( oSettings ) == 'ssp';
14159  var aiDisplay = oSettings.aiDisplay;
14160 
14161  oSettings.bDrawing = true;
14162 
14163  /* Check and see if we have an initial draw position from state saving */
14164  if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
14165  {
14166   oSettings._iDisplayStart = bServerSide ?
14167    iInitDisplayStart :
14168    iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
14169     0 :
14170     iInitDisplayStart;
14171 
14172   oSettings.iInitDisplayStart = -1;
14173  }
14174 
14175  var iDisplayStart = oSettings._iDisplayStart;
14176  var iDisplayEnd = oSettings.fnDisplayEnd();
14177 
14178  /* Server-side processing draw intercept */
14179  if ( oSettings.bDeferLoading )
14180  {
14181   oSettings.bDeferLoading = false;
14182   oSettings.iDraw++;
14183   _fnProcessingDisplay( oSettings, false );
14184  }
14185  else if ( !bServerSide )
14186  {
14187   oSettings.iDraw++;
14188  }
14189  else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
14190  {
14191   return;
14192  }
14193 
14194  if ( aiDisplay.length !== 0 )
14195  {
14196   var iStart = bServerSide ? 0 : iDisplayStart;
14197   var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
14198 
14199   for ( var j=iStart ; j<iEnd ; j++ )
14200   {
14201    var iDataIndex = aiDisplay[j];
14202    var aoData = oSettings.aoData[ iDataIndex ];
14203    if ( aoData.nTr === null )
14204    {
14205     _fnCreateTr( oSettings, iDataIndex );
14206    }
14207 
14208    var nRow = aoData.nTr;
14209 
14210    /* Remove the old striping classes and then add the new one */
14211    if ( iStripes !== 0 )
14212    {
14213     var sStripe = asStripeClasses[ iRowCount % iStripes ];
14214     if ( aoData._sRowStripe != sStripe )
14215     {
14216      $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
14217      aoData._sRowStripe = sStripe;
14218     }
14219    }
14220 
14221    // Row callback functions - might want to manipulate the row
14222    // iRowCount and j are not currently documented. Are they at all
14223    // useful?
14224    _fnCallbackFire( oSettings, 'aoRowCallback', null,
14225     [nRow, aoData._aData, iRowCount, j] );
14226 
14227    anRows.push( nRow );
14228    iRowCount++;
14229   }
14230  }
14231  else
14232  {
14233   /* Table is empty - create a row with an empty message in it */
14234   var sZero = oLang.sZeroRecords;
14235   if ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )
14236   {
14237    sZero = oLang.sLoadingRecords;
14238   }
14239   else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
14240   {
14241    sZero = oLang.sEmptyTable;
14242   }
14243 
14244   anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
14245    .append( $('<td />', {
14246     'valign':  'top',
14247     'colSpan': _fnVisbleColumns( oSettings ),
14248     'class':   oSettings.oClasses.sRowEmpty
14249    } ).html( sZero ) )[0];
14250  }
14251 
14252  /* Header and footer callbacks */
14253  _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
14254   _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
14255 
14256  _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
14257   _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
14258 
14259  var body = $(oSettings.nTBody);
14260 
14261  body.children().detach();
14262  body.append( $(anRows) );
14263 
14264  /* Call all required callback functions for the end of a draw */
14265  _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
14266 
14267  /* Draw is complete, sorting and filtering must be as well */
14268  oSettings.bSorted = false;
14269  oSettings.bFiltered = false;
14270  oSettings.bDrawing = false;
14271 }
14272 
14273 
14274 /**
14275  * Redraw the table - taking account of the various features which are enabled
14276  *  @param {object} oSettings dataTables settings object
14277  *  @param {boolean} [holdPosition] Keep the current paging position. By default
14278  *    the paging is reset to the first page
14279  *  @memberof DataTable#oApi
14280  */
14281 function _fnReDraw( settings, holdPosition )
14282 {
14283  var
14284   features = settings.oFeatures,
14285   sort     = features.bSort,
14286   filter   = features.bFilter;
14287 
14288  if ( sort ) {
14289   _fnSort( settings );
14290  }
14291 
14292  if ( filter ) {
14293   _fnFilterComplete( settings, settings.oPreviousSearch );
14294  }
14295  else {
14296   // No filtering, so we want to just use the display master
14297   settings.aiDisplay = settings.aiDisplayMaster.slice();
14298  }
14299 
14300  if ( holdPosition !== true ) {
14301   settings._iDisplayStart = 0;
14302  }
14303 
14304  // Let any modules know about the draw hold position state (used by
14305  // scrolling internally)
14306  settings._drawHold = holdPosition;
14307 
14308  _fnDraw( settings );
14309 
14310  settings._drawHold = false;
14311 }
14312 
14313 
14314 /**
14315  * Add the options to the page HTML for the table
14316  *  @param {object} oSettings dataTables settings object
14317  *  @memberof DataTable#oApi
14318  */
14319 function _fnAddOptionsHtml ( oSettings )
14320 {
14321  var classes = oSettings.oClasses;
14322  var table = $(oSettings.nTable);
14323  var holding = $('<div/>').insertBefore( table ); // Holding element for speed
14324  var features = oSettings.oFeatures;
14325 
14326  // All DataTables are wrapped in a div
14327  var insert = $('<div/>', {
14328   id:      oSettings.sTableId+'_wrapper',
14329   'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
14330  } );
14331 
14332  oSettings.nHolding = holding[0];
14333  oSettings.nTableWrapper = insert[0];
14334  oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
14335 
14336  /* Loop over the user set positioning and place the elements as needed */
14337  var aDom = oSettings.sDom.split('');
14338  var featureNode, cOption, nNewNode, cNext, sAttr, j;
14339  for ( var i=0 ; i<aDom.length ; i++ )
14340  {
14341   featureNode = null;
14342   cOption = aDom[i];
14343 
14344   if ( cOption == '<' )
14345   {
14346    /* New container div */
14347    nNewNode = $('<div/>')[0];
14348 
14349    /* Check to see if we should append an id and/or a class name to the container */
14350    cNext = aDom[i+1];
14351    if ( cNext == "'" || cNext == '"' )
14352    {
14353     sAttr = "";
14354     j = 2;
14355     while ( aDom[i+j] != cNext )
14356     {
14357      sAttr += aDom[i+j];
14358      j++;
14359     }
14360 
14361     /* Replace jQuery UI constants @todo depreciated */
14362     if ( sAttr == "H" )
14363     {
14364      sAttr = classes.sJUIHeader;
14365     }
14366     else if ( sAttr == "F" )
14367     {
14368      sAttr = classes.sJUIFooter;
14369     }
14370 
14371     /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
14372      * breaks the string into parts and applies them as needed
14373      */
14374     if ( sAttr.indexOf('.') != -1 )
14375     {
14376      var aSplit = sAttr.split('.');
14377      nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
14378      nNewNode.className = aSplit[1];
14379     }
14380     else if ( sAttr.charAt(0) == "#" )
14381     {
14382      nNewNode.id = sAttr.substr(1, sAttr.length-1);
14383     }
14384     else
14385     {
14386      nNewNode.className = sAttr;
14387     }
14388 
14389     i += j; /* Move along the position array */
14390    }
14391 
14392    insert.append( nNewNode );
14393    insert = $(nNewNode);
14394   }
14395   else if ( cOption == '>' )
14396   {
14397    /* End container div */
14398    insert = insert.parent();
14399   }
14400   // @todo Move options into their own plugins?
14401   else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
14402   {
14403    /* Length */
14404    featureNode = _fnFeatureHtmlLength( oSettings );
14405   }
14406   else if ( cOption == 'f' && features.bFilter )
14407   {
14408    /* Filter */
14409    featureNode = _fnFeatureHtmlFilter( oSettings );
14410   }
14411   else if ( cOption == 'r' && features.bProcessing )
14412   {
14413    /* pRocessing */
14414    featureNode = _fnFeatureHtmlProcessing( oSettings );
14415   }
14416   else if ( cOption == 't' )
14417   {
14418    /* Table */
14419    featureNode = _fnFeatureHtmlTable( oSettings );
14420   }
14421   else if ( cOption ==  'i' && features.bInfo )
14422   {
14423    /* Info */
14424    featureNode = _fnFeatureHtmlInfo( oSettings );
14425   }
14426   else if ( cOption == 'p' && features.bPaginate )
14427   {
14428    /* Pagination */
14429    featureNode = _fnFeatureHtmlPaginate( oSettings );
14430   }
14431   else if ( DataTable.ext.feature.length !== 0 )
14432   {
14433    /* Plug-in features */
14434    var aoFeatures = DataTable.ext.feature;
14435    for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
14436    {
14437     if ( cOption == aoFeatures[k].cFeature )
14438     {
14439      featureNode = aoFeatures[k].fnInit( oSettings );
14440      break;
14441     }
14442    }
14443   }
14444 
14445   /* Add to the 2D features array */
14446   if ( featureNode )
14447   {
14448    var aanFeatures = oSettings.aanFeatures;
14449 
14450    if ( ! aanFeatures[cOption] )
14451    {
14452     aanFeatures[cOption] = [];
14453    }
14454 
14455    aanFeatures[cOption].push( featureNode );
14456    insert.append( featureNode );
14457   }
14458  }
14459 
14460  /* Built our DOM structure - replace the holding div with what we want */
14461  holding.replaceWith( insert );
14462  oSettings.nHolding = null;
14463 }
14464 
14465 
14466 /**
14467  * Use the DOM source to create up an array of header cells. The idea here is to
14468  * create a layout grid (array) of rows x columns, which contains a reference
14469  * to the cell that that point in the grid (regardless of col/rowspan), such that
14470  * any column / row could be removed and the new grid constructed
14471  *  @param array {object} aLayout Array to store the calculated layout in
14472  *  @param {node} nThead The header/footer element for the table
14473  *  @memberof DataTable#oApi
14474  */
14475 function _fnDetectHeader ( aLayout, nThead )
14476 {
14477  var nTrs = $(nThead).children('tr');
14478  var nTr, nCell;
14479  var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
14480  var bUnique;
14481  var fnShiftCol = function ( a, i, j ) {
14482   var k = a[i];
14483                 while ( k[j] ) {
14484    j++;
14485   }
14486   return j;
14487  };
14488 
14489  aLayout.splice( 0, aLayout.length );
14490 
14491  /* We know how many rows there are in the layout - so prep it */
14492  for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
14493  {
14494   aLayout.push( [] );
14495  }
14496 
14497  /* Calculate a layout array */
14498  for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
14499  {
14500   nTr = nTrs[i];
14501   iColumn = 0;
14502 
14503   /* For every cell in the row... */
14504   nCell = nTr.firstChild;
14505   while ( nCell ) {
14506    if ( nCell.nodeName.toUpperCase() == "TD" ||
14507         nCell.nodeName.toUpperCase() == "TH" )
14508    {
14509     /* Get the col and rowspan attributes from the DOM and sanitise them */
14510     iColspan = nCell.getAttribute('colspan') * 1;
14511     iRowspan = nCell.getAttribute('rowspan') * 1;
14512     iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
14513     iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
14514 
14515     /* There might be colspan cells already in this row, so shift our target
14516      * accordingly
14517      */
14518     iColShifted = fnShiftCol( aLayout, i, iColumn );
14519 
14520     /* Cache calculation for unique columns */
14521     bUnique = iColspan === 1 ? true : false;
14522 
14523     /* If there is col / rowspan, copy the information into the layout grid */
14524     for ( l=0 ; l<iColspan ; l++ )
14525     {
14526      for ( k=0 ; k<iRowspan ; k++ )
14527      {
14528       aLayout[i+k][iColShifted+l] = {
14529        "cell": nCell,
14530        "unique": bUnique
14531       };
14532       aLayout[i+k].nTr = nTr;
14533      }
14534     }
14535    }
14536    nCell = nCell.nextSibling;
14537   }
14538  }
14539 }
14540 
14541 
14542 /**
14543  * Get an array of unique th elements, one for each column
14544  *  @param {object} oSettings dataTables settings object
14545  *  @param {node} nHeader automatically detect the layout from this node - optional
14546  *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
14547  *  @returns array {node} aReturn list of unique th's
14548  *  @memberof DataTable#oApi
14549  */
14550 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
14551 {
14552  var aReturn = [];
14553  if ( !aLayout )
14554  {
14555   aLayout = oSettings.aoHeader;
14556   if ( nHeader )
14557   {
14558    aLayout = [];
14559    _fnDetectHeader( aLayout, nHeader );
14560   }
14561  }
14562 
14563  for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
14564  {
14565   for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
14566   {
14567    if ( aLayout[i][j].unique &&
14568      (!aReturn[j] || !oSettings.bSortCellsTop) )
14569    {
14570     aReturn[j] = aLayout[i][j].cell;
14571    }
14572   }
14573  }
14574 
14575  return aReturn;
14576 }
14577 
14578 /**
14579  * Create an Ajax call based on the table's settings, taking into account that
14580  * parameters can have multiple forms, and backwards compatibility.
14581  *
14582  * @param {object} oSettings dataTables settings object
14583  * @param {array} data Data to send to the server, required by
14584  *     DataTables - may be augmented by developer callbacks
14585  * @param {function} fn Callback function to run when data is obtained
14586  */
14587 function _fnBuildAjax( oSettings, data, fn )
14588 {
14589  // Compatibility with 1.9-, allow fnServerData and event to manipulate
14590  _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
14591 
14592  // Convert to object based for 1.10+ if using the old array scheme which can
14593  // come from server-side processing or serverParams
14594  if ( data && $.isArray(data) ) {
14595   var tmp = {};
14596   var rbracket = /(.*?)\[\]$/;
14597 
14598   $.each( data, function (key, val) {
14599    var match = val.name.match(rbracket);
14600 
14601    if ( match ) {
14602     // Support for arrays
14603     var name = match[0];
14604 
14605     if ( ! tmp[ name ] ) {
14606      tmp[ name ] = [];
14607     }
14608     tmp[ name ].push( val.value );
14609    }
14610    else {
14611     tmp[val.name] = val.value;
14612    }
14613   } );
14614   data = tmp;
14615  }
14616 
14617  var ajaxData;
14618  var ajax = oSettings.ajax;
14619  var instance = oSettings.oInstance;
14620  var callback = function ( json ) {
14621   _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
14622   fn( json );
14623  };
14624 
14625  if ( $.isPlainObject( ajax ) && ajax.data )
14626  {
14627   ajaxData = ajax.data;
14628 
14629   var newData = $.isFunction( ajaxData ) ?
14630    ajaxData( data, oSettings ) :  // fn can manipulate data or return
14631    ajaxData;                      // an object object or array to merge
14632 
14633   // If the function returned something, use that alone
14634   data = $.isFunction( ajaxData ) && newData ?
14635    newData :
14636    $.extend( true, data, newData );
14637 
14638   // Remove the data property as we've resolved it already and don't want
14639   // jQuery to do it again (it is restored at the end of the function)
14640   delete ajax.data;
14641  }
14642 
14643  var baseAjax = {
14644   "data": data,
14645   "success": function (json) {
14646    var error = json.error || json.sError;
14647    if ( error ) {
14648     _fnLog( oSettings, 0, error );
14649    }
14650 
14651    oSettings.json = json;
14652    callback( json );
14653   },
14654   "dataType": "json",
14655   "cache": false,
14656   "type": oSettings.sServerMethod,
14657   "error": function (xhr, error, thrown) {
14658    var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
14659 
14660    if ( $.inArray( true, ret ) === -1 ) {
14661     if ( error == "parsererror" ) {
14662      _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
14663     }
14664     else if ( xhr.readyState === 4 ) {
14665      _fnLog( oSettings, 0, 'Ajax error', 7 );
14666     }
14667    }
14668 
14669    _fnProcessingDisplay( oSettings, false );
14670   }
14671  };
14672 
14673  // Store the data submitted for the API
14674  oSettings.oAjaxData = data;
14675 
14676  // Allow plug-ins and external processes to modify the data
14677  _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
14678 
14679  if ( oSettings.fnServerData )
14680  {
14681   // DataTables 1.9- compatibility
14682   oSettings.fnServerData.call( instance,
14683    oSettings.sAjaxSource,
14684    $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
14685     return { name: key, value: val };
14686    } ),
14687    callback,
14688    oSettings
14689   );
14690  }
14691  else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
14692  {
14693   // DataTables 1.9- compatibility
14694   oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
14695    url: ajax || oSettings.sAjaxSource
14696   } ) );
14697  }
14698  else if ( $.isFunction( ajax ) )
14699  {
14700   // Is a function - let the caller define what needs to be done
14701   oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
14702  }
14703  else
14704  {
14705   // Object to extend the base settings
14706   oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
14707 
14708   // Restore for next time around
14709   ajax.data = ajaxData;
14710  }
14711 }
14712 
14713 
14714 /**
14715  * Update the table using an Ajax call
14716  *  @param {object} settings dataTables settings object
14717  *  @returns {boolean} Block the table drawing or not
14718  *  @memberof DataTable#oApi
14719  */
14720 function _fnAjaxUpdate( settings )
14721 {
14722  if ( settings.bAjaxDataGet ) {
14723   settings.iDraw++;
14724   _fnProcessingDisplay( settings, true );
14725 
14726   _fnBuildAjax(
14727    settings,
14728    _fnAjaxParameters( settings ),
14729    function(json) {
14730     _fnAjaxUpdateDraw( settings, json );
14731    }
14732   );
14733 
14734   return false;
14735  }
14736  return true;
14737 }
14738 
14739 
14740 /**
14741  * Build up the parameters in an object needed for a server-side processing
14742  * request. Note that this is basically done twice, is different ways - a modern
14743  * method which is used by default in DataTables 1.10 which uses objects and
14744  * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
14745  * the sAjaxSource option is used in the initialisation, or the legacyAjax
14746  * option is set.
14747  *  @param {object} oSettings dataTables settings object
14748  *  @returns {bool} block the table drawing or not
14749  *  @memberof DataTable#oApi
14750  */
14751 function _fnAjaxParameters( settings )
14752 {
14753  var
14754   columns = settings.aoColumns,
14755   columnCount = columns.length,
14756   features = settings.oFeatures,
14757   preSearch = settings.oPreviousSearch,
14758   preColSearch = settings.aoPreSearchCols,
14759   i, data = [], dataProp, column, columnSearch,
14760   sort = _fnSortFlatten( settings ),
14761   displayStart = settings._iDisplayStart,
14762   displayLength = features.bPaginate !== false ?
14763    settings._iDisplayLength :
14764    -1;
14765 
14766  var param = function ( name, value ) {
14767   data.push( { 'name': name, 'value': value } );
14768  };
14769 
14770  // DataTables 1.9- compatible method
14771  param( 'sEcho',          settings.iDraw );
14772  param( 'iColumns',       columnCount );
14773  param( 'sColumns',       _pluck( columns, 'sName' ).join(',') );
14774  param( 'iDisplayStart',  displayStart );
14775  param( 'iDisplayLength', displayLength );
14776 
14777  // DataTables 1.10+ method
14778  var d = {
14779   draw:    settings.iDraw,
14780   columns: [],
14781   order:   [],
14782   start:   displayStart,
14783   length:  displayLength,
14784   search:  {
14785    value: preSearch.sSearch,
14786    regex: preSearch.bRegex
14787   }
14788  };
14789 
14790  for ( i=0 ; i<columnCount ; i++ ) {
14791   column = columns[i];
14792   columnSearch = preColSearch[i];
14793   dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
14794 
14795   d.columns.push( {
14796    data:       dataProp,
14797    name:       column.sName,
14798    searchable: column.bSearchable,
14799    orderable:  column.bSortable,
14800    search:     {
14801     value: columnSearch.sSearch,
14802     regex: columnSearch.bRegex
14803    }
14804   } );
14805 
14806   param( "mDataProp_"+i, dataProp );
14807 
14808   if ( features.bFilter ) {
14809    param( 'sSearch_'+i,     columnSearch.sSearch );
14810    param( 'bRegex_'+i,      columnSearch.bRegex );
14811    param( 'bSearchable_'+i, column.bSearchable );
14812   }
14813 
14814   if ( features.bSort ) {
14815    param( 'bSortable_'+i, column.bSortable );
14816   }
14817  }
14818 
14819  if ( features.bFilter ) {
14820   param( 'sSearch', preSearch.sSearch );
14821   param( 'bRegex', preSearch.bRegex );
14822  }
14823 
14824  if ( features.bSort ) {
14825   $.each( sort, function ( i, val ) {
14826    d.order.push( { column: val.col, dir: val.dir } );
14827 
14828    param( 'iSortCol_'+i, val.col );
14829    param( 'sSortDir_'+i, val.dir );
14830   } );
14831 
14832   param( 'iSortingCols', sort.length );
14833  }
14834 
14835  // If the legacy.ajax parameter is null, then we automatically decide which
14836  // form to use, based on sAjaxSource
14837  var legacy = DataTable.ext.legacy.ajax;
14838  if ( legacy === null ) {
14839   return settings.sAjaxSource ? data : d;
14840  }
14841 
14842  // Otherwise, if legacy has been specified then we use that to decide on the
14843  // form
14844  return legacy ? data : d;
14845 }
14846 
14847 
14848 /**
14849  * Data the data from the server (nuking the old) and redraw the table
14850  *  @param {object} oSettings dataTables settings object
14851  *  @param {object} json json data return from the server.
14852  *  @param {string} json.sEcho Tracking flag for DataTables to match requests
14853  *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
14854  *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
14855  *  @param {array} json.aaData The data to display on this page
14856  *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
14857  *  @memberof DataTable#oApi
14858  */
14859 function _fnAjaxUpdateDraw ( settings, json )
14860 {
14861  // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
14862  // Support both
14863  var compat = function ( old, modern ) {
14864   return json[old] !== undefined ? json[old] : json[modern];
14865  };
14866 
14867  var data = _fnAjaxDataSrc( settings, json );
14868  var draw            = compat( 'sEcho',                'draw' );
14869  var recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );
14870  var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
14871 
14872  if ( draw ) {
14873   // Protect against out of sequence returns
14874   if ( draw*1 < settings.iDraw ) {
14875    return;
14876   }
14877   settings.iDraw = draw * 1;
14878  }
14879 
14880  _fnClearTable( settings );
14881  settings._iRecordsTotal   = parseInt(recordsTotal, 10);
14882  settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
14883 
14884  for ( var i=0, ien=data.length ; i<ien ; i++ ) {
14885   _fnAddData( settings, data[i] );
14886  }
14887  settings.aiDisplay = settings.aiDisplayMaster.slice();
14888 
14889  settings.bAjaxDataGet = false;
14890  _fnDraw( settings );
14891 
14892  if ( ! settings._bInitComplete ) {
14893   _fnInitComplete( settings, json );
14894  }
14895 
14896  settings.bAjaxDataGet = true;
14897  _fnProcessingDisplay( settings, false );
14898 }
14899 
14900 
14901 /**
14902  * Get the data from the JSON data source to use for drawing a table. Using
14903  * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
14904  * source object, or from a processing function.
14905  *  @param {object} oSettings dataTables settings object
14906  *  @param  {object} json Data source object / array from the server
14907  *  @return {array} Array of data to use
14908  */
14909 function _fnAjaxDataSrc ( oSettings, json )
14910 {
14911  var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
14912   oSettings.ajax.dataSrc :
14913   oSettings.sAjaxDataProp; // Compatibility with 1.9-.
14914 
14915  // Compatibility with 1.9-. In order to read from aaData, check if the
14916  // default has been changed, if not, check for aaData
14917  if ( dataSrc === 'data' ) {
14918   return json.aaData || json[dataSrc];
14919  }
14920 
14921  return dataSrc !== "" ?
14922   _fnGetObjectDataFn( dataSrc )( json ) :
14923   json;
14924 }
14925 
14926 /**
14927  * Generate the node required for filtering text
14928  *  @returns {node} Filter control element
14929  *  @param {object} oSettings dataTables settings object
14930  *  @memberof DataTable#oApi
14931  */
14932 function _fnFeatureHtmlFilter ( settings )
14933 {
14934  var classes = settings.oClasses;
14935  var tableId = settings.sTableId;
14936  var language = settings.oLanguage;
14937  var previousSearch = settings.oPreviousSearch;
14938  var features = settings.aanFeatures;
14939  var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
14940 
14941  var str = language.sSearch;
14942  str = str.match(/_INPUT_/) ?
14943   str.replace('_INPUT_', input) :
14944   str+input;
14945 
14946  var filter = $('<div/>', {
14947    'id': ! features.f ? tableId+'_filter' : null,
14948    'class': classes.sFilter
14949   } )
14950   .append( $('<label/>' ).append( str ) );
14951 
14952  var searchFn = function() {
14953   /* Update all other filter input elements for the new display */
14954   var n = features.f;
14955   var val = !this.value ? "" : this.value; // mental IE8 fix :-(
14956 
14957   /* Now do the filter */
14958   if ( val != previousSearch.sSearch ) {
14959    _fnFilterComplete( settings, {
14960     "sSearch": val,
14961     "bRegex": previousSearch.bRegex,
14962     "bSmart": previousSearch.bSmart ,
14963     "bCaseInsensitive": previousSearch.bCaseInsensitive
14964    } );
14965 
14966    // Need to redraw, without resorting
14967    settings._iDisplayStart = 0;
14968    _fnDraw( settings );
14969   }
14970  };
14971 
14972  var searchDelay = settings.searchDelay !== null ?
14973   settings.searchDelay :
14974   _fnDataSource( settings ) === 'ssp' ?
14975    400 :
14976    0;
14977 
14978  var jqFilter = $('input', filter)
14979   .val( previousSearch.sSearch )
14980   .attr( 'placeholder', language.sSearchPlaceholder )
14981   .bind(
14982    'keyup.DT search.DT input.DT paste.DT cut.DT',
14983    searchDelay ?
14984     _fnThrottle( searchFn, searchDelay ) :
14985     searchFn
14986   )
14987   .bind( 'keypress.DT', function(e) {
14988    /* Prevent form submission */
14989    if ( e.keyCode == 13 ) {
14990     return false;
14991    }
14992   } )
14993   .attr('aria-controls', tableId);
14994 
14995  // Update the input elements whenever the table is filtered
14996  $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
14997   if ( settings === s ) {
14998    // IE9 throws an 'unknown error' if document.activeElement is used
14999    // inside an iframe or frame...
15000    try {
15001     if ( jqFilter[0] !== document.activeElement ) {
15002      jqFilter.val( previousSearch.sSearch );
15003     }
15004    }
15005    catch ( e ) {}
15006   }
15007  } );
15008 
15009  return filter[0];
15010 }
15011 
15012 
15013 /**
15014  * Filter the table using both the global filter and column based filtering
15015  *  @param {object} oSettings dataTables settings object
15016  *  @param {object} oSearch search information
15017  *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
15018  *  @memberof DataTable#oApi
15019  */
15020 function _fnFilterComplete ( oSettings, oInput, iForce )
15021 {
15022  var oPrevSearch = oSettings.oPreviousSearch;
15023  var aoPrevSearch = oSettings.aoPreSearchCols;
15024  var fnSaveFilter = function ( oFilter ) {
15025   /* Save the filtering values */
15026   oPrevSearch.sSearch = oFilter.sSearch;
15027   oPrevSearch.bRegex = oFilter.bRegex;
15028   oPrevSearch.bSmart = oFilter.bSmart;
15029   oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
15030  };
15031  var fnRegex = function ( o ) {
15032   // Backwards compatibility with the bEscapeRegex option
15033   return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
15034  };
15035 
15036  // Resolve any column types that are unknown due to addition or invalidation
15037  // @todo As per sort - can this be moved into an event handler?
15038  _fnColumnTypes( oSettings );
15039 
15040  /* In server-side processing all filtering is done by the server, so no point hanging around here */
15041  if ( _fnDataSource( oSettings ) != 'ssp' )
15042  {
15043   /* Global filter */
15044   _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
15045   fnSaveFilter( oInput );
15046 
15047   /* Now do the individual column filter */
15048   for ( var i=0 ; i<aoPrevSearch.length ; i++ )
15049   {
15050    _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
15051     aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
15052   }
15053 
15054   /* Custom filtering */
15055   _fnFilterCustom( oSettings );
15056  }
15057  else
15058  {
15059   fnSaveFilter( oInput );
15060  }
15061 
15062  /* Tell the draw function we have been filtering */
15063  oSettings.bFiltered = true;
15064  _fnCallbackFire( oSettings, null, 'search', [oSettings] );
15065 }
15066 
15067 
15068 /**
15069  * Apply custom filtering functions
15070  *  @param {object} oSettings dataTables settings object
15071  *  @memberof DataTable#oApi
15072  */
15073 function _fnFilterCustom( settings )
15074 {
15075  var filters = DataTable.ext.search;
15076  var displayRows = settings.aiDisplay;
15077  var row, rowIdx;
15078 
15079  for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
15080   var rows = [];
15081 
15082   // Loop over each row and see if it should be included
15083   for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
15084    rowIdx = displayRows[ j ];
15085    row = settings.aoData[ rowIdx ];
15086 
15087    if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
15088     rows.push( rowIdx );
15089    }
15090   }
15091 
15092   // So the array reference doesn't break set the results into the
15093   // existing array
15094   displayRows.length = 0;
15095   $.merge( displayRows, rows );
15096  }
15097 }
15098 
15099 
15100 /**
15101  * Filter the table on a per-column basis
15102  *  @param {object} oSettings dataTables settings object
15103  *  @param {string} sInput string to filter on
15104  *  @param {int} iColumn column to filter
15105  *  @param {bool} bRegex treat search string as a regular expression or not
15106  *  @param {bool} bSmart use smart filtering or not
15107  *  @param {bool} bCaseInsensitive Do case insenstive matching or not
15108  *  @memberof DataTable#oApi
15109  */
15110 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
15111 {
15112  if ( searchStr === '' ) {
15113   return;
15114  }
15115 
15116  var data;
15117  var display = settings.aiDisplay;
15118  var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
15119 
15120  for ( var i=display.length-1 ; i>=0 ; i-- ) {
15121   data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
15122 
15123   if ( ! rpSearch.test( data ) ) {
15124    display.splice( i, 1 );
15125   }
15126  }
15127 }
15128 
15129 
15130 /**
15131  * Filter the data table based on user input and draw the table
15132  *  @param {object} settings dataTables settings object
15133  *  @param {string} input string to filter on
15134  *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
15135  *  @param {bool} regex treat as a regular expression or not
15136  *  @param {bool} smart perform smart filtering or not
15137  *  @param {bool} caseInsensitive Do case insenstive matching or not
15138  *  @memberof DataTable#oApi
15139  */
15140 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
15141 {
15142  var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
15143  var prevSearch = settings.oPreviousSearch.sSearch;
15144  var displayMaster = settings.aiDisplayMaster;
15145  var display, invalidated, i;
15146 
15147  // Need to take account of custom filtering functions - always filter
15148  if ( DataTable.ext.search.length !== 0 ) {
15149   force = true;
15150  }
15151 
15152  // Check if any of the rows were invalidated
15153  invalidated = _fnFilterData( settings );
15154 
15155  // If the input is blank - we just want the full data set
15156  if ( input.length <= 0 ) {
15157   settings.aiDisplay = displayMaster.slice();
15158  }
15159  else {
15160   // New search - start from the master array
15161   if ( invalidated ||
15162     force ||
15163     prevSearch.length > input.length ||
15164     input.indexOf(prevSearch) !== 0 ||
15165     settings.bSorted // On resort, the display master needs to be
15166                      // re-filtered since indexes will have changed
15167   ) {
15168    settings.aiDisplay = displayMaster.slice();
15169   }
15170 
15171   // Search the display array
15172   display = settings.aiDisplay;
15173 
15174   for ( i=display.length-1 ; i>=0 ; i-- ) {
15175    if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
15176     display.splice( i, 1 );
15177    }
15178   }
15179  }
15180 }
15181 
15182 
15183 /**
15184  * Build a regular expression object suitable for searching a table
15185  *  @param {string} sSearch string to search for
15186  *  @param {bool} bRegex treat as a regular expression or not
15187  *  @param {bool} bSmart perform smart filtering or not
15188  *  @param {bool} bCaseInsensitive Do case insensitive matching or not
15189  *  @returns {RegExp} constructed object
15190  *  @memberof DataTable#oApi
15191  */
15192 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
15193 {
15194  search = regex ?
15195   search :
15196   _fnEscapeRegex( search );
15197  
15198  if ( smart ) {
15199   /* For smart filtering we want to allow the search to work regardless of
15200    * word order. We also want double quoted text to be preserved, so word
15201    * order is important - a la google. So this is what we want to
15202    * generate:
15203    * 
15204    * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
15205    */
15206   var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
15207    if ( word.charAt(0) === '"' ) {
15208     var m = word.match( /^"(.*)"$/ );
15209     word = m ? m[1] : word;
15210    }
15211 
15212    return word.replace('"', '');
15213   } );
15214 
15215   search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
15216  }
15217 
15218  return new RegExp( search, caseInsensitive ? 'i' : '' );
15219 }
15220 
15221 
15222 /**
15223  * Escape a string such that it can be used in a regular expression
15224  *  @param {string} sVal string to escape
15225  *  @returns {string} escaped string
15226  *  @memberof DataTable#oApi
15227  */
15228 var _fnEscapeRegex = DataTable.util.escapeRegex;
15229 
vendor: 66,580 bytes, lines 15230-17568
15230 var __filter_div = $('<div>')[0];
15231 var __filter_div_textContent = __filter_div.textContent !== undefined;
15232 
15233 // Update the filtering data for each row if needed (by invalidation or first run)
15234 function _fnFilterData ( settings )
15235 {
15236  var columns = settings.aoColumns;
15237  var column;
15238  var i, j, ien, jen, filterData, cellData, row;
15239  var fomatters = DataTable.ext.type.search;
15240  var wasInvalidated = false;
15241 
15242  for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
15243   row = settings.aoData[i];
15244 
15245   if ( ! row._aFilterData ) {
15246    filterData = [];
15247 
15248    for ( j=0, jen=columns.length ; j<jen ; j++ ) {
15249     column = columns[j];
15250 
15251     if ( column.bSearchable ) {
15252      cellData = _fnGetCellData( settings, i, j, 'filter' );
15253 
15254      if ( fomatters[ column.sType ] ) {
15255       cellData = fomatters[ column.sType ]( cellData );
15256      }
15257 
15258      // Search in DataTables 1.10 is string based. In 1.11 this
15259      // should be altered to also allow strict type checking.
15260      if ( cellData === null ) {
15261       cellData = '';
15262      }
15263 
15264      if ( typeof cellData !== 'string' && cellData.toString ) {
15265       cellData = cellData.toString();
15266      }
15267     }
15268     else {
15269      cellData = '';
15270     }
15271 
15272     // If it looks like there is an HTML entity in the string,
15273     // attempt to decode it so sorting works as expected. Note that
15274     // we could use a single line of jQuery to do this, but the DOM
15275     // method used here is much faster http://jsperf.com/html-decode
15276     if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
15277      __filter_div.innerHTML = cellData;
15278      cellData = __filter_div_textContent ?
15279       __filter_div.textContent :
15280       __filter_div.innerText;
15281     }
15282 
15283     if ( cellData.replace ) {
15284      cellData = cellData.replace(/[\r\n]/g, '');
15285     }
15286 
15287     filterData.push( cellData );
15288    }
15289 
15290    row._aFilterData = filterData;
15291    row._sFilterRow = filterData.join('  ');
15292    wasInvalidated = true;
15293   }
15294  }
15295 
15296  return wasInvalidated;
15297 }
15298 
15299 
15300 /**
15301  * Convert from the internal Hungarian notation to camelCase for external
15302  * interaction
15303  *  @param {object} obj Object to convert
15304  *  @returns {object} Inverted object
15305  *  @memberof DataTable#oApi
15306  */
15307 function _fnSearchToCamel ( obj )
15308 {
15309  return {
15310   search:          obj.sSearch,
15311   smart:           obj.bSmart,
15312   regex:           obj.bRegex,
15313   caseInsensitive: obj.bCaseInsensitive
15314  };
15315 }
15316 
15317 
15318 
15319 /**
15320  * Convert from camelCase notation to the internal Hungarian. We could use the
15321  * Hungarian convert function here, but this is cleaner
15322  *  @param {object} obj Object to convert
15323  *  @returns {object} Inverted object
15324  *  @memberof DataTable#oApi
15325  */
15326 function _fnSearchToHung ( obj )
15327 {
15328  return {
15329   sSearch:          obj.search,
15330   bSmart:           obj.smart,
15331   bRegex:           obj.regex,
15332   bCaseInsensitive: obj.caseInsensitive
15333  };
15334 }
15335 
15336 /**
15337  * Generate the node required for the info display
15338  *  @param {object} oSettings dataTables settings object
15339  *  @returns {node} Information element
15340  *  @memberof DataTable#oApi
15341  */
15342 function _fnFeatureHtmlInfo ( settings )
15343 {
15344  var
15345   tid = settings.sTableId,
15346   nodes = settings.aanFeatures.i,
15347   n = $('<div/>', {
15348    'class': settings.oClasses.sInfo,
15349    'id': ! nodes ? tid+'_info' : null
15350   } );
15351 
15352  if ( ! nodes ) {
15353   // Update display on each draw
15354   settings.aoDrawCallback.push( {
15355    "fn": _fnUpdateInfo,
15356    "sName": "information"
15357   } );
15358 
15359   n
15360    .attr( 'role', 'status' )
15361    .attr( 'aria-live', 'polite' );
15362 
15363   // Table is described by our info div
15364   $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
15365  }
15366 
15367  return n[0];
15368 }
15369 
15370 
15371 /**
15372  * Update the information elements in the display
15373  *  @param {object} settings dataTables settings object
15374  *  @memberof DataTable#oApi
15375  */
15376 function _fnUpdateInfo ( settings )
15377 {
15378  /* Show information about the table */
15379  var nodes = settings.aanFeatures.i;
15380  if ( nodes.length === 0 ) {
15381   return;
15382  }
15383 
15384  var
15385   lang  = settings.oLanguage,
15386   start = settings._iDisplayStart+1,
15387   end   = settings.fnDisplayEnd(),
15388   max   = settings.fnRecordsTotal(),
15389   total = settings.fnRecordsDisplay(),
15390   out   = total ?
15391    lang.sInfo :
15392    lang.sInfoEmpty;
15393 
15394  if ( total !== max ) {
15395   /* Record set after filtering */
15396   out += ' ' + lang.sInfoFiltered;
15397  }
15398 
15399  // Convert the macros
15400  out += lang.sInfoPostFix;
15401  out = _fnInfoMacros( settings, out );
15402 
15403  var callback = lang.fnInfoCallback;
15404  if ( callback !== null ) {
15405   out = callback.call( settings.oInstance,
15406    settings, start, end, max, total, out
15407   );
15408  }
15409 
15410  $(nodes).html( out );
15411 }
15412 
15413 
15414 function _fnInfoMacros ( settings, str )
15415 {
15416  // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
15417  // internally
15418  var
15419   formatter  = settings.fnFormatNumber,
15420   start      = settings._iDisplayStart+1,
15421   len        = settings._iDisplayLength,
15422   vis        = settings.fnRecordsDisplay(),
15423   all        = len === -1;
15424 
15425  return str.
15426   replace(/_START_/g, formatter.call( settings, start ) ).
15427   replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
15428   replace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).
15429   replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
15430   replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
15431   replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
15432 }
15433 
15434 
15435 
15436 /**
15437  * Draw the table for the first time, adding all required features
15438  *  @param {object} settings dataTables settings object
15439  *  @memberof DataTable#oApi
15440  */
15441 function _fnInitialise ( settings )
15442 {
15443  var i, iLen, iAjaxStart=settings.iInitDisplayStart;
15444  var columns = settings.aoColumns, column;
15445  var features = settings.oFeatures;
15446  var deferLoading = settings.bDeferLoading; // value modified by the draw
15447 
15448  /* Ensure that the table data is fully initialised */
15449  if ( ! settings.bInitialised ) {
15450   setTimeout( function(){ _fnInitialise( settings ); }, 200 );
15451   return;
15452  }
15453 
15454  /* Show the display HTML options */
15455  _fnAddOptionsHtml( settings );
15456 
15457  /* Build and draw the header / footer for the table */
15458  _fnBuildHead( settings );
15459  _fnDrawHead( settings, settings.aoHeader );
15460  _fnDrawHead( settings, settings.aoFooter );
15461 
15462  /* Okay to show that something is going on now */
15463  _fnProcessingDisplay( settings, true );
15464 
15465  /* Calculate sizes for columns */
15466  if ( features.bAutoWidth ) {
15467   _fnCalculateColumnWidths( settings );
15468  }
15469 
15470  for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
15471   column = columns[i];
15472 
15473   if ( column.sWidth ) {
15474    column.nTh.style.width = _fnStringToCss( column.sWidth );
15475   }
15476  }
15477 
15478  _fnCallbackFire( settings, null, 'preInit', [settings] );
15479 
15480  // If there is default sorting required - let's do it. The sort function
15481  // will do the drawing for us. Otherwise we draw the table regardless of the
15482  // Ajax source - this allows the table to look initialised for Ajax sourcing
15483  // data (show 'loading' message possibly)
15484  _fnReDraw( settings );
15485 
15486  // Server-side processing init complete is done by _fnAjaxUpdateDraw
15487  var dataSrc = _fnDataSource( settings );
15488  if ( dataSrc != 'ssp' || deferLoading ) {
15489   // if there is an ajax source load the data
15490   if ( dataSrc == 'ajax' ) {
15491    _fnBuildAjax( settings, [], function(json) {
15492     var aData = _fnAjaxDataSrc( settings, json );
15493 
15494     // Got the data - add it to the table
15495     for ( i=0 ; i<aData.length ; i++ ) {
15496      _fnAddData( settings, aData[i] );
15497     }
15498 
15499     // Reset the init display for cookie saving. We've already done
15500     // a filter, and therefore cleared it before. So we need to make
15501     // it appear 'fresh'
15502     settings.iInitDisplayStart = iAjaxStart;
15503 
15504     _fnReDraw( settings );
15505 
15506     _fnProcessingDisplay( settings, false );
15507     _fnInitComplete( settings, json );
15508    }, settings );
15509   }
15510   else {
15511    _fnProcessingDisplay( settings, false );
15512    _fnInitComplete( settings );
15513   }
15514  }
15515 }
15516 
15517 
15518 /**
15519  * Draw the table for the first time, adding all required features
15520  *  @param {object} oSettings dataTables settings object
15521  *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
15522  *    with client-side processing (optional)
15523  *  @memberof DataTable#oApi
15524  */
15525 function _fnInitComplete ( settings, json )
15526 {
15527  settings._bInitComplete = true;
15528 
15529  // When data was added after the initialisation (data or Ajax) we need to
15530  // calculate the column sizing
15531  if ( json || settings.oInit.aaData ) {
15532   _fnAdjustColumnSizing( settings );
15533  }
15534 
15535  _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
15536  _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
15537 }
15538 
15539 
15540 function _fnLengthChange ( settings, val )
15541 {
15542  var len = parseInt( val, 10 );
15543  settings._iDisplayLength = len;
15544 
15545  _fnLengthOverflow( settings );
15546 
15547  // Fire length change event
15548  _fnCallbackFire( settings, null, 'length', [settings, len] );
15549 }
15550 
15551 
15552 /**
15553  * Generate the node required for user display length changing
15554  *  @param {object} settings dataTables settings object
15555  *  @returns {node} Display length feature node
15556  *  @memberof DataTable#oApi
15557  */
15558 function _fnFeatureHtmlLength ( settings )
15559 {
15560  var
15561   classes  = settings.oClasses,
15562   tableId  = settings.sTableId,
15563   menu     = settings.aLengthMenu,
15564   d2       = $.isArray( menu[0] ),
15565   lengths  = d2 ? menu[0] : menu,
15566   language = d2 ? menu[1] : menu;
15567 
15568  var select = $('<select/>', {
15569   'name':          tableId+'_length',
15570   'aria-controls': tableId,
15571   'class':         classes.sLengthSelect
15572  } );
15573 
15574  for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
15575   select[0][ i ] = new Option( language[i], lengths[i] );
15576  }
15577 
15578  var div = $('<div><label/></div>').addClass( classes.sLength );
15579  if ( ! settings.aanFeatures.l ) {
15580   div[0].id = tableId+'_length';
15581  }
15582 
15583  div.children().append(
15584   settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
15585  );
15586 
15587  // Can't use `select` variable as user might provide their own and the
15588  // reference is broken by the use of outerHTML
15589  $('select', div)
15590   .val( settings._iDisplayLength )
15591   .bind( 'change.DT', function(e) {
15592    _fnLengthChange( settings, $(this).val() );
15593    _fnDraw( settings );
15594   } );
15595 
15596  // Update node value whenever anything changes the table's length
15597  $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
15598   if ( settings === s ) {
15599    $('select', div).val( len );
15600   }
15601  } );
15602 
15603  return div[0];
15604 }
15605 
15606 
15607 
15608 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15609  * Note that most of the paging logic is done in
15610  * DataTable.ext.pager
15611  */
15612 
15613 /**
15614  * Generate the node required for default pagination
15615  *  @param {object} oSettings dataTables settings object
15616  *  @returns {node} Pagination feature node
15617  *  @memberof DataTable#oApi
15618  */
15619 function _fnFeatureHtmlPaginate ( settings )
15620 {
15621  var
15622   type   = settings.sPaginationType,
15623   plugin = DataTable.ext.pager[ type ],
15624   modern = typeof plugin === 'function',
15625   redraw = function( settings ) {
15626    _fnDraw( settings );
15627   },
15628   node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
15629   features = settings.aanFeatures;
15630 
15631  if ( ! modern ) {
15632   plugin.fnInit( settings, node, redraw );
15633  }
15634 
15635  /* Add a draw callback for the pagination on first instance, to update the paging display */
15636  if ( ! features.p )
15637  {
15638   node.id = settings.sTableId+'_paginate';
15639 
15640   settings.aoDrawCallback.push( {
15641    "fn": function( settings ) {
15642     if ( modern ) {
15643      var
15644       start      = settings._iDisplayStart,
15645       len        = settings._iDisplayLength,
15646       visRecords = settings.fnRecordsDisplay(),
15647       all        = len === -1,
15648       page = all ? 0 : Math.ceil( start / len ),
15649       pages = all ? 1 : Math.ceil( visRecords / len ),
15650       buttons = plugin(page, pages),
15651       i, ien;
15652 
15653      for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
15654       _fnRenderer( settings, 'pageButton' )(
15655        settings, features.p[i], i, buttons, page, pages
15656       );
15657      }
15658     }
15659     else {
15660      plugin.fnUpdate( settings, redraw );
15661     }
15662    },
15663    "sName": "pagination"
15664   } );
15665  }
15666 
15667  return node;
15668 }
15669 
15670 
15671 /**
15672  * Alter the display settings to change the page
15673  *  @param {object} settings DataTables settings object
15674  *  @param {string|int} action Paging action to take: "first", "previous",
15675  *    "next" or "last" or page number to jump to (integer)
15676  *  @param [bool] redraw Automatically draw the update or not
15677  *  @returns {bool} true page has changed, false - no change
15678  *  @memberof DataTable#oApi
15679  */
15680 function _fnPageChange ( settings, action, redraw )
15681 {
15682  var
15683   start     = settings._iDisplayStart,
15684   len       = settings._iDisplayLength,
15685   records   = settings.fnRecordsDisplay();
15686 
15687  if ( records === 0 || len === -1 )
15688  {
15689   start = 0;
15690  }
15691  else if ( typeof action === "number" )
15692  {
15693   start = action * len;
15694 
15695   if ( start > records )
15696   {
15697    start = 0;
15698   }
15699  }
15700  else if ( action == "first" )
15701  {
15702   start = 0;
15703  }
15704  else if ( action == "previous" )
15705  {
15706   start = len >= 0 ?
15707    start - len :
15708    0;
15709 
15710   if ( start < 0 )
15711   {
15712     start = 0;
15713   }
15714  }
15715  else if ( action == "next" )
15716  {
15717   if ( start + len < records )
15718   {
15719    start += len;
15720   }
15721  }
15722  else if ( action == "last" )
15723  {
15724   start = Math.floor( (records-1) / len) * len;
15725  }
15726  else
15727  {
15728   _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
15729  }
15730 
15731  var changed = settings._iDisplayStart !== start;
15732  settings._iDisplayStart = start;
15733 
15734  if ( changed ) {
15735   _fnCallbackFire( settings, null, 'page', [settings] );
15736 
15737   if ( redraw ) {
15738    _fnDraw( settings );
15739   }
15740  }
15741 
15742  return changed;
15743 }
15744 
15745 
15746 
15747 /**
15748  * Generate the node required for the processing node
15749  *  @param {object} settings dataTables settings object
15750  *  @returns {node} Processing element
15751  *  @memberof DataTable#oApi
15752  */
15753 function _fnFeatureHtmlProcessing ( settings )
15754 {
15755  return $('<div/>', {
15756    'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
15757    'class': settings.oClasses.sProcessing
15758   } )
15759   .html( settings.oLanguage.sProcessing )
15760   .insertBefore( settings.nTable )[0];
15761 }
15762 
15763 
15764 /**
15765  * Display or hide the processing indicator
15766  *  @param {object} settings dataTables settings object
15767  *  @param {bool} show Show the processing indicator (true) or not (false)
15768  *  @memberof DataTable#oApi
15769  */
15770 function _fnProcessingDisplay ( settings, show )
15771 {
15772  if ( settings.oFeatures.bProcessing ) {
15773   $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
15774  }
15775 
15776  _fnCallbackFire( settings, null, 'processing', [settings, show] );
15777 }
15778 
15779 /**
15780  * Add any control elements for the table - specifically scrolling
15781  *  @param {object} settings dataTables settings object
15782  *  @returns {node} Node to add to the DOM
15783  *  @memberof DataTable#oApi
15784  */
15785 function _fnFeatureHtmlTable ( settings )
15786 {
15787  var table = $(settings.nTable);
15788 
15789  // Add the ARIA grid role to the table
15790  table.attr( 'role', 'grid' );
15791 
15792  // Scrolling from here on in
15793  var scroll = settings.oScroll;
15794 
15795  if ( scroll.sX === '' && scroll.sY === '' ) {
15796   return settings.nTable;
15797  }
15798 
15799  var scrollX = scroll.sX;
15800  var scrollY = scroll.sY;
15801  var classes = settings.oClasses;
15802  var caption = table.children('caption');
15803  var captionSide = caption.length ? caption[0]._captionSide : null;
15804  var headerClone = $( table[0].cloneNode(false) );
15805  var footerClone = $( table[0].cloneNode(false) );
15806  var footer = table.children('tfoot');
15807  var _div = '<div/>';
15808  var size = function ( s ) {
15809   return !s ? null : _fnStringToCss( s );
15810  };
15811 
15812  if ( ! footer.length ) {
15813   footer = null;
15814  }
15815 
15816  /*
15817   * The HTML structure that we want to generate in this function is:
15818   *  div - scroller
15819   *    div - scroll head
15820   *      div - scroll head inner
15821   *        table - scroll head table
15822   *          thead - thead
15823   *    div - scroll body
15824   *      table - table (master table)
15825   *        thead - thead clone for sizing
15826   *        tbody - tbody
15827   *    div - scroll foot
15828   *      div - scroll foot inner
15829   *        table - scroll foot table
15830   *          tfoot - tfoot
15831   */
15832  var scroller = $( _div, { 'class': classes.sScrollWrapper } )
15833   .append(
15834    $(_div, { 'class': classes.sScrollHead } )
15835     .css( {
15836      overflow: 'hidden',
15837      position: 'relative',
15838      border: 0,
15839      width: scrollX ? size(scrollX) : '100%'
15840     } )
15841     .append(
15842      $(_div, { 'class': classes.sScrollHeadInner } )
15843       .css( {
15844        'box-sizing': 'content-box',
15845        width: scroll.sXInner || '100%'
15846       } )
15847       .append(
15848        headerClone
15849         .removeAttr('id')
15850         .css( 'margin-left', 0 )
15851         .append( captionSide === 'top' ? caption : null )
15852         .append(
15853          table.children('thead')
15854         )
15855       )
15856     )
15857   )
15858   .append(
15859    $(_div, { 'class': classes.sScrollBody } )
15860     .css( {
15861      position: 'relative',
15862      overflow: 'auto',
15863      width: size( scrollX )
15864     } )
15865     .append( table )
15866   );
15867 
15868  if ( footer ) {
15869   scroller.append(
15870    $(_div, { 'class': classes.sScrollFoot } )
15871     .css( {
15872      overflow: 'hidden',
15873      border: 0,
15874      width: scrollX ? size(scrollX) : '100%'
15875     } )
15876     .append(
15877      $(_div, { 'class': classes.sScrollFootInner } )
15878       .append(
15879        footerClone
15880         .removeAttr('id')
15881         .css( 'margin-left', 0 )
15882         .append( captionSide === 'bottom' ? caption : null )
15883         .append(
15884          table.children('tfoot')
15885         )
15886       )
15887     )
15888   );
15889  }
15890 
15891  var children = scroller.children();
15892  var scrollHead = children[0];
15893  var scrollBody = children[1];
15894  var scrollFoot = footer ? children[2] : null;
15895 
15896  // When the body is scrolled, then we also want to scroll the headers
15897  if ( scrollX ) {
15898   $(scrollBody).on( 'scroll.DT', function (e) {
15899    var scrollLeft = this.scrollLeft;
15900 
15901    scrollHead.scrollLeft = scrollLeft;
15902 
15903    if ( footer ) {
15904     scrollFoot.scrollLeft = scrollLeft;
15905    }
15906   } );
15907  }
15908 
15909  $(scrollBody).css(
15910   scrollY && scroll.bCollapse ? 'max-height' : 'height', 
15911   scrollY
15912  );
15913 
15914  settings.nScrollHead = scrollHead;
15915  settings.nScrollBody = scrollBody;
15916  settings.nScrollFoot = scrollFoot;
15917 
15918  // On redraw - align columns
15919  settings.aoDrawCallback.push( {
15920   "fn": _fnScrollDraw,
15921   "sName": "scrolling"
15922  } );
15923 
15924  return scroller[0];
15925 }
15926 
15927 
15928 
15929 /**
15930  * Update the header, footer and body tables for resizing - i.e. column
15931  * alignment.
15932  *
15933  * Welcome to the most horrible function DataTables. The process that this
15934  * function follows is basically:
15935  *   1. Re-create the table inside the scrolling div
15936  *   2. Take live measurements from the DOM
15937  *   3. Apply the measurements to align the columns
15938  *   4. Clean up
15939  *
15940  *  @param {object} settings dataTables settings object
15941  *  @memberof DataTable#oApi
15942  */
15943 function _fnScrollDraw ( settings )
15944 {
15945  // Given that this is such a monster function, a lot of variables are use
15946  // to try and keep the minimised size as small as possible
15947  var
15948   scroll         = settings.oScroll,
15949   scrollX        = scroll.sX,
15950   scrollXInner   = scroll.sXInner,
15951   scrollY        = scroll.sY,
15952   barWidth       = scroll.iBarWidth,
15953   divHeader      = $(settings.nScrollHead),
15954   divHeaderStyle = divHeader[0].style,
15955   divHeaderInner = divHeader.children('div'),
15956   divHeaderInnerStyle = divHeaderInner[0].style,
15957   divHeaderTable = divHeaderInner.children('table'),
15958   divBodyEl      = settings.nScrollBody,
15959   divBody        = $(divBodyEl),
15960   divBodyStyle   = divBodyEl.style,
15961   divFooter      = $(settings.nScrollFoot),
15962   divFooterInner = divFooter.children('div'),
15963   divFooterTable = divFooterInner.children('table'),
15964   header         = $(settings.nTHead),
15965   table          = $(settings.nTable),
15966   tableEl        = table[0],
15967   tableStyle     = tableEl.style,
15968   footer         = settings.nTFoot ? $(settings.nTFoot) : null,
15969   browser        = settings.oBrowser,
15970   ie67           = browser.bScrollOversize,
15971   dtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),
15972   headerTrgEls, footerTrgEls,
15973   headerSrcEls, footerSrcEls,
15974   headerCopy, footerCopy,
15975   headerWidths=[], footerWidths=[],
15976   headerContent=[], footerContent=[],
15977   idx, correction, sanityWidth,
15978   zeroOut = function(nSizer) {
15979    var style = nSizer.style;
15980    style.paddingTop = "0";
15981    style.paddingBottom = "0";
15982    style.borderTopWidth = "0";
15983    style.borderBottomWidth = "0";
15984    style.height = 0;
15985   };
15986 
15987  // If the scrollbar visibility has changed from the last draw, we need to
15988  // adjust the column sizes as the table width will have changed to account
15989  // for the scrollbar
15990  var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
15991  
15992  if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
15993   settings.scrollBarVis = scrollBarVis;
15994   _fnAdjustColumnSizing( settings );
15995   return; // adjust column sizing will call this function again
15996  }
15997  else {
15998   settings.scrollBarVis = scrollBarVis;
15999  }
16000 
16001  /*
16002   * 1. Re-create the table inside the scrolling div
16003   */
16004 
16005  // Remove the old minimised thead and tfoot elements in the inner table
16006  table.children('thead, tfoot').remove();
16007 
16008  if ( footer ) {
16009   footerCopy = footer.clone().prependTo( table );
16010   footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
16011   footerSrcEls = footerCopy.find('tr');
16012  }
16013 
16014  // Clone the current header and footer elements and then place it into the inner table
16015  headerCopy = header.clone().prependTo( table );
16016  headerTrgEls = header.find('tr'); // original header is in its own table
16017  headerSrcEls = headerCopy.find('tr');
16018  headerCopy.find('th, td').removeAttr('tabindex');
16019 
16020 
16021  /*
16022   * 2. Take live measurements from the DOM - do not alter the DOM itself!
16023   */
16024 
16025  // Remove old sizing and apply the calculated column widths
16026  // Get the unique column headers in the newly created (cloned) header. We want to apply the
16027  // calculated sizes to this header
16028  if ( ! scrollX )
16029  {
16030   divBodyStyle.width = '100%';
16031   divHeader[0].style.width = '100%';
16032  }
16033 
16034  $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
16035   idx = _fnVisibleToColumnIndex( settings, i );
16036   el.style.width = settings.aoColumns[idx].sWidth;
16037  } );
16038 
16039  if ( footer ) {
16040   _fnApplyToChildren( function(n) {
16041    n.style.width = "";
16042   }, footerSrcEls );
16043  }
16044 
16045  // Size the table as a whole
16046  sanityWidth = table.outerWidth();
16047  if ( scrollX === "" ) {
16048   // No x scrolling
16049   tableStyle.width = "100%";
16050 
16051   // IE7 will make the width of the table when 100% include the scrollbar
16052   // - which is shouldn't. When there is a scrollbar we need to take this
16053   // into account.
16054   if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
16055    divBody.css('overflow-y') == "scroll")
16056   ) {
16057    tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
16058   }
16059 
16060   // Recalculate the sanity width
16061   sanityWidth = table.outerWidth();
16062  }
16063  else if ( scrollXInner !== "" ) {
16064   // legacy x scroll inner has been given - use it
16065   tableStyle.width = _fnStringToCss(scrollXInner);
16066 
16067   // Recalculate the sanity width
16068   sanityWidth = table.outerWidth();
16069  }
16070 
16071  // Hidden header should have zero height, so remove padding and borders. Then
16072  // set the width based on the real headers
16073 
16074  // Apply all styles in one pass
16075  _fnApplyToChildren( zeroOut, headerSrcEls );
16076 
16077  // Read all widths in next pass
16078  _fnApplyToChildren( function(nSizer) {
16079   headerContent.push( nSizer.innerHTML );
16080   headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
16081  }, headerSrcEls );
16082 
16083  // Apply all widths in final pass
16084  _fnApplyToChildren( function(nToSize, i) {
16085   // Only apply widths to the DataTables detected header cells - this
16086   // prevents complex headers from having contradictory sizes applied
16087   if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
16088    nToSize.style.width = headerWidths[i];
16089   }
16090  }, headerTrgEls );
16091 
16092  $(headerSrcEls).height(0);
16093 
16094  /* Same again with the footer if we have one */
16095  if ( footer )
16096  {
16097   _fnApplyToChildren( zeroOut, footerSrcEls );
16098 
16099   _fnApplyToChildren( function(nSizer) {
16100    footerContent.push( nSizer.innerHTML );
16101    footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
16102   }, footerSrcEls );
16103 
16104   _fnApplyToChildren( function(nToSize, i) {
16105    nToSize.style.width = footerWidths[i];
16106   }, footerTrgEls );
16107 
16108   $(footerSrcEls).height(0);
16109  }
16110 
16111 
16112  /*
16113   * 3. Apply the measurements
16114   */
16115 
16116  // "Hide" the header and footer that we used for the sizing. We need to keep
16117  // the content of the cell so that the width applied to the header and body
16118  // both match, but we want to hide it completely. We want to also fix their
16119  // width to what they currently are
16120  _fnApplyToChildren( function(nSizer, i) {
16121   nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
16122   nSizer.style.width = headerWidths[i];
16123  }, headerSrcEls );
16124 
16125  if ( footer )
16126  {
16127   _fnApplyToChildren( function(nSizer, i) {
16128    nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
16129    nSizer.style.width = footerWidths[i];
16130   }, footerSrcEls );
16131  }
16132 
16133  // Sanity check that the table is of a sensible width. If not then we are going to get
16134  // misalignment - try to prevent this by not allowing the table to shrink below its min width
16135  if ( table.outerWidth() < sanityWidth )
16136  {
16137   // The min width depends upon if we have a vertical scrollbar visible or not */
16138   correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
16139    divBody.css('overflow-y') == "scroll")) ?
16140     sanityWidth+barWidth :
16141     sanityWidth;
16142 
16143   // IE6/7 are a law unto themselves...
16144   if ( ie67 && (divBodyEl.scrollHeight >
16145    divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
16146   ) {
16147    tableStyle.width = _fnStringToCss( correction-barWidth );
16148   }
16149 
16150   // And give the user a warning that we've stopped the table getting too small
16151   if ( scrollX === "" || scrollXInner !== "" ) {
16152    _fnLog( settings, 1, 'Possible column misalignment', 6 );
16153   }
16154  }
16155  else
16156  {
16157   correction = '100%';
16158  }
16159 
16160  // Apply to the container elements
16161  divBodyStyle.width = _fnStringToCss( correction );
16162  divHeaderStyle.width = _fnStringToCss( correction );
16163 
16164  if ( footer ) {
16165   settings.nScrollFoot.style.width = _fnStringToCss( correction );
16166  }
16167 
16168 
16169  /*
16170   * 4. Clean up
16171   */
16172  if ( ! scrollY ) {
16173   /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
16174    * the scrollbar height from the visible display, rather than adding it on. We need to
16175    * set the height in order to sort this. Don't want to do it in any other browsers.
16176    */
16177   if ( ie67 ) {
16178    divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
16179   }
16180  }
16181 
16182  /* Finally set the width's of the header and footer tables */
16183  var iOuterWidth = table.outerWidth();
16184  divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
16185  divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
16186 
16187  // Figure out if there are scrollbar present - if so then we need a the header and footer to
16188  // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
16189  var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
16190  var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
16191  divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
16192 
16193  if ( footer ) {
16194   divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
16195   divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
16196   divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
16197  }
16198 
16199  // Correct DOM ordering for colgroup - comes before the thead
16200  table.children('colgroup').insertBefore( table.children('thead') );
16201 
16202  /* Adjust the position of the header in case we loose the y-scrollbar */
16203  divBody.scroll();
16204 
16205  // If sorting or filtering has occurred, jump the scrolling back to the top
16206  // only if we aren't holding the position
16207  if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
16208   divBodyEl.scrollTop = 0;
16209  }
16210 }
16211 
16212 
16213 
16214 /**
16215  * Apply a given function to the display child nodes of an element array (typically
16216  * TD children of TR rows
16217  *  @param {function} fn Method to apply to the objects
16218  *  @param array {nodes} an1 List of elements to look through for display children
16219  *  @param array {nodes} an2 Another list (identical structure to the first) - optional
16220  *  @memberof DataTable#oApi
16221  */
16222 function _fnApplyToChildren( fn, an1, an2 )
16223 {
16224  var index=0, i=0, iLen=an1.length;
16225  var nNode1, nNode2;
16226 
16227  while ( i < iLen ) {
16228   nNode1 = an1[i].firstChild;
16229   nNode2 = an2 ? an2[i].firstChild : null;
16230 
16231   while ( nNode1 ) {
16232    if ( nNode1.nodeType === 1 ) {
16233     if ( an2 ) {
16234      fn( nNode1, nNode2, index );
16235     }
16236     else {
16237      fn( nNode1, index );
16238     }
16239 
16240     index++;
16241    }
16242 
16243    nNode1 = nNode1.nextSibling;
16244    nNode2 = an2 ? nNode2.nextSibling : null;
16245   }
16246 
16247   i++;
16248  }
16249 }
16250 
16251 
16252 
16253 var __re_html_remove = /<.*?>/g;
16254 
16255 
16256 /**
16257  * Calculate the width of columns for the table
16258  *  @param {object} oSettings dataTables settings object
16259  *  @memberof DataTable#oApi
16260  */
16261 function _fnCalculateColumnWidths ( oSettings )
16262 {
16263  var
16264   table = oSettings.nTable,
16265   columns = oSettings.aoColumns,
16266   scroll = oSettings.oScroll,
16267   scrollY = scroll.sY,
16268   scrollX = scroll.sX,
16269   scrollXInner = scroll.sXInner,
16270   columnCount = columns.length,
16271   visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
16272   headerCells = $('th', oSettings.nTHead),
16273   tableWidthAttr = table.getAttribute('width'), // from DOM element
16274   tableContainer = table.parentNode,
16275   userInputs = false,
16276   i, column, columnIdx, width, outerWidth,
16277   browser = oSettings.oBrowser,
16278   ie67 = browser.bScrollOversize;
16279 
16280  var styleWidth = table.style.width;
16281  if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
16282   tableWidthAttr = styleWidth;
16283  }
16284 
16285  /* Convert any user input sizes into pixel sizes */
16286  for ( i=0 ; i<visibleColumns.length ; i++ ) {
16287   column = columns[ visibleColumns[i] ];
16288 
16289   if ( column.sWidth !== null ) {
16290    column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
16291 
16292    userInputs = true;
16293   }
16294  }
16295 
16296  /* If the number of columns in the DOM equals the number that we have to
16297   * process in DataTables, then we can use the offsets that are created by
16298   * the web- browser. No custom sizes can be set in order for this to happen,
16299   * nor scrolling used
16300   */
16301  if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
16302       columnCount == _fnVisbleColumns( oSettings ) &&
16303       columnCount == headerCells.length
16304  ) {
16305   for ( i=0 ; i<columnCount ; i++ ) {
16306    var colIdx = _fnVisibleToColumnIndex( oSettings, i );
16307 
16308    if ( colIdx !== null ) {
16309     columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
16310    }
16311   }
16312  }
16313  else
16314  {
16315   // Otherwise construct a single row, worst case, table with the widest
16316   // node in the data, assign any user defined widths, then insert it into
16317   // the DOM and allow the browser to do all the hard work of calculating
16318   // table widths
16319   var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
16320    .css( 'visibility', 'hidden' )
16321    .removeAttr( 'id' );
16322 
16323   // Clean up the table body
16324   tmpTable.find('tbody tr').remove();
16325   var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
16326 
16327   // Clone the table header and footer - we can't use the header / footer
16328   // from the cloned table, since if scrolling is active, the table's
16329   // real header and footer are contained in different table tags
16330   tmpTable.find('thead, tfoot').remove();
16331   tmpTable
16332    .append( $(oSettings.nTHead).clone() )
16333    .append( $(oSettings.nTFoot).clone() );
16334 
16335   // Remove any assigned widths from the footer (from scrolling)
16336   tmpTable.find('tfoot th, tfoot td').css('width', '');
16337 
16338   // Apply custom sizing to the cloned header
16339   headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
16340 
16341   for ( i=0 ; i<visibleColumns.length ; i++ ) {
16342    column = columns[ visibleColumns[i] ];
16343 
16344    headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
16345     _fnStringToCss( column.sWidthOrig ) :
16346     '';
16347 
16348    // For scrollX we need to force the column width otherwise the
16349    // browser will collapse it. If this width is smaller than the
16350    // width the column requires, then it will have no effect
16351    if ( column.sWidthOrig && scrollX ) {
16352     $( headerCells[i] ).append( $('<div/>').css( {
16353      width: column.sWidthOrig,
16354      margin: 0,
16355      padding: 0,
16356      border: 0,
16357      height: 1
16358     } ) );
16359    }
16360   }
16361 
16362   // Find the widest cell for each column and put it into the table
16363   if ( oSettings.aoData.length ) {
16364    for ( i=0 ; i<visibleColumns.length ; i++ ) {
16365     columnIdx = visibleColumns[i];
16366     column = columns[ columnIdx ];
16367 
16368     $( _fnGetWidestNode( oSettings, columnIdx ) )
16369      .clone( false )
16370      .append( column.sContentPadding )
16371      .appendTo( tr );
16372    }
16373   }
16374 
16375   // Tidy the temporary table - remove name attributes so there aren't
16376   // duplicated in the dom (radio elements for example)
16377   $('[name]', tmpTable).removeAttr('name');
16378 
16379   // Table has been built, attach to the document so we can work with it.
16380   // A holding element is used, positioned at the top of the container
16381   // with minimal height, so it has no effect on if the container scrolls
16382   // or not. Otherwise it might trigger scrolling when it actually isn't
16383   // needed
16384   var holder = $('<div/>').css( scrollX || scrollY ?
16385     {
16386      position: 'absolute',
16387      top: 0,
16388      left: 0,
16389      height: 1,
16390      right: 0,
16391      overflow: 'hidden'
16392     } :
16393     {}
16394    )
16395    .append( tmpTable )
16396    .appendTo( tableContainer );
16397 
16398   // When scrolling (X or Y) we want to set the width of the table as 
16399   // appropriate. However, when not scrolling leave the table width as it
16400   // is. This results in slightly different, but I think correct behaviour
16401   if ( scrollX && scrollXInner ) {
16402    tmpTable.width( scrollXInner );
16403   }
16404   else if ( scrollX ) {
16405    tmpTable.css( 'width', 'auto' );
16406    tmpTable.removeAttr('width');
16407 
16408    // If there is no width attribute or style, then allow the table to
16409    // collapse
16410    if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
16411     tmpTable.width( tableContainer.clientWidth );
16412    }
16413   }
16414   else if ( scrollY ) {
16415    tmpTable.width( tableContainer.clientWidth );
16416   }
16417   else if ( tableWidthAttr ) {
16418    tmpTable.width( tableWidthAttr );
16419   }
16420 
16421   // Get the width of each column in the constructed table - we need to
16422   // know the inner width (so it can be assigned to the other table's
16423   // cells) and the outer width so we can calculate the full width of the
16424   // table. This is safe since DataTables requires a unique cell for each
16425   // column, but if ever a header can span multiple columns, this will
16426   // need to be modified.
16427   var total = 0;
16428   for ( i=0 ; i<visibleColumns.length ; i++ ) {
16429    var cell = $(headerCells[i]);
16430    var border = cell.outerWidth() - cell.width();
16431 
16432    // Use getBounding... where possible (not IE8-) because it can give
16433    // sub-pixel accuracy, which we then want to round up!
16434    var bounding = browser.bBounding ?
16435     Math.ceil( headerCells[i].getBoundingClientRect().width ) :
16436     cell.outerWidth();
16437 
16438    // Total is tracked to remove any sub-pixel errors as the outerWidth
16439    // of the table might not equal the total given here (IE!).
16440    total += bounding;
16441 
16442    // Width for each column to use
16443    columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
16444   }
16445 
16446   table.style.width = _fnStringToCss( total );
16447 
16448   // Finished with the table - ditch it
16449   holder.remove();
16450  }
16451 
16452  // If there is a width attr, we want to attach an event listener which
16453  // allows the table sizing to automatically adjust when the window is
16454  // resized. Use the width attr rather than CSS, since we can't know if the
16455  // CSS is a relative value or absolute - DOM read is always px.
16456  if ( tableWidthAttr ) {
16457   table.style.width = _fnStringToCss( tableWidthAttr );
16458  }
16459 
16460  if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
16461   var bindResize = function () {
16462    $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
16463     _fnAdjustColumnSizing( oSettings );
16464    } ) );
16465   };
16466 
16467   // IE6/7 will crash if we bind a resize event handler on page load.
16468   // To be removed in 1.11 which drops IE6/7 support
16469   if ( ie67 ) {
16470    setTimeout( bindResize, 1000 );
16471   }
16472   else {
16473    bindResize();
16474   }
16475 
16476   oSettings._reszEvt = true;
16477  }
16478 }
16479 
16480 
16481 /**
16482  * Throttle the calls to a function. Arguments and context are maintained for
16483  * the throttled function
16484  *  @param {function} fn Function to be called
16485  *  @param {int} [freq=200] call frequency in mS
16486  *  @returns {function} wrapped function
16487  *  @memberof DataTable#oApi
16488  */
16489 var _fnThrottle = DataTable.util.throttle;
16490 
16491 
16492 /**
16493  * Convert a CSS unit width to pixels (e.g. 2em)
16494  *  @param {string} width width to be converted
16495  *  @param {node} parent parent to get the with for (required for relative widths) - optional
16496  *  @returns {int} width in pixels
16497  *  @memberof DataTable#oApi
16498  */
16499 function _fnConvertToWidth ( width, parent )
16500 {
16501  if ( ! width ) {
16502   return 0;
16503  }
16504 
16505  var n = $('<div/>')
16506   .css( 'width', _fnStringToCss( width ) )
16507   .appendTo( parent || document.body );
16508 
16509  var val = n[0].offsetWidth;
16510  n.remove();
16511 
16512  return val;
16513 }
16514 
16515 
16516 /**
16517  * Get the widest node
16518  *  @param {object} settings dataTables settings object
16519  *  @param {int} colIdx column of interest
16520  *  @returns {node} widest table node
16521  *  @memberof DataTable#oApi
16522  */
16523 function _fnGetWidestNode( settings, colIdx )
16524 {
16525  var idx = _fnGetMaxLenString( settings, colIdx );
16526  if ( idx < 0 ) {
16527   return null;
16528  }
16529 
16530  var data = settings.aoData[ idx ];
16531  return ! data.nTr ? // Might not have been created when deferred rendering
16532   $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
16533   data.anCells[ colIdx ];
16534 }
16535 
16536 
16537 /**
16538  * Get the maximum strlen for each data column
16539  *  @param {object} settings dataTables settings object
16540  *  @param {int} colIdx column of interest
16541  *  @returns {string} max string length for each column
16542  *  @memberof DataTable#oApi
16543  */
16544 function _fnGetMaxLenString( settings, colIdx )
16545 {
16546  var s, max=-1, maxIdx = -1;
16547 
16548  for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
16549   s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
16550   s = s.replace( __re_html_remove, '' );
16551   s = s.replace( /&nbsp;/g, ' ' );
16552 
16553   if ( s.length > max ) {
16554    max = s.length;
16555    maxIdx = i;
16556   }
16557  }
16558 
16559  return maxIdx;
16560 }
16561 
16562 
16563 /**
16564  * Append a CSS unit (only if required) to a string
16565  *  @param {string} value to css-ify
16566  *  @returns {string} value with css unit
16567  *  @memberof DataTable#oApi
16568  */
16569 function _fnStringToCss( s )
16570 {
16571  if ( s === null ) {
16572   return '0px';
16573  }
16574 
16575  if ( typeof s == 'number' ) {
16576   return s < 0 ?
16577    '0px' :
16578    s+'px';
16579  }
16580 
16581  // Check it has a unit character already
16582  return s.match(/\d$/) ?
16583   s+'px' :
16584   s;
16585 }
16586 
16587 
16588 
16589 function _fnSortFlatten ( settings )
16590 {
16591  var
16592   i, iLen, k, kLen,
16593   aSort = [],
16594   aiOrig = [],
16595   aoColumns = settings.aoColumns,
16596   aDataSort, iCol, sType, srcCol,
16597   fixed = settings.aaSortingFixed,
16598   fixedObj = $.isPlainObject( fixed ),
16599   nestedSort = [],
16600   add = function ( a ) {
16601    if ( a.length && ! $.isArray( a[0] ) ) {
16602     // 1D array
16603     nestedSort.push( a );
16604    }
16605    else {
16606     // 2D array
16607     $.merge( nestedSort, a );
16608    }
16609   };
16610 
16611  // Build the sort array, with pre-fix and post-fix options if they have been
16612  // specified
16613  if ( $.isArray( fixed ) ) {
16614   add( fixed );
16615  }
16616 
16617  if ( fixedObj && fixed.pre ) {
16618   add( fixed.pre );
16619  }
16620 
16621  add( settings.aaSorting );
16622 
16623  if (fixedObj && fixed.post ) {
16624   add( fixed.post );
16625  }
16626 
16627  for ( i=0 ; i<nestedSort.length ; i++ )
16628  {
16629   srcCol = nestedSort[i][0];
16630   aDataSort = aoColumns[ srcCol ].aDataSort;
16631 
16632   for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
16633   {
16634    iCol = aDataSort[k];
16635    sType = aoColumns[ iCol ].sType || 'string';
16636 
16637    if ( nestedSort[i]._idx === undefined ) {
16638     nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
16639    }
16640 
16641    aSort.push( {
16642     src:       srcCol,
16643     col:       iCol,
16644     dir:       nestedSort[i][1],
16645     index:     nestedSort[i]._idx,
16646     type:      sType,
16647     formatter: DataTable.ext.type.order[ sType+"-pre" ]
16648    } );
16649   }
16650  }
16651 
16652  return aSort;
16653 }
16654 
16655 /**
16656  * Change the order of the table
16657  *  @param {object} oSettings dataTables settings object
16658  *  @memberof DataTable#oApi
16659  *  @todo This really needs split up!
16660  */
16661 function _fnSort ( oSettings )
16662 {
16663  var
16664   i, ien, iLen, j, jLen, k, kLen,
16665   sDataType, nTh,
16666   aiOrig = [],
16667   oExtSort = DataTable.ext.type.order,
16668   aoData = oSettings.aoData,
16669   aoColumns = oSettings.aoColumns,
16670   aDataSort, data, iCol, sType, oSort,
16671   formatters = 0,
16672   sortCol,
16673   displayMaster = oSettings.aiDisplayMaster,
16674   aSort;
16675 
16676  // Resolve any column types that are unknown due to addition or invalidation
16677  // @todo Can this be moved into a 'data-ready' handler which is called when
16678  //   data is going to be used in the table?
16679  _fnColumnTypes( oSettings );
16680 
16681  aSort = _fnSortFlatten( oSettings );
16682 
16683  for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
16684   sortCol = aSort[i];
16685 
16686   // Track if we can use the fast sort algorithm
16687   if ( sortCol.formatter ) {
16688    formatters++;
16689   }
16690 
16691   // Load the data needed for the sort, for each cell
16692   _fnSortData( oSettings, sortCol.col );
16693  }
16694 
16695  /* No sorting required if server-side or no sorting array */
16696  if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
16697  {
16698   // Create a value - key array of the current row positions such that we can use their
16699   // current position during the sort, if values match, in order to perform stable sorting
16700   for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
16701    aiOrig[ displayMaster[i] ] = i;
16702   }
16703 
16704   /* Do the sort - here we want multi-column sorting based on a given data source (column)
16705    * and sorting function (from oSort) in a certain direction. It's reasonably complex to
16706    * follow on it's own, but this is what we want (example two column sorting):
16707    *  fnLocalSorting = function(a,b){
16708    *    var iTest;
16709    *    iTest = oSort['string-asc']('data11', 'data12');
16710    *      if (iTest !== 0)
16711    *        return iTest;
16712    *    iTest = oSort['numeric-desc']('data21', 'data22');
16713    *    if (iTest !== 0)
16714    *      return iTest;
16715    *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
16716    *  }
16717    * Basically we have a test for each sorting column, if the data in that column is equal,
16718    * test the next column. If all columns match, then we use a numeric sort on the row
16719    * positions in the original data array to provide a stable sort.
16720    *
16721    * Note - I know it seems excessive to have two sorting methods, but the first is around
16722    * 15% faster, so the second is only maintained for backwards compatibility with sorting
16723    * methods which do not have a pre-sort formatting function.
16724    */
16725   if ( formatters === aSort.length ) {
16726    // All sort types have formatting functions
16727    displayMaster.sort( function ( a, b ) {
16728     var
16729      x, y, k, test, sort,
16730      len=aSort.length,
16731      dataA = aoData[a]._aSortData,
16732      dataB = aoData[b]._aSortData;
16733 
16734     for ( k=0 ; k<len ; k++ ) {
16735      sort = aSort[k];
16736 
16737      x = dataA[ sort.col ];
16738      y = dataB[ sort.col ];
16739 
16740      test = x<y ? -1 : x>y ? 1 : 0;
16741      if ( test !== 0 ) {
16742       return sort.dir === 'asc' ? test : -test;
16743      }
16744     }
16745 
16746     x = aiOrig[a];
16747     y = aiOrig[b];
16748     return x<y ? -1 : x>y ? 1 : 0;
16749    } );
16750   }
16751   else {
16752    // Depreciated - remove in 1.11 (providing a plug-in option)
16753    // Not all sort types have formatting methods, so we have to call their sorting
16754    // methods.
16755    displayMaster.sort( function ( a, b ) {
16756     var
16757      x, y, k, l, test, sort, fn,
16758      len=aSort.length,
16759      dataA = aoData[a]._aSortData,
16760      dataB = aoData[b]._aSortData;
16761 
16762     for ( k=0 ; k<len ; k++ ) {
16763      sort = aSort[k];
16764 
16765      x = dataA[ sort.col ];
16766      y = dataB[ sort.col ];
16767 
16768      fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
16769      test = fn( x, y );
16770      if ( test !== 0 ) {
16771       return test;
16772      }
16773     }
16774 
16775     x = aiOrig[a];
16776     y = aiOrig[b];
16777     return x<y ? -1 : x>y ? 1 : 0;
16778    } );
16779   }
16780  }
16781 
16782  /* Tell the draw function that we have sorted the data */
16783  oSettings.bSorted = true;
16784 }
16785 
16786 
16787 function _fnSortAria ( settings )
16788 {
16789  var label;
16790  var nextSort;
16791  var columns = settings.aoColumns;
16792  var aSort = _fnSortFlatten( settings );
16793  var oAria = settings.oLanguage.oAria;
16794 
16795  // ARIA attributes - need to loop all columns, to update all (removing old
16796  // attributes as needed)
16797  for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
16798  {
16799   var col = columns[i];
16800   var asSorting = col.asSorting;
16801   var sTitle = col.sTitle.replace( /<.*?>/g, "" );
16802   var th = col.nTh;
16803 
16804   // IE7 is throwing an error when setting these properties with jQuery's
16805   // attr() and removeAttr() methods...
16806   th.removeAttribute('aria-sort');
16807 
16808   /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
16809   if ( col.bSortable ) {
16810    if ( aSort.length > 0 && aSort[0].col == i ) {
16811     th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
16812     nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
16813    }
16814    else {
16815     nextSort = asSorting[0];
16816    }
16817 
16818    label = sTitle + ( nextSort === "asc" ?
16819     oAria.sSortAscending :
16820     oAria.sSortDescending
16821    );
16822   }
16823   else {
16824    label = sTitle;
16825   }
16826 
16827   th.setAttribute('aria-label', label);
16828  }
16829 }
16830 
16831 
16832 /**
16833  * Function to run on user sort request
16834  *  @param {object} settings dataTables settings object
16835  *  @param {node} attachTo node to attach the handler to
16836  *  @param {int} colIdx column sorting index
16837  *  @param {boolean} [append=false] Append the requested sort to the existing
16838  *    sort if true (i.e. multi-column sort)
16839  *  @param {function} [callback] callback function
16840  *  @memberof DataTable#oApi
16841  */
16842 function _fnSortListener ( settings, colIdx, append, callback )
16843 {
16844  var col = settings.aoColumns[ colIdx ];
16845  var sorting = settings.aaSorting;
16846  var asSorting = col.asSorting;
16847  var nextSortIdx;
16848  var next = function ( a, overflow ) {
16849   var idx = a._idx;
16850   if ( idx === undefined ) {
16851    idx = $.inArray( a[1], asSorting );
16852   }
16853 
16854   return idx+1 < asSorting.length ?
16855    idx+1 :
16856    overflow ?
16857     null :
16858     0;
16859  };
16860 
16861  // Convert to 2D array if needed
16862  if ( typeof sorting[0] === 'number' ) {
16863   sorting = settings.aaSorting = [ sorting ];
16864  }
16865 
16866  // If appending the sort then we are multi-column sorting
16867  if ( append && settings.oFeatures.bSortMulti ) {
16868   // Are we already doing some kind of sort on this column?
16869   var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
16870 
16871   if ( sortIdx !== -1 ) {
16872    // Yes, modify the sort
16873    nextSortIdx = next( sorting[sortIdx], true );
16874 
16875    if ( nextSortIdx === null && sorting.length === 1 ) {
16876     nextSortIdx = 0; // can't remove sorting completely
16877    }
16878 
16879    if ( nextSortIdx === null ) {
16880     sorting.splice( sortIdx, 1 );
16881    }
16882    else {
16883     sorting[sortIdx][1] = asSorting[ nextSortIdx ];
16884     sorting[sortIdx]._idx = nextSortIdx;
16885    }
16886   }
16887   else {
16888    // No sort on this column yet
16889    sorting.push( [ colIdx, asSorting[0], 0 ] );
16890    sorting[sorting.length-1]._idx = 0;
16891   }
16892  }
16893  else if ( sorting.length && sorting[0][0] == colIdx ) {
16894   // Single column - already sorting on this column, modify the sort
16895   nextSortIdx = next( sorting[0] );
16896 
16897   sorting.length = 1;
16898   sorting[0][1] = asSorting[ nextSortIdx ];
16899   sorting[0]._idx = nextSortIdx;
16900  }
16901  else {
16902   // Single column - sort only on this column
16903   sorting.length = 0;
16904   sorting.push( [ colIdx, asSorting[0] ] );
16905   sorting[0]._idx = 0;
16906  }
16907 
16908  // Run the sort by calling a full redraw
16909  _fnReDraw( settings );
16910 
16911  // callback used for async user interaction
16912  if ( typeof callback == 'function' ) {
16913   callback( settings );
16914  }
16915 }
16916 
16917 
16918 /**
16919  * Attach a sort handler (click) to a node
16920  *  @param {object} settings dataTables settings object
16921  *  @param {node} attachTo node to attach the handler to
16922  *  @param {int} colIdx column sorting index
16923  *  @param {function} [callback] callback function
16924  *  @memberof DataTable#oApi
16925  */
16926 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
16927 {
16928  var col = settings.aoColumns[ colIdx ];
16929 
16930  _fnBindAction( attachTo, {}, function (e) {
16931   /* If the column is not sortable - don't to anything */
16932   if ( col.bSortable === false ) {
16933    return;
16934   }
16935 
16936   // If processing is enabled use a timeout to allow the processing
16937   // display to be shown - otherwise to it synchronously
16938   if ( settings.oFeatures.bProcessing ) {
16939    _fnProcessingDisplay( settings, true );
16940 
16941    setTimeout( function() {
16942     _fnSortListener( settings, colIdx, e.shiftKey, callback );
16943 
16944     // In server-side processing, the draw callback will remove the
16945     // processing display
16946     if ( _fnDataSource( settings ) !== 'ssp' ) {
16947      _fnProcessingDisplay( settings, false );
16948     }
16949    }, 0 );
16950   }
16951   else {
16952    _fnSortListener( settings, colIdx, e.shiftKey, callback );
16953   }
16954  } );
16955 }
16956 
16957 
16958 /**
16959  * Set the sorting classes on table's body, Note: it is safe to call this function
16960  * when bSort and bSortClasses are false
16961  *  @param {object} oSettings dataTables settings object
16962  *  @memberof DataTable#oApi
16963  */
16964 function _fnSortingClasses( settings )
16965 {
16966  var oldSort = settings.aLastSort;
16967  var sortClass = settings.oClasses.sSortColumn;
16968  var sort = _fnSortFlatten( settings );
16969  var features = settings.oFeatures;
16970  var i, ien, colIdx;
16971 
16972  if ( features.bSort && features.bSortClasses ) {
16973   // Remove old sorting classes
16974   for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
16975    colIdx = oldSort[i].src;
16976 
16977    // Remove column sorting
16978    $( _pluck( settings.aoData, 'anCells', colIdx ) )
16979     .removeClass( sortClass + (i<2 ? i+1 : 3) );
16980   }
16981 
16982   // Add new column sorting
16983   for ( i=0, ien=sort.length ; i<ien ; i++ ) {
16984    colIdx = sort[i].src;
16985 
16986    $( _pluck( settings.aoData, 'anCells', colIdx ) )
16987     .addClass( sortClass + (i<2 ? i+1 : 3) );
16988   }
16989  }
16990 
16991  settings.aLastSort = sort;
16992 }
16993 
16994 
16995 // Get the data to sort a column, be it from cache, fresh (populating the
16996 // cache), or from a sort formatter
16997 function _fnSortData( settings, idx )
16998 {
16999  // Custom sorting function - provided by the sort data type
17000  var column = settings.aoColumns[ idx ];
17001  var customSort = DataTable.ext.order[ column.sSortDataType ];
17002  var customData;
17003 
17004  if ( customSort ) {
17005   customData = customSort.call( settings.oInstance, settings, idx,
17006    _fnColumnIndexToVisible( settings, idx )
17007   );
17008  }
17009 
17010  // Use / populate cache
17011  var row, cellData;
17012  var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
17013 
17014  for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
17015   row = settings.aoData[i];
17016 
17017   if ( ! row._aSortData ) {
17018    row._aSortData = [];
17019   }
17020 
17021   if ( ! row._aSortData[idx] || customSort ) {
17022    cellData = customSort ?
17023     customData[i] : // If there was a custom sort function, use data from there
17024     _fnGetCellData( settings, i, idx, 'sort' );
17025 
17026    row._aSortData[ idx ] = formatter ?
17027     formatter( cellData ) :
17028     cellData;
17029   }
17030  }
17031 }
17032 
17033 
17034 
17035 /**
17036  * Save the state of a table
17037  *  @param {object} oSettings dataTables settings object
17038  *  @memberof DataTable#oApi
17039  */
17040 function _fnSaveState ( settings )
17041 {
17042  if ( !settings.oFeatures.bStateSave || settings.bDestroying )
17043  {
17044   return;
17045  }
17046 
17047  /* Store the interesting variables */
17048  var state = {
17049   time:    +new Date(),
17050   start:   settings._iDisplayStart,
17051   length:  settings._iDisplayLength,
17052   order:   $.extend( true, [], settings.aaSorting ),
17053   search:  _fnSearchToCamel( settings.oPreviousSearch ),
17054   columns: $.map( settings.aoColumns, function ( col, i ) {
17055    return {
17056     visible: col.bVisible,
17057     search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
17058    };
17059   } )
17060  };
17061 
17062  _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
17063 
17064  settings.oSavedState = state;
17065  settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
17066 }
17067 
17068 
17069 /**
17070  * Attempt to load a saved table state
17071  *  @param {object} oSettings dataTables settings object
17072  *  @param {object} oInit DataTables init object so we can override settings
17073  *  @memberof DataTable#oApi
17074  */
17075 function _fnLoadState ( settings, oInit )
17076 {
17077  var i, ien;
17078  var columns = settings.aoColumns;
17079 
17080  if ( ! settings.oFeatures.bStateSave ) {
17081   return;
17082  }
17083 
17084  var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
17085  if ( ! state || ! state.time ) {
17086   return;
17087  }
17088 
17089  /* Allow custom and plug-in manipulation functions to alter the saved data set and
17090   * cancelling of loading by returning false
17091   */
17092  var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
17093  if ( $.inArray( false, abStateLoad ) !== -1 ) {
17094   return;
17095  }
17096 
17097  /* Reject old data */
17098  var duration = settings.iStateDuration;
17099  if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
17100   return;
17101  }
17102 
17103  // Number of columns have changed - all bets are off, no restore of settings
17104  if ( columns.length !== state.columns.length ) {
17105   return;
17106  }
17107 
17108  // Store the saved state so it might be accessed at any time
17109  settings.oLoadedState = $.extend( true, {}, state );
17110 
17111  // Restore key features - todo - for 1.11 this needs to be done by
17112  // subscribed events
17113  if ( state.start !== undefined ) {
17114   settings._iDisplayStart    = state.start;
17115   settings.iInitDisplayStart = state.start;
17116  }
17117  if ( state.length !== undefined ) {
17118   settings._iDisplayLength   = state.length;
17119  }
17120 
17121  // Order
17122  if ( state.order !== undefined ) {
17123   settings.aaSorting = [];
17124   $.each( state.order, function ( i, col ) {
17125    settings.aaSorting.push( col[0] >= columns.length ?
17126     [ 0, col[1] ] :
17127     col
17128    );
17129   } );
17130  }
17131 
17132  // Search
17133  if ( state.search !== undefined ) {
17134   $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
17135  }
17136 
17137  // Columns
17138  for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
17139   var col = state.columns[i];
17140 
17141   // Visibility
17142   if ( col.visible !== undefined ) {
17143    columns[i].bVisible = col.visible;
17144   }
17145 
17146   // Search
17147   if ( col.search !== undefined ) {
17148    $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
17149   }
17150  }
17151 
17152  _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
17153 }
17154 
17155 
17156 /**
17157  * Return the settings object for a particular table
17158  *  @param {node} table table we are using as a dataTable
17159  *  @returns {object} Settings object - or null if not found
17160  *  @memberof DataTable#oApi
17161  */
17162 function _fnSettingsFromNode ( table )
17163 {
17164  var settings = DataTable.settings;
17165  var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
17166 
17167  return idx !== -1 ?
17168   settings[ idx ] :
17169   null;
17170 }
17171 
17172 
17173 /**
17174  * Log an error message
17175  *  @param {object} settings dataTables settings object
17176  *  @param {int} level log error messages, or display them to the user
17177  *  @param {string} msg error message
17178  *  @param {int} tn Technical note id to get more information about the error.
17179  *  @memberof DataTable#oApi
17180  */
17181 function _fnLog( settings, level, msg, tn )
17182 {
17183  msg = 'DataTables warning: '+
17184   (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
17185 
17186  if ( tn ) {
17187   msg += '. For more information about this error, please see '+
17188   'http://datatables.net/tn/'+tn;
17189  }
17190 
17191  if ( ! level  ) {
17192   // Backwards compatibility pre 1.10
17193   var ext = DataTable.ext;
17194   var type = ext.sErrMode || ext.errMode;
17195 
17196   if ( settings ) {
17197    _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
17198   }
17199 
17200   if ( type == 'alert' ) {
17201    alert( msg );
17202   }
17203   else if ( type == 'throw' ) {
17204    throw new Error(msg);
17205   }
17206   else if ( typeof type == 'function' ) {
17207    type( settings, tn, msg );
17208   }
17209  }
17210  else if ( window.console && console.log ) {
17211   console.log( msg );
17212  }
17213 }
17214 
17215 
17216 /**
17217  * See if a property is defined on one object, if so assign it to the other object
17218  *  @param {object} ret target object
17219  *  @param {object} src source object
17220  *  @param {string} name property
17221  *  @param {string} [mappedName] name to map too - optional, name used if not given
17222  *  @memberof DataTable#oApi
17223  */
17224 function _fnMap( ret, src, name, mappedName )
17225 {
17226  if ( $.isArray( name ) ) {
17227   $.each( name, function (i, val) {
17228    if ( $.isArray( val ) ) {
17229     _fnMap( ret, src, val[0], val[1] );
17230    }
17231    else {
17232     _fnMap( ret, src, val );
17233    }
17234   } );
17235 
17236   return;
17237  }
17238 
17239  if ( mappedName === undefined ) {
17240   mappedName = name;
17241  }
17242 
17243  if ( src[name] !== undefined ) {
17244   ret[mappedName] = src[name];
17245  }
17246 }
17247 
17248 
17249 /**
17250  * Extend objects - very similar to jQuery.extend, but deep copy objects, and
17251  * shallow copy arrays. The reason we need to do this, is that we don't want to
17252  * deep copy array init values (such as aaSorting) since the dev wouldn't be
17253  * able to override them, but we do want to deep copy arrays.
17254  *  @param {object} out Object to extend
17255  *  @param {object} extender Object from which the properties will be applied to
17256  *      out
17257  *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
17258  *      independent copy with the exception of the `data` or `aaData` parameters
17259  *      if they are present. This is so you can pass in a collection to
17260  *      DataTables and have that used as your data source without breaking the
17261  *      references
17262  *  @returns {object} out Reference, just for convenience - out === the return.
17263  *  @memberof DataTable#oApi
17264  *  @todo This doesn't take account of arrays inside the deep copied objects.
17265  */
17266 function _fnExtend( out, extender, breakRefs )
17267 {
17268  var val;
17269 
17270  for ( var prop in extender ) {
17271   if ( extender.hasOwnProperty(prop) ) {
17272    val = extender[prop];
17273 
17274    if ( $.isPlainObject( val ) ) {
17275     if ( ! $.isPlainObject( out[prop] ) ) {
17276      out[prop] = {};
17277     }
17278     $.extend( true, out[prop], val );
17279    }
17280    else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
17281     out[prop] = val.slice();
17282    }
17283    else {
17284     out[prop] = val;
17285    }
17286   }
17287  }
17288 
17289  return out;
17290 }
17291 
17292 
17293 /**
17294  * Bind an event handers to allow a click or return key to activate the callback.
17295  * This is good for accessibility since a return on the keyboard will have the
17296  * same effect as a click, if the element has focus.
17297  *  @param {element} n Element to bind the action to
17298  *  @param {object} oData Data object to pass to the triggered function
17299  *  @param {function} fn Callback function for when the event is triggered
17300  *  @memberof DataTable#oApi
17301  */
17302 function _fnBindAction( n, oData, fn )
17303 {
17304  $(n)
17305   .bind( 'click.DT', oData, function (e) {
17306     n.blur(); // Remove focus outline for mouse users
17307     fn(e);
17308    } )
17309   .bind( 'keypress.DT', oData, function (e){
17310     if ( e.which === 13 ) {
17311      e.preventDefault();
17312      fn(e);
17313     }
17314    } )
17315   .bind( 'selectstart.DT', function () {
17316     /* Take the brutal approach to cancelling text selection */
17317     return false;
17318    } );
17319 }
17320 
17321 
17322 /**
17323  * Register a callback function. Easily allows a callback function to be added to
17324  * an array store of callback functions that can then all be called together.
17325  *  @param {object} oSettings dataTables settings object
17326  *  @param {string} sStore Name of the array storage for the callbacks in oSettings
17327  *  @param {function} fn Function to be called back
17328  *  @param {string} sName Identifying name for the callback (i.e. a label)
17329  *  @memberof DataTable#oApi
17330  */
17331 function _fnCallbackReg( oSettings, sStore, fn, sName )
17332 {
17333  if ( fn )
17334  {
17335   oSettings[sStore].push( {
17336    "fn": fn,
17337    "sName": sName
17338   } );
17339  }
17340 }
17341 
17342 
17343 /**
17344  * Fire callback functions and trigger events. Note that the loop over the
17345  * callback array store is done backwards! Further note that you do not want to
17346  * fire off triggers in time sensitive applications (for example cell creation)
17347  * as its slow.
17348  *  @param {object} settings dataTables settings object
17349  *  @param {string} callbackArr Name of the array storage for the callbacks in
17350  *      oSettings
17351  *  @param {string} eventName Name of the jQuery custom event to trigger. If
17352  *      null no trigger is fired
17353  *  @param {array} args Array of arguments to pass to the callback function /
17354  *      trigger
17355  *  @memberof DataTable#oApi
17356  */
17357 function _fnCallbackFire( settings, callbackArr, eventName, args )
17358 {
17359  var ret = [];
17360 
17361  if ( callbackArr ) {
17362   ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
17363    return val.fn.apply( settings.oInstance, args );
17364   } );
17365  }
17366 
17367  if ( eventName !== null ) {
17368   var e = $.Event( eventName+'.dt' );
17369 
17370   $(settings.nTable).trigger( e, args );
17371 
17372   ret.push( e.result );
17373  }
17374 
17375  return ret;
17376 }
17377 
17378 
17379 function _fnLengthOverflow ( settings )
17380 {
17381  var
17382   start = settings._iDisplayStart,
17383   end = settings.fnDisplayEnd(),
17384   len = settings._iDisplayLength;
17385 
17386  /* If we have space to show extra rows (backing up from the end point - then do so */
17387  if ( start >= end )
17388  {
17389   start = end - len;
17390  }
17391 
17392  // Keep the start record on the current page
17393  start -= (start % len);
17394 
17395  if ( len === -1 || start < 0 )
17396  {
17397   start = 0;
17398  }
17399 
17400  settings._iDisplayStart = start;
17401 }
17402 
17403 
17404 function _fnRenderer( settings, type )
17405 {
17406  var renderer = settings.renderer;
17407  var host = DataTable.ext.renderer[type];
17408 
17409  if ( $.isPlainObject( renderer ) && renderer[type] ) {
17410   // Specific renderer for this type. If available use it, otherwise use
17411   // the default.
17412   return host[renderer[type]] || host._;
17413  }
17414  else if ( typeof renderer === 'string' ) {
17415   // Common renderer - if there is one available for this type use it,
17416   // otherwise use the default
17417   return host[renderer] || host._;
17418  }
17419 
17420  // Use the default
17421  return host._;
17422 }
17423 
17424 
17425 /**
17426  * Detect the data source being used for the table. Used to simplify the code
17427  * a little (ajax) and to make it compress a little smaller.
17428  *
17429  *  @param {object} settings dataTables settings object
17430  *  @returns {string} Data source
17431  *  @memberof DataTable#oApi
17432  */
17433 function _fnDataSource ( settings )
17434 {
17435  if ( settings.oFeatures.bServerSide ) {
17436   return 'ssp';
17437  }
17438  else if ( settings.ajax || settings.sAjaxSource ) {
17439   return 'ajax';
17440  }
17441  return 'dom';
17442 }
17443 
17444 
17445 
17446 /**
17447  * Computed structure of the DataTables API, defined by the options passed to
17448  * `DataTable.Api.register()` when building the API.
17449  *
17450  * The structure is built in order to speed creation and extension of the Api
17451  * objects since the extensions are effectively pre-parsed.
17452  *
17453  * The array is an array of objects with the following structure, where this
17454  * base array represents the Api prototype base:
17455  *
17456  *     [
17457  *       {
17458  *         name:      'data'                -- string   - Property name
17459  *         val:       function () {},       -- function - Api method (or undefined if just an object
17460  *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
17461  *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
17462  *       },
17463  *       {
17464  *         name:     'row'
17465  *         val:       {},
17466  *         methodExt: [ ... ],
17467  *         propExt:   [
17468  *           {
17469  *             name:      'data'
17470  *             val:       function () {},
17471  *             methodExt: [ ... ],
17472  *             propExt:   [ ... ]
17473  *           },
17474  *           ...
17475  *         ]
17476  *       }
17477  *     ]
17478  *
17479  * @type {Array}
17480  * @ignore
17481  */
17482 var __apiStruct = [];
17483 
17484 
17485 /**
17486  * `Array.prototype` reference.
17487  *
17488  * @type object
17489  * @ignore
17490  */
17491 var __arrayProto = Array.prototype;
17492 
17493 
17494 /**
17495  * Abstraction for `context` parameter of the `Api` constructor to allow it to
17496  * take several different forms for ease of use.
17497  *
17498  * Each of the input parameter types will be converted to a DataTables settings
17499  * object where possible.
17500  *
17501  * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
17502  *   of:
17503  *
17504  *   * `string` - jQuery selector. Any DataTables' matching the given selector
17505  *     with be found and used.
17506  *   * `node` - `TABLE` node which has already been formed into a DataTable.
17507  *   * `jQuery` - A jQuery object of `TABLE` nodes.
17508  *   * `object` - DataTables settings object
17509  *   * `DataTables.Api` - API instance
17510  * @return {array|null} Matching DataTables settings objects. `null` or
17511  *   `undefined` is returned if no matching DataTable is found.
17512  * @ignore
17513  */
17514 var _toSettings = function ( mixed )
17515 {
17516  var idx, jq;
17517  var settings = DataTable.settings;
17518  var tables = $.map( settings, function (el, i) {
17519   return el.nTable;
17520  } );
17521 
17522  if ( ! mixed ) {
17523   return [];
17524  }
17525  else if ( mixed.nTable && mixed.oApi ) {
17526   // DataTables settings object
17527   return [ mixed ];
17528  }
17529  else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
17530   // Table node
17531   idx = $.inArray( mixed, tables );
17532   return idx !== -1 ? [ settings[idx] ] : null;
17533  }
17534  else if ( mixed && typeof mixed.settings === 'function' ) {
17535   return mixed.settings().toArray();
17536  }
17537  else if ( typeof mixed === 'string' ) {
17538   // jQuery selector
17539   jq = $(mixed);
17540  }
17541  else if ( mixed instanceof $ ) {
17542   // jQuery object (also DataTables instance)
17543   jq = mixed;
17544  }
17545 
17546  if ( jq ) {
17547   return jq.map( function(i) {
17548    idx = $.inArray( this, tables );
17549    return idx !== -1 ? settings[idx] : null;
17550   } ).toArray();
17551  }
17552 };
17553 
17554 
17555 /**
17556  * DataTables API class - used to control and interface with  one or more
17557  * DataTables enhanced tables.
17558  *
17559  * The API class is heavily based on jQuery, presenting a chainable interface
17560  * that you can use to interact with tables. Each instance of the API class has
17561  * a "context" - i.e. the tables that it will operate on. This could be a single
17562  * table, all tables on a page or a sub-set thereof.
17563  *
17564  * Additionally the API is designed to allow you to easily work with the data in
17565  * the tables, retrieving and manipulating it as required. This is done by
17566  * presenting the API class as an array like interface. The contents of the
17567  * array depend upon the actions requested by each method (for example
17568  * `rows().nodes()` will return an array of nodes, while `rows().data()` will
17569  * return an array of objects or arrays depending upon your table's
17570  * configuration). The API object has a number of array like methods (`push`,
17571  * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
17572  * `unique` etc) to assist your working with the data held in a table.
17573  *
17574  * Most methods (those which return an Api instance) are chainable, which means
17575  * the return from a method call also has all of the methods available that the
17576  * top level object had. For example, these two calls are equivalent:
17577  *
17578  *     // Not chained
17579  *     api.row.add( {...} );
17580  *     api.draw();
17581  *
17582  *     // Chained
17583  *     api.row.add( {...} ).draw();
17584  *
17585  * @class DataTable.Api
17586  * @param {array|object|string|jQuery} context DataTable identifier. This is
17587  *   used to define which DataTables enhanced tables this API will operate on.
17588  *   Can be one of:
17589  *
17590  *   * `string` - jQuery selector. Any DataTables' matching the given selector
17591  *     with be found and used.
17592  *   * `node` - `TABLE` node which has already been formed into a DataTable.
17593  *   * `jQuery` - A jQuery object of `TABLE` nodes.
17594  *   * `object` - DataTables settings object
17595  * @param {array} [data] Data to initialise the Api instance with.
17596  *
17597  * @example
17598  *   // Direct initialisation during DataTables construction
17599  *   var api = $('#example').DataTable();
17600  *
17601  * @example
17602  *   // Initialisation using a DataTables jQuery object
17603  *   var api = $('#example').dataTable().api();
17604  *
17605  * @example
17606  *   // Initialisation as a constructor
17607  *   var api = new $.fn.DataTable.Api( 'table.dataTable' );
17608  */
17609 _Api = function ( context, data )
17610 {
17611  if ( ! (this instanceof _Api) ) {
17612   return new _Api( context, data );
17613  }
17614 
17615  var settings = [];
17616  var ctxSettings = function ( o ) {
17617   var a = _toSettings( o );
17618   if ( a ) {
17619    settings = settings.concat( a );
17620   }
17621  };
17622 
17623  if ( $.isArray( context ) ) {
17624   for ( var i=0, ien=context.length ; i<ien ; i++ ) {
17625    ctxSettings( context[i] );
17626   }
17627  }
17628  else {
17629   ctxSettings( context );
17630  }
17631 
17632  // Remove duplicates
17633  this.context = _unique( settings );
17634 
17635  // Initial data
17636  if ( data ) {
17637   $.merge( this, data );
17638  }
17639 
17640  // selector
17641  this.selector = {
17642   rows: null,
17643   cols: null,
17644   opts: null
17645  };
17646 
17647  _Api.extend( this, this, __apiStruct );
17648 };
17649 
17650 DataTable.Api = _Api;
17651 
17652 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
17653 // isPlainObject.
17654 $.extend( _Api.prototype, {
17655  any: function ()
17656  {
17657   return this.count() !== 0;
17658  },
17659 
17660 
17661  concat:  __arrayProto.concat,
17662 
17663 
17664  context: [], // array of table settings objects
17665 
17666 
17667  count: function ()
17668  {
17669   return this.flatten().length;
17670  },
17671 
17672 
17673  each: function ( fn )
17674  {
17675   for ( var i=0, ien=this.length ; i<ien; i++ ) {
17676    fn.call( this, this[i], i, this );
17677   }
17678 
17679   return this;
17680  },
17681 
17682 
17683  eq: function ( idx )
17684  {
17685   var ctx = this.context;
17686 
17687   return ctx.length > idx ?
17688    new _Api( ctx[idx], this[idx] ) :
17689    null;
17690  },
17691 
17692 
17693  filter: function ( fn )
17694  {
17695   var a = [];
17696 
17697   if ( __arrayProto.filter ) {
17698    a = __arrayProto.filter.call( this, fn, this );
17699   }
17700   else {
17701    // Compatibility for browsers without EMCA-252-5 (JS 1.6)
17702    for ( var i=0, ien=this.length ; i<ien ; i++ ) {
17703     if ( fn.call( this, this[i], i, this ) ) {
17704      a.push( this[i] );
17705     }
17706    }
17707   }
17708 
17709   return new _Api( this.context, a );
17710  },
17711 
17712 
17713  flatten: function ()
17714  {
17715   var a = [];
17716   return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
17717  },
17718 
17719 
17720  join:    __arrayProto.join,
17721 
17722 
17723  indexOf: __arrayProto.indexOf || function (obj, start)
17724  {
17725   for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
17726    if ( this[i] === obj ) {
17727     return i;
17728    }
17729   }
17730   return -1;
17731  },
17732 
17733  iterator: function ( flatten, type, fn, alwaysNew ) {
17734   var
17735    a = [], ret,
17736    i, ien, j, jen,
17737    context = this.context,
17738    rows, items, item,
17739    selector = this.selector;
17740 
17741   // Argument shifting
17742   if ( typeof flatten === 'string' ) {
17743    alwaysNew = fn;
17744    fn = type;
17745    type = flatten;
17746    flatten = false;
17747   }
17748 
17749   for ( i=0, ien=context.length ; i<ien ; i++ ) {
17750    var apiInst = new _Api( context[i] );
17751 
17752    if ( type === 'table' ) {
17753     ret = fn.call( apiInst, context[i], i );
17754 
17755     if ( ret !== undefined ) {
17756      a.push( ret );
17757     }
17758    }
17759    else if ( type === 'columns' || type === 'rows' ) {
17760     // this has same length as context - one entry for each table
17761     ret = fn.call( apiInst, context[i], this[i], i );
17762 
17763     if ( ret !== undefined ) {
17764      a.push( ret );
17765     }
17766    }
17767    else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
17768     // columns and rows share the same structure.
17769     // 'this' is an array of column indexes for each context
17770     items = this[i];
17771 
17772     if ( type === 'column-rows' ) {
17773      rows = _selector_row_indexes( context[i], selector.opts );
17774     }
17775 
17776     for ( j=0, jen=items.length ; j<jen ; j++ ) {
17777      item = items[j];
17778 
17779      if ( type === 'cell' ) {
17780       ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
17781      }
17782      else {
17783       ret = fn.call( apiInst, context[i], item, i, j, rows );
17784      }
17785 
17786      if ( ret !== undefined ) {
17787       a.push( ret );
17788      }
17789     }
17790    }
17791   }
17792 
17793   if ( a.length || alwaysNew ) {
17794    var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
17795    var apiSelector = api.selector;
17796    apiSelector.rows = selector.rows;
17797    apiSelector.cols = selector.cols;
17798    apiSelector.opts = selector.opts;
17799    return api;
17800   }
17801   return this;
17802  },
17803 
17804 
17805  lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
17806  {
17807   // Bit cheeky...
17808   return this.indexOf.apply( this.toArray.reverse(), arguments );
17809  },
17810 
17811 
17812  length:  0,
17813 
17814 
17815  map: function ( fn )
17816  {
17817   var a = [];
17818 
17819   if ( __arrayProto.map ) {
17820    a = __arrayProto.map.call( this, fn, this );
17821   }
17822   else {
17823    // Compatibility for browsers without EMCA-252-5 (JS 1.6)
17824    for ( var i=0, ien=this.length ; i<ien ; i++ ) {
17825     a.push( fn.call( this, this[i], i ) );
17826    }
17827   }
17828 
17829   return new _Api( this.context, a );
17830  },
17831 
17832 
17833  pluck: function ( prop )
17834  {
17835   return this.map( function ( el ) {
17836    return el[ prop ];
17837   } );
17838  },
17839 
17840  pop:     __arrayProto.pop,
17841 
17842 
17843  push:    __arrayProto.push,
17844 
17845 
17846  // Does not return an API instance
17847  reduce: __arrayProto.reduce || function ( fn, init )
17848  {
17849   return _fnReduce( this, fn, init, 0, this.length, 1 );
17850  },
17851 
17852 
17853  reduceRight: __arrayProto.reduceRight || function ( fn, init )
17854  {
17855   return _fnReduce( this, fn, init, this.length-1, -1, -1 );
17856  },
17857 
17858 
17859  reverse: __arrayProto.reverse,
17860 
17861 
17862  // Object with rows, columns and opts
17863  selector: null,
17864 
17865 
17866  shift:   __arrayProto.shift,
17867 
17868 
17869  sort:    __arrayProto.sort, // ? name - order?
17870 
17871 
17872  splice:  __arrayProto.splice,
17873 
17874 
17875  toArray: function ()
17876  {
17877   return __arrayProto.slice.call( this );
17878  },
17879 
17880 
17881  to$: function ()
17882  {
17883   return $( this );
17884  },
17885 
17886 
17887  toJQuery: function ()
17888  {
17889   return $( this );
17890  },
17891 
17892 
17893  unique: function ()
17894  {
17895   return new _Api( this.context, _unique(this) );
17896  },
17897 
17898 
17899  unshift: __arrayProto.unshift
17900 } );
17901 
17902 
17903 _Api.extend = function ( scope, obj, ext )
17904 {
17905  // Only extend API instances and static properties of the API
17906  if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
17907   return;
17908  }
17909 
17910  var
17911   i, ien,
17912   j, jen,
17913   struct, inner,
17914   methodScoping = function ( scope, fn, struc ) {
17915    return function () {
17916     var ret = fn.apply( scope, arguments );
17917 
17918     // Method extension
17919     _Api.extend( ret, ret, struc.methodExt );
17920     return ret;
17921    };
17922   };
17923 
17924  for ( i=0, ien=ext.length ; i<ien ; i++ ) {
17925   struct = ext[i];
17926 
17927   // Value
17928   obj[ struct.name ] = typeof struct.val === 'function' ?
17929    methodScoping( scope, struct.val, struct ) :
17930    $.isPlainObject( struct.val ) ?
17931     {} :
17932     struct.val;
17933 
17934   obj[ struct.name ].__dt_wrapper = true;
17935 
17936   // Property extension
17937   _Api.extend( scope, obj[ struct.name ], struct.propExt );
17938  }
17939 };
17940 
17941 
17942 // @todo - Is there need for an augment function?
17943 // _Api.augment = function ( inst, name )
17944 // {
17945 //  // Find src object in the structure from the name
17946 //  var parts = name.split('.');
17947 
17948 //  _Api.extend( inst, obj );
17949 // };
17950 
17951 
17952 //     [
17953 //       {
17954 //         name:      'data'                -- string   - Property name
17955 //         val:       function () {},       -- function - Api method (or undefined if just an object
17956 //         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
17957 //         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
17958 //       },
17959 //       {
17960 //         name:     'row'
17961 //         val:       {},
17962 //         methodExt: [ ... ],
17963 //         propExt:   [
17964 //           {
17965 //             name:      'data'
17966 //             val:       function () {},
17967 //             methodExt: [ ... ],
17968 //             propExt:   [ ... ]
17969 //           },
17970 //           ...
17971 //         ]
17972 //       }
17973 //     ]
17974 
17975 _Api.register = _api_register = function ( name, val )
17976 {
17977  if ( $.isArray( name ) ) {
17978   for ( var j=0, jen=name.length ; j<jen ; j++ ) {
17979    _Api.register( name[j], val );
17980   }
17981   return;
17982  }
17983 
17984  var
17985   i, ien,
17986   heir = name.split('.'),
17987   struct = __apiStruct,
17988   key, method;
17989 
17990  var find = function ( src, name ) {
17991   for ( var i=0, ien=src.length ; i<ien ; i++ ) {
17992    if ( src[i].name === name ) {
17993     return src[i];
17994    }
17995   }
17996   return null;
17997  };
17998 
17999  for ( i=0, ien=heir.length ; i<ien ; i++ ) {
18000   method = heir[i].indexOf('()') !== -1;
18001   key = method ?
vendor: 42,517 bytes, lines 18002-19612
18002    heir[i].replace('()', '') :
18003    heir[i];
18004 
18005   var src = find( struct, key );
18006   if ( ! src ) {
18007    src = {
18008     name:      key,
18009     val:       {},
18010     methodExt: [],
18011     propExt:   []
18012    };
18013    struct.push( src );
18014   }
18015 
18016   if ( i === ien-1 ) {
18017    src.val = val;
18018   }
18019   else {
18020    struct = method ?
18021     src.methodExt :
18022     src.propExt;
18023   }
18024  }
18025 };
18026 
18027 
18028 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
18029  _Api.register( pluralName, val );
18030 
18031  _Api.register( singularName, function () {
18032   var ret = val.apply( this, arguments );
18033 
18034   if ( ret === this ) {
18035    // Returned item is the API instance that was passed in, return it
18036    return this;
18037   }
18038   else if ( ret instanceof _Api ) {
18039    // New API instance returned, want the value from the first item
18040    // in the returned array for the singular result.
18041    return ret.length ?
18042     $.isArray( ret[0] ) ?
18043      new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
18044      ret[0] :
18045     undefined;
18046   }
18047 
18048   // Non-API return - just fire it back
18049   return ret;
18050  } );
18051 };
18052 
18053 
18054 /**
18055  * Selector for HTML tables. Apply the given selector to the give array of
18056  * DataTables settings objects.
18057  *
18058  * @param {string|integer} [selector] jQuery selector string or integer
18059  * @param  {array} Array of DataTables settings objects to be filtered
18060  * @return {array}
18061  * @ignore
18062  */
18063 var __table_selector = function ( selector, a )
18064 {
18065  // Integer is used to pick out a table by index
18066  if ( typeof selector === 'number' ) {
18067   return [ a[ selector ] ];
18068  }
18069 
18070  // Perform a jQuery selector on the table nodes
18071  var nodes = $.map( a, function (el, i) {
18072   return el.nTable;
18073  } );
18074 
18075  return $(nodes)
18076   .filter( selector )
18077   .map( function (i) {
18078    // Need to translate back from the table node to the settings
18079    var idx = $.inArray( this, nodes );
18080    return a[ idx ];
18081   } )
18082   .toArray();
18083 };
18084 
18085 
18086 
18087 /**
18088  * Context selector for the API's context (i.e. the tables the API instance
18089  * refers to.
18090  *
18091  * @name    DataTable.Api#tables
18092  * @param {string|integer} [selector] Selector to pick which tables the iterator
18093  *   should operate on. If not given, all tables in the current context are
18094  *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
18095  *   select multiple tables or as an integer to select a single table.
18096  * @returns {DataTable.Api} Returns a new API instance if a selector is given.
18097  */
18098 _api_register( 'tables()', function ( selector ) {
18099  // A new instance is created if there was a selector specified
18100  return selector ?
18101   new _Api( __table_selector( selector, this.context ) ) :
18102   this;
18103 } );
18104 
18105 
18106 _api_register( 'table()', function ( selector ) {
18107  var tables = this.tables( selector );
18108  var ctx = tables.context;
18109 
18110  // Truncate to the first matched table
18111  return ctx.length ?
18112   new _Api( ctx[0] ) :
18113   tables;
18114 } );
18115 
18116 
18117 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
18118  return this.iterator( 'table', function ( ctx ) {
18119   return ctx.nTable;
18120  }, 1 );
18121 } );
18122 
18123 
18124 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
18125  return this.iterator( 'table', function ( ctx ) {
18126   return ctx.nTBody;
18127  }, 1 );
18128 } );
18129 
18130 
18131 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
18132  return this.iterator( 'table', function ( ctx ) {
18133   return ctx.nTHead;
18134  }, 1 );
18135 } );
18136 
18137 
18138 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
18139  return this.iterator( 'table', function ( ctx ) {
18140   return ctx.nTFoot;
18141  }, 1 );
18142 } );
18143 
18144 
18145 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
18146  return this.iterator( 'table', function ( ctx ) {
18147   return ctx.nTableWrapper;
18148  }, 1 );
18149 } );
18150 
18151 
18152 
18153 /**
18154  * Redraw the tables in the current context.
18155  */
18156 _api_register( 'draw()', function ( paging ) {
18157  return this.iterator( 'table', function ( settings ) {
18158   if ( paging === 'page' ) {
18159    _fnDraw( settings );
18160   }
18161   else {
18162    if ( typeof paging === 'string' ) {
18163     paging = paging === 'full-hold' ?
18164      false :
18165      true;
18166    }
18167 
18168    _fnReDraw( settings, paging===false );
18169   }
18170  } );
18171 } );
18172 
18173 
18174 
18175 /**
18176  * Get the current page index.
18177  *
18178  * @return {integer} Current page index (zero based)
18179  *//**
18180  * Set the current page.
18181  *
18182  * Note that if you attempt to show a page which does not exist, DataTables will
18183  * not throw an error, but rather reset the paging.
18184  *
18185  * @param {integer|string} action The paging action to take. This can be one of:
18186  *  * `integer` - The page index to jump to
18187  *  * `string` - An action to take:
18188  *    * `first` - Jump to first page.
18189  *    * `next` - Jump to the next page
18190  *    * `previous` - Jump to previous page
18191  *    * `last` - Jump to the last page.
18192  * @returns {DataTables.Api} this
18193  */
18194 _api_register( 'page()', function ( action ) {
18195  if ( action === undefined ) {
18196   return this.page.info().page; // not an expensive call
18197  }
18198 
18199  // else, have an action to take on all tables
18200  return this.iterator( 'table', function ( settings ) {
18201   _fnPageChange( settings, action );
18202  } );
18203 } );
18204 
18205 
18206 /**
18207  * Paging information for the first table in the current context.
18208  *
18209  * If you require paging information for another table, use the `table()` method
18210  * with a suitable selector.
18211  *
18212  * @return {object} Object with the following properties set:
18213  *  * `page` - Current page index (zero based - i.e. the first page is `0`)
18214  *  * `pages` - Total number of pages
18215  *  * `start` - Display index for the first record shown on the current page
18216  *  * `end` - Display index for the last record shown on the current page
18217  *  * `length` - Display length (number of records). Note that generally `start
18218  *    + length = end`, but this is not always true, for example if there are
18219  *    only 2 records to show on the final page, with a length of 10.
18220  *  * `recordsTotal` - Full data set length
18221  *  * `recordsDisplay` - Data set length once the current filtering criterion
18222  *    are applied.
18223  */
18224 _api_register( 'page.info()', function ( action ) {
18225  if ( this.context.length === 0 ) {
18226   return undefined;
18227  }
18228 
18229  var
18230   settings   = this.context[0],
18231   start      = settings._iDisplayStart,
18232   len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
18233   visRecords = settings.fnRecordsDisplay(),
18234   all        = len === -1;
18235 
18236  return {
18237   "page":           all ? 0 : Math.floor( start / len ),
18238   "pages":          all ? 1 : Math.ceil( visRecords / len ),
18239   "start":          start,
18240   "end":            settings.fnDisplayEnd(),
18241   "length":         len,
18242   "recordsTotal":   settings.fnRecordsTotal(),
18243   "recordsDisplay": visRecords,
18244   "serverSide":     _fnDataSource( settings ) === 'ssp'
18245  };
18246 } );
18247 
18248 
18249 /**
18250  * Get the current page length.
18251  *
18252  * @return {integer} Current page length. Note `-1` indicates that all records
18253  *   are to be shown.
18254  *//**
18255  * Set the current page length.
18256  *
18257  * @param {integer} Page length to set. Use `-1` to show all records.
18258  * @returns {DataTables.Api} this
18259  */
18260 _api_register( 'page.len()', function ( len ) {
18261  // Note that we can't call this function 'length()' because `length`
18262  // is a Javascript property of functions which defines how many arguments
18263  // the function expects.
18264  if ( len === undefined ) {
18265   return this.context.length !== 0 ?
18266    this.context[0]._iDisplayLength :
18267    undefined;
18268  }
18269 
18270  // else, set the page length
18271  return this.iterator( 'table', function ( settings ) {
18272   _fnLengthChange( settings, len );
18273  } );
18274 } );
18275 
18276 
18277 
18278 var __reload = function ( settings, holdPosition, callback ) {
18279  // Use the draw event to trigger a callback
18280  if ( callback ) {
18281   var api = new _Api( settings );
18282 
18283   api.one( 'draw', function () {
18284    callback( api.ajax.json() );
18285   } );
18286  }
18287 
18288  if ( _fnDataSource( settings ) == 'ssp' ) {
18289   _fnReDraw( settings, holdPosition );
18290  }
18291  else {
18292   _fnProcessingDisplay( settings, true );
18293 
18294   // Cancel an existing request
18295   var xhr = settings.jqXHR;
18296   if ( xhr && xhr.readyState !== 4 ) {
18297    xhr.abort();
18298   }
18299 
18300   // Trigger xhr
18301   _fnBuildAjax( settings, [], function( json ) {
18302    _fnClearTable( settings );
18303 
18304    var data = _fnAjaxDataSrc( settings, json );
18305    for ( var i=0, ien=data.length ; i<ien ; i++ ) {
18306     _fnAddData( settings, data[i] );
18307    }
18308 
18309    _fnReDraw( settings, holdPosition );
18310    _fnProcessingDisplay( settings, false );
18311   } );
18312  }
18313 };
18314 
18315 
18316 /**
18317  * Get the JSON response from the last Ajax request that DataTables made to the
18318  * server. Note that this returns the JSON from the first table in the current
18319  * context.
18320  *
18321  * @return {object} JSON received from the server.
18322  */
18323 _api_register( 'ajax.json()', function () {
18324  var ctx = this.context;
18325 
18326  if ( ctx.length > 0 ) {
18327   return ctx[0].json;
18328  }
18329 
18330  // else return undefined;
18331 } );
18332 
18333 
18334 /**
18335  * Get the data submitted in the last Ajax request
18336  */
18337 _api_register( 'ajax.params()', function () {
18338  var ctx = this.context;
18339 
18340  if ( ctx.length > 0 ) {
18341   return ctx[0].oAjaxData;
18342  }
18343 
18344  // else return undefined;
18345 } );
18346 
18347 
18348 /**
18349  * Reload tables from the Ajax data source. Note that this function will
18350  * automatically re-draw the table when the remote data has been loaded.
18351  *
18352  * @param {boolean} [reset=true] Reset (default) or hold the current paging
18353  *   position. A full re-sort and re-filter is performed when this method is
18354  *   called, which is why the pagination reset is the default action.
18355  * @returns {DataTables.Api} this
18356  */
18357 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
18358  return this.iterator( 'table', function (settings) {
18359   __reload( settings, resetPaging===false, callback );
18360  } );
18361 } );
18362 
18363 
18364 /**
18365  * Get the current Ajax URL. Note that this returns the URL from the first
18366  * table in the current context.
18367  *
18368  * @return {string} Current Ajax source URL
18369  *//**
18370  * Set the Ajax URL. Note that this will set the URL for all tables in the
18371  * current context.
18372  *
18373  * @param {string} url URL to set.
18374  * @returns {DataTables.Api} this
18375  */
18376 _api_register( 'ajax.url()', function ( url ) {
18377  var ctx = this.context;
18378 
18379  if ( url === undefined ) {
18380   // get
18381   if ( ctx.length === 0 ) {
18382    return undefined;
18383   }
18384   ctx = ctx[0];
18385 
18386   return ctx.ajax ?
18387    $.isPlainObject( ctx.ajax ) ?
18388     ctx.ajax.url :
18389     ctx.ajax :
18390    ctx.sAjaxSource;
18391  }
18392 
18393  // set
18394  return this.iterator( 'table', function ( settings ) {
18395   if ( $.isPlainObject( settings.ajax ) ) {
18396    settings.ajax.url = url;
18397   }
18398   else {
18399    settings.ajax = url;
18400   }
18401   // No need to consider sAjaxSource here since DataTables gives priority
18402   // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
18403   // value of `sAjaxSource` redundant.
18404  } );
18405 } );
18406 
18407 
18408 /**
18409  * Load data from the newly set Ajax URL. Note that this method is only
18410  * available when `ajax.url()` is used to set a URL. Additionally, this method
18411  * has the same effect as calling `ajax.reload()` but is provided for
18412  * convenience when setting a new URL. Like `ajax.reload()` it will
18413  * automatically redraw the table once the remote data has been loaded.
18414  *
18415  * @returns {DataTables.Api} this
18416  */
18417 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
18418  // Same as a reload, but makes sense to present it for easy access after a
18419  // url change
18420  return this.iterator( 'table', function ( ctx ) {
18421   __reload( ctx, resetPaging===false, callback );
18422  } );
18423 } );
18424 
18425 
18426 
18427 
18428 var _selector_run = function ( type, selector, selectFn, settings, opts )
18429 {
18430  var
18431   out = [], res,
18432   a, i, ien, j, jen,
18433   selectorType = typeof selector;
18434 
18435  // Can't just check for isArray here, as an API or jQuery instance might be
18436  // given with their array like look
18437  if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
18438   selector = [ selector ];
18439  }
18440 
18441  for ( i=0, ien=selector.length ; i<ien ; i++ ) {
18442   a = selector[i] && selector[i].split ?
18443    selector[i].split(',') :
18444    [ selector[i] ];
18445 
18446   for ( j=0, jen=a.length ; j<jen ; j++ ) {
18447    res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
18448 
18449    if ( res && res.length ) {
18450     out = out.concat( res );
18451    }
18452   }
18453  }
18454 
18455  // selector extensions
18456  var ext = _ext.selector[ type ];
18457  if ( ext.length ) {
18458   for ( i=0, ien=ext.length ; i<ien ; i++ ) {
18459    out = ext[i]( settings, opts, out );
18460   }
18461  }
18462 
18463  return _unique( out );
18464 };
18465 
18466 
18467 var _selector_opts = function ( opts )
18468 {
18469  if ( ! opts ) {
18470   opts = {};
18471  }
18472 
18473  // Backwards compatibility for 1.9- which used the terminology filter rather
18474  // than search
18475  if ( opts.filter && opts.search === undefined ) {
18476   opts.search = opts.filter;
18477  }
18478 
18479  return $.extend( {
18480   search: 'none',
18481   order: 'current',
18482   page: 'all'
18483  }, opts );
18484 };
18485 
18486 
18487 var _selector_first = function ( inst )
18488 {
18489  // Reduce the API instance to the first item found
18490  for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
18491   if ( inst[i].length > 0 ) {
18492    // Assign the first element to the first item in the instance
18493    // and truncate the instance and context
18494    inst[0] = inst[i];
18495    inst[0].length = 1;
18496    inst.length = 1;
18497    inst.context = [ inst.context[i] ];
18498 
18499    return inst;
18500   }
18501  }
18502 
18503  // Not found - return an empty instance
18504  inst.length = 0;
18505  return inst;
18506 };
18507 
18508 
18509 var _selector_row_indexes = function ( settings, opts )
18510 {
18511  var
18512   i, ien, tmp, a=[],
18513   displayFiltered = settings.aiDisplay,
18514   displayMaster = settings.aiDisplayMaster;
18515 
18516  var
18517   search = opts.search,  // none, applied, removed
18518   order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
18519   page   = opts.page;    // all, current
18520 
18521  if ( _fnDataSource( settings ) == 'ssp' ) {
18522   // In server-side processing mode, most options are irrelevant since
18523   // rows not shown don't exist and the index order is the applied order
18524   // Removed is a special case - for consistency just return an empty
18525   // array
18526   return search === 'removed' ?
18527    [] :
18528    _range( 0, displayMaster.length );
18529  }
18530  else if ( page == 'current' ) {
18531   // Current page implies that order=current and fitler=applied, since it is
18532   // fairly senseless otherwise, regardless of what order and search actually
18533   // are
18534   for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
18535    a.push( displayFiltered[i] );
18536   }
18537  }
18538  else if ( order == 'current' || order == 'applied' ) {
18539   a = search == 'none' ?
18540    displayMaster.slice() :                      // no search
18541    search == 'applied' ?
18542     displayFiltered.slice() :                // applied search
18543     $.map( displayMaster, function (el, i) { // removed search
18544      return $.inArray( el, displayFiltered ) === -1 ? el : null;
18545     } );
18546  }
18547  else if ( order == 'index' || order == 'original' ) {
18548   for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
18549    if ( search == 'none' ) {
18550     a.push( i );
18551    }
18552    else { // applied | removed
18553     tmp = $.inArray( i, displayFiltered );
18554 
18555     if ((tmp === -1 && search == 'removed') ||
18556      (tmp >= 0   && search == 'applied') )
18557     {
18558      a.push( i );
18559     }
18560    }
18561   }
18562  }
18563 
18564  return a;
18565 };
18566 
18567 
18568 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18569  * Rows
18570  *
18571  * {}          - no selector - use all available rows
18572  * {integer}   - row aoData index
18573  * {node}      - TR node
18574  * {string}    - jQuery selector to apply to the TR elements
18575  * {array}     - jQuery array of nodes, or simply an array of TR nodes
18576  *
18577  */
18578 
18579 
18580 var __row_selector = function ( settings, selector, opts )
18581 {
18582  var run = function ( sel ) {
18583   var selInt = _intVal( sel );
18584   var i, ien;
18585 
18586   // Short cut - selector is a number and no options provided (default is
18587   // all records, so no need to check if the index is in there, since it
18588   // must be - dev error if the index doesn't exist).
18589   if ( selInt !== null && ! opts ) {
18590    return [ selInt ];
18591   }
18592 
18593   var rows = _selector_row_indexes( settings, opts );
18594 
18595   if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
18596    // Selector - integer
18597    return [ selInt ];
18598   }
18599   else if ( ! sel ) {
18600    // Selector - none
18601    return rows;
18602   }
18603 
18604   // Selector - function
18605   if ( typeof sel === 'function' ) {
18606    return $.map( rows, function (idx) {
18607     var row = settings.aoData[ idx ];
18608     return sel( idx, row._aData, row.nTr ) ? idx : null;
18609    } );
18610   }
18611 
18612   // Get nodes in the order from the `rows` array with null values removed
18613   var nodes = _removeEmpty(
18614    _pluck_order( settings.aoData, rows, 'nTr' )
18615   );
18616 
18617   // Selector - node
18618   if ( sel.nodeName ) {
18619    if ( sel._DT_RowIndex !== undefined ) {
18620     return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
18621    }
18622    else if ( sel._DT_CellIndex ) {
18623     return [ sel._DT_CellIndex.row ];
18624    }
18625    else {
18626     var host = $(sel).closest('*[data-dt-row]');
18627     return host.length ?
18628      [ host.data('dt-row') ] :
18629      [];
18630    }
18631   }
18632 
18633   // ID selector. Want to always be able to select rows by id, regardless
18634   // of if the tr element has been created or not, so can't rely upon
18635   // jQuery here - hence a custom implementation. This does not match
18636   // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
18637   // but to select it using a CSS selector engine (like Sizzle or
18638   // querySelect) it would need to need to be escaped for some characters.
18639   // DataTables simplifies this for row selectors since you can select
18640   // only a row. A # indicates an id any anything that follows is the id -
18641   // unescaped.
18642   if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
18643    // get row index from id
18644    var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
18645    if ( rowObj !== undefined ) {
18646     return [ rowObj.idx ];
18647    }
18648 
18649    // need to fall through to jQuery in case there is DOM id that
18650    // matches
18651   }
18652 
18653   // Selector - jQuery selector string, array of nodes or jQuery object/
18654   // As jQuery's .filter() allows jQuery objects to be passed in filter,
18655   // it also allows arrays, so this will cope with all three options
18656   return $(nodes)
18657    .filter( sel )
18658    .map( function () {
18659     return this._DT_RowIndex;
18660    } )
18661    .toArray();
18662  };
18663 
18664  return _selector_run( 'row', selector, run, settings, opts );
18665 };
18666 
18667 
18668 _api_register( 'rows()', function ( selector, opts ) {
18669  // argument shifting
18670  if ( selector === undefined ) {
18671   selector = '';
18672  }
18673  else if ( $.isPlainObject( selector ) ) {
18674   opts = selector;
18675   selector = '';
18676  }
18677 
18678  opts = _selector_opts( opts );
18679 
18680  var inst = this.iterator( 'table', function ( settings ) {
18681   return __row_selector( settings, selector, opts );
18682  }, 1 );
18683 
18684  // Want argument shifting here and in __row_selector?
18685  inst.selector.rows = selector;
18686  inst.selector.opts = opts;
18687 
18688  return inst;
18689 } );
18690 
18691 _api_register( 'rows().nodes()', function () {
18692  return this.iterator( 'row', function ( settings, row ) {
18693   return settings.aoData[ row ].nTr || undefined;
18694  }, 1 );
18695 } );
18696 
18697 _api_register( 'rows().data()', function () {
18698  return this.iterator( true, 'rows', function ( settings, rows ) {
18699   return _pluck_order( settings.aoData, rows, '_aData' );
18700  }, 1 );
18701 } );
18702 
18703 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
18704  return this.iterator( 'row', function ( settings, row ) {
18705   var r = settings.aoData[ row ];
18706   return type === 'search' ? r._aFilterData : r._aSortData;
18707  }, 1 );
18708 } );
18709 
18710 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
18711  return this.iterator( 'row', function ( settings, row ) {
18712   _fnInvalidate( settings, row, src );
18713  } );
18714 } );
18715 
18716 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
18717  return this.iterator( 'row', function ( settings, row ) {
18718   return row;
18719  }, 1 );
18720 } );
18721 
18722 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
18723  var a = [];
18724  var context = this.context;
18725 
18726  // `iterator` will drop undefined values, but in this case we want them
18727  for ( var i=0, ien=context.length ; i<ien ; i++ ) {
18728   for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
18729    var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
18730    a.push( (hash === true ? '#' : '' )+ id );
18731   }
18732  }
18733 
18734  return new _Api( context, a );
18735 } );
18736 
18737 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
18738  var that = this;
18739 
18740  this.iterator( 'row', function ( settings, row, thatIdx ) {
18741   var data = settings.aoData;
18742   var rowData = data[ row ];
18743   var i, ien, j, jen;
18744   var loopRow, loopCells;
18745 
18746   data.splice( row, 1 );
18747 
18748   // Update the cached indexes
18749   for ( i=0, ien=data.length ; i<ien ; i++ ) {
18750    loopRow = data[i];
18751    loopCells = loopRow.anCells;
18752 
18753    // Rows
18754    if ( loopRow.nTr !== null ) {
18755     loopRow.nTr._DT_RowIndex = i;
18756    }
18757 
18758    // Cells
18759    if ( loopCells !== null ) {
18760     for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
18761      loopCells[j]._DT_CellIndex.row = i;
18762     }
18763    }
18764   }
18765 
18766   // Delete from the display arrays
18767   _fnDeleteIndex( settings.aiDisplayMaster, row );
18768   _fnDeleteIndex( settings.aiDisplay, row );
18769   _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
18770 
18771   // Check for an 'overflow' they case for displaying the table
18772   _fnLengthOverflow( settings );
18773 
18774   // Remove the row's ID reference if there is one
18775   var id = settings.rowIdFn( rowData._aData );
18776   if ( id !== undefined ) {
18777    delete settings.aIds[ id ];
18778   }
18779  } );
18780 
18781  this.iterator( 'table', function ( settings ) {
18782   for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
18783    settings.aoData[i].idx = i;
18784   }
18785  } );
18786 
18787  return this;
18788 } );
18789 
18790 
18791 _api_register( 'rows.add()', function ( rows ) {
18792  var newRows = this.iterator( 'table', function ( settings ) {
18793    var row, i, ien;
18794    var out = [];
18795 
18796    for ( i=0, ien=rows.length ; i<ien ; i++ ) {
18797     row = rows[i];
18798 
18799     if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
18800      out.push( _fnAddTr( settings, row )[0] );
18801     }
18802     else {
18803      out.push( _fnAddData( settings, row ) );
18804     }
18805    }
18806 
18807    return out;
18808   }, 1 );
18809 
18810  // Return an Api.rows() extended instance, so rows().nodes() etc can be used
18811  var modRows = this.rows( -1 );
18812  modRows.pop();
18813  $.merge( modRows, newRows );
18814 
18815  return modRows;
18816 } );
18817 
18818 
18819 
18820 
18821 
18822 /**
18823  *
18824  */
18825 _api_register( 'row()', function ( selector, opts ) {
18826  return _selector_first( this.rows( selector, opts ) );
18827 } );
18828 
18829 
18830 _api_register( 'row().data()', function ( data ) {
18831  var ctx = this.context;
18832 
18833  if ( data === undefined ) {
18834   // Get
18835   return ctx.length && this.length ?
18836    ctx[0].aoData[ this[0] ]._aData :
18837    undefined;
18838  }
18839 
18840  // Set
18841  ctx[0].aoData[ this[0] ]._aData = data;
18842 
18843  // Automatically invalidate
18844  _fnInvalidate( ctx[0], this[0], 'data' );
18845 
18846  return this;
18847 } );
18848 
18849 
18850 _api_register( 'row().node()', function () {
18851  var ctx = this.context;
18852 
18853  return ctx.length && this.length ?
18854   ctx[0].aoData[ this[0] ].nTr || null :
18855   null;
18856 } );
18857 
18858 
18859 _api_register( 'row.add()', function ( row ) {
18860  // Allow a jQuery object to be passed in - only a single row is added from
18861  // it though - the first element in the set
18862  if ( row instanceof $ && row.length ) {
18863   row = row[0];
18864  }
18865 
18866  var rows = this.iterator( 'table', function ( settings ) {
18867   if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
18868    return _fnAddTr( settings, row )[0];
18869   }
18870   return _fnAddData( settings, row );
18871  } );
18872 
18873  // Return an Api.rows() extended instance, with the newly added row selected
18874  return this.row( rows[0] );
18875 } );
18876 
18877 
18878 
18879 var __details_add = function ( ctx, row, data, klass )
18880 {
18881  // Convert to array of TR elements
18882  var rows = [];
18883  var addRow = function ( r, k ) {
18884   // Recursion to allow for arrays of jQuery objects
18885   if ( $.isArray( r ) || r instanceof $ ) {
18886    for ( var i=0, ien=r.length ; i<ien ; i++ ) {
18887     addRow( r[i], k );
18888    }
18889    return;
18890   }
18891 
18892   // If we get a TR element, then just add it directly - up to the dev
18893   // to add the correct number of columns etc
18894   if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
18895    rows.push( r );
18896   }
18897   else {
18898    // Otherwise create a row with a wrapper
18899    var created = $('<tr><td/></tr>').addClass( k );
18900    $('td', created)
18901     .addClass( k )
18902     .html( r )
18903     [0].colSpan = _fnVisbleColumns( ctx );
18904 
18905    rows.push( created[0] );
18906   }
18907  };
18908 
18909  addRow( data, klass );
18910 
18911  if ( row._details ) {
18912   row._details.remove();
18913  }
18914 
18915  row._details = $(rows);
18916 
18917  // If the children were already shown, that state should be retained
18918  if ( row._detailsShow ) {
18919   row._details.insertAfter( row.nTr );
18920  }
18921 };
18922 
18923 
18924 var __details_remove = function ( api, idx )
18925 {
18926  var ctx = api.context;
18927 
18928  if ( ctx.length ) {
18929   var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
18930 
18931   if ( row && row._details ) {
18932    row._details.remove();
18933 
18934    row._detailsShow = undefined;
18935    row._details = undefined;
18936   }
18937  }
18938 };
18939 
18940 
18941 var __details_display = function ( api, show ) {
18942  var ctx = api.context;
18943 
18944  if ( ctx.length && api.length ) {
18945   var row = ctx[0].aoData[ api[0] ];
18946 
18947   if ( row._details ) {
18948    row._detailsShow = show;
18949 
18950    if ( show ) {
18951     row._details.insertAfter( row.nTr );
18952    }
18953    else {
18954     row._details.detach();
18955    }
18956 
18957    __details_events( ctx[0] );
18958   }
18959  }
18960 };
18961 
18962 
18963 var __details_events = function ( settings )
18964 {
18965  var api = new _Api( settings );
18966  var namespace = '.dt.DT_details';
18967  var drawEvent = 'draw'+namespace;
18968  var colvisEvent = 'column-visibility'+namespace;
18969  var destroyEvent = 'destroy'+namespace;
18970  var data = settings.aoData;
18971 
18972  api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
18973 
18974  if ( _pluck( data, '_details' ).length > 0 ) {
18975   // On each draw, insert the required elements into the document
18976   api.on( drawEvent, function ( e, ctx ) {
18977    if ( settings !== ctx ) {
18978     return;
18979    }
18980 
18981    api.rows( {page:'current'} ).eq(0).each( function (idx) {
18982     // Internal data grab
18983     var row = data[ idx ];
18984 
18985     if ( row._detailsShow ) {
18986      row._details.insertAfter( row.nTr );
18987     }
18988    } );
18989   } );
18990 
18991   // Column visibility change - update the colspan
18992   api.on( colvisEvent, function ( e, ctx, idx, vis ) {
18993    if ( settings !== ctx ) {
18994     return;
18995    }
18996 
18997    // Update the colspan for the details rows (note, only if it already has
18998    // a colspan)
18999    var row, visible = _fnVisbleColumns( ctx );
19000 
19001    for ( var i=0, ien=data.length ; i<ien ; i++ ) {
19002     row = data[i];
19003 
19004     if ( row._details ) {
19005      row._details.children('td[colspan]').attr('colspan', visible );
19006     }
19007    }
19008   } );
19009 
19010   // Table destroyed - nuke any child rows
19011   api.on( destroyEvent, function ( e, ctx ) {
19012    if ( settings !== ctx ) {
19013     return;
19014    }
19015 
19016    for ( var i=0, ien=data.length ; i<ien ; i++ ) {
19017     if ( data[i]._details ) {
19018      __details_remove( api, i );
19019     }
19020    }
19021   } );
19022  }
19023 };
19024 
19025 // Strings for the method names to help minification
19026 var _emp = '';
19027 var _child_obj = _emp+'row().child';
19028 var _child_mth = _child_obj+'()';
19029 
19030 // data can be:
19031 //  tr
19032 //  string
19033 //  jQuery or array of any of the above
19034 _api_register( _child_mth, function ( data, klass ) {
19035  var ctx = this.context;
19036 
19037  if ( data === undefined ) {
19038   // get
19039   return ctx.length && this.length ?
19040    ctx[0].aoData[ this[0] ]._details :
19041    undefined;
19042  }
19043  else if ( data === true ) {
19044   // show
19045   this.child.show();
19046  }
19047  else if ( data === false ) {
19048   // remove
19049   __details_remove( this );
19050  }
19051  else if ( ctx.length && this.length ) {
19052   // set
19053   __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
19054  }
19055 
19056  return this;
19057 } );
19058 
19059 
19060 _api_register( [
19061  _child_obj+'.show()',
19062  _child_mth+'.show()' // only when `child()` was called with parameters (without
19063 ], function ( show ) {   // it returns an object and this method is not executed)
19064  __details_display( this, true );
19065  return this;
19066 } );
19067 
19068 
19069 _api_register( [
19070  _child_obj+'.hide()',
19071  _child_mth+'.hide()' // only when `child()` was called with parameters (without
19072 ], function () {         // it returns an object and this method is not executed)
19073  __details_display( this, false );
19074  return this;
19075 } );
19076 
19077 
19078 _api_register( [
19079  _child_obj+'.remove()',
19080  _child_mth+'.remove()' // only when `child()` was called with parameters (without
19081 ], function () {           // it returns an object and this method is not executed)
19082  __details_remove( this );
19083  return this;
19084 } );
19085 
19086 
19087 _api_register( _child_obj+'.isShown()', function () {
19088  var ctx = this.context;
19089 
19090  if ( ctx.length && this.length ) {
19091   // _detailsShown as false or undefined will fall through to return false
19092   return ctx[0].aoData[ this[0] ]._detailsShow || false;
19093  }
19094  return false;
19095 } );
19096 
19097 
19098 
19099 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19100  * Columns
19101  *
19102  * {integer}           - column index (>=0 count from left, <0 count from right)
19103  * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
19104  * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
19105  * "{string}:name"     - column name
19106  * "{string}"          - jQuery selector on column header nodes
19107  *
19108  */
19109 
19110 // can be an array of these items, comma separated list, or an array of comma
19111 // separated lists
19112 
19113 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
19114 
19115 
19116 // r1 and r2 are redundant - but it means that the parameters match for the
19117 // iterator callback in columns().data()
19118 var __columnData = function ( settings, column, r1, r2, rows ) {
19119  var a = [];
19120  for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
19121   a.push( _fnGetCellData( settings, rows[row], column ) );
19122  }
19123  return a;
19124 };
19125 
19126 
19127 var __column_selector = function ( settings, selector, opts )
19128 {
19129  var
19130   columns = settings.aoColumns,
19131   names = _pluck( columns, 'sName' ),
19132   nodes = _pluck( columns, 'nTh' );
19133 
19134  var run = function ( s ) {
19135   var selInt = _intVal( s );
19136 
19137   // Selector - all
19138   if ( s === '' ) {
19139    return _range( columns.length );
19140   }
19141 
19142   // Selector - index
19143   if ( selInt !== null ) {
19144    return [ selInt >= 0 ?
19145     selInt : // Count from left
19146     columns.length + selInt // Count from right (+ because its a negative value)
19147    ];
19148   }
19149 
19150   // Selector = function
19151   if ( typeof s === 'function' ) {
19152    var rows = _selector_row_indexes( settings, opts );
19153 
19154    return $.map( columns, function (col, idx) {
19155     return s(
19156       idx,
19157       __columnData( settings, idx, 0, 0, rows ),
19158       nodes[ idx ]
19159      ) ? idx : null;
19160    } );
19161   }
19162 
19163   // jQuery or string selector
19164   var match = typeof s === 'string' ?
19165    s.match( __re_column_selector ) :
19166    '';
19167 
19168   if ( match ) {
19169    switch( match[2] ) {
19170     case 'visIdx':
19171     case 'visible':
19172      var idx = parseInt( match[1], 10 );
19173      // Visible index given, convert to column index
19174      if ( idx < 0 ) {
19175       // Counting from the right
19176       var visColumns = $.map( columns, function (col,i) {
19177        return col.bVisible ? i : null;
19178       } );
19179       return [ visColumns[ visColumns.length + idx ] ];
19180      }
19181      // Counting from the left
19182      return [ _fnVisibleToColumnIndex( settings, idx ) ];
19183 
19184     case 'name':
19185      // match by name. `names` is column index complete and in order
19186      return $.map( names, function (name, i) {
19187       return name === match[1] ? i : null;
19188      } );
19189 
19190     default:
19191      return [];
19192    }
19193   }
19194 
19195   // Cell in the table body
19196   if ( s.nodeName && s._DT_CellIndex ) {
19197    return [ s._DT_CellIndex.column ];
19198   }
19199 
19200   // jQuery selector on the TH elements for the columns
19201   var jqResult = $( nodes )
19202    .filter( s )
19203    .map( function () {
19204     return $.inArray( this, nodes ); // `nodes` is column index complete and in order
19205    } )
19206    .toArray();
19207 
19208   if ( jqResult.length || ! s.nodeName ) {
19209    return jqResult;
19210   }
19211 
19212   // Otherwise a node which might have a `dt-column` data attribute, or be
19213   // a child or such an element
19214   var host = $(s).closest('*[data-dt-column]');
19215   return host.length ?
19216    [ host.data('dt-column') ] :
19217    [];
19218  };
19219 
19220  return _selector_run( 'column', selector, run, settings, opts );
19221 };
19222 
19223 
19224 var __setColumnVis = function ( settings, column, vis ) {
19225  var
19226   cols = settings.aoColumns,
19227   col  = cols[ column ],
19228   data = settings.aoData,
19229   row, cells, i, ien, tr;
19230 
19231  // Get
19232  if ( vis === undefined ) {
19233   return col.bVisible;
19234  }
19235 
19236  // Set
19237  // No change
19238  if ( col.bVisible === vis ) {
19239   return;
19240  }
19241 
19242  if ( vis ) {
19243   // Insert column
19244   // Need to decide if we should use appendChild or insertBefore
19245   var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
19246 
19247   for ( i=0, ien=data.length ; i<ien ; i++ ) {
19248    tr = data[i].nTr;
19249    cells = data[i].anCells;
19250 
19251    if ( tr ) {
19252     // insertBefore can act like appendChild if 2nd arg is null
19253     tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
19254    }
19255   }
19256  }
19257  else {
19258   // Remove column
19259   $( _pluck( settings.aoData, 'anCells', column ) ).detach();
19260  }
19261 
19262  // Common actions
19263  col.bVisible = vis;
19264  _fnDrawHead( settings, settings.aoHeader );
19265  _fnDrawHead( settings, settings.aoFooter );
19266 
19267  _fnSaveState( settings );
19268 };
19269 
19270 
19271 _api_register( 'columns()', function ( selector, opts ) {
19272  // argument shifting
19273  if ( selector === undefined ) {
19274   selector = '';
19275  }
19276  else if ( $.isPlainObject( selector ) ) {
19277   opts = selector;
19278   selector = '';
19279  }
19280 
19281  opts = _selector_opts( opts );
19282 
19283  var inst = this.iterator( 'table', function ( settings ) {
19284   return __column_selector( settings, selector, opts );
19285  }, 1 );
19286 
19287  // Want argument shifting here and in _row_selector?
19288  inst.selector.cols = selector;
19289  inst.selector.opts = opts;
19290 
19291  return inst;
19292 } );
19293 
19294 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
19295  return this.iterator( 'column', function ( settings, column ) {
19296   return settings.aoColumns[column].nTh;
19297  }, 1 );
19298 } );
19299 
19300 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
19301  return this.iterator( 'column', function ( settings, column ) {
19302   return settings.aoColumns[column].nTf;
19303  }, 1 );
19304 } );
19305 
19306 _api_registerPlural( 'columns().data()', 'column().data()', function () {
19307  return this.iterator( 'column-rows', __columnData, 1 );
19308 } );
19309 
19310 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
19311  return this.iterator( 'column', function ( settings, column ) {
19312   return settings.aoColumns[column].mData;
19313  }, 1 );
19314 } );
19315 
19316 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
19317  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
19318   return _pluck_order( settings.aoData, rows,
19319    type === 'search' ? '_aFilterData' : '_aSortData', column
19320   );
19321  }, 1 );
19322 } );
19323 
19324 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
19325  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
19326   return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
19327  }, 1 );
19328 } );
19329 
19330 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
19331  var ret = this.iterator( 'column', function ( settings, column ) {
19332   if ( vis === undefined ) {
19333    return settings.aoColumns[ column ].bVisible;
19334   } // else
19335   __setColumnVis( settings, column, vis );
19336  } );
19337 
19338  // Group the column visibility changes
19339  if ( vis !== undefined ) {
19340   // Second loop once the first is done for events
19341   this.iterator( 'column', function ( settings, column ) {
19342    _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
19343   } );
19344 
19345   if ( calc === undefined || calc ) {
19346    this.columns.adjust();
19347   }
19348  }
19349 
19350  return ret;
19351 } );
19352 
19353 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
19354  return this.iterator( 'column', function ( settings, column ) {
19355   return type === 'visible' ?
19356    _fnColumnIndexToVisible( settings, column ) :
19357    column;
19358  }, 1 );
19359 } );
19360 
19361 _api_register( 'columns.adjust()', function () {
19362  return this.iterator( 'table', function ( settings ) {
19363   _fnAdjustColumnSizing( settings );
19364  }, 1 );
19365 } );
19366 
19367 _api_register( 'column.index()', function ( type, idx ) {
19368  if ( this.context.length !== 0 ) {
19369   var ctx = this.context[0];
19370 
19371   if ( type === 'fromVisible' || type === 'toData' ) {
19372    return _fnVisibleToColumnIndex( ctx, idx );
19373   }
19374   else if ( type === 'fromData' || type === 'toVisible' ) {
19375    return _fnColumnIndexToVisible( ctx, idx );
19376   }
19377  }
19378 } );
19379 
19380 _api_register( 'column()', function ( selector, opts ) {
19381  return _selector_first( this.columns( selector, opts ) );
19382 } );
19383 
19384 
19385 
19386 var __cell_selector = function ( settings, selector, opts )
19387 {
19388  var data = settings.aoData;
19389  var rows = _selector_row_indexes( settings, opts );
19390  var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
19391  var allCells = $( [].concat.apply([], cells) );
19392  var row;
19393  var columns = settings.aoColumns.length;
19394  var a, i, ien, j, o, host;
19395 
19396  var run = function ( s ) {
19397   var fnSelector = typeof s === 'function';
19398 
19399   if ( s === null || s === undefined || fnSelector ) {
19400    // All cells and function selectors
19401    a = [];
19402 
19403    for ( i=0, ien=rows.length ; i<ien ; i++ ) {
19404     row = rows[i];
19405 
19406     for ( j=0 ; j<columns ; j++ ) {
19407      o = {
19408       row: row,
19409       column: j
19410      };
19411 
19412      if ( fnSelector ) {
19413       // Selector - function
19414       host = data[ row ];
19415 
19416       if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
19417        a.push( o );
19418       }
19419      }
19420      else {
19421       // Selector - all
19422       a.push( o );
19423      }
19424     }
19425    }
19426 
19427    return a;
19428   }
19429   
19430   // Selector - index
19431   if ( $.isPlainObject( s ) ) {
19432    return [s];
19433   }
19434 
19435   // Selector - jQuery filtered cells
19436   var jqResult = allCells
19437    .filter( s )
19438    .map( function (i, el) {
19439     return { // use a new object, in case someone changes the values
19440      row:    el._DT_CellIndex.row,
19441      column: el._DT_CellIndex.column
19442      };
19443    } )
19444    .toArray();
19445 
19446   if ( jqResult.length || ! s.nodeName ) {
19447    return jqResult;
19448   }
19449 
19450   // Otherwise the selector is a node, and there is one last option - the
19451   // element might be a child of an element which has dt-row and dt-column
19452   // data attributes
19453   host = $(s).closest('*[data-dt-row]');
19454   return host.length ?
19455    [ {
19456     row: host.data('dt-row'),
19457     column: host.data('dt-column')
19458    } ] :
19459    [];
19460  };
19461 
19462  return _selector_run( 'cell', selector, run, settings, opts );
19463 };
19464 
19465 
19466 
19467 
19468 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
19469  // Argument shifting
19470  if ( $.isPlainObject( rowSelector ) ) {
19471   // Indexes
19472   if ( rowSelector.row === undefined ) {
19473    // Selector options in first parameter
19474    opts = rowSelector;
19475    rowSelector = null;
19476   }
19477   else {
19478    // Cell index objects in first parameter
19479    opts = columnSelector;
19480    columnSelector = null;
19481   }
19482  }
19483  if ( $.isPlainObject( columnSelector ) ) {
19484   opts = columnSelector;
19485   columnSelector = null;
19486  }
19487 
19488  // Cell selector
19489  if ( columnSelector === null || columnSelector === undefined ) {
19490   return this.iterator( 'table', function ( settings ) {
19491    return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
19492   } );
19493  }
19494 
19495  // Row + column selector
19496  var columns = this.columns( columnSelector, opts );
19497  var rows = this.rows( rowSelector, opts );
19498  var a, i, ien, j, jen;
19499 
19500  var cells = this.iterator( 'table', function ( settings, idx ) {
19501   a = [];
19502 
19503   for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
19504    for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
19505     a.push( {
19506      row:    rows[idx][i],
19507      column: columns[idx][j]
19508     } );
19509    }
19510   }
19511 
19512   return a;
19513  }, 1 );
19514 
19515  $.extend( cells.selector, {
19516   cols: columnSelector,
19517   rows: rowSelector,
19518   opts: opts
19519  } );
19520 
19521  return cells;
19522 } );
19523 
19524 
19525 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
19526  return this.iterator( 'cell', function ( settings, row, column ) {
19527   var data = settings.aoData[ row ];
19528 
19529   return data && data.anCells ?
19530    data.anCells[ column ] :
19531    undefined;
19532  }, 1 );
19533 } );
19534 
19535 
19536 _api_register( 'cells().data()', function () {
19537  return this.iterator( 'cell', function ( settings, row, column ) {
19538   return _fnGetCellData( settings, row, column );
19539  }, 1 );
19540 } );
19541 
19542 
19543 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
19544  type = type === 'search' ? '_aFilterData' : '_aSortData';
19545 
19546  return this.iterator( 'cell', function ( settings, row, column ) {
19547   return settings.aoData[ row ][ type ][ column ];
19548  }, 1 );
19549 } );
19550 
19551 
19552 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
19553  return this.iterator( 'cell', function ( settings, row, column ) {
19554   return _fnGetCellData( settings, row, column, type );
19555  }, 1 );
19556 } );
19557 
19558 
19559 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
19560  return this.iterator( 'cell', function ( settings, row, column ) {
19561   return {
19562    row: row,
19563    column: column,
19564    columnVisible: _fnColumnIndexToVisible( settings, column )
19565   };
19566  }, 1 );
19567 } );
19568 
19569 
19570 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
19571  return this.iterator( 'cell', function ( settings, row, column ) {
19572   _fnInvalidate( settings, row, src, column );
19573  } );
19574 } );
19575 
19576 
19577 
19578 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
19579  return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
19580 } );
19581 
19582 
19583 _api_register( 'cell().data()', function ( data ) {
19584  var ctx = this.context;
19585  var cell = this[0];
19586 
19587  if ( data === undefined ) {
19588   // Get
19589   return ctx.length && cell.length ?
19590    _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
19591    undefined;
19592  }
19593 
19594  // Set
19595  _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
19596  _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
19597 
19598  return this;
19599 } );
19600 
19601 
19602 
19603 /**
19604  * Get current ordering (sorting) that has been applied to the table.
19605  *
19606  * @returns {array} 2D array containing the sorting information for the first
19607  *   table in the current context. Each element in the parent array represents
19608  *   a column being sorted upon (i.e. multi-sorting with two columns would have
19609  *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
19610  *   the column index that the sorting condition applies to, the second is the
19611  *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
19612  *   index of the sorting order from the `column.sorting` initialisation array.
19613  *//**
19614  * Set the ordering for the table.
19615  *
19616  * @param {integer} order Column index to sort upon.
19617  * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
19618  * @returns {DataTables.Api} this
19619  *//**
19620  * Set the ordering for the table.
19621  *
19622  * @param {array} order 1D array of sorting information to be applied.
19623  * @param {array} [...] Optional additional sorting conditions
19624  * @returns {DataTables.Api} this
19625  *//**
19626  * Set the ordering for the table.
19627  *
19628  * @param {array} order 2D array of sorting information to be applied.
19629  * @returns {DataTables.Api} this
19630  */
19631 _api_register( 'order()', function ( order, dir ) {
19632  var ctx = this.context;
19633 
19634  if ( order === undefined ) {
19635   // get
19636   return ctx.length !== 0 ?
19637    ctx[0].aaSorting :
19638    undefined;
19639  }
19640 
19641  // set
19642  if ( typeof order === 'number' ) {
19643   // Simple column / direction passed in
19644   order = [ [ order, dir ] ];
19645  }
19646  else if ( order.length && ! $.isArray( order[0] ) ) {
19647   // Arguments passed in (list of 1D arrays)
19648   order = Array.prototype.slice.call( arguments );
19649  }
19650  // otherwise a 2D array was passed in
19651 
19652  return this.iterator( 'table', function ( settings ) {
19653   settings.aaSorting = order.slice();
19654  } );
19655 } );
19656 
19657 
19658 /**
19659  * Attach a sort listener to an element for a given column
19660  *
19661  * @param {node|jQuery|string} node Identifier for the element(s) to attach the
19662  *   listener to. This can take the form of a single DOM node, a jQuery
vendor: 9,293 bytes, lines 19663-20015
19663  *   collection of nodes or a jQuery selector which will identify the node(s).
19664  * @param {integer} column the column that a click on this node will sort on
19665  * @param {function} [callback] callback function when sort is run
19666  * @returns {DataTables.Api} this
19667  */
19668 _api_register( 'order.listener()', function ( node, column, callback ) {
19669  return this.iterator( 'table', function ( settings ) {
19670   _fnSortAttachListener( settings, node, column, callback );
19671  } );
19672 } );
19673 
19674 
19675 _api_register( 'order.fixed()', function ( set ) {
19676  if ( ! set ) {
19677   var ctx = this.context;
19678   var fixed = ctx.length ?
19679    ctx[0].aaSortingFixed :
19680    undefined;
19681 
19682   return $.isArray( fixed ) ?
19683    { pre: fixed } :
19684    fixed;
19685  }
19686 
19687  return this.iterator( 'table', function ( settings ) {
19688   settings.aaSortingFixed = $.extend( true, {}, set );
19689  } );
19690 } );
19691 
19692 
19693 // Order by the selected column(s)
19694 _api_register( [
19695  'columns().order()',
19696  'column().order()'
19697 ], function ( dir ) {
19698  var that = this;
19699 
19700  return this.iterator( 'table', function ( settings, i ) {
19701   var sort = [];
19702 
19703   $.each( that[i], function (j, col) {
19704    sort.push( [ col, dir ] );
19705   } );
19706 
19707   settings.aaSorting = sort;
19708  } );
19709 } );
19710 
19711 
19712 
19713 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
19714  var ctx = this.context;
19715 
19716  if ( input === undefined ) {
19717   // get
19718   return ctx.length !== 0 ?
19719    ctx[0].oPreviousSearch.sSearch :
19720    undefined;
19721  }
19722 
19723  // set
19724  return this.iterator( 'table', function ( settings ) {
19725   if ( ! settings.oFeatures.bFilter ) {
19726    return;
19727   }
19728 
19729   _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
19730    "sSearch": input+"",
19731    "bRegex":  regex === null ? false : regex,
19732    "bSmart":  smart === null ? true  : smart,
19733    "bCaseInsensitive": caseInsen === null ? true : caseInsen
19734   } ), 1 );
19735  } );
19736 } );
19737 
19738 
19739 _api_registerPlural(
19740  'columns().search()',
19741  'column().search()',
19742  function ( input, regex, smart, caseInsen ) {
19743   return this.iterator( 'column', function ( settings, column ) {
19744    var preSearch = settings.aoPreSearchCols;
19745 
19746    if ( input === undefined ) {
19747     // get
19748     return preSearch[ column ].sSearch;
19749    }
19750 
19751    // set
19752    if ( ! settings.oFeatures.bFilter ) {
19753     return;
19754    }
19755 
19756    $.extend( preSearch[ column ], {
19757     "sSearch": input+"",
19758     "bRegex":  regex === null ? false : regex,
19759     "bSmart":  smart === null ? true  : smart,
19760     "bCaseInsensitive": caseInsen === null ? true : caseInsen
19761    } );
19762 
19763    _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
19764   } );
19765  }
19766 );
19767 
19768 /*
19769  * State API methods
19770  */
19771 
19772 _api_register( 'state()', function () {
19773  return this.context.length ?
19774   this.context[0].oSavedState :
19775   null;
19776 } );
19777 
19778 
19779 _api_register( 'state.clear()', function () {
19780  return this.iterator( 'table', function ( settings ) {
19781   // Save an empty object
19782   settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
19783  } );
19784 } );
19785 
19786 
19787 _api_register( 'state.loaded()', function () {
19788  return this.context.length ?
19789   this.context[0].oLoadedState :
19790   null;
19791 } );
19792 
19793 
19794 _api_register( 'state.save()', function () {
19795  return this.iterator( 'table', function ( settings ) {
19796   _fnSaveState( settings );
19797  } );
19798 } );
19799 
19800 
19801 
19802 /**
19803  * Provide a common method for plug-ins to check the version of DataTables being
19804  * used, in order to ensure compatibility.
19805  *
19806  *  @param {string} version Version string to check for, in the format "X.Y.Z".
19807  *    Note that the formats "X" and "X.Y" are also acceptable.
19808  *  @returns {boolean} true if this version of DataTables is greater or equal to
19809  *    the required version, or false if this version of DataTales is not
19810  *    suitable
19811  *  @static
19812  *  @dtopt API-Static
19813  *
19814  *  @example
19815  *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
19816  */
19817 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
19818 {
19819  var aThis = DataTable.version.split('.');
19820  var aThat = version.split('.');
19821  var iThis, iThat;
19822 
19823  for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
19824   iThis = parseInt( aThis[i], 10 ) || 0;
19825   iThat = parseInt( aThat[i], 10 ) || 0;
19826 
19827   // Parts are the same, keep comparing
19828   if (iThis === iThat) {
19829    continue;
19830   }
19831 
19832   // Parts are different, return immediately
19833   return iThis > iThat;
19834  }
19835 
19836  return true;
19837 };
19838 
19839 
19840 /**
19841  * Check if a `<table>` node is a DataTable table already or not.
19842  *
19843  *  @param {node|jquery|string} table Table node, jQuery object or jQuery
19844  *      selector for the table to test. Note that if more than more than one
19845  *      table is passed on, only the first will be checked
19846  *  @returns {boolean} true the table given is a DataTable, or false otherwise
19847  *  @static
19848  *  @dtopt API-Static
19849  *
19850  *  @example
19851  *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
19852  *      $('#example').dataTable();
19853  *    }
19854  */
19855 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
19856 {
19857  var t = $(table).get(0);
19858  var is = false;
19859 
19860  $.each( DataTable.settings, function (i, o) {
19861   var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
19862   var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
19863 
19864   if ( o.nTable === t || head === t || foot === t ) {
19865    is = true;
19866   }
19867  } );
19868 
19869  return is;
19870 };
19871 
19872 
19873 /**
19874  * Get all DataTable tables that have been initialised - optionally you can
19875  * select to get only currently visible tables.
19876  *
19877  *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
19878  *    or visible tables only.
19879  *  @returns {array} Array of `table` nodes (not DataTable instances) which are
19880  *    DataTables
19881  *  @static
19882  *  @dtopt API-Static
19883  *
19884  *  @example
19885  *    $.each( $.fn.dataTable.tables(true), function () {
19886  *      $(table).DataTable().columns.adjust();
19887  *    } );
19888  */
19889 DataTable.tables = DataTable.fnTables = function ( visible )
19890 {
19891  var api = false;
19892 
19893  if ( $.isPlainObject( visible ) ) {
19894   api = visible.api;
19895   visible = visible.visible;
19896  }
19897 
19898  var a = $.map( DataTable.settings, function (o) {
19899   if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
19900    return o.nTable;
19901   }
19902  } );
19903 
19904  return api ?
19905   new _Api( a ) :
19906   a;
19907 };
19908 
19909 
19910 /**
19911  * Convert from camel case parameters to Hungarian notation. This is made public
19912  * for the extensions to provide the same ability as DataTables core to accept
19913  * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
19914  * parameters.
19915  *
19916  *  @param {object} src The model object which holds all parameters that can be
19917  *    mapped.
19918  *  @param {object} user The object to convert from camel case to Hungarian.
19919  *  @param {boolean} force When set to `true`, properties which already have a
19920  *    Hungarian value in the `user` object will be overwritten. Otherwise they
19921  *    won't be.
19922  */
19923 DataTable.camelToHungarian = _fnCamelToHungarian;
19924 
19925 
19926 
19927 /**
19928  *
19929  */
19930 _api_register( '$()', function ( selector, opts ) {
19931  var
19932   rows   = this.rows( opts ).nodes(), // Get all rows
19933   jqRows = $(rows);
19934 
19935  return $( [].concat(
19936   jqRows.filter( selector ).toArray(),
19937   jqRows.find( selector ).toArray()
19938  ) );
19939 } );
19940 
19941 
19942 // jQuery functions to operate on the tables
19943 $.each( [ 'on', 'one', 'off' ], function (i, key) {
19944  _api_register( key+'()', function ( /* event, handler */ ) {
19945   var args = Array.prototype.slice.call(arguments);
19946 
19947   // Add the `dt` namespace automatically if it isn't already present
19948   if ( ! args[0].match(/\.dt\b/) ) {
19949    args[0] += '.dt';
19950   }
19951 
19952   var inst = $( this.tables().nodes() );
19953   inst[key].apply( inst, args );
19954   return this;
19955  } );
19956 } );
19957 
19958 
19959 _api_register( 'clear()', function () {
19960  return this.iterator( 'table', function ( settings ) {
19961   _fnClearTable( settings );
19962  } );
19963 } );
19964 
19965 
19966 _api_register( 'settings()', function () {
19967  return new _Api( this.context, this.context );
19968 } );
19969 
19970 
19971 _api_register( 'init()', function () {
19972  var ctx = this.context;
19973  return ctx.length ? ctx[0].oInit : null;
19974 } );
19975 
19976 
19977 _api_register( 'data()', function () {
19978  return this.iterator( 'table', function ( settings ) {
19979   return _pluck( settings.aoData, '_aData' );
19980  } ).flatten();
19981 } );
19982 
19983 
19984 _api_register( 'destroy()', function ( remove ) {
19985  remove = remove || false;
19986 
19987  return this.iterator( 'table', function ( settings ) {
19988   var orig      = settings.nTableWrapper.parentNode;
19989   var classes   = settings.oClasses;
19990   var table     = settings.nTable;
19991   var tbody     = settings.nTBody;
19992   var thead     = settings.nTHead;
19993   var tfoot     = settings.nTFoot;
19994   var jqTable   = $(table);
19995   var jqTbody   = $(tbody);
19996   var jqWrapper = $(settings.nTableWrapper);
19997   var rows      = $.map( settings.aoData, function (r) { return r.nTr; } );
19998   var i, ien;
19999 
20000   // Flag to note that the table is currently being destroyed - no action
20001   // should be taken
20002   settings.bDestroying = true;
20003 
20004   // Fire off the destroy callbacks for plug-ins etc
20005   _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
20006 
20007   // If not being removed from the document, make all columns visible
20008   if ( ! remove ) {
20009    new _Api( settings ).columns().visible( true );
20010   }
20011 
20012   // Blitz all `DT` namespaced events (these are internal events, the
20013   // lowercase, `dt` events are user subscribed and they are responsible
20014   // for removing them
20015   jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
20016   $(window).unbind('.DT-'+settings.sInstance);
20017 
20018   // When scrolling we had to break the table up - restore it
20019   if ( table != thead.parentNode ) {
20020    jqTable.children('thead').detach();
20021    jqTable.append( thead );
20022   }
20023 
20024   if ( tfoot && table != tfoot.parentNode ) {
20025    jqTable.children('tfoot').detach();
20026    jqTable.append( tfoot );
20027   }
20028 
20029   settings.aaSorting = [];
20030   settings.aaSortingFixed = [];
20031   _fnSortingClasses( settings );
20032 
20033   $( rows ).removeClass( settings.asStripeClasses.join(' ') );
20034 
20035   $('th, td', thead).removeClass( classes.sSortable+' '+
20036    classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
20037   );
20038 
20039   if ( settings.bJUI ) {
20040    $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
20041    $('th, td', thead).each( function () {
20042     var wrapper = $('div.'+classes.sSortJUIWrapper, this);
20043     $(this).append( wrapper.contents() );
20044     wrapper.detach();
20045    } );
20046   }
20047 
20048   // Add the TR elements back into the table in their original order
20049   jqTbody.children().detach();
20050   jqTbody.append( rows );
20051 
20052   // Remove the DataTables generated nodes, events and classes
20053   var removedMethod = remove ? 'remove' : 'detach';
20054   jqTable[ removedMethod ]();
20055   jqWrapper[ removedMethod ]();
20056 
20057   // If we need to reattach the table to the document
20058   if ( ! remove && orig ) {
20059    // insertBefore acts like appendChild if !arg[1]
20060    orig.insertBefore( table, settings.nTableReinsertBefore );
20061 
20062    // Restore the width of the original table - was read from the style property,
20063    // so we can restore directly to that
20064    jqTable
20065     .css( 'width', settings.sDestroyWidth )
20066     .removeClass( classes.sTable );
20067 
20068    // If the were originally stripe classes - then we add them back here.
20069    // Note this is not fool proof (for example if not all rows had stripe
20070    // classes - but it's a good effort without getting carried away
20071    ien = settings.asDestroyStripes.length;
20072 
20073    if ( ien ) {
20074     jqTbody.children().each( function (i) {
20075      $(this).addClass( settings.asDestroyStripes[i % ien] );
20076     } );
20077    }
20078   }
20079 
20080   /* Remove the settings object from the settings array */
20081   var idx = $.inArray( settings, DataTable.settings );
20082   if ( idx !== -1 ) {
20083    DataTable.settings.splice( idx, 1 );
20084   }
20085  } );
20086 } );
20087 
20088 
20089 // Add the `every()` method for rows, columns and cells in a compact form
20090 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
20091  _api_register( type+'s().every()', function ( fn ) {
20092   var opts = this.selector.opts;
20093   var api = this;
20094 
20095   return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
20096    // Rows and columns:
20097    //  arg1 - index
20098    //  arg2 - table counter
20099    //  arg3 - loop counter
20100    //  arg4 - undefined
20101    // Cells:
20102    //  arg1 - row index
20103    //  arg2 - column index
20104    //  arg3 - table counter
20105    //  arg4 - loop counter
20106    fn.call(
20107     api[ type ](
20108      arg1,
20109      type==='cell' ? arg2 : opts,
20110      type==='cell' ? opts : undefined
20111     ),
20112     arg1, arg2, arg3, arg4
20113    );
20114   } );
20115  } );
20116 } );
20117 
20118 
20119 // i18n method for extensions to be able to use the language object from the
20120 // DataTable
20121 _api_register( 'i18n()', function ( token, def, plural ) {
20122  var ctx = this.context[0];
20123  var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
20124 
20125  if ( resolved === undefined ) {
20126   resolved = def;
20127  }
20128 
20129  if ( plural !== undefined && $.isPlainObject( resolved ) ) {
20130   resolved = resolved[ plural ] !== undefined ?
20131    resolved[ plural ] :
20132    resolved._;
20133  }
20134 
20135  return resolved.replace( '%d', plural ); // nb: plural might be undefined,
20136 } );
20137 /**
20138  * Version string for plug-ins to check compatibility. Allowed format is
20139  * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
20140  * only for non-release builds. See http://semver.org/ for more information.
20141  *  @member
20142  *  @type string
20143  *  @default Version number
20144  */
20145 DataTable.version = "1.10.12";
20146 /**
20147  * Private data store, containing all of the settings objects that are
20148  * created for the tables on a given page.
20149  *
20150  * Note that the `DataTable.settings` object is aliased to
20151  * `jQuery.fn.dataTableExt` through which it may be accessed and
20152  * manipulated, or `jQuery.fn.dataTable.settings`.
20153  *  @member
20154  *  @type array
20155  *  @default []
20156  *  @private
20157  */
20158 DataTable.settings = [];
20159 /**
20160  * Object models container, for the various models that DataTables has
20161  * available to it. These models define the objects that are used to hold
20162  * the active state and configuration of the table.
20163  *  @namespace
20164  */
20165 DataTable.models = {};
20166 
20167 
20168 
20169 /**
20170  * Template object for the way in which DataTables holds information about
20171  * search information for the global filter and individual column filters.
20172  *  @namespace
20173  */
20174 DataTable.models.oSearch = {
20175  /**
20176   * Flag to indicate if the filtering should be case insensitive or not
20177   *  @type boolean
20178   *  @default true
20179   */
20180  "bCaseInsensitive": true,
20181 
20182  /**
20183   * Applied search term
20184   *  @type string
20185   *  @default <i>Empty string</i>
20186   */
20187  "sSearch": "",
20188 
20189  /**
20190   * Flag to indicate if the search term should be interpreted as a
20191   * regular expression (true) or not (false) and therefore and special
20192   * regex characters escaped.
20193   *  @type boolean
20194   *  @default false
20195   */
20196  "bRegex": false,
20197 
20198  /**
20199   * Flag to indicate if DataTables is to use its smart filtering or not.
20200   *  @type boolean
20201   *  @default true
20202   */
20203  "bSmart": true
20204 };
20205 
20206 
20207 
20208 
20209 /**
20210  * Template object for the way in which DataTables holds information about
20211  * each individual row. This is the object format used for the settings
20212  * aoData array.
20213  *  @namespace
20214  */
20215 DataTable.models.oRow = {
20216  /**
20217   * TR element for the row
20218   *  @type node
20219   *  @default null
20220   */
20221  "nTr": null,
20222 
20223  /**
20224   * Array of TD elements for each row. This is null until the row has been
20225   * created.
20226   *  @type array nodes
20227   *  @default []
20228   */
20229  "anCells": null,
20230 
20231  /**
20232   * Data object from the original data source for the row. This is either
20233   * an array if using the traditional form of DataTables, or an object if
20234   * using mData options. The exact type will depend on the passed in
20235   * data from the data source, or will be an array if using DOM a data
20236   * source.
20237   *  @type array|object
20238   *  @default []
20239   */
20240  "_aData": [],
20241 
20242  /**
20243   * Sorting data cache - this array is ostensibly the same length as the
20244   * number of columns (although each index is generated only as it is
20245   * needed), and holds the data that is used for sorting each column in the
20246   * row. We do this cache generation at the start of the sort in order that
20247   * the formatting of the sort data need be done only once for each cell
20248   * per sort. This array should not be read from or written to by anything
20249   * other than the master sorting methods.
20250   *  @type array
20251   *  @default null
20252   *  @private
20253   */
20254  "_aSortData": null,
20255 
20256  /**
20257   * Per cell filtering data cache. As per the sort data cache, used to
20258   * increase the performance of the filtering in DataTables
20259   *  @type array
20260   *  @default null
20261   *  @private
20262   */
20263  "_aFilterData": null,
20264 
20265  /**
20266   * Filtering data cache. This is the same as the cell filtering cache, but
20267   * in this case a string rather than an array. This is easily computed with
20268   * a join on `_aFilterData`, but is provided as a cache so the join isn't
20269   * needed on every search (memory traded for performance)
20270   *  @type array
20271   *  @default null
20272   *  @private
20273   */
20274  "_sFilterRow": null,
20275 
20276  /**
20277   * Cache of the class name that DataTables has applied to the row, so we
20278   * can quickly look at this variable rather than needing to do a DOM check
20279   * on className for the nTr property.
20280   *  @type string
20281   *  @default <i>Empty string</i>
20282   *  @private
20283   */
20284  "_sRowStripe": "",
20285 
20286  /**
20287   * Denote if the original data source was from the DOM, or the data source
20288   * object. This is used for invalidating data, so DataTables can
20289   * automatically read data from the original source, unless uninstructed
20290   * otherwise.
20291   *  @type string
20292   *  @default null
20293   *  @private
20294   */
20295  "src": null,
20296 
20297  /**
20298   * Index in the aoData array. This saves an indexOf lookup when we have the
20299   * object, but want to know the index
20300   *  @type integer
20301   *  @default -1
20302   *  @private
20303   */
20304  "idx": -1
20305 };
20306 
20307 
20308 /**
20309  * Template object for the column information object in DataTables. This object
20310  * is held in the settings aoColumns array and contains all the information that
20311  * DataTables needs about each individual column.
20312  *
20313  * Note that this object is related to {@link DataTable.defaults.column}
20314  * but this one is the internal data store for DataTables's cache of columns.
20315  * It should NOT be manipulated outside of DataTables. Any configuration should
20316  * be done through the initialisation options.
20317  *  @namespace
20318  */
20319 DataTable.models.oColumn = {
20320  /**
20321   * Column index. This could be worked out on-the-fly with $.inArray, but it
20322   * is faster to just hold it as a variable
20323   *  @type integer
20324   *  @default null
20325   */
20326  "idx": null,
20327 
20328  /**
20329   * A list of the columns that sorting should occur on when this column
20330   * is sorted. That this property is an array allows multi-column sorting
20331   * to be defined for a column (for example first name / last name columns
20332   * would benefit from this). The values are integers pointing to the
20333   * columns to be sorted on (typically it will be a single integer pointing
20334   * at itself, but that doesn't need to be the case).
20335   *  @type array
20336   */
20337  "aDataSort": null,
20338 
20339  /**
20340   * Define the sorting directions that are applied to the column, in sequence
20341   * as the column is repeatedly sorted upon - i.e. the first value is used
20342   * as the sorting direction when the column if first sorted (clicked on).
20343   * Sort it again (click again) and it will move on to the next index.
20344   * Repeat until loop.
20345   *  @type array
20346   */
20347  "asSorting": null,
20348 
20349  /**
20350   * Flag to indicate if the column is searchable, and thus should be included
20351   * in the filtering or not.
20352   *  @type boolean
20353   */
20354  "bSearchable": null,
20355 
20356  /**
20357   * Flag to indicate if the column is sortable or not.
20358   *  @type boolean
20359   */
20360  "bSortable": null,
20361 
20362  /**
20363   * Flag to indicate if the column is currently visible in the table or not
20364   *  @type boolean
20365   */
20366  "bVisible": null,
20367 
20368  /**
20369   * Store for manual type assignment using the `column.type` option. This
20370   * is held in store so we can manipulate the column's `sType` property.
20371   *  @type string
20372   *  @default null
20373   *  @private
20374   */
20375  "_sManualType": null,
20376 
20377  /**
20378   * Flag to indicate if HTML5 data attributes should be used as the data
20379   * source for filtering or sorting. True is either are.
20380   *  @type boolean
20381   *  @default false
20382   *  @private
20383   */
20384  "_bAttrSrc": false,
20385 
20386  /**
20387   * Developer definable function that is called whenever a cell is created (Ajax source,
20388   * etc) or processed for input (DOM source). This can be used as a compliment to mRender
20389   * allowing you to modify the DOM element (add background colour for example) when the
20390   * element is available.
20391   *  @type function
20392   *  @param {element} nTd The TD node that has been created
20393   *  @param {*} sData The Data for the cell
20394   *  @param {array|object} oData The data for the whole row
20395   *  @param {int} iRow The row index for the aoData data store
20396   *  @default null
20397   */
20398  "fnCreatedCell": null,
20399 
20400  /**
20401   * Function to get data from a cell in a column. You should <b>never</b>
20402   * access data directly through _aData internally in DataTables - always use
20403   * the method attached to this property. It allows mData to function as
20404   * required. This function is automatically assigned by the column
20405   * initialisation method
20406   *  @type function
20407   *  @param {array|object} oData The data array/object for the array
20408   *    (i.e. aoData[]._aData)
20409   *  @param {string} sSpecific The specific data type you want to get -
20410   *    'display', 'type' 'filter' 'sort'
20411   *  @returns {*} The data for the cell from the given row's data
20412   *  @default null
20413   */
20414  "fnGetData": null,
20415 
20416  /**
20417   * Function to set data for a cell in the column. You should <b>never</b>
20418   * set the data directly to _aData internally in DataTables - always use
20419   * this method. It allows mData to function as required. This function
20420   * is automatically assigned by the column initialisation method
20421   *  @type function
20422   *  @param {array|object} oData The data array/object for the array
20423   *    (i.e. aoData[]._aData)
20424   *  @param {*} sValue Value to set
20425   *  @default null
20426   */
20427  "fnSetData": null,
20428 
20429  /**
20430   * Property to read the value for the cells in the column from the data
20431   * source array / object. If null, then the default content is used, if a
20432   * function is given then the return from the function is used.
20433   *  @type function|int|string|null
20434   *  @default null
20435   */
20436  "mData": null,
20437 
20438  /**
20439   * Partner property to mData which is used (only when defined) to get
20440   * the data - i.e. it is basically the same as mData, but without the
20441   * 'set' option, and also the data fed to it is the result from mData.
20442   * This is the rendering method to match the data method of mData.
20443   *  @type function|int|string|null
20444   *  @default null
20445   */
20446  "mRender": null,
20447 
20448  /**
20449   * Unique header TH/TD element for this column - this is what the sorting
20450   * listener is attached to (if sorting is enabled.)
20451   *  @type node
20452   *  @default null
20453   */
20454  "nTh": null,
20455 
20456  /**
20457   * Unique footer TH/TD element for this column (if there is one). Not used
20458   * in DataTables as such, but can be used for plug-ins to reference the
20459   * footer for each column.
20460   *  @type node
20461   *  @default null
20462   */
20463  "nTf": null,
20464 
20465  /**
20466   * The class to apply to all TD elements in the table's TBODY for the column
20467   *  @type string
20468   *  @default null
20469   */
20470  "sClass": null,
20471 
20472  /**
20473   * When DataTables calculates the column widths to assign to each column,
20474   * it finds the longest string in each column and then constructs a
20475   * temporary table and reads the widths from that. The problem with this
20476   * is that "mmm" is much wider then "iiii", but the latter is a longer
20477   * string - thus the calculation can go wrong (doing it properly and putting
20478   * it into an DOM object and measuring that is horribly(!) slow). Thus as
20479   * a "work around" we provide this option. It will append its value to the
20480   * text that is found to be the longest string for the column - i.e. padding.
20481   *  @type string
20482   */
20483  "sContentPadding": null,
20484 
20485  /**
20486   * Allows a default value to be given for a column's data, and will be used
20487   * whenever a null data source is encountered (this can be because mData
20488   * is set to null, or because the data source itself is null).
20489   *  @type string
20490   *  @default null
20491   */
20492  "sDefaultContent": null,
20493 
20494  /**
20495   * Name for the column, allowing reference to the column by name as well as
20496   * by index (needs a lookup to work by name).
20497   *  @type string
20498   */
20499  "sName": null,
20500 
20501  /**
20502   * Custom sorting data type - defines which of the available plug-ins in
20503   * afnSortData the custom sorting will use - if any is defined.
20504   *  @type string
20505   *  @default std
20506   */
20507  "sSortDataType": 'std',
20508 
20509  /**
20510   * Class to be applied to the header element when sorting on this column
20511   *  @type string
20512   *  @default null
20513   */
20514  "sSortingClass": null,
20515 
20516  /**
20517   * Class to be applied to the header element when sorting on this column -
20518   * when jQuery UI theming is used.
20519   *  @type string
20520   *  @default null
20521   */
20522  "sSortingClassJUI": null,
20523 
20524  /**
20525   * Title of the column - what is seen in the TH element (nTh).
20526   *  @type string
20527   */
20528  "sTitle": null,
20529 
20530  /**
20531   * Column sorting and filtering type
20532   *  @type string
20533   *  @default null
20534   */
20535  "sType": null,
20536 
20537  /**
20538   * Width of the column
20539   *  @type string
20540   *  @default null
20541   */
20542  "sWidth": null,
20543 
20544  /**
20545   * Width of the column when it was first "encountered"
20546   *  @type string
20547   *  @default null
20548   */
20549  "sWidthOrig": null
20550 };
20551 
20552 
20553 /*
20554  * Developer note: The properties of the object below are given in Hungarian
20555  * notation, that was used as the interface for DataTables prior to v1.10, however
20556  * from v1.10 onwards the primary interface is camel case. In order to avoid
20557  * breaking backwards compatibility utterly with this change, the Hungarian
20558  * version is still, internally the primary interface, but is is not documented
20559  * - hence the @name tags in each doc comment. This allows a Javascript function
20560  * to create a map from Hungarian notation to camel case (going the other direction
20561  * would require each property to be listed, which would at around 3K to the size
20562  * of DataTables, while this method is about a 0.5K hit.
20563  *
20564  * Ultimately this does pave the way for Hungarian notation to be dropped
20565  * completely, but that is a massive amount of work and will break current
20566  * installs (therefore is on-hold until v2).
20567  */
20568 
20569 /**
20570  * Initialisation options that can be given to DataTables at initialisation
20571  * time.
20572  *  @namespace
20573  */
20574 DataTable.defaults = {
20575  /**
20576   * An array of data to use for the table, passed in at initialisation which
20577   * will be used in preference to any data which is already in the DOM. This is
20578   * particularly useful for constructing tables purely in Javascript, for
20579   * example with a custom Ajax call.
20580   *  @type array
20581   *  @default null
20582   *
20583   *  @dtopt Option
20584   *  @name DataTable.defaults.data
20585   *
20586   *  @example
20587   *    // Using a 2D array data source
20588   *    $(document).ready( function () {
20589   *      $('#example').dataTable( {
20590   *        "data": [
20591   *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
20592   *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
20593   *        ],
20594   *        "columns": [
20595   *          { "title": "Engine" },
20596   *          { "title": "Browser" },
20597   *          { "title": "Platform" },
20598   *          { "title": "Version" },
20599   *          { "title": "Grade" }
20600   *        ]
20601   *      } );
20602   *    } );
20603   *
20604   *  @example
20605   *    // Using an array of objects as a data source (`data`)
20606   *    $(document).ready( function () {
20607   *      $('#example').dataTable( {
20608   *        "data": [
20609   *          {
20610   *            "engine":   "Trident",
20611   *            "browser":  "Internet Explorer 4.0",
20612   *            "platform": "Win 95+",
20613   *            "version":  4,
20614   *            "grade":    "X"
20615   *          },
20616   *          {
20617   *            "engine":   "Trident",
20618   *            "browser":  "Internet Explorer 5.0",
20619   *            "platform": "Win 95+",
20620   *            "version":  5,
20621   *            "grade":    "C"
20622   *          }
20623   *        ],
20624   *        "columns": [
20625   *          { "title": "Engine",   "data": "engine" },
20626   *          { "title": "Browser",  "data": "browser" },
20627   *          { "title": "Platform", "data": "platform" },
20628   *          { "title": "Version",  "data": "version" },
20629   *          { "title": "Grade",    "data": "grade" }
20630   *        ]
20631   *      } );
20632   *    } );
20633   */
20634  "aaData": null,
20635 
20636 
20637  /**
20638   * If ordering is enabled, then DataTables will perform a first pass sort on
20639   * initialisation. You can define which column(s) the sort is performed
20640   * upon, and the sorting direction, with this variable. The `sorting` array
20641   * should contain an array for each column to be sorted initially containing
20642   * the column's index and a direction string ('asc' or 'desc').
20643   *  @type array
20644   *  @default [[0,'asc']]
20645   *
20646   *  @dtopt Option
20647   *  @name DataTable.defaults.order
20648   *
20649   *  @example
20650   *    // Sort by 3rd column first, and then 4th column
20651   *    $(document).ready( function() {
20652   *      $('#example').dataTable( {
20653   *        "order": [[2,'asc'], [3,'desc']]
20654   *      } );
20655   *    } );
20656   *
20657   *    // No initial sorting
20658   *    $(document).ready( function() {
20659   *      $('#example').dataTable( {
20660   *        "order": []
20661   *      } );
20662   *    } );
20663   */
20664  "aaSorting": [[0,'asc']],
20665 
20666 
20667  /**
20668   * This parameter is basically identical to the `sorting` parameter, but
20669   * cannot be overridden by user interaction with the table. What this means
20670   * is that you could have a column (visible or hidden) which the sorting
20671   * will always be forced on first - any sorting after that (from the user)
20672   * will then be performed as required. This can be useful for grouping rows
20673   * together.
20674   *  @type array
20675   *  @default null
20676   *
20677   *  @dtopt Option
20678   *  @name DataTable.defaults.orderFixed
20679   *
20680   *  @example
20681   *    $(document).ready( function() {
20682   *      $('#example').dataTable( {
20683   *        "orderFixed": [[0,'asc']]
20684   *      } );
20685   *    } )
20686   */
20687  "aaSortingFixed": [],
20688 
20689 
20690  /**
20691   * DataTables can be instructed to load data to display in the table from a
20692   * Ajax source. This option defines how that Ajax call is made and where to.
20693   *
20694   * The `ajax` property has three different modes of operation, depending on
20695   * how it is defined. These are:
20696   *
20697   * * `string` - Set the URL from where the data should be loaded from.
20698   * * `object` - Define properties for `jQuery.ajax`.
20699   * * `function` - Custom data get function
20700   *
20701   * `string`
20702   * --------
20703   *
20704   * As a string, the `ajax` property simply defines the URL from which
20705   * DataTables will load data.
20706   *
20707   * `object`
20708   * --------
20709   *
20710   * As an object, the parameters in the object are passed to
20711   * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
20712   * of the Ajax request. DataTables has a number of default parameters which
20713   * you can override using this option. Please refer to the jQuery
20714   * documentation for a full description of the options available, although
20715   * the following parameters provide additional options in DataTables or
20716   * require special consideration:
20717   *
20718   * * `data` - As with jQuery, `data` can be provided as an object, but it
20719   *   can also be used as a function to manipulate the data DataTables sends
20720   *   to the server. The function takes a single parameter, an object of
20721   *   parameters with the values that DataTables has readied for sending. An
20722   *   object may be returned which will be merged into the DataTables
20723   *   defaults, or you can add the items to the object that was passed in and
20724   *   not return anything from the function. This supersedes `fnServerParams`
20725   *   from DataTables 1.9-.
20726   *
20727   * * `dataSrc` - By default DataTables will look for the property `data` (or
20728   *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
20729   *   from an Ajax source or for server-side processing - this parameter
20730   *   allows that property to be changed. You can use Javascript dotted
20731   *   object notation to get a data source for multiple levels of nesting, or
20732   *   it my be used as a function. As a function it takes a single parameter,
20733   *   the JSON returned from the server, which can be manipulated as
20734   *   required, with the returned value being that used by DataTables as the
20735   *   data source for the table. This supersedes `sAjaxDataProp` from
20736   *   DataTables 1.9-.
20737   *
20738   * * `success` - Should not be overridden it is used internally in
20739   *   DataTables. To manipulate / transform the data returned by the server
20740   *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
20741   *
20742   * `function`
20743   * ----------
20744   *
20745   * As a function, making the Ajax call is left up to yourself allowing
20746   * complete control of the Ajax request. Indeed, if desired, a method other
20747   * than Ajax could be used to obtain the required data, such as Web storage
20748   * or an AIR database.
20749   *
20750   * The function is given four parameters and no return is required. The
20751   * parameters are:
20752   *
20753   * 1. _object_ - Data to send to the server
20754   * 2. _function_ - Callback function that must be executed when the required
20755   *    data has been obtained. That data should be passed into the callback
20756   *    as the only parameter
20757   * 3. _object_ - DataTables settings object for the table
20758   *
20759   * Note that this supersedes `fnServerData` from DataTables 1.9-.
20760   *
20761   *  @type string|object|function
20762   *  @default null
20763   *
20764   *  @dtopt Option
20765   *  @name DataTable.defaults.ajax
20766   *  @since 1.10.0
20767   *
20768   * @example
20769   *   // Get JSON data from a file via Ajax.
20770   *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
20771   *   $('#example').dataTable( {
20772   *     "ajax": "data.json"
20773   *   } );
20774   *
20775   * @example
20776   *   // Get JSON data from a file via Ajax, using `dataSrc` to change
20777   *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
20778   *   $('#example').dataTable( {
20779   *     "ajax": {
20780   *       "url": "data.json",
20781   *       "dataSrc": "tableData"
20782   *     }
20783   *   } );
20784   *
20785   * @example
20786   *   // Get JSON data from a file via Ajax, using `dataSrc` to read data
20787   *   // from a plain array rather than an array in an object
20788   *   $('#example').dataTable( {
20789   *     "ajax": {
20790   *       "url": "data.json",
20791   *       "dataSrc": ""
20792   *     }
20793   *   } );
20794   *
20795   * @example
20796   *   // Manipulate the data returned from the server - add a link to data
20797   *   // (note this can, should, be done using `render` for the column - this
20798   *   // is just a simple example of how the data can be manipulated).
20799   *   $('#example').dataTable( {
20800   *     "ajax": {
20801   *       "url": "data.json",
20802   *       "dataSrc": function ( json ) {
20803   *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {
20804   *           json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
20805   *         }
20806   *         return json;
20807   *       }
20808   *     }
20809   *   } );
20810   *
20811   * @example
20812   *   // Add data to the request
20813   *   $('#example').dataTable( {
20814   *     "ajax": {
20815   *       "url": "data.json",
20816   *       "data": function ( d ) {
20817   *         return {
20818   *           "extra_search": $('#extra').val()
20819   *         };
20820   *       }
20821   *     }
20822   *   } );
20823   *
20824   * @example
20825   *   // Send request as POST
20826   *   $('#example').dataTable( {
20827   *     "ajax": {
20828   *       "url": "data.json",
20829   *       "type": "POST"
20830   *     }
20831   *   } );
20832   *
20833   * @example
20834   *   // Get the data from localStorage (could interface with a form for
20835   *   // adding, editing and removing rows).
20836   *   $('#example').dataTable( {
20837   *     "ajax": function (data, callback, settings) {
20838   *       callback(
20839   *         JSON.parse( localStorage.getItem('dataTablesData') )
20840   *       );
20841   *     }
20842   *   } );
20843   */
20844  "ajax": null,
20845 
20846 
20847  /**
20848   * This parameter allows you to readily specify the entries in the length drop
20849   * down menu that DataTables shows when pagination is enabled. It can be
20850   * either a 1D array of options which will be used for both the displayed
20851   * option and the value, or a 2D array which will use the array in the first
20852   * position as the value, and the array in the second position as the
20853   * displayed options (useful for language strings such as 'All').
20854   *
20855   * Note that the `pageLength` property will be automatically set to the
20856   * first value given in this array, unless `pageLength` is also provided.
20857   *  @type array
20858   *  @default [ 10, 25, 50, 100 ]
20859   *
20860   *  @dtopt Option
20861   *  @name DataTable.defaults.lengthMenu
20862   *
20863   *  @example
20864   *    $(document).ready( function() {
20865   *      $('#example').dataTable( {
20866   *        "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
20867   *      } );
20868   *    } );
20869   */
20870  "aLengthMenu": [ 10, 25, 50, 100 ],
20871 
20872 
20873  /**
20874   * The `columns` option in the initialisation parameter allows you to define
20875   * details about the way individual columns behave. For a full list of
20876   * column options that can be set, please see
20877   * {@link DataTable.defaults.column}. Note that if you use `columns` to
20878   * define your columns, you must have an entry in the array for every single
20879   * column that you have in your table (these can be null if you don't which
20880   * to specify any options).
20881   *  @member
20882   *
20883   *  @name DataTable.defaults.column
20884   */
20885  "aoColumns": null,
20886 
20887  /**
20888   * Very similar to `columns`, `columnDefs` allows you to target a specific
20889   * column, multiple columns, or all columns, using the `targets` property of
20890   * each object in the array. This allows great flexibility when creating
20891   * tables, as the `columnDefs` arrays can be of any length, targeting the
20892   * columns you specifically want. `columnDefs` may use any of the column
20893   * options available: {@link DataTable.defaults.column}, but it _must_
20894   * have `targets` defined in each object in the array. Values in the `targets`
20895   * array may be:
20896   *   <ul>
20897   *     <li>a string - class name will be matched on the TH for the column</li>
20898   *     <li>0 or a positive integer - column index counting from the left</li>
20899   *     <li>a negative integer - column index counting from the right</li>
20900   *     <li>the string "_all" - all columns (i.e. assign a default)</li>
20901   *   </ul>
20902   *  @member
20903   *
20904   *  @name DataTable.defaults.columnDefs
20905   */
20906  "aoColumnDefs": null,
20907 
20908 
20909  /**
20910   * Basically the same as `search`, this parameter defines the individual column
20911   * filtering state at initialisation time. The array must be of the same size
20912   * as the number of columns, and each element be an object with the parameters
20913   * `search` and `escapeRegex` (the latter is optional). 'null' is also
20914   * accepted and the default will be used.
20915   *  @type array
20916   *  @default []
20917   *
20918   *  @dtopt Option
20919   *  @name DataTable.defaults.searchCols
20920   *
20921   *  @example
20922   *    $(document).ready( function() {
20923   *      $('#example').dataTable( {
20924   *        "searchCols": [
20925   *          null,
20926   *          { "search": "My filter" },
20927   *          null,
20928   *          { "search": "^[0-9]", "escapeRegex": false }
20929   *        ]
20930   *      } );
20931   *    } )
20932   */
20933  "aoSearchCols": [],
20934 
20935 
20936  /**
20937   * An array of CSS classes that should be applied to displayed rows. This
20938   * array may be of any length, and DataTables will apply each class
20939   * sequentially, looping when required.
20940   *  @type array
20941   *  @default null <i>
20941Will take the values determined by the `oClasses.stripe*`
20942   *    options</i>
20943   *
20944   *  @dtopt Option
20945   *  @name DataTable.defaults.stripeClasses
20946   *
20947   *  @example
20948   *    $(document).ready( function() {
20949   *      $('#example').dataTable( {
20950   *        "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
20951   *      } );
20952   *    } )
20953   */
20954  "asStripeClasses": null,
20955 
20956 
20957  /**
20958   * Enable or disable automatic column width calculation. This can be disabled
20959   * as an optimisation (it takes some time to calculate the widths) if the
20960   * tables widths are passed in using `columns`.
20961   *  @type boolean
20962   *  @default true
20963   *
20964   *  @dtopt Features
20965   *  @name DataTable.defaults.autoWidth
20966   *
20967   *  @example
20968   *    $(document).ready( function () {
20969   *      $('#example').dataTable( {
20970   *        "autoWidth": false
20971   *      } );
20972   *    } );
20973   */
20974  "bAutoWidth": true,
20975 
20976 
20977  /**
20978   * Deferred rendering can provide DataTables with a huge speed boost when you
20979   * are using an Ajax or JS data source for the table. This option, when set to
20980   * true, will cause DataTables to defer the creation of the table elements for
20981   * each row until they are needed for a draw - saving a significant amount of
20982   * time.
20983   *  @type boolean
20984   *  @default false
20985   *
20986   *  @dtopt Features
20987   *  @name DataTable.defaults.deferRender
20988   *
20989   *  @example
20990   *    $(document).ready( function() {
20991   *      $('#example').dataTable( {
20992   *        "ajax": "sources/arrays.txt",
20993   *        "deferRender": true
20994   *      } );
20995   *    } );
20996   */
20997  "bDeferRender": false,
20998 
20999 
21000  /**
21001   * Replace a DataTable which matches the given selector and replace it with
21002   * one which has the properties of the new initialisation object passed. If no
21003   * table matches the selector, then the new DataTable will be constructed as
21004   * per normal.
21005   *  @type boolean
21006   *  @default false
21007   *
21008   *  @dtopt Options
21009   *  @name DataTable.defaults.destroy
21010   *
21011   *  @example
21012   *    $(document).ready( function() {
21013   *      $('#example').dataTable( {
21014   *        "srollY": "200px",
21015   *        "paginate": false
21016   *      } );
21017   *
21018   *      // Some time later....
21019   *      $('#example').dataTable( {
21020   *        "filter": false,
21021   *        "destroy": true
21022   *      } );
21023   *    } );
21024   */
21025  "bDestroy": false,
21026 
21027 
21028  /**
21029   * Enable or disable filtering of data. Filtering in DataTables is "smart" in
21030   * that it allows the end user to input multiple words (space separated) and
21031   * will match a row containing those words, even if not in the order that was
21032   * specified (this allow matching across multiple columns). Note that if you
21033   * wish to use filtering in DataTables this must remain 'true' - to remove the
21034   * default filtering input box and retain filtering abilities, please use
21035   * {@link DataTable.defaults.dom}.
21036   *  @type boolean
21037   *  @default true
21038   *
21039   *  @dtopt Features
21040   *  @name DataTable.defaults.searching
21041   *
21042   *  @example
21043   *    $(document).ready( function () {
21044   *      $('#example').dataTable( {
21045   *        "searching": false
21046   *      } );
21047   *    } );
21048   */
21049  "bFilter": true,
21050 
21051 
21052  /**
21053   * Enable or disable the table information display. This shows information
21054   * about the data that is currently visible on the page, including information
21055   * about filtered data if that action is being performed.
21056   *  @type boolean
21057   *  @default true
21058   *
21059   *  @dtopt Features
21060   *  @name DataTable.defaults.info
21061   *
21062   *  @example
21063   *    $(document).ready( function () {
21064   *      $('#example').dataTable( {
21065   *        "info": false
21066   *      } );
21067   *    } );
21068   */
21069  "bInfo": true,
21070 
21071 
21072  /**
21073   * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
21074   * slightly different and additional mark-up from what DataTables has
21075   * traditionally used).
21076   *  @type boolean
21077   *  @default false
21078   *
21079   *  @dtopt Features
21080   *  @name DataTable.defaults.jQueryUI
21081   *
21082   *  @example
21083   *    $(document).ready( function() {
21084   *      $('#example').dataTable( {
21085   *        "jQueryUI": true
21086   *      } );
21087   *    } );
21088   */
21089  "bJQueryUI": false,
21090 
21091 
21092  /**
21093   * Allows the end user to select the size of a formatted page from a select
21094   * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
21095   *  @type boolean
21096   *  @default true
21097   *
21098   *  @dtopt Features
21099   *  @name DataTable.defaults.lengthChange
21100   *
21101   *  @example
21102   *    $(document).ready( function () {
21103   *      $('#example').dataTable( {
21104   *        "lengthChange": false
21105   *      } );
21106   *    } );
21107   */
21108  "bLengthChange": true,
21109 
21110 
21111  /**
21112   * Enable or disable pagination.
21113   *  @type boolean
21114   *  @default true
21115   *
21116   *  @dtopt Features
21117   *  @name DataTable.defaults.paging
21118   *
21119   *  @example
21120   *    $(document).ready( function () {
21121   *      $('#example').dataTable( {
21122   *        "paging": false
21123   *      } );
21124   *    } );
21125   */
21126  "bPaginate": true,
21127 
21128 
21129  /**
21130   * Enable or disable the display of a 'processing' indicator when the table is
21131   * being processed (e.g. a sort). This is particularly useful for tables with
21132   * large amounts of data where it can take a noticeable amount of time to sort
21133   * the entries.
21134   *  @type boolean
21135   *  @default false
21136   *
21137   *  @dtopt Features
21138   *  @name DataTable.defaults.processing
21139   *
21140   *  @example
21141   *    $(document).ready( function () {
21142   *      $('#example').dataTable( {
21143   *        "processing": true
21144   *      } );
21145   *    } );
21146   */
21147  "bProcessing": false,
21148 
21149 
21150  /**
21151   * Retrieve the DataTables object for the given selector. Note that if the
21152   * table has already been initialised, this parameter will cause DataTables
21153   * to simply return the object that has already been set up - it will not take
21154   * account of any changes you might have made to the initialisation object
21155   * passed to DataTables (setting this parameter to true is an acknowledgement
21156   * that you understand this). `destroy` can be used to reinitialise a table if
21157   * you need.
21158   *  @type boolean
21159   *  @default false
21160   *
21161   *  @dtopt Options
21162   *  @name DataTable.defaults.retrieve
21163   *
21164   *  @example
21165   *    $(document).ready( function() {
21166   *      initTable();
21167   *      tableActions();
21168   *    } );
21169   *
21170   *    function initTable ()
21171   *    {
21172   *      return $('#example').dataTable( {
21173   *        "scrollY": "200px",
21174   *        "paginate": false,
21175   *        "retrieve": true
21176   *      } );
21177   *    }
21178   *
21179   *    function tableActions ()
21180   *    {
21181   *      var table = initTable();
21182   *      // perform API operations with oTable
21183   *    }
21184   */
21185  "bRetrieve": false,
21186 
21187 
21188  /**
21189   * When vertical (y) scrolling is enabled, DataTables will force the height of
21190   * the table's viewport to the given height at all times (useful for layout).
21191   * However, this can look odd when filtering data down to a small data set,
21192   * and the footer is left "floating" further down. This parameter (when
21193   * enabled) will cause DataTables to collapse the table's viewport down when
21194   * the result set will fit within the given Y height.
21195   *  @type boolean
21196   *  @default false
21197   *
21198   *  @dtopt Options
21199   *  @name DataTable.defaults.scrollCollapse
21200   *
21201   *  @example
21202   *    $(document).ready( function() {
21203   *      $('#example').dataTable( {
21204   *        "scrollY": "200",
21205   *        "scrollCollapse": true
21206   *      } );
21207   *    } );
21208   */
21209  "bScrollCollapse": false,
21210 
21211 
21212  /**
21213   * Configure DataTables to use server-side processing. Note that the
21214   * `ajax` parameter must also be given in order to give DataTables a
21215   * source to obtain the required data for each draw.
21216   *  @type boolean
21217   *  @default false
21218   *
21219   *  @dtopt Features
21220   *  @dtopt Server-side
21221   *  @name DataTable.defaults.serverSide
21222   *
21223   *  @example
21224   *    $(document).ready( function () {
21225   *      $('#example').dataTable( {
21226   *        "serverSide": true,
21227   *        "ajax": "xhr.php"
21228   *      } );
21229   *    } );
21230   */
21231  "bServerSide": false,
21232 
21233 
21234  /**
21235   * Enable or disable sorting of columns. Sorting of individual columns can be
21236   * disabled by the `sortable` option for each column.
21237   *  @type boolean
21238   *  @default true
21239   *
21240   *  @dtopt Features
21241   *  @name DataTable.defaults.ordering
21242   *
21243   *  @example
21244   *    $(document).ready( function () {
21245   *      $('#example').dataTable( {
21246   *        "ordering": false
21247   *      } );
21248   *    } );
21249   */
21250  "bSort": true,
21251 
21252 
21253  /**
21254   * Enable or display DataTables' ability to sort multiple columns at the
21255   * same time (activated by shift-click by the user).
21256   *  @type boolean
21257   *  @default true
21258   *
21259   *  @dtopt Options
21260   *  @name DataTable.defaults.orderMulti
21261   *
21262   *  @example
21263   *    // Disable multiple column sorting ability
21264   *    $(document).ready( function () {
21265   *      $('#example').dataTable( {
21266   *        "orderMulti": false
21267   *      } );
21268   *    } );
21269   */
21270  "bSortMulti": true,
21271 
21272 
21273  /**
21274   * Allows control over whether DataTables should use the top (true) unique
21275   * cell that is found for a single column, or the bottom (false - default).
21276   * This is useful when using complex headers.
21277   *  @type boolean
21278   *  @default false
21279   *
21280   *  @dtopt Options
21281   *  @name DataTable.defaults.orderCellsTop
21282   *
21283   *  @example
21284   *    $(document).ready( function() {
21285   *      $('#example').dataTable( {
21286   *        "orderCellsTop": true
21287   *      } );
21288   *    } );
21289   */
21290  "bSortCellsTop": false,
21291 
21292 
21293  /**
21294   * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
21295   * `sorting\_3` to the columns which are currently being sorted on. This is
21296   * presented as a feature switch as it can increase processing time (while
21297   * classes are removed and added) so for large data sets you might want to
21298   * turn this off.
21299   *  @type boolean
21300   *  @default true
21301   *
21302   *  @dtopt Features
21303   *  @name DataTable.defaults.orderClasses
21304   *
21305   *  @example
21306   *    $(document).ready( function () {
21307   *      $('#example').dataTable( {
21308   *        "orderClasses": false
21309   *      } );
21310   *    } );
21311   */
21312  "bSortClasses": true,
21313 
21314 
21315  /**
21316   * Enable or disable state saving. When enabled HTML5 `localStorage` will be
21317   * used to save table display information such as pagination information,
21318   * display length, filtering and sorting. As such when the end user reloads
21319   * the page the display display will match what thy had previously set up.
21320   *
21321   * Due to the use of `localStorage` the default state saving is not supported
21322   * in IE6 or 7. If state saving is required in those browsers, use
21323   * `stateSaveCallback` to provide a storage solution such as cookies.
21324   *  @type boolean
21325   *  @default false
21326   *
21327   *  @dtopt Features
21328   *  @name DataTable.defaults.stateSave
21329   *
21330   *  @example
21331   *    $(document).ready( function () {
21332   *      $('#example').dataTable( {
21333   *        "stateSave": true
21334   *      } );
21335   *    } );
21336   */
21337  "bStateSave": false,
21338 
21339 
21340  /**
21341   * This function is called when a TR element is created (and all TD child
21342   * elements have been inserted), or registered if using a DOM source, allowing
21343   * manipulation of the TR element (adding classes etc).
21344   *  @type function
21345   *  @param {node} row "TR" element for the current row
21346   *  @param {array} data Raw data array for this row
21347   *  @param {int} dataIndex The index of this row in the internal aoData array
21348   *
21349   *  @dtopt Callbacks
21350   *  @name DataTable.defaults.createdRow
21351   *
21352   *  @example
21353   *    $(document).ready( function() {
21354   *      $('#example').dataTable( {
21355   *        "createdRow": function( row, data, dataIndex ) {
21356   *          // Bold the grade for all 'A' grade browsers
21357   *          if ( data[4] == "A" )
21358   *          {
21359   *            $('td:eq(4)', row).html( '<b>A</b>' );
21360   *          }
21361   *        }
21362   *      } );
21363   *    } );
21364   */
21365  "fnCreatedRow": null,
21366 
21367 
21368  /**
21369   * This function is called on every 'draw' event, and allows you to
21370   * dynamically modify any aspect you want about the created DOM.
21371   *  @type function
21372   *  @param {object} settings DataTables settings object
21373   *
21374   *  @dtopt Callbacks
21375   *  @name DataTable.defaults.drawCallback
21376   *
21377   *  @example
21378   *    $(document).ready( function() {
21379   *      $('#example').dataTable( {
21380   *        "drawCallback": function( settings ) {
21381   *          alert( 'DataTables has redrawn the table' );
21382   *        }
21383   *      } );
21384   *    } );
21385   */
21386  "fnDrawCallback": null,
21387 
21388 
21389  /**
21390   * Identical to fnHeaderCallback() but for the table footer this function
21391   * allows you to modify the table footer on every 'draw' event.
21392   *  @type function
21393   *  @param {node} foot "TR" element for the footer
21394   *  @param {array} data Full table data (as derived from the original HTML)
21395   *  @param {int} start Index for the current display starting point in the
21396   *    display array
21397   *  @param {int} end Index for the current display ending point in the
21398   *    display array
21399   *  @param {array int} display Index array to translate the visual position
21400   *    to the full data array
21401   *
21402   *  @dtopt Callbacks
21403   *  @name DataTable.defaults.footerCallback
21404   *
21405   *  @example
21406   *    $(document).ready( function() {
21407   *      $('#example').dataTable( {
21408   *        "footerCallback": function( tfoot, data, start, end, display ) {
21409   *          tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
21410   *        }
21411   *      } );
21412   *    } )
21413   */
21414  "fnFooterCallback": null,
21415 
21416 
21417  /**
21418   * When rendering large numbers in the information element for the table
21419   * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
21420   * to have a comma separator for the 'thousands' units (e.g. 1 million is
21421   * rendered as "1,000,000") to help readability for the end user. This
21422   * function will override the default method DataTables uses.
21423   *  @type function
21424   *  @member
21425   *  @param {int} toFormat number to be formatted
21426   *  @returns {string} formatted string for DataTables to show the number
21427   *
21428   *  @dtopt Callbacks
21429   *  @name DataTable.defaults.formatNumber
21430   *
21431   *  @example
21432   *    // Format a number using a single quote for the separator (note that
21433   *    // this can also be done with the language.thousands option)
21434   *    $(document).ready( function() {
21435   *      $('#example').dataTable( {
21436   *        "formatNumber": function ( toFormat ) {
21437   *          return toFormat.toString().replace(
21438   *            /\B(?=(\d{3})+(?!\d))/g, "'"
21439   *          );
21440   *        };
21441   *      } );
21442   *    } );
21443   */
21444  "fnFormatNumber": function ( toFormat ) {
21445   return toFormat.toString().replace(
21446    /\B(?=(\d{3})+(?!\d))/g,
21447    this.oLanguage.sThousands
21448   );
21449  },
21450 
21451 
21452  /**
21453   * This function is called on every 'draw' event, and allows you to
21454   * dynamically modify the header row. This can be used to calculate and
21455   * display useful information about the table.
21456   *  @type function
21457   *  @param {node} head "TR" element for the header
21458   *  @param {array} data Full table data (as derived from the original HTML)
21459   *  @param {int} start Index for the current display starting point in the
21460   *    display array
21461   *  @param {int} end Index for the current display ending point in the
21462   *    display array
21463   *  @param {array int} display Index array to translate the visual position
21464   *    to the full data array
21465   *
21466   *  @dtopt Callbacks
21467   *  @name DataTable.defaults.headerCallback
21468   *
21469   *  @example
21470   *    $(document).ready( function() {
21471   *      $('#example').dataTable( {
21472   *        "fheaderCallback": function( head, data, start, end, display ) {
21473   *          head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
21474   *        }
21475   *      } );
21476   *    } )
21477   */
21478  "fnHeaderCallback": null,
21479 
21480 
21481  /**
21482   * The information element can be used to convey information about the current
21483   * state of the table. Although the internationalisation options presented by
21484   * DataTables are quite capable of dealing with most customisations, there may
21485   * be times where you wish to customise the string further. This callback
21486   * allows you to do exactly that.
21487   *  @type function
21488   *  @param {object} oSettings DataTables settings object
21489   *  @param {int} start Starting position in data for the draw
21490   *  @param {int} end End position in data for the draw
21491   *  @param {int} max Total number of rows in the table (regardless of
21492   *    filtering)
21493   *  @param {int} total Total number of rows in the data set, after filtering
21494   *  @param {string} pre The string that DataTables has formatted using it's
21495   *    own rules
21496   *  @returns {string} The string to be displayed in the information element.
21497   *
21498   *  @dtopt Callbacks
21499   *  @name DataTable.defaults.infoCallback
21500   *
21501   *  @example
21502   *    $('#example').dataTable( {
21503   *      "infoCallback": function( settings, start, end, max, total, pre ) {
21504   *        return start +" to "+ end;
21505   *      }
21506   *    } );
21507   */
21508  "fnInfoCallback": null,
21509 
21510 
21511  /**
21512   * Called when the table has been initialised. Normally DataTables will
21513   * initialise sequentially and there will be no need for this function,
21514   * however, this does not hold true when using external language information
21515   * since that is obtained using an async XHR call.
21516   *  @type function
21517   *  @param {object} settings DataTables settings object
21518   *  @param {object} json The JSON object request from the server - only
21519   *    present if client-side Ajax sourced data is used
21520   *
21521   *  @dtopt Callbacks
21522   *  @name DataTable.defaults.initComplete
21523   *
21524   *  @example
21525   *    $(document).ready( function() {
21526   *      $('#example').dataTable( {
21527   *        "initComplete": function(settings, json) {
21528   *          alert( 'DataTables has finished its initialisation.' );
21529   *        }
21530   *      } );
21531   *    } )
21532   */
21533  "fnInitComplete": null,
21534 
21535 
21536  /**
21537   * Called at the very start of each table draw and can be used to cancel the
21538   * draw by returning false, any other return (including undefined) results in
21539   * the full draw occurring).
21540   *  @type function
21541   *  @param {object} settings DataTables settings object
21542   *  @returns {boolean} False will cancel the draw, anything else (including no
21543   *    return) will allow it to complete.
21544   *
21545   *  @dtopt Callbacks
21546   *  @name DataTable.defaults.preDrawCallback
21547   *
21548   *  @example
21549   *    $(document).ready( function() {
21550   *      $('#example').dataTable( {
21551   *        "preDrawCallback": function( settings ) {
21552   *          if ( $('#test').val() == 1 ) {
21553   *            return false;
21554   *          }
21555   *        }
21556   *      } );
21557   *    } );
21558   */
21559  "fnPreDrawCallback": null,
21560 
21561 
21562  /**
21563   * This function allows you to 'post process' each row after it have been
21564   * generated for each table draw, but before it is rendered on screen. This
21565   * function might be used for setting the row class name etc.
21566   *  @type function
21567   *  @param {node} row "TR" element for the current row
21568   *  @param {array} data Raw data array for this row
21569   *  @param {int} displayIndex The display index for the current table draw
21570   *  @param {int} displayIndexFull The index of the data in the full list of
21571   *    rows (after filtering)
21572   *
21573   *  @dtopt Callbacks
21574   *  @name DataTable.defaults.rowCallback
21575   *
21576   *  @example
21577   *    $(document).ready( function() {
21578   *      $('#example').dataTable( {
21579   *        "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
21580   *          // Bold the grade for all 'A' grade browsers
21581   *          if ( data[4] == "A" ) {
21582   *            $('td:eq(4)', row).html( '<b>A</b>' );
21583   *          }
21584   *        }
21585   *      } );
21586   *    } );
21587   */
21588  "fnRowCallback": null,
21589 
21590 
21591  /**
21592   * __Deprecated__ The functionality provided by this parameter has now been
21593   * superseded by that provided through `ajax`, which should be used instead.
21594   *
21595   * This parameter allows you to override the default function which obtains
21596   * the data from the server so something more suitable for your application.
21597   * For example you could use POST data, or pull information from a Gears or
21598   * AIR database.
21599   *  @type function
21600   *  @member
21601   *  @param {string} source HTTP source to obtain the data from (`ajax`)
21602   *  @param {array} data A key/value pair object containing the data to send
21603   *    to the server
21604   *  @param {function} callback to be called on completion of the data get
21605   *    process that will draw the data on the page.
21606   *  @param {object} settings DataTables settings object
21607   *
21608   *  @dtopt Callbacks
21609   *  @dtopt Server-side
21610   *  @name DataTable.defaults.serverData
21611   *
21612   *  @deprecated 1.10. Please use `ajax` for this functionality now.
21613   */
21614  "fnServerData": null,
21615 
21616 
21617  /**
21618   * __Deprecated__ The functionality provided by this parameter has now been
21619   * superseded by that provided through `ajax`, which should be used instead.
21620   *
21621   *  It is often useful to send extra data to the server when making an Ajax
21622   * request - for example custom filtering information, and this callback
21623   * function makes it trivial to send extra information to the server. The
21624   * passed in parameter is the data set that has been constructed by
21625   * DataTables, and you can add to this or modify it as you require.
21626   *  @type function
21627   *  @param {array} data Data array (array of objects which are name/value
21628   *    pairs) that has been constructed by DataTables and will be sent to the
21629   *    server. In the case of Ajax sourced data with server-side processing
21630   *    this will be an empty array, for server-side processing there will be a
21631   *    significant number of parameters!
21632   *  @returns {undefined} Ensure that you modify the data array passed in,
21633   *    as this is passed by reference.
21634   *
21635   *  @dtopt Callbacks
21636   *  @dtopt Server-side
21637   *  @name DataTable.defaults.serverParams
21638   *
21639   *  @deprecated 1.10. Please use `ajax` for this functionality now.
21640   */
21641  "fnServerParams": null,
21642 
21643 
21644  /**
21645   * Load the table state. With this function you can define from where, and how, the
21646   * state of a table is loaded. By default DataTables will load from `localStorage`
21647   * but you might wish to use a server-side database or cookies.
21648   *  @type function
21649   *  @member
21650   *  @param {object} settings DataTables settings object
21651   *  @return {object} The DataTables state object to be loaded
21652   *
21653   *  @dtopt Callbacks
21654   *  @name DataTable.defaults.stateLoadCallback
21655   *
21656   *  @example
21657   *    $(document).ready( function() {
21658   *      $('#example').dataTable( {
21659   *        "stateSave": true,
21660   *        "stateLoadCallback": function (settings) {
21661   *          var o;
21662   *
21663   *          // Send an Ajax request to the server to get the data. Note that
21664   *          // this is a synchronous request.
21665   *          $.ajax( {
21666   *            "url": "/state_load",
21667   *            "async": false,
21668   *            "dataType": "json",
21669   *            "success": function (json) {
21670   *              o = json;
21671   *            }
21672   *          } );
21673   *
21674   *          return o;
21675   *        }
21676   *      } );
21677   *    } );
21678   */
21679  "fnStateLoadCallback": function ( settings ) {
21680   try {
21681    return JSON.parse(
21682     (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
21683      'DataTables_'+settings.sInstance+'_'+location.pathname
21684     )
21685    );
21686   } catch (e) {}
21687  },
21688 
21689 
21690  /**
21691   * Callback which allows modification of the saved state prior to loading that state.
21692   * This callback is called when the table is loading state from the stored data, but
21693   * prior to the settings object being modified by the saved state. Note that for
21694   * plug-in authors, you should use the `stateLoadParams` event to load parameters for
21695   * a plug-in.
21696   *  @type function
21697   *  @param {object} settings DataTables settings object
21698   *  @param {object} data The state object that is to be loaded
21699   *
21700   *  @dtopt Callbacks
21701   *  @name DataTable.defaults.stateLoadParams
21702   *
21703   *  @example
21704   *    // Remove a saved filter, so filtering is never loaded
21705   *    $(document).ready( function() {
21706   *      $('#example').dataTable( {
21707   *        "stateSave": true,
21708   *        "stateLoadParams": function (settings, data) {
21709   *          data.oSearch.sSearch = "";
21710   *        }
21711   *      } );
21712   *    } );
21713   *
21714   *  @example
21715   *    // Disallow state loading by returning false
21716   *    $(document).ready( function() {
21717   *      $('#example').dataTable( {
21718   *        "stateSave": true,
21719   *        "stateLoadParams": function (settings, data) {
21720   *          return false;
21721   *        }
21722   *      } );
21723   *    } );
21724   */
21725  "fnStateLoadParams": null,
21726 
21727 
21728  /**
21729   * Callback that is called when the state has been loaded from the state saving method
21730   * and the DataTables settings object has been modified as a result of the loaded state.
21731   *  @type function
21732   *  @param {object} settings DataTables settings object
21733   *  @param {object} data The state object that was loaded
21734   *
21735   *  @dtopt Callbacks
21736   *  @name DataTable.defaults.stateLoaded
21737   *
21738   *  @example
21739   *    // Show an alert with the filtering value that was saved
21740   *    $(document).ready( function() {
21741   *      $('#example').dataTable( {
21742   *        "stateSave": true,
21743   *        "stateLoaded": function (settings, data) {
21744   *          alert( 'Saved filter was: '+data.oSearch.sSearch );
21745   *        }
21746   *      } );
21747   *    } );
21748   */
21749  "fnStateLoaded": null,
21750 
21751 
21752  /**
21753   * Save the table state. This function allows you to define where and how the state
21754   * information for the table is stored By default DataTables will use `localStorage`
21755   * but you might wish to use a server-side database or cookies.
21756   *  @type function
21757   *  @member
21758   *  @param {object} settings DataTables settings object
21759   *  @param {object} data The state object to be saved
21760   *
21761   *  @dtopt Callbacks
21762   *  @name DataTable.defaults.stateSaveCallback
21763   *
21764   *  @example
21765   *    $(document).ready( function() {
21766   *      $('#example').dataTable( {
21767   *        "stateSave": true,
21768   *        "stateSaveCallback": function (settings, data) {
21769   *          // Send an Ajax request to the server with the state object
21770   *          $.ajax( {
21771   *            "url": "/state_save",
21772   *            "data": data,
21773   *            "dataType": "json",
21774   *            "method": "POST"
21775   *            "success": function () {}
21776   *          } );
21777   *        }
21778   *      } );
21779   *    } );
21780   */
21781  "fnStateSaveCallback": function ( settings, data ) {
21782   try {
21783    (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
21784     'DataTables_'+settings.sInstance+'_'+location.pathname,
21785     JSON.stringify( data )
21786    );
21787   } catch (e) {}
21788  },
21789 
21790 
21791  /**
21792   * Callback which allows modification of the state to be saved. Called when the table
21793   * has changed state a new state save is required. This method allows modification of
21794   * the state saving object prior to actually doing the save, including addition or
21795   * other state properties or modification. Note that for plug-in authors, you should
21796   * use the `stateSaveParams` event to save parameters for a plug-in.
21797   *  @type function
21798   *  @param {object} settings DataTables settings object
21799   *  @param {object} data The state object to be saved
21800   *
21801   *  @dtopt Callbacks
21802   *  @name DataTable.defaults.stateSaveParams
21803   *
21804   *  @example
21805   *    // Remove a saved filter, so filtering is never saved
21806   *    $(document).ready( function() {
21807   *      $('#example').dataTable( {
21808   *        "stateSave": true,
21809   *        "stateSaveParams": function (settings, data) {
21810   *          data.oSearch.sSearch = "";
21811   *        }
21812   *      } );
21813   *    } );
21814   */
21815  "fnStateSaveParams": null,
21816 
21817 
21818  /**
21819   * Duration for which the saved state information is considered valid. After this period
21820   * has elapsed the state will be returned to the default.
21821   * Value is given in seconds.
21822   *  @type int
21823   *  @default 7200 <i>(2 hours)</i>
21824   *
21825   *  @dtopt Options
21826   *  @name DataTable.defaults.stateDuration
21827   *
21828   *  @example
21829   *    $(document).ready( function() {
21830   *      $('#example').dataTable( {
21831   *        "stateDuration": 60*60*24; // 1 day
21832   *      } );
21833   *    } )
21834   */
21835  "iStateDuration": 7200,
21836 
21837 
21838  /**
21839   * When enabled DataTables will not make a request to the server for the first
21840   * page draw - rather it will use the data already on the page (no sorting etc
21841   * will be applied to it), thus saving on an XHR at load time. `deferLoading`
21842   * is used to indicate that deferred loading is required, but it is also used
21843   * to tell DataTables how many records there are in the full table (allowing
21844   * the information element and pagination to be displayed correctly). In the case
21845   * where a filtering is applied to the table on initial load, this can be
21846   * indicated by giving the parameter as an array, where the first element is
21847   * the number of records available after filtering and the second element is the
21848   * number of records without filtering (allowing the table information element
21849   * to be shown correctly).
21850   *  @type int | array
21851   *  @default null
21852   *
21853   *  @dtopt Options
21854   *  @name DataTable.defaults.deferLoading
21855   *
21856   *  @example
21857   *    // 57 records available in the table, no filtering applied
21858   *    $(document).ready( function() {
21859   *      $('#example').dataTable( {
21860   *        "serverSide": true,
21861   *        "ajax": "scripts/server_processing.php",
21862   *        "deferLoading": 57
21863   *      } );
21864   *    } );
21865   *
21866   *  @example
21867   *    // 57 records after filtering, 100 without filtering (an initial filter applied)
21868   *    $(document).ready( function() {
21869   *      $('#example').dataTable( {
21870   *        "serverSide": true,
21871   *        "ajax": "scripts/server_processing.php",
21872   *        "deferLoading": [ 57, 100 ],
21873   *        "search": {
21874   *          "search": "my_filter"
21875   *        }
21876   *      } );
21877   *    } );
21878   */
21879  "iDeferLoading": null,
21880 
21881 
21882  /**
21883   * Number of rows to display on a single page when using pagination. If
21884   * feature enabled (`lengthChange`) then the end user will be able to override
21885   * this to a custom setting using a pop-up menu.
21886   *  @type int
21887   *  @default 10
21888   *
21889   *  @dtopt Options
21890   *  @name DataTable.defaults.pageLength
21891   *
21892   *  @example
21893   *    $(document).ready( function() {
21894   *      $('#example').dataTable( {
21895   *        "pageLength": 50
21896   *      } );
21897   *    } )
21898   */
21899  "iDisplayLength": 10,
21900 
21901 
21902  /**
21903   * Define the starting point for data display when using DataTables with
21904   * pagination. Note that this parameter is the number of records, rather than
21905   * the page number, so if you have 10 records per page and want to start on
21906   * the third page, it should be "20".
21907   *  @type int
21908   *  @default 0
21909   *
21910   *  @dtopt Options
21911   *  @name DataTable.defaults.displayStart
21912   *
21913   *  @example
21914   *    $(document).ready( function() {
21915   *      $('#example').dataTable( {
21916   *        "displayStart": 20
21917   *      } );
21918   *    } )
21919   */
21920  "iDisplayStart": 0,
21921 
21922 
21923  /**
21924   * By default DataTables allows keyboard navigation of the table (sorting, paging,
21925   * and filtering) by adding a `tabindex` attribute to the required elements. This
21926   * allows you to tab through the controls and press the enter key to activate them.
21927   * The tabindex is default 0, meaning that the tab follows the flow of the document.
21928   * You can overrule this using this parameter if you wish. Use a value of -1 to
21929   * disable built-in keyboard navigation.
21930   *  @type int
21931   *  @default 0
21932   *
21933   *  @dtopt Options
21934   *  @name DataTable.defaults.tabIndex
21935   *
21936   *  @example
21937   *    $(document).ready( function() {
21938   *      $('#example').dataTable( {
21939   *        "tabIndex": 1
21940   *      } );
21941   *    } );
21942   */
21943  "iTabIndex": 0,
21944 
21945 
21946  /**
21947   * Classes that DataTables assigns to the various components and features
21948   * that it adds to the HTML table. This allows classes to be configured
21949   * during initialisation in addition to through the static
21950   * {@link DataTable.ext.oStdClasses} object).
21951   *  @namespace
21952   *  @name DataTable.defaults.classes
21953   */
21954  "oClasses": {},
21955 
21956 
21957  /**
21958   * All strings that DataTables uses in the user interface that it creates
21959   * are defined in this object, allowing you to modified them individually or
21960   * completely replace them all as required.
21961   *  @namespace
21962   *  @name DataTable.defaults.language
21963   */
21964  "oLanguage": {
21965   /**
21966    * Strings that are used for WAI-ARIA labels and controls only (these are not
21967    * actually visible on the page, but will be read by screenreaders, and thus
21968    * must be internationalised as well).
21969    *  @namespace
21970    *  @name DataTable.defaults.language.aria
21971    */
21972   "oAria": {
21973    /**
21974     * ARIA label that is added to the table headers when the column may be
21975     * sorted ascending by activing the column (click or return when focu
21975sed).
21976     * Note that the column header is prefixed to this string.
21977     *  @type string
21978     *  @default : activate to sort column ascending
21979     *
21980     *  @dtopt Language
21981     *  @name DataTable.defaults.language.aria.sortAscending
21982     *
21983     *  @example
21984     *    $(document).ready( function() {
21985     *      $('#example').dataTable( {
21986     *        "language": {
21987     *          "aria": {
21988     *            "sortAscending": " - click/return to sort ascending"
21989     *          }
21990     *        }
21991     *      } );
21992     *    } );
21993     */
21994    "sSortAscending": ": activate to sort column ascending",
21995 
21996    /**
21997     * ARIA label that is added to the table headers when the column may be
21998     * sorted descending by activing the column (click or return when focused).
21999     * Note that the column header is prefixed to this string.
22000     *  @type string
22001     *  @default : activate to sort column ascending
22002     *
22003     *  @dtopt Language
22004     *  @name DataTable.defaults.language.aria.sortDescending
22005     *
22006     *  @example
22007     *    $(document).ready( function() {
22008     *      $('#example').dataTable( {
22009     *        "language": {
22010     *          "aria": {
22011     *            "sortDescending": " - click/return to sort descending"
22012     *          }
22013     *        }
22014     *      } );
22015     *    } );
22016     */
22017    "sSortDescending": ": activate to sort column descending"
22018   },
22019 
22020   /**
22021    * Pagination string used by DataTables for the built-in pagination
22022    * control types.
22023    *  @namespace
22024    *  @name DataTable.defaults.language.paginate
22025    */
22026   "oPaginate": {
22027    /**
22028     * Text to use when using the 'full_numbers' type of pagination for the
22029     * button to take the user to the first page.
22030     *  @type string
22031     *  @default First
22032     *
22033     *  @dtopt Language
22034     *  @name DataTable.defaults.language.paginate.first
22035     *
22036     *  @example
22037     *    $(document).ready( function() {
22038     *      $('#example').dataTable( {
22039     *        "language": {
22040     *          "paginate": {
22041     *            "first": "First page"
22042     *          }
22043     *        }
22044     *      } );
22045     *    } );
22046     */
22047    "sFirst": "First",
22048 
22049 
22050    /**
22051     * Text to use when using the 'full_numbers' type of pagination for the
22052     * button to take the user to the last page.
22053     *  @type string
22054     *  @default Last
22055     *
22056     *  @dtopt Language
22057     *  @name DataTable.defaults.language.paginate.last
22058     *
22059     *  @example
22060     *    $(document).ready( function() {
22061     *      $('#example').dataTable( {
22062     *        "language": {
22063     *          "paginate": {
22064     *            "last": "Last page"
22065     *          }
22066     *        }
22067     *      } );
22068     *    } );
22069     */
22070    "sLast": "Last",
22071 
22072 
22073    /**
22074     * Text to use for the 'next' pagination button (to take the user to the
22075     * next page).
22076     *  @type string
22077     *  @default Next
22078     *
22079     *  @dtopt Language
22080     *  @name DataTable.defaults.language.paginate.next
22081     *
22082     *  @example
22083     *    $(document).ready( function() {
22084     *      $('#example').dataTable( {
22085     *        "language": {
22086     *          "paginate": {
22087     *            "next": "Next page"
22088     *          }
22089     *        }
22090     *      } );
22091     *    } );
22092     */
22093    "sNext": "Next",
22094 
22095 
22096    /**
22097     * Text to use for the 'previous' pagination button (to take the user to
22098     * the previous page).
22099     *  @type string
22100     *  @default Previous
22101     *
22102     *  @dtopt Language
22103     *  @name DataTable.defaults.language.paginate.previous
22104     *
22105     *  @example
22106     *    $(document).ready( function() {
22107     *      $('#example').dataTable( {
22108     *        "language": {
22109     *          "paginate": {
22110     *            "previous": "Previous page"
22111     *          }
22112     *        }
22113     *      } );
22114     *    } );
22115     */
22116    "sPrevious": "Previous"
22117   },
22118 
22119   /**
22120    * This string is shown in preference to `zeroRecords` when the table is
22121    * empty of data (regardless of filtering). Note that this is an optional
22122    * parameter - if it is not given, the value of `zeroRecords` will be used
22123    * instead (either the default or given value).
22124    *  @type string
22125    *  @default No data available in table
22126    *
22127    *  @dtopt Language
22128    *  @name DataTable.defaults.language.emptyTable
22129    *
22130    *  @example
22131    *    $(document).ready( function() {
22132    *      $('#example').dataTable( {
22133    *        "language": {
22134    *          "emptyTable": "No data available in table"
22135    *        }
22136    *      } );
22137    *    } );
22138    */
22139   "sEmptyTable": "No data available in table",
22140 
22141 
22142   /**
22143    * This string gives information to the end user about the information
22144    * that is current on display on the page. The following tokens can be
22145    * used in the string and will be dynamically replaced as the table
22146    * display updates. This tokens can be placed anywhere in the string, or
22147    * removed as needed by the language requires:
22148    *
22149    * * `\_START\_` - Display index of the first record on the current page
22150    * * `\_END\_` - Display index of the last record on the current page
22151    * * `\_TOTAL\_` - Number of records in the table after filtering
22152    * * `\_MAX\_` - Number of records in the table without filtering
22153    * * `\_PAGE\_` - Current page number
22154    * * `\_PAGES\_` - Total number of pages of data in the table
22155    *
22156    *  @type string
22157    *  @default Showing _START_ to _END_ of _TOTAL_ entries
22158    *
22159    *  @dtopt Language
22160    *  @name DataTable.defaults.language.info
22161    *
22162    *  @example
22163    *    $(document).ready( function() {
22164    *      $('#example').dataTable( {
22165    *        "language": {
22166    *          "info": "Showing page _PAGE_ of _PAGES_"
22167    *        }
22168    *      } );
22169    *    } );
22170    */
22171   "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
22172 
22173 
22174   /**
22175    * Display information string for when the table is empty. Typically the
22176    * format of this string should match `info`.
22177    *  @type string
22178    *  @default Showing 0 to 0 of 0 entries
22179    *
22180    *  @dtopt Language
22181    *  @name DataTable.defaults.language.infoEmpty
22182    *
22183    *  @example
22184    *    $(document).ready( function() {
22185    *      $('#example').dataTable( {
22186    *        "language": {
22187    *          "infoEmpty": "No entries to show"
22188    *        }
22189    *      } );
22190    *    } );
22191    */
22192   "sInfoEmpty": "Showing 0 to 0 of 0 entries",
22193 
22194 
22195   /**
22196    * When a user filters the information in a table, this string is appended
22197    * to the information (`info`) to give an idea of how strong the filtering
22198    * is. The variable _MAX_ is dynamically updated.
22199    *  @type string
22200    *  @default (filtered from _MAX_ total entries)
22201    *
22202    *  @dtopt Language
22203    *  @name DataTable.defaults.language.infoFiltered
22204    *
22205    *  @example
22206    *    $(document).ready( function() {
22207    *      $('#example').dataTable( {
22208    *        "language": {
22209    *          "infoFiltered": " - filtering from _MAX_ records"
22210    *        }
22211    *      } );
22212    *    } );
22213    */
22214   "sInfoFiltered": "(filtered from _MAX_ total entries)",
22215 
22216 
22217   /**
22218    * If can be useful to append extra information to the info string at times,
22219    * and this variable does exactly that. This information will be appended to
22220    * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
22221    * being used) at all times.
22222    *  @type string
22223    *  @default <i>Empty string</i>
22224    *
22225    *  @dtopt Language
22226    *  @name DataTable.defaults.language.infoPostFix
22227    *
22228    *  @example
22229    *    $(document).ready( function() {
22230    *      $('#example').dataTable( {
22231    *        "language": {
22232    *          "infoPostFix": "All records shown are derived from real information."
22233    *        }
22234    *      } );
22235    *    } );
22236    */
22237   "sInfoPostFix": "",
22238 
22239 
22240   /**
22241    * This decimal place operator is a little different from the other
22242    * language options since DataTables doesn't output floating point
22243    * numbers, so it won't ever use this for display of a number. Rather,
22244    * what this parameter does is modify the sort methods of the table so
22245    * that numbers which are in a format which has a character other than
22246    * a period (`.`) as a decimal place will be sorted numerically.
22247    *
22248    * Note that numbers with different decimal places cannot be shown in
22249    * the same table and still be sortable, the table must be consistent.
22250    * However, multiple different tables on the page can use different
22251    * decimal place characters.
22252    *  @type string
22253    *  @default 
22254    *
22255    *  @dtopt Language
22256    *  @name DataTable.defaults.language.decimal
22257    *
22258    *  @example
22259    *    $(document).ready( function() {
22260    *      $('#example').dataTable( {
22261    *        "language": {
22262    *          "decimal": ","
22263    *          "thousands": "."
22264    *        }
22265    *      } );
22266    *    } );
22267    */
22268   "sDecimal": "",
22269 
22270 
22271   /**
22272    * DataTables has a build in number formatter (`formatNumber`) which is
22273    * used to format large numbers that are used in the table information.
22274    * By default a comma is used, but this can be trivially changed to any
22275    * character you wish with this parameter.
22276    *  @type string
22277    *  @default ,
22278    *
22279    *  @dtopt Language
22280    *  @name DataTable.defaults.language.thousands
22281    *
22282    *  @example
22283    *    $(document).ready( function() {
22284    *      $('#example').dataTable( {
22285    *        "language": {
22286    *          "thousands": "'"
22287    *        }
22288    *      } );
22289    *    } );
22290    */
22291   "sThousands": ",",
22292 
22293 
22294   /**
22295    * Detail the action that will be taken when the drop down menu for the
22296    * pagination length option is changed. The '_MENU_' variable is replaced
22297    * with a default select list of 10, 25, 50 and 100, and can be replaced
22298    * with a custom select box if required.
22299    *  @type string
22300    *  @default Show _MENU_ entries
22301    *
22302    *  @dtopt Language
22303    *  @name DataTable.defaults.language.lengthMenu
22304    *
22305    *  @example
22306    *    // Language change only
22307    *    $(document).ready( function() {
22308    *      $('#example').dataTable( {
22309    *        "language": {
22310    *          "lengthMenu": "Display _MENU_ records"
22311    *        }
22312    *      } );
22313    *    } );
22314    *
22315    *  @example
22316    *    // Language and options change
22317    *    $(document).ready( function() {
22318    *      $('#example').dataTable( {
22319    *        "language": {
22320    *          "lengthMenu": 'Display <select>'+
22321    *            '<option value="10">10</option>'+
22322    *            '<option value="20">20</option>'+
22323    *            '<option value="30">30</option>'+
22324    *            '<option value="40">40</option>'+
22325    *            '<option value="50">50</option>'+
22326    *            '<option value="-1">All</option>'+
22327    *            '</select> records'
22328    *        }
22329    *      } );
22330    *    } );
22331    */
22332   "sLengthMenu": "Show _MENU_ entries",
22333 
22334 
22335   /**
22336    * When using Ajax sourced data and during the first draw when DataTables is
22337    * gathering the data, this message is shown in an empty row in the table to
22338    * indicate to the end user the the data is being loaded. Note that this
22339    * parameter is not used when loading data by server-side processing, just
22340    * Ajax sourced data with client-side processing.
22341    *  @type string
22342    *  @default Loading...
22343    *
22344    *  @dtopt Language
22345    *  @name DataTable.defaults.language.loadingRecords
22346    *
22347    *  @example
22348    *    $(document).ready( function() {
22349    *      $('#example').dataTable( {
22350    *        "language": {
22351    *          "loadingRecords": "Please wait - loading..."
22352    *        }
22353    *      } );
22354    *    } );
22355    */
22356   "sLoadingRecords": "Loading...",
22357 
22358 
22359   /**
22360    * Text which is displayed when the table is processing a user action
22361    * (usually a sort command or similar).
22362    *  @type string
22363    *  @default Processing...
22364    *
22365    *  @dtopt Language
22366    *  @name DataTable.defaults.language.processing
22367    *
22368    *  @example
22369    *    $(document).ready( function() {
22370    *      $('#example').dataTable( {
22371    *        "language": {
22372    *          "processing": "DataTables is currently busy"
22373    *        }
22374    *      } );
22375    *    } );
22376    */
22377   "sProcessing": "Processing...",
22378 
22379 
22380   /**
22381    * Details the actions that will be taken when the user types into the
22382    * filtering input text box. The variable "_INPUT_", if used in the string,
22383    * is replaced with the HTML text box for the filtering input allowing
22384    * control over where it appears in the string. If "_INPUT_" is not given
22385    * then the input box is appended to the string automatically.
22386    *  @type string
22387    *  @default Search:
22388    *
22389    *  @dtopt Language
22390    *  @name DataTable.defaults.language.search
22391    *
22392    *  @example
22393    *    // Input text box will be appended at the end automatically
22394    *    $(document).ready( function() {
22395    *      $('#example').dataTable( {
22396    *        "language": {
22397    *          "search": "Filter records:"
22398    *        }
22399    *      } );
22400    *    } );
22401    *
22402    *  @example
22403    *    // Specify where the filter should appear
22404    *    $(document).ready( function() {
22405    *      $('#example').dataTable( {
22406    *        "language": {
22407    *          "search": "Apply filter _INPUT_ to table"
22408    *        }
22409    *      } );
22410    *    } );
22411    */
22412   "sSearch": "Search:",
22413 
22414 
22415   /**
22416    * Assign a `placeholder` attribute to the search `input` element
22417    *  @type string
22418    *  @default 
22419    *
22420    *  @dtopt Language
22421    *  @name DataTable.defaults.language.searchPlaceholder
22422    */
22423   "sSearchPlaceholder": "",
22424 
22425 
22426   /**
22427    * All of the language information can be stored in a file on the
22428    * server-side, which DataTables will look up if this parameter is passed.
22429    * It must store the URL of the language file, which is in a JSON format,
22430    * and the object has the same properties as the oLanguage object in the
22431    * initialiser object (i.e. the above parameters). Please refer to one of
22432    * the example language files to see how this works in action.
22433    *  @type string
22434    *  @default <i>Empty string - i.e. disabled</i>
22435    *
22436    *  @dtopt Language
22437    *  @name DataTable.defaults.language.url
22438    *
22439    *  @example
22440    *    $(document).ready( function() {
22441    *      $('#example').dataTable( {
22442    *        "language": {
22443    *          "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
22444    *        }
22445    *      } );
22446    *    } );
22447    */
22448   "sUrl": "",
22449 
22450 
22451   /**
22452    * Text shown inside the table records when the is no information to be
22453    * displayed after filtering. `emptyTable` is shown when there is simply no
22454    * information in the table at all (regardless of filtering).
22455    *  @type string
22456    *  @default No matching records found
22457    *
22458    *  @dtopt Language
22459    *  @name DataTable.defaults.language.zeroRecords
22460    *
22461    *  @example
22462    *    $(document).ready( function() {
22463    *      $('#example').dataTable( {
22464    *        "language": {
22465    *          "zeroRecords": "No records to display"
22466    *        }
22467    *      } );
22468    *    } );
22469    */
22470   "sZeroRecords": "No matching records found"
22471  },
22472 
22473 
22474  /**
22475   * This parameter allows you to have define the global filtering state at
22476   * initialisation time. As an object the `search` parameter must be
22477   * defined, but all other parameters are optional. When `regex` is true,
22478   * the search string will be treated as a regular expression, when false
22479   * (default) it will be treated as a straight string. When `smart`
22480   * DataTables will use it's smart filtering methods (to word match at
22481   * any point in the data), when false this will not be done.
22482   *  @namespace
22483   *  @extends DataTable.models.oSearch
22484   *
22485   *  @dtopt Options
22486   *  @name DataTable.defaults.search
22487   *
22488   *  @example
22489   *    $(document).ready( function() {
22490   *      $('#example').dataTable( {
22491   *        "search": {"search": "Initial search"}
22492   *      } );
22493   *    } )
22494   */
22495  "oSearch": $.extend( {}, DataTable.models.oSearch ),
22496 
22497 
22498  /**
22499   * __Deprecated__ The functionality provided by this parameter has now been
22500   * superseded by that provided through `ajax`, which should be used instead.
22501   *
22502   * By default DataTables will look for the property `data` (or `aaData` for
22503   * compatibility with DataTables 1.9-) when obtaining data from an Ajax
22504   * source or for server-side processing - this parameter allows that
22505   * property to be changed. You can use Javascript dotted object notation to
22506   * get a data source for multiple levels of nesting.
22507   *  @type string
22508   *  @default data
22509   *
22510   *  @dtopt Options
22511   *  @dtopt Server-side
22512   *  @name DataTable.defaults.ajaxDataProp
22513   *
22514   *  @deprecated 1.10. Please use `ajax` for this functionality now.
22515   */
22516  "sAjaxDataProp": "data",
22517 
22518 
22519  /**
22520   * __Deprecated__ The functionality provided by this parameter has now been
22521   * superseded by that provided through `ajax`, which should be used instead.
22522   *
22523   * You can instruct DataTables to load data from an external
22524   * source using this parameter (use aData if you want to pass data in you
22525   * already have). Simply provide a url a JSON object can be obtained from.
22526   *  @type string
22527   *  @default null
22528   *
22529   *  @dtopt Options
22530   *  @dtopt Server-side
22531   *  @name DataTable.defaults.ajaxSource
22532   *
22533   *  @deprecated 1.10. Please use `ajax` for this functionality now.
22534   */
22535  "sAjaxSource": null,
22536 
22537 
22538  /**
22539   * This initialisation variable allows you to specify exactly where in the
22540   * DOM you want DataTables to inject the various controls it adds to the page
22541   * (for example you might want the pagination controls at the top of the
22542   * table). DIV elements (with or without a custom class) can also be added to
22543   * aid styling. The follow syntax is used:
22544   *   <ul>
22545   *     <li>The following options are allowed:
22546   *       <ul>
22547   *         <li>'l' - Length changing</li>
22548   *         <li>'f' - Filtering input</li>
22549   *         <li>'t' - The table!</li>
22550   *         <li>'i' - Information</li>
22551   *         <li>'p' - Pagination</li>
22552   *         <li>'r' - pRocessing</li>
22553   *       </ul>
22554   *     </li>
22555   *     <li>The following constants are allowed:
22556   *       <ul>
22557   *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
22558   *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
22559   *       </ul>
22560   *     </li>
22561   *     <li>The following syntax is expected:
22562   *       <ul>
22563   *         <li>'&lt;' and '&gt;' - div elements</li>
22564   *         <li>'&lt;"class" and '&gt;' - div with a class</li>
22565   *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
22566   *       </ul>
22567   *     </li>
22568   *     <li>Examples:
22569   *       <ul>
22570   *         <li>'&lt;"wrapper"flipt&gt;'</li>
22571   *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
22572   *       </ul>
22573   *     </li>
22574   *   </ul>
22575   *  @type string
22576   *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
22577   *    <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
22578   *
22579   *  @dtopt Options
22580   *  @name DataTable.defaults.dom
22581   *
22582   *  @example
22583   *    $(document).ready( function() {
22584   *      $('#example').dataTable( {
22585   *        "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
22586   *      } );
22587   *    } );
22588   */
22589  "sDom": "lfrtip",
22590 
22591 
22592  /**
22593   * Search delay option. This will throttle full table searches that use the
22594   * DataTables provided search input element (it does not effect calls to
22595   * `dt-api search()`, providing a delay before the search is made.
22596   *  @type integer
22597   *  @default 0
22598   *
22599   *  @dtopt Options
22600   *  @name DataTable.defaults.searchDelay
22601   *
22602   *  @example
22603   *    $(document).ready( function() {
22604   *      $('#example').dataTable( {
22605   *        "searchDelay": 200
22606   *      } );
22607   *    } )
22608   */
22609  "searchDelay": null,
22610 
22611 
22612  /**
22613   * DataTables features four different built-in options for the buttons to
22614   * display for pagination control:
22615   *
22616   * * `simple` - 'Previous' and 'Next' buttons only
22617   * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
22618   * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
22619   * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
22620   *   page numbers
22621   *  
22622   * Further methods can be added using {@link DataTable.ext.oPagination}.
22623   *  @type string
22624   *  @default simple_numbers
22625   *
22626   *  @dtopt Options
22627   *  @name DataTable.defaults.pagingType
22628   *
22629   *  @example
22630   *    $(document).ready( function() {
22631   *      $('#example').dataTable( {
22632   *        "pagingType": "full_numbers"
22633   *      } );
22634   *    } )
22635   */
22636  "sPaginationType": "simple_numbers",
22637 
22638 
22639  /**
22640   * Enable horizontal scrolling. When a table is too wide to fit into a
22641   * certain layout, or you have a large number of columns in the table, you
22642   * can enable x-scrolling to show the table in a viewport, which can be
22643   * scrolled. This property can be `true` which will allow the table to
22644   * scroll horizontally when needed, or any CSS unit, or a number (in which
22645   * case it will be treated as a pixel measurement). Setting as simply `true`
22646   * is recommended.
22647   *  @type boolean|string
22648   *  @default <i>blank string - i.e. disabled</i>
22649   *
22650   *  @dtopt Features
22651   *  @name DataTable.defaults.scrollX
22652   *
22653   *  @example
22654   *    $(document).ready( function() {
22655   *      $('#example').dataTable( {
22656   *        "scrollX": true,
22657   *        "scrollCollapse": true
22658   *      } );
22659   *    } );
22660   */
22661  "sScrollX": "",
22662 
22663 
22664  /**
22665   * This property can be used to force a DataTable to use more width than it
22666   * might otherwise do when x-scrolling is enabled. For example if you have a
22667   * table which requires to be well spaced, this parameter is useful for
22668   * "over-sizing" the table, and thus forcing scrolling. This property can by
22669   * any CSS unit, or a number (in which case it will be treated as a pixel
22670   * measurement).
22671   *  @type string
22672   *  @default <i>blank string - i.e. disabled</i>
22673   *
22674   *  @dtopt Options
22675   *  @name DataTable.defaults.scrollXInner
22676   *
22677   *  @example
22678   *    $(document).ready( function() {
22679   *      $('#example').dataTable( {
22680   *        "scrollX": "100%",
22681   *        "scrollXInner": "110%"
22682   *      } );
22683   *    } );
22684   */
22685  "sScrollXInner": "",
22686 
22687 
22688  /**
22689   * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
22690   * to the given height, and enable scrolling for any data which overflows the
22691   * current viewport. This can be used as an alternative to paging to display
22692   * a lot of data in a small area (although paging and scrolling can both be
22693   * enabled at the same time). This property can be any CSS unit, or a number
22694   * (in which case it will be treated as a pixel measurement).
22695   *  @type string
22696   *  @default <i>blank string - i.e. disabled</i>
22697   *
22698   *  @dtopt Features
22699   *  @name DataTable.defaults.scrollY
22700   *
22701   *  @example
22702   *    $(document).ready( function() {
22703   *      $('#example').dataTable( {
22704   *        "scrollY": "200px",
22705   *        "paginate": false
22706   *      } );
22707   *    } );
22708   */
22709  "sScrollY": "",
22710 
22711 
22712  /**
22713   * __Deprecated__ The functionality provided by this parameter has now been
22714   * superseded by that provided through `ajax`, which should be used instead.
22715   *
22716   * Set the HTTP method that is used to make the Ajax call for server-side
22717   * processing or Ajax sourced data.
22718   *  @type string
22719   *  @default GET
22720   *
22721   *  @dtopt Options
22722   *  @dtopt Server-side
22723   *  @name DataTable.defaults.serverMethod
22724   *
22725   *  @deprecated 1.10. Please use `ajax` for this functionality now.
22726   */
22727  "sServerMethod": "GET",
22728 
22729 
22730  /**
22731   * DataTables makes use of renderers when displaying HTML elements for
22732   * a table. These renderers can be added or modified by plug-ins to
22733   * generate suitable mark-up for a site. For example the Bootstrap
22734   * integration plug-in for DataTables uses a paging button renderer to
22735   * display pagination buttons in the mark-up required by Bootstrap.
22736   *
22737   * For further information about the renderers available see
22738   * DataTable.ext.renderer
22739   *  @type string|object
22740   *  @default null
22741   *
22742   *  @name DataTable.defaults.renderer
22743   *
22744   */
22745  "renderer": null,
22746 
22747 
22748  /**
22749   * Set the data property name that DataTables should use to get a row's id
22750   * to set as the `id` property in the node.
22751   *  @type string
22752   *  @default DT_RowId
22753   *
22754   *  @name DataTable.defaults.rowId
22755   */
22756  "rowId": "DT_RowId"
22757 };
22758 
22759 _fnHungarianMap( DataTable.defaults );
22760 
22761 
22762 
22763 /*
22764  * Developer note - See note in model.defaults.js about the use of Hungarian
22765  * notation and camel case.
22766  */
22767 
22768 /**
22769  * Column options that can be given to DataTables at initialisation time.
22770  *  @namespace
22771  */
22772 DataTable.defaults.column = {
22773  /**
22774   * Define which column(s) an order will occur on for this column. This
22775   * allows a column's ordering to take multiple columns into account when
22776   * doing a sort or use the data from a different column. For example first
22777   * name / last name columns make sense to do a multi-column sort over the
22778   * two columns.
22779   *  @type array|int
22780   *  @default null <i>Takes the value of the column index automatically</i>
22781   *
22782   *  @name DataTable.defaults.column.orderData
22783   *  @dtopt Columns
22784   *
22785   *  @example
22786   *    // Using `columnDefs`
22787   *    $(document).ready( function() {
22788   *      $('#example').dataTable( {
22789   *        "columnDefs": [
22790   *          { "orderData": [ 0, 1 ], "targets": [ 0 ] },
22791   *          { "orderData": [ 1, 0 ], "targets": [ 1 ] },
22792   *          { "orderData": 2, "targets": [ 2 ] }
22793   *        ]
22794   *      } );
22795   *    } );
22796   *
22797   *  @example
22798   *    // Using `columns`
22799   *    $(document).ready( function() {
22800   *      $('#example').dataTable( {
22801   *        "columns": [
22802   *          { "orderData": [ 0, 1 ] },
22803   *          { "orderData": [ 1, 0 ] },
22804   *          { "orderData": 2 },
22805   *          null,
22806   *          null
22807   *        ]
22808   *      } );
22809   *    } );
22810   */
22811  "aDataSort": null,
22812  "iDataSort": -1,
22813 
22814 
22815  /**
22816   * You can control the default ordering direction, and even alter the
22817   * behaviour of the sort handler (i.e. only allow ascending ordering etc)
22818   * using this parameter.
22819   *  @type array
22820   *  @default [ 'asc', 'desc' ]
22821   *
22822   *  @name DataTable.defaults.column.orderSequence
22823   *  @dtopt Columns
22824   *
22825   *  @example
22826   *    // Using `columnDefs`
22827   *    $(document).ready( function() {
22828   *      $('#example').dataTable( {
22829   *        "columnDefs": [
22830   *          { "orderSequence": [ "asc" ], "targets": [ 1 ] },
22831   *          { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
22832   *          { "orderSequence": [ "desc" ], "targets": [ 3 ] }
22833   *        ]
22834   *      } );
22835   *    } );
22836   *
22837   *  @example
22838   *    // Using `columns`
22839   *    $(document).ready( function() {
22840   *      $('#example').dataTable( {
22841   *        "columns": [
22842   *          null,
22843   *          { "orderSequence": [ "asc" ] },
22844   *          { "orderSequence": [ "desc", "asc", "asc" ] },
22845   *          { "orderSequence": [ "desc" ] },
22846   *          null
22847   *        ]
22848   *      } );
22849   *    } );
22850   */
22851  "asSorting": [ 'asc', 'desc' ],
22852 
22853 
22854  /**
22855   * Enable or disable filtering on the data in this column.
22856   *  @type boolean
22857   *  @default true
22858   *
22859   *  @name DataTable.defaults.column.searchable
22860   *  @dtopt Columns
22861   *
22862   *  @example
22863   *    // Using `columnDefs`
22864   *    $(document).ready( function() {
22865   *      $('#example').dataTable( {
22866   *        "columnDefs": [
22867   *          { "searchable": false, "targets": [ 0 ] }
22868   *        ] } );
22869   *    } );
22870   *
22871   *  @example
22872   *    // Using `columns`
22873   *    $(document).ready( function() {
22874   *      $('#example').dataTable( {
22875   *        "columns": [
22876   *          { "searchable": false },
22877   *          null,
22878   *          null,
22879   *          null,
22880   *          null
22881   *        ] } );
22882   *    } );
22883   */
22884  "bSearchable": true,
22885 
22886 
22887  /**
22888   * Enable or disable ordering on this column.
22889   *  @type boolean
22890   *  @default true
22891   *
22892   *  @name DataTable.defaults.column.orderable
22893   *  @dtopt Columns
22894   *
22895   *  @example
22896   *    // Using `columnDefs`
22897   *    $(document).ready( function() {
22898   *      $('#example').dataTable( {
22899   *        "columnDefs": [
22900   *          { "orderable": false, "targets": [ 0 ] }
22901   *        ] } );
22902   *    } );
22903   *
22904   *  @example
22905   *    // Using `columns`
22906   *    $(document).ready( function() {
22907   *      $('#example').dataTable( {
22908   *        "columns": [
22909   *          { "orderable": false },
22910   *          null,
22911   *          null,
22912   *          null,
22913   *          null
22914   *        ] } );
22915   *    } );
22916   */
22917  "bSortable": true,
22918 
22919 
22920  /**
22921   * Enable or disable the display of this column.
22922   *  @type boolean
22923   *  @default true
22924   *
22925   *  @name DataTable.defaults.column.visible
22926   *  @dtopt Columns
22927   *
22928   *  @example
22929   *    // Using `columnDefs`
22930   *    $(document).ready( function() {
22931   *      $('#example').dataTable( {
22932   *        "columnDefs": [
22933   *          { "visible": false, "targets": [ 0 ] }
22934   *        ] } );
22935   *    } );
22936   *
22937   *  @example
22938   *    // Using `columns`
22939   *    $(document).ready( function() {
22940   *      $('#example').dataTable( {
22941   *        "columns": [
22942   *          { "visible": false },
22943   *          null,
22944   *          null,
22945   *          null,
22946   *          null
22947   *        ] } );
22948   *    } );
22949   */
22950  "bVisible": true,
22951 
22952 
22953  /**
22954   * Developer definable function that is called whenever a cell is created (Ajax source,
22955   * etc) or processed for input (DOM source). This can be used as a compliment to mRender
22956   * allowing you to modify the DOM element (add background colour for example) when the
22957   * element is available.
22958   *  @type function
22959   *  @param {element} td The TD node that has been created
22960   *  @param {*} cellData The Data for the cell
22961   *  @param {array|object} rowData The data for the whole row
22962   *  @param {int} row The row index for the aoData data store
22963   *  @param {int} col The column index for aoColumns
22964   *
22965   *  @name DataTable.defaults.column.createdCell
22966   *  @dtopt Columns
22967   *
22968   *  @example
22969   *    $(document).ready( function() {
22970   *      $('#example').dataTable( {
22971   *        "columnDefs": [ {
22972   *          "targets": [3],
22973   *          "createdCell": function (td, cellData, rowData, row, c
22973ol) {
22974   *            if ( cellData == "1.7" ) {
22975   *              $(td).css('color', 'blue')
22976   *            }
22977   *          }
22978   *        } ]
22979   *      });
22980   *    } );
22981   */
22982  "fnCreatedCell": null,
22983 
22984 
22985  /**
22986   * This parameter has been replaced by `data` in DataTables to ensure naming
22987   * consistency. `dataProp` can still be used, as there is backwards
22988   * compatibility in DataTables for this option, but it is strongly
22989   * recommended that you use `data` in preference to `dataProp`.
22990   *  @name DataTable.defaults.column.dataProp
22991   */
22992 
22993 
22994  /**
22995   * This property can be used to read data from any data source property,
22996   * including deeply nested objects / properties. `data` can be given in a
22997   * number of different ways which effect its behaviour:
22998   *
22999   * * `integer` - treated as an array index for the data source. This is the
23000   *   default that DataTables uses (incrementally increased for each column).
23001   * * `string` - read an object property from the data source. There are
23002   *   three 'special' options that can be used in the string to alter how
23003   *   DataTables reads the data from the source object:
23004   *    * `.` - Dotted Javascript notation. Just as you use a `.` in
23005   *      Javascript to read from nested objects, so to can the options
23006   *      specified in `data`. For example: `browser.version` or
23007   *      `browser.name`. If your object parameter name contains a period, use
23008   *      `\\` to escape it - i.e. `first\\.name`.
23009   *    * `[]` - Array notation. DataTables can automatically combine data
23010   *      from and array source, joining the data with the characters provided
23011   *      between the two brackets. For example: `name[, ]` would provide a
23012   *      comma-space separated list from the source array. If no characters
23013   *      are provided between the brackets, the original array source is
23014   *      returned.
23015   *    * `()` - Function notation. Adding `()` to the end of a parameter will
23016   *      execute a function of the name given. For example: `browser()` for a
23017   *      simple function on the data source, `browser.version()` for a
23018   *      function in a nested property or even `browser().version` to get an
23019   *      object property if the function called returns an object. Note that
23020   *      function notation is recommended for use in `render` rather than
23021   *      `data` as it is much simpler to use as a renderer.
23022   * * `null` - use the original data source for the row rather than plucking
23023   *   data directly from it. This action has effects on two other
23024   *   initialisation options:
23025   *    * `defaultContent` - When null is given as the `data` option and
23026   *      `defaultContent` is specified for the column, the value defined by
23027   *      `defaultContent` will be used for the cell.
23028   *    * `render` - When null is used for the `data` option and the `render`
23029   *      option is specified for the column, the whole data source for the
23030   *      row is used for the renderer.
23031   * * `function` - the function given will be executed whenever DataTables
23032   *   needs to set or get the data for a cell in the column. The function
23033   *   takes three parameters:
23034   *    * Parameters:
23035   *      * `{array|object}` The data source for the row
23036   *      * `{string}` The type call data requested - this will be 'set' when
23037   *        setting data or 'filter', 'display', 'type', 'sort' or undefined
23038   *        when gathering data. Note that when `undefined` is given for the
23039   *        type DataTables expects to get the raw data for the object back<
23040   *      * `{*}` Data to set when the second parameter is 'set'.
23041   *    * Return:
23042   *      * The return value from the function is not required when 'set' is
23043   *        the type of call, but otherwise the return is what will be used
23044   *        for the data requested.
23045   *
23046   * Note that `data` is a getter and setter option. If you just require
23047   * formatting of data for output, you will likely want to use `render` which
23048   * is simply a getter and thus simpler to use.
23049   *
23050   * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
23051   * name change reflects the flexibility of this property and is consistent
23052   * with the naming of mRender. If 'mDataProp' is given, then it will still
23053   * be used by DataTables, as it automatically maps the old name to the new
23054   * if required.
23055   *
23056   *  @type string|int|function|null
23057   *  @default null <i>Use automatically calculated column index</i>
23058   *
23059   *  @name DataTable.defaults.column.data
23060   *  @dtopt Columns
23061   *
23062   *  @example
23063   *    // Read table data from objects
23064   *    // JSON structure for each row:
23065   *    //   {
23066   *    //      "engine": {value},
23067   *    //      "browser": {value},
23068   *    //      "platform": {value},
23069   *    //      "version": {value},
23070   *    //      "grade": {value}
23071   *    //   }
23072   *    $(document).ready( function() {
23073   *      $('#example').dataTable( {
23074   *        "ajaxSource": "sources/objects.txt",
23075   *        "columns": [
23076   *          { "data": "engine" },
23077   *          { "data": "browser" },
23078   *          { "data": "platform" },
23079   *          { "data": "version" },
23080   *          { "data": "grade" }
23081   *        ]
23082   *      } );
23083   *    } );
23084   *
23085   *  @example
23086   *    // Read information from deeply nested objects
23087   *    // JSON structure for each row:
23088   *    //   {
23089   *    //      "engine": {value},
23090   *    //      "browser": {value},
23091   *    //      "platform": {
23092   *    //         "inner": {value}
23093   *    //      },
23094   *    //      "details": [
23095   *    //         {value}, {value}
23096   *    //      ]
23097   *    //   }
23098   *    $(document).ready( function() {
23099   *      $('#example').dataTable( {
23100   *        "ajaxSource": "sources/deep.txt",
23101   *        "columns": [
23102   *          { "data": "engine" },
23103   *          { "data": "browser" },
23104   *          { "data": "platform.inner" },
23105   *          { "data": "platform.details.0" },
23106   *          { "data": "platform.details.1" }
23107   *        ]
23108   *      } );
23109   *    } );
23110   *
23111   *  @example
23112   *    // Using `data` as a function to provide different information for
23113   *    // sorting, filtering and display. In this case, currency (price)
23114   *    $(document).ready( function() {
23115   *      $('#example').dataTable( {
23116   *        "columnDefs": [ {
23117   *          "targets": [ 0 ],
23118   *          "data": function ( source, type, val ) {
23119   *            if (type === 'set') {
23120   *              source.price = val;
23121   *              // Store the computed dislay and filter values for efficiency
23122   *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
23123   *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
23124   *              return;
23125   *            }
23126   *            else if (type === 'display') {
23127   *              return source.price_display;
23128   *            }
23129   *            else if (type === 'filter') {
23130   *              return source.price_filter;
23131   *            }
23132   *            // 'sort', 'type' and undefined all just use the integer
23133   *            return source.price;
23134   *          }
23135   *        } ]
23136   *      } );
23137   *    } );
23138   *
23139   *  @example
23140   *    // Using default content
23141   *    $(document).ready( function() {
23142   *      $('#example').dataTable( {
23143   *        "columnDefs": [ {
23144   *          "targets": [ 0 ],
23145   *          "data": null,
23146   *          "defaultContent": "Click to edit"
23147   *        } ]
23148   *      } );
23149   *    } );
23150   *
23151   *  @example
23152   *    // Using array notation - outputting a list from an array
23153   *    $(document).ready( function() {
23154   *      $('#example').dataTable( {
23155   *        "columnDefs": [ {
23156   *          "targets": [ 0 ],
23157   *          "data": "name[, ]"
23158   *        } ]
23159   *      } );
23160   *    } );
23161   *
23162   */
23163  "mData": null,
23164 
23165 
23166  /**
23167   * This property is the rendering partner to `data` and it is suggested that
23168   * when you want to manipulate data for display (including filtering,
23169   * sorting etc) without altering the underlying data for the table, use this
23170   * property. `render` can be considered to be the the read only companion to
23171   * `data` which is read / write (then as such more complex). Like `data`
23172   * this option can be given in a number of different ways to effect its
23173   * behaviour:
23174   *
23175   * * `integer` - treated as an array index for the data source. This is the
23176   *   default that DataTables uses (incrementally increased for each column).
23177   * * `string` - read an object property from the data source. There are
23178   *   three 'special' options that can be used in the string to alter how
23179   *   DataTables reads the data from the source object:
23180   *    * `.` - Dotted Javascript notation. Just as you use a `.` in
23181   *      Javascript to read from nested objects, so to can the options
23182   *      specified in `data`. For example: `browser.version` or
23183   *      `browser.name`. If your object parameter name contains a period, use
23184   *      `\\` to escape it - i.e. `first\\.name`.
23185   *    * `[]` - Array notation. DataTables can automatically combine data
23186   *      from and array source, joining the data with the characters provided
23187   *      between the two brackets. For example: `name[, ]` would provide a
23188   *      comma-space separated list from the source array. If no characters
23189   *      are provided between the brackets, the original array source is
23190   *      returned.
23191   *    * `()` - Function notation. Adding `()` to the end of a parameter will
23192   *      execute a function of the name given. For example: `browser()` for a
23193   *      simple function on the data source, `browser.version()` for a
23194   *      function in a nested property or even `browser().version` to get an
23195   *      object property if the function called returns an object.
23196   * * `object` - use different data for the different data types requested by
23197   *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
23198   *   of the object is the data type the property refers to and the value can
23199   *   defined using an integer, string or function using the same rules as
23200   *   `render` normally does. Note that an `_` option _must_ be specified.
23201   *   This is the default value to use if you haven't specified a value for
23202   *   the data type requested by DataTables.
23203   * * `function` - the function given will be executed whenever DataTables
23204   *   needs to set or get the data for a cell in the column. The function
23205   *   takes three parameters:
23206   *    * Parameters:
23207   *      * {array|object} The data source for the row (based on `data`)
23208   *      * {string} The type call data requested - this will be 'filter',
23209   *        'display', 'type' or 'sort'.
23210   *      * {array|object} The full data source for the row (not based on
23211   *        `data`)
23212   *    * Return:
23213   *      * The return value from the function is what will be used for the
23214   *        data requested.
23215   *
23216   *  @type string|int|function|object|null
23217   *  @default null Use the data source value.
23218   *
23219   *  @name DataTable.defaults.column.render
23220   *  @dtopt Columns
23221   *
23222   *  @example
23223   *    // Create a comma separated list from an array of objects
23224   *    $(document).ready( function() {
23225   *      $('#example').dataTable( {
23226   *        "ajaxSource": "sources/deep.txt",
23227   *        "columns": [
23228   *          { "data": "engine" },
23229   *          { "data": "browser" },
23230   *          {
23231   *            "data": "platform",
23232   *            "render": "[, ].name"
23233   *          }
23234   *        ]
23235   *      } );
23236   *    } );
23237   *
23238   *  @example
23239   *    // Execute a function to obtain data
23240   *    $(document).ready( function() {
23241   *      $('#example').dataTable( {
23242   *        "columnDefs": [ {
23243   *          "targets": [ 0 ],
23244   *          "data": null, // Use the full data source object for the renderer's source
23245   *          "render": "browserName()"
23246   *        } ]
23247   *      } );
23248   *    } );
23249   *
23250   *  @example
23251   *    // As an object, extracting different data for the different types
23252   *    // This would be used with a data source such as:
23253   *    //   { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
23254   *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
23255   *    // (which has both forms) is used for filtering for if a user inputs either format, while
23256   *    // the formatted phone number is the one that is shown in the table.
23257   *    $(document).ready( function() {
23258   *      $('#example').dataTable( {
23259   *        "columnDefs": [ {
23260   *          "targets": [ 0 ],
23261   *          "data": null, // Use the full data source object for the renderer's source
23262   *          "render": {
23263   *            "_": "phone",
23264   *            "filter": "phone_filter",
23265   *            "display": "phone_display"
23266   *          }
23267   *        } ]
23268   *      } );
23269   *    } );
23270   *
23271   *  @example
23272   *    // Use as a function to create a link from the data source
23273   *    $(document).ready( function() {
23274   *      $('#example').dataTable( {
23275   *        "columnDefs": [ {
23276   *          "targets": [ 0 ],
23277   *          "data": "download_link",
23278   *          "render": function ( data, type, full ) {
23279   *            return '<a href="'+data+'">Download</a>';
23280   *          }
23281   *        } ]
23282   *      } );
23283   *    } );
23284   */
23285  "mRender": null,
23286 
23287 
23288  /**
23289   * Change the cell type created for the column - either TD cells or TH cells. This
23290   * can be useful as TH cells have semantic meaning in the table body, allowing them
23291   * to act as a header for a row (you may wish to add scope='row' to the TH elements).
23292   *  @type string
23293   *  @default td
23294   *
23295   *  @name DataTable.defaults.column.cellType
23296   *  @dtopt Columns
23297   *
23298   *  @example
23299   *    // Make the first column use TH cells
23300   *    $(document).ready( function() {
23301   *      $('#example').dataTable( {
23302   *        "columnDefs": [ {
23303   *          "targets": [ 0 ],
23304   *          "cellType": "th"
23305   *        } ]
23306   *      } );
23307   *    } );
23308   */
23309  "sCellType": "td",
23310 
23311 
23312  /**
23313   * Class to give to each cell in this column.
23314   *  @type string
23315   *  @default <i>Empty string</i>
23316   *
23317   *  @name DataTable.defaults.column.class
23318   *  @dtopt Columns
23319   *
23320   *  @example
23321   *    // Using `columnDefs`
23322   *    $(document).ready( function() {
23323   *      $('#example').dataTable( {
23324   *        "columnDefs": [
23325   *          { "class": "my_class", "targets": [ 0 ] }
23326   *        ]
23327   *      } );
23328   *    } );
23329   *
23330   *  @example
23331   *    // Using `columns`
23332   *    $(document).ready( function() {
23333   *      $('#example').dataTable( {
23334   *        "columns": [
23335   *          { "class": "my_class" },
23336   *          null,
23337   *          null,
23338   *          null,
23339   *          null
23340   *        ]
23341   *      } );
23342   *    } );
23343   */
23344  "sClass": "",
23345 
23346  /**
23347   * When DataTables calculates the column widths to assign to each column,
23348   * it finds the longest string in each column and then constructs a
23349   * temporary table and reads the widths from that. The problem with this
23350   * is that "mmm" is much wider then "iiii", but the latter is a longer
23351   * string - thus the calculation can go wrong (doing it properly and putting
23352   * it into an DOM object and measuring that is horribly(!) slow). Thus as
23353   * a "work around" we provide this option. It will append its value to the
23354   * text that is found to be the longest string for the column - i.e. padding.
23355   * Generally you shouldn't need this!
23356   *  @type string
23357   *  @default <i>Empty string<i>
23358   *
23359   *  @name DataTable.defaults.column.contentPadding
23360   *  @dtopt Columns
23361   *
23362   *  @example
23363   *    // Using `columns`
23364   *    $(document).ready( function() {
23365   *      $('#example').dataTable( {
23366   *        "columns": [
23367   *          null,
23368   *          null,
23369   *          null,
23370   *          {
23371   *            "contentPadding": "mmm"
23372   *          }
23373   *        ]
23374   *      } );
23375   *    } );
23376   */
23377  "sContentPadding": "",
23378 
23379 
23380  /**
23381   * Allows a default value to be given for a column's data, and will be used
23382   * whenever a null data source is encountered (this can be because `data`
23383   * is set to null, or because the data source itself is null).
23384   *  @type string
23385   *  @default null
23386   *
23387   *  @name DataTable.defaults.column.defaultContent
23388   *  @dtopt Columns
23389   *
23390   *  @example
23391   *    // Using `columnDefs`
23392   *    $(document).ready( function() {
23393   *      $('#example').dataTable( {
23394   *        "columnDefs": [
23395   *          {
23396   *            "data": null,
23397   *            "defaultContent": "Edit",
23398   *            "targets": [ -1 ]
23399   *          }
23400   *        ]
23401   *      } );
23402   *    } );
23403   *
23404   *  @example
23405   *    // Using `columns`
23406   *    $(document).ready( function() {
23407   *      $('#example').dataTable( {
23408   *        "columns": [
23409   *          null,
23410   *          null,
23411   *          null,
23412   *          {
23413   *            "data": null,
23414   *            "defaultContent": "Edit"
23415   *          }
23416   *        ]
23417   *      } );
23418   *    } );
23419   */
23420  "sDefaultContent": null,
23421 
23422 
23423  /**
23424   * This parameter is only used in DataTables' server-side processing. It can
23425   * be exceptionally useful to know what columns are being displayed on the
23426   * client side, and to map these to database fields. When defined, the names
23427   * also allow DataTables to reorder information from the server if it comes
23428   * back in an unexpected order (i.e. if you switch your columns around on the
23429   * client-side, your server-side code does not also need updating).
23430   *  @type string
23431   *  @default <i>Empty string</i>
23432   *
23433   *  @name DataTable.defaults.column.name
23434   *  @dtopt Columns
23435   *
23436   *  @example
23437   *    // Using `columnDefs`
23438   *    $(document).ready( function() {
23439   *      $('#example').dataTable( {
23440   *        "columnDefs": [
23441   *          { "name": "engine", "targets": [ 0 ] },
23442   *          { "name": "browser", "targets": [ 1 ] },
23443   *          { "name": "platform", "targets": [ 2 ] },
23444   *          { "name": "version", "targets": [ 3 ] },
23445   *          { "name": "grade", "targets": [ 4 ] }
23446   *        ]
23447   *      } );
23448   *    } );
23449   *
23450   *  @example
23451   *    // Using `columns`
23452   *    $(document).ready( function() {
23453   *      $('#example').dataTable( {
23454   *        "columns": [
23455   *          { "name": "engine" },
23456   *          { "name": "browser" },
23457   *          { "name": "platform" },
23458   *          { "name": "version" },
23459   *          { "name": "grade" }
23460   *        ]
23461   *      } );
23462   *    } );
23463   */
23464  "sName": "",
23465 
23466 
23467  /**
23468   * Defines a data source type for the ordering which can be used to read
23469   * real-time information from the table (updating the internally cached
23470   * version) prior to ordering. This allows ordering to occur on user
23471   * editable elements such as form inputs.
23472   *  @type string
23473   *  @default std
23474   *
23475   *  @name DataTable.defaults.column.orderDataType
23476   *  @dtopt Columns
23477   *
23478   *  @example
23479   *    // Using `columnDefs`
23480   *    $(document).ready( function() {
23481   *      $('#example').dataTable( {
23482   *        "columnDefs": [
23483   *          { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
23484   *          { "type": "numeric", "targets": [ 3 ] },
23485   *          { "orderDataType": "dom-select", "targets": [ 4 ] },
23486   *          { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
23487   *        ]
23488   *      } );
23489   *    } );
23490   *
23491   *  @example
23492   *    // Using `columns`
23493   *    $(document).ready( function() {
23494   *      $('#example').dataTable( {
23495   *        "columns": [
23496   *          null,
23497   *          null,
23498   *          { "orderDataType": "dom-text" },
23499   *          { "orderDataType": "dom-text", "type": "numeric" },
23500   *          { "orderDataType": "dom-select" },
23501   *          { "orderDataType": "dom-checkbox" }
23502   *        ]
23503   *      } );
23504   *    } );
23505   */
23506  "sSortDataType": "std",
23507 
23508 
23509  /**
23510   * The title of this column.
23511   *  @type string
23512   *  @default null <i>Derived from the 'TH' value for this column in the
23513   *    original HTML table.</i>
23514   *
23515   *  @name DataTable.defaults.column.title
23516   *  @dtopt Columns
23517   *
23518   *  @example
23519   *    // Using `columnDefs`
23520   *    $(document).ready( function() {
23521   *      $('#example').dataTable( {
23522   *        "columnDefs": [
23523   *          { "title": "My column title", "targets": [ 0 ] }
23524   *        ]
23525   *      } );
23526   *    } );
23527   *
23528   *  @example
23529   *    // Using `columns`
23530   *    $(document).ready( function() {
23531   *      $('#example').dataTable( {
23532   *        "columns": [
23533   *          { "title": "My column title" },
23534   *          null,
23535   *          null,
23536   *          null,
23537   *          null
23538   *        ]
23539   *      } );
23540   *    } );
23541   */
23542  "sTitle": null,
23543 
23544 
23545  /**
23546   * The type allows you to specify how the data for this column will be
23547   * ordered. Four types (string, numeric, date and html (which will strip
23548   * HTML tags before ordering)) are currently available. Note that only date
23549   * formats understood by Javascript's Date() object will be accepted as type
23550   * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
23551   * 'numeric', 'date' or 'html' (by default). Further types can be adding
23552   * through plug-ins.
23553   *  @type string
23554   *  @default null <i>Auto-detected from raw data</i>
23555   *
23556   *  @name DataTable.defaults.column.type
23557   *  @dtopt Columns
23558   *
23559   *  @example
23560   *    // Using `columnDefs`
23561   *    $(document).ready( function() {
23562   *      $('#example').dataTable( {
23563   *        "columnDefs": [
23564   *          { "type": "html", "targets": [ 0 ] }
23565   *        ]
23566   *      } );
23567   *    } );
23568   *
23569   *  @example
23570   *    // Using `columns`
23571   *    $(document).ready( function() {
23572   *      $('#example').dataTable( {
23573   *        "columns": [
23574   *          { "type": "html" },
23575   *          null,
23576   *          null,
23577   *          null,
23578   *          null
23579   *        ]
23580   *      } );
23581   *    } );
23582   */
23583  "sType": null,
23584 
23585 
23586  /**
23587   * Defining the width of the column, this parameter may take any CSS value
23588   * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
23589   * been given a specific width through this interface ensuring that the table
23590   * remains readable.
23591   *  @type string
23592   *  @default null <i>Automatic</i>
23593   *
23594   *  @name DataTable.defaults.column.width
23595   *  @dtopt Columns
23596   *
23597   *  @example
23598   *    // Using `columnDefs`
23599   *    $(document).ready( function() {
23600   *      $('#example').dataTable( {
23601   *        "columnDefs": [
23602   *          { "width": "20%", "targets": [ 0 ] }
23603   *        ]
23604   *      } );
23605   *    } );
23606   *
23607   *  @example
23608   *    // Using `columns`
23609   *    $(document).ready( function() {
23610   *      $('#example').dataTable( {
23611   *        "columns": [
23612   *          { "width": "20%" },
23613   *          null,
23614   *          null,
23615   *          null,
23616   *          null
23617   *        ]
23618   *      } );
23619   *    } );
23620   */
23621  "sWidth": null
23622 };
23623 
23624 _fnHungarianMap( DataTable.defaults.column );
23625 
23626 
23627 
23628 /**
23629  * DataTables settings object - this holds all the information needed for a
23630  * given table, including configuration, data and current application of the
23631  * table options. DataTables does not have a single instance for each DataTable
23632  * with the settings attached to that instance, but rather instances of the
23633  * DataTable "class" are created on-the-fly as needed (typically by a
23634  * $().dataTable() call) and the settings object is then applied to that
23635  * instance.
23636  *
23637  * Note that this object is related to {@link DataTable.defaults} but this
23638  * one is the internal data store for DataTables's cache of columns. It should
23639  * NOT be manipulated outside of DataTables. Any configuration should be done
23640  * through the initialisation options.
23641  *  @namespace
23642  *  @todo Really should attach the settings object to individual instances so we
23643  *    don't need to create new instances on each $().dataTable() call (if the
23644  *    table already exists). It would also save passing oSettings around and
23645  *    into every single function. However, this is a very significant
23646  *    architecture change for DataTables and will almost certainly break
23647  *    backwards compatibility with older installations. This is something that
23648  *    will be done in 2.0.
23649  */
23650 DataTable.models.oSettings = {
23651  /**
23652   * Primary features of DataTables and their enablement state.
23653   *  @namespace
23654   */
23655  "oFeatures": {
23656 
23657   /**
23658    * Flag to say if DataTables should automatically try to calculate the
23659    * optimum table and columns widths (true) or not (false).
23660    * Note that this parameter will be set by the initialisation routine. To
23661    * set a default use {@link DataTable.defaults}.
23662    *  @type boolean
23663    */
23664   "bAutoWidth": null,
23665 
23666   /**
23667    * Delay the creation of TR and TD elements until they are actually
23668    * needed by a driven page draw. This can give a significant speed
23669    * increase for Ajax source and Javascript source data, but makes no
23670    * difference at all fro DOM and server-side processing tables.
23671    * Note that this parameter will be set by the initialisation routine. To
23672    * set a default use {@link DataTable.defaults}.
23673    *  @type boolean
23674    */
23675   "bDeferRender": null,
23676 
23677   /**
23678    * Enable filtering on the table or not. Note that if this is disabled
23679    * then there is no filtering at all on the table, including fnFilter.
23680    * To just remove the filtering input use sDom and remove the 'f' option.
23681    * Note that this parameter will be set by the initialisation routine. To
23682    * set a default use {@link DataTable.defaults}.
23683    *  @type boolean
23684    */
23685   "bFilter": null,
23686 
23687   /**
23688    * Table information element (the 'Showing x of y records' div) enable
23689    * flag.
23690    * Note that this parameter will be set by the initialisation routine. To
23691    * set a default use {@link DataTable.defaults}.
23692    *  @type boolean
23693    */
23694   "bInfo": null,
23695 
23696   /**
23697    * Present a user control allowing the end user to change the page size
23698    * when pagination is enabled.
23699    * Note that this parameter will be set by the initialisation routine. To
23700    * set a default use {@link DataTable.defaults}.
23701    *  @type boolean
23702    */
23703   "bLengthChange": null,
23704 
23705   /**
23706    * Pagination enabled or not. Note that if this is disabled then length
23707    * changing must also be disabled.
23708    * Note that this parameter will be set by the initialisation routine. To
23709    * set a default use {@link DataTable.defaults}.
23710    *  @type boolean
23711    */
23712   "bPaginate": null,
23713 
23714   /**
23715    * Processing indicator enable flag whenever DataTables is enacting a
23716    * user request - typically an Ajax request for server-side processing.
23717    * Note that this parameter will be set by the initialisation routine. To
23718    * set a default use {@link DataTable.defaults}.
23719    *  @type boolean
23720    */
23721   "bProcessing": null,
23722 
23723   /**
23724    * Server-side processing enabled flag - when enabled DataTables will
23725    * get all data from the server for every draw - there is no filtering,
23726    * sorting or paging done on the client-side.
23727    * Note that this parameter will be set by the initialisation routine. To
23728    * set a default use {@link DataTable.defaults}.
23729    *  @type boolean
23730    */
23731   "bServerSide": null,
23732 
23733   /**
23734    * Sorting enablement flag.
23735    * Note that this parameter will be set by the initialisation routine. To
23736    * set a default use {@link DataTable.defaults}.
23737    *  @type boolean
23738    */
23739   "bSort": null,
23740 
23741   /**
23742    * Multi-column sorting
23743    * Note that this parameter will be set by the initialisation routine. To
23744    * set a default use {@link DataTable.defaults}.
23745    *  @type boolean
23746    */
23747   "bSortMulti": null,
23748 
23749   /**
23750    * Apply a class to the columns which are being sorted to provide a
23751    * visual highlight or not. This can slow things down when enabled since
23752    * there is a lot of DOM interaction.
23753    * Note that this parameter will be set by the initialisation routine. To
23754    * set a default use {@link DataTable.defaults}.
23755    *  @type boolean
23756    */
23757   "bSortClasses": null,
23758 
23759   /**
23760    * State saving enablement flag.
23761    * Note that this parameter will be set by the initialisation routine. To
23762    * set a default use {@link DataTable.defaults}.
23763    *  @type boolean
23764    */
23765   "bStateSave": null
23766  },
23767 
23768 
23769  /**
23770   * Scrolling settings for a table.
23771   *  @namespace
23772   */
23773  "oScroll": {
23774   /**
23775    * When the table is shorter in height than sScrollY, collapse the
23776    * table container down to the height of the table (when true).
23777    * Note that this parameter will be set by the initialisation routine. To
23778    * set a default use {@link DataTable.defaults}.
23779    *  @type boolean
23780    */
23781   "bCollapse": null,
23782 
23783   /**
23784    * Width of the scrollbar for the web-browser's platform. Calculated
23785    * during table initialisation.
23786    *  @type int
23787    *  @default 0
23788    */
23789   "iBarWidth": 0,
23790 
23791   /**
23792    * Viewport width for horizontal scrolling. Horizontal scrolling is
23793    * disabled if an empty string.
23794    * Note that this parameter will be set by the initialisation routine. To
23795    * set a default use {@link DataTable.defaults}.
23796    *  @type string
23797    */
23798   "sX": null,
23799 
23800   /**
23801    * Width to expand the table to when using x-scrolling. Typically you
23802    * should not need to use this.
23803    * Note that this parameter will be set by the initialisation routine. To
23804    * set a default use {@link DataTable.defaults}.
23805    *  @type string
23806    *  @deprecated
23807    */
23808   "sXInner": null,
23809 
23810   /**
23811    * Viewport height for vertical scrolling. Vertical scrolling is disabled
23812    * if an empty string.
23813    * Note that this parameter will be set by the initialisation routine. To
23814    * set a default use {@link DataTable.defaults}.
23815    *  @type string
23816    */
23817   "sY": null
23818  },
23819 
23820  /**
23821   * Language information for the table.
23822   *  @namespace
23823   *  @extends DataTable.defaults.oLanguage
23824   */
23825  "oLanguage": {
23826   /**
23827    * Information callback function. See
23828    * {@link DataTable.defaults.fnInfoCallback}
23829    *  @type function
23830    *  @default null
23831    */
23832   "fnInfoCallback": null
23833  },
23834 
23835  /**
23836   * Browser support parameters
23837   *  @namespace
23838   */
23839  "oBrowser": {
23840   /**
23841    * Indicate if the browser incorrectly calculates width:100% inside a
23842    * scrolling element (IE6/7)
23843    *  @type boolean
23844    *  @default false
23845    */
23846   "bScrollOversize": false,
23847 
23848   /**
23849    * Determine if the vertical scrollbar is on the right or left of the
23850    * scrolling container - needed for rtl language layout, although not
23851    * all browsers move the scrollbar (Safari).
23852    *  @type boolean
23853    *  @default false
23854    */
23855   "bScrollbarLeft": false,
23856 
23857   /**
23858    * Flag for if `getBoundingClientRect` is fully supported or not
23859    *  @type boolean
23860    *  @default false
23861    */
23862   "bBounding": false,
23863 
23864   /**
23865    * Browser scrollbar width
23866    *  @type integer
23867    *  @default 0
23868    */
23869   "barWidth": 0
23870  },
23871 
23872 
23873  "ajax": null,
23874 
23875 
23876  /**
23877   * Array referencing the nodes which are used for the features. The
23878   * parameters of this object match what is allowed by sDom - i.e.
23879   *   <ul>
23880   *     <li>'l' - Length changing</li>
23881   *     <li>'f' - Filtering input</li>
23882   *     <li>'t' - The table!</li>
23883   *     <li>'i' - Information</li>
23884   *     <li>'p' - Pagination</li>
23885   *     <li>'r' - pRocessing</li>
23886   *   </ul>
23887   *  @type array
23888   *  @default []
23889   */
23890  "aanFeatures": [],
23891 
23892  /**
23893   * Store data information - see {@link DataTable.models.oRow} for detailed
23894   * information.
23895   *  @type array
23896   *  @default []
23897   */
23898  "aoData": [],
23899 
23900  /**
23901   * Array of indexes which are in the current display (after filtering etc)
23902   *  @type array
23903   *  @default []
23904   */
23905  "aiDisplay": [],
23906 
23907  /**
23908   * Array of indexes for display - no filtering
23909   *  @type array
23910   *  @default []
23911   */
23912  "aiDisplayMaster": [],
23913 
23914  /**
23915   * Map of row ids to data indexes
23916   *  @type object
23917   *  @default {}
23918   */
23919  "aIds": {},
23920 
23921  /**
23922   * Store information about each column that is in use
23923   *  @type array
23924   *  @default []
23925   */
23926  "aoColumns": [],
23927 
23928  /**
23929   * Store information about the table's header
23930   *  @type array
23931   *  @default []
23932   */
23933  "aoHeader": [],
23934 
23935  /**
23936   * Store information about the table's footer
23937   *  @type array
23938   *  @default []
23939   */
23940  "aoFooter": [],
23941 
23942  /**
23943   * Store the applied global search information in case we want to force a
23944   * research or compare the old search to a new one.
23945   * Note that this parameter will be set by the initialisation routine. To
23946   * set a default use {@link DataTable.defaults}.
23947   *  @namespace
23948   *  @extends DataTable.models.oSearch
23949   */
23950  "oPreviousSearch": {},
23951 
23952  /**
23953   * Store the applied search for each column - see
23954   * {@link DataTable.models.oSearch} for the format that is used for the
23955   * filtering information for each column.
23956   *  @type array
23957   *  @default []
23958   */
23959  "aoPreSearchCols": [],
23960 
23961  /**
23962   * Sorting that is applied to the table. Note that the inner arrays are
23963   * used in the following manner:
23964   * <ul>
23965   *   <li>Index 0 - column number</li>
23966   *   <li>Index 1 - current sorting direction</li>
23967   * </ul>
23968   * Note that this parameter will be set by the initialisation routine. To
23969   * set a default use {@link DataTable.defaults}.
23970   *  @type array
23971   *  @todo These inner arrays should really be objects
23972   */
23973  "aaSorting": null,
23974 
23975  /**
23976   * Sorting that is always applied to the table (i.e. prefixed in front of
23977   * aaSorting).
23978   * Note that this parameter will be set by the initialisation routine. To
23979   * set a default use {@link DataTable.defaults}.
23980   *  @type array
23981   *  @default []
23982   */
23983  "aaSortingFixed": [],
23984 
23985  /**
23986   * Classes to use for the striping of a table.
23987   * Note that this parameter will be set by the initialisation routine. To
23988   * set a default use {@link DataTable.defaults}.
23989   *  @type array
23990   *  @default []
23991   */
23992  "asStripeClasses": null,
23993 
23994  /**
23995   * If restoring a table - we should restore its striping classes as well
23996   *  @type array
23997   *  @default []
23998   */
23999  "asDestroyStripes": [],
24000 
24001  /**
24002   * If restoring a table - we should restore its width
24003   *  @type int
24004   *  @default 0
24005   */
24006  "sDestroyWidth": 0,
24007 
24008  /**
24009   * Callback functions array for every time a row is inserted (i.e. on a draw).
24010   *  @type array
24011   *  @default []
24012   */
24013  "aoRowCallback": [],
24014 
24015  /**
24016   * Callback functions for the header on each draw.
24017   *  @type array
24018   *  @default []
24019   */
24020  "aoHeaderCallback": [],
24021 
24022  /**
24023   * Callback function for the footer on each draw.
24024   *  @type array
24025   *  @default []
24026   */
24027  "aoFooterCallback": [],
24028 
24029  /**
24030   * Array of callback functions for draw callback functions
24031   *  @type array
24032   *  @default []
24033   */
24034  "aoDrawCallback": [],
24035 
24036  /**
24037   * Array of callback functions for row created function
24038   *  @type array
24039   *  @default []
24040   */
24041  "aoRowCreatedCallback": [],
24042 
24043  /**
24044   * Callback functions for just before the table is redrawn. A return of
24045   * false will be used to cancel the draw.
24046   *  @type array
24047   *  @default []
24048   */
24049  "aoPreDrawCallback": [],
24050 
24051  /**
24052   * Callback functions for when the table has been initialised.
24053   *  @type array
24054   *  @default []
24055   */
24056  "aoInitComplete": [],
24057 
24058 
24059  /**
24060   * Callbacks for modifying the settings to be stored for state saving, prior to
24061   * saving state.
24062   *  @type array
24063   *  @default []
24064   */
24065  "aoStateSaveParams": [],
24066 
24067  /**
24068   * Callbacks for modifying the settings that have been stored for state saving
24069   * prior to using the stored values to restore the state.
24070   *  @type array
24071   *  @default []
24072   */
24073  "aoStateLoadParams": [],
24074 
24075  /**
24076   * Callbacks for operating on the settings object once the saved state has been
24077   * loaded
24078   *  @type array
24079   *  @default []
24080   */
24081  "aoStateLoaded": [],
24082 
24083  /**
24084   * Cache the table ID for quick access
24085   *  @type string
24086   *  @default <i>Empty string</i>
24087   */
24088  "sTableId": "",
24089 
24090  /**
24091   * The TABLE node for the main table
24092   *  @type node
24093   *  @default null
24094   */
24095  "nTable": null,
24096 
24097  /**
24098   * Permanent ref to the thead element
24099   *  @type node
24100   *  @default null
24101   */
24102  "nTHead": null,
24103 
24104  /**
24105   * Permanent ref to the tfoot element - if it exists
24106   *  @type node
24107   *  @default null
24108   */
24109  "nTFoot": null,
24110 
24111  /**
24112   * Permanent ref to the tbody element
24113   *  @type node
24114   *  @default null
24115   */
24116  "nTBody": null,
24117 
24118  /**
24119   * Cache the wrapper node (contains all DataTables controlled elements)
24120   *  @type node
24121   *  @default null
24122   */
24123  "nTableWrapper": null,
24124 
24125  /**
24126   * Indicate if when using server-side processing the loading of data
24127   * should be deferred until the second draw.
24128   * Note that this parameter will be set by the initialisation routine. To
24129   * set a default use {@link DataTable.defaults}.
24130   *  @type boolean
24131   *  @default false
24132   */
24133  "bDeferLoading": false,
24134 
24135  /**
24136   * Indicate if all required information has been read in
24137   *  @type boolean
24138   *  @default false
24139   */
24140  "bInitialised": false,
24141 
24142  /**
24143   * Information about open rows. Each object in the array has the parameters
24144   * 'nTr' and 'nParent'
24145   *  @type array
24146   *  @default []
24147   */
24148  "aoOpenRows": [],
24149 
24150  /**
24151   * Dictate the positioning of DataTables' control elements - see
24152   * {@link DataTable.model.oInit.sDom}.
24153   * Note that this parameter will be set by the initialisation routine. To
24154   * set a default use {@link DataTable.defaults}.
24155   *  @type string
24156   *  @default null
24157   */
24158  "sDom": null,
24159 
24160  /**
24161   * Search delay (in mS)
24162   *  @type integer
24163   *  @default null
24164   */
24165  "searchDelay": null,
24166 
24167  /**
24168   * Which type of pagination should be used.
24169   * Note that this parameter will be set by the initialisation routine. To
24170   * set a default use {@link DataTable.defaults}.
24171   *  @type string
24172   *  @default two_button
24173   */
24174  "sPaginationType": "two_button",
24175 
24176  /**
24177   * The state duration (for `stateSave`) in seconds.
24178   * Note that this parameter will be set by the initialisation routine. To
24179   * set a default use {@link DataTable.defaults}.
24180   *  @type int
24181   *  @default 0
24182   */
24183  "iStateDuration": 0,
24184 
24185  /**
24186   * Array of callback functions for state saving. Each array element is an
24187   * object with the following parameters:
24188   *   <ul>
24189   *     <li>function:fn - function to call. Takes two parameters, oSettings
24190   *       and the JSON string to save that has been thus far created. Returns
24191   *       a JSON string to be inserted into a json object
24192   *       (i.e. '"param": [ 0, 1, 2]')</li>
24193   *     <li>string:sName - name of callback</li>
24194   *   </ul>
24195   *  @type array
24196   *  @default []
24197   */
24198  "aoStateSave": [],
24199 
24200  /**
24201   * Array of callback functions for state loading. Each array element is an
24202   * object with the following parameters:
24203   *   <ul>
24204   *     <li>function:fn - function to call. Takes two parameters, oSettings
24205   *       and the object stored. May return false to cancel state loading</li>
24206   *     <li>string:sName - name of callback</li>
24207   *   </ul>
24208   *  @type array
24209   *  @default []
24210   */
24211  "aoStateLoad": [],
24212 
24213  /**
24214   * State that was saved. Useful for back reference
24215   *  @type object
24216   *  @default null
24217   */
24218  "oSavedState": null,
24219 
24220  /**
24221   * State that was loaded. Useful for back reference
24222   *  @type object
24223   *  @default null
24224   */
24225  "oLoadedState": null,
24226 
24227  /**
24228   * Source url for AJAX data for the table.
24229   * Note that this parameter will be set by the initialisation routine. To
24230   * set a default use {@link DataTable.defaults}.
24231   *  @type string
24232   *  @default null
24233   */
24234  "sAjaxSource": null,
24235 
24236  /**
24237   * Property from a given object from which to read the table data from. This
24238   * can be an empty string (when not server-side processing), in which case
24239   * it is  assumed an an array is given directly.
24240   * Note that this parameter will be set by the initialisation routine. To
24241   * set a default use {@link DataTable.defaults}.
24242   *  @type string
24243   */
24244  "sAjaxDataProp": null,
24245 
24246  /**
24247   * Note if draw should be blocked while getting data
24248   *  @type boolean
24249   *  @default true
24250   */
24251  "bAjaxDataGet": true,
24252 
24253  /**
24254   * The last jQuery XHR object that was used for server-side data gathering.
24255   * This can be used for working with the XHR information in one of the
24256   * callbacks
24257   *  @type object
24258   *  @default null
24259   */
24260  "jqXHR": null,
24261 
24262  /**
24263   * JSON returned from the server in the last Ajax request
24264   *  @type object
24265   *  @default undefined
24266   */
24267  "json": undefined,
24268 
24269  /**
24270   * Data submitted as part of the last Ajax request
24271   *  @type object
24272   *  @default undefined
24273   */
24274  "oAjaxData": undefined,
24275 
24276  /**
24277   * Function to get the server-side data.
24278   * Note that this parameter will be set by the initialisation routine. To
24279   * set a default use {@link DataTable.defaults}.
24280   *  @type function
24281   */
24282  "fnServerData": null,
24283 
24284  /**
24285   * Functions which are called prior to sending an Ajax request so extra
24286   * parameters can easily be sent to the server
24287   *  @type array
24288   *  @default []
24289   */
24290  "aoServerParams": [],
24291 
24292  /**
24293   * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
24294   * required).
24295   * Note that this parameter will be set by the initialisation routine. To
24296   * set a default use {@link DataTable.defaults}.
24297   *  @type string
24298   */
24299  "sServerMethod": null,
24300 
24301  /**
24302   * Format numbers for display.
24303   * Note that this parameter will be set by the initialisation routine. To
24304   * set a default use {@link DataTable.defaults}.
24305   *  @type function
24306   */
24307  "fnFormatNumber": null,
24308 
24309  /**
24310   * List of options that can be used for the user selectable length menu.
24311   * Note that this parameter will be set by the initialisation routine. To
24312   * set a default use {@link DataTable.defaults}.
24313   *  @type array
24314   *  @default []
24315   */
24316  "aLengthMenu": null,
24317 
24318  /**
24319   * Counter for the draws that the table does. Also used as a tracker for
24320   * server-side processing
24321   *  @type int
24322   *  @default 0
24323   */
24324  "iDraw": 0,
24325 
24326  /**
24327   * Indicate if a redraw is being done - useful for Ajax
24328   *  @type boolean
24329   *  @default false
24330   */
24331  "bDrawing": false,
24332 
24333  /**
24334   * Draw index (iDraw) of the last error when parsing the returned data
24335   *  @type int
24336   *  @default -1
24337   */
24338  "iDrawError": -1,
24339 
24340  /**
24341   * Paging display length
24342   *  @type int
24343   *  @default 10
24344   */
24345  "_iDisplayLength": 10,
24346 
24347  /**
24348   * Paging start point - aiDisplay index
24349   *  @type int
24350   *  @default 0
24351   */
24352  "_iDisplayStart": 0,
24353 
24354  /**
24355   * Server-side processing - number of records in the result set
24356   * (i.e. before filtering), Use fnRecordsTotal rather than
24357   * this property to get the value of the number of records, regardless of
24358   * the server-side processing setting.
24359   *  @type int
24360   *  @default 0
24361   *  @private
24362   */
24363  "_iRecordsTotal": 0,
24364 
24365  /**
24366   * Server-side processing - number of records in the current display set
24367   * (i.e. after filtering). Use fnRecordsDisplay rather than
24368   * this property to get the value of the number of records, regardless of
24369   * the server-side processing setting.
24370   *  @type boolean
24371   *  @default 0
24372   *  @private
24373   */
24374  "_iRecordsDisplay": 0,
24375 
24376  /**
24377   * Flag to indicate if jQuery UI marking and classes should be used.
24378   * Note that this parameter will be set by the initialisation routine. To
24379   * set a default use {@link DataTable.defaults}.
24380   *  @type boolean
24381   */
24382  "bJUI": null,
24383 
24384  /**
24385   * The classes to use for the table
24386   *  @type object
24387   *  @default {}
24388   */
24389  "oClasses": {},
24390 
24391  /**
24392   * Flag attached to the settings object so you can check in the draw
24393   * callback if filtering has been done in the draw. Deprecated 
vendor: 4,896 bytes, lines 24393-24611
24393in favour of
24394   * events.
24395   *  @type boolean
24396   *  @default false
24397   *  @deprecated
24398   */
24399  "bFiltered": false,
24400 
24401  /**
24402   * Flag attached to the settings object so you can check in the draw
24403   * callback if sorting has been done in the draw. Deprecated in favour of
24404   * events.
24405   *  @type boolean
24406   *  @default false
24407   *  @deprecated
24408   */
24409  "bSorted": false,
24410 
24411  /**
24412   * Indicate that if multiple rows are in the header and there is more than
24413   * one unique cell per column, if the top one (true) or bottom one (false)
24414   * should be used for sorting / title by DataTables.
24415   * Note that this parameter will be set by the initialisation routine. To
24416   * set a default use {@link DataTable.defaults}.
24417   *  @type boolean
24418   */
24419  "bSortCellsTop": null,
24420 
24421  /**
24422   * Initialisation object that is used for the table
24423   *  @type object
24424   *  @default null
24425   */
24426  "oInit": null,
24427 
24428  /**
24429   * Destroy callback functions - for plug-ins to attach themselves to the
24430   * destroy so they can clean up markup and events.
24431   *  @type array
24432   *  @default []
24433   */
24434  "aoDestroyCallback": [],
24435 
24436 
24437  /**
24438   * Get the number of records in the current record set, before filtering
24439   *  @type function
24440   */
24441  "fnRecordsTotal": function ()
24442  {
24443   return _fnDataSource( this ) == 'ssp' ?
24444    this._iRecordsTotal * 1 :
24445    this.aiDisplayMaster.length;
24446  },
24447 
24448  /**
24449   * Get the number of records in the current record set, after filtering
24450   *  @type function
24451   */
24452  "fnRecordsDisplay": function ()
24453  {
24454   return _fnDataSource( this ) == 'ssp' ?
24455    this._iRecordsDisplay * 1 :
24456    this.aiDisplay.length;
24457  },
24458 
24459  /**
24460   * Get the display end point - aiDisplay index
24461   *  @type function
24462   */
24463  "fnDisplayEnd": function ()
24464  {
24465   var
24466    len      = this._iDisplayLength,
24467    start    = this._iDisplayStart,
24468    calc     = start + len,
24469    records  = this.aiDisplay.length,
24470    features = this.oFeatures,
24471    paginate = features.bPaginate;
24472 
24473   if ( features.bServerSide ) {
24474    return paginate === false || len === -1 ?
24475     start + records :
24476     Math.min( start+len, this._iRecordsDisplay );
24477   }
24478   else {
24479    return ! paginate || calc>records || len===-1 ?
24480     records :
24481     calc;
24482   }
24483  },
24484 
24485  /**
24486   * The DataTables object for this table
24487   *  @type object
24488   *  @default null
24489   */
24490  "oInstance": null,
24491 
24492  /**
24493   * Unique identifier for each instance of the DataTables object. If there
24494   * is an ID on the table node, then it takes that value, otherwise an
24495   * incrementing internal counter is used.
24496   *  @type string
24497   *  @default null
24498   */
24499  "sInstance": null,
24500 
24501  /**
24502   * tabindex attribute value that is added to DataTables control elements, allowing
24503   * keyboard navigation of the table and its controls.
24504   */
24505  "iTabIndex": 0,
24506 
24507  /**
24508   * DIV container for the footer scrolling table if scrolling
24509   */
24510  "nScrollHead": null,
24511 
24512  /**
24513   * DIV container for the footer scrolling table if scrolling
24514   */
24515  "nScrollFoot": null,
24516 
24517  /**
24518   * Last applied sort
24519   *  @type array
24520   *  @default []
24521   */
24522  "aLastSort": [],
24523 
24524  /**
24525   * Stored plug-in instances
24526   *  @type object
24527   *  @default {}
24528   */
24529  "oPlugins": {},
24530 
24531  /**
24532   * Function used to get a row's id from the row's data
24533   *  @type function
24534   *  @default null
24535   */
24536  "rowIdFn": null,
24537 
24538  /**
24539   * Data location where to store a row's id
24540   *  @type string
24541   *  @default null
24542   */
24543  "rowId": null
24544 };
24545 /**
24546  * Extension object for DataTables that is used to provide all extension
24547  * options.
24548  *
24549  * Note that the `DataTable.ext` object is available through
24550  * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
24551  * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
24552  *  @namespace
24553  *  @extends DataTable.models.ext
24554  */
24555 
24556 
24557 /**
24558  * DataTables extensions
24559  * 
24560  * This namespace acts as a collection area for plug-ins that can be used to
24561  * extend DataTables capabilities. Indeed many of the build in methods
24562  * use this method to provide their own capabilities (sorting methods for
24563  * example).
24564  *
24565  * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
24566  * reasons
24567  *
24568  *  @namespace
24569  */
24570 DataTable.ext = _ext = {
24571  /**
24572   * Buttons. For use with the Buttons extension for DataTables. This is
24573   * defined here so other extensions can define buttons regardless of load
24574   * order. It is _not_ used by DataTables core.
24575   *
24576   *  @type object
24577   *  @default {}
24578   */
24579  buttons: {},
24580 
24581 
24582  /**
24583   * Element class names
24584   *
24585   *  @type object
24586   *  @default {}
24587   */
24588  classes: {},
24589 
24590 
24591  /**
24592   * DataTables build type (expanded by the download builder)
24593   *
24594   *  @type string
24595   */
24596  builder: "-source-",
24597 
24598 
24599  /**
24600   * Error reporting.
24601   * 
24602   * How should DataTables report an error. Can take the value 'alert',
24603   * 'throw', 'none' or a function.
24604   *
24605   *  @type string|function
24606   *  @default alert
24607   */
24608  errMode: "alert",
24609 
24610 
24611  /**
24612   * Feature plug-ins.
24613   * 
24614   * This is an array of objects which describe the feature plug-ins that are
24615   * available to DataTables. These feature plug-ins are then available for
24616   * use through the `dom` initialisation option.
24617   * 
24618   * Each feature plug-in is described by an object which must have the
24619   * following properties:
24620   * 
24621   * * `fnInit` - function that is used to initialise the plug-in,
24622   * * `cFeature` - a character so the feature can be enabled by the `dom`
24623   *   instillation option. This is case sensitive.
24624   *
24625   * The `fnInit` function has the following input parameters:
24626   *
24627   * 1. `{object}` DataTables settings object: see
24628   *    {@link DataTable.models.oSettings}
24629   *
24630   * And the following return is expected:
24631   * 
24632   * * {node|null} The element which contains your feature. Note that the
24633   *   return may also be void if your plug-in does not require to inject any
24634   *   DOM elements into DataTables control (`dom`) - for example this might
24635   *   be useful when developing a plug-in which allows table control via
24636   *   keyboard entry
24637   *
24638   *  @type array
24639   *
24640   *  @example
24641   *    $.fn.dataTable.ext.features.push( {
24642   *      "fnInit": function( oSettings ) {
24643   *        return new TableTools( { "oDTSettings": oSettings } );
24644   *      },
24645   *      "cFeature": "T"
24646   *    } );
24647   */
24648  feature: [],
24649 
24650 
24651  /**
24652   * Row searching.
24653   * 
24654   * This method of searching is complimentary to the default type based
24655   * searching, and a lot more comprehensive as it allows you complete control
24656   * over the searching logic. Each element in this array is a function
24657   * (parameters described below) that is called for every row in the table,
24658   * and your logic decides if it should be included in the searching data set
24659   * or not.
24660   *
24661   * Searching functions have the following input parameters:
24662   *
24663   * 1. `{object}` DataTables settings object: see
24664   *    {@link DataTable.models.oSettings}
24665   * 2. `{array|object}` Data for the row to be processed (same as the
24666   *    original format that was passed in as the data source, or an array
24667   *    from a DOM data source
24668   * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
24669   *    can be useful to retrieve the `TR` element if you need DOM interaction.
24670   *
24671   * And the following return is expected:
24672   *
24673   * * {boolean} Include the row in the searched result set (true) or not
24674   *   (false)
24675   *
24676   * Note that as with the main search ability in DataTables, technically this
24677   * is "filtering", since it is subtractive. However, for consistency in
24678   * naming we call it searching here.
24679   *
24680   *  @type array
24681   *  @default []
24682   *
24683   *  @example
24684   *    // The following example shows custom search being applied to the
24685   *    // fourth column (i.e. the data[3] index) based on two input values
24686   *    // from the end-user, matching the data in a certain range.
24687   *    $.fn.dataTable.ext.search.push(
24688   *      function( settings, data, dataIndex ) {
24689   *        var min = document.getElementById('min').value * 1;
24690   *        var max = document.getElementById('max').value * 1;
24691   *        var version = data[3] == "-" ? 0 : data[3]*1;
24692   *
24693   *        if ( min == "" && max == "" ) {
24694   *          return true;
24695   *        }
24696   *        else if ( min == "" && version < max ) {
24697   *          return true;
24698   *        }
24699   *        else if ( min < version && "" == max ) {
24700   *          return true;
24701   *        }
24702   *        else if ( min < version && version < max ) {
24703   *          return true;
24704   *        }
24705   *        return false;
24706   *      }
24707   *    );
24708   */
24709  search: [],
24710 
24711 
24712  /**
24713   * Selector extensions
24714   *
24715   * The `selector` option can be used to extend the options available for the
24716   * selector modifier options (`selector-modifier` object data type) that
24717   * each of the three built in selector types offer (row, column and cell +
24718   * their plural counterparts). For example the Select extension uses this
24719   * mechanism to provide an option to select only rows, columns and cells
24720   * that have been marked as selected by the end user (`{selected: true}`),
24721   * which can be used in conjunction with the existing built in selector
24722   * options.
24723   *
24724   * Each property is an array to which functions can be pushed. The functions
24725   * take three attributes:
24726   *
24727   * * Settings object for the host table
24728   * * Options object (`selector-modifier` object type)
24729   * * Array of selected item indexes
24730   *
24731   * The return is an array of the resulting item indexes after the custom
24732   * selector has been applied.
24733   *
24734   *  @type object
24735   */
24736  selector: {
24737   cell: [],
24738   column: [],
24739   row: []
24740  },
24741 
24742 
24743  /**
24744   * Internal functions, exposed for used in plug-ins.
24745   * 
24746   * Please note that you should not need to use the internal methods for
24747   * anything other than a plug-in (and even then, try to avoid if possible).
24748   * The internal function may change between releases.
24749   *
24750   *  @type object
24751   *  @default {}
24752   */
24753  internal: {},
24754 
24755 
24756  /**
24757   * Legacy configuration options. Enable and disable legacy options that
24758   * are available in DataTables.
24759   *
24760   *  @type object
24761   */
24762  legacy: {
24763   /**
24764    * Enable / disable DataTables 1.9 compatible server-side processing
24765    * requests
24766    *
24767    *  @type boolean
24768    *  @default null
24769    */
24770   ajax: null
24771  },
24772 
24773 
24774  /**
24775   * Pagination plug-in methods.
24776   * 
24777   * Each entry in this object is a function and defines which buttons should
24778   * be shown by the pagination rendering method that is used for the table:
24779   * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
24780   * buttons are displayed in the document, while the functions here tell it
24781   * what buttons to display. This is done by returning an array of button
24782   * descriptions (what each button will do).
24783   *
24784   * Pagination types (the four built in options and any additional plug-in
24785   * options defined here) can be used through the `paginationType`
24786   * initialisation parameter.
24787   *
24788   * The functions defined take two parameters:
24789   *
24790   * 1. `{int} page` The current page index
24791   * 2. `{int} pages` The number of pages in the table
24792   *
24793   * Each function is expected to return an array where each element of the
24794   * array can be one of:
24795   *
24796   * * `first` - Jump to first page when activated
24797   * * `last` - Jump to last page when activated
24798   * * `previous` - Show previous page when activated
24799   * * `next` - Show next page when activated
24800   * * `{int}` - Show page of the index given
24801   * * `{array}` - A nested array containing the above elements to add a
24802   *   containing 'DIV' element (might be useful for styling).
24803   *
24804   * Note that DataTables v1.9- used this object slightly differently whereby
24805   * an object with two functions would be defined for each plug-in. That
24806   * ability is still supported by DataTables 1.10+ to provide backwards
24807   * compatibility, but this option of use is now decremented and no longer
24808   * documented in DataTables 1.10+.
24809   *
24810   *  @type object
24811   *  @default {}
24812   *
24813   *  @example
24814   *    // Show previous, next and current page buttons only
24815   *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
24816   *      return [ 'previous', page, 'next' ];
24817   *    };
24818   */
24819  pager: {},
24820 
24821 
24822  renderer: {
24823   pageButton: {},
24824   header: {}
24825  },
24826 
24827 
24828  /**
24829   * Ordering plug-ins - custom data source
24830   * 
24831   * The extension options for ordering of data available here is complimentary
24832   * to the default type based ordering that DataTables typically uses. It
24833   * allows much greater control over the the data that is being used to
24834   * order a column, but is necessarily therefore more complex.
24835   * 
24836   * This type of ordering is useful if you want to do ordering based on data
24837   * live from the DOM (for example the contents of an 'input' element) rather
24838   * than just the static string that DataTables knows of.
24839   * 
24840   * The way these plug-ins work is that you create an array of the values you
24841   * wish to be ordering for the column in question and then return that
24842   * array. The data in the array much be in the index order of the rows in
24843   * the table (not the currently ordering order!). Which order data gathering
24844   * function is run here depends on the `dt-init columns.orderDataType`
24845   * parameter that is used for the column (if any).
24846   *
24847   * The functions defined take two parameters:
24848   *
24849   * 1. `{object}` DataTables settings object: see
24850   *    {@link DataTable.models.oSettings}
24851   * 2. `{int}` Target column index
24852   *
24853   * Each function is expected to return an array:
24854   *
24855   * * `{array}` Data for the column to be ordering upon
24856   *
24857   *  @type array
24858   *
24859   *  @example
24860   *    // Ordering using `input` node values
24861   *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
24862   *    {
24863   *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
24864   *        return $('input', td).val();
24865   *      } );
24866   *    }
24867   */
24868  order: {},
24869 
24870 
24871  /**
24872   * Type based plug-ins.
24873   *
24874   * Each column in DataTables has a type assigned to it, either by automatic
24875   * detection or by direct assignment using the `type` option for the column.
24876   * The type of a column will effect how it is ordering and search (plug-ins
24877   * can also make use of the column type if required).
24878   *
24879   * @namespace
24880   */
24881  type: {
24882   /**
24883    * Type detection functions.
24884    *
24885    * The functions defined in this object are used to automatically detect
24886    * a column's type, making initialisation of DataTables super easy, even
24887    * when complex data is in the table.
24888    *
24889    * The functions defined take two parameters:
24890    *
24891       *  1. `{*}` Data from the column cell to be analysed
24892       *  2. `{settings}` DataTables settings object. This can be used to
24893       *     perform context specific type detection - for example detection
24894       *     based on language settings such as using a comma for a decimal
24895       *     place. Generally speaking the options from the settings will not
24896       *     be required
24897    *
24898    * Each function is expected to return:
24899    *
24900    * * `{string|null}` Data type detected, or null if unknown (and thus
24901    *   pass it on to the other type detection functions.
24902    *
24903    *  @type array
24904    *
24905    *  @example
24906    *    // Currency type detection plug-in:
24907    *    $.fn.dataTable.ext.type.detect.push(
24908    *      function ( data, settings ) {
24909    *        // Check the numeric part
24910    *        if ( ! $.isNumeric( data.substring(1) ) ) {
24911    *          return null;
24912    *        }
24913    *
24914    *        // Check prefixed by currency
24915    *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
24916    *          return 'currency';
24917    *        }
24918    *        return null;
24919    *      }
24920    *    );
24921    */
24922   detect: [],
24923 
24924 
24925   /**
24926    * Type based search formatting.
24927    *
24928    * The type based searching functions can be used to pre-format the
24929    * data to be search on. For example, it can be used to strip HTML
24930    * tags or to de-format telephone numbers for numeric only searching.
24931    *
24932    * Note that is a search is not defined for a column of a given type,
24933    * no search formatting will be performed.
24934    * 
24935    * Pre-processing of searching data plug-ins - When you assign the sType
24936    * for a column (or have it automatically detected for you by DataTables
24937    * or a type detection plug-in), you will typically be using this for
24938    * custom sorting, but it can also be used to provide custom searching
24939    * by allowing you to pre-processing the data and returning the data in
24940    * the format that should be searched upon. This is done by adding
24941    * functions this object with a parameter name which matches the sType
24942    * for that target column. This is the corollary of <i>afnSortData</i>
24943    * for searching data.
24944    *
24945    * The functions defined take a single parameter:
24946    *
24947       *  1. `{*}` Data from the column cell to be prepared for searching
24948    *
24949    * Each function is expected to return:
24950    *
24951    * * `{string|null}` Formatted string that will be used for the searching.
24952    *
24953    *  @type object
24954    *  @default {}
24955    *
24956    *  @example
24957    *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
24958    *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
24959    *    }
24960    */
24961   search: {},
24962 
24963 
24964   /**
24965    * Type based ordering.
24966    *
24967    * The column type tells DataTables what ordering to apply to the table
24968    * when a column is sorted upon. The order for each type that is defined,
24969    * is defined by the functions available in this object.
24970    *
24971    * Each ordering option can be described by three properties added to
24972    * this object:
24973    *
24974    * * `{type}-pre` - Pre-formatting function
24975    * * `{type}-asc` - Ascending order function
24976    * * `{type}-desc` - Descending order function
24977    *
24978    * All three can be used together, only `{type}-pre` or only
24979    * `{type}-asc` and `{type}-desc` together. It is generally recommended
24980    * that only `{type}-pre` is used, as this provides the optimal
24981    * implementation in terms of speed, although the others are provided
24982    * for compatibility with existing Javascript sort functions.
24983    *
24984    * `{type}-pre`: Functions defined take a single parameter:
24985    *
24986       *  1. `{*}` Data from the column cell to be prepared for ordering
24987    *
24988    * And return:
24989    *
24990    * * `{*}` Data to be sorted upon
24991    *
24992    * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
24993    * functions, taking two parameters:
24994    *
24995       *  1. `{*}` Data to compare to the second parameter
24996       *  2. `{*}` Data to compare to the first parameter
24997    *
24998    * And returning:
24999    *
25000    * * `{*}` Ordering match: <0 if first parameter should be sorted lower
25001    *   than the second parameter, ===0 if the two parameters are equal and
25002    *   >0 if the first parameter should be sorted height than the second
25003    *   parameter.
25004    * 
25005    *  @type object
25006    *  @default {}
25007    *
25008    *  @example
25009    *    // Numeric ordering of formatted numbers with a pre-formatter
25010    *    $.extend( $.fn.dataTable.ext.type.order, {
25011    *      "string-pre": function(x) {
25012    *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
25013    *        return parseFloat( a );
25014    *      }
25015    *    } );
25016    *
25017    *  @example
25018    *    // Case-sensitive string ordering, with no pre-formatting method
25019    *    $.extend( $.fn.dataTable.ext.order, {
25020    *      "string-case-asc": function(x,y) {
25021    *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
25022    *      },
25023    *      "string-case-desc": function(x,y) {
25024    *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
25025    *      }
25026    *    } );
25027    */
25028   order: {}
25029  },
25030 
25031  /**
25032   * Unique DataTables instance counter
25033   *
25034   * @type int
25035   * @private
25036   */
25037  _unique: 0,
25038 
25039 
25040  //
25041  // Depreciated
25042  // The following properties are retained for backwards compatiblity only.
25043  // The should not be used in new projects and will be removed in a future
25044  // version
25045  //
25046 
25047  /**
25048   * Version check function.
25049   *  @type function
25050   *  @depreciated Since 1.10
25051   */
25052  fnVersionCheck: DataTable.fnVersionCheck,
25053 
25054 
25055  /**
25056   * Index for what 'this' index API functions should use
25057   *  @type int
25058   *  @deprecated Since v1.10
25059   */
25060  iApiIndex: 0,
25061 
25062 
25063  /**
25064   * jQuery UI class container
25065   *  @type object
25066   *  @deprecated Since v1.10
25067   */
25068  oJUIClasses: {},
25069 
25070 
25071  /**
25072   * Software version
25073   *  @type string
25074   *  @deprecated Since v1.10
25075   */
25076  sVersion: DataTable.version
25077 };
25078 
25079 
25080 //
25081 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
25082 //
25083 $.extend( _ext, {
25084  afnFiltering: _ext.search,
25085  aTypes:       _ext.type.detect,
25086  ofnSearch:    _ext.type.search,
25087  oSort:        _ext.type.order,
25088  afnSortData:  _ext.order,
25089  aoFeatures:   _ext.feature,
25090  oApi:         _ext.internal,
25091  oStdClasses:  _ext.classes,
25092  oPagination:  _ext.pager
25093 } );
25094 
25095 
25096 $.extend( DataTable.ext.classes, {
25097  "sTable": "dataTable",
25098  "sNoFooter": "no-footer",
25099 
25100  /* Paging buttons */
25101  "sPageButton": "paginate_button",
25102  "sPageButtonActive": "current",
25103  "sPageButtonDisabled": "disabled",
25104 
25105  /* Striping classes */
25106  "sStripeOdd": "odd",
25107  "sStripeEven": "even",
25108 
25109  /* Empty row */
25110  "sRowEmpty": "dataTables_empty",
25111 
25112  /* Features */
25113  "sWrapper": "dataTables_wrapper",
25114  "sFilter": "dataTables_filter",
25115  "sInfo": "dataTables_info",
25116  "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
25117  "sLength": "dataTables_length",
25118  "sProcessing": "dataTables_processing",
25119 
25120  /* Sorting */
25121  "sSortAsc": "sorting_asc",
25122  "sSortDesc": "sorting_desc",
25123  "sSortable": "sorting", /* Sortable in both directions */
25124  "sSortableAsc": "sorting_asc_disabled",
25125  "sSortableDesc": "sorting_desc_disabled",
25126  "sSortableNone": "sorting_disabled",
25127  "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
25128 
25129  /* Filtering */
25130  "sFilterInput": "",
25131 
25132  /* Page length */
25133  "sLengthSelect": "",
25134 
25135  /* Scrolling */
25136  "sScrollWrapper": "dataTables_scroll",
25137  "sScrollHead": "dataTables_scrollHead",
25138  "sScrollHeadInner": "dataTables_scrollHeadInner",
25139  "sScrollBody": "dataTables_scrollBody",
25140  "sScrollFoot": "dataTables_scrollFoot",
25141  "sScrollFootInner": "dataTables_scrollFootInner",
25142 
25143  /* Misc */
25144  "sHeaderTH": "",
25145  "sFooterTH": "",
25146 
25147  // Deprecated
25148  "sSortJUIAsc": "",
25149  "sSortJUIDesc": "",
25150  "sSortJUI": "",
25151  "sSortJUIAscAllowed": "",
25152  "sSortJUIDescAllowed": "",
25153  "sSortJUIWrapper": "",
25154  "sSortIcon": "",
25155  "sJUIHeader": "",
25156  "sJUIFooter": ""
25157 } );
25158 
25159 
25160 (function() {
25161 
25162 // Reused strings for better compression. Closure compiler appears to have a
25163 // weird edge case where it is trying to expand strings rather than use the
25164 // variable version. This results in about 200 bytes being added, for very
25165 // little preference benefit since it this run on script load only.
25166 var _empty = '';
25167 _empty = '';
25168 
25169 var _stateDefault = _empty + 'ui-state-default';
25170 var _sortIcon     = _empty + 'css_right ui-icon ui-icon-';
25171 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
25172 
25173 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
25174  /* Full numbers paging buttons */
25175  "sPageButton":         "fg-button ui-button "+_stateDefault,
25176  "sPageButtonActive":   "ui-state-disabled",
25177  "sPageButtonDisabled": "ui-state-disabled",
25178 
25179  /* Features */
25180  "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
25181   "ui-buttonset-multi paging_", /* Note that the type is postfixed */
25182 
25183  /* Sorting */
25184  "sSortAsc":            _stateDefault+" sorting_asc",
25185  "sSortDesc":           _stateDefault+" sorting_desc",
25186  "sSortable":           _stateDefault+" sorting",
25187  "sSortableAsc":        _stateDefault+" sorting_asc_disabled",
25188  "sSortableDesc":       _stateDefault+" sorting_desc_disabled",
25189  "sSortableNone":       _stateDefault+" sorting_disabled",
25190  "sSortJUIAsc":         _sortIcon+"triangle-1-n",
25191  "sSortJUIDesc":        _sortIcon+"triangle-1-s",
25192  "sSortJUI":            _sortIcon+"carat-2-n-s",
25193  "sSortJUIAscAllowed":  _sortIcon+"carat-1-n",
25194  "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
25195  "sSortJUIWrapper":     "DataTables_sort_wrapper",
25196  "sSortIcon":           "DataTables_sort_icon",
25197 
25198  /* Scrolling */
25199  "sScrollHead": "dataTables_scrollHead "+_stateDefault,
25200  "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
25201 
25202  /* Misc */
25203  "sHeaderTH":  _stateDefault,
25204  "sFooterTH":  _stateDefault,
25205  "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
25206  "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
25207 } );
25208 
25209 }());
25210 
25211 
25212 
25213 var extPagination = DataTable.ext.pager;
25214 
25215 function _numbers ( page, pages ) {
25216  var
25217   numbers = [],
25218   buttons = extPagination.numbers_length,
25219   half = Math.floor( buttons / 2 ),
25220   i = 1;
25221 
25222  if ( pages <= buttons ) {
25223   numbers = _range( 0, pages );
25224  }
25225  else if ( page <= half ) {
25226   numbers = _range( 0, buttons-2 );
25227   numbers.push( 'ellipsis' );
25228   numbers.push( pages-1 );
25229  }
25230  else if ( page >= pages - 1 - half ) {
25231   numbers = _range( pages-(buttons-2), pages );
25232   numbers.splice( 0, 0, 'ellipsis' );
25232 // no unshift in ie6
25233   numbers.splice( 0, 0, 0 );
25234  }
25235  else {
25236   numbers = _range( page-half+2, page+half-1 );
25237   numbers.push( 'ellipsis' );
25238   numbers.push( pages-1 );
25239   numbers.splice( 0, 0, 'ellipsis' );
25240   numbers.splice( 0, 0, 0 );
25241  }
25242 
25243  numbers.DT_el = 'span';
25244  return numbers;
25245 }
25246 
25247 
25248 $.extend( extPagination, {
25249  simple: function ( page, pages ) {
25250   return [ 'previous', 'next' ];
25251  },
25252 
25253  full: function ( page, pages ) {
25254   return [  'first', 'previous', 'next', 'last' ];
25255  },
25256 
25257  numbers: function ( page, pages ) {
25258   return [ _numbers(page, pages) ];
25259  },
25260 
25261  simple_numbers: function ( page, pages ) {
25262   return [ 'previous', _numbers(page, pages), 'next' ];
25263  },
25264 
25265  full_numbers: function ( page, pages ) {
25266   return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
25267  },
25268 
25269  // For testing and plug-ins to use
25270  _numbers: _numbers,
25271 
25272  // Number of number buttons (including ellipsis) to show. _Must be odd!_
25273  numbers_length: 7
25274 } );
25275 
25276 
25277 $.extend( true, DataTable.ext.renderer, {
25278  pageButton: {
25279   _: function ( settings, host, idx, buttons, page, pages ) {
25280    var classes = settings.oClasses;
25281    var lang = settings.oLanguage.oPaginate;
25282    var aria = settings.oLanguage.oAria.paginate || {};
25283    var btnDisplay, btnClass, counter=0;
25284 
25285    var attach = function( container, buttons ) {
25286     var i, ien, node, button;
25287     var clickHandler = function ( e ) {
25288      _fnPageChange( settings, e.data.action, true );
25289     };
25290 
25291     for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
25292      button = buttons[i];
25293 
25294      if ( $.isArray( button ) ) {
25295       var inner = $( '<'+(button.DT_el || 'div')+'/>' )
25296        .appendTo( container );
25297       attach( inner, button );
25298      }
25299      else {
25300       btnDisplay = null;
25301       btnClass = '';
25302 
25303       switch ( button ) {
25304        case 'ellipsis':
25305         container.append('<span class="ellipsis">&#x2026;</span>');
25306         break;
25307 
25308        case 'first':
25309         btnDisplay = lang.sFirst;
25310         btnClass = button + (page > 0 ?
25311          '' : ' '+classes.sPageButtonDisabled);
25312         break;
25313 
25314        case 'previous':
25315         btnDisplay = lang.sPrevious;
25316         btnClass = button + (page > 0 ?
25317          '' : ' '+classes.sPageButtonDisabled);
25318         break;
25319 
25320        case 'next':
25321         btnDisplay = lang.sNext;
25322         btnClass = button + (page < pages-1 ?
25323          '' : ' '+classes.sPageButtonDisabled);
25324         break;
25325 
25326        case 'last':
25327         btnDisplay = lang.sLast;
25328         btnClass = button + (page < pages-1 ?
25329          '' : ' '+classes.sPageButtonDisabled);
25330         break;
25331 
25332        default:
25333         btnDisplay = button + 1;
25334         btnClass = page === button ?
25335          classes.sPageButtonActive : '';
25336         break;
25337       }
25338 
25339       if ( btnDisplay !== null ) {
25340        node = $('<a>', {
25341          'class': classes.sPageButton+' '+btnClass,
25342          'aria-controls': settings.sTableId,
25343          'aria-label': aria[ button ],
25344          'data-dt-idx': counter,
25345          'tabindex': settings.iTabIndex,
25346          'id': idx === 0 && typeof button === 'string' ?
25347           settings.sTableId +'_'+ button :
25348           null
25349         } )
25350         .html( btnDisplay )
25351         .appendTo( container );
25352 
25353        _fnBindAction(
25354         node, {action: button}, clickHandler
25355        );
25356 
25357        counter++;
25358       }
25359      }
25360     }
25361    };
25362 
25363    // IE9 throws an 'unknown error' if document.activeElement is used
25364    // inside an iframe or frame. Try / catch the error. Not good for
25365    // accessibility, but neither are frames.
25366    var activeEl;
25367 
25368    try {
25369     // Because this approach is destroying and recreating the paging
25370     // elements, focus is lost on the select button which is bad for
25371     // accessibility. So we want to restore focus once the draw has
25372     // completed
25373     activeEl = $(host).find(document.activeElement).data('dt-idx');
25374    }
25375    catch (e) {}
25376 
25377    attach( $(host).empty(), buttons );
25378 
25379    if ( activeEl ) {
25380     $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
25381    }
25382   }
25383  }
25384 } );
25385 
25386 
25387 
25388 // Built in type detection. See model.ext.aTypes for information about
25389 // what is required from this methods.
25390 $.extend( DataTable.ext.type.detect, [
vendor: 18,135 bytes, lines 25391-25968
25391  // Plain numbers - first since V8 detects some plain numbers as dates
25392  // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
25393  function ( d, settings )
25394  {
25395   var decimal = settings.oLanguage.sDecimal;
25396   return _isNumber( d, decimal ) ? 'num'+decimal : null;
25397  },
25398 
25399  // Dates (only those recognised by the browser's Date.parse)
25400  function ( d, settings )
25401  {
25402   // V8 will remove any unknown characters at the start and end of the
25403   // expression, leading to false matches such as `$245.12` or `10%` being
25404   // a valid date. See forum thread 18941 for detail.
25405   if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
25406    return null;
25407   }
25408   var parsed = Date.parse(d);
25409   return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
25410  },
25411 
25412  // Formatted numbers
25413  function ( d, settings )
25414  {
25415   var decimal = settings.oLanguage.sDecimal;
25416   return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
25417  },
25418 
25419  // HTML numeric
25420  function ( d, settings )
25421  {
25422   var decimal = settings.oLanguage.sDecimal;
25423   return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
25424  },
25425 
25426  // HTML numeric, formatted
25427  function ( d, settings )
25428  {
25429   var decimal = settings.oLanguage.sDecimal;
25430   return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
25431  },
25432 
25433  // HTML (this is strict checking - there must be html)
25434  function ( d, settings )
25435  {
25436   return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
25437    'html' : null;
25438  }
25439 ] );
25440 
25441 
25442 
25443 // Filter formatting functions. See model.ext.ofnSearch for information about
25444 // what is required from these methods.
25445 // 
25446 // Note that additional search methods are added for the html numbers and
25447 // html formatted numbers by `_addNumericSort()` when we know what the decimal
25448 // place is
25449 
25450 
25451 $.extend( DataTable.ext.type.search, {
25452  html: function ( data ) {
25453   return _empty(data) ?
25454    data :
25455    typeof data === 'string' ?
25456     data
25457      .replace( _re_new_lines, " " )
25458      .replace( _re_html, "" ) :
25459     '';
25460  },
25461 
25462  string: function ( data ) {
25463   return _empty(data) ?
25464    data :
25465    typeof data === 'string' ?
25466     data.replace( _re_new_lines, " " ) :
25467     data;
25468  }
25469 } );
25470 
25471 
25472 
25473 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
25474  if ( d !== 0 && (!d || d === '-') ) {
25475   return -Infinity;
25476  }
25477 
25478  // If a decimal place other than `.` is used, it needs to be given to the
25479  // function so we can detect it and replace with a `.` which is the only
25480  // decimal place Javascript recognises - it is not locale aware.
25481  if ( decimalPlace ) {
25482   d = _numToDecimal( d, decimalPlace );
25483  }
25484 
25485  if ( d.replace ) {
25486   if ( re1 ) {
25487    d = d.replace( re1, '' );
25488   }
25489 
25490   if ( re2 ) {
25491    d = d.replace( re2, '' );
25492   }
25493  }
25494 
25495  return d * 1;
25496 };
25497 
25498 
25499 // Add the numeric 'deformatting' functions for sorting and search. This is done
25500 // in a function to provide an easy ability for the language options to add
25501 // additional methods if a non-period decimal place is used.
25502 function _addNumericSort ( decimalPlace ) {
25503  $.each(
25504   {
25505    // Plain numbers
25506    "num": function ( d ) {
25507     return __numericReplace( d, decimalPlace );
25508    },
25509 
25510    // Formatted numbers
25511    "num-fmt": function ( d ) {
25512     return __numericReplace( d, decimalPlace, _re_formatted_numeric );
25513    },
25514 
25515    // HTML numeric
25516    "html-num": function ( d ) {
25517     return __numericReplace( d, decimalPlace, _re_html );
25518    },
25519 
25520    // HTML numeric, formatted
25521    "html-num-fmt": function ( d ) {
25522     return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
25523    }
25524   },
25525   function ( key, fn ) {
25526    // Add the ordering method
25527    _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
25528 
25529    // For HTML types add a search formatter that will strip the HTML
25530    if ( key.match(/^html\-/) ) {
25531     _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
25532    }
25533   }
25534  );
25535 }
25536 
25537 
25538 // Default sort methods
25539 $.extend( _ext.type.order, {
25540  // Dates
25541  "date-pre": function ( d ) {
25542   return Date.parse( d ) || 0;
25543  },
25544 
25545  // html
25546  "html-pre": function ( a ) {
25547   return _empty(a) ?
25548    '' :
25549    a.replace ?
25550     a.replace( /<.*?>/g, "" ).toLowerCase() :
25551     a+'';
25552  },
25553 
25554  // string
25555  "string-pre": function ( a ) {
25556   // This is a little complex, but faster than always calling toString,
25557   // http://jsperf.com/tostring-v-check
25558   return _empty(a) ?
25559    '' :
25560    typeof a === 'string' ?
25561     a.toLowerCase() :
25562     ! a.toString ?
25563      '' :
25564      a.toString();
25565  },
25566 
25567  // string-asc and -desc are retained only for compatibility with the old
25568  // sort methods
25569  "string-asc": function ( x, y ) {
25570   return ((x < y) ? -1 : ((x > y) ? 1 : 0));
25571  },
25572 
25573  "string-desc": function ( x, y ) {
25574   return ((x < y) ? 1 : ((x > y) ? -1 : 0));
25575  }
25576 } );
25577 
25578 
25579 // Numeric sorting types - order doesn't matter here
25580 _addNumericSort( '' );
25581 
25582 
25583 $.extend( true, DataTable.ext.renderer, {
25584  header: {
25585   _: function ( settings, cell, column, classes ) {
25586    // No additional mark-up required
25587    // Attach a sort listener to update on sort - note that using the
25588    // `DT` namespace will allow the event to be removed automatically
25589    // on destroy, while the `dt` namespaced event is the one we are
25590    // listening for
25591    $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
25592     if ( settings !== ctx ) { // need to check this this is the host
25593      return;               // table, not a nested one
25594     }
25595 
25596     var colIdx = column.idx;
25597 
25598     cell
25599      .removeClass(
25600       column.sSortingClass +' '+
25601       classes.sSortAsc +' '+
25602       classes.sSortDesc
25603      )
25604      .addClass( columns[ colIdx ] == 'asc' ?
25605       classes.sSortAsc : columns[ colIdx ] == 'desc' ?
25606        classes.sSortDesc :
25607        column.sSortingClass
25608      );
25609    } );
25610   },
25611 
25612   jqueryui: function ( settings, cell, column, classes ) {
25613    $('<div/>')
25614     .addClass( classes.sSortJUIWrapper )
25615     .append( cell.contents() )
25616     .append( $('<span/>')
25617      .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
25618     )
25619     .appendTo( cell );
25620 
25621    // Attach a sort listener to update on sort
25622    $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
25623     if ( settings !== ctx ) {
25624      return;
25625     }
25626 
25627     var colIdx = column.idx;
25628 
25629     cell
25630      .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
25631      .addClass( columns[ colIdx ] == 'asc' ?
25632       classes.sSortAsc : columns[ colIdx ] == 'desc' ?
25633        classes.sSortDesc :
25634        column.sSortingClass
25635      );
25636 
25637     cell
25638      .find( 'span.'+classes.sSortIcon )
25639      .removeClass(
25640       classes.sSortJUIAsc +" "+
25641       classes.sSortJUIDesc +" "+
25642       classes.sSortJUI +" "+
25643       classes.sSortJUIAscAllowed +" "+
25644       classes.sSortJUIDescAllowed
25645      )
25646      .addClass( columns[ colIdx ] == 'asc' ?
25647       classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
25648        classes.sSortJUIDesc :
25649        column.sSortingClassJUI
25650      );
25651    } );
25652   }
25653  }
25654 } );
25655 
25656 /*
25657  * Public helper functions. These aren't used internally by DataTables, or
25658  * called by any of the options passed into DataTables, but they can be used
25659  * externally by developers working with DataTables. They are helper functions
25660  * to make working with DataTables a little bit easier.
25661  */
25662 
25663 var __htmlEscapeEntities = function ( d ) {
25664  return typeof d === 'string' ?
25665   d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
25666   d;
25667 };
25668 
25669 /**
25670  * Helpers for `columns.render`.
25671  *
25672  * The options defined here can be used with the `columns.render` initialisation
25673  * option to provide a display renderer. The following functions are defined:
25674  *
25675  * * `number` - Will format numeric data (defined by `columns.data`) for
25676  *   display, retaining the original unformatted data for sorting and filtering.
25677  *   It takes 5 parameters:
25678  *   * `string` - Thousands grouping separator
25679  *   * `string` - Decimal point indicator
25680  *   * `integer` - Number of decimal points to show
25681  *   * `string` (optional) - Prefix.
25682  *   * `string` (optional) - Postfix (/suffix).
25683  * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
25684  *   parameters.
25685  *
25686  * @example
25687  *   // Column definition using the number renderer
25688  *   {
25689  *     data: "salary",
25690  *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
25691  *   }
25692  *
25693  * @namespace
25694  */
25695 DataTable.render = {
25696  number: function ( thousands, decimal, precision, prefix, postfix ) {
25697   return {
25698    display: function ( d ) {
25699     if ( typeof d !== 'number' && typeof d !== 'string' ) {
25700      return d;
25701     }
25702 
25703     var negative = d < 0 ? '-' : '';
25704     var flo = parseFloat( d );
25705 
25706     // If NaN then there isn't much formatting that we can do - just
25707     // return immediately, escaping any HTML (this was supposed to
25708     // be a number after all)
25709     if ( isNaN( flo ) ) {
25710      return __htmlEscapeEntities( d );
25711     }
25712 
25713     d = Math.abs( flo );
25714 
25715     var intPart = parseInt( d, 10 );
25716     var floatPart = precision ?
25717      decimal+(d - intPart).toFixed( precision ).substring( 2 ):
25718      '';
25719 
25720     return negative + (prefix||'') +
25721      intPart.toString().replace(
25722       /\B(?=(\d{3})+(?!\d))/g, thousands
25723      ) +
25724      floatPart +
25725      (postfix||'');
25726    }
25727   };
25728  },
25729 
25730  text: function () {
25731   return {
25732    display: __htmlEscapeEntities
25733   };
25734  }
25735 };
25736 
25737 
25738 /*
25739  * This is really a good bit rubbish this method of exposing the internal methods
25740  * publicly... - To be fixed in 2.0 using methods on the prototype
25741  */
25742 
25743 
25744 /**
25745  * Create a wrapper function for exporting an internal functions to an external API.
25746  *  @param {string} fn API function name
25747  *  @returns {function} wrapped function
25748  *  @memberof DataTable#internal
25749  */
25750 function _fnExternApiFunc (fn)
25751 {
25752  return function() {
25753   var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
25754    Array.prototype.slice.call(arguments)
25755   );
25756   return DataTable.ext.internal[fn].apply( this, args );
25757  };
25758 }
25759 
25760 
25761 /**
25762  * Reference to internal functions for use by plug-in developers. Note that
25763  * these methods are references to internal functions and are considered to be
25764  * private. If you use these methods, be aware that they are liable to change
25765  * between versions.
25766  *  @namespace
25767  */
25768 $.extend( DataTable.ext.internal, {
25769  _fnExternApiFunc: _fnExternApiFunc,
25770  _fnBuildAjax: _fnBuildAjax,
25771  _fnAjaxUpdate: _fnAjaxUpdate,
25772  _fnAjaxParameters: _fnAjaxParameters,
25773  _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
25774  _fnAjaxDataSrc: _fnAjaxDataSrc,
25775  _fnAddColumn: _fnAddColumn,
25776  _fnColumnOptions: _fnColumnOptions,
25777  _fnAdjustColumnSizing: _fnAdjustColumnSizing,
25778  _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
25779  _fnColumnIndexToVisible: _fnColumnIndexToVisible,
25780  _fnVisbleColumns: _fnVisbleColumns,
25781  _fnGetColumns: _fnGetColumns,
25782  _fnColumnTypes: _fnColumnTypes,
25783  _fnApplyColumnDefs: _fnApplyColumnDefs,
25784  _fnHungarianMap: _fnHungarianMap,
25785  _fnCamelToHungarian: _fnCamelToHungarian,
25786  _fnLanguageCompat: _fnLanguageCompat,
25787  _fnBrowserDetect: _fnBrowserDetect,
25788  _fnAddData: _fnAddData,
25789  _fnAddTr: _fnAddTr,
25790  _fnNodeToDataIndex: _fnNodeToDataIndex,
25791  _fnNodeToColumnIndex: _fnNodeToColumnIndex,
25792  _fnGetCellData: _fnGetCellData,
25793  _fnSetCellData: _fnSetCellData,
25794  _fnSplitObjNotation: _fnSplitObjNotation,
25795  _fnGetObjectDataFn: _fnGetObjectDataFn,
25796  _fnSetObjectDataFn: _fnSetObjectDataFn,
25797  _fnGetDataMaster: _fnGetDataMaster,
25798  _fnClearTable: _fnClearTable,
25799  _fnDeleteIndex: _fnDeleteIndex,
25800  _fnInvalidate: _fnInvalidate,
25801  _fnGetRowElements: _fnGetRowElements,
25802  _fnCreateTr: _fnCreateTr,
25803  _fnBuildHead: _fnBuildHead,
25804  _fnDrawHead: _fnDrawHead,
25805  _fnDraw: _fnDraw,
25806  _fnReDraw: _fnReDraw,
25807  _fnAddOptionsHtml: _fnAddOptionsHtml,
25808  _fnDetectHeader: _fnDetectHeader,
25809  _fnGetUniqueThs: _fnGetUniqueThs,
25810  _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
25811  _fnFilterComplete: _fnFilterComplete,
25812  _fnFilterCustom: _fnFilterCustom,
25813  _fnFilterColumn: _fnFilterColumn,
25814  _fnFilter: _fnFilter,
25815  _fnFilterCreateSearch: _fnFilterCreateSearch,
25816  _fnEscapeRegex: _fnEscapeRegex,
25817  _fnFilterData: _fnFilterData,
25818  _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
25819  _fnUpdateInfo: _fnUpdateInfo,
25820  _fnInfoMacros: _fnInfoMacros,
25821  _fnInitialise: _fnInitialise,
25822  _fnInitComplete: _fnInitComplete,
25823  _fnLengthChange: _fnLengthChange,
25824  _fnFeatureHtmlLength: _fnFeatureHtmlLength,
25825  _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
25826  _fnPageChange: _fnPageChange,
25827  _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
25828  _fnProcessingDisplay: _fnProcessingDisplay,
25829  _fnFeatureHtmlTable: _fnFeatureHtmlTable,
25830  _fnScrollDraw: _fnScrollDraw,
25831  _fnApplyToChildren: _fnApplyToChildren,
25832  _fnCalculateColumnWidths: _fnCalculateColumnWidths,
25833  _fnThrottle: _fnThrottle,
25834  _fnConvertToWidth: _fnConvertToWidth,
25835  _fnGetWidestNode: _fnGetWidestNode,
25836  _fnGetMaxLenString: _fnGetMaxLenString,
25837  _fnStringToCss: _fnStringToCss,
25838  _fnSortFlatten: _fnSortFlatten,
25839  _fnSort: _fnSort,
25840  _fnSortAria: _fnSortAria,
25841  _fnSortListener: _fnSortListener,
25842  _fnSortAttachListener: _fnSortAttachListener,
25843  _fnSortingClasses: _fnSortingClasses,
25844  _fnSortData: _fnSortData,
25845  _fnSaveState: _fnSaveState,
25846  _fnLoadState: _fnLoadState,
25847  _fnSettingsFromNode: _fnSettingsFromNode,
25848  _fnLog: _fnLog,
25849  _fnMap: _fnMap,
25850  _fnBindAction: _fnBindAction,
25851  _fnCallbackReg: _fnCallbackReg,
25852  _fnCallbackFire: _fnCallbackFire,
25853  _fnLengthOverflow: _fnLengthOverflow,
25854  _fnRenderer: _fnRenderer,
25855  _fnDataSource: _fnDataSource,
25856  _fnRowAttributes: _fnRowAttributes,
25857  _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
25858                                  // in 1.10, so this dead-end function is
25859                                  // added to prevent errors
25860 } );
25861 
25862 // jQuery access
25863 $.fn.dataTable = DataTable;
25864 // Provide access to the host jQuery object (circular reference)
25865 DataTable.$ = $;
25866 // Legacy aliases
25867 $.fn.dataTableSettings = DataTable.settings;
25868 $.fn.dataTableExt = DataTable.ext;
25869 // With a capital `D` we return a DataTables API instance rather than a
25870 // jQuery object
25871 $.fn.DataTable = function ( opts ) {
25872  return $(this).dataTable( opts ).api();
25873 };
25874 // All properties that are available to $.fn.dataTable should also be
25875 // available on $.fn.DataTable
25876 $.each( DataTable, function ( prop, val ) {
25877  $.fn.DataTable[ prop ] = val;
25878 } );
25879 // Information about events fired by DataTables - for documentation.
25880 /**
25881  * Draw event, fired whenever the table is redrawn on the page, at the same
25882  * point as fnDrawCallback. This may be useful for binding events or
25883  * performing calculations when the table is altered at all.
25884  *  @name DataTable#draw.dt
25885  *  @event
25886  *  @param {event} e jQuery event object
25887  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
25888  */
25889 /**
25890  * Search event, fired when the searching applied to the table (using the
25891  * built-in global search, or column filters) is altered.
25892  *  @name DataTable#search.dt
25893  *  @event
25894  *  @param {event} e jQuery event object
25895  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
25896  */
25897 /**
25898  * Page change event, fired when the paging of the table is altered.
25899  *  @name DataTable#page.dt
25900  *  @event
25901  *  @param {event} e jQuery event object
25902  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
25903  */
25904 /**
25905  * Order event, fired when the ordering applied to the table is altered.
25906  *  @name DataTable#order.dt
25907  *  @event
25908  *  @param {event} e jQuery event object
25909  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
25910  */
25911 /**
25912  * DataTables initialisation complete event, fired when the table is fully
25913  * drawn, including Ajax data loaded, if Ajax data is required.
25914  *  @name DataTable#init.dt
25915  *  @event
25916  *  @param {event} e jQuery event object
25917  *  @param {object} oSettings DataTables settings object
25918  *  @param {object} json The JSON object request from the server - only
25919  *    present if client-side Ajax sourced data is used</li></ol>
25920  */
25921 /**
25922  * State save event, fired when the table has changed state a new state save
25923  * is required. This event allows modification of the state saving object
25924  * prior to actually doing the save, including addition or other state
25925  * properties (for plug-ins) or modification of a DataTables core property.
25926  *  @name DataTable#stateSaveParams.dt
25927  *  @event
25928  *  @param {event} e jQuery event object
25929  *  @param {object} oSettings DataTables settings object
25930  *  @param {object} json The state information to be saved
25931  */
25932 /**
25933  * State load event, fired when the table is loading state from the stored
25934  * data, but prior to the settings object being modified by the saved state
25935  * - allowing modification of the saved state is required or loading of
25936  * state for a plug-in.
25937  *  @name DataTable#stateLoadParams.dt
25938  *  @event
25939  *  @param {event} e jQuery event object
25940  *  @param {object} oSettings DataTables settings object
25941  *  @param {object} json The saved state information
25942  */
25943 /**
25944  * State loaded event, fired when state has been loaded from stored data and
25945  * the settings object has been modified by the loaded data.
25946  *  @name DataTable#stateLoaded.dt
25947  *  @event
25948  *  @param {event} e jQuery event object
25949  *  @param {object} oSettings DataTables settings object
25950  *  @param {object} json The saved state information
25951  */
25952 /**
25953  * Processing event, fired when DataTables is doing some kind of processing
25954  * (be it, order, searcg or anything else). It can be used to indicate to
25955  * the end user that there is something happening, or that something has
25956  * finished.
25957  *  @name DataTable#processing.dt
25958  *  @event
25959  *  @param {event} e jQuery event object
25960  *  @param {object} oSettings DataTables settings object
25961  *  @param {boolean} bShow Flag for if DataTables is doing processing or not
25962  */
25963 /**
25964  * Ajax (XHR) event, fired whenever an Ajax request is completed from a
25965  * request to made to the server for new data. This event is called before
25966  * DataTables processed the returned data, so it can also be used to pre-
25967  * process the data returned from the server, if needed.
25968  *
25969  * Note that this trigger is called in `fnServerData`, if you override
25970  * `fnServerData` and which to use this event, you need to trigger it in you
25971  * success function.
25972  *  @name DataTable#xhr.dt
25973  *  @event
25974  *  @param {event} e jQuery event object
25975  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
25976  *  @param {object} json JSON returned from the server
25977  *
25978  *  @example
25979  *     // Use a custom property returned from the server in another DOM element
25980  *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
25981  *       $('#status').html( json.status );
25982  *     } );
25983  *
25984  *  @example
25985  *     // Pre-process the data returned from the server
25986  *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
25987  *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
25988  *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
25989  *       }
25990  *       // Note no return - manipulate the data directly in the JSON object.
25991  *     } );
25992  */
25993 /**
25994  * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
25995  * or passing the bDestroy:true parameter in the initialisation object. This
25996  * can be used to remove bound events, added DOM nodes, etc.
25997  *  @name DataTable#destroy.dt
25998  *  @event
25999  *  @param {event} e jQuery event object
26000  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
26001  */
26002 /**
26003  * Page length change event, fired when number of records to show on each
26004  * page (the length) is changed.
26005  *  @name DataTable#length.dt
26006  *  @event
26007  *  @param {event} e jQuery event object
26008  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
26009  *  @param {integer} len New length
26010  */
26011 /**
26012  * Column sizing has changed.
26013  *  @name DataTable#column-sizing.dt
26014  *  @event
26015  *  @param {event} e jQuery event object
26016  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
26017  */
26018 /**
26019  * Column visibility has changed.
26020  *  @name DataTable#column-visibility.dt
26021  *  @event
26022  *  @param {event} e jQuery event object
26023  *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
26024  *  @param {int} column Column index
26025  *  @param {bool} vis `false` if column now hidden, or `true` if visible
26026  */
26027 return $.fn.dataTable;
26028}));
26029
26030   /* Ende jquery.datatables */
26031   /* Start jquery.cookie */
26032   /*!
26033 * jQuery Cookie Plugin v1.4.1
26034 * https://github.com/carhartl/jquery-cookie
26035 *
26036 * Copyright 2013 Klaus Hartl
26037 * Released under the MIT license
26038 */
26039(function (factory) {
26040 if (typeof define === 'function' && define.amd) {
26041  // AMD
26042  define(['jquery'], factory);
26043 } else if (typeof exports === 'object') {
26044  // CommonJS
26045  factory(require('jquery'));
26046 } else {
26047  // Browser globals
26048  factory(jQuery);
26049 }
26050}(function ($) {
26051
26052 var pluses = /\+/g;
26053
26054 function encode(s) {
26055  return config.raw ? s : encodeURIComponent(s);
26056 }
26057
26058 function decode(s) {
26059  return config.raw ? s : decodeURIComponent(s);
26060 }
26061
26062 function stringifyCookieValue(value) {
26063  return encode(config.json ? JSON.stringify(value) : String(value));
26064 }
26065
26066 function parseCookieValue(s) {
26067  if (s.indexOf('"') === 0) {
26068   // This is a quoted cookie as according to RFC2068, unescape...
26069   s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
26070  }
26071
26072  try {
26073   // Replace server-side written pluses with spaces.
26074   // If we can't decode the cookie, ignore it, it's unusable.
26075   // If we can't parse the cookie, ignore it, it's unusable.
26076   s = decodeURIComponent(s.replace(pluses, ' '));
26077   return config.json ? JSON.parse(s) : s;
26078  } catch(e) {}
26079 }
26080
26081 function read(s, converter) {
26082  var value = config.raw ? s : parseCookieValue(s);
26083  return $.isFunction(converter) ? converter(value) : value;
26084 }
26085
26086 var config = $.cookie = function (key, value, options) {
26087
26088  // Write
26089
26090  if (value !== undefined && !$.isFunction(value)) {
26091   options = $.extend({}, config.defaults, options);
26092
26093   if (typeof options.expires === 'number') {
26094    var days = options.expires, t = options.expires = new Date();
26095    t.setTime(+t + days * 864e+5);
26096   }
26097
26098   return (document.cookie = [
26099    encode(key), '=', stringifyCookieValue(value),
26100    options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
26101    options.path    ? '; path=' + options.path : '',
26102    options.domain  ? '; domain=' + options.domain : '',
26103    options.secure  ? '; secure' : ''
26104   ].join(''));
26105  }
26106
26107  // Read
26108
26109  var result = key ? undefined : {};
26110
26111  // To prevent the for loop in the first place assign an empty array
26112  // in case there are no cookies at all. Also prevents odd result when
26113  // calling $.cookie().
26114  var cookies = document.cookie ? document.cookie.split('; ') : [];
26115
26116  for (var i = 0, l = cookies.length; i < l; i++) {
26117   var parts = cookies[i].split('=');
26118   var name = decode(parts.shift());
26119   var cookie = parts.join('=');
26120
26121   if (key && key === name) {
26122    // If second argument (value) is a function it's a converter...
26123    result = read(cookie, value);
26124    break;
26125   }
26126
26127   // Prevent storing a cookie that we couldn't decode.
26128   if (!key && (cookie = read(cookie)) !== undefined) {
26129    result[name] = cookie;
26130   }
26131  }
26132
26133  return result;
26134 };
26135
26136 config.defaults = {};
26137
26138 $.removeCookie = function (key, options) {
26139  if ($.cookie(key) === undefined) {
26140   return false;
26141  }
26142
26143  // Must not alter options, thus extending a fresh object...
26144  $.cookie(key, '', $.extend({}, options, { expires: -1 }));
26145  return !$.cookie(key);
26146 };
26147
26148}));
26149   /* Ende jquery.cookie */
26150   /* Start gsb_responsiveListener */
26151   /*!
26152 * @name responsiveListener
26153 * @author @anuebel/pespeloe
26154 * Licensed under the MIT license
26155 *
26156 * Callback function je Breakpoint
26157 * */
26158;
26159(function ($) {
26160  if (!$.gsb) {
26161    $.gsb = {};
26162  }
26163  ;
26164
26165  $.gsb.responsiveListener = function (pluginBase) {
26166    var base = this;
26167    this.base = base;
26168    this.pluginBase = pluginBase;
26169
26170    // Add a reverse reference to the DOM object
26171    this.base.breakpoints = [];
26172    this.base.breakpointSettings = [];
26173    this.base.activeBreakpoint = null;
26174    this.base.windowWidth = 0;
26175
26176    base.init = function () {
26177      //Da die Lib keine eigenen Options hat, Options vom Plugin holen
26178      base.options = pluginBase.options;
26179      base.originalOptions = base.options;
26180      this.base.options = base.options;
26181      this.base.originalOptions = base.originalOptions;
26182      base.initResponsive();
26183      base.checkResponsive();
26184      if (base.options.respondToEvents === true) {
26185        base.initEvents();
26186      }
26187    };
26188
26189
26190    /**
26191     * Initialisiert die Events.
26192     */
26193    $.gsb.responsiveListener.prototype.initEvents = function () {
26194      var $window = $(window),
26195        onResize = function () {
26196          if ($(window).width() !== base.windowWidth) {
26197            clearTimeout(base.windowDelay);
26198            base.windowDelay = window.setTimeout(function () {
26199              base.windowWidth = $(window).width();
26200              base.checkResponsive();
26201            }, 100);
26202          }
26203        };
26204      $window.on('resize', onResize);
26205      $window.on('orientationchange', function () {
26206        base.checkResponsive();
26207      });
26208    };
26209
26210    // Run initializer
26211    base.init();
26212  };
26213
26214
26215  /**
26216   * Initialisiert die Datenstrukturen fuer die responsiven Ueberpruefungen.
26217   */
26218  $.gsb.responsiveListener.prototype.initResponsive = function () {
26219    var breakpoint,
26220      responsiveSettings = this.base.options.responsive || null;
26221
26222    if (responsiveSettings && responsiveSettings.length > -1) {
26223      for (breakpoint in responsiveSettings) {
26224        if (responsiveSettings.hasOwnProperty(breakpoint)) {
26225          this.base.breakpoints.push(responsiveSettings[
26226            breakpoint].breakpoint);
26227          this.base.breakpointSettings[responsiveSettings[
26228            breakpoint].breakpoint] =
26229            responsiveSettings[breakpoint];
26230        }
26231      }
26232      this.base.breakpoints.sort(function (a, b) {
26233        return b - a;
26234      });
26235    }
26236  };
26237
26238
26239  /**
26240   * Ueberprueft, ob eine Aenderung der Einstellungen durchgefuehrt werden muss. Dies ist dann der Fall, wenn
26241   * sich  die Breite des Viewports(window-Objekt) geaendert hat und mindestens einen der angegebenen Breakpoints
26242   * unterschreitet. Ausschlaggebend fuer die Aenderungen ist der letzte konfigurierte Breakpoint, dessen Breite
26243   * unterschritten wird.
26244   *
26245   */
26246  $.gsb.responsiveListener.prototype.checkResponsive = function () {
26247    var breakpoint,
26248      targetBreakpoint,
26249      respondToWidth = window.innerWidth || $(window).width();
26250
26251    if (this.base.originalOptions.responsive &&
26252      this.base.originalOptions.responsive.length > -1 &&
26253      this.base.originalOptions.responsive !== null) {
26254
26255      targetBreakpoint = null;
26256
26257      if (this.base.activeBreakpoint !== null && respondToWidth >= this.base.breakpoints[0]) {
26258        this.base.activeBreakpoint = null;
26259        this.pluginBase.options = this.base.originalOptions;
26260      }
26261
26262      for (breakpoint in this.base.breakpoints) {
26263        if (this.base.breakpoints.hasOwnProperty(breakpoint)) {
26264          if (respondToWidth < this.base.breakpoints[breakpoint]) {
26265            targetBreakpoint = this.base.breakpoints[breakpoint];
26266            this.base.highestResolution = false;
26267          }
26268        }
26269      }
26270
26271      if (this.base.highestResolution) {
26272        return;
26273      }
26274
26275      if (targetBreakpoint !== null) {
26276        if (this.base.activeBreakpoint !== null) {
26277          if (targetBreakpoint !== this.base.activeBreakpoint) {
26278            this.base.activeBreakpoint = targetBreakpoint;
26279            this.pluginBase.options = $.extend({},
26280              this.base.originalOptions,
26281              this.base.breakpointSettings[targetBreakpoint]);
26282            this.base.triggerRefresh();
26283          }
26284        } else {
26285          this.base.activeBreakpoint = targetBreakpoint;
26286          this.pluginBase.options = $.extend({},
26287            this.base.originalOptions,
26288            this.base.breakpointSettings[targetBreakpoint]);
26289          this.base.triggerRefresh();
26290        }
26291      } else {
26292        if (this.base.activeBreakpoint !== null) {
26293          this.base.activeBreakpoint = null;
26294          this.base.options = this.base.originalOptions;
26295          this.base.triggerRefresh();
26296        } else {
26297          this.base.highestResolution = true;
26298          this.base.triggerRefresh();
26299        }
26300      }
26301    } else if (this.base.originalOptions.onRefresh &&
26302      this.base.originalOptions.onRefresh.length > -1 &&
26303      this.base.originalOptions.onRefresh !== null) {
26304      if (this.base.highestResolution) {
26305        return;
26306      }
26307      this.base.triggerRefresh();
26308      this.base.highestResolution = true;
26309    }
26310  };
26311
26312
26313  /**
26314   * Loest die Aktualisierung des Scripts aus.
26315   */
26316  $.gsb.responsiveListener.prototype.triggerRefresh = function () {
26317    if (typeof this.pluginBase.options.onRefresh === 'function') {
26318      this.pluginBase.options.onRefresh.call(this.pluginBase);
26319    }
26320  };
26321
26322  $.fn.gsb_responsiveListener = function (pluginBase) {
26323    return this.each(function () {
26324      (new $.gsb.responsiveListener(pluginBase));
26325    });
26326  };
26327})(jQuery);
26328   /* Ende gsb_responsiveListener */
26329   /* Start gsb_ariaSupport */
26330   /**
26331 * @module ariaSupport
26332 * @version 1.1.0
26333 * @see {@link http://semver.org|Semantic Versioning}
26334 * @author pespeloe
26335 *
26336 * @desc Diese Erweiterung fügt Aria-Support für gsb Plugins hinzu.
26337 * Falls eine Mobulvariante noch nicht verfügbar ist, muss diese als Option hinzugefügt werden (genaueres direkt im Quellcode Kommentar nachzulesen).
26338 * ACHTUNG: Es ist zwingend notwendig unser module-Pattern zu verwenden (ähnlich wie beim responsiveListener)
26339 *
26340 * Das Script wird direkt im Modul konfiguriert. Es müssen folgende Schritte gemacht werden:
26341 * 1. Die Option ariaType muss angegeben werden - also mobilemenu, tab, accordion, lightbox usw.
26342 * 2. Es müssen base.controlPanel und base.contentPanel gesetzt werden  - hier direkt Panel (was geklickt wird) und Content (was angezeigt werden soll)
26343 * 3. Nach Aktion (click usw.) funktion base.aria.updateAria() aufrufen (zu übergebende Parameter unten aufgelistet) um Inhalt der WAI-ARIA Attribute zu tauschen
26344 *
26345 * @example
26346 *       base.controlPanel = base.menu.find('.mm-vertical > .mm-next');  //Aufklapptpfeil im MMenu
26347 *       base.contentPanel = base.menu.find('li > .mm-panel.mm-vertical > ul'); // Ul welches aufgeklappt wird
26348 *
26349 *       Innerhalb des click-Events:
26350 *
26351 *       //Menü öffnen
26352 *       base.aria.updateAria(this, false, true);
26353 *
26354 *       //Menu schließen
26355 *       base.aria.updateAria(this, true, true);
26356 *
26357 * */
26358;
26359(function ($) {
26360  if (!$.gsb) {
26361    $.gsb = {};
26362  }
26363  ;
26364
26365  $.gsb.ariaSupport = function (pluginBase) {
26366    this.base = this;
26367    this.pluginBase = pluginBase;
26368
26369    this.base.init = function () {
26370      //Da die Lib keine eigenen Options hat, Options vom Plugin holen
26371      this.base.options = pluginBase.options;
26372
26373      this.base.ariaOptions = $.extend({}, $.gsb.ariaSupport.defaultOptions, pluginBase.options.ariaSupport)
26374
26375      this.base.originalOptions = this.base.options;
26376      this.base.options = this.base.options;
26377      this.base.originalOptions = this.base.originalOptions;
26378      this.base.initializeAria();
26379    };
26380
26381    // Run initializer
26382    this.base.init();
26383
26384  };
26385
26386  //*************************************** Verschiedene Aria-Typen initialisieren ************************************/
26387  /**
26388   * @method initialize
26389   * @desc Initialisierung des Scripts
26390   */
26391  $.gsb.ariaSupport.prototype.initializeAria = function(){
26392    var ariaType = this.base.options.ariaType,
26393      base = this.base,
26394      pluginBase= this.pluginBase,
26395      ariaOptions = this.base.ariaOptions;
26396
26397    base.moduleOptions = ariaOptions[ariaType.toUpperCase()];
26398    base.attributesPanel = ariaOptions[ariaType.toUpperCase()]['panel'];
26399    base.attributesContent = ariaOptions[ariaType.toUpperCase()]['content'];
26400
26401    base.panelToggle = base.setToggleoptions(base.attributesPanel);
26402    base.contentToggle = base.setToggleoptions(base.attributesContent);
26403
26404    pluginBase.controlPanel.get().forEach(function(panel, index){
26405      var firstOpen = ariaOptions[ariaType.toUpperCase()].firstOpen;
26406      var addAural = ariaOptions[ariaType.toUpperCase()].addAural;
26407
26408      if(firstOpen && index >0){
26409        firstOpen = false
26410      }
26411
26412      //Attribute fuer Controlpanel setzen
26413      base.setAttributes(panel, base.attributesPanel, index, firstOpen);
26414
26415      //falls aural hinzugefuegt werden soll
26416      if(addAural){
26417        if(firstOpen){
26418          base.addAural(panel, true);
26419        }else{
26420          base.addAural(panel, false);
26421        }
26422      }
26423
26424      //Atttribute fuert Contentpanel setzen, wenn contentPanel vorhanden ist
26425      if(pluginBase.contentPanel && pluginBase.contentPanel.get(index)){
26426        base.setAttributes(pluginBase.contentPanel.get(index), base.attributesContent, index, firstOpen);
26427      }
26428    });
26429  };
26430
26431  //*********************************Ende Verschiedene Aria-Typen initialisieren **************************************/
26432
26433
26434  //*********************************Aria-Typen Attribute Zuordnungen *************************************************/
26435
26436  /*
26437   * Array : 1. Wert aktiver Zustand, 2. Wert inaktiver Zustand
26438   * Function: Es können alle Funktionen die sich in dieser Lib befinden, genutzt werden. An die Funktion innerhalb
26439   * der Option wird immer this, base und index übergeben
26440   * Listener: erste Array ist der Zustand in dem etwas aktiv gesetzt werden soll, der zweite für den wo alles wieder
26441   * zurückgesetzt werden soll
26442   */
26443  $.gsb.ariaSupport.defaultOptions = {
26444
26445    TAB: {
26446      firstOpen: true,
26447      panel:{
26448        id : function (base){
26449          return base.generateID()
26450        },
26451        role: "tab",
26452        aria_expanded: [
26453          "true","false"
26454        ],
26455        aria_controls: function (base){
26456          return base.generateID()
26457        }
26458      },
26459      content:{
26460        role: 'tabpanel',
26461        aria_hidden:[
26462          "false","true"
26463        ],
26464        id: function(base, index){
26465          return base.getPanelAttribute(index, "aria-controls")
26466        },
26467        aria_labelledby: function (base, index){
26468          return base.getPanelAttribute(index, "id")
26469        }
26470      }
26471    },
26472
26473    ACCORDION:{
26474      panel:{
26475        role: 'tab',
26476        aria_expanded: [
26477          "true", "false"
26478        ],
26479        aria_selected: [
26480          "true","false"
26481        ],
26482        id : function (base){
26483          return base.generateID()
26484        },
26485        aria_controls: function (base){
26486          return base.generateID()
26487        }
26488      },
26489      content: {
26490        role: 'tabpanel',
26491        aria_hidden:[
26492          "false","true"
26493        ],
26494        id: function(base, index){
26495          return base.getPanelAttribute(index, "aria-controls")
26496        },
26497        aria_labelledby: function (base, index){
26498          return base.getPanelAttribute(index, "id")
26499        }
26500      }
26501    },
26502
26503    LIGTHBOX: {
26504      panel:{
26505        aria_haspopup : "true"
26506      }
26507    },
26508
26509    MOBILEMENU:{
26510      /*addAural: true,
26511      auralText:[
26512        SHOW_LESS, SHOW_MORE
26513      ],*/
26514      panel: {
26515        aria_controls: function (base){
26516            return base.generateID()
26517        },
26518        id : function (base){
26519          return base.generateID()
26520        }
26521      },
26522      content: {
26523        aria_labelledby: function (base, index){
26524          return base.getPanelAttribute(index, "id")
26525        },
26526        id: function(base, index){
26527          return base.getPanelAttribute(index, "aria-controls")
26528        },
26529        aria_hidden:[
26530          "false","true"
26531        ],
26532        aria_expanded:[
26533          "true","false"
26534        ]
26535      }
26536    }
26537  };
26538
26539  //**************************** Ende Aria-Typen Attribute Zuordnungen ************************************************/
26540
26541  //********************************* Helper **************************************************************************/
26542  /**
26543   * @method generateID
26544   * @desc generiert eine ID aus einer Zufallszahl und dessen toString result mit der Basis 36
26545   */
26546  $.gsb.ariaSupport.prototype.generateID = function(){
26547
26548    // Math.random should be unique because of its seeding algorithm.
26549    // Convert it to base 36 (numbers + letters), and grab the first 9 characters
26550    // after the decimal.
26551    return '_' + Math.random().toString(36).substr(2, 9);
26552  };
26553
26554
26555  //********************************* Aural **************************************************************************/
26556  /**
26557   * @method addAural
26558   * @desc fuegt ein span Aural mit dem "defaultText" hinzu
26559   * @param {elem} Element
26560   * @param {boolean} open: soll Text fuer geoeffnet oder geschlossen ausgegeben werden?
26561   */
26562  $.gsb.ariaSupport.prototype.addAural = function(elem, open){
26563    var base = this.base;
26564
26565    //Span erstellen und Class setzen
26566    var auralSpan = document.createElement("span");
26567    auralSpan.classList.add('aural');
26568
26569    //Angabe, welcher Text ausgegeben werden soll - 0 = geoeffnet, 1 = geschlossen
26570    var index = 1;
26571    if(open == true){
26572      index = 0;
26573    }
26574
26575    //Auraltext hinzufuegen
26576    var auralText = document.createTextNode(base.moduleOptions.auralText[index]);
26577    auralSpan.appendChild(auralText);
26578
26579    elem.insertBefore(auralSpan, elem.firstChild);
26580
26581  }
26582
26583  /**
26584   * @method updateAural
26585   * @desc Tauscht den auraltext
26586   * @param {Object} clickedElem Element welches geklickt wurde
26587   * @param {boolean} open: wird das Element geoeffnet oder geschlossen
26588   */
26589  $.gsb.ariaSupport.prototype.updateAural = function(clickedElem, open){
26590    var base = this.base;
26591    var auralSpan = clickedElem.querySelector('.aural');
26592
26593    //Angabe, welcher Text ausgegeben werden soll - 0 = geoeffnet, 1 = geschlossen
26594    var index = 1;
26595    if(open == true){
26596      index = 0;
26597    }
26598
26599    auralSpan.removeChild(auralSpan.firstChild);
26600
26601    //Auraltext hinzufuegen
26602    var auralText = document.createTextNode(base.moduleOptions.auralText[index]);
26603    auralSpan.appendChild(auralText);
26604
26605  }
26606
26607  //********************************* Aria **************************************************************************/
26608  /**
26609   * @method setAttributes
26610   * @desc setzt Attribute aus einem Array
26611   * @param {elem} Element
26612   * @param {Object} options: Options die als attribute gesetzt werden sollen
26613   * @param {int} index: Index des Elements welches aktualisiert werden soll
26614   * @param {boolean} open: Aria-Attribut für "geöffnet" setzen
26615   */
26616  $.gsb.ariaSupport.prototype.setAttributes = function (elem, options, index, open){
26617    var base = this.base;
26618
26619    for(var key in options){
26620      //JSON keynames mit - nicht erlaubt, desswegen muss jetzt wieder von _ zu - umgewandelt werden
26621      var keyNameAsProperty = key.replace(/_/g,'-');
26622
26623      if(typeof options[key] === 'function' ){
26624        elem.setAttribute(keyNameAsProperty, options[key].call(this, base, index))
26625      } else if(Array.isArray(options[key])){
26626        if(options[key].length == 2){
26627          if(open){
26628            elem.setAttribute(keyNameAsProperty,options[key][0]);
26629          } else{
26630            elem.setAttribute(keyNameAsProperty,options[key][1]);
26631          }
26632        }
26633      }else{
26634        elem.setAttribute(keyNameAsProperty,options[key]);
26635      }
26636    }
26637  };
26638
26639
26640  /**
26641   * @method setToggleoptions
26642   * @desc Setzt die übergebenen Optionen als Attribute für Content oder Panel - Keyname = Attributname, Valu = Value
26643   * @param {Array} Object mit Attributen
26644   */
26645  $.gsb.ariaSupport.prototype.setToggleoptions = function(options){
26646    var obj={};
26647
26648    for(key in options){
26649      if(Array.isArray(options[key])){
26650        obj[key] = options[key];
26651      }
26652    }
26653
26654    return obj;
26655  };
26656
26657  /**
26658   * @method getPanelAttribute
26659   * @desc liefert den Wert des Attributes
26660   * getAttribute zu erzeugen)
26661   * @param {int} elementIdex: Index des Panelelements, von welchem die Attribute ausgelesen werden sollen
26662   * @param {String} Attribute: welches Attribute soll gelesen werden
26663   */
26664  $.gsb.ariaSupport.prototype.getPanelAttribute = function(elementIndex, attribute){
26665    return this.pluginBase.controlPanel.get(elementIndex).getAttribute(attribute);
26666  };
26667
26668
26669  /**
26670   * @method getContentAttribute
26671   * @desc liefert den Wert des Attributes getAttribute zu erzeugen)
26672   * @param {int} elementIdex: Index des Panelelements, von welchem die Attribute ausgelesen werden sollen
26673   * @param {String} Attribute: welches Attribute soll gelesen werden
26674   */
26675  $.gsb.ariaSupport.prototype.getContentAttribute = function(elementIndex, attribute){
26676    return this.pluginBase.contentPanel.get(elementIndex).getAttribute(attribute);
26677  };
26678
26679  /**
26680   * @method updateAria
26681   * @desc Tauscht den Value der ARI-Attribute
26682   * @param {Object} clickedElem Element welches geklickt wurde
26683   * @param {boolean} externalOpen: Aria Status für geöffnetes Element erzwingen
26684   * @param {boolean} singleOpen: Es soll nur ein Element geöffnet werden  (also nicht wie bei einem Accordion - eins öffnen, andere Schließen)
26685   */
26686  $.gsb.ariaSupport.prototype.updateAria = function(clickedElem, externalOpen, singleOpen){
26687    var base = this.base
26688    pluginBase = base.pluginBase;
26689
26690    if(typeof externalOpen != "boolean"){
26691      externalOpen = null;
26692    }
26693
26694    base.pluginBase.controlPanel.get().forEach(function(elem, index){
26695      var open = false;
26696
26697      if(externalOpen){
26698        open = true
26699      } else if(externalOpen == null && elem == clickedElem){
26700        open = true;
26701      }
26702
26703      if(singleOpen){
26704        if(elem !== clickedElem){
26705          // Wenn nur ein Element geöffnet werden soll und das geklickte nicht das aktuelle aus dem Schleifen
26706          // durchlauf ist, nächste Durchlauf
26707          return;
26708        }
26709      }
26710
26711      base.setAttributes(elem, base.panelToggle, index, open );
26712      base.setAttributes(pluginBase.contentPanel.get(index), base.contentToggle, index, open );
26713    });
26714  };
26715
26716
26717  $.fn.gsb_ariaSupport = function (pluginBase) {
26718    return (new $.gsb.ariaSupport(pluginBase));
26719  };
26720})(jQuery);
26721   /* Ende gsb_ariaSupport */
26722   /* Start foundation */
26723   /*
26724 * Foundation Responsive Library
26725 * http://foundation.zurb.com
26726 * Copyright 2014, ZURB
26727 * Free to use under the MIT license.
26728 * http://www.opensource.org/licenses/mit-license.php
26729*/
26730(function ($, window, document, undefined) {
26731  'use strict';
26732  var header_helpers = function (class_array) {
26733    var i = class_array.length;
26734    var head = $('head');
26735    while (i--) {
26736      if(head.has('.' + class_array[i]).length === 0) {
26737        head.append('<meta class="' + class_array[i] + '" />');
26738      }
26739    }
26740  };
26741  header_helpers([
26742    'foundation-mq-small',
26743    'foundation-mq-medium',
26744    'foundation-mq-large',
26745    'foundation-mq-xlarge',
26746    'foundation-mq-xxlarge',
26747    'foundation-data-attribute-namespace']);
26748  // Enable FastClick if present
26749  $(function() {
26750    if (typeof FastClick !== 'undefined') {
26751      // Don't attach to body if undefined
26752      if (typeof document.body !== 'undefined') {
26753        FastClick.attach(document.body);
26754      }
26755    }
26756  });
26757  // private Fast Selector wrapper,
26758  // returns jQuery object. Only use where
26759  // getElementById is not available.
26760  var S = function (selector, context) {
26761    if (typeof selector === 'string') {
26762      if (context) {
26763        var cont;
26764        if (context.jquery) {
26765          cont = context[0];
26766          if (!cont) return context;
26767        } else {
26768          cont = context;
26769        }
26770        return $(cont.querySelectorAll(selector));
26771      }
26772      return $(document.querySelectorAll(selector));
26773    }
26774    return $(selector, context);
26775  };
26776  // Namespace functions.
26777  var attr_name = function (init) {
26778    var arr = [];
26779    if (!init) arr.push('data');
26780    if (this.namespace.length > 0) arr.push(this.namespace);
26781    arr.push(this.name);
26782    return arr.join('-');
26783  };
26784  var add_namespace = function (str) {
26785    var parts = str.split('-'),
26786        i = parts.length,
26787        arr = [];
26788    while (i--) {
26789      if (i !== 0) {
26790        arr.push(parts[i]);
26791      } else {
26792        if (this.namespace.length > 0) {
26793          arr.push(this.namespace, parts[i]);
26794        } else {
26795          arr.push(parts[i]);
26796        }
26797      }
26798    }
26799    return arr.reverse().join('-');
26800  };
26801  // Event binding and data-options updating.
26802  var bindings = function (method, options) {
26803    var self = this,
26804        should_bind_events = !S(this).data(this.attr_name(true));
26805    if (S(this.scope).is('[' + this.attr_name() +']')) {
26806      S(this.scope).data(this.attr_name(true) + '-init', $.extend({}, this.settings, (options || method), this.data_options(S(this.scope))));
26807      if (should_bind_events) {
26808        this.events(this.scope);
26809      }
26810    } else {
26811      S('[' + this.attr_name() +']', this.scope).each(function () {
26812        var should_bind_events = !S(this).data(self.attr_name(true) + '-init');
26813        S(this).data(self.attr_name(true) + '-init', $.extend({}, self.settings, (options || method), self.data_options(S(this))));
26814        if (should_bind_events) {
26815          self.events(this);
26816        }
26817      });
26818    }
26819    // # Patch to fix #5043 to move this *after* the if/else clause in order for Backbone and similar frameworks to have improved control over event binding and data-options updating.
26820    if (typeof method === 'string') {
26821      return this[method].call(this, options);
26822    }
26823  };
26824  var single_image_loaded = function (image, callback) {
26825    function loaded () {
26826      callback(image[0]);
26827    }
26828    function bindLoad () {
26829      this.one('load', loaded);
26830      if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
26831        var src = this.attr( 'src' ),
26832            param = src.match( /\?/ ) ? '&' : '?';
26833        param += 'random=' + (new Date()).getTime();
26834        this.attr('src', src + param);
26835      }
26836    }
26837    if (!image.attr('src')) {
26838      loaded();
26839      return;
26840    }
26841    if (image[0].complete || image[0].readyState === 4) {
26842      loaded();
26843    } else {
26844      bindLoad.call(image);
26845    }
26846  };
26847  /*
26848    https://github.com/paulirish/matchMedia.js
26849  */
26850  window.matchMedia = window.matchMedia || (function( doc ) {
26851    "use strict";
26852    var bool,
26853        docElem = doc.documentElement,
26854        refNode = docElem.firstElementChild || docElem.firstChild,
26855        // fakeBody required for <FF4 when executed in <head>
26856        fakeBody = doc.createElement( "body" ),
26857        div = doc.createElement( "div" );
26858    div.id = "mq-test-1";
26859    div.style.cssText = "position:absolute;top:-100em";
26860    fakeBody.style.background = "none";
26861    fakeBody.appendChild(div);
26862    return function (q) {
26863      div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
26864      docElem.insertBefore( fakeBody, refNode );
26865      bool = div.offsetWidth === 42;
26866      docElem.removeChild( fakeBody );
26867      return {
26868        matches: bool,
26869        media: q
26870      };
26871    };
26872  }( document ));
26873  /*
26874   * jquery.requestAnimationFrame
26875   * https://github.com/gnarf37/jquery-requestAnimationFrame
26876   * Requires jQuery 1.8+
26877   *
26878   * Copyright (c) 2012 Corey Frang
26879   * Licensed under the MIT license.
26880   */
26881  (function($) {
26882  // requestAnimationFrame polyfill adapted from Erik Möller
26883  // fixes from Paul Irish and Tino Zijdel
26884  // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
26885  // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
26886  var animating,
26887      lastTime = 0,
26888      vendors = ['webkit', 'moz'],
26889      requestAnimationFrame = window.requestAnimationFrame,
26890      cancelAnimationFrame = window.cancelAnimationFrame,
26891      jqueryFxAvailable = 'undefined' !== typeof jQuery.fx;
26892  for (; lastTime < vendors.length && !requestAnimationFrame; lastTime++) {
26893    requestAnimationFrame = window[ vendors[lastTime] + "RequestAnimationFrame" ];
26894    cancelAnimationFrame = cancelAnimationFrame ||
26895      window[ vendors[lastTime] + "CancelAnimationFrame" ] ||
26896      window[ vendors[lastTime] + "CancelRequestAnimationFrame" ];
26897  }
26898  function raf() {
26899    if (animating) {
26900      requestAnimationFrame(raf);
26901      if (jqueryFxAvailable) {
26902        jQuery.fx.tick();
26903      }
26904    }
26905  }
26906  if (requestAnimationFrame) {
26907    // use rAF
26908    window.requestAnimationFrame = requestAnimationFrame;
26909    window.cancelAnimationFrame = cancelAnimationFrame;
26910    if (jqueryFxAvailable) {
26911      jQuery.fx.timer = function (timer) {
26912        if (timer() && jQuery.timers.push(timer) && !animating) {
26913          animating = true;
26914          raf();
26915        }
26916      };
26917      jQuery.fx.stop = function () {
26918        animating = false;
26919      };
26920    }
26921  } else {
26922    // polyfill
26923    window.requestAnimationFrame = function (callback) {
26924      var currTime = new Date().getTime(),
26925        timeToCall = Math.max(0, 16 - (currTime - lastTime)),
26926        id = window.setTimeout(function () {
26927          callback(currTime + timeToCall);
26928        }, timeToCall);
26929      lastTime = currTime + timeToCall;
26930      return id;
26931    };
26932    window.cancelAnimationFrame = function (id) {
26933      clearTimeout(id);
26934    };
26935  }
26936  }( jQuery ));
26937  function removeQuotes (string) {
26938    if (typeof string === 'string' || string instanceof String) {
26939      string = string.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g, '');
26940    }
26941    return string;
26942  }
26943  window.Foundation = {
26944    name : 'Foundation',
26945    version : '{{VERSION}}',
26946    media_queries : {
26947      small : S('.foundation-mq-small').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
26948      medium : S('.foundation-mq-medium').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
26949      large : S('.foundation-mq-large').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
26950      xlarge: S('.foundation-mq-xlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
26951      xxlarge: S('.foundation-mq-xxlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, '')
26952    },
26953    stylesheet : $('<style></style>').appendTo('head')[0].sheet,
26954    global: {
26955      namespace: undefined
26956    },
26957    init : function (scope, libraries, method, options, response) {
26958      var args = [scope, method, options, response],
26959          responses = [];
26960      // check RTL
26961      this.rtl = /rtl/i.test(S('html').attr('dir'));
26962      // set foundation global scope
26963      this.scope = scope || this.scope;
26964      this.set_namespace();
26965      if (libraries && typeof libraries === 'string' && !/reflow/i.test(libraries)) {
26966        if (this.libs.hasOwnProperty(libraries)) {
26967          responses.push(this.init_lib(libraries, args));
26968        }
26969      } else {
26970        for (var lib in this.libs) {
26971          responses.push(this.init_lib(lib, libraries));
26972        }
26973      }
26974      S(window).load(function(){
26975        S(window)
26976          .trigger('resize.fndtn.clearing')
26977          .trigger('resize.fndtn.dropdown')
26978          .trigger('resize.fndtn.equalizer')
26979          .trigger('resize.fndtn.interchange')
26980          .trigger('resize.fndtn.joyride')
26981          .trigger('resize.fndtn.magellan')
26982          .trigger('resize.fndtn.topbar')
26983          .trigger('resize.fndtn.slider');
26984      });
26985      return scope;
26986    },
26987    init_lib : function (lib, args) {
26988      if (this.libs.hasOwnProperty(lib)) {
26989        this.patch(this.libs[lib]);
26990        if (args && args.hasOwnProperty(lib)) {
26991            if (typeof this.libs[lib].settings !== 'undefined') {
26992                $.extend(true, this.libs[lib].settings, args[lib]);
26993            }
26994            else if (typeof this.libs[lib].defaults !== 'undefined') {
26995                $.extend(true, this.libs[lib].defaults, args[lib]);
26996            }
26997          return this.libs[lib].init.apply(this.libs[lib], [this.scope, args[lib]]);
26998        }
26999        args = args instanceof Array ? args : new Array(args);    // PATCH: added this line
27000        return this.libs[lib].init.apply(this.libs[lib], args);
27001      }
27002      return function () {};
27003    },
27004    patch : function (lib) {
27005      lib.scope = this.scope;
27006      lib.namespace = this.global.namespace;
27007      lib.rtl = this.rtl;
27008      lib['data_options'] = this.utils.data_options;
27009      lib['attr_name'] = attr_name;
27010      lib['add_namespace'] = add_namespace;
27011      lib['bindings'] = bindings;
27012      lib['S'] = this.utils.S;
27013    },
27014    inherit : function (scope, methods) {
27015      var methods_arr = methods.split(' '),
27016          i = methods_arr.length;
27017      while (i--) {
27018        if (this.utils.hasOwnProperty(methods_arr[i])) {
27019          scope[methods_arr[i]] = this.utils[methods_arr[i]];
27020        }
27021      }
27022    },
27023    set_namespace: function () {
27024      // Description:
27025      //    Don't bother reading the namespace out of the meta tag
27026      //    if the namespace has been set globally in javascript
27027      //
27028      // Example:
27029      //    Foundation.global.namespace = 'my-namespace';
27030      // or make it an empty string:
27031      //    Foundation.global.namespace = '';
27032      //
27033      //
27034      // If the namespace has not been set (is undefined), try to read it out of the meta element.
27035      // Otherwise use the globally defined namespace, even if it's empty ('')
27036      var namespace = ( this.global.namespace === undefined ) ? $('.foundation-data-attribute-namespace').css('font-family') : this.global.namespace;
27037      // Finally, if the namsepace is either undefined or false, set it to an empty string.
27038      // Otherwise use the namespace value.
27039      this.global.namespace = ( namespace === undefined || /false/i.test(namespace) ) ? '' : namespace;
27040    },
27041    libs : {},
27042    // methods that can be inherited in libraries
27043    utils : {
27044      // Description:
27045      //    Fast Selector wrapper returns jQuery object. Only use where getElementById
27046      //    is not available.
27047      //
27048      // Arguments:
27049      //    Selector (String): CSS selector describing the element(s) to be
27050      //    returned as a jQuery object.
27051      //
27052      //    Scope (String): CSS selector describing the area to be searched. Default
27053      //    is document.
27054      //
27055      // Returns:
27056      //    Element (jQuery Object): jQuery object containing elements matching the
27057      //    selector within the scope.
27058      S : S,
27059      // Description:
27060      //    Executes a function a max of once every n milliseconds
27061      //
27062      // Arguments:
27063      //    Func (Function): Function to be throttled.
27064      //
27065      //    Delay (Integer): Function execution threshold in milliseconds.
27066      //
27067      // Returns:
27068      //    Lazy_function (Function): Function with throttling applied.
27069      throttle : function (func, delay) {
27070        var timer = null;
27071        return function () {
27072          var context = this, args = arguments;
27073          if (timer == null) {
27074            timer = setTimeout(function () {
27075              func.apply(context, args);
27076              timer = null;
27077            }, delay);
27078          }
27079        };
27080      },
27081      // Description:
27082      //    Executes a function when it stops being invoked for n seconds
27083      //    Modified version of _.debounce() http://underscorejs.org
27084      //
27085      // Arguments:
27086      //    Func (Function): Function to be debounced.
27087      //
27088      //    Delay (Integer): Function execution threshold in milliseconds.
27089      //
27090      //    Immediate (Bool): Whether the function should be called at the beginning
27091      //    of the delay instead of the end. Default is false.
27092      //
27093      // Returns:
27094      //    Lazy_function (Function): Function with debouncing applied.
27095      debounce : function (func, delay, immediate) {
27096        var timeout, result;
27097        return function () {
27098          var context = this, args = arguments;
27099          var later = function () {
27100            timeout = null;
27101            if (!immediate) result = func.apply(context, args);
27102          };
27103          var callNow = immediate && !timeout;
27104          clearTimeout(timeout);
27105          timeout = setTimeout(later, delay);
27106          if (callNow) result = func.apply(context, args);
27107          return result;
27108        };
27109      },
27110      // Description:
27111      //    Parses data-options attribute
27112      //
27113      // Arguments:
27114      //    El (jQuery Object): Element to be parsed.
27115      //
27116      // Returns:
27117      //    Options (Javascript Object): Contents of the element's data-options
27118      //    attribute.
27119      data_options : function (el, data_attr_name) {
27120        data_attr_name = data_attr_name || 'options';
27121        var opts = {}, ii, p, opts_arr,
27122            data_options = function (el) {
27123              var namespace = Foundation.global.namespace;
27124              if (namespace.length > 0) {
27125                return el.data(namespace + '-' + data_attr_name);
27126              }
27127              return el.data(data_attr_name);
27128            };
27129        var cached_options = data_options(el);
27130        if (typeof cached_options === 'object') {
27131          return cached_options;
27132        }
27133        opts_arr = (cached_options || ':').split(';');
27134        ii = opts_arr.length;
27135        function isNumber (o) {
27136          return ! isNaN (o-0) && o !== null && o !== "" && o !== false && o !== true;
27137        }
27138        function trim (str) {
27139          if (typeof str === 'string') return $.trim(str);
27140          return str;
27141        }
27142        while (ii--) {
27143          p = opts_arr[ii].split(':');
27144          p = [p[0], p.slice(1).join(':')];
27145          if (/true/i.test(p[1])) p[1] = true;
27146          if (/false/i.test(p[1])) p[1] = false;
27147          if (isNumber(p[1])) {
27148            if (p[1].indexOf('.') === -1) {
27149              p[1] = parseInt(p[1], 10);
27150            } else {
27151              p[1] = parseFloat(p[1]);
27152            }
27153          }
27154          if (p.length === 2 && p[0].length > 0) {
27155            opts[trim(p[0])] = trim(p[1]);
27156          }
27157        }
27158        return opts;
27159      },
27160      // Description:
27161      //    Adds JS-recognizable media queries
27162      //
27163      // Arguments:
27164      //    Media (String): Key string for the media query to be stored as in
27165      //    Foundation.media_queries
27166      //
27167      //    Class (String): Class name for the generated <meta> tag
27168      register_media : function (media, media_class) {
27169        if(Foundation.media_queries[media] === undefined) {
27170          $('head').append('<meta class="' + media_class + '"/>');
27171          Foundation.media_queries[media] = removeQuotes($('.' + media_class).css('font-family'));
27172        }
27173      },
27174      // Description:
27175      //    Add custom CSS within a JS-defined media query
27176      //
27177      // Arguments:
27178      //    Rule (String): CSS rule to be appended to the document.
27179      //
27180      //    Media (String): Optional media query string for the CSS rule to be
27181      //    nested under.
27182      add_custom_rule : function (rule, media) {
27183        if (media === undefined && Foundation.stylesheet) {
27184          Foundation.stylesheet.insertRule(rule, Foundation.stylesheet.cssRules.length);
27185        } else {
27186          var query = Foundation.media_queries[media];
27187          if (query !== undefined) {
27188            Foundation.stylesheet.insertRule('@media ' +
27189              Foundation.media_queries[media] + '{ ' + rule + ' }');
27190          }
27191        }
27192      },
27193      // Description:
27194      //    Performs a callback function when an image is fully loaded
27195      //
27196      // Arguments:
27197      //    Image (jQuery Object): Image(s) to check if loaded.
27198      //
27199      //    Callback (Function): Function to execute when image is fully loaded.
27200      image_loaded : function (images, callback) {
27201        var self = this,
27202            unloaded = images.length;
27203        if (unloaded === 0) {
27204          callback(images);
27205        }
27206        images.each(function () {
27207          single_image_loaded(self.S(this), function () {
27208            unloaded -= 1;
27209            if (unloaded === 0) {
27210              callback(images);
27211            }
27212          });
27213        });
27214      },
27215      // Description:
27216      //    Returns a random, alphanumeric string
27217      //
27218      // Arguments:
27219      //    Length (Integer): Length of string to be generated. Defaults to random
27220      //    integer.
27221      //
27222      // Returns:
27223      //    Rand (String): Pseudo-random, alphanumeric string.
27224      random_str : function () {
27225        if (!this.fidx) this.fidx = 0;
27226        this.prefix = this.prefix || [(this.name || 'F'), (+new Date).toString(36)].join('-');
27227        return this.prefix + (this.fidx++).toString(36);
27228      }
27229    }
27230  };
27231  $.fn.foundation = function () {
27232    var args = Array.prototype.slice.call(arguments, 0);
27233    return this.each(function () {
27234      Foundation.init.apply(Foundation, [this].concat(args));
27235      return this;
27236    });
27237  };
27238}(jQuery, window, window.document));
27239
27240   /* Ende foundation */
27241   /* Start foundation.tooltip */
27242   ;(function ($, window, document, undefined) {
27243  'use strict';
27244
27245  Foundation.libs.tooltip = {
27246    name : 'tooltip',
27247
27248    version : '{{VERSION}}',
27249
27250    settings : {
27251      additional_inheritable_classes : [],
27252      tooltip_class : '.tooltip',
27253      append_to: 'body',
27254      touch_close_text: 'Tap To Close',
27255      disable_for_touch: false,
27256      hover_delay: 200,
27257      show_on : 'all',
27258      tip_template : function (selector, content) {
27259        return '<span data-selector="' + selector + '" id="' + selector + '" class="'
27260          + Foundation.libs.tooltip.settings.tooltip_class.substring(1)
27261          + '" role="tooltip">' + content + '<span class="nub"></span></span>';
27262      }
27263    },
27264
27265    cache : {},
27266
27267    init : function (scope, method, options) {
27268      Foundation.inherit(this, 'random_str');
27269      this.bindings(method, options);
27270    },
27271
27272    should_show: function (target, tip) {
27273      var settings = $.extend({}, this.settings, this.data_options(target));
27274
27275      if (settings.show_on === 'all') {
27276        return true;
27277      } else if (this.small() && settings.show_on === 'small') {
27278        return true;
27279      } else if (this.medium() && settings.show_on === 'medium') {
27280        return true;
27281      } else if (this.large() && settings.show_on === 'large') {
27282        return true;
27283      }
27284      return false;
27285    },
27286
27287    medium : function () {
27288      return matchMedia(Foundation.media_queries['medium']).matches;
27289    },
27290
27291    large : function () {
27292      return matchMedia(Foundation.media_queries['large']).matches;
27293    },
27294
27295    events : function (instance) {
27296      var self = this,
27297          S = self.S;
27298
27299      self.create(this.S(instance));
27300
27301      $(this.scope)
27302        .off('.tooltip')
27303        .on('mouseenter.fndtn.tooltip mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip',
27304          '[' + this.attr_name() + ']', function (e) {
27305          var $this = S(this),
27306              settings = $.extend({}, self.settings, self.data_options($this)),
27307              is_touch = false;
27308
27309          if (Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type) && S(e.target).is('a')) {
27310            return false;
27311          }
27312
27313          if (/mouse/i.test(e.type) && self.ie_touch(e)) return false;
27314
27315          if ($this.hasClass('open')) {
27316            if (Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) e.preventDefault();
27317            self.hide($this);
27318          } else {
27319            if (settings.disable_for_touch && Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) {
27320              return;
27321            } else if(!settings.disable_for_touch && Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) {
27322              e.preventDefault();
27323              S(settings.tooltip_class + '.open').hide();
27324              is_touch = true;
27325            }
27326
27327            if (/enter|over/i.test(e.type)) {
27328              this.timer = setTimeout(function () {
27329                var tip = self.showTip($this);
27330              }.bind(this), self.settings.hover_delay);
27331            } else if (e.type === 'mouseout' || e.type === 'mouseleave') {
27332              clearTimeout(this.timer);
27333              self.hide($this);
27334            } else {
27335              self.showTip($this);
27336            }
27337          }
27338        })
27339        .on('mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', '[' + this.attr_name() + '].open', function (e) {
27340          if (/mouse/i.test(e.type) && self.ie_touch(e)) return false;
27341
27342          if($(this).data('tooltip-open-event-type') == 'touch' && e.type == 'mouseleave') {
27343            return;
27344          }
27345          else if($(this).data('tooltip-open-event-type') == 'mouse' && /MSPointerDown|touchstart/i.test(e.type)) {
27346            self.convert_to_touch($(this));
27347          } else {
27348            self.hide($(this));
27349          }
27350        })
27351        // .on('DOMNodeRemoved DOMAttrModified', '[' + this.attr_name() + ']:not(a)', function (e) {
27352        //   self.hide(S(this));
27353        // });
27354    },
27355
27356    ie_touch : function (e) {
27357      // How do I distinguish between IE11 and Windows Phone 8?????
27358      return false;
27359    },
27360
27361    showTip : function ($target) {
27362      var $tip = this.getTip($target);
27363      if (this.should_show($target, $tip)){
27364        return this.show($target);
27365      }
27366      return;
27367    },
27368
27369    getTip : function ($target) {
27370      var selector = this.selector($target),
27371          settings = $.extend({}, this.settings, this.data_options($target)),
27372          tip = null;
27373
27374      if (selector) {
27375        tip = this.S('span[data-selector="' + selector + '"]' + settings.tooltip_class);
27376      }
27377
27378      return (typeof tip === 'object') ? tip : false;
27379    },
27380
27381    selector : function ($target) {
27382      var id = $target.attr('id'),
27383          dataSelector = $target.attr(this.attr_name()) || $target.attr('data-selector');
27384
27385      if ((id && id.length < 1 || !id) && typeof dataSelector != 'string') {
27386        dataSelector = this.random_str(6);
27387        $target
27388          .attr('data-selector', dataSelector)
27389          .attr('aria-describedby', dataSelector);
27390      }
27391
27392      return (id && id.length > 0) ? id : dataSelector;
27393    },
27394
27395    create : function ($target) {
27396      var self = this,
27397          settings = $.extend({}, this.settings, this.data_options($target)),
27398          tip_template = this.settings.tip_template;
27399
27400      if (typeof settings.tip_template === 'string' && window.hasOwnProperty(settings.tip_template)) {
27401        tip_template = window[settings.tip_template];
27402      }
27403
27404      var $tip = $(tip_template(this.selector($target), $('<div></div>').html($target.attr('title')).html())),
27405          classes = this.inheritable_classes($target);
27406
27407      $tip.addClass(classes).appendTo(settings.append_to);
27408
27409      if (Modernizr.touch) {
27410        $tip.append('<span class="tap-to-close">'+settings.touch_close_text+'</span>');
27411        $tip.on('touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', function(e) {
27412          self.hide($target);
27413        });
27414      }
27415
27416      $target.removeAttr('title').attr('title','');
27417    },
27418
27419    reposition : function (target, tip, classes) {
27420      var width, nub, nubHeight, nubWidth, column, objPos;
27421
27422      tip.css('visibility', 'hidden').show();
27423
27424      width = target.data('width');
27425      nub = tip.children('.nub');
27426      nubHeight = nub.outerHeight();
27427      nubWidth = nub.outerHeight();
27428
27429      if (this.small()) {
27430        tip.css({'width' : '100%' });
27431      } else {
27432        tip.css({'width' : (width) ? width : 'auto'});
27433      }
27434
27435      objPos = function (obj, top, right, bottom, left, width) {
27436        return obj.css({
27437          'top' : (top) ? top : 'auto',
27438          'bottom' : (bottom) ? bottom : 'auto',
27439          'left' : (left) ? left : 'auto',
27440          'right' : (right) ? right : 'auto'
27441        }).end();
27442      };
27443
27444      objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', target.offset().left);
27445
27446      if (this.small()) {
27447        objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', 12.5, $(this.scope).width());
27448        tip.addClass('tip-override');
27449        objPos(nub, -nubHeight, 'auto', 'auto', target.offset().left);
27450      } else {
27451        var left = target.offset().left;
27452        if (Foundation.rtl) {
27453          nub.addClass('rtl');
27454          left = target.offset().left + target.outerWidth() - tip.outerWidth();
27455        }
27456        objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', left);
27457        tip.removeClass('tip-override');
27458        if (classes && classes.indexOf('tip-top') > -1) {
27459          if (Foundation.rtl) nub.addClass('rtl');
27460          objPos(tip, (target.offset().top - tip.outerHeight()), 'auto', 'auto', left)
27461            .removeClass('tip-override');
27462        } else if (classes && classes.indexOf('tip-left') > -1) {
27463          objPos(tip, (target.offset().top + (target.outerHeight() / 2) - (tip.outerHeight() / 2)), 'auto', 'auto', (target.offset().left - tip.outerWidth() - nubHeight))
27464            .removeClass('tip-override');
27465          nub.removeClass('rtl');
27466        } else if (classes && classes.indexOf('tip-right') > -1) {
27467          objPos(tip, (target.offset().top + (target.outerHeight() / 2) - (tip.outerHeight() / 2)), 'auto', 'auto', (target.offset().left + target.outerWidth() + nubHeight))
27468            .removeClass('tip-override');
27469          nub.removeClass('rtl');
27470        }
27471      }
27472
27473      tip.css('visibility', 'visible').hide();
27474    },
27475
27476    small : function () {
27477      return matchMedia(Foundation.media_queries.small).matches &&
27478        !matchMedia(Foundation.media_queries.medium).matches;
27479    },
27480
27481    inheritable_classes : function ($target) {
27482      var settings = $.extend({}, this.settings, this.data_options($target)),
27483          inheritables = ['tip-top', 'tip-left', 'tip-bottom', 'tip-right', 'radius', 'round'].concat(settings.additional_inheritable_classes),
27484          classes = $target.attr('class'),
27485          filtered = classes ? $.map(classes.split(' '), function (el, i) {
27486            if ($.inArray(el, inheritables) !== -1) {
27487              return el;
27488            }
27489          }).join(' ') : '';
27490
27491      return $.trim(filtered);
27492    },
27493
27494    convert_to_touch : function($target) {
27495      var self = this,
27496          $tip = self.getTip($target),
27497          settings = $.extend({}, self.settings, self.data_options($target));
27498
27499      if ($tip.find('.tap-to-close').length === 0) {
27500        $tip.append('<span class="tap-to-close">'+settings.touch_close_text+'</span>');
27501        $tip.on('click.fndtn.tooltip.tapclose touchstart.fndtn.tooltip.tapclose MSPointerDown.fndtn.tooltip.tapclose', function(e) {
27502          self.hide($target);
27503        });
27504      }
27505
27506      $target.data('tooltip-open-event-type', 'touch');
27507    },
27508
27509    show : function ($target) {
27510      var $tip = this.getTip($target);
27511
27512      if ($target.data('tooltip-open-event-type') == 'touch') {
27513        this.convert_to_touch($target);
27514      }
27515
27516      this.reposition($target, $tip, $target.attr('class'));
27517      $target.addClass('open');
27518      $tip.fadeIn(150);
27519    },
27520
27521    hide : function ($target) {
27522      var $tip = this.getTip($target);
27523
27524      $tip.fadeOut(150, function() {
27525        $tip.find('.tap-to-close').remove();
27526        $tip.off('click.fndtn.tooltip.tapclose MSPointerDown.fndtn.tapclose');
27527        $target.removeClass('open');
27528      });
27529    },
27530
27531    off : function () {
27532      var self = this;
27533      this.S(this.scope).off('.fndtn.tooltip');
27534      this.S(this.settings.tooltip_class).each(function (i) {
27535        $('[' + self.attr_name() + ']').eq(i).attr('title', $(this).text());
27536      }).remove();
27537    },
27538
27539    reflow : function () {}
27540  };
27541}(jQuery, window, window.document));
27542   /* Ende foundation.tooltip */
27543   /* Start hammer */
27544   /*! Hammer.JS - v2.0.2 - 2014-07-28  * http://hammerjs.github.io/  *  * Copyright (c) 2014 Jorik Tangelder <[email protected]>;  * Licensed under the MIT license */ ! function(a, b, c, d) {
27545    function e(a, b, c) {
27546        return setTimeout(k(a, c), b);
27547    }
27548
27549    function f(a, b, c) {
27550        return Array.isArray(a) ? (g(a, c[b], c), !0) : !1;
27551    }
27552
27553    function g(a, b, c) {
27554        var e, f;
27555        if (a) {
27556            if (a.forEach) {
27557                a.forEach(b, c);
27558            } else {
27559                if (a.length !== d) {
27560                    for (e = 0, f = a.length; f > e; e++) {
27561                        b.call(c, a[e], e, a);
27562                    }
27563                } else {
27564                    for (e in a) {
27565                        a.hasOwnProperty(e) && b.call(c, a[e], e, a);
27566                    }
27567                }
27568            }
27569        }
27570    }
27571
27572    function h(a, b, c) {
27573        for (var e = Object.keys(b), f = 0, g = e.length; g > f; f++) {
27574            (!c || c && a[e[f]] === d) && (a[e[f]] = b[e[f]]);
27575        }
27576        return a;
27577    }
27578
27579    function i(a, b) {
27580        return h(a, b, !0);
27581    }
27582
27583    function j(a, b, c) {
27584        var d, e = b.prototype;
27585        d = a.prototype = Object.create(e), d.constructor = a, d._super = e, c && h(d, c);
27586    }
27587
27588    function k(a, b) {
27589        return function() {
27590            return a.apply(b, arguments);
27591        };
27592    }
27593
27594    function l(a, b) {
27595        return typeof a == hb ? a.apply(b ? b[0] || d : d, b) : a;
27596    }
27597
27598    function m(a, b) {
27599        return a === d ? b : a;
27600    }
27601
27602    function n(a, b, c) {
27603        g(r(b), function(b) {
27604            a.addEventListener(b, c, !1);
27605        });
27606    }
27607
27608    function o(a, b, c) {
27609        g(r(b), function(b) {
27610            a.removeEventListener(b, c, !1);
27611        });
27612    }
27613
27614    function p(a, b) {
27615        for (; a;) {
27616            if (a == b) {
27617                return !0;
27618            }
27619            a = a.parentNode;
27620        }
27621        return !1;
27622    }
27623
27624    function q(a, b) {
27625        return a.indexOf(b) > -1;
27626    }
27627
27628    function r(a) {
27629        return a.trim().split(/\s+/g);
27630    }
27631
27632    function s(a, b, c) {
27633        if (a.indexOf && !c) {
27634            return a.indexOf(b);
27635        }
27636        for (var d = 0, e = a.length; e > d; d++) {
27637            if (c && a[d][c] == b || !c && a[d] === b) {
27638                return d;
27639            }
27640        }
27641        return -1;
27642    }
27643
27644    function t(a) {
27645        return Array.prototype.slice.call(a, 0);
27646    }
27647
27648    function u(a, b, c) {
27649        for (var d = [], e = [], f = 0, g = a.length; g > f; f++) {
27650            var h = b ? a[f][b] : a[f];
27651            s(e, h) < 0 && d.push(a[f]), e[f] = h;
27652        }
27653        return c && (d = b ? d.sort(function(a, c) {
27654            return a[b] > c[b];
27655        }) : d.sort()), d;
27656    }
27657
27658    function v(a, b) {
27659        for (var c, e, f = b[0].toUpperCase() + b.slice(1), g = 0, h = fb.length; h > g; g++) {
27660            if (c = fb[g], e = c ? c + f : b, e in a) {
27661                return e;
27662            }
27663        }
27664        return d;
27665    }
27666
27667    function w() {
27668        return lb++;
27669    }
27670
27671    function x(b, c) {
27672        var d = this;
27673        this.manager = b, this.callback = c, this.element = b.element, this.target = b.options.inputTarget, this.domHandler = function(a) {
27674            l(b.options.enable, [b]) && d.handler(a);
27675        }, this.evEl && n(this.element, this.evEl, this.domHandler), this.evTarget && n(this.target, this.evTarget, this.domHandler), this.evWin && n(a, this.evWin, this.domHandler);
27676    }
27677
27678    function y(a) {
27679        var b;
27680        return new(b = ob ? M : pb ? N : nb ? P : L)(a, z);
27681    }
27682
27683    function z(a, b, c) {
27684        var d = c.pointers.length,
27685            e = c.changedPointers.length,
27686            f = b & vb && d - e === 0,
27687            g = b & (xb | yb) && d - e === 0;
27688        c.isFirst = !!f, c.isFinal = !!g, f && (a.session = {}), c.eventType = b, A(a, c), a.emit("hammer.input", c), a.recognize(c), a.session.prevInput = c;
27689    }
27690
27691    function A(a, b) {
27692        var c = a.session,
27693            d = b.pointers,
27694            e = d.length;
27695        c.firstInput || (c.firstInput = D(b)), e > 1 && !c.firstMultiple ? c.firstMultiple = D(b) : 1 === e && (c.firstMultiple = !1);
27696        var f = c.firstInput,
27697            g = c.firstMultiple,
27698            h = g ? g.center : f.center,
27699            i = b.center = E(d);
27700        b.timeStamp = kb(), b.deltaTime = b.timeStamp - f.timeStamp, b.angle = I(h, i), b.distance = H(h, i), B(c, b), b.offsetDirection = G(b.deltaX, b.deltaY), b.scale = g ? K(g.pointers, d) : 1, b.rotation = g ? J(g.pointers, d) : 0, C(c, b);
27701        var j = a.element;
27702        p(b.srcEvent.target, j) && (j = b.srcEvent.target), b.target = j;
27703    }
27704
27705    function B(a, b) {
27706        var c = b.center,
27707            d = a.offsetDelta || {},
27708            e = a.prevDelta || {},
27709            f = a.prevInput || {};
27710        (b.eventType === vb || f.eventType === xb) && (e = a.prevDelta = {
27711            x: f.deltaX || 0,
27712            y: f.deltaY || 0
27713        }, d = a.offsetDelta = {
27714            x: c.x,
27715            y: c.y
27716        }), b.deltaX = e.x + (c.x - d.x), b.deltaY = e.y + (c.y - d.y);
27717    }
27718
27719    function C(a, b) {
27720        var c, e, f, g, h = a.lastInterval || b,
27721            i = b.timeStamp - h.timeStamp;
27722        if (b.eventType != yb && (i > ub || h.velocity === d)) {
27723            var j = h.deltaX - b.deltaX,
27724                k = h.deltaY - b.deltaY,
27725                l = F(i, j, k);
27726            e = l.x, f = l.y, c = jb(l.x) > jb(l.y) ? l.x : l.y, g = G(j, k), a.lastInterval = b;
27727        } else {
27728            c = h.velocity, e = h.velocityX, f = h.velocityY, g = h.direction;
27729        }
27730        b.velocity = c, b.velocityX = e, b.velocityY = f, b.direction = g;
27731    }
27732
27733    function D(a) {
27734        for (var b = [], c = 0; c < a.pointers.length; c++) {
27735            b[c] = {
27736                clientX: ib(a.pointers[c].clientX),
27737                clientY: ib(a.pointers[c].clientY)
27738            };
27739        }
27740        return {
27741            timeStamp: kb(),
27742            pointers: b,
27743            center: E(b),
27744            deltaX: a.deltaX,
27745            deltaY: a.deltaY
27746        };
27747    }
27748
27749    function E(a) {
27750        var b = a.length;
27751        if (1 === b) {
27752            return {
27753                x: ib(a[0].clientX),
27754                y: ib(a[0].clientY)
27755            };
27756        }
27757        for (var c = 0, d = 0, e = 0; b > e; e++) {
27758            c += a[e].clientX, d += a[e].clientY;
27759        }
27760        return {
27761            x: ib(c / b),
27762            y: ib(d / b)
27763        };
27764    }
27765
27766    function F(a, b, c) {
27767        return {
27768            x: b / a || 0,
27769            y: c / a || 0
27770        };
27771    }
27772
27773    function G(a, b) {
27774        return a === b ? zb : jb(a) >= jb(b) ? a > 0 ? Ab : Bb : b > 0 ? Cb : Db;
27775    }
27776
27777    function H(a, b, c) {
27778        c || (c = Hb);
27779        var d = b[c[0]] - a[c[0]],
27780            e = b[c[1]] - a[c[1]];
27781        return Math.sqrt(d * d + e * e);
27782    }
27783
27784    function I(a, b, c) {
27785        c || (c = Hb);
27786        var d = b[c[0]] - a[c[0]],
27787            e = b[c[1]] - a[c[1]];
27788        return 180 * Math.atan2(e, d) / Math.PI;
27789    }
27790
27791    function J(a, b) {
27792        return I(b[1], b[0], Ib) - I(a[1], a[0], Ib);
27793    }
27794
27795    function K(a, b) {
27796        return H(b[0], b[1], Ib) / H(a[0], a[1], Ib);
27797    }
27798
27799    function L() {
27800        this.evEl = Kb, this.evWin = Lb, this.allow = !0, this.pressed = !1, x.apply(this, arguments);
27801    }
27802
27803    function M() {
27804        this.evEl = Ob, this.evWin = Pb, x.apply(this, arguments), this.store = this.manager.session.pointerEvents = [];
27805    }
27806
27807    function N() {
27808        this.evTarget = Rb, this.targetIds = {}, x.apply(this, arguments);
27809    }
27810
27811    function O(a, b) {
27812        var c = t(a.touches),
27813            d = this.targetIds;
27814        if (b & (vb | wb) && 1 === c.length) {
27815            return d[c[0].identifier] = !0, [c, c];
27816        }
27817        var e, f, g = t(a.targetTouches),
27818            h = t(a.changedTouches),
27819            i = [];
27820        if (b === vb) {
27821            for (e = 0, f = g.length; f > e; e++) {
27822                d[g[e].identifier] = !0;
27823            }
27824        }
27825        for (e = 0, f = h.length; f > e; e++) {
27826            d[h[e].identifier] && i.push(h[e]), b & (xb | yb) && delete d[h[e].identifier];
27827        }
27828        return i.length ? [u(g.concat(i), "identifier", !0), i] : void 0;
27829    }
27830
27831    function P() {
27832        x.apply(this, arguments);
27833        var a = k(this.handler, this);
27834        this.touch = new N(this.manager, a), this.mouse = new L(this.manager, a);
27835    }
27836
27837    function Q(a, b) {
27838        this.manager = a, this.set(b);
27839    }
27840
27841    function R(a) {
27842        if (q(a, Xb)) {
27843            return Xb;
27844        }
27845        var b = q(a, Yb),
27846            c = q(a, Zb);
27847        return b && c ? Yb + " " + Zb : b || c ? b ? Yb : Zb : q(a, Wb) ? Wb : Vb;
27848    }
27849
27850    function S(a) {
27851        this.id = w(), this.manager = null, this.options = i(a || {}, this.defaults), this.options.enable = m(this.options.enable, !0), this.state = $b, this.simultaneous = {}, this.requireFail = [];
27852    }
27853
27854    function T(a) {
27855        return a & dc ? "cancel" : a & bc ? "end" : a & ac ? "move" : a & _b ? "start" : "";
27856    }
27857
27858    function U(a) {
27859        return a == Db ? "down" : a == Cb ? "up" : a == Ab ? "left" : a == Bb ? "right" : "";
27860    }
27861
27862    function V(a, b) {
27863        var c = b.manager;
27864        return c ? c.get(a) : a;
27865    }
27866
27867    function W() {
27868        S.apply(this, arguments);
27869    }
27870
27871    function X() {
27872        W.apply(this, arguments), this.pX = null, this.pY = null;
27873    }
27874
27875    function Y() {
27876        W.apply(this, arguments);
27877    }
27878
27879    function Z() {
27880        S.apply(this, arguments), this._timer = null, this._input = null;
27881    }
27882
27883    function $() {
27884        W.apply(this, arguments);
27885    }
27886
27887    function _() {
27888        W.apply(this, arguments);
27889    }
27890
27891    function ab() {
27892        S.apply(this, arguments), this.pTime = !1, this.pCenter = !1, this._timer = null, this._input = null, this.count = 0;
27893    }
27894
27895    function bb(a, b) {
27896        return b = b || {}, b.recognizers = m(b.recognizers, bb.defaults.preset), new cb(a, b);
27897    }
27898
27899    function cb(a, b) {
27900        b = b || {}, this.options = i(b, bb.defaults), this.options.inputTarget = this.options.inputTarget || a, this.handlers = {}, this.session = {}, this.recognizers = [], this.element = a, this.input = y(this), this.touchAction = new Q(this, this.options.touchAction), db(this, !0), g(b.recognizers, function(a) {
27901            var b = this.add(new a[0](a[1]));
27902            a[2] && b.recognizeWith(a[2]), a[3] && b.requireFailure(a[2]);
27903        }, this);
27904    }
27905
27906    function db(a, b) {
27907        var c = a.element;
27908        g(a.options.cssProps, function(a, d) {
27909            c.style[v(c.style, d)] = b ? a : "";
27910        });
27911    }
27912
27913    function eb(a, c) {
27914        var d = b.createEvent("Event");
27915        d.initEvent(a, !0, !0), d.gesture = c, c.target.dispatchEvent(d);
27916    }
27917    var fb = ["", "webkit", "moz", "MS", "ms", "o"],
27918        gb = b.createElement("div"),
27919        hb = "function",
27920        ib = Math.round,
27921        jb = Math.abs,
27922        kb = Date.now,
27923        lb = 1,
27924        mb = /mobile|tablet|ip(ad|hone|od)|android/i,
27925        nb = "ontouchstart" in a,
27926        ob = v(a, "PointerEvent") !== d,
27927        pb = nb && mb.test(navigator.userAgent),
27928        qb = "touch",
27929        rb = "pen",
27930        sb = "mouse",
27931        tb = "kinect",
27932        ub = 25,
27933        vb = 1,
27934        wb = 2,
27935        xb = 4,
27936        yb = 8,
27937        zb = 1,
27938        Ab = 2,
27939        Bb = 4,
27940        Cb = 8,
27941        Db = 16,
27942        Eb = Ab | Bb,
27943        Fb = Cb | Db,
27944        Gb = Eb | Fb,
27945        Hb = ["x", "y"],
27946        Ib = ["clientX", "clientY"];
27947    x.prototype = {
27948        handler: function() {},
27949        destroy: function() {
27950            this.evEl && o(this.element, this.evEl, this.domHandler), this.evTarget && o(this.target, this.evTarget, this.domHandler), this.evWin && o(a, this.evWin, this.domHandler);
27951        }
27952    };
27953    var Jb = {
27954            mousedown: vb,
27955            mousemove: wb,
27956            mouseup: xb
27957        },
27958        Kb = "mousedown",
27959        Lb = "mousemove mouseup";
27960    j(L, x, {
27961        handler: function(a) {
27962            var b = Jb[a.type];
27963            b & vb && 0 === a.button && (this.pressed = !0), b & wb && 1 !== a.which && (b = xb), this.pressed && this.allow && (b & xb && (this.pressed = !1), this.callback(this.manager, b, {
27964                pointers: [a],
27965                changedPointers: [a],
27966                pointerType: sb,
27967                srcEvent: a
27968            }));
27969        }
27970    });
27971    var Mb = {
27972            pointerdown: vb,
27973            pointermove: wb,
27974            pointerup: xb,
27975            pointercancel: yb,
27976            pointerout: yb
27977        },
27978        Nb = {
27979            2: qb,
27980            3: rb,
27981            4: sb,
27982            5: tb
27983        },
27984        Ob = "pointerdown",
27985        Pb = "pointermove pointerup pointercancel";
27986    a.MSPointerEvent && (Ob = "MSPointerDown", Pb = "MSPointerMove MSPointerUp MSPointerCancel"), j(M, x, {
27987        handler: function(a) {
27988            var b = this.store,
27989                c = !1,
27990                d = a.type.toLowerCase().replace("ms", ""),
27991                e = Mb[d],
27992                f = Nb[a.pointerType] || a.pointerType,
27993                g = f == qb;
27994            e & vb && (0 === a.button || g) ? b.push(a) : e & (xb | yb) && (c = !0);
27995            var h = s(b, a.pointerId, "pointerId");
27996            0 > h || (b[h] = a, this.callback(this.manager, e, {
27997                pointers: b,
27998                changedPointers: [a],
27999                pointerType: f,
28000                srcEvent: a
28001            }
28001), c && b.splice(h, 1));
28002        }
28003    });
28004    var Qb = {
28005            touchstart: vb,
28006            touchmove: wb,
28007            touchend: xb,
28008            touchcancel: yb
28009        },
28010        Rb = "touchstart touchmove touchend touchcancel";
28011    j(N, x, {
28012        handler: function(a) {
28013            var b = Qb[a.type],
28014                c = O.call(this, a, b);
28015            c && this.callback(this.manager, b, {
28016                pointers: c[0],
28017                changedPointers: c[1],
28018                pointerType: qb,
28019                srcEvent: a
28020            });
28021        }
28022    }), j(P, x, {
28023        handler: function(a, b, c) {
28024            var d = c.pointerType == qb,
28025                e = c.pointerType == sb;
28026            if (d) {
28027                this.mouse.allow = !1;
28028            } else {
28029                if (e && !this.mouse.allow) {
28030                    return;
28031                }
28032            }
28033            b & (xb | yb) && (this.mouse.allow = !0), this.callback(a, b, c);
28034        },
28035        destroy: function() {
28036            this.touch.destroy(), this.mouse.destroy();
28037        }
28038    });
28039    var Sb = v(gb.style, "touchAction"),
28040        Tb = Sb !== d,
28041        Ub = "compute",
28042        Vb = "auto",
28043        Wb = "manipulation",
28044        Xb = "none",
28045        Yb = "pan-x",
28046        Zb = "pan-y";
28047    Q.prototype = {
28048        set: function(a) {
28049            a == Ub && (a = this.compute()), Tb && (this.manager.element.style[Sb] = a), this.actions = a.toLowerCase().trim();
28050        },
28051        update: function() {
28052            this.set(this.manager.options.touchAction);
28053        },
28054        compute: function() {
28055            var a = [];
28056            return g(this.manager.recognizers, function(b) {
28057                l(b.options.enable, [b]) && (a = a.concat(b.getTouchAction()));
28058            }), R(a.join(" "));
28059        },
28060        preventDefaults: function(a) {
28061            if (!Tb) {
28062                var b = a.srcEvent,
28063                    c = a.offsetDirection;
28064                if (this.manager.session.prevented) {
28065                    return void b.preventDefault();
28066                }
28067                var d = this.actions,
28068                    e = q(d, Xb),
28069                    f = q(d, Zb),
28070                    g = q(d, Yb);
28071                return e || f && g || f && c & Eb || g && c & Fb ? this.preventSrc(b) : void 0;
28072            }
28073        },
28074        preventSrc: function(a) {
28075            this.manager.session.prevented = !0, a.preventDefault();
28076        }
28077    };
28078    var $b = 1,
28079        _b = 2,
28080        ac = 4,
28081        bc = 8,
28082        cc = bc,
28083        dc = 16,
28084        ec = 32;
28085    S.prototype = {
28086        defaults: {},
28087        set: function(a) {
28088            return h(this.options, a), this.manager && this.manager.touchAction.update(), this;
28089        },
28090        recognizeWith: function(a) {
28091            if (f(a, "recognizeWith", this)) {
28092                return this;
28093            }
28094            var b = this.simultaneous;
28095            return a = V(a, this), b[a.id] || (b[a.id] = a, a.recognizeWith(this)), this;
28096        },
28097        dropRecognizeWith: function(a) {
28098            return f(a, "dropRecognizeWith", this) ? this : (a = V(a, this), delete this.simultaneous[a.id], this);
28099        },
28100        requireFailure: function(a) {
28101            if (f(a, "requireFailure", this)) {
28102                return this;
28103            }
28104            var b = this.requireFail;
28105            return a = V(a, this), -1 === s(b, a) && (b.push(a), a.requireFailure(this)), this;
28106        },
28107        dropRequireFailure: function(a) {
28108            if (f(a, "dropRequireFailure", this)) {
28109                return this;
28110            }
28111            a = V(a, this);
28112            var b = s(this.requireFail, a);
28113            return b > -1 && this.requireFail.splice(b, 1), this;
28114        },
28115        hasRequireFailures: function() {
28116            return this.requireFail.length > 0;
28117        },
28118        canRecognizeWith: function(a) {
28119            return !!this.simultaneous[a.id];
28120        },
28121        emit: function(a) {
28122            function b(b) {
28123                c.manager.emit(c.options.event + (b ? T(d) : ""), a);
28124            }
28125            var c = this,
28126                d = this.state;
28127            bc > d && b(!0), b(), d >= bc && b(!0);
28128        },
28129        tryEmit: function(a) {
28130            return this.canEmit() ? this.emit(a) : void(this.state = ec);
28131        },
28132        canEmit: function() {
28133            for (var a = 0; a < this.requireFail.length; a++) {
28134                if (!(this.requireFail[a].state & (ec | $b))) {
28135                    return !1;
28136                }
28137            }
28138            return !0;
28139        },
28140        recognize: function(a) {
28141            var b = h({}, a);
28142            return l(this.options.enable, [this, b]) ? (this.state & (cc | dc | ec) && (this.state = $b), this.state = this.process(b), void(this.state & (_b | ac | bc | dc) && this.tryEmit(b))) : (this.reset(), void(this.state = ec));
28143        },
28144        process: function() {},
28145        getTouchAction: function() {},
28146        reset: function() {}
28147    }, j(W, S, {
28148        defaults: {
28149            pointers: 1
28150        },
28151        attrTest: function(a) {
28152            var b = this.options.pointers;
28153            return 0 === b || a.pointers.length === b;
28154        },
28155        process: function(a) {
28156            var b = this.state,
28157                c = a.eventType,
28158                d = b & (_b | ac),
28159                e = this.attrTest(a);
28160            return d && (c & yb || !e) ? b | dc : d || e ? c & xb ? b | bc : b & _b ? b | ac : _b : ec;
28161        }
28162    }), j(X, W, {
28163        defaults: {
28164            event: "pan",
28165            threshold: 10,
28166            pointers: 1,
28167            direction: Gb
28168        },
28169        getTouchAction: function() {
28170            var a = this.options.direction;
28171            if (a === Gb) {
28172                return [Xb];
28173            }
28174            var b = [];
28175            return a & Eb && b.push(Zb), a & Fb && b.push(Yb), b;
28176        },
28177        directionTest: function(a) {
28178            var b = this.options,
28179                c = !0,
28180                d = a.distance,
28181                e = a.direction,
28182                f = a.deltaX,
28183                g = a.deltaY;
28184            return e & b.direction || (b.direction & Eb ? (e = 0 === f ? zb : 0 > f ? Ab : Bb, c = f != this.pX, d = Math.abs(a.deltaX)) : (e = 0 === g ? zb : 0 > g ? Cb : Db, c = g != this.pY, d = Math.abs(a.deltaY))), a.direction = e, c && d > b.threshold && e & b.direction;
28185        },
28186        attrTest: function(a) {
28187            return W.prototype.attrTest.call(this, a) && (this.state & _b || !(this.state & _b) && this.directionTest(a));
28188        },
28189        emit: function(a) {
28190            this.pX = a.deltaX, this.pY = a.deltaY;
28191            var b = U(a.direction);
28192            b && this.manager.emit(this.options.event + b, a), this._super.emit.call(this, a);
28193        }
28194    }), j(Y, W, {
28195        defaults: {
28196            event: "pinch",
28197            threshold: 0,
28198            pointers: 2
28199        },
28200        getTouchAction: function() {
28201            return [Xb];
28202        },
28203        attrTest: function(a) {
28204            return this._super.attrTest.call(this, a) && (Math.abs(a.scale - 1) > this.options.threshold || this.state & _b);
28205        },
28206        emit: function(a) {
28207            if (this._super.emit.call(this, a), 1 !== a.scale) {
28208                var b = a.scale < 1 ? "in" : "out";
28209                this.manager.emit(this.options.event + b, a);
28210            }
28211        }
28212    }), j(Z, S, {
28213        defaults: {
28214            event: "press",
28215            pointers: 1,
28216            time: 500,
28217            threshold: 5
28218        },
28219        getTouchAction: function() {
28220            return [Vb];
28221        },
28222        process: function(a) {
28223            var b = this.options,
28224                c = a.pointers.length === b.pointers,
28225                d = a.distance < b.threshold,
28226                f = a.deltaTime > b.time;
28227            if (this._input = a, !d || !c || a.eventType & (xb | yb) && !f) {
28228                this.reset();
28229            } else {
28230                if (a.eventType & vb) {
28231                    this.reset(), this._timer = e(function() {
28232                        this.state = cc, this.tryEmit();
28233                    }, b.time, this);
28234                } else {
28235                    if (a.eventType & xb) {
28236                        return cc;
28237                    }
28238                }
28239            }
28240            return ec;
28241        },
28242        reset: function() {
28243            clearTimeout(this._timer);
28244        },
28245        emit: function(a) {
28246            this.state === cc && (a && a.eventType & xb ? this.manager.emit(this.options.event + "up", a) : (this._input.timeStamp = kb(), this.manager.emit(this.options.event, this._input)));
28247        }
28248    }), j($, W, {
28249        defaults: {
28250            event: "rotate",
28251            threshold: 0,
28252            pointers: 2
28253        },
28254        getTouchAction: function() {
28255            return [Xb];
28256        },
28257        attrTest: function(a) {
28258            return this._super.attrTest.call(this, a) && (Math.abs(a.rotation) > this.options.threshold || this.state & _b);
28259        }
28260    }), j(_, W, {
28261        defaults: {
28262            event: "swipe",
28263            threshold: 10,
28264            velocity: 0.65,
28265            direction: Eb | Fb,
28266            pointers: 1
28267        },
28268        getTouchAction: function() {
28269            return X.prototype.getTouchAction.call(this);
28270        },
28271        attrTest: function(a) {
28272            var b, c = this.options.direction;
28273            return c & (Eb | Fb) ? b = a.velocity : c & Eb ? b = a.velocityX : c & Fb && (b = a.velocityY), this._super.attrTest.call(this, a) && c & a.direction && jb(b) > this.options.velocity && a.eventType & xb;
28274        },
28275        emit: function(a) {
28276            var b = U(a.direction);
28277            b && this.manager.emit(this.options.event + b, a), this.manager.emit(this.options.event, a);
28278        }
28279    }), j(ab, S, {
28280        defaults: {
28281            event: "tap",
28282            pointers: 1,
28283            taps: 1,
28284            interval: 300,
28285            time: 250,
28286            threshold: 2,
28287            posThreshold: 10
28288        },
28289        getTouchAction: function() {
28290            return [Wb];
28291        },
28292        process: function(a) {
28293            var b = this.options,
28294                c = a.pointers.length === b.pointers,
28295                d = a.distance < b.threshold,
28296                f = a.deltaTime < b.time;
28297            if (this.reset(), a.eventType & vb && 0 === this.count) {
28298                return this.failTimeout();
28299            }
28300            if (d && f && c) {
28301                if (a.eventType != xb) {
28302                    return this.failTimeout();
28303                }
28304                var g = this.pTime ? a.timeStamp - this.pTime < b.interval : !0,
28305                    h = !this.pCenter || H(this.pCenter, a.center) < b.posThreshold;
28306                this.pTime = a.timeStamp, this.pCenter = a.center, h && g ? this.count += 1 : this.count = 1, this._input = a;
28307                var i = this.count % b.taps;
28308                if (0 === i) {
28309                    return this.hasRequireFailures() ? (this._timer = e(function() {
28310                        this.state = cc, this.tryEmit();
28311                    }, b.interval, this), _b) : cc;
28312                }
28313            }
28314            return ec;
28315        },
28316        failTimeout: function() {
28317            return this._timer = e(function() {
28318                this.state = ec;
28319            }, this.options.interval, this), ec;
28320        },
28321        reset: function() {
28322            clearTimeout(this._timer);
28323        },
28324        emit: function() {
28325            this.state == cc && (this._input.tapCount = this.count, this.manager.emit(this.options.event, this._input));
28326        }
28327    }), bb.VERSION = "2.0.2", bb.defaults = {
28328        domEvents: !1,
28329        touchAction: Ub,
28330        inputTarget: null,
28331        enable: !0,
28332        preset: [
28333            [$, {
28334                enable: !1
28335            }],
28336            [Y, {
28337                    enable: !1
28338                },
28339                ["rotate"]
28340            ],
28341            [_, {
28342                direction: Eb
28343            }],
28344            [X, {
28345                    direction: Eb
28346                },
28347                ["swipe"]
28348            ],
28349            [ab],
28350            [ab, {
28351                    event: "doubletap",
28352                    taps: 2
28353                },
28354                ["tap"]
28355            ],
28356            [Z]
28357        ],
28358        cssProps: {
28359            userSelect: "none",
28360            touchSelect: "none",
28361            touchCallout: "none",
28362            contentZooming: "none",
28363            userDrag: "none",
28364            tapHighlightColor: "rgba(0,0,0,0)"
28365        }
28366    };
28367    var fc = 1,
28368        gc = 2;
28369    cb.prototype = {
28370        set: function(a) {
28371            return h(this.options, a), this;
28372        },
28373        stop: function(a) {
28374            this.session.stopped = a ? gc : fc;
28375        },
28376        recognize: function(a) {
28377            var b = this.session;
28378            if (!b.stopped) {
28379                this.touchAction.preventDefaults(a);
28380                var c, d = this.recognizers,
28381                    e = b.curRecognizer;
28382                (!e || e && e.state & cc) && (e = b.curRecognizer = null);
28383                for (var f = 0, g = d.length; g > f; f++) {
28384                    c = d[f], b.stopped === gc || e && c != e && !c.canRecognizeWith(e) ? c.reset() : c.recognize(a), !e && c.state & (_b | ac | bc) && (e = b.curRecognizer = c);
28385                }
28386            }
28387        },
28388        get: function(a) {
28389            if (a instanceof S) {
28390                return a;
28391            }
28392            for (var b = this.recognizers, c = 0; c < b.length; c++) {
28393                if (b[c].options.event == a) {
28394                    return b[c];
28395                }
28396            }
28397            return null;
28398        },
28399        add: function(a) {
28400            if (f(a, "add", this)) {
28401                return this;
28402            }
28403            var b = this.get(a.options.event);
28404            return b && this.remove(b), this.recognizers.push(a), a.manager = this, this.touchAction.update(), a;
28405        },
28406        remove: function(a) {
28407            if (f(a, "remove", this)) {
28408                return this;
28409            }
28410            var b = this.recognizers;
28411            return a = this.get(a), b.splice(s(b, a), 1), this.touchAction.update(), this;
28412        },
28413        on: function(a, b) {
28414            var c = this.handlers;
28415            return g(r(a), function(a) {
28416                c[a] = c[a] || [], c[a].push(b);
28417            }), this;
28418        },
28419        off: function(a, b) {
28420            var c = this.handlers;
28421            return g(r(a), function(a) {
28422                b ? c[a].splice(s(c[a], b), 1) : delete c[a];
28423            }), this;
28424        },
28425        emit: function(a, b) {
28426            this.options.domEvents && eb(a, b);
28427            var c = this.handlers[a] && this.handlers[a].slice();
28428            if (c && c.length) {
28429                b.type = a, b.preventDefault = function() {
28430                    b.srcEvent.preventDefault();
28431                };
28432                for (var d = 0, e = c.length; e > d; d++) {
28433                    c[d](b);
28434                }
28435            }
28436        },
28437        destroy: function() {
28438            this.element && db(this, !1), this.handlers = {}, this.session = {}, this.input.destroy(), this.element = null;
28439        }
28440    }, h(bb, {
28441        INPUT_START: vb,
28442        INPUT_MOVE: wb,
28443        INPUT_END: xb,
28444        INPUT_CANCEL: yb,
28445        STATE_POSSIBLE: $b,
28446        STATE_BEGAN: _b,
28447        STATE_CHANGED: ac,
28448        STATE_ENDED: bc,
28449        STATE_RECOGNIZED: cc,
28450        STATE_CANCELLED: dc,
28451        STATE_FAILED: ec,
28452        DIRECTION_NONE: zb,
28453        DIRECTION_LEFT: Ab,
28454        DIRECTION_RIGHT: Bb,
28455        DIRECTION_UP: Cb,
28456        DIRECTION_DOWN: Db,
28457        DIRECTION_HORIZONTAL: Eb,
28458        DIRECTION_VERTICAL: Fb,
28459        DIRECTION_ALL: Gb,
28460        Manager: cb,
28461        Input: x,
28462        TouchAction: Q,
28463        Recognizer: S,
28464        AttrRecognizer: W,
28465        Tap: ab,
28466        Pan: X,
28467        Swipe: _,
28468        Pinch: Y,
28469        Rotate: $,
28470        Press: Z,
28471        on: n,
28472        off: o,
28473        each: g,
28474        merge: i,
28475        extend: h,
28476        inherit: j,
28477        bindFn: k,
28478        prefixed: v
28479    }), typeof define == hb && define.amd ? define(function() {
28480        return bb;
28481    }) : "undefined" != typeof module && module.exports ? module.exports = bb : a[c] = bb;
28482}(window, document, "Hammer");
28483   /* Ende hammer */
28484   /* Start jquery.hammer */
28485   (function($, Hammer, dataAttr) {
28486    function hammerify(el, options) {
28487        var $el = $(el);
28488        if(!$el.data(dataAttr)) {
28489            $el.data(dataAttr, new Hammer($el[0], options));
28490        }
28491    }
28492
28493    $.fn.hammer = function(options) {
28494        return this.each(function() {
28495            hammerify(this, options);
28496        });
28497    };
28498
28499    // extend the emit method to also trigger jQuery events
28500    Hammer.Manager.prototype.emit = (function(originalEmit) {
28501        return function(type, data) {
28502            originalEmit.call(this, type, data);
28503            jQuery(this.element).triggerHandler({
28504                type: type,
28505                gesture: data
28506            });
28507        };
28508    })(Hammer.Manager.prototype.emit);
28509})(jQuery, Hammer, "hammer");
28510   /* Ende jquery.hammer */
28511   /* Start jquery.mmenu */
28512   /*
28513 * jQuery mmenu v5.5.3
28514 * @requires jQuery 1.7.0 or later
28515 *
28516 * mmenu.frebsite.nl
28517 *  
28518 * Copyright (c) Fred Heusschen
28519 * www.frebsite.nl
28520 *
28521 * Licensed under the MIT license:
28522 * http://en.wikipedia.org/wiki/MIT_License
28523 */
28524
28525(function( $ ) {
28526
28527  var _PLUGIN_  = 'mmenu',
28528    _VERSION_  = '5.5.3';
28529
28530
28531  //  Plugin already excists
28532  if ( $[ _PLUGIN_ ] && $[ _PLUGIN_ ].version > _VERSION_ )
28533  {
28534    return;
28535  }
28536
28537
28538  /*
28539   Class
28540   */
28541  $[ _PLUGIN_ ] = function( $menu, opts, conf )
28542  {
28543    this.$menu  = $menu;
28544    this._api  = [ 'bind', 'init', 'update', 'setSelected', 'getInstance', 'openPanel', 'closePanel', 'closeAllPanels' ];
28545    this.opts  = opts;
28546    this.conf  = conf;
28547    this.vars  = {};
28548    this.cbck  = {};
28549
28550
28551    if ( typeof this.___deprecated == 'function' )
28552    {
28553      this.___deprecated();
28554    }
28555
28556    this._initMenu();
28557    this._initAnchors();
28558
28559    var $pnls = this.$pnls.children();
28560
28561    this._initAddons();
28562    this.init( $pnls );
28563
28564
28565    if ( typeof this.___debug == 'function' )
28566    {
28567      this.___debug();
28568    }
28569
28570    return this;
28571  };
28572
28573  $[ _PLUGIN_ ].version   = _VERSION_;
28574  $[ _PLUGIN_ ].addons   = {};
28575  $[ _PLUGIN_ ].uniqueId   = 0;
28576
28577
28578  $[ _PLUGIN_ ].defaults   = {
28579    extensions    : [],
28580    navbar       : {
28581      add       : true,
28582      title      : 'Menu',
28583      titleLink    : 'panel'
28584    },
28585    onClick      : {
28586//      close      : true,
28587//      preventDefault  : null,
28588      setSelected    : true
28589    },
28590    slidingSubmenus  : true
28591  };
28592
28593  $[ _PLUGIN_ ].configuration = {
28594    classNames      : {
28595      divider    : 'Divider',
28596      inset     : 'Inset',
28597      panel    : 'Panel',
28598      selected  : 'Selected',
28599      spacer    : 'Spacer',
28600      vertical  : 'Vertical'
28601    },
28602    clone        : false,
28603    openingInterval    : 25,
28604    panelNodetype    : 'ul, ol, div',
28605    transitionDuration  : 400
28606  };
28607
28608  $[ _PLUGIN_ ].prototype = {
28609
28610    init: function( $panels )
28611    {
28612      $panels = $panels.not( '.' + _c.nopanel );
28613      $panels = this._initPanels( $panels );
28614
28615      this.trigger( 'init', $panels );
28616      this.trigger( 'update' );
28617    },
28618
28619    update: function()
28620    {
28621      this.trigger( 'update' );
28622    },
28623
28624    setSelected: function( $li )
28625    {
28626      this.$menu.find( '.' + _c.listview ).children().removeClass( _c.selected );
28627      $li.addClass( _c.selected );
28628      this.trigger( 'setSelected', $li );
28629    },
28630
28631    openPanel: function( $panel )
28632    {
28633      var $l = $panel.parent();
28634
28635      //  Vertical
28636      if ( $l.hasClass( _c.vertical ) )
28637      {
28638        var $sub = $l.parents( '.' + _c.subopened );
28639        if ( $sub.length )
28640        {
28641          return this.openPanel( $sub.first() );
28642        }
28643        $l.addClass( _c.opened );
28644      }
28645
28646      //  Horizontal
28647      else
28648      {
28649        if ( $panel.hasClass( _c.current ) )
28650        {
28651          return;
28652        }
28653
28654        var $panels = this.$pnls.children( '.' + _c.panel ),
28655          $current = $panels.filter( '.' + _c.current );
28656
28657        $panels
28658          .removeClass( _c.highest )
28659          .removeClass( _c.current )
28660          .not( $panel )
28661          .not( $current )
28662          .not( '.' + _c.vertical )
28663          .addClass( _c.hidden );
28664
28665        if ( !$[ _PLUGIN_ ].support.csstransitions )
28666        {
28667          $current.addClass( _c.hidden );
28668        }
28669
28670        if ( $panel.hasClass( _c.opened ) )
28671        {
28672          $panel.nextAll( '.' + _c.opened )
28673            .addClass( _c.highest )
28674            .removeClass( _c.opened )
28675            .removeClass( _c.subopened );
28676        }
28677        else
28678        {
28679          $panel.addClass( _c.highest );
28680          $current.addClass( _c.subopened );
28681        }
28682
28683        $panel
28684          .removeClass( _c.hidden )
28685          .addClass( _c.current );
28686
28687        //  Without the timeout, the animation won't work because the element had display: none;
28688        setTimeout(
28689          function()
28690          {
28691            $panel
28692              .removeClass( _c.subopened )
28693              .addClass( _c.opened );
28694
28695          }, this.conf.openingInterval
28696        );
28697      }
28698      this.trigger( 'openPanel', $panel );
28699    },
28700
28701    closePanel: function( $panel )
28702    {
28703      var $l = $panel.parent();
28704
28705      //  Vertical only
28706      if ( $l.hasClass( _c.vertical ) )
28707      {
28708        $l.removeClass( _c.opened );
28709        this.trigger( 'closePanel', $panel );
28710      }
28711    },
28712
28713    closeAllPanels: function()
28714    {
28715      //  Vertical
28716      this.$menu.find( '.' + _c.listview )
28717        .children()
28718        .removeClass( _c.selected )
28719        .filter( '.' + _c.vertical )
28720        .removeClass( _c.opened );
28721
28722      //  Horizontal
28723      var $pnls = this.$pnls.children( '.' + _c.panel ),
28724        $frst = $pnls.first();
28725
28726      this.$pnls.children( '.' + _c.panel )
28727        .not( $frst )
28728        .removeClass( _c.subopened )
28729        .removeClass( _c.opened )
28730        .removeClass( _c.current )
28731        .removeClass( _c.highest )
28732        .addClass( _c.hidden );
28733
28734      this.openPanel( $frst );
28735    },
28736
28737    togglePanel: function( $panel )
28738    {
28739      var $l = $panel.parent();
28740
28741      //  Vertical only
28742      if ( $l.hasClass( _c.vertical ) )
28743      {
28744        this[ $l.hasClass( _c.opened ) ? 'closePanel' : 'openPanel' ]( $panel );
28745      }
28746    },
28747
28748    getInstance: function()
28749    {
28750      return this;
28751    },
28752
28753    bind: function( event, fn )
28754    {
28755      this.cbck[ event ] = this.cbck[ event ] || [];
28756      this.cbck[ event ].push( fn );
28757    },
28758
28759    trigger: function()
28760    {
28761      var that = this,
28762        args = Array.prototype.slice.call( arguments ),
28763        evnt = args.shift();
28764
28765      if ( this.cbck[ evnt ] )
28766      {
28767        for ( var e = 0, l = this.cbck[ evnt ].length; e < l; e++ )
28768        {
28769          this.cbck[ evnt ][ e ].apply( that, args );
28770        }
28771      }
28772    },
28773
28774    _initMenu: function()
28775    {
28776      var that = this;
28777
28778      //  Clone if needed
28779      if ( this.opts.offCanvas && this.conf.clone )
28780      {
28781        this.$menu = this.$menu.clone( true );
28782        this.$menu.add( this.$menu.find( '[id]' ) )
28783          .filter( '[id]' )
28784          .each(
28785          function()
28786          {
28787            $(this).attr( 'id', _c.mm( $(this).attr( 'id' ) ) );
28788          }
28789        );
28790      }
28791
28792      //  Strip whitespace
28793      this.$menu.contents().each(
28794        function()
28795        {
28796          if ( $(this)[ 0 ].nodeType == 3 )
28797          {
28798            $(this).remove();
28799          }
28800        }
28801      );
28802
28803      //  Add markup
28804      this.$pnls = $( '<div class="' + _c.panels + '" />' )
28805        .append( this.$menu.children( this.conf.panelNodetype ) )
28806        .prependTo( this.$menu );
28807
28808      //  Add classes
28809      this.$menu
28810        .parent()
28811        .addClass( _c.wrapper );
28812
28813      var clsn = [ _c.menu ];
28814
28815      //  Add direction class
28816      if ( !this.opts.slidingSubmenus )
28817      {
28818        clsn.push( _c.vertical );
28819      }
28820
28821      //  Add extensions classes
28822      this.opts.extensions = ( this.opts.extensions.length )
28823        ? 'mm-' + this.opts.extensions.join( ' mm-' )
28824        : '';
28825
28826      if ( this.opts.extensions )
28827      {
28828        clsn.push( this.opts.extensions );
28829      }
28830
28831      this.$menu.addClass( clsn.join( ' ' ) );
28832    },
28833
28834    _initPanels: function( $panels )
28835    {
28836      var that = this;
28837
28838      //  Add List class
28839      var $lists = this.__findAddBack( $panels, 'ul, ol' );
28840
28841      this.__refactorClass( $lists, this.conf.classNames.inset, 'inset' )
28842        .addClass( _c.nolistview + ' ' + _c.nopanel );
28843
28844      $lists.not( '.' + _c.nolistview )
28845        .addClass( _c.listview );
28846
28847      var $lis = this.__findAddBack( $panels, '.' + _c.listview ).children();
28848
28849      //  Refactor Selected class
28850      this.__refactorClass( $lis, this.conf.classNames.selected, 'selected' );
28851
28852      //  Refactor divider class
28853      this.__refactorClass( $lis, this.conf.classNames.divider, 'divider' );
28854
28855      //  Refactor Spacer class
28856      this.__refactorClass( $lis, this.conf.classNames.spacer, 'spacer' );
28857
28858      //  Refactor Panel class
28859      this.__refactorClass( this.__findAddBack( $panels, '.' + this.conf.classNames.panel ), this.conf.classNames.panel, 'panel' );
28860
28861      //  Create panels
28862      var $curpanels = $(),
28863        $oldpanels = $panels
28864          .add( $panels.find( '.' + _c.panel ) )
28865          .add( this.__findAddBack( $panels, '.' + _c.listview ).children().children( this.conf.panelNodetype ) )
28866          .not( '.' + _c.nopanel );
28867
28868      this.__refactorClass( $oldpanels, this.conf.classNames.vertical, 'vertical' );
28869
28870      if ( !this.opts.slidingSubmenus )
28871      {
28872        $oldpanels.addClass( _c.vertical );
28873      }
28874
28875      $oldpanels
28876        .each(
28877        function()
28878        {
28879          var $t = $(this),
28880            $p = $t;
28881
28882          if ( $t.is( 'ul, ol' ) )
28883          {
28884            $t.wrap( '<div class="' + _c.panel + '" />' );
28885            $p = $t.parent();
28886          }
28887          else
28888          {
28889            $p.addClass( _c.panel );
28890          }
28891
28892          var id = $t.attr( 'id' );
28893          $t.removeAttr( 'id' );
28894          $p.attr( 'id', id || that.__getUniqueId() );
28895
28896          if ( $t.hasClass( _c.vertical ) )
28897          {
28898            $t.removeClass( that.conf.classNames.vertical );
28899            $p.add( $p.parent() ).addClass( _c.vertical );
28900          }
28901
28902          $curpanels = $curpanels.add( $p );
28903        }
28904      );
28905
28906      var $allpanels = $('.' + _c.panel, this.$menu);
28907
28908      //  Add open and close links to menu items
28909      $curpanels
28910        .each(
28911        function( i )
28912        {
28913          var $t = $(this),
28914            $p = $t.parent(),
28915            $a = $p.children( 'a, span' ).first();
28916
28917          if ( !$p.is( '.' + _c.panels ) )
28918          {
28919            $p.data( _d.sub, $t );
28920            $t.data( _d.parent, $p );
28921          }
28922
28923          //  Open link
28924          if ( !$p.children( '.' + _c.next ).length )
28925          {
28926            if ( $p.parent().is( '.' + _c.listview ) )
28927            {
28928              var id = $t.attr( 'id' ),
28929                $b = $( '<a class="' + _c.next + '" href="#' + id + '" data-target="#' + id + '" />' ).insertBefore( $a );
28930
28931              if ( $a.is( 'span' ) )
28932              {
28933                $b.addClass( _c.fullsubopen );
28934              }
28935            }
28936          }
28937
28938          //  Navbar
28939          if ( !$t.children( '.' + _c.navbar ).length )
28940          {
28941            if ( !$p.hasClass( _c.vertical ) )
28942            {
28943              if ( $p.parent().is( '.' + _c.listview ) )
28944              {
28945                //  Listview, the panel wrapping this panel
28946                var $p = $p.closest( '.' + _c.panel );
28947              }
28948              else
28949              {
28950                //  Non-listview, the first panel that has an anchor that links to this panel
28951                var $a = $p.closest( '.' + _c.panel ).find( 'a[href="#' + $t.attr( 'id' ) + '"]' ).first(),
28952                  $p = $a.closest( '.' + _c.panel );
28953              }
28954
28955              var $navbar = $( '<div class="' + _c.navbar + '" />' );
28956
28957              if ( $p.length )
28958              {
28959                var id = $p.attr( 'id' );
28960                switch ( that.opts.navbar.titleLink )
28961                {
28962                  case 'anchor':
28963                    _url = $a.attr( 'href' );
28964                    break;
28965
28966                  case 'panel':
28967                  case 'parent':
28968                    _url = '#' + id;
28969                    break;
28970
28971                  case 'none':
28972                  default:
28973                    _url = false;
28974                    break;
28975                }
28976
28977                $navbar
28978                  .append( '<a class="' + _c.btn + ' ' + _c.prev + '" href="#' + id + '" data-target="#' + id + '" />' )
28979                  .append( $('<a class="' + _c.title + '"' + ( _url ? ' href="' + _url + '"' : '' ) + ' />').text( $a.text() ) )
28980                  .prependTo( $t );
28981
28982                if ( that.opts.navbar.add )
28983                {
28984                  $t.addClass( _c.hasnavbar );
28985                }
28986              }
28987              else if ( that.opts.navbar.title )
28988              {
28989                $navbar
28990                  .append( '<a class="' + _c.title + '">' + that.opts.navbar.title + '</a>' )
28991                  .prependTo( $t );
28992
28993                if ( that.opts.navbar.add )
28994                {
28995                  $t.addClass( _c.hasnavbar );
28996                }
28997              }
28998            }
28999          }
29000        }
29001      );
29002
29003
29004      //  Add opened-classes to parents
29005      var $s = this.__findAddBack( $panels, '.' + _c.listview )
29006        .children( '.' + _c.selected )
29007        .removeClass( _c.selected )
29008        .last()
29009        .addClass( _c.selected );
29010
29011      $s.add( $s.parentsUntil( '.' + _c.menu, 'li' ) )
29012        .filter( '.' + _c.vertical )
29013        .addClass( _c.opened )
29014        .end()
29015        .not( '.' + _c.vertical )
29016        .each(
29017        function()
29018        {
29019          $(this).parentsUntil( '.' + _c.menu, '.' + _c.panel )
29020            .not( '.' + _c.vertical )
29021            .first()
29022            .addClass( _c.opened )
29023            .parentsUntil( '.' + _c.menu, '.' + _c.panel )
29024            .not( '.' + _c.vertical )
29025            .first()
29026            .addClass( _c.opened )
29027            .addClass( _c.subopened );
29028        }
29029      );
29030
29031
29032      //  Add opened-classes to child
29033      $s.children( '.' + _c.panel )
29034        .not( '.' + _c.vertical )
29035        .addClass( _c.opened )
29036        .parentsUntil( '.' + _c.menu, '.' + _c.panel )
29037        .not( '.' + _c.vertical )
29038        .first()
29039        .addClass( _c.opened )
29040        .addClass( _c.subopened );
29041
29042
29043      //  Set current opened
29044      var $current = $allpanels.filter( '.' + _c.opened );
29045      if ( !$current.length )
29046      {
29047        $current = $curpanels.first();
29048      }
29049      $current
29050        .addClass( _c.opened )
29051        .last()
29052        .addClass( _c.current );
29053
29054
29055      //  Rearrange markup
29056      $curpanels
29057        .not( '.' + _c.vertical )
29058        .not( $current.last() )
29059        .addClass( _c.hidden )
29060        .end()
29061        .appendTo( this.$pnls );
29062
29063      return $curpanels;
29064    },
29065
29066    _initAnchors: function()
29067    {
29068      var that = this;
29069
29070      glbl.$body
29071        .on( _e.click + '-oncanvas',
29072        'a[href]',
29073        function( e )
29074        {
29075          var $t = $(this),
29076            fired   = false,
29077            inMenu   = that.$menu.find( $t ).length;
29078
29079          //  Find behavior for addons
29080          for ( var a in $[ _PLUGIN_ ].addons )
29081          {
29082            if ( fired = $[ _PLUGIN_ ].addons[ a ].clickAnchor.call( that, $t, inMenu ) )
29083            {
29084              break;
29085            }
29086          }
29087
29088          //  Open/Close panel
29089          if ( !fired && inMenu )
29090          {
29091            var _h = $t.attr( 'href' );
29092            if ( _h.length > 1 && _h.slice( 0, 1 ) == '#' )
29093            {
29094              try
29095              {
29096                var $h = $(_h, that.$menu);
29097                if ( $h.is( '.' + _c.panel ) )
29098                {
29099                  fired = true;
29100                  that[ $t.parent().hasClass( _c.vertical ) ? 'togglePanel' : 'openPanel' ]( $h );
29101                }
29102              }
29103              catch( err ) {}
29104            }
29105          }
29106
29107          if ( fired )
29108          {
29109            e.preventDefault();
29110          }
29111
29112
29113          //  All other anchors in lists
29114          if ( !fired && inMenu )
29115          {
29116            if ( $t.is( '.' + _c.listview + ' > li > a' )
29117              && !$t.is( '[rel="external"]' )
29118              && !$t.is( '[target="_blank"]' ) )
29119            {
29120
29121              //  Set selected item
29122              if ( that.__valueOrFn( that.opts.onClick.setSelected, $t ) )
29123              {
29124                that.setSelected( $(e.target).parent() );
29125              }
29126
29127              //  Prevent default / don't follow link. Default: false
29128              var preventDefault = that.__valueOrFn( that.opts.onClick.preventDefault, $t, _h.slice( 0, 1 ) == '#' );
29129              if ( preventDefault )
29130              {
29131                e.preventDefault();
29132              }
29133
29134              //  Close menu. Default: true if preventDefault, false otherwise
29135              if ( that.__valueOrFn( that.opts.onClick.close, $t, preventDefault ) )
29136              {
29137                that.close();
29138              }
29139            }
29140          }
29141        }
29142      );
29143    },
29144
29145    _initAddons: function()
29146    {
29147      //  Add add-ons to plugin
29148      for ( var a in $[ _PLUGIN_ ].addons )
29149      {
29150        $[ _PLUGIN_ ].addons[ a ].add.call( this );
29151        $[ _PLUGIN_ ].addons[ a ].add = function() {};
29152      }
29153
29154      //  Setup adds-on for menu
29155      for ( var a in $[ _PLUGIN_ ].addons )
29156      {
29157        $[ _PLUGIN_ ].addons[ a ].setup.call( this );
29158      }
29159    },
29160
29161    __api: function()
29162    {
29163      var that = this,
29164        api = {};
29165
29166      $.each( this._api,
29167        function( i )
29168        {
29169          var fn = this;
29170          api[ fn ] = function()
29171          {
29172            var re = that[ fn ].apply( that, arguments );
29173            return ( typeof re == 'undefined' ) ? api : re;
29174          }
29175        }
29176      );
29177      return api;
29178    },
29179
29180    __valueOrFn: function( o, $e, d )
29181    {
29182      if ( typeof o == 'function' )
29183      {
29184        return o.call( $e[ 0 ] );
29185      }
29186      if ( typeof o == 'undefined' && typeof d != 'undefined' )
29187      {
29188        return d;
29189      }
29190      return o;
29191    },
29192
29193    __refactorClass: function( $e, o, c )
29194    {
29195      return $e.filter( '.' + o ).removeClass( o ).addClass( _c[ c ] );
29196    },
29197
29198    __findAddBack: function( $e, s )
29199    {
29200      return $e.find( s ).add( $e.filter( s ) );
29201    },
29202
29203    __filterListItems: function( $i )
29204    {
29205      return $i
29206        .not( '.' + _c.divider )
29207        .not( '.' + _c.hidden );
29208    },
29209
29210    __transitionend: function( $e, fn, duration )
29211    {
29212      var _ended = false,
29213        _fn = function()
29214        {
29215          if ( !_ended )
29216          {
29217            fn.call( $e[ 0 ] );
29218          }
29219          _ended = true;
29220        };
29221
29222      $e.one( _e.transitionend, _fn );
29223      $e.one( _e.webkitTransitionEnd, _fn );
29224      setTimeout( _fn, duration * 1.1 );
29225    },
29226
29227    __getUniqueId: function()
29228    {
29229      return _c.mm( $[ _PLUGIN_ ].uniqueId++ );
29230    }
29231  };
29232
29233
29234  /*
29235   jQuery plugin
29236   */
29237  $.fn[ _PLUGIN_ ] = function( opts, conf )
29238  {
29239    //  First time plugin is fired
29240    initPlugin();
29241
29242    //  Extend options
29243    opts = $.extend( true, {}, $[ _PLUGIN_ ].defaults, opts );
29244    conf = $.extend( true, {}, $[ _PLUGIN_ ].configuration, conf );
29245
29246    return this.each(
29247      function()
29248      {
29249        var $menu = $(this);
29250        if ( $menu.data( _PLUGIN_ ) )
29251        {
29252          return;
29253        }
29254        var _menu = new $[ _PLUGIN_ ]( $menu, opts, conf );
29255        $menu.data( _PLUGIN_, _menu.__api() );
29256      }
29257    );
29258  };
29259
29260
29261  /*
29262   SUPPORT
29263   */
29264  $[ _PLUGIN_ ].support = {
29265    touch: 'ontouchstart' in window || navigator.msMaxTouchPoints,
29266    csstransitions: (function()
29267    {
29268      //  Use Modernizr test
29269      if ( typeof Modernizr !== 'undefined' &&
29270        typeof Modernizr.csstransitions !== 'undefined'
29271        ) {
29272        return Modernizr.csstransitions;
29273      }
29274
29275      var b = document.body || document.documentElement,
29276        s = b.style,
29277        p = 'transition';
29278
29279      //  Default support
29280      if ( typeof s[ p ] == 'string' )
29281      {
29282        return true;
29283      }
29284
29285      //  Vendor specific support
29286      var v = [ 'Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms' ];
29287      p = p.charAt( 0 ).toUpperCase() + p.substr( 1 );
29288
29289      for ( var i = 0; i < v.length; i++ )
29290      {
29291        if ( typeof s[ v[ i ] + p ] == 'string' )
29292        {
29293          return true;
29294        }
29295      }
29296
29297      //  No support
29298      return false;
29299    })()
29300  };
29301
29302
29303  //  Global variables
29304  var _c, _d, _e, glbl;
29305
29306  function initPlugin()
29307  {
29308    if ( $[ _PLUGIN_ ].glbl )
29309    {
29310      return;
29311    }
29312
29313    glbl = {
29314      $wndw : $(window),
29315      $html : $('html'),
29316      $body : $('body')
29317    };
29318
29319
29320    //  Classnames, Datanames, Eventnames
29321    _c = {};
29322    _d = {};
29323    _e = {};
29324    $.each( [ _c, _d, _e ],
29325      function( i, o )
29326      {
29327        o.add = function( a )
29328        {
29329          a = a.split( ' ' );
29330          for ( var b = 0, l = a.length; b < l; b++ )
29331          {
29332            o[ a[ b ] ] = o.mm( a[ b ] );
29333          }
29334        };
29335      }
29336    );
29337
29338    //  Classnames
29339    _c.mm = function( c ) { return 'mm-' + c; };
29340    _c.add( 'wrapper menu panels panel nopanel current highest opened subopened navbar hasnavbar title btn prev next listview nolistview inset vertical selected divider spacer hidden fullsubopen' );
29341    _c.umm = function( c )
29342    {
29343      if ( c.slice( 0, 3 ) == 'mm-' )
29344      {
29345        c = c.slice( 3 );
29346      }
29347      return c;
29348    };
29349
29350    //  Datanames
29351    _d.mm = function( d ) { return 'mm-' + d; };
29352    _d.add( 'parent sub' );
29353
29354    //  Eventnames
29355    _e.mm = function( e ) { return e + '.mm'; };
29356    _e.add( 'transitionend webkitTransitionEnd mousedown mouseup touchstart touchmove touchend click keydown' );
29357
29358    $[ _PLUGIN_ ]._c = _c;
29359    $[ _PLUGIN_ ]._d = _d;
29360    $[ _PLUGIN_ ]._e = _e;
29361
29362    $[ _PLUGIN_ ].glbl = glbl;
29363  }
29364
29365
29366})( jQuery );
29367
29368
29369/*
29370 * jQuery mmenu offCanvas addon
29371 * mmenu.frebsite.nl
29372 *
29373 * Copyright (c) Fred Heusschen
29374 */
29375
29376(function( $ ) {
29377
29378  var _PLUGIN_ = 'mmenu',
29379    _ADDON_  = 'offCanvas';
29380
29381
29382  $[ _PLUGIN_ ].addons[ _ADDON_ ] = {
29383
29384    //  setup: fired once per menu
29385    setup: function()
29386    {
29387      if ( !this.opts[ _ADDON_ ] )
29388      {
29389        return;
29390      }
29391
29392      var that = this,
29393        opts = this.opts[ _ADDON_ ],
29394        conf = this.conf[ _ADDON_ ];
29395
29396      glbl = $[ _PLUGIN_ ].glbl;
29397
29398
29399      //  Add methods to api
29400      this._api = $.merge( this._api, [ 'open', 'close', 'setPage' ] );
29401
29402
29403      //  Debug positioning
29404      if ( opts.position == 'top' || opts.position == 'bottom' )
29405      {
29406        opts.zposition = 'front';
29407      }
29408
29409
29410      //  Extend configuration
29411      if ( typeof conf.pageSelector != 'string' )
29412      {
29413        conf.pageSelector = '> ' + conf.pageNodetype;
29414      }
29415
29416
29417      glbl.$allMenus = ( glbl.$allMenus || $() ).add( this.$menu );
29418
29419
29420      //  Setup the menu
29421      this.vars.opened = false;
29422
29423      var clsn = [ _c.offcanvas ];
29424
29425      if ( opts.position != 'left' )
29426      {
29427        clsn.push( _c.mm( opts.position ) );
29428      }
29429      if ( opts.zposition != 'back' )
29430      {
29431        clsn.push( _c.mm( opts.zposition ) );
29432      }
29433
29434      this.$menu
29435        .addClass( clsn.join( ' ' ) )
29436        .parent()
29437        .removeClass( _c.wrapper );
29438
29439
29440      //  Setup the page
29441      this.setPage( glbl.$page );
29442
29443
29444      //  Setup the UI blocker and the window
29445      this._initBlocker();
29446      this[ '_initWindow_' + _ADDON_ ]();
29447
29448
29449      //  Append to the body
29450      this.$menu[ conf.menuInjectMethod + 'To' ]( conf.menuWrapperSelector );
29451    },
29452
29453    //  add: fired once per page load
29454    add: function()
29455    {
29456      _c = $[ _PLUGIN_ ]._c;
29457      _d = $[ _PLUGIN_ ]._d;
29458      _e = $[ _PLUGIN_ ]._e;
29459
29460      _c.add( 'offcanvas slideout blocking modal background opening blocker page' );
29461      _d.add( 'style' );
29462      _e.add( 'resize' );
29463    },
29464
29465    //  clickAnchor: prevents default behavior when clicking an anchor
29466    clickAnchor: function( $a, inMenu )
29467    {
29468      if ( !this.opts[ _ADDON_ ] )
29469      {
29470        return false;
29471      }
29472
29473      //  Open menu
29474      var id = this.$menu.attr( 'id' );
29475      if ( id && id.length )
29476      {
29477        if ( this.conf.clone )
29478        {
29479          id = _c.umm( id );
29480        }
29481        if ( $a.is( '[href="#' + id + '"]' ) )
29482        {
29483          this.open();
29484          return true;
29485        }
29486      }
29487
29488      //  Close menu
29489      if ( !glbl.$page )
29490      {
29491        return;
29492      }
29493      var id = glbl.$page.first().attr( 'id' );
29494      if ( id && id.length )
29495      {
29496        if ( $a.is( '[href="#' + id + '"]' ) )
29497        {
29498          this.close();
29499          return true;
29500        }
29501      }
29502
29503      return false;
29504    }
29505  };
29506
29507
29508  //  Default options and configuration
29509  $[ _PLUGIN_ ].defaults[ _ADDON_ ] = {
29510    position    : 'left',
29511    zposition    : 'back',
29512    blockUI      : true, // 'modal'
29513    moveBackground  : true
29514  };
29515  $[ _PLUGIN_ ].configuration[ _ADDON_ ] = {
29516    pageNodetype    : 'div',
29517    pageSelector    : null,
29518    noPageSelector    : [],
29519    wrapPageIfNeeded  : true,
29520    menuWrapperSelector  : 'body',
29521    menuInjectMethod  : 'prepend'
29522  };
29523
29524
29525  //  Methods
29526  $[ _PLUGIN_ ].prototype.open = function()
29527  {
29528    if ( this.vars.opened )
29529    {
29530      return;
29531    }
29532
29533    var that = this;
29534
29535    this._openSetup();
29536
29537    //  Without the timeout, the animation won't work because the menu had display: none;
29538    setTimeout(
29539      function()
29540      {
29541        that._openFinish();
29542      }, this.conf.openingInterval
29543    );
29544    this.trigger( 'open' );
29545  };
29546
29547  $[ _PLUGIN_ ].prototype._openSetup = function()
29548  {
29549    var that = this,
29550      opts = this.opts[ _ADDON_ ];
29551
29552    //  Close other menus
29553    this.closeAllOthers();
29554
29555    //  Store style and position
29556    glbl.$page.each(
29557      function()
29558      {
29559        $(this).data( _d.style, $(this).attr( 'style' ) || '' );
29560      }
29561    );
29562
29563    //  Trigger window-resize to measure height
29564    glbl.$wndw.trigger( _e.resize + '-' + _ADDON_, [ true ] );
29565
29566    var clsn = [ _c.opened ];
29567
29568    //  Add options
29569    if ( opts.blockUI )
29570    {
29571      clsn.push( _c.blocking );
29572    }
29573    if ( opts.blockUI == 'modal' )
29574    {
29575      clsn.push( _c.modal );
29576    }
29577    if ( opts.moveBackground )
29578    {
29579      clsn.push( _c.background );
29580    }
29581    if ( opts.position != 'left' )
29582    {
29583      clsn.push( _c.mm( this.opts[ _ADDON_ ].position ) );
29584    }
29585    if ( opts.zposition != 'back' )
29586    {
29587      clsn.push( _c.mm( this.opts[ _ADDON_ ].zposition ) );
29588    }
29589    if ( this.opts.extensions )
29590    {
29591      clsn.push( this.opts.extensions );
29592    }
29593    glbl.$html.addClass( clsn.join( ' ' ) );
29594
29595    //  Open
29596    setTimeout(function(){
29597      that.vars.opened = true;
29598    },this.conf.openingInterval);
29599
29600    this.$menu.addClass( _c.current + ' ' + _c.opened );
29601  };
29602
29603  $[ _PLUGIN_ ].prototype._openFinish = function()
29604  {
29605    var that = this;
29606
29607    //  Callback
29608    this.__transitionend( glbl.$page.first(),
29609      function()
29610      {
29611        that.trigger( 'opened' );
29612      }, this.conf.transitionDuration
29613    );
29614
29615    //  Opening
29616    glbl.$html.addClass( _c.opening );
29617    this.trigger( 'opening' );
29618  };
29619
29620  $[ _PLUGIN_ ].prototype.close = function()
29621  {
29622    if ( !this.vars.opened )
29623    {
29624      return;
29625    }
29626
29627    var that = this;
29628
29629    //  Callback
29630    this.__transitionend( glbl.$page.first(),
29631      function()
29632      {
29633        that.$menu
29634          .removeClass( _c.current )
29635          .removeClass( _c.opened );
29636
29637        glbl.$html
29638          .removeClass( _c.opened )
29639          .removeClass( _c.blocking )
29640          .removeClass( _c.modal )
29641          .removeClass( _c.background )
29642          .removeClass( _c.mm( that.opts[ _ADDON_ ].position ) )
29643          .removeClass( _c.mm( that.opts[ _ADDON_ ].zposition ) );
29644
29645        if ( that.opts.extensions )
29646        {
29647          glbl.$html.removeClass( that.opts.extensions );
29648        }
29649
29650        //  Restore style and position
29651        glbl.$page.each(
29652          function()
29653          {
29654            $(this).attr( 'style', $(this).data( _d.style ) );
29655          }
29656        );
29657
29658        that.vars.opened = false;
29659        that.trigger( 'closed' );
29660
29661      }, this.conf.transitionDuration
29662    );
29663
29664    //  Closing
29665    glbl.$html.removeClass( _c.opening );
29666    this.trigger( 'close' );
29667    this.trigger( 'closing' );
29668  };
29669
29670  $[ _PLUGIN_ ].prototype.closeAllOthers = function()
29671  {
29672    glbl.$allMenus
29673      .not( this.$menu )
29674      .each(
29675      function()
29676      {
29677        var api = $(this).data( _PLUGIN_ );
29678        if ( api && api.close )
29679        {
29680          api.close();
29681        }
29682      }
29683    );
29684  }
29685
29686  $[ _PLUGIN_ ].prototype.setPage = function( $page )
29687  {
29688    var that = this,
29689      conf = this.conf[ _ADDON_ ];
29690
29691    if ( !$page || !$page.length )
29692    {
29693      $page = glbl.$body.find( conf.pageSelector );
29694
29695      if ( conf.noPageSelector.length )
29696      {
29697        $page = $page.not( conf.noPageSelector.join( ', ' ) );
29698      }
29699      if ( $page.length > 1 && conf.wrapPageIfNeeded )
29700      {
29701        $page = $page
29702          .wrapAll( '<' + this.conf[ _ADDON_ ].pageNodetype + ' />' )
29703          .parent();
29704      }
29705    }
29706
29707    $page.each(
29708      function()
29709      {
29710        $(this).attr( 'id', $(this).attr( 'id' ) || that.__getUniqueId() );
29711      }
29712    );
29713    $page.addClass( _c.page + ' ' + _c.slideout );
29714    glbl.$page = $page;
29715
29716    this.trigger( 'setPage', $page );
29717  };
29718
29719  $[ _PLUGIN_ ].prototype[ '_initWindow_' + _ADDON_ ] = function()
29720  {
29721    //  Prevent tabbing
29722    glbl.$wndw
29723      .off( _e.keydown + '-' + _ADDON_ )
29724      .on(  _e.keydown + '-' + _ADDON_,
29725      function( e )
29726      {
29727        if ( glbl.$html.hasClass( _c.opened ) )
29728        {
29729          if ( e.keyCode == 9 )
29730          {
29731            e.preventDefault();
29732            return false;
29733          }
29734        }
29735      }
29736    );
29737
29738    //  Set page min-height to window height
29739    var _h = 0;
29740    glbl.$wndw
29741      .off( _e.resize + '-' + _ADDON_ )
29742      .on(  _e.resize + '-' + _ADDON_,
29743      function( e, force )
29744      {
29745        if ( glbl.$page.length == 1 )
29746        {
29747          if ( force || glbl.$html.hasClass( _c.opened ) )
29748          {
29749            var nh = glbl.$wndw.height();
29750            if ( force || nh != _h )
29751            {
29752              _h = nh;
29753              glbl.$page.css( 'minHeight', nh );
29754            }
29755          }
29756        }
29757      }
29758    );
29759  };
29760
29761  $[ _PLUGIN_ ].prototype._initBlocker = function()
29762  {
29763    var that = this;
29764
29765    if ( !this.opts[ _ADDON_ ].blockUI )
29766    {
29767      return;
29768    }
29769
29770    if ( !glbl.$blck )
29771    {
29772      glbl.$blck = $( '<div id="' + _c.blocker + '" class="' + _c.slideout + '" />' );
29773    }
29774
29775    glbl.$blck
29776      .appendTo( glbl.$body )
29777      .off( _e.touchstart + '-' + _ADDON_ + ' ' + _e.touchmove + '-' + _ADDON_ )
29778      .on(  _e.touchstart + '-' + _ADDON_ + ' ' + _e.touchmove + '-' + _ADDON_,
29779      function( e )
29780      {
29781        e.preventDefault();
29782        e.stopPropagation();
29783        glbl.$blck.trigger( _e.mousedown + '-' + _ADDON_ );
29784      }
29785    )
29786      .off( _e.mousedown + '-' + _ADDON_ )
29787      .on(  _e.mousedown + '-' + _ADDON_,
29788      function( e )
29789      {
29790        e.preventDefault();
29791        if ( !glbl.$html.hasClass( _c.modal ) )
29792        {
29793          that.closeAllOthers();
29794          that.close();
29795        }
29796      }
29797    );
29798  };
29799
29800
29801  var _c, _d, _e, glbl;
29802
29803})( jQuery );
29804   /* Ende jquery.mmenu */
29805   /* Start jquery.mmenu.searchfield */
29806   (function($){var _PLUGIN_="mmenu",_ADDON_="searchfield";$[_PLUGIN_].addons[_ADDON_]={setup:function(){var that=this,opts=this.opts[_ADDON_],conf=this.conf[_ADDON_];glbl=$[_PLUGIN_].glbl;if(typeof opts=="boolean"){opts={add:opts};}if(typeof opts!="object"){opts={};}opts=this.opts[_ADDON_]=$.extend(true,{},$[_PLUGIN_].defaults[_ADDON_],opts);this.bind("close",function(){this.$menu.find("."+_c.search).find("input").blur();});this.bind("init",function($panels){if(opts.add){switch(opts.addTo){case"panels":var $wrapper=$panels;break;default:var $wrapper=$(opts.addTo,this.$menu);break;}$wrapper.each(function(){var $panl=$(this);if($panl.is("."+_c.panel)&&$panl.is("."+_c.vertical)){return;}if(!$panl.children("."+_c.search).length){var _srch=(conf.form)?"form":"div";var $srch=$("<"+_srch+' class="'+_c.search+'" />');if(conf.form&&typeof conf.form=="object"){for(var f in conf.form){$srch.attr(f,conf.form[f]);}}$srch.append('<input placeholder="'+opts.placeholder+'" type="text" autocomplete="off" />');if($panl.hasClass(_c.search)){$panl.replaceWith($srch);}else{$panl.prepend($srch).addClass(_c.hassearch);}}if(opts.noResults){var inPanel=$panl.closest("."+_c.panel).length;if(!inPanel){$panl=that.$pnls.children("."+_c.panel).first();}if(!$panl.children("."+_c.noresultsmsg).length){var $lst=$panl.children("."+_c.listview).first();$('<div class="'+_c.noresultsmsg+'" />').append(opts.noResults)[$lst.length?"insertAfter":"prependTo"]($lst.length?$lst:$panl);}}});if(opts.search){$("."+_c.search,this.$menu).each(function(){var $srch=$(this),inPanel=$srch.closest("."+_c.panel).length;if(inPanel){var $pnls=$srch.closest("."+_c.panel),$panl=$pnls;}else{var $pnls=$("."+_c.panel,that.$menu),$panl=that.$menu;}var $inpt=$srch.children("input"),$itms=that.__findAddBack($pnls,"."+_c.listview).children("li"),$dvdr=$itms.filter("."+_c.divider),$rslt=that.__filterListItems($itms);var _anchor="> a",_both=_anchor+", > span";var search=function(){var query=$inpt.val().toLowerCase();$pnls.scrollTop(0);$rslt.add($dvdr).addClass(_c.hidden).find("."+_c.fullsubopensearch).removeClass(_c.fullsubopen).removeClass(_c.fullsubopensearch);$rslt.each(function(){var $item=$(this),_search=_anchor;if(opts.showTextItems||(opts.showSubPanels&&$item.find("."+_c.next))){_search=_both;}if($(_search,$item).text().toLowerCase().indexOf(query)>-1){$item.add($item.prevAll("."+_c.divider).first()).removeClass(_c.hidden);}});if(opts.showSubPanels){$pnls.each(function(i){var $panl=$(this);that.__filterListItems($panl.find("."+_c.listview).children()).each(function(){var $li=$(this),$su=$li.data(_d.sub);$li.removeClass(_c.nosubresults);if($su){$su.find("."+_c.listview).children().removeClass(_c.hidden);}});});}$($pnls.get().reverse()).each(function(i){var $panl=$(this),$prnt=$panl.data(_d.parent);if($prnt){if(that.__filterListItems($panl.find("."+_c.listview).children()).length){if($prnt.hasClass(_c.hidden)){$prnt.children("."+_c.next).not("."+_c.fullsubopen).addClass(_c.fullsubopen).addClass(_c.fullsubopensearch);}$prnt.removeClass(_c.hidden).removeClass(_c.nosubresults).prevAll("."+_c.divider).first().removeClass(_c.hidden);}else{if(!inPanel){if($panl.hasClass(_c.opened)){setTimeout(function(){that.openPanel
29806($prnt.closest("."+_c.panel));},(i+1)*(that.conf.openingInterval*1.5));}$prnt.addClass(_c.nosubresults);}}}});$panl[$rslt.not("."+_c.hidden).length?"removeClass":"addClass"](_c.noresults);this.update();};$inpt.off(_e.keyup+"-searchfield "+_e.change+"-searchfield").on(_e.keyup+"-searchfield",function(e){if(!preventKeypressSearch(e.keyCode)){search.call(that);}}).on(_e.change+"-searchfield",function(e){search.call(that);});});}}});},add:function(){_c=$[_PLUGIN_]._c;_d=$[_PLUGIN_]._d;_e=$[_PLUGIN_]._e;_c.add("search hassearch noresultsmsg noresults nosubresults fullsubopensearch");_e.add("change keyup");},clickAnchor:function($a,inMenu){}};$[_PLUGIN_].defaults[_ADDON_]={add:false,addTo:"panels",search:true,placeholder:"Search",noResults:"No results found.",showTextItems:false,showSubPanels:true};$[_PLUGIN_].configuration[_ADDON_]={form:false};var _c,_d,_e,glbl;function preventKeypressSearch(c){switch(c){case 9:case 16:case 17:case 18:case 37:case 38:case 39:case 40:return true;}return false;}})(jQuery);
29807
29808   /* Ende jquery.mmenu.searchfield */
29809   /* Start jquery.mmenu.navbars */
29810   /* 
29811 * jQuery mmenu navbar addon
29812 * mmenu.frebsite.nl
29813 *
29814 * Copyright (c) Fred Heusschen
29815 */
29816!function(n){var a="mmenu",t="navbars";n[a].addons[t]={setup:function(){var r=this,s=this.opts[t],c=this.conf[t];if(i=n[a].glbl,"undefined"!=typeof s){s instanceof Array||(s=[s]);var d={};n.each(s,function(i){var o=s[i];"boolean"==typeof o&&o&&(o={}),"object"!=typeof o&&(o={}),"undefined"==typeof o.content&&(o.content=["prev","title"]),o.content instanceof Array||(o.content=[o.content]),o=n.extend(!0,{},r.opts.navbar,o);var l=o.position,h=o.height;"number"!=typeof h&&(h=1),h=Math.min(4,Math.max(1,h)),"bottom"!=l&&(l="top"),d[l]||(d[l]=0),d[l]++;var f=n("<div />").addClass(e.navbar+" "+e.navbar+"-"+l+" "+e.navbar+"-"+l+"-"+d[l]+" "+e.navbar+"-size-"+h);d[l]+=h-1;for(var v=0,p=o.content.length;p>v;v++){var u=n[a].addons[t][o.content[v]]||!1;u?u.call(r,f,o,c):(u=o.content[v],u instanceof n||(u=n(o.content[v])),u.each(function(){f.append(n(this))}))}var b=Math.ceil(f.children().not("."+e.btn).length/h);b>1&&f.addClass(e.navbar+"-content-"+b),f.children("."+e.btn).length&&f.addClass(e.hasbtns),f.prependTo(r.$menu)});for(var o in d)r.$menu.addClass(e.hasnavbar+"-"+o+"-"+d[o])}},add:function(){e=n[a]._c,r=n[a]._d,s=n[a]._e,e.add("close hasbtns")},clickAnchor:function(){}},n[a].configuration[t]={breadcrumbSeparator:"/"},n[a].configuration.classNames[t]={panelTitle:"Title",panelNext:"Next",panelPrev:"Prev"};var e,r,s,i}(jQuery),/* 
29817 * jQuery mmenu navbar addon breadcrumbs content
29818 * mmenu.frebsite.nl
29819 *
29820 * Copyright (c) Fred Heusschen
29821 */
29822function(n){var a="mmenu",t="navbars",e="breadcrumbs";n[a].addons[t][e]=function(t,e,r){var s=n[a]._c,i=n[a]._d;s.add("breadcrumbs separator"),t.append('<span class="'+s.breadcrumbs+'"></span>'),this.bind("init",function(a){a.removeClass(s.hasnavbar).each(function(){for(var a=[],t=n(this),e=n('<span class="'+s.breadcrumbs+'"></span>'),c=n(this).children().first(),d=!0;c&&c.length;){c.is("."+s.panel)||(c=c.closest("."+s.panel));var o=c.children("."+s.navbar).children("."+s.title).text();a.unshift(d?"<span>"+o+"</span>":'<a href="#'+c.attr("id")+'">'+o+"</a>"),d=!1,c=c.data(i.parent)}e.append(a.join('<span class="'+s.separator+'">'+r.breadcrumbSeparator+"</span>")).appendTo(t.children("."+s.navbar))})});var c=function(){var n=this.$pnls.children("."+s.current),a=t.find("."+s.breadcrumbs),e=n.children("."+s.navbar).children("."+s.breadcrumbs);a.html(e.html())};this.bind("openPanel",c),this.bind("init",c)}}(jQuery),/* 
29823 * jQuery mmenu navbar addon close content
29824 * mmenu.frebsite.nl
29825 *
29826 * Copyright (c) Fred Heusschen
29827 */
29828function(n){var a="mmenu",t="navbars",e="close";n[a].addons[t][e]=function(t){var e=n[a]._c,r=n[a].glbl;t.append('<a class="'+e.close+" "+e.btn+'" href="#"></a>');var s=function(n){t.find("."+e.close).attr("href","#"+n.attr("id"))};s.call(this,r.$page),this.bind("setPage",s)}}(jQuery),/* 
29829 * jQuery mmenu navbar addon next content
29830 * mmenu.frebsite.nl
29831 *
29832 * Copyright (c) Fred Heusschen
29833 */
29834function(n){var a="mmenu",t="navbars",e="next";n[a].addons[t][e]=function(e){var r=n[a]._c;e.append('<a class="'+r.next+" "+r.btn+'" href="#"></a>');var s=function(n){n=n||this.$pnls.children("."+r.current);var a=e.find("."+r.next),s=n.find("."+this.conf.classNames[t].panelNext),i=s.attr("href"),c=s.html();a[i?"attr":"removeAttr"]("href",i),a[i||c?"removeClass":"addClass"](r.hidden),a.html(c)};
29834this.bind("openPanel",s),this.bind("init",function(){s.call(this)})}}(jQuery),/* 
29835 * jQuery mmenu navbar addon prev content
29836 * mmenu.frebsite.nl
29837 *
29838 * Copyright (c) Fred Heusschen
29839 */
29840function(n){var a="mmenu",t="navbars",e="prev";n[a].addons[t][e]=function(e){var r=n[a]._c;e.append('<a class="'+r.prev+" "+r.btn+'" href="#"></a>'),this.bind("init",function(n){n.removeClass(r.hasnavbar)});var s=function(){var n=this.$pnls.children("."+r.current),a=e.find("."+r.prev),s=n.find("."+this.conf.classNames[t].panelPrev);s.length||(s=n.children("."+r.navbar).children("."+r.prev));var i=s.attr("href"),c=s.html();a[i?"attr":"removeAttr"]("href",i),a[i||c?"removeClass":"addClass"](r.hidden),a.html(c)};this.bind("openPanel",s),this.bind("init",s)}}(jQuery),/* 
29841 * jQuery mmenu navbar addon searchfield content
29842 * mmenu.frebsite.nl
29843 *
29844 * Copyright (c) Fred Heusschen
29845 */
29846function(n){var a="mmenu",t="navbars",e="searchfield";n[a].addons[t][e]=function(t){var e=n[a]._c,r=n('<div class="'+e.search+'" />').appendTo(t);"object"!=typeof this.opts.searchfield&&(this.opts.searchfield={}),this.opts.searchfield.add=!0,this.opts.searchfield.addTo=r}}(jQuery),/* 
29847 * jQuery mmenu navbar addon title content
29848 * mmenu.frebsite.nl
29849 *
29850 * Copyright (c) Fred Heusschen
29851 */
29852function(n){var a="mmenu",t="navbars",e="title";n[a].addons[t][e]=function(e,r){var s=n[a]._c;e.append('<a class="'+s.title+'"></a>');var i=function(n){n=n||this.$pnls.children("."+s.current);var a=e.find("."+s.title),i=n.find("."+this.conf.classNames[t].panelTitle);i.length||(i=n.children("."+s.navbar).children("."+s.title));var c=i.attr("href"),d=i.html()||r.title;a[c?"attr":"removeAttr"]("href",c),a[c||d?"removeClass":"addClass"](s.hidden),a.html(d)};this.bind("openPanel",i),this.bind("init",function(){i.call(this)})}}(jQuery);
29853
29854   /* Ende jquery.mmenu.navbars */
29855   /* Start jqueryUI */
29856   /*! jQuery UI - v1.12.1 - 2017-05-16
29857* http://jqueryui.com
29858* Includes: widget.js, position.js, keycode.js, unique-id.js, widgets/autocomplete.js, widgets/datepicker.js, widgets/menu.js
29859* Copyright jQuery Foundation and other contributors; Licensed MIT */
29860(function( factory ) {
29861 if ( typeof define === "function" && define.amd ) {
29862  // AMD. Register as an anonymous module.
29863  define([ "jquery" ], factory );
29864 } else {
29865  // Browser globals
29866  factory( jQuery );
29867 }
29868}(function( $ ) {
29869$.ui = $.ui || {};
29870var version = $.ui.version = "1.12.1";
29871/*!
29872 * jQuery UI Widget 1.12.1
29873 * http://jqueryui.com
29874 *
29875 * Copyright jQuery Foundation and other contributors
29876 * Released under the MIT license.
29877 * http://jquery.org/license
29878 */
29879//>>label: Widget
29880//>>group: Core
29881//>>description: Provides a factory for creating stateful widgets with a common API.
29882//>>docs: http://api.jqueryui.com/jQuery.widget/
29883//>>demos: http://jqueryui.com/widget/
29884var widgetUuid = 0;
29885var widgetSlice = Array.prototype.slice;
29886$.cleanData = ( function( orig ) {
29887 return function( elems ) {
29888  var events, elem, i;
29889  for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
29890   try {
29891    // Only trigger remove when necessary to save time
29892    events = $._data( elem, "events" );
29893    if ( events && events.remove ) {
29894     $( elem ).triggerHandler( "remove" );
29895    }
29896   // Http://bugs.jquery.com/ticket/8235
29897   } catch ( e ) {}
29898  }
29899  orig( elems );
29900 };
29901} )( $.cleanData );
29902$.widget = function( name, base, prototype ) {
29903 var existingConstructor, constructor, basePrototype;
29904 // ProxiedPrototype allows the provided prototype to remain unmodified
29905 // so that it can be used as a mixin for multiple widgets (#8876)
29906 var proxiedPrototype = {};
29907 var namespace = name.split( "." )[ 0 ];
29908 name = name.split( "." )[ 1 ];
29909 var fullName = namespace + "-" + name;
29910 if ( !prototype ) {
29911  prototype = base;
29912  base = $.Widget;
29913 }
29914 if ( $.isArray( prototype ) ) {
29915  prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
29916 }
29917 // Create selector for plugin
29918 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
29919  return !!$.data( elem, fullName );
29920 };
29921 $[ namespace ] = $[ namespace ] || {};
29922 existingConstructor = $[ namespace ][ name ];
29923 constructor = $[ namespace ][ name ] = function( options, element ) {
29924  // Allow instantiation without "new" keyword
29925  if ( !this._createWidget ) {
29926   return new constructor( options, element );
29927  }
29928  // Allow instantiation without initializing for simple inheritance
29929  // must use "new" keyword (the code above always passes args)
29930  if ( arguments.length ) {
29931   this._createWidget( options, element );
29932  }
29933 };
29934 // Extend with the existing constructor to carry over any static properties
29935 $.extend( constructor, existingConstructor, {
29936  version: prototype.version,
29937  // Copy the object used to create the prototype in case we need to
29938  // redefine the widget later
29939  _proto: $.extend( {}, prototype ),
29940  // Track widgets that inherit from this widget in case this widget is
29941  // redefined after a widget inherits from it
29942  _childConstructors: []
29943 } );
29944 basePrototype = new base();
29945 // We need to make the options hash a property directly on the new instance
29946 // otherwise we'll modify the options hash on the prototype that we're
29947 // inheriting from
29948 basePrototype.options = $.widget.extend( {}, basePrototype.options );
29949 $.each( prototype, function( prop, value ) {
29950  if ( !$.isFunction( value ) ) {
29951   proxiedPrototype[ prop ] = value;
29952   return;
29953  }
29954  proxiedPrototype[ prop ] = ( function() {
29955   function _super() {
29956    return base.prototype[ prop ].apply( this, arguments );
29957   }
29958   function _superApply( args ) {
29959    return base.prototype[ prop ].apply( this, args );
29960   }
29961   return function() {
29962    var __super = this._super;
29963    var __superApply = this._superApply;
29964    var returnValue;
29965    this._super = _super;
29966    this._superApply = _superApply;
vendor: 15,799 bytes, lines 29967-30449
29967    returnValue = value.apply( this, arguments );
29968    this._super = __super;
29969    this._superApply = __superApply;
29970    return returnValue;
29971   };
29972  } )();
29973 } );
29974 constructor.prototype = $.widget.extend( basePrototype, {
29975  // TODO: remove support for widgetEventPrefix
29976  // always use the name + a colon as the prefix, e.g., draggable:start
29977  // don't prefix for widgets that aren't DOM-based
29978  widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
29979 }, proxiedPrototype, {
29980  constructor: constructor,
29981  namespace: namespace,
29982  widgetName: name,
29983  widgetFullName: fullName
29984 } );
29985 // If this widget is being redefined then we need to find all widgets that
29986 // are inheriting from it and redefine all of them so that they inherit from
29987 // the new version of this widget. We're essentially trying to replace one
29988 // level in the prototype chain.
29989 if ( existingConstructor ) {
29990  $.each( existingConstructor._childConstructors, function( i, child ) {
29991   var childPrototype = child.prototype;
29992   // Redefine the child widget using the same prototype that was
29993   // originally used, but inherit from the new version of the base
29994   $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
29995    child._proto );
29996  } );
29997  // Remove the list of existing child constructors from the old constructor
29998  // so the old child constructors can be garbage collected
29999  delete existingConstructor._childConstructors;
30000 } else {
30001  base._childConstructors.push( constructor );
30002 }
30003 $.widget.bridge( name, constructor );
30004 return constructor;
30005};
30006$.widget.extend = function( target ) {
30007 var input = widgetSlice.call( arguments, 1 );
30008 var inputIndex = 0;
30009 var inputLength = input.length;
30010 var key;
30011 var value;
30012 for ( ; inputIndex < inputLength; inputIndex++ ) {
30013  for ( key in input[ inputIndex ] ) {
30014   value = input[ inputIndex ][ key ];
30015   if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
30016    // Clone objects
30017    if ( $.isPlainObject( value ) ) {
30018     target[ key ] = $.isPlainObject( target[ key ] ) ?
30019      $.widget.extend( {}, target[ key ], value ) :
30020      // Don't extend strings, arrays, etc. with objects
30021      $.widget.extend( {}, value );
30022    // Copy everything else by reference
30023    } else {
30024     target[ key ] = value;
30025    }
30026   }
30027  }
30028 }
30029 return target;
30030};
30031$.widget.bridge = function( name, object ) {
30032 var fullName = object.prototype.widgetFullName || name;
30033 $.fn[ name ] = function( options ) {
30034  var isMethodCall = typeof options === "string";
30035  var args = widgetSlice.call( arguments, 1 );
30036  var returnValue = this;
30037  if ( isMethodCall ) {
30038   // If this is an empty collection, we need to have the instance method
30039   // return undefined instead of the jQuery instance
30040   if ( !this.length && options === "instance" ) {
30041    returnValue = undefined;
30042   } else {
30043    this.each( function() {
30044     var methodValue;
30045     var instance = $.data( this, fullName );
30046     if ( options === "instance" ) {
30047      returnValue = instance;
30048      return false;
30049     }
30050     if ( !instance ) {
30051      return $.error( "cannot call methods on " + name +
30052       " prior to initialization; " +
30053       "attempted to call method '" + options + "'" );
30054     }
30055     if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
30056      return $.error( "no such method '" + options + "' for " + name +
30057       " widget instance" );
30058     }
30059     methodValue = instance[ options ].apply( instance, args );
30060     if ( methodValue !== instance && methodValue !== undefined ) {
30061      returnValue = methodValue && methodValue.jquery ?
30062       returnValue.pushStack( methodValue.get() ) :
30063       methodValue;
30064      return false;
30065     }
30066    } );
30067   }
30068  } else {
30069   // Allow multiple hashes to be passed on init
30070   if ( args.length ) {
30071    options = $.widget.extend.apply( null, [ options ].concat( args ) );
30072   }
30073   this.each( function() {
30074    var instance = $.data( this, fullName );
30075    if ( instance ) {
30076     instance.option( options || {} );
30077     if ( instance._init ) {
30078      instance._init();
30079     }
30080    } else {
30081     $.data( this, fullName, new object( options, this ) );
30082    }
30083   } );
30084  }
30085  return returnValue;
30086 };
30087};
30088$.Widget = function( /* options, element */ ) {};
30089$.Widget._childConstructors = [];
30090$.Widget.prototype = {
30091 widgetName: "widget",
30092 widgetEventPrefix: "",
30093 defaultElement: "<div>",
30094 options: {
30095  classes: {},
30096  disabled: false,
30097  // Callbacks
30098  create: null
30099 },
30100 _createWidget: function( options, element ) {
30101  element = $( element || this.defaultElement || this )[ 0 ];
30102  this.element = $( element );
30103  this.uuid = widgetUuid++;
30104  this.eventNamespace = "." + this.widgetName + this.uuid;
30105  this.bindings = $();
30106  this.hoverable = $();
30107  this.focusable = $();
30108  this.classesElementLookup = {};
30109  if ( element !== this ) {
30110   $.data( element, this.widgetFullName, this );
30111   this._on( true, this.element, {
30112    remove: function( event ) {
30113     if ( event.target === element ) {
30114      this.destroy();
30115     }
30116    }
30117   } );
30118   this.document = $( element.style ?
30119    // Element within the document
30120    element.ownerDocument :
30121    // Element is window or document
30122    element.document || element );
30123   this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
30124  }
30125  this.options = $.widget.extend( {},
30126   this.options,
30127   this._getCreateOptions(),
30128   options );
30129  this._create();
30130  if ( this.options.disabled ) {
30131   this._setOptionDisabled( this.options.disabled );
30132  }
30133  this._trigger( "create", null, this._getCreateEventData() );
30134  this._init();
30135 },
30136 _getCreateOptions: function() {
30137  return {};
30138 },
30139 _getCreateEventData: $.noop,
30140 _create: $.noop,
30141 _init: $.noop,
30142 destroy: function() {
30143  var that = this;
30144  this._destroy();
30145  $.each( this.classesElementLookup, function( key, value ) {
30146   that._removeClass( value, key );
30147  } );
30148  // We can probably remove the unbind calls in 2.0
30149  // all event bindings should go through this._on()
30150  this.element
30151   .off( this.eventNamespace )
30152   .removeData( this.widgetFullName );
30153  this.widget()
30154   .off( this.eventNamespace )
30155   .removeAttr( "aria-disabled" );
30156  // Clean up events and states
30157  this.bindings.off( this.eventNamespace );
30158 },
30159 _destroy: $.noop,
30160 widget: function() {
30161  return this.element;
30162 },
30163 option: function( key, value ) {
30164  var options = key;
30165  var parts;
30166  var curOption;
30167  var i;
30168  if ( arguments.length === 0 ) {
30169   // Don't return a reference to the internal hash
30170   return $.widget.extend( {}, this.options );
30171  }
30172  if ( typeof key === "string" ) {
30173   // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
30174   options = {};
30175   parts = key.split( "." );
30176   key = parts.shift();
30177   if ( parts.length ) {
30178    curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
30179    for ( i = 0; i < parts.length - 1; i++ ) {
30180     curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
30181     curOption = curOption[ parts[ i ] ];
30182    }
30183    key = parts.pop();
30184    if ( arguments.length === 1 ) {
30185     return curOption[ key ] === undefined ? null : curOption[ key ];
30186    }
30187    curOption[ key ] = value;
30188   } else {
30189    if ( arguments.length === 1 ) {
30190     return this.options[ key ] === undefined ? null : this.options[ key ];
30191    }
30192    options[ key ] = value;
30193   }
30194  }
30195  this._setOptions( options );
30196  return this;
30197 },
30198 _setOptions: function( options ) {
30199  var key;
30200  for ( key in options ) {
30201   this._setOption( key, options[ key ] );
30202  }
30203  return this;
30204 },
30205 _setOption: function( key, value ) {
30206  if ( key === "classes" ) {
30207   this._setOptionClasses( value );
30208  }
30209  this.options[ key ] = value;
30210  if ( key === "disabled" ) {
30211   this._setOptionDisabled( value );
30212  }
30213  return this;
30214 },
30215 _setOptionClasses: function( value ) {
30216  var classKey, elements, currentElements;
30217  for ( classKey in value ) {
30218   currentElements = this.classesElementLookup[ classKey ];
30219   if ( value[ classKey ] === this.options.classes[ classKey ] ||
30220     !currentElements ||
30221     !currentElements.length ) {
30222    continue;
30223   }
30224   // We are doing this to create a new jQuery object because the _removeClass() call
30225   // on the next line is going to destroy the reference to the current elements being
30226   // tracked. We need to save a copy of this collection so that we can add the new classes
30227   // below.
30228   elements = $( currentElements.get() );
30229   this._removeClass( currentElements, classKey );
30230   // We don't use _addClass() here, because that uses this.options.classes
30231   // for generating the string of classes. We want to use the value passed in from
30232   // _setOption(), this is the new value of the classes option which was passed to
30233   // _setOption(). We pass this value directly to _classes().
30234   elements.addClass( this._classes( {
30235    element: elements,
30236    keys: classKey,
30237    classes: value,
30238    add: true
30239   } ) );
30240  }
30241 },
30242 _setOptionDisabled: function( value ) {
30243  this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
30244  // If the widget is becoming disabled, then nothing is interactive
30245  if ( value ) {
30246   this._removeClass( this.hoverable, null, "ui-state-hover" );
30247   this._removeClass( this.focusable, null, "ui-state-focus" );
30248  }
30249 },
30250 enable: function() {
30251  return this._setOptions( { disabled: false } );
30252 },
30253 disable: function() {
30254  return this._setOptions( { disabled: true } );
30255 },
30256 _classes: function( options ) {
30257  var full = [];
30258  var that = this;
30259  options = $.extend( {
30260   element: this.element,
30261   classes: this.options.classes || {}
30262  }, options );
30263  function processClassString( classes, checkOption ) {
30264   var current, i;
30265   for ( i = 0; i < classes.length; i++ ) {
30266    current = that.classesElementLookup[ classes[ i ] ] || $();
30267    if ( options.add ) {
30268     current = $( $.unique( current.get().concat( options.element.get() ) ) );
30269    } else {
30270     current = $( current.not( options.element ).get() );
30271    }
30272    that.classesElementLookup[ classes[ i ] ] = current;
30273    full.push( classes[ i ] );
30274    if ( checkOption && options.classes[ classes[ i ] ] ) {
30275     full.push( options.classes[ classes[ i ] ] );
30276    }
30277   }
30278  }
30279  this._on( options.element, {
30280   "remove": "_untrackClassesElement"
30281  } );
30282  if ( options.keys ) {
30283   processClassString( options.keys.match( /\S+/g ) || [], true );
30284  }
30285  if ( options.extra ) {
30286   processClassString( options.extra.match( /\S+/g ) || [] );
30287  }
30288  return full.join( " " );
30289 },
30290 _untrackClassesElement: function( event ) {
30291  var that = this;
30292  $.each( that.classesElementLookup, function( key, value ) {
30293   if ( $.inArray( event.target, value ) !== -1 ) {
30294    that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
30295   }
30296  } );
30297 },
30298 _removeClass: function( element, keys, extra ) {
30299  return this._toggleClass( element, keys, extra, false );
30300 },
30301 _addClass: function( element, keys, extra ) {
30302  return this._toggleClass( element, keys, extra, true );
30303 },
30304 _toggleClass: function( element, keys, extra, add ) {
30305  add = ( typeof add === "boolean" ) ? add : extra;
30306  var shift = ( typeof element === "string" || element === null ),
30307   options = {
30308    extra: shift ? keys : extra,
30309    keys: shift ? element : keys,
30310    element: shift ? this.element : element,
30311    add: add
30312   };
30313  options.element.toggleClass( this._classes( options ), add );
30314  return this;
30315 },
30316 _on: function( suppressDisabledCheck, element, handlers ) {
30317  var delegateElement;
30318  var instance = this;
30319  // No suppressDisabledCheck flag, shuffle arguments
30320  if ( typeof suppressDisabledCheck !== "boolean" ) {
30321   handlers = element;
30322   element = suppressDisabledCheck;
30323   suppressDisabledCheck = false;
30324  }
30325  // No element argument, shuffle and use this.element
30326  if ( !handlers ) {
30327   handlers = element;
30328   element = this.element;
30329   delegateElement = this.widget();
30330  } else {
30331   element = delegateElement = $( element );
30332   this.bindings = this.bindings.add( element );
30333  }
30334  $.each( handlers, function( event, handler ) {
30335   function handlerProxy() {
30336    // Allow widgets to customize the disabled handling
30337    // - disabled as an array instead of boolean
30338    // - disabled class as method for disabling individual parts
30339    if ( !suppressDisabledCheck &&
30340      ( instance.options.disabled === true ||
30341      $( this ).hasClass( "ui-state-disabled" ) ) ) {
30342     return;
30343    }
30344    return ( typeof handler === "string" ? instance[ handler ] : handler )
30345     .apply( instance, arguments );
30346   }
30347   // Copy the guid so direct unbinding works
30348   if ( typeof handler !== "string" ) {
30349    handlerProxy.guid = handler.guid =
30350     handler.guid || handlerProxy.guid || $.guid++;
30351   }
30352   var match = event.match( /^([\w:-]*)\s*(.*)$/ );
30353   var eventName = match[ 1 ] + instance.eventNamespace;
30354   var selector = match[ 2 ];
30355   if ( selector ) {
30356    delegateElement.on( eventName, selector, handlerProxy );
30357   } else {
30358    element.on( eventName, handlerProxy );
30359   }
30360  } );
30361 },
30362 _off: function( element, eventName ) {
30363  eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
30364   this.eventNamespace;
30365  element.off( eventName ).off( eventName );
30366  // Clear the stack to avoid memory leaks (#10056)
30367  this.bindings = $( this.bindings.not( element ).get() );
30368  this.focusable = $( this.focusable.not( element ).get() );
30369  this.hoverable = $( this.hoverable.not( element ).get() );
30370 },
30371 _delay: function( handler, delay ) {
30372  function handlerProxy() {
30373   return ( typeof handler === "string" ? instance[ handler ] : handler )
30374    .apply( instance, arguments );
30375  }
30376  var instance = this;
30377  return setTimeout( handlerProxy, delay || 0 );
30378 },
30379 _hoverable: function( element ) {
30380  this.hoverable = this.hoverable.add( element );
30381  this._on( element, {
30382   mouseenter: function( event ) {
30383    this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
30384   },
30385   mouseleave: function( event ) {
30386    this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
30387   }
30388  } );
30389 },
30390 _focusable: function( element ) {
30391  this.focusable = this.focusable.add( element );
30392  this._on( element, {
30393   focusin: function( event ) {
30394    this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
30395   },
30396   focusout: function( event ) {
30397    this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
30398   }
30399  } );
30400 },
30401 _trigger: function( type, event, data ) {
30402  var prop, orig;
30403  var callback = this.options[ type ];
30404  data = data || {};
30405  event = $.Event( event );
30406  event.type = ( type === this.widgetEventPrefix ?
30407   type :
30408   this.widgetEventPrefix + type ).toLowerCase();
30409  // The original event may come from any element
30410  // so we need to reset the target on the new event
30411  event.target = this.element[ 0 ];
30412  // Copy original event properties over to the new event
30413  orig = event.originalEvent;
30414  if ( orig ) {
30415   for ( prop in orig ) {
30416    if ( !( prop in event ) ) {
30417     event[ prop ] = orig[ prop ];
30418    }
30419   }
30420  }
30421  this.element.trigger( event, data );
30422  return !( $.isFunction( callback ) &&
30423   callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
30424   event.isDefaultPrevented() );
30425 }
30426};
30427$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
30428 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
30429  if ( typeof options === "string" ) {
30430   options = { effect: options };
30431  }
30432  var hasOptions;
30433  var effectName = !options ?
30434   method :
30435   options === true || typeof options === "number" ?
30436    defaultEffect :
30437    options.effect || defaultEffect;
30438  options = options || {};
30439  if ( typeof options === "number" ) {
30440   options = { duration: options };
30441  }
30442  hasOptions = !$.isEmptyObject( options );
30443  options.complete = callback;
30444  if ( options.delay ) {
30445   element.delay( options.delay );
30446  }
30447  if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
30448   element[ method ]( options );
30449  } else if ( effectName !== method && element[ effectName ] ) {
vendor: 4,779 bytes, lines 30450-30606
30450   element[ effectName ]( options.duration, options.easing, callback );
30451  } else {
30452   element.queue( function( next ) {
30453    $( this )[ method ]();
30454    if ( callback ) {
30455     callback.call( element[ 0 ] );
30456    }
30457    next();
30458   } );
30459  }
30460 };
30461} );
30462var widget = $.widget;
30463/*!
30464 * jQuery UI Position 1.12.1
30465 * http://jqueryui.com
30466 *
30467 * Copyright jQuery Foundation and other contributors
30468 * Released under the MIT license.
30469 * http://jquery.org/license
30470 *
30471 * http://api.jqueryui.com/position/
30472 */
30473//>>label: Position
30474//>>group: Core
30475//>>description: Positions elements relative to other elements.
30476//>>docs: http://api.jqueryui.com/position/
30477//>>demos: http://jqueryui.com/position/
30478( function() {
30479var cachedScrollbarWidth,
30480 max = Math.max,
30481 abs = Math.abs,
30482 rhorizontal = /left|center|right/,
30483 rvertical = /top|center|bottom/,
30484 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
30485 rposition = /^\w+/,
30486 rpercent = /%$/,
30487 _position = $.fn.position;
30488function getOffsets( offsets, width, height ) {
30489 return [
30490  parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
30491  parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
30492 ];
30493}
30494function parseCss( element, property ) {
30495 return parseInt( $.css( element, property ), 10 ) || 0;
30496}
30497function getDimensions( elem ) {
30498 var raw = elem[ 0 ];
30499 if ( raw.nodeType === 9 ) {
30500  return {
30501   width: elem.width(),
30502   height: elem.height(),
30503   offset: { top: 0, left: 0 }
30504  };
30505 }
30506 if ( $.isWindow( raw ) ) {
30507  return {
30508   width: elem.width(),
30509   height: elem.height(),
30510   offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
30511  };
30512 }
30513 if ( raw.preventDefault ) {
30514  return {
30515   width: 0,
30516   height: 0,
30517   offset: { top: raw.pageY, left: raw.pageX }
30518  };
30519 }
30520 return {
30521  width: elem.outerWidth(),
30522  height: elem.outerHeight(),
30523  offset: elem.offset()
30524 };
30525}
30526$.position = {
30527 scrollbarWidth: function() {
30528  if ( cachedScrollbarWidth !== undefined ) {
30529   return cachedScrollbarWidth;
30530  }
30531  var w1, w2,
30532   div = $( "<div " +
30533    "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
30534    "<div style='height:100px;width:auto;'></div></div>" ),
30535   innerDiv = div.children()[ 0 ];
30536  $( "body" ).append( div );
30537  w1 = innerDiv.offsetWidth;
30538  div.css( "overflow", "scroll" );
30539  w2 = innerDiv.offsetWidth;
30540  if ( w1 === w2 ) {
30541   w2 = div[ 0 ].clientWidth;
30542  }
30543  div.remove();
30544  return ( cachedScrollbarWidth = w1 - w2 );
30545 },
30546 getScrollInfo: function( within ) {
30547  var overflowX = within.isWindow || within.isDocument ? "" :
30548    within.element.css( "overflow-x" ),
30549   overflowY = within.isWindow || within.isDocument ? "" :
30550    within.element.css( "overflow-y" ),
30551   hasOverflowX = overflowX === "scroll" ||
30552    ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
30553   hasOverflowY = overflowY === "scroll" ||
30554    ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
30555  return {
30556   width: hasOverflowY ? $.position.scrollbarWidth() : 0,
30557   height: hasOverflowX ? $.position.scrollbarWidth() : 0
30558  };
30559 },
30560 getWithinInfo: function( element ) {
30561  var withinElement = $( element || window ),
30562   isWindow = $.isWindow( withinElement[ 0 ] ),
30563   isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
30564   hasOffset = !isWindow && !isDocument;
30565  return {
30566   element: withinElement,
30567   isWindow: isWindow,
30568   isDocument: isDocument,
30569   offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
30570   scrollLeft: withinElement.scrollLeft(),
30571   scrollTop: withinElement.scrollTop(),
30572   width: withinElement.outerWidth(),
30573   height: withinElement.outerHeight()
30574  };
30575 }
30576};
30577$.fn.position = function( options ) {
30578 if ( !options || !options.of ) {
30579  return _position.apply( this, arguments );
30580 }
30581 // Make a copy, we don't want to modify arguments
30582 options = $.extend( {}, options );
30583 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
30584  target = $( options.of ),
30585  within = $.position.getWithinInfo( options.within ),
30586  scrollInfo = $.position.getScrollInfo( within ),
30587  collision = ( options.collision || "flip" ).split( " " ),
30588  offsets = {};
30589 dimensions = getDimensions( target );
30590 if ( target[ 0 ].preventDefault ) {
30591  // Force left top to allow flipping
30592  options.at = "left top";
30593 }
30594 targetWidth = dimensions.width;
30595 targetHeight = dimensions.height;
30596 targetOffset = dimensions.offset;
30597 // Clone to reuse original targetOffset later
30598 basePosition = $.extend( {}, targetOffset );
30599 // Force my and at to have valid horizontal and vertical positions
30600 // if a value is missing or invalid, it will be converted to center
30601 $.each( [ "my", "at" ], function() {
30602  var pos = ( options[ this ] || "" ).split( " " ),
30603   horizontalOffset,
30604   verticalOffset;
30605  if ( pos.length === 1 ) {
30606   pos = rhorizontal.test( pos[ 0 ] ) ?
vendor: 10,072 bytes, lines 30607-30896
30607    pos.concat( [ "center" ] ) :
30608    rvertical.test( pos[ 0 ] ) ?
30609     [ "center" ].concat( pos ) :
30610     [ "center", "center" ];
30611  }
30612  pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
30613  pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
30614  // Calculate offsets
30615  horizontalOffset = roffset.exec( pos[ 0 ] );
30616  verticalOffset = roffset.exec( pos[ 1 ] );
30617  offsets[ this ] = [
30618   horizontalOffset ? horizontalOffset[ 0 ] : 0,
30619   verticalOffset ? verticalOffset[ 0 ] : 0
30620  ];
30621  // Reduce to just the positions without the offsets
30622  options[ this ] = [
30623   rposition.exec( pos[ 0 ] )[ 0 ],
30624   rposition.exec( pos[ 1 ] )[ 0 ]
30625  ];
30626 } );
30627 // Normalize collision option
30628 if ( collision.length === 1 ) {
30629  collision[ 1 ] = collision[ 0 ];
30630 }
30631 if ( options.at[ 0 ] === "right" ) {
30632  basePosition.left += targetWidth;
30633 } else if ( options.at[ 0 ] === "center" ) {
30634  basePosition.left += targetWidth / 2;
30635 }
30636 if ( options.at[ 1 ] === "bottom" ) {
30637  basePosition.top += targetHeight;
30638 } else if ( options.at[ 1 ] === "center" ) {
30639  basePosition.top += targetHeight / 2;
30640 }
30641 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
30642 basePosition.left += atOffset[ 0 ];
30643 basePosition.top += atOffset[ 1 ];
30644 return this.each( function() {
30645  var collisionPosition, using,
30646   elem = $( this ),
30647   elemWidth = elem.outerWidth(),
30648   elemHeight = elem.outerHeight(),
30649   marginLeft = parseCss( this, "marginLeft" ),
30650   marginTop = parseCss( this, "marginTop" ),
30651   collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
30652    scrollInfo.width,
30653   collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
30654    scrollInfo.height,
30655   position = $.extend( {}, basePosition ),
30656   myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
30657  if ( options.my[ 0 ] === "right" ) {
30658   position.left -= elemWidth;
30659  } else if ( options.my[ 0 ] === "center" ) {
30660   position.left -= elemWidth / 2;
30661  }
30662  if ( options.my[ 1 ] === "bottom" ) {
30663   position.top -= elemHeight;
30664  } else if ( options.my[ 1 ] === "center" ) {
30665   position.top -= elemHeight / 2;
30666  }
30667  position.left += myOffset[ 0 ];
30668  position.top += myOffset[ 1 ];
30669  collisionPosition = {
30670   marginLeft: marginLeft,
30671   marginTop: marginTop
30672  };
30673  $.each( [ "left", "top" ], function( i, dir ) {
30674   if ( $.ui.position[ collision[ i ] ] ) {
30675    $.ui.position[ collision[ i ] ][ dir ]( position, {
30676     targetWidth: targetWidth,
30677     targetHeight: targetHeight,
30678     elemWidth: elemWidth,
30679     elemHeight: elemHeight,
30680     collisionPosition: collisionPosition,
30681     collisionWidth: collisionWidth,
30682     collisionHeight: collisionHeight,
30683     offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
30684     my: options.my,
30685     at: options.at,
30686     within: within,
30687     elem: elem
30688    } );
30689   }
30690  } );
30691  if ( options.using ) {
30692   // Adds feedback as second argument to using callback, if present
30693   using = function( props ) {
30694    var left = targetOffset.left - position.left,
30695     right = left + targetWidth - elemWidth,
30696     top = targetOffset.top - position.top,
30697     bottom = top + targetHeight - elemHeight,
30698     feedback = {
30699      target: {
30700       element: target,
30701       left: targetOffset.left,
30702       top: targetOffset.top,
30703       width: targetWidth,
30704       height: targetHeight
30705      },
30706      element: {
30707       element: elem,
30708       left: position.left,
30709       top: position.top,
30710       width: elemWidth,
30711       height: elemHeight
30712      },
30713      horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
30714      vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
30715     };
30716    if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
30717     feedback.horizontal = "center";
30718    }
30719    if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
30720     feedback.vertical = "middle";
30721    }
30722    if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
30723     feedback.important = "horizontal";
30724    } else {
30725     feedback.important = "vertical";
30726    }
30727    options.using.call( this, props, feedback );
30728   };
30729  }
30730  elem.offset( $.extend( position, { using: using } ) );
30731 } );
30732};
30733$.ui.position = {
30734 fit: {
30735  left: function( position, data ) {
30736   var within = data.within,
30737    withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
30738    outerWidth = within.width,
30739    collisionPosLeft = position.left - data.collisionPosition.marginLeft,
30740    overLeft = withinOffset - collisionPosLeft,
30741    overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
30742    newOverRight;
30743   // Element is wider than within
30744   if ( data.collisionWidth > outerWidth ) {
30745    // Element is initially over the left side of within
30746    if ( overLeft > 0 && overRight <= 0 ) {
30747     newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
30748      withinOffset;
30749     position.left += overLeft - newOverRight;
30750    // Element is initially over right side of within
30751    } else if ( overRight > 0 && overLeft <= 0 ) {
30752     position.left = withinOffset;
30753    // Element is initially over both left and right sides of within
30754    } else {
30755     if ( overLeft > overRight ) {
30756      position.left = withinOffset + outerWidth - data.collisionWidth;
30757     } else {
30758      position.left = withinOffset;
30759     }
30760    }
30761   // Too far left -> align with left edge
30762   } else if ( overLeft > 0 ) {
30763    position.left += overLeft;
30764   // Too far right -> align with right edge
30765   } else if ( overRight > 0 ) {
30766    position.left -= overRight;
30767   // Adjust based on position and margin
30768   } else {
30769    position.left = max( position.left - collisionPosLeft, position.left );
30770   }
30771  },
30772  top: function( position, data ) {
30773   var within = data.within,
30774    withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
30775    outerHeight = data.within.height,
30776    collisionPosTop = position.top - data.collisionPosition.marginTop,
30777    overTop = withinOffset - collisionPosTop,
30778    overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
30779    newOverBottom;
30780   // Element is taller than within
30781   if ( data.collisionHeight > outerHeight ) {
30782    // Element is initially over the top of within
30783    if ( overTop > 0 && overBottom <= 0 ) {
30784     newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
30785      withinOffset;
30786     position.top += overTop - newOverBottom;
30787    // Element is initially over bottom of within
30788    } else if ( overBottom > 0 && overTop <= 0 ) {
30789     position.top = withinOffset;
30790    // Element is initially over both top and bottom of within
30791    } else {
30792     if ( overTop > overBottom ) {
30793      position.top = withinOffset + outerHeight - data.collisionHeight;
30794     } else {
30795      position.top = withinOffset;
30796     }
30797    }
30798   // Too far up -> align with top
30799   } else if ( overTop > 0 ) {
30800    position.top += overTop;
30801   // Too far down -> align with bottom edge
30802   } else if ( overBottom > 0 ) {
30803    position.top -= overBottom;
30804   // Adjust based on position and margin
30805   } else {
30806    position.top = max( position.top - collisionPosTop, position.top );
30807   }
30808  }
30809 },
30810 flip: {
30811  left: function( position, data ) {
30812   var within = data.within,
30813    withinOffset = within.offset.left + within.scrollLeft,
30814    outerWidth = within.width,
30815    offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
30816    collisionPosLeft = position.left - data.collisionPosition.marginLeft,
30817    overLeft = collisionPosLeft - offsetLeft,
30818    overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
30819    myOffset = data.my[ 0 ] === "left" ?
30820     -data.elemWidth :
30821     data.my[ 0 ] === "right" ?
30822      data.elemWidth :
30823      0,
30824    atOffset = data.at[ 0 ] === "left" ?
30825     data.targetWidth :
30826     data.at[ 0 ] === "right" ?
30827      -data.targetWidth :
30828      0,
30829    offset = -2 * data.offset[ 0 ],
30830    newOverRight,
30831    newOverLeft;
30832   if ( overLeft < 0 ) {
30833    newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
30834     outerWidth - withinOffset;
30835    if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
30836     position.left += myOffset + atOffset + offset;
30837    }
30838   } else if ( overRight > 0 ) {
30839    newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
30840     atOffset + offset - offsetLeft;
30841    if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
30842     position.left += myOffset + atOffset + offset;
30843    }
30844   }
30845  },
30846  top: function( position, data ) {
30847   var within = data.within,
30848    withinOffset = within.offset.top + within.scrollTop,
30849    outerHeight = within.height,
30850    offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
30851    collisionPosTop = position.top - data.collisionPosition.marginTop,
30852    overTop = collisionPosTop - offsetTop,
30853    overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
30854    top = data.my[ 1 ] === "top",
30855    myOffset = top ?
30856     -data.elemHeight :
30857     data.my[ 1 ] === "bottom" ?
30858      data.elemHeight :
30859      0,
30860    atOffset = data.at[ 1 ] === "top" ?
30861     data.targetHeight :
30862     data.at[ 1 ] === "bottom" ?
30863      -data.targetHeight :
30864      0,
30865    offset = -2 * data.offset[ 1 ],
30866    newOverTop,
30867    newOverBottom;
30868   if ( overTop < 0 ) {
30869    newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
30870     outerHeight - withinOffset;
30871    if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
30872     position.top += myOffset + atOffset + offset;
30873    }
30874   } else if ( overBottom > 0 ) {
30875    newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
30876     offset - offsetTop;
30877    if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
30878     position.top += myOffset + atOffset + offset;
30879    }
30880   }
30881  }
30882 },
30883 flipfit: {
30884  left: function() {
30885   $.ui.position.flip.left.apply( this, arguments );
30886   $.ui.position.fit.left.apply( this, arguments );
30887  },
30888  top: function() {
30889   $.ui.position.flip.top.apply( this, arguments );
30890   $.ui.position.fit.top.apply( this, arguments );
30891  }
30892 }
30893};
30894} )();
30895var position = $.ui.position;
30896/*!
vendor: 5,645 bytes, lines 30897-31090
30897 * jQuery UI Keycode 1.12.1
30898 * http://jqueryui.com
30899 *
30900 * Copyright jQuery Foundation and other contributors
30901 * Released under the MIT license.
30902 * http://jquery.org/license
30903 */
30904//>>label: Keycode
30905//>>group: Core
30906//>>description: Provide keycodes as keynames
30907//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
30908var keycode = $.ui.keyCode = {
30909 BACKSPACE: 8,
30910 COMMA: 188,
30911 DELETE: 46,
30912 DOWN: 40,
30913 END: 35,
30914 ENTER: 13,
30915 ESCAPE: 27,
30916 HOME: 36,
30917 LEFT: 37,
30918 PAGE_DOWN: 34,
30919 PAGE_UP: 33,
30920 PERIOD: 190,
30921 RIGHT: 39,
30922 SPACE: 32,
30923 TAB: 9,
30924 UP: 38
30925};
30926/*!
30927 * jQuery UI Unique ID 1.12.1
30928 * http://jqueryui.com
30929 *
30930 * Copyright jQuery Foundation and other contributors
30931 * Released under the MIT license.
30932 * http://jquery.org/license
30933 */
30934//>>label: uniqueId
30935//>>group: Core
30936//>>description: Functions to generate and remove uniqueId's
30937//>>docs: http://api.jqueryui.com/uniqueId/
30938var uniqueId = $.fn.extend( {
30939 uniqueId: ( function() {
30940  var uuid = 0;
30941  return function() {
30942   return this.each( function() {
30943    if ( !this.id ) {
30944     this.id = "ui-id-" + ( ++uuid );
30945    }
30946   } );
30947  };
30948 } )(),
30949 removeUniqueId: function() {
30950  return this.each( function() {
30951   if ( /^ui-id-\d+$/.test( this.id ) ) {
30952    $( this ).removeAttr( "id" );
30953   }
30954  } );
30955 }
30956} );
30957var safeActiveElement = $.ui.safeActiveElement = function( document ) {
30958 var activeElement;
30959 // Support: IE 9 only
30960 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
30961 try {
30962  activeElement = document.activeElement;
30963 } catch ( error ) {
30964  activeElement = document.body;
30965 }
30966 // Support: IE 9 - 11 only
30967 // IE may return null instead of an element
30968 // Interestingly, this only seems to occur when NOT in an iframe
30969 if ( !activeElement ) {
30970  activeElement = document.body;
30971 }
30972 // Support: IE 11 only
30973 // IE11 returns a seemingly empty object in some cases when accessing
30974 // document.activeElement from an <iframe>
30975 if ( !activeElement.nodeName ) {
30976  activeElement = document.body;
30977 }
30978 return activeElement;
30979};
30980/*!
30981 * jQuery UI Menu 1.12.1
30982 * http://jqueryui.com
30983 *
30984 * Copyright jQuery Foundation and other contributors
30985 * Released under the MIT license.
30986 * http://jquery.org/license
30987 */
30988//>>label: Menu
30989//>>group: Widgets
30990//>>description: Creates nestable menus.
30991//>>docs: http://api.jqueryui.com/menu/
30992//>>demos: http://jqueryui.com/menu/
30993//>>css.structure: ../../themes/base/core.css
30994//>>css.structure: ../../themes/base/menu.css
30995//>>css.theme: ../../themes/base/theme.css
30996var widgetsMenu = $.widget( "ui.menu", {
30997 version: "1.12.1",
30998 defaultElement: "<ul>",
30999 delay: 300,
31000 options: {
31001  icons: {
31002   submenu: "ui-icon-caret-1-e"
31003  },
31004  items: "> *",
31005  menus: "ul",
31006  position: {
31007   my: "left top",
31008   at: "right top"
31009  },
31010  role: "menu",
31011  // Callbacks
31012  blur: null,
31013  focus: null,
31014  select: null
31015 },
31016 _create: function() {
31017  this.activeMenu = this.element;
31018  // Flag used to prevent firing of the click handler
31019  // as the event bubbles up through nested menus
31020  this.mouseHandled = false;
31021  this.element
31022   .uniqueId()
31023   .attr( {
31024    role: this.options.role,
31025    tabIndex: 0
31026   } );
31027  this._addClass( "ui-menu", "ui-widget ui-widget-content" );
31028  this._on( {
31029   // Prevent focus from sticking to links inside menu after clicking
31030   // them (focus should always stay on UL during navigation).
31031   "mousedown .ui-menu-item": function( event ) {
31032    event.preventDefault();
31033   },
31034   "click .ui-menu-item": function( event ) {
31035    var target = $( event.target );
31036    var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
31037    if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
31038     this.select( event );
31039     // Only set the mouseHandled flag if the event will bubble, see #9469.
31040     if ( !event.isPropagationStopped() ) {
31041      this.mouseHandled = true;
31042     }
31043     // Open submenu on click
31044     if ( target.has( ".ui-menu" ).length ) {
31045      this.expand( event );
31046     } else if ( !this.element.is( ":focus" ) &&
31047       active.closest( ".ui-menu" ).length ) {
31048      // Redirect focus to the menu
31049      this.element.trigger( "focus", [ true ] );
31050      // If the active item is on the top level, let it stay active.
31051      // Otherwise, blur the active item since it is no longer visible.
31052      if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
31053       clearTimeout( this.timer );
31054      }
31055     }
31056    }
31057   },
31058   "mouseenter .ui-menu-item": function( event ) {
31059    // Ignore mouse events while typeahead is active, see #10458.
31060    // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
31061    // is over an item in the menu
31062    if ( this.previousFilter ) {
31063     return;
31064    }
31065    var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
31066     target = $( event.currentTarget );
31067    // Ignore bubbled events on parent items, see #11641
31068    if ( actualTarget[ 0 ] !== target[ 0 ] ) {
31069     return;
31070    }
31071    // Remove ui-state-active class from siblings of the newly focused menu item
31072    // to avoid a jump caused by adjacent elements both having a class with a border
31073    this._removeClass( target.siblings().children( ".ui-state-active" ),
31074     null, "ui-state-active" );
31075    this.focus( event, target );
31076   },
31077   mouseleave: "collapseAll",
31078   "mouseleave .ui-menu": "collapseAll",
31079   focus: function( event, keepActiveItem ) {
31080    // If there's already an active item, keep it active
31081    // If not, activate the first item
31082    var item = this.active || this.element.find( this.options.items ).eq( 0 );
31083    if ( !keepActiveItem ) {
31084     this.focus( event, item );
31085    }
31086   },
31087   blur: function( event ) {
31088    this._delay( function() {
31089     var notContained = !$.contains(
31090      this.element[ 0 ],
vendor: 2,041 bytes, lines 31091-31171
31091      $.ui.safeActiveElement( this.document[ 0 ] )
31092     );
31093     if ( notContained ) {
31094      this.collapseAll( event );
31095     }
31096    } );
31097   },
31098   keydown: "_keydown"
31099  } );
31100  this.refresh();
31101  // Clicks outside of a menu collapse any open menus
31102  this._on( this.document, {
31103   click: function( event ) {
31104    if ( this._closeOnDocumentClick( event ) ) {
31105     this.collapseAll( event );
31106    }
31107    // Reset the mouseHandled flag
31108    this.mouseHandled = false;
31109   }
31110  } );
31111 },
31112 _destroy: function() {
31113  var items = this.element.find( ".ui-menu-item" )
31114    .removeAttr( "role aria-disabled" ),
31115   submenus = items.children( ".ui-menu-item-wrapper" )
31116    .removeUniqueId()
31117    .removeAttr( "tabIndex role aria-haspopup" );
31118  // Destroy (sub)menus
31119  this.element
31120   .removeAttr( "aria-activedescendant" )
31121   .find( ".ui-menu" ).addBack()
31122    .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
31123     "tabIndex" )
31124    .removeUniqueId()
31125    .show();
31126  submenus.children().each( function() {
31127   var elem = $( this );
31128   if ( elem.data( "ui-menu-submenu-caret" ) ) {
31129    elem.remove();
31130   }
31131  } );
31132 },
31133 _keydown: function( event ) {
31134  var match, prev, character, skip,
31135   preventDefault = true;
31136  switch ( event.keyCode ) {
31137  case $.ui.keyCode.PAGE_UP:
31138   this.previousPage( event );
31139   break;
31140  case $.ui.keyCode.PAGE_DOWN:
31141   this.nextPage( event );
31142   break;
31143  case $.ui.keyCode.HOME:
31144   this._move( "first", "first", event );
31145   break;
31146  case $.ui.keyCode.END:
31147   this._move( "last", "last", event );
31148   break;
31149  case $.ui.keyCode.UP:
31150   this.previous( event );
31151   break;
31152  case $.ui.keyCode.DOWN:
31153   this.next( event );
31154   break;
31155  case $.ui.keyCode.LEFT:
31156   this.collapse( event );
31157   break;
31158  case $.ui.keyCode.RIGHT:
31159   if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
31160    this.expand( event );
31161   }
31162   break;
31163  case $.ui.keyCode.ENTER:
31164  case $.ui.keyCode.SPACE:
31165   this._activate( event );
31166   break;
31167  case $.ui.keyCode.ESCAPE:
31168   this.collapse( event );
31169   break;
31170  default:
31171   preventDefault = false;
vendor: 6,885 bytes, lines 31172-31375
31172   prev = this.previousFilter || "";
31173   skip = false;
31174   // Support number pad values
31175   character = event.keyCode >= 96 && event.keyCode <= 105 ?
31176    ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
31177   clearTimeout( this.filterTimer );
31178   if ( character === prev ) {
31179    skip = true;
31180   } else {
31181    character = prev + character;
31182   }
31183   match = this._filterMenuItems( character );
31184   match = skip && match.index( this.active.next() ) !== -1 ?
31185    this.active.nextAll( ".ui-menu-item" ) :
31186    match;
31187   // If no matches on the current filter, reset to the last character pressed
31188   // to move down the menu to the first item that starts with that character
31189   if ( !match.length ) {
31190    character = String.fromCharCode( event.keyCode );
31191    match = this._filterMenuItems( character );
31192   }
31193   if ( match.length ) {
31194    this.focus( event, match );
31195    this.previousFilter = character;
31196    this.filterTimer = this._delay( function() {
31197     delete this.previousFilter;
31198    }, 1000 );
31199   } else {
31200    delete this.previousFilter;
31201   }
31202  }
31203  if ( preventDefault ) {
31204   event.preventDefault();
31205  }
31206 },
31207 _activate: function( event ) {
31208  if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
31209   if ( this.active.children( "[aria-haspopup='true']" ).length ) {
31210    this.expand( event );
31211   } else {
31212    this.select( event );
31213   }
31214  }
31215 },
31216 refresh: function() {
31217  var menus, items, newSubmenus, newItems, newWrappers,
31218   that = this,
31219   icon = this.options.icons.submenu,
31220   submenus = this.element.find( this.options.menus );
31221  this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
31222  // Initialize nested menus
31223  newSubmenus = submenus.filter( ":not(.ui-menu)" )
31224   .hide()
31225   .attr( {
31226    role: this.options.role,
31227    "aria-hidden": "true",
31228    "aria-expanded": "false"
31229   } )
31230   .each( function() {
31231    var menu = $( this ),
31232     item = menu.prev(),
31233     submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
31234    that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
31235    item
31236     .attr( "aria-haspopup", "true" )
31237     .prepend( submenuCaret );
31238    menu.attr( "aria-labelledby", item.attr( "id" ) );
31239   } );
31240  this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
31241  menus = submenus.add( this.element );
31242  items = menus.find( this.options.items );
31243  // Initialize menu-items containing spaces and/or dashes only as dividers
31244  items.not( ".ui-menu-item" ).each( function() {
31245   var item = $( this );
31246   if ( that._isDivider( item ) ) {
31247    that._addClass( item, "ui-menu-divider", "ui-widget-content" );
31248   }
31249  } );
31250  // Don't refresh list items that are already adapted
31251  newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
31252  newWrappers = newItems.children()
31253   .not( ".ui-menu" )
31254    .uniqueId()
31255    .attr( {
31256     tabIndex: -1,
31257     role: this._itemRole()
31258    } );
31259  this._addClass( newItems, "ui-menu-item" )
31260   ._addClass( newWrappers, "ui-menu-item-wrapper" );
31261  // Add aria-disabled attribute to any disabled menu item
31262  items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
31263  // If the active item has been removed, blur the menu
31264  if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
31265   this.blur();
31266  }
31267 },
31268 _itemRole: function() {
31269  return {
31270   menu: "menuitem",
31271   listbox: "option"
31272  }[ this.options.role ];
31273 },
31274 _setOption: function( key, value ) {
31275  if ( key === "icons" ) {
31276   var icons = this.element.find( ".ui-menu-icon" );
31277   this._removeClass( icons, null, this.options.icons.submenu )
31278    ._addClass( icons, null, value.submenu );
31279  }
31280  this._super( key, value );
31281 },
31282 _setOptionDisabled: function( value ) {
31283  this._super( value );
31284  this.element.attr( "aria-disabled", String( value ) );
31285  this._toggleClass( null, "ui-state-disabled", !!value );
31286 },
31287 focus: function( event, item ) {
31288  var nested, focused, activeParent;
31289  this.blur( event, event && event.type === "focus" );
31290  this._scrollIntoView( item );
31291  this.active = item.first();
31292  focused = this.active.children( ".ui-menu-item-wrapper" );
31293  this._addClass( focused, null, "ui-state-active" );
31294  // Only update aria-activedescendant if there's a role
31295  // otherwise we assume focus is managed elsewhere
31296  if ( this.options.role ) {
31297   this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
31298  }
31299  // Highlight active parent menu item, if any
31300  activeParent = this.active
31301   .parent()
31302    .closest( ".ui-menu-item" )
31303     .children( ".ui-menu-item-wrapper" );
31304  this._addClass( activeParent, null, "ui-state-active" );
31305  if ( event && event.type === "keydown" ) {
31306   this._close();
31307  } else {
31308   this.timer = this._delay( function() {
31309    this._close();
31310   }, this.delay );
31311  }
31312  nested = item.children( ".ui-menu" );
31313  if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
31314   this._startOpening( nested );
31315  }
31316  this.activeMenu = item.parent();
31317  this._trigger( "focus", event, { item: item } );
31318 },
31319 _scrollIntoView: function( item ) {
31320  var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
31321  if ( this._hasScroll() ) {
31322   borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
31323   paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
31324   offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
31325   scroll = this.activeMenu.scrollTop();
31326   elementHeight = this.activeMenu.height();
31327   itemHeight = item.outerHeight();
31328   if ( offset < 0 ) {
31329    this.activeMenu.scrollTop( scroll + offset );
31330   } else if ( offset + itemHeight > elementHeight ) {
31331    this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
31332   }
31333  }
31334 },
31335 blur: function( event, fromFocus ) {
31336  if ( !fromFocus ) {
31337   clearTimeout( this.timer );
31338  }
31339  if ( !this.active ) {
31340   return;
31341  }
31342  this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
31343   null, "ui-state-active" );
31344  this._trigger( "blur", event, { item: this.active } );
31345  this.active = null;
31346 },
31347 _startOpening: function( submenu ) {
31348  clearTimeout( this.timer );
31349  // Don't open if already open fixes a Firefox bug that caused a .5 pixel
31350  // shift in the submenu position when mousing over the caret icon
31351  if ( submenu.attr( "aria-hidden" ) !== "true" ) {
31352   return;
31353  }
31354  this.timer = this._delay( function() {
31355   this._close();
31356   this._open( submenu );
31357  }, this.delay );
31358 },
31359 _open: function( submenu ) {
31360  var position = $.extend( {
31361   of: this.active
31362  }, this.options.position );
31363  clearTimeout( this.timer );
31364  this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
31365   .hide()
31366   .attr( "aria-hidden", "true" );
31367  submenu
31368   .show()
31369   .removeAttr( "aria-hidden" )
31370   .attr( "aria-expanded", "true" )
31371   .position( position );
31372 },
31373 collapseAll: function( event, all ) {
31374  clearTimeout( this.timer );
31375  this.timer = this._delay( function() {
vendor: 26,702 bytes, lines 31376-32177
31376   // If we were passed an event, look for the submenu that contains the event
31377   var currentMenu = all ? this.element :
31378    $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
31379   // If we found no valid submenu ancestor, use the main menu to close all
31380   // sub menus anyway
31381   if ( !currentMenu.length ) {
31382    currentMenu = this.element;
31383   }
31384   this._close( currentMenu );
31385   this.blur( event );
31386   // Work around active item staying active after menu is blurred
31387   this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
31388   this.activeMenu = currentMenu;
31389  }, this.delay );
31390 },
31391 // With no arguments, closes the currently active menu - if nothing is active
31392 // it closes all menus.  If passed an argument, it will search for menus BELOW
31393 _close: function( startMenu ) {
31394  if ( !startMenu ) {
31395   startMenu = this.active ? this.active.parent() : this.element;
31396  }
31397  startMenu.find( ".ui-menu" )
31398   .hide()
31399   .attr( "aria-hidden", "true" )
31400   .attr( "aria-expanded", "false" );
31401 },
31402 _closeOnDocumentClick: function( event ) {
31403  return !$( event.target ).closest( ".ui-menu" ).length;
31404 },
31405 _isDivider: function( item ) {
31406  // Match hyphen, em dash, en dash
31407  return !/[^\-\u2014\u2013\s]/.test( item.text() );
31408 },
31409 collapse: function( event ) {
31410  var newItem = this.active &&
31411   this.active.parent().closest( ".ui-menu-item", this.element );
31412  if ( newItem && newItem.length ) {
31413   this._close();
31414   this.focus( event, newItem );
31415  }
31416 },
31417 expand: function( event ) {
31418  var newItem = this.active &&
31419   this.active
31420    .children( ".ui-menu " )
31421     .find( this.options.items )
31422      .first();
31423  if ( newItem && newItem.length ) {
31424   this._open( newItem.parent() );
31425   // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
31426   this._delay( function() {
31427    this.focus( event, newItem );
31428   } );
31429  }
31430 },
31431 next: function( event ) {
31432  this._move( "next", "first", event );
31433 },
31434 previous: function( event ) {
31435  this._move( "prev", "last", event );
31436 },
31437 isFirstItem: function() {
31438  return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
31439 },
31440 isLastItem: function() {
31441  return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
31442 },
31443 _move: function( direction, filter, event ) {
31444  var next;
31445  if ( this.active ) {
31446   if ( direction === "first" || direction === "last" ) {
31447    next = this.active
31448     [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
31449     .eq( -1 );
31450   } else {
31451    next = this.active
31452     [ direction + "All" ]( ".ui-menu-item" )
31453     .eq( 0 );
31454   }
31455  }
31456  if ( !next || !next.length || !this.active ) {
31457   next = this.activeMenu.find( this.options.items )[ filter ]();
31458  }
31459  this.focus( event, next );
31460 },
31461 nextPage: function( event ) {
31462  var item, base, height;
31463  if ( !this.active ) {
31464   this.next( event );
31465   return;
31466  }
31467  if ( this.isLastItem() ) {
31468   return;
31469  }
31470  if ( this._hasScroll() ) {
31471   base = this.active.offset().top;
31472   height = this.element.height();
31473   this.active.nextAll( ".ui-menu-item" ).each( function() {
31474    item = $( this );
31475    return item.offset().top - base - height < 0;
31476   } );
31477   this.focus( event, item );
31478  } else {
31479   this.focus( event, this.activeMenu.find( this.options.items )
31480    [ !this.active ? "first" : "last" ]() );
31481  }
31482 },
31483 previousPage: function( event ) {
31484  var item, base, height;
31485  if ( !this.active ) {
31486   this.next( event );
31487   return;
31488  }
31489  if ( this.isFirstItem() ) {
31490   return;
31491  }
31492  if ( this._hasScroll() ) {
31493   base = this.active.offset().top;
31494   height = this.element.height();
31495   this.active.prevAll( ".ui-menu-item" ).each( function() {
31496    item = $( this );
31497    return item.offset().top - base + height > 0;
31498   } );
31499   this.focus( event, item );
31500  } else {
31501   this.focus( event, this.activeMenu.find( this.options.items ).first() );
31502  }
31503 },
31504 _hasScroll: function() {
31505  return this.element.outerHeight() < this.element.prop( "scrollHeight" );
31506 },
31507 select: function( event ) {
31508  // TODO: It should never be possible to not have an active item at this
31509  // point, but the tests don't trigger mouseenter before click.
31510  this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
31511  var ui = { item: this.active };
31512  if ( !this.active.has( ".ui-menu" ).length ) {
31513   this.collapseAll( event, true );
31514  }
31515  this._trigger( "select", event, ui );
31516 },
31517 _filterMenuItems: function( character ) {
31518  var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
31519   regex = new RegExp( "^" + escapedCharacter, "i" );
31520  return this.activeMenu
31521   .find( this.options.items )
31522    // Only match on items, not dividers or other content (#10571)
31523    .filter( ".ui-menu-item" )
31524     .filter( function() {
31525      return regex.test(
31526       $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
31527     } );
31528 }
31529} );
31530/*!
31531 * jQuery UI Autocomplete 1.12.1
31532 * http://jqueryui.com
31533 *
31534 * Copyright jQuery Foundation and other contributors
31535 * Released under the MIT license.
31536 * http://jquery.org/license
31537 */
31538//>>label: Autocomplete
31539//>>group: Widgets
31540//>>description: Lists suggested words as the user is typing.
31541//>>docs: http://api.jqueryui.com/autocomplete/
31542//>>demos: http://jqueryui.com/autocomplete/
31543//>>css.structure: ../../themes/base/core.css
31544//>>css.structure: ../../themes/base/autocomplete.css
31545//>>css.theme: ../../themes/base/theme.css
31546$.widget( "ui.autocomplete", {
31547 version: "1.12.1",
31548 defaultElement: "<input>",
31549 options: {
31550  appendTo: null,
31551  autoFocus: false,
31552  delay: 300,
31553  minLength: 1,
31554  position: {
31555   my: "left top",
31556   at: "left bottom",
31557   collision: "none"
31558  },
31559  source: null,
31560  // Callbacks
31561  change: null,
31562  close: null,
31563  focus: null,
31564  open: null,
31565  response: null,
31566  search: null,
31567  select: null
31568 },
31569 requestIndex: 0,
31570 pending: 0,
31571 _create: function() {
31572  // Some browsers only repeat keydown events, not keypress events,
31573  // so we use the suppressKeyPress flag to determine if we've already
31574  // handled the keydown event. #7269
31575  // Unfortunately the code for & in keypress is the same as the up arrow,
31576  // so we use the suppressKeyPressRepeat flag to avoid handling keypress
31577  // events when we know the keydown event was used to modify the
31578  // search term. #7799
31579  var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
31580   nodeName = this.element[ 0 ].nodeName.toLowerCase(),
31581   isTextarea = nodeName === "textarea",
31582   isInput = nodeName === "input";
31583  // Textareas are always multi-line
31584  // Inputs are always single-line, even if inside a contentEditable element
31585  // IE also treats inputs as contentEditable
31586  // All other element types are determined by whether or not they're contentEditable
31587  this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
31588  this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
31589  this.isNewMenu = true;
31590  this._addClass( "ui-autocomplete-input" );
31591  this.element.attr( "autocomplete", "off" );
31592  this._on( this.element, {
31593   keydown: function( event ) {
31594    if ( this.element.prop( "readOnly" ) ) {
31595     suppressKeyPress = true;
31596     suppressInput = true;
31597     suppressKeyPressRepeat = true;
31598     return;
31599    }
31600    suppressKeyPress = false;
31601    suppressInput = false;
31602    suppressKeyPressRepeat = false;
31603    var keyCode = $.ui.keyCode;
31604    switch ( event.keyCode ) {
31605    case keyCode.PAGE_UP:
31606     suppressKeyPress = true;
31607     this._move( "previousPage", event );
31608     break;
31609    case keyCode.PAGE_DOWN:
31610     suppressKeyPress = true;
31611     this._move( "nextPage", event );
31612     break;
31613    case keyCode.UP:
31614     suppressKeyPress = true;
31615     this._keyEvent( "previous", event );
31616     break;
31617    case keyCode.DOWN:
31618     suppressKeyPress = true;
31619     this._keyEvent( "next", event );
31620     break;
31621    case keyCode.ENTER:
31622     // when menu is open and has focus
31623     if ( this.menu.active ) {
31624      // #6055 - Opera still allows the keypress to occur
31625      // which causes forms to submit
31626      suppressKeyPress = true;
31627      event.preventDefault();
31628      this.menu.select( event );
31629     }
31630     break;
31631    case keyCode.TAB:
31632     if ( this.menu.active ) {
31633      this.menu.select( event );
31634     }
31635     break;
31636    case keyCode.ESCAPE:
31637     if ( this.menu.element.is( ":visible" ) ) {
31638      if ( !this.isMultiLine ) {
31639       this._value( this.term );
31640      }
31641      this.close( event );
31642      // Different browsers have different default behavior for escape
31643      // Single press can mean undo or clear
31644      // Double press in IE means clear the whole form
31645      event.preventDefault();
31646     }
31647     break;
31648    default:
31649     suppressKeyPressRepeat = true;
31650     // search timeout should be triggered before the input value is changed
31651     this._searchTimeout( event );
31652     break;
31653    }
31654   },
31655   keypress: function( event ) {
31656    if ( suppressKeyPress ) {
31657     suppressKeyPress = false;
31658     if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
31659      event.preventDefault();
31660     }
31661     return;
31662    }
31663    if ( suppressKeyPressRepeat ) {
31664     return;
31665    }
31666    // Replicate some key handlers to allow them to repeat in Firefox and Opera
31667    var keyCode = $.ui.keyCode;
31668    switch ( event.keyCode ) {
31669    case keyCode.PAGE_UP:
31670     this._move( "previousPage", event );
31671     break;
31672    case keyCode.PAGE_DOWN:
31673     this._move( "nextPage", event );
31674     break;
31675    case keyCode.UP:
31676     this._keyEvent( "previous", event );
31677     break;
31678    case keyCode.DOWN:
31679     this._keyEvent( "next", event );
31680     break;
31681    }
31682   },
31683   input: function( event ) {
31684    if ( suppressInput ) {
31685     suppressInput = false;
31686     event.preventDefault();
31687     return;
31688    }
31689    this._searchTimeout( event );
31690   },
31691   focus: function() {
31692    this.selectedItem = null;
31693    this.previous = this._value();
31694   },
31695   blur: function( event ) {
31696    if ( this.cancelBlur ) {
31697     delete this.cancelBlur;
31698     return;
31699    }
31700    clearTimeout( this.searching );
31701    this.close( event );
31702    this._change( event );
31703   }
31704  } );
31705  this._initSource();
31706  this.menu = $( "<ul>" )
31707   .appendTo( this._appendTo() )
31708   .menu( {
31709    // disable ARIA support, the live region takes care of that
31710    role: null
31711   } )
31712   .hide()
31713   .menu( "instance" );
31714  this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
31715  this._on( this.menu.element, {
31716   mousedown: function( event ) {
31717    // prevent moving focus out of the text field
31718    event.preventDefault();
31719    // IE doesn't prevent moving focus even with event.preventDefault()
31720    // so we set a flag to know when we should ignore the blur event
31721    this.cancelBlur = true;
31722    this._delay( function() {
31723     delete this.cancelBlur;
31724     // Support: IE 8 only
31725     // Right clicking a menu item or selecting text from the menu items will
31726     // result in focus moving out of the input. However, we've already received
31727     // and ignored the blur event because of the cancelBlur flag set above. So
31728     // we restore focus to ensure that the menu closes properly based on the user's
31729     // next actions.
31730     if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
31731      this.element.trigger( "focus" );
31732     }
31733    } );
31734   },
31735   menufocus: function( event, ui ) {
31736    var label, item;
31737    // support: Firefox
31738    // Prevent accidental activation of menu items in Firefox (#7024 #9118)
31739    if ( this.isNewMenu ) {
31740     this.isNewMenu = false;
31741     if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
31742      this.menu.blur();
31743      this.document.one( "mousemove", function() {
31744       $( event.target ).trigger( event.originalEvent );
31745      } );
31746      return;
31747     }
31748    }
31749    item = ui.item.data( "ui-autocomplete-item" );
31750    if ( false !== this._trigger( "focus", event, { item: item } ) ) {
31751     // use value to match what will end up in the input, if it was a key event
31752     if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
31753      this._value( item.value );
31754     }
31755    }
31756    // Announce the value in the liveRegion
31757    label = ui.item.attr( "aria-label" ) || item.value;
31758    if ( label && $.trim( label ).length ) {
31759     this.liveRegion.children().hide();
31760     $( "<div>" ).text( label ).appendTo( this.liveRegion );
31761    }
31762   },
31763   menuselect: function( event, ui ) {
31764    var item = ui.item.data( "ui-autocomplete-item" ),
31765     previous = this.previous;
31766    // Only trigger when focus was lost (click on menu)
31767    if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
31768     this.element.trigger( "focus" );
31769     this.previous = previous;
31770     // #6109 - IE triggers two focus events and the second
31771     // is asynchronous, so we need to reset the previous
31772     // term synchronously and asynchronously :-(
31773     this._delay( function() {
31774      this.previous = previous;
31775      this.selectedItem = item;
31776     } );
31777    }
31778    if ( false !== this._trigger( "select", event, { item: item } ) ) {
31779     this._value( item.value );
31780    }
31781    // reset the term after the select event
31782    // this allows custom select handling to work properly
31783    this.term = this._value();
31784    this.close( event );
31785    this.selectedItem = item;
31786   }
31787  } );
31788  this.liveRegion = $( "<div>", {
31789   role: "status",
31790   "aria-live": "assertive",
31791   "aria-relevant": "additions"
31792  } )
31793   .appendTo( this.document[ 0 ].body );
31794  this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
31795  // Turning off autocomplete prevents the browser from remembering the
31796  // value when navigating through history, so we re-enable autocomplete
31797  // if the page is unloaded before the widget is destroyed. #7790
31798  this._on( this.window, {
31799   beforeunload: function() {
31800    this.element.removeAttr( "autocomplete" );
31801   }
31802  } );
31803 },
31804 _destroy: function() {
31805  clearTimeout( this.searching );
31806  this.element.removeAttr( "autocomplete" );
31807  this.menu.element.remove();
31808  this.liveRegion.remove();
31809 },
31810 _setOption: function( key, value ) {
31811  this._super( key, value );
31812  if ( key === "source" ) {
31813   this._initSource();
31814  }
31815  if ( key === "appendTo" ) {
31816   this.menu.element.appendTo( this._appendTo() );
31817  }
31818  if ( key === "disabled" && value && this.xhr ) {
31819   this.xhr.abort();
31820  }
31821 },
31822 _isEventTargetInWidget: function( event ) {
31823  var menuElement = this.menu.element[ 0 ];
31824  return event.target === this.element[ 0 ] ||
31825   event.target === menuElement ||
31826   $.contains( menuElement, event.target );
31827 },
31828 _closeOnClickOutside: function( event ) {
31829  if ( !this._isEventTargetInWidget( event ) ) {
31830   this.close();
31831  }
31832 },
31833 _appendTo: function() {
31834  var element = this.options.appendTo;
31835  if ( element ) {
31836   element = element.jquery || element.nodeType ?
31837    $( element ) :
31838    this.document.find( element ).eq( 0 );
31839  }
31840  if ( !element || !element[ 0 ] ) {
31841   element = this.element.closest( ".ui-front, dialog" );
31842  }
31843  if ( !element.length ) {
31844   element = this.document[ 0 ].body;
31845  }
31846  return element;
31847 },
31848 _initSource: function() {
31849  var array, url,
31850   that = this;
31851  if ( $.isArray( this.options.source ) ) {
31852   array = this.options.source;
31853   this.source = function( request, response ) {
31854    response( $.ui.autocomplete.filter( array, request.term ) );
31855   };
31856  } else if ( typeof this.options.source === "string" ) {
31857   url = this.options.source;
31858   this.source = function( request, response ) {
31859    if ( that.xhr ) {
31860     that.xhr.abort();
31861    }
31862    that.xhr = $.ajax( {
31863     url: url,
31864     data: request,
31865     dataType: "json",
31866     success: function( data ) {
31867      response( data );
31868     },
31869     error: function() {
31870      response( [] );
31871     }
31872    } );
31873   };
31874  } else {
31875   this.source = this.options.source;
31876  }
31877 },
31878 _searchTimeout: function( event ) {
31879  clearTimeout( this.searching );
31880  this.searching = this._delay( function() {
31881   // Search if the value has changed, or if the user retypes the same value (see #7434)
31882   var equalValues = this.term === this._value(),
31883    menuVisible = this.menu.element.is( ":visible" ),
31884    modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
31885   if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
31886    this.selectedItem = null;
31887    this.search( null, event );
31888   }
31889  }, this.options.delay );
31890 },
31891 search: function( value, event ) {
31892  value = value != null ? value : this._value();
31893  // Always save the actual value, not the one passed as an argument
31894  this.term = this._value();
31895  if ( value.length < this.options.minLength ) {
31896   return this.close( event );
31897  }
31898  if ( this._trigger( "search", event ) === false ) {
31899   return;
31900  }
31901  return this._search( value );
31902 },
31903 _search: function( value ) {
31904  this.pending++;
31905  this._addClass( "ui-autocomplete-loading" );
31906  this.cancelSearch = false;
31907  this.source( { term: value }, this._response() );
31908 },
31909 _response: function() {
31910  var index = ++this.requestIndex;
31911  return $.proxy( function( content ) {
31912   if ( index === this.requestIndex ) {
31913    this.__response( content );
31914   }
31915   this.pending--;
31916   if ( !this.pending ) {
31917    this._removeClass( "ui-autocomplete-loading" );
31918   }
31919  }, this );
31920 },
31921 __response: function( content ) {
31922  if ( content ) {
31923   content = this._normalize( content );
31924  }
31925  this._trigger( "response", null, { content: content } );
31926  if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
31927   this._suggest( content );
31928   this._trigger( "open" );
31929  } else {
31930   // use ._close() instead of .close() so we don't cancel future searches
31931   this._close();
31932  }
31933 },
31934 close: function( event ) {
31935  this.cancelSearch = true;
31936  this._close( event );
31937 },
31938 _close: function( event ) {
31939  // Remove the handler that closes the menu on outside clicks
31940  this._off( this.document, "mousedown" );
31941  if ( this.menu.element.is( ":visible" ) ) {
31942   this.menu.element.hide();
31943   this.menu.blur();
31944   this.isNewMenu = true;
31945   this._trigger( "close", event );
31946  }
31947 },
31948 _change: function( event ) {
31949  if ( this.previous !== this._value() ) {
31950   this._trigger( "change", event, { item: this.selectedItem } );
31951  }
31952 },
31953 _normalize: function( items ) {
31954  // assume all items have the right format when the first item is complete
31955  if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
31956   return items;
31957  }
31958  return $.map( items, function( item ) {
31959   if ( typeof item === "string" ) {
31960    return {
31961     label: item,
31962     value: item
31963    };
31964   }
31965   return $.extend( {}, item, {
31966    label: item.label || item.value,
31967    value: item.value || item.label
31968   } );
31969  } );
31970 },
31971 _suggest: function( items ) {
31972  var ul = this.menu.element.empty();
31973  this._renderMenu( ul, items );
31974  this.isNewMenu = true;
31975  this.menu.refresh();
31976  // Size and position menu
31977  ul.show();
31978  this._resizeMenu();
31979  ul.position( $.extend( {
31980   of: this.element
31981  }, this.options.position ) );
31982  if ( this.options.autoFocus ) {
31983   this.menu.next();
31984  }
31985  // Listen for interactions outside of the widget (#6642)
31986  this._on( this.document, {
31987   mousedown: "_closeOnClickOutside"
31988  } );
31989 },
31990 _resizeMenu: function() {
31991  var ul = this.menu.element;
31992  ul.outerWidth( Math.max(
31993   // Firefox wraps long text (possibly a rounding bug)
31994   // so we add 1px to avoid the wrapping (#7513)
31995   ul.width( "" ).outerWidth() + 1,
31996   this.element.outerWidth()
31997  ) );
31998 },
31999 _renderMenu: function( ul, items ) {
32000  var that = this;
32001  $.each( items, function( index, item ) {
32002   that._renderItemData( ul, item );
32003  } );
32004 },
32005 _renderItemData: function( ul, item ) {
32006  return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
32007 },
32008 _renderItem: function( ul, item ) {
32009  return $( "<li>" )
32010   .append( $( "<div>" ).text( item.label ) )
32011   .appendTo( ul );
32012 },
32013 _move: function( direction, event ) {
32014  if ( !this.menu.element.is( ":visible" ) ) {
32015   this.search( null, event );
32016   return;
32017  }
32018  if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
32019    this.menu.isLastItem() && /^next/.test( direction ) ) {
32020   if ( !this.isMultiLine ) {
32021    this._value( this.term );
32022   }
32023   this.menu.blur();
32024   return;
32025  }
32026  this.menu[ direction ]( event );
32027 },
32028 widget: function() {
32029  return this.menu.element;
32030 },
32031 _value: function() {
32032  return this.valueMethod.apply( this.element, arguments );
32033 },
32034 _keyEvent: function( keyEvent, event ) {
32035  if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
32036   this._move( keyEvent, event );
32037   // Prevents moving cursor to beginning/end of the text field in some browsers
32038   event.preventDefault();
32039  }
32040 },
32041 // Support: Chrome <=50
32042 // We should be able to just use this.element.prop( "isContentEditable" )
32043 // but hidden elements always report false in Chrome.
32044 // https://code.google.com/p/chromium/issues/detail?id=313082
32045 _isContentEditable: function( element ) {
32046  if ( !element.length ) {
32047   return false;
32048  }
32049  var editable = element.prop( "contentEditable" );
32050  if ( editable === "inherit" ) {
32051    return this._isContentEditable( element.parent() );
32052  }
32053  return editable === "true";
32054 }
32055} );
32056$.extend( $.ui.autocomplete, {
32057 escapeRegex: function( value ) {
32058  return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
32059 },
32060 filter: function( array, term ) {
32061  var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
32062  return $.grep( array, function( value ) {
32063   return matcher.test( value.label || value.value || value );
32064  } );
32065 }
32066} );
32067// Live region extension, adding a `messages` option
32068// NOTE: This is an experimental API. We are still investigating
32069// a full solution for string manipulation and internationalization.
32070$.widget( "ui.autocomplete", $.ui.autocomplete, {
32071 options: {
32072  messages: {
32073   noResults: "No search results.",
32074   results: function( amount ) {
32075    return amount + ( amount > 1 ? " results are" : " result is" ) +
32076     " available, use up and down arrow keys to navigate.";
32077   }
32078  }
32079 },
32080 __response: function( content ) {
32081  var message;
32082  this._superApply( arguments );
32083  if ( this.options.disabled || this.cancelSearch ) {
32084   return;
32085  }
32086  if ( content && content.length ) {
32087   message = this.options.messages.results( content.length );
32088  } else {
32089   message = this.options.messages.noResults;
32090  }
32091  this.liveRegion.children().hide();
32092  $( "<div>" ).text( message ).appendTo( this.liveRegion );
32093 }
32094} );
32095var widgetsAutocomplete = $.ui.autocomplete;
32096// jscs:disable maximumLineLength
32097/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
32098/*!
32099 * jQuery UI Datepicker 1.12.1
32100 * http://jqueryui.com
32101 *
32102 * Copyright jQuery Foundation and other contributors
32103 * Released under the MIT license.
32104 * http://jquery.org/license
32105 */
32106//>>label: Datepicker
32107//>>group: Widgets
32108//>>description: Displays a calendar from an input or inline for selecting dates.
32109//>>docs: http://api.jqueryui.com/datepicker/
32110//>>demos: http://jqueryui.com/datepicker/
32111//>>css.structure: ../../themes/base/core.css
32112//>>css.structure: ../../themes/base/datepicker.css
32113//>>css.theme: ../../themes/base/theme.css
32114$.extend( $.ui, { datepicker: { version: "1.12.1" } } );
32115var datepicker_instActive;
32116function datepicker_getZindex( elem ) {
32117 var position, value;
32118 while ( elem.length && elem[ 0 ] !== document ) {
32119  // Ignore z-index if position is set to a value where z-index is ignored by the browser
32120  // This makes behavior of this function consistent across browsers
32121  // WebKit always returns auto if the element is positioned
32122  position = elem.css( "position" );
32123  if ( position === "absolute" || position === "relative" || position === "fixed" ) {
32124   // IE returns 0 when zIndex is not specified
32125   // other browsers return a string
32126   // we ignore the case of nested elements with an explicit value of 0
32127   // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
32128   value = parseInt( elem.css( "zIndex" ), 10 );
32129   if ( !isNaN( value ) && value !== 0 ) {
32130    return value;
32131   }
32132  }
32133  elem = elem.parent();
32134 }
32135 return 0;
32136}
32137/* Date picker manager.
32138   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
32139   Settings for (groups of) date pickers are maintained in an instance object,
32140   allowing multiple different settings on the same page. */
32141function Datepicker() {
32142 this._curInst = null; // The current instance in use
32143 this._keyEvent = false; // If the last event was a key event
32144 this._disabledInputs = []; // List of date picker inputs that have been disabled
32145 this._datepickerShowing = false; // True if the popup picker is showing , false if not
32146 this._inDialog = false; // True if showing within a "dialog", false if not
32147 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
32148 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
32149 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
32150 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
32151 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
32152 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
32153 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
32154 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
32155 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
32156 this.regional = []; // Available regional settings, indexed by language code
32157 this.regional[ "" ] = { // Default regional settings
32158  closeText: "Done", // Display text for close link
32159  prevText: "Prev", // Display text for previous month link
32160  nextText: "Next", // Display text for next month link
32161  currentText: "Today", // Display text for current month link
32162  monthNames: [ "January","February","March","April","May","June",
32163   "July","August","September","October","November","December" ], // Names of months for drop-down and formatting
32164  monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
32165  dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
32166  dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
32167  dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
32168  weekHeader: "Wk", // Column header for week of the year
32169  dateFormat: "mm/dd/yy", // See format options on parseDate
32170  firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
32171  isRTL: false, // True if right-to-left language, false if left-to-right
32172  showMonthAfterYear: false, // True if the year select precedes month, false for month then year
32173  yearSuffix: "" // Additional text to append to the year in the month headers
32174 };
32175 this._defaults = { // Global defaults for all the date picker instances
32176  showOn: "focus", // "focus" for popup on focus,
32177   // "button" for trigger button, or "both" for either
vendor: 6,618 bytes, lines 32178-32300
32178  showAnim: "fadeIn", // Name of jQuery animation for popup
32179  showOptions: {}, // Options for enhanced animations
32180  defaultDate: null, // Used when field is blank: actual date,
32181   // +/-number for offset from today, null for today
32182  appendText: "", // Display text following the input box, e.g. showing the format
32183  buttonText: "...", // Text for trigger button
32184  buttonImage: "", // URL for trigger button image
32185  buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
32186  hideIfNoPrevNext: false, // True to hide next/previous month links
32187   // if not applicable, false to just disable them
32188  navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
32189  gotoCurrent: false, // True if today link goes back to current selection instead
32190  changeMonth: false, // True if month can be selected directly, false if only prev/next
32191  changeYear: false, // True if year can be selected directly, false if only prev/next
32192  yearRange: "c-10:c+10", // Range of years to display in drop-down,
32193   // either relative to today's year (-nn:+nn), relative to currently displayed year
32194   // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
32195  showOtherMonths: false, // True to show dates in other months, false to leave blank
32196  selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
32197  showWeek: false, // True to show week of the year, false to not show it
32198  calculateWeek: this.iso8601Week, // How to calculate the week of the year,
32199   // takes a Date and returns the number of the week for it
32200  shortYearCutoff: "+10", // Short year values < this are in the current century,
32201   // > this are in the previous century,
32202   // string value starting with "+" for current year + value
32203  minDate: null, // The earliest selectable date, or null for no limit
32204  maxDate: null, // The latest selectable date, or null for no limit
32205  duration: "fast", // Duration of display/closure
32206  beforeShowDay: null, // Function that takes a date and returns an array with
32207   // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
32208   // [2] = cell title (optional), e.g. $.datepicker.noWeekends
32209  beforeShow: null, // Function that takes an input field and
32210   // returns a set of custom settings for the date picker
32211  onSelect: null, // Define a callback function when a date is selected
32212  onChangeMonthYear: null, // Define a callback function when the month or year is changed
32213  onClose: null, // Define a callback function when the datepicker is closed
32214  numberOfMonths: 1, // Number of months to show at a time
32215  showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
32216  stepMonths: 1, // Number of months to step back/forward
32217  stepBigMonths: 12, // Number of months to step back/forward for the big links
32218  altField: "", // Selector for an alternate field to store selected dates into
32219  altFormat: "", // The date format to use for the alternate field
32220  constrainInput: true, // The input is constrained by the current date format
32221  showButtonPanel: false, // True to show button panel, false to not show it
32222  autoSize: false, // True to size the input for the date format, false to leave as is
32223  disabled: false // The initial disabled state
32224 };
32225 $.extend( this._defaults, this.regional[ "" ] );
32226 this.regional.en = $.extend( true, {}, this.regional[ "" ] );
32227 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
32228 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
32229}
32230$.extend( Datepicker.prototype, {
32231 /* Class name added to elements to indicate already configured with a date picker. */
32232 markerClassName: "hasDatepicker",
32233 //Keep track of the maximum number of rows displayed (see #7043)
32234 maxRows: 4,
32235 // TODO rename to "widget" when switching to widget factory
32236 _widgetDatepicker: function() {
32237  return this.dpDiv;
32238 },
32239 /* Override the default settings for all instances of the date picker.
32240  * @param  settings  object - the new settings to use as defaults (anonymous object)
32241  * @return the manager object
32242  */
32243 setDefaults: function( settings ) {
32244  datepicker_extendRemove( this._defaults, settings || {} );
32245  return this;
32246 },
32247 /* Attach the date picker to a jQuery selection.
32248  * @param  target element - the target input field or division or span
32249  * @param  settings  object - the new settings to use for this date picker instance (anonymous)
32250  */
32251 _attachDatepicker: function( target, settings ) {
32252  var nodeName, inline, inst;
32253  nodeName = target.nodeName.toLowerCase();
32254  inline = ( nodeName === "div" || nodeName === "span" );
32255  if ( !target.id ) {
32256   this.uuid += 1;
32257   target.id = "dp" + this.uuid;
32258  }
32259  inst = this._newInst( $( target ), inline );
32260  inst.settings = $.extend( {}, settings || {} );
32261  if ( nodeName === "input" ) {
32262   this._connectDatepicker( target, inst );
32263  } else if ( inline ) {
32264   this._inlineDatepicker( target, inst );
32265  }
32266 },
32267 /* Create a new instance object. */
32268 _newInst: function( target, inline ) {
32269  var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
32270  return { id: id, input: target, // associated target
32271   selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
32272   drawMonth: 0, drawYear: 0, // month being drawn
32273   inline: inline, // is datepicker inline or not
32274   dpDiv: ( !inline ? this.dpDiv : // presentation div
32275   datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
32276 },
32277 /* Attach the date picker to an input field. */
32278 _connectDatepicker: function( target, inst ) {
32279  var input = $( target );
32280  inst.append = $( [] );
32281  inst.trigger = $( [] );
32282  if ( input.hasClass( this.markerClassName ) ) {
32283   return;
32284  }
32285  this._attachments( input, inst );
32286  input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
32287   on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
32288  this._autoSize( inst );
32289  $.data( target, "datepicker", inst );
32290  //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
32291  if ( inst.settings.disabled ) {
32292   this._disableDatepicker( target );
32293  }
32294 },
32295 /* Make attachments based on settings. */
32296 _attachments: function( input, inst ) {
32297  var showOn, buttonText, buttonImage,
32298   appendText = this._get( inst, "appendText" ),
32299   isRTL = this._get( inst, "isRTL" );
32300  if ( inst.append ) {
vendor: 6,019 bytes, lines 32301-32443
32301   inst.append.remove();
32302  }
32303  if ( appendText ) {
32304   inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
32305   input[ isRTL ? "before" : "after" ]( inst.append );
32306  }
32307  input.off( "focus", this._showDatepicker );
32308  if ( inst.trigger ) {
32309   inst.trigger.remove();
32310  }
32311  showOn = this._get( inst, "showOn" );
32312  if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
32313   input.on( "focus", this._showDatepicker );
32314  }
32315  if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
32316   buttonText = this._get( inst, "buttonText" );
32317   buttonImage = this._get( inst, "buttonImage" );
32318   inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
32319    $( "<img/>" ).addClass( this._triggerClass ).
32320     attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
32321    $( "<button type='button'></button>" ).addClass( this._triggerClass ).
32322     html( !buttonImage ? buttonText : $( "<img/>" ).attr(
32323     { src:buttonImage, alt:buttonText, title:buttonText } ) ) );
32324   input[ isRTL ? "before" : "after" ]( inst.trigger );
32325   inst.trigger.on( "click", function() {
32326    if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
32327     $.datepicker._hideDatepicker();
32328    } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
32329     $.datepicker._hideDatepicker();
32330     $.datepicker._showDatepicker( input[ 0 ] );
32331    } else {
32332     $.datepicker._showDatepicker( input[ 0 ] );
32333    }
32334    return false;
32335   } );
32336  }
32337 },
32338 /* Apply the maximum length for the date format. */
32339 _autoSize: function( inst ) {
32340  if ( this._get( inst, "autoSize" ) && !inst.inline ) {
32341   var findMax, max, maxI, i,
32342    date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
32343    dateFormat = this._get( inst, "dateFormat" );
32344   if ( dateFormat.match( /[DM]/ ) ) {
32345    findMax = function( names ) {
32346     max = 0;
32347     maxI = 0;
32348     for ( i = 0; i < names.length; i++ ) {
32349      if ( names[ i ].length > max ) {
32350       max = names[ i ].length;
32351       maxI = i;
32352      }
32353     }
32354     return maxI;
32355    };
32356    date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
32357     "monthNames" : "monthNamesShort" ) ) ) );
32358    date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
32359     "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
32360   }
32361   inst.input.attr( "size", this._formatDate( inst, date ).length );
32362  }
32363 },
32364 /* Attach an inline date picker to a div. */
32365 _inlineDatepicker: function( target, inst ) {
32366  var divSpan = $( target );
32367  if ( divSpan.hasClass( this.markerClassName ) ) {
32368   return;
32369  }
32370  divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
32371  $.data( target, "datepicker", inst );
32372  this._setDate( inst, this._getDefaultDate( inst ), true );
32373  this._updateDatepicker( inst );
32374  this._updateAlternate( inst );
32375  //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
32376  if ( inst.settings.disabled ) {
32377   this._disableDatepicker( target );
32378  }
32379  // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
32380  // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
32381  inst.dpDiv.css( "display", "block" );
32382 },
32383 /* Pop-up the date picker in a "dialog" box.
32384  * @param  input element - ignored
32385  * @param  date string or Date - the initial date to display
32386  * @param  onSelect  function - the function to call when a date is selected
32387  * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
32388  * @param  pos int[2] - coordinates for the dialog's position within the screen or
32389  *     event - with x/y coordinates or
32390  *     leave empty for default (screen centre)
32391  * @return the manager object
32392  */
32393 _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
32394  var id, browserWidth, browserHeight, scrollX, scrollY,
32395   inst = this._dialogInst; // internal instance
32396  if ( !inst ) {
32397   this.uuid += 1;
32398   id = "dp" + this.uuid;
32399   this._dialogInput = $( "<input type='text' id='" + id +
32400    "' style='position: absolute; top: -100px; width: 0px;'/>" );
32401   this._dialogInput.on( "keydown", this._doKeyDown );
32402   $( "body" ).append( this._dialogInput );
32403   inst = this._dialogInst = this._newInst( this._dialogInput, false );
32404   inst.settings = {};
32405   $.data( this._dialogInput[ 0 ], "datepicker", inst );
32406  }
32407  datepicker_extendRemove( inst.settings, settings || {} );
32408  date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
32409  this._dialogInput.val( date );
32410  this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
32411  if ( !this._pos ) {
32412   browserWidth = document.documentElement.clientWidth;
32413   browserHeight = document.documentElement.clientHeight;
32414   scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
32415   scrollY = document.documentElement.scrollTop || document.body.scrollTop;
32416   this._pos = // should use actual width/height below
32417    [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
32418  }
32419  // Move input on screen for focus, but hidden behind dialog
32420  this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
32421  inst.settings.onSelect = onSelect;
32422  this._inDialog = true;
32423  this.dpDiv.addClass( this._dialogClass );
32424  this._showDatepicker( this._dialogInput[ 0 ] );
32425  if ( $.blockUI ) {
32426   $.blockUI( this.dpDiv );
32427  }
32428  $.data( this._dialogInput[ 0 ], "datepicker", inst );
32429  return this;
32430 },
32431 /* Detach a datepicker from its control.
32432  * @param  target element - the target input field or division or span
32433  */
32434 _destroyDatepicker: function( target ) {
32435  var nodeName,
32436   $target = $( target ),
32437   inst = $.data( target, "datepicker" );
32438  if ( !$target.hasClass( this.markerClassName ) ) {
32439   return;
32440  }
32441  nodeName = target.nodeName.toLowerCase();
32442  $.removeData( target, "datepicker" );
32443  if ( nodeName === "input" ) {
vendor: 7,114 bytes, lines 32444-32635
32444   inst.append.remove();
32445   inst.trigger.remove();
32446   $target.removeClass( this.markerClassName ).
32447    off( "focus", this._showDatepicker ).
32448    off( "keydown", this._doKeyDown ).
32449    off( "keypress", this._doKeyPress ).
32450    off( "keyup", this._doKeyUp );
32451  } else if ( nodeName === "div" || nodeName === "span" ) {
32452   $target.removeClass( this.markerClassName ).empty();
32453  }
32454  if ( datepicker_instActive === inst ) {
32455   datepicker_instActive = null;
32456  }
32457 },
32458 /* Enable the date picker to a jQuery selection.
32459  * @param  target element - the target input field or division or span
32460  */
32461 _enableDatepicker: function( target ) {
32462  var nodeName, inline,
32463   $target = $( target ),
32464   inst = $.data( target, "datepicker" );
32465  if ( !$target.hasClass( this.markerClassName ) ) {
32466   return;
32467  }
32468  nodeName = target.nodeName.toLowerCase();
32469  if ( nodeName === "input" ) {
32470   target.disabled = false;
32471   inst.trigger.filter( "button" ).
32472    each( function() { this.disabled = false; } ).end().
32473    filter( "img" ).css( { opacity: "1.0", cursor: "" } );
32474  } else if ( nodeName === "div" || nodeName === "span" ) {
32475   inline = $target.children( "." + this._inlineClass );
32476   inline.children().removeClass( "ui-state-disabled" );
32477   inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
32478    prop( "disabled", false );
32479  }
32480  this._disabledInputs = $.map( this._disabledInputs,
32481   function( value ) { return ( value === target ? null : value ); } ); // delete entry
32482 },
32483 /* Disable the date picker to a jQuery selection.
32484  * @param  target element - the target input field or division or span
32485  */
32486 _disableDatepicker: function( target ) {
32487  var nodeName, inline,
32488   $target = $( target ),
32489   inst = $.data( target, "datepicker" );
32490  if ( !$target.hasClass( this.markerClassName ) ) {
32491   return;
32492  }
32493  nodeName = target.nodeName.toLowerCase();
32494  if ( nodeName === "input" ) {
32495   target.disabled = true;
32496   inst.trigger.filter( "button" ).
32497    each( function() { this.disabled = true; } ).end().
32498    filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
32499  } else if ( nodeName === "div" || nodeName === "span" ) {
32500   inline = $target.children( "." + this._inlineClass );
32501   inline.children().addClass( "ui-state-disabled" );
32502   inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
32503    prop( "disabled", true );
32504  }
32505  this._disabledInputs = $.map( this._disabledInputs,
32506   function( value ) { return ( value === target ? null : value ); } ); // delete entry
32507  this._disabledInputs[ this._disabledInputs.length ] = target;
32508 },
32509 /* Is the first field in a jQuery collection disabled as a datepicker?
32510  * @param  target element - the target input field or division or span
32511  * @return boolean - true if disabled, false if enabled
32512  */
32513 _isDisabledDatepicker: function( target ) {
32514  if ( !target ) {
32515   return false;
32516  }
32517  for ( var i = 0; i < this._disabledInputs.length; i++ ) {
32518   if ( this._disabledInputs[ i ] === target ) {
32519    return true;
32520   }
32521  }
32522  return false;
32523 },
32524 /* Retrieve the instance data for the target control.
32525  * @param  target  element - the target input field or division or span
32526  * @return  object - the associated instance data
32527  * @throws  error if a jQuery problem getting data
32528  */
32529 _getInst: function( target ) {
32530  try {
32531   return $.data( target, "datepicker" );
32532  }
32533  catch ( err ) {
32534   throw "Missing instance data for this datepicker";
32535  }
32536 },
32537 /* Update or retrieve the settings for a date picker attached to an input field or division.
32538  * @param  target  element - the target input field or division or span
32539  * @param  name object - the new settings to update or
32540  *    string - the name of the setting to change or retrieve,
32541  *    when retrieving also "all" for all instance settings or
32542  *    "defaults" for all global defaults
32543  * @param  value   any - the new value for the setting
32544  *    (omit if above is an object or to retrieve a value)
32545  */
32546 _optionDatepicker: function( target, name, value ) {
32547  var settings, date, minDate, maxDate,
32548   inst = this._getInst( target );
32549  if ( arguments.length === 2 && typeof name === "string" ) {
32550   return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
32551    ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
32552    this._get( inst, name ) ) : null ) );
32553  }
32554  settings = name || {};
32555  if ( typeof name === "string" ) {
32556   settings = {};
32557   settings[ name ] = value;
32558  }
32559  if ( inst ) {
32560   if ( this._curInst === inst ) {
32561    this._hideDatepicker();
32562   }
32563   date = this._getDateDatepicker( target, true );
32564   minDate = this._getMinMaxDate( inst, "min" );
32565   maxDate = this._getMinMaxDate( inst, "max" );
32566   datepicker_extendRemove( inst.settings, settings );
32567   // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
32568   if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
32569    inst.settings.minDate = this._formatDate( inst, minDate );
32570   }
32571   if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
32572    inst.settings.maxDate = this._formatDate( inst, maxDate );
32573   }
32574   if ( "disabled" in settings ) {
32575    if ( settings.disabled ) {
32576     this._disableDatepicker( target );
32577    } else {
32578     this._enableDatepicker( target );
32579    }
32580   }
32581   this._attachments( $( target ), inst );
32582   this._autoSize( inst );
32583   this._setDate( inst, date );
32584   this._updateAlternate( inst );
32585   this._updateDatepicker( inst );
32586  }
32587 },
32588 // Change method deprecated
32589 _changeDatepicker: function( target, name, value ) {
32590  this._optionDatepicker( target, name, value );
32591 },
32592 /* Redraw the date picker attached to an input field or division.
32593  * @param  target  element - the target input field or division or span
32594  */
32595 _refreshDatepicker: function( target ) {
32596  var inst = this._getInst( target );
32597  if ( inst ) {
32598   this._updateDatepicker( inst );
32599  }
32600 },
32601 /* Set the dates for a jQuery selection.
32602  * @param  target element - the target input field or division or span
32603  * @param  date Date - the new date
32604  */
32605 _setDateDatepicker: function( target, date ) {
32606  var inst = this._getInst( target );
32607  if ( inst ) {
32608   this._setDate( inst, date );
32609   this._updateDatepicker( inst );
32610   this._updateAlternate( inst );
32611  }
32612 },
32613 /* Get the date(s) for the first entry in a jQuery selection.
32614  * @param  target element - the target input field or division or span
32615  * @param  noDefault boolean - true if no default date is to be used
32616  * @return Date - the current date
32617  */
32618 _getDateDatepicker: function( target, noDefault ) {
32619  var inst = this._getInst( target );
32620  if ( inst && !inst.inline ) {
32621   this._setDateFromField( inst, noDefault );
32622  }
32623  return ( inst ? this._getDate( inst ) : null );
32624 },
32625 /* Handle keystrokes. */
32626 _doKeyDown: function( event ) {
32627  var onSelect, dateStr, sel,
32628   inst = $.datepicker._getInst( event.target ),
32629   handled = true,
32630   isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
32631  inst._keyEvent = true;
32632  if ( $.datepicker._datepickerShowing ) {
32633   switch ( event.keyCode ) {
32634    case 9: $.datepicker._hideDatepicker();
32635      handled = false;
vendor: 4,621 bytes, lines 32636-32749
32636      break; // hide on tab out
32637    case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
32638         $.datepicker._currentClass + ")", inst.dpDiv );
32639      if ( sel[ 0 ] ) {
32640       $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
32641      }
32642      onSelect = $.datepicker._get( inst, "onSelect" );
32643      if ( onSelect ) {
32644       dateStr = $.datepicker._formatDate( inst );
32645       // Trigger custom callback
32646       onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
32647      } else {
32648       $.datepicker._hideDatepicker();
32649      }
32650      return false; // don't submit the form
32651    case 27: $.datepicker._hideDatepicker();
32652      break; // hide on escape
32653    case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
32654       -$.datepicker._get( inst, "stepBigMonths" ) :
32655       -$.datepicker._get( inst, "stepMonths" ) ), "M" );
32656      break; // previous month/year on page up/+ ctrl
32657    case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
32658       +$.datepicker._get( inst, "stepBigMonths" ) :
32659       +$.datepicker._get( inst, "stepMonths" ) ), "M" );
32660      break; // next month/year on page down/+ ctrl
32661    case 35: if ( event.ctrlKey || event.metaKey ) {
32662       $.datepicker._clearDate( event.target );
32663      }
32664      handled = event.ctrlKey || event.metaKey;
32665      break; // clear on ctrl or command +end
32666    case 36: if ( event.ctrlKey || event.metaKey ) {
32667       $.datepicker._gotoToday( event.target );
32668      }
32669      handled = event.ctrlKey || event.metaKey;
32670      break; // current on ctrl or command +home
32671    case 37: if ( event.ctrlKey || event.metaKey ) {
32672       $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
32673      }
32674      handled = event.ctrlKey || event.metaKey;
32675      // -1 day on ctrl or command +left
32676      if ( event.originalEvent.altKey ) {
32677       $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
32678        -$.datepicker._get( inst, "stepBigMonths" ) :
32679        -$.datepicker._get( inst, "stepMonths" ) ), "M" );
32680      }
32681      // next month/year on alt +left on Mac
32682      break;
32683    case 38: if ( event.ctrlKey || event.metaKey ) {
32684       $.datepicker._adjustDate( event.target, -7, "D" );
32685      }
32686      handled = event.ctrlKey || event.metaKey;
32687      break; // -1 week on ctrl or command +up
32688    case 39: if ( event.ctrlKey || event.metaKey ) {
32689       $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
32690      }
32691      handled = event.ctrlKey || event.metaKey;
32692      // +1 day on ctrl or command +right
32693      if ( event.originalEvent.altKey ) {
32694       $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
32695        +$.datepicker._get( inst, "stepBigMonths" ) :
32696        +$.datepicker._get( inst, "stepMonths" ) ), "M" );
32697      }
32698      // next month/year on alt +right
32699      break;
32700    case 40: if ( event.ctrlKey || event.metaKey ) {
32701       $.datepicker._adjustDate( event.target, +7, "D" );
32702      }
32703      handled = event.ctrlKey || event.metaKey;
32704      break; // +1 week on ctrl or command +down
32705    default: handled = false;
32706   }
32707  } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
32708   $.datepicker._showDatepicker( this );
32709  } else {
32710   handled = false;
32711  }
32712  if ( handled ) {
32713   event.preventDefault();
32714   event.stopPropagation();
32715  }
32716 },
32717 /* Filter entered characters - based on date format. */
32718 _doKeyPress: function( event ) {
32719  var chars, chr,
32720   inst = $.datepicker._getInst( event.target );
32721  if ( $.datepicker._get( inst, "constrainInput" ) ) {
32722   chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
32723   chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
32724   return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
32725  }
32726 },
32727 /* Synchronise manual entry and field/alternate field. */
32728 _doKeyUp: function( event ) {
32729  var date,
32730   inst = $.datepicker._getInst( event.target );
32731  if ( inst.input.val() !== inst.lastVal ) {
32732   try {
32733    date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
32734     ( inst.input ? inst.input.val() : null ),
32735     $.datepicker._getFormatConfig( inst ) );
32736    if ( date ) { // only if valid
32737     $.datepicker._setDateFromField( inst );
32738     $.datepicker._updateAlternate( inst );
32739     $.datepicker._updateDatepicker( inst );
32740    }
32741   }
32742   catch ( err ) {
32743   }
32744  }
32745  return true;
32746 },
32747 /* Pop-up the date picker for a given input field.
32748  * If false returned from beforeShow event handler do not show.
32749  * @param  input  element - the input field attached to the date picker or
vendor: 4,237 bytes, lines 32750-32849
32750  *     event - if triggered by focus
32751  */
32752 _showDatepicker: function( input ) {
32753  input = input.target || input;
32754  if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
32755   input = $( "input", input.parentNode )[ 0 ];
32756  }
32757  if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
32758   return;
32759  }
32760  var inst, beforeShow, beforeShowSettings, isFixed,
32761   offset, showAnim, duration;
32762  inst = $.datepicker._getInst( input );
32763  if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
32764   $.datepicker._curInst.dpDiv.stop( true, true );
32765   if ( inst && $.datepicker._datepickerShowing ) {
32766    $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
32767   }
32768  }
32769  beforeShow = $.datepicker._get( inst, "beforeShow" );
32770  beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
32771  if ( beforeShowSettings === false ) {
32772   return;
32773  }
32774  datepicker_extendRemove( inst.settings, beforeShowSettings );
32775  inst.lastVal = null;
32776  $.datepicker._lastInput = input;
32777  $.datepicker._setDateFromField( inst );
32778  if ( $.datepicker._inDialog ) { // hide cursor
32779   input.value = "";
32780  }
32781  if ( !$.datepicker._pos ) { // position below input
32782   $.datepicker._pos = $.datepicker._findPos( input );
32783   $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
32784  }
32785  isFixed = false;
32786  $( input ).parents().each( function() {
32787   isFixed |= $( this ).css( "position" ) === "fixed";
32788   return !isFixed;
32789  } );
32790  offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
32791  $.datepicker._pos = null;
32792  //to avoid flashes on Firefox
32793  inst.dpDiv.empty();
32794  // determine sizing offscreen
32795  inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
32796  $.datepicker._updateDatepicker( inst );
32797  // fix width for dynamic number of date pickers
32798  // and adjust position before showing
32799  offset = $.datepicker._checkOffset( inst, offset, isFixed );
32800  inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
32801   "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
32802   left: offset.left + "px", top: offset.top + "px" } );
32803  if ( !inst.inline ) {
32804   showAnim = $.datepicker._get( inst, "showAnim" );
32805   duration = $.datepicker._get( inst, "duration" );
32806   inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
32807   $.datepicker._datepickerShowing = true;
32808   if ( $.effects && $.effects.effect[ showAnim ] ) {
32809    inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
32810   } else {
32811    inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
32812   }
32813   if ( $.datepicker._shouldFocusInput( inst ) ) {
32814    inst.input.trigger( "focus" );
32815   }
32816   $.datepicker._curInst = inst;
32817  }
32818 },
32819 /* Generate the date picker content. */
32820 _updateDatepicker: function( inst ) {
32821  this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
32822  datepicker_instActive = inst; // for delegate hover events
32823  inst.dpDiv.empty().append( this._generateHTML( inst ) );
32824  this._attachHandlers( inst );
32825  var origyearshtml,
32826   numMonths = this._getNumberOfMonths( inst ),
32827   cols = numMonths[ 1 ],
32828   width = 17,
32829   activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
32830  if ( activeCell.length > 0 ) {
32831   datepicker_handleMouseover.apply( activeCell.get( 0 ) );
32832  }
32833  inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
32834  if ( cols > 1 ) {
32835   inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
32836  }
32837  inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
32838   "Class" ]( "ui-datepicker-multi" );
32839  inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
32840   "Class" ]( "ui-datepicker-rtl" );
32841  if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
32842   inst.input.trigger( "focus" );
32843  }
32844  // Deffered render of the years select (to avoid flashes on Firefox)
32845  if ( inst.yearshtml ) {
32846   origyearshtml = inst.yearshtml;
32847   setTimeout( function() {
32848    //assure that inst.yearshtml didn't change.
32849    if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
vendor: 5,456 bytes, lines 32850-32982
32850     inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
32851    }
32852    origyearshtml = inst.yearshtml = null;
32853   }, 0 );
32854  }
32855 },
32856 // #6694 - don't focus the input if it's already focused
32857 // this breaks the change event in IE
32858 // Support: IE and jQuery <1.9
32859 _shouldFocusInput: function( inst ) {
32860  return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
32861 },
32862 /* Check positioning to remain on screen. */
32863 _checkOffset: function( inst, offset, isFixed ) {
32864  var dpWidth = inst.dpDiv.outerWidth(),
32865   dpHeight = inst.dpDiv.outerHeight(),
32866   inputWidth = inst.input ? inst.input.outerWidth() : 0,
32867   inputHeight = inst.input ? inst.input.outerHeight() : 0,
32868   viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
32869   viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
32870  offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
32871  offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
32872  offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
32873  // Now check if datepicker is showing outside window viewport - move to a better place if so.
32874  offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
32875   Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
32876  offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
32877   Math.abs( dpHeight + inputHeight ) : 0 );
32878  return offset;
32879 },
32880 /* Find an object's position on the screen. */
32881 _findPos: function( obj ) {
32882  var position,
32883   inst = this._getInst( obj ),
32884   isRTL = this._get( inst, "isRTL" );
32885  while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
32886   obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
32887  }
32888  position = $( obj ).offset();
32889  return [ position.left, position.top ];
32890 },
32891 /* Hide the date picker from view.
32892  * @param  input  element - the input field attached to the date picker
32893  */
32894 _hideDatepicker: function( input ) {
32895  var showAnim, duration, postProcess, onClose,
32896   inst = this._curInst;
32897  if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
32898   return;
32899  }
32900  if ( this._datepickerShowing ) {
32901   showAnim = this._get( inst, "showAnim" );
32902   duration = this._get( inst, "duration" );
32903   postProcess = function() {
32904    $.datepicker._tidyDialog( inst );
32905   };
32906   // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
32907   if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
32908    inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
32909   } else {
32910    inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
32911     ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
32912   }
32913   if ( !showAnim ) {
32914    postProcess();
32915   }
32916   this._datepickerShowing = false;
32917   onClose = this._get( inst, "onClose" );
32918   if ( onClose ) {
32919    onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
32920   }
32921   this._lastInput = null;
32922   if ( this._inDialog ) {
32923    this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
32924    if ( $.blockUI ) {
32925     $.unblockUI();
32926     $( "body" ).append( this.dpDiv );
32927    }
32928   }
32929   this._inDialog = false;
32930  }
32931 },
32932 /* Tidy up after a dialog display. */
32933 _tidyDialog: function( inst ) {
32934  inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
32935 },
32936 /* Close date picker if clicked elsewhere. */
32937 _checkExternalClick: function( event ) {
32938  if ( !$.datepicker._curInst ) {
32939   return;
32940  }
32941  var $target = $( event.target ),
32942   inst = $.datepicker._getInst( $target[ 0 ] );
32943  if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
32944    $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
32945    !$target.hasClass( $.datepicker.markerClassName ) &&
32946    !$target.closest( "." + $.datepicker._triggerClass ).length &&
32947    $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
32948   ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
32949    $.datepicker._hideDatepicker();
32950  }
32951 },
32952 /* Adjust one of the date sub-fields. */
32953 _adjustDate: function( id, offset, period ) {
32954  var target = $( id ),
32955   inst = this._getInst( target[ 0 ] );
32956  if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
32957   return;
32958  }
32959  this._adjustInstDate( inst, offset +
32960   ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
32961   period );
32962  this._updateDatepicker( inst );
32963 },
32964 /* Action for current link. */
32965 _gotoToday: function( id ) {
32966  var date,
32967   target = $( id ),
32968   inst = this._getInst( target[ 0 ] );
32969  if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
32970   inst.selectedDay = inst.currentDay;
32971   inst.drawMonth = inst.selectedMonth = inst.currentMonth;
32972   inst.drawYear = inst.selectedYear = inst.currentYear;
32973  } else {
32974   date = new Date();
32975   inst.selectedDay = date.getDate();
32976   inst.drawMonth = inst.selectedMonth = date.getMonth();
32977   inst.drawYear = inst.selectedYear = date.getFullYear();
32978  }
32979  this._notifyChange( inst );
32980  this._adjustDate( target );
32981 },
32982 /* Action for selecting a new month/year. */
vendor: 4,554 bytes, lines 32983-33095
32983 _selectMonthYear: function( id, select, period ) {
32984  var target = $( id ),
32985   inst = this._getInst( target[ 0 ] );
32986  inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
32987  inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
32988   parseInt( select.options[ select.selectedIndex ].value, 10 );
32989  this._notifyChange( inst );
32990  this._adjustDate( target );
32991 },
32992 /* Action for selecting a day. */
32993 _selectDay: function( id, month, year, td ) {
32994  var inst,
32995   target = $( id );
32996  if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
32997   return;
32998  }
32999  inst = this._getInst( target[ 0 ] );
33000  inst.selectedDay = inst.currentDay = $( "a", td ).html();
33001  inst.selectedMonth = inst.currentMonth = month;
33002  inst.selectedYear = inst.currentYear = year;
33003  this._selectDate( id, this._formatDate( inst,
33004   inst.currentDay, inst.currentMonth, inst.currentYear ) );
33005 },
33006 /* Erase the input field and hide the date picker. */
33007 _clearDate: function( id ) {
33008  var target = $( id );
33009  this._selectDate( target, "" );
33010 },
33011 /* Update the input field with the selected date. */
33012 _selectDate: function( id, dateStr ) {
33013  var onSelect,
33014   target = $( id ),
33015   inst = this._getInst( target[ 0 ] );
33016  dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
33017  if ( inst.input ) {
33018   inst.input.val( dateStr );
33019  }
33020  this._updateAlternate( inst );
33021  onSelect = this._get( inst, "onSelect" );
33022  if ( onSelect ) {
33023   onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );  // trigger custom callback
33024  } else if ( inst.input ) {
33025   inst.input.trigger( "change" ); // fire the change event
33026  }
33027  if ( inst.inline ) {
33028   this._updateDatepicker( inst );
33029  } else {
33030   this._hideDatepicker();
33031   this._lastInput = inst.input[ 0 ];
33032   if ( typeof( inst.input[ 0 ] ) !== "object" ) {
33033    inst.input.trigger( "focus" ); // restore focus
33034   }
33035   this._lastInput = null;
33036  }
33037 },
33038 /* Update any alternate field to synchronise with the main field. */
33039 _updateAlternate: function( inst ) {
33040  var altFormat, date, dateStr,
33041   altField = this._get( inst, "altField" );
33042  if ( altField ) { // update alternate field too
33043   altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
33044   date = this._getDate( inst );
33045   dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
33046   $( altField ).val( dateStr );
33047  }
33048 },
33049 /* Set as beforeShowDay function to prevent selection of weekends.
33050  * @param  date  Date - the date to customise
33051  * @return [boolean, string] - is this date selectable?, what is its CSS class?
33052  */
33053 noWeekends: function( date ) {
33054  var day = date.getDay();
33055  return [ ( day > 0 && day < 6 ), "" ];
33056 },
33057 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
33058  * @param  date  Date - the date to get the week for
33059  * @return  number - the number of the week within the year that contains this date
33060  */
33061 iso8601Week: function( date ) {
33062  var time,
33063   checkDate = new Date( date.getTime() );
33064  // Find Thursday of this week starting on Monday
33065  checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
33066  time = checkDate.getTime();
33067  checkDate.setMonth( 0 ); // Compare with Jan 1
33068  checkDate.setDate( 1 );
33069  return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
33070 },
33071 /* Parse a string value into a date object.
33072  * See formatDate below for the possible formats.
33073  *
33074  * @param  format string - the expected format of the date
33075  * @param  value string - the date in the above format
33076  * @param  settings Object - attributes include:
33077  *     shortYearCutoff  number - the cutoff year for determining the century (optional)
33078  *     dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
33079  *     dayNames  string[7] - names of the days from Sunday (optional)
33080  *     monthNamesShort string[12] - abbreviated names of the months (optional)
33081  *     monthNames  string[12] - names of the months (optional)
33082  * @return  Date - the extracted date value or null if value is blank
33083  */
33084 parseDate: function( format, value, settings ) {
33085  if ( format == null || value == null ) {
33086   throw "Invalid arguments";
33087  }
33088  value = ( typeof value === "object" ? value.toString() : value + "" );
33089  if ( value === "" ) {
33090   return null;
33091  }
33092  var iFormat, dim, extra,
33093   iValue = 0,
33094   shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
33095   shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp 
vendor: 16,955 bytes, lines 33095-33588
33095:
33096    new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
33097   dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
33098   dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
33099   monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
33100   monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
33101   year = -1,
33102   month = -1,
33103   day = -1,
33104   doy = -1,
33105   literal = false,
33106   date,
33107   // Check whether a format character is doubled
33108   lookAhead = function( match ) {
33109    var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
33110    if ( matches ) {
33111     iFormat++;
33112    }
33113    return matches;
33114   },
33115   // Extract a number from the string value
33116   getNumber = function( match ) {
33117    var isDoubled = lookAhead( match ),
33118     size = ( match === "@" ? 14 : ( match === "!" ? 20 :
33119     ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
33120     minSize = ( match === "y" ? size : 1 ),
33121     digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
33122     num = value.substring( iValue ).match( digits );
33123    if ( !num ) {
33124     throw "Missing number at position " + iValue;
33125    }
33126    iValue += num[ 0 ].length;
33127    return parseInt( num[ 0 ], 10 );
33128   },
33129   // Extract a name from the string value and convert to an index
33130   getName = function( match, shortNames, longNames ) {
33131    var index = -1,
33132     names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
33133      return [ [ k, v ] ];
33134     } ).sort( function( a, b ) {
33135      return -( a[ 1 ].length - b[ 1 ].length );
33136     } );
33137    $.each( names, function( i, pair ) {
33138     var name = pair[ 1 ];
33139     if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
33140      index = pair[ 0 ];
33141      iValue += name.length;
33142      return false;
33143     }
33144    } );
33145    if ( index !== -1 ) {
33146     return index + 1;
33147    } else {
33148     throw "Unknown name at position " + iValue;
33149    }
33150   },
33151   // Confirm that a literal character matches the string value
33152   checkLiteral = function() {
33153    if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
33154     throw "Unexpected literal at position " + iValue;
33155    }
33156    iValue++;
33157   };
33158  for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
33159   if ( literal ) {
33160    if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
33161     literal = false;
33162    } else {
33163     checkLiteral();
33164    }
33165   } else {
33166    switch ( format.charAt( iFormat ) ) {
33167     case "d":
33168      day = getNumber( "d" );
33169      break;
33170     case "D":
33171      getName( "D", dayNamesShort, dayNames );
33172      break;
33173     case "o":
33174      doy = getNumber( "o" );
33175      break;
33176     case "m":
33177      month = getNumber( "m" );
33178      break;
33179     case "M":
33180      month = getName( "M", monthNamesShort, monthNames );
33181      break;
33182     case "y":
33183      year = getNumber( "y" );
33184      break;
33185     case "@":
33186      date = new Date( getNumber( "@" ) );
33187      year = date.getFullYear();
33188      month = date.getMonth() + 1;
33189      day = date.getDate();
33190      break;
33191     case "!":
33192      date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
33193      year = date.getFullYear();
33194      month = date.getMonth() + 1;
33195      day = date.getDate();
33196      break;
33197     case "'":
33198      if ( lookAhead( "'" ) ) {
33199       checkLiteral();
33200      } else {
33201       literal = true;
33202      }
33203      break;
33204     default:
33205      checkLiteral();
33206    }
33207   }
33208  }
33209  if ( iValue < value.length ) {
33210   extra = value.substr( iValue );
33211   if ( !/^\s+/.test( extra ) ) {
33212    throw "Extra/unparsed characters found in date: " + extra;
33213   }
33214  }
33215  if ( year === -1 ) {
33216   year = new Date().getFullYear();
33217  } else if ( year < 100 ) {
33218   year += new Date().getFullYear() - new Date().getFullYear() % 100 +
33219    ( year <= shortYearCutoff ? 0 : -100 );
33220  }
33221  if ( doy > -1 ) {
33222   month = 1;
33223   day = doy;
33224   do {
33225    dim = this._getDaysInMonth( year, month - 1 );
33226    if ( day <= dim ) {
33227     break;
33228    }
33229    month++;
33230    day -= dim;
33231   } while ( true );
33232  }
33233  date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
33234  if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
33235   throw "Invalid date"; // E.g. 31/02/00
33236  }
33237  return date;
33238 },
33239 /* Standard date formats. */
33240 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
33241 COOKIE: "D, dd M yy",
33242 ISO_8601: "yy-mm-dd",
33243 RFC_822: "D, d M y",
33244 RFC_850: "DD, dd-M-y",
33245 RFC_1036: "D, d M y",
33246 RFC_1123: "D, d M yy",
33247 RFC_2822: "D, d M yy",
33248 RSS: "D, d M y", // RFC 822
33249 TICKS: "!",
33250 TIMESTAMP: "@",
33251 W3C: "yy-mm-dd", // ISO 8601
33252 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
33253  Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
33254 /* Format a date object into a string value.
33255  * The format can be combinations of the following:
33256  * d  - day of month (no leading zero)
33257  * dd - day of month (two digit)
33258  * o  - day of year (no leading zeros)
33259  * oo - day of year (three digit)
33260  * D  - day name short
33261  * DD - day name long
33262  * m  - month of year (no leading zero)
33263  * mm - month of year (two digit)
33264  * M  - month name short
33265  * MM - month name long
33266  * y  - year (two digit)
33267  * yy - year (four digit)
33268  * @ - Unix timestamp (ms since 01/01/1970)
33269  * ! - Windows ticks (100ns since 01/01/0001)
33270  * "..." - literal text
33271  * '' - single quote
33272  *
33273  * @param  format string - the desired format of the date
33274  * @param  date Date - the date value to format
33275  * @param  settings Object - attributes include:
33276  *     dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
33277  *     dayNames  string[7] - names of the days from Sunday (optional)
33278  *     monthNamesShort string[12] - abbreviated names of the months (optional)
33279  *     monthNames  string[12] - names of the months (optional)
33280  * @return  string - the date in the above format
33281  */
33282 formatDate: function( format, date, settings ) {
33283  if ( !date ) {
33284   return "";
33285  }
33286  var iFormat,
33287   dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
33288   dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
33289   monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
33290   monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
33291   // Check whether a format character is doubled
33292   lookAhead = function( match ) {
33293    var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
33294    if ( matches ) {
33295     iFormat++;
33296    }
33297    return matches;
33298   },
33299   // Format a number, with leading zero if necessary
33300   formatNumber = function( match, value, len ) {
33301    var num = "" + value;
33302    if ( lookAhead( match ) ) {
33303     while ( num.length < len ) {
33304      num = "0" + num;
33305     }
33306    }
33307    return num;
33308   },
33309   // Format a name, short or long as requested
33310   formatName = function( match, value, shortNames, longNames ) {
33311    return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
33312   },
33313   output = "",
33314   literal = false;
33315  if ( date ) {
33316   for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
33317    if ( literal ) {
33318     if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
33319      literal = false;
33320     } else {
33321      output += format.charAt( iFormat );
33322     }
33323    } else {
33324     switch ( format.charAt( iFormat ) ) {
33325      case "d":
33326       output += formatNumber( "d", date.getDate(), 2 );
33327       break;
33328      case "D":
33329       output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
33330       break;
33331      case "o":
33332       output += formatNumber( "o",
33333        Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
33334       break;
33335      case "m":
33336       output += formatNumber( "m", date.getMonth() + 1, 2 );
33337       break;
33338      case "M":
33339       output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
33340       break;
33341      case "y":
33342       output += ( lookAhead( "y" ) ? date.getFullYear() :
33343        ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
33344       break;
33345      case "@":
33346       output += date.getTime();
33347       break;
33348      case "!":
33349       output += date.getTime() * 10000 + this._ticksTo1970;
33350       break;
33351      case "'":
33352       if ( lookAhead( "'" ) ) {
33353        output += "'";
33354       } else {
33355        literal = true;
33356       }
33357       break;
33358      default:
33359       output += format.charAt( iFormat );
33360     }
33361    }
33362   }
33363  }
33364  return output;
33365 },
33366 /* Extract all possible characters from the date format. */
33367 _possibleChars: function( format ) {
33368  var iFormat,
33369   chars = "",
33370   literal = false,
33371   // Check whether a format character is doubled
33372   lookAhead = function( match ) {
33373    var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
33374    if ( matches ) {
33375     iFormat++;
33376    }
33377    return matches;
33378   };
33379  for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
33380   if ( literal ) {
33381    if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
33382     literal = false;
33383    } else {
33384     chars += format.charAt( iFormat );
33385    }
33386   } else {
33387    switch ( format.charAt( iFormat ) ) {
33388     case "d": case "m": case "y": case "@":
33389      chars += "0123456789";
33390      break;
33391     case "D": case "M":
33392      return null; // Accept anything
33393     case "'":
33394      if ( lookAhead( "'" ) ) {
33395       chars += "'";
33396      } else {
33397       literal = true;
33398      }
33399      break;
33400     default:
33401      chars += format.charAt( iFormat );
33402    }
33403   }
33404  }
33405  return chars;
33406 },
33407 /* Get a setting value, defaulting if necessary. */
33408 _get: function( inst, name ) {
33409  return inst.settings[ name ] !== undefined ?
33410   inst.settings[ name ] : this._defaults[ name ];
33411 },
33412 /* Parse existing date and initialise date picker. */
33413 _setDateFromField: function( inst, noDefault ) {
33414  if ( inst.input.val() === inst.lastVal ) {
33415   return;
33416  }
33417  var dateFormat = this._get( inst, "dateFormat" ),
33418   dates = inst.lastVal = inst.input ? inst.input.val() : null,
33419   defaultDate = this._getDefaultDate( inst ),
33420   date = defaultDate,
33421   settings = this._getFormatConfig( inst );
33422  try {
33423   date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
33424  } catch ( event ) {
33425   dates = ( noDefault ? "" : dates );
33426  }
33427  inst.selectedDay = date.getDate();
33428  inst.drawMonth = inst.selectedMonth = date.getMonth();
33429  inst.drawYear = inst.selectedYear = date.getFullYear();
33430  inst.currentDay = ( dates ? date.getDate() : 0 );
33431  inst.currentMonth = ( dates ? date.getMonth() : 0 );
33432  inst.currentYear = ( dates ? date.getFullYear() : 0 );
33433  this._adjustInstDate( inst );
33434 },
33435 /* Retrieve the default date shown on opening. */
33436 _getDefaultDate: function( inst ) {
33437  return this._restrictMinMax( inst,
33438   this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
33439 },
33440 /* A date may be specified as an exact value or a relative one. */
33441 _determineDate: function( inst, date, defaultDate ) {
33442  var offsetNumeric = function( offset ) {
33443    var date = new Date();
33444    date.setDate( date.getDate() + offset );
33445    return date;
33446   },
33447   offsetString = function( offset ) {
33448    try {
33449     return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
33450      offset, $.datepicker._getFormatConfig( inst ) );
33451    }
33452    catch ( e ) {
33453     // Ignore
33454    }
33455    var date = ( offset.toLowerCase().match( /^c/ ) ?
33456     $.datepicker._getDate( inst ) : null ) || new Date(),
33457     year = date.getFullYear(),
33458     month = date.getMonth(),
33459     day = date.getDate(),
33460     pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
33461     matches = pattern.exec( offset );
33462    while ( matches ) {
33463     switch ( matches[ 2 ] || "d" ) {
33464      case "d" : case "D" :
33465       day += parseInt( matches[ 1 ], 10 ); break;
33466      case "w" : case "W" :
33467       day += parseInt( matches[ 1 ], 10 ) * 7; break;
33468      case "m" : case "M" :
33469       month += parseInt( matches[ 1 ], 10 );
33470       day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
33471       break;
33472      case "y": case "Y" :
33473       year += parseInt( matches[ 1 ], 10 );
33474       day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
33475       break;
33476     }
33477     matches = pattern.exec( offset );
33478    }
33479    return new Date( year, month, day );
33480   },
33481   newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
33482    ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
33483  newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
33484  if ( newDate ) {
33485   newDate.setHours( 0 );
33486   newDate.setMinutes( 0 );
33487   newDate.setSeconds( 0 );
33488   newDate.setMilliseconds( 0 );
33489  }
33490  return this._daylightSavingAdjust( newDate );
33491 },
33492 /* Handle switch to/from daylight saving.
33493  * Hours may be non-zero on daylight saving cut-over:
33494  * > 12 when midnight changeover, but then cannot generate
33495  * midnight datetime, so jump to 1AM, otherwise reset.
33496  * @param  date  (Date) the date to check
33497  * @return  (Date) the corrected date
33498  */
33499 _daylightSavingAdjust: function( date ) {
33500  if ( !date ) {
33501   return null;
33502  }
33503  date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
33504  return date;
33505 },
33506 /* Set the date(s) directly. */
33507 _setDate: function( inst, date, noChange ) {
33508  var clear = !date,
33509   origMonth = inst.selectedMonth,
33510   origYear = inst.selectedYear,
33511   newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
33512  inst.selectedDay = inst.currentDay = newDate.getDate();
33513  inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
33514  inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
33515  if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
33516   this._notifyChange( inst );
33517  }
33518  this._adjustInstDate( inst );
33519  if ( inst.input ) {
33520   inst.input.val( clear ? "" : this._formatDate( inst ) );
33521  }
33522 },
33523 /* Retrieve the date(s) directly. */
33524 _getDate: function( inst ) {
33525  var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
33526   this._daylightSavingAdjust( new Date(
33527   inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
33528   return startDate;
33529 },
33530 /* Attach the onxxx handlers.  These are declared statically so
33531  * they work with static code transformers like Caja.
33532  */
33533 _attachHandlers: function( inst ) {
33534  var stepMonths = this._get( inst, "stepMonths" ),
33535   id = "#" + inst.id.replace( /\\\\/g, "\\" );
33536  inst.dpDiv.find( "[data-handler]" ).map( function() {
33537   var handler = {
33538    prev: function() {
33539     $.datepicker._adjustDate( id, -stepMonths, "M" );
33540    },
33541    next: function() {
33542     $.datepicker._adjustDate( id, +stepMonths, "M" );
33543    },
33544    hide: function() {
33545     $.datepicker._hideDatepicker();
33546    },
33547    today: function() {
33548     $.datepicker._gotoToday( id );
33549    },
33550    selectDay: function() {
33551     $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
33552     return false;
33553    },
33554    selectMonth: function() {
33555     $.datepicker._selectMonthYear( id, this, "M" );
33556     return false;
33557    },
33558    selectYear: function() {
33559     $.datepicker._selectMonthYear( id, this, "Y" );
33560     return false;
33561    }
33562   };
33563   $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
33564  } );
33565 },
33566 /* Generate the HTML for the current state of the date picker. */
33567 _generateHTML: function( inst ) {
33568  var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
33569   controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
33570   monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
33571   selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
33572   cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
33573   printDate, dRow, tbody, daySettings, otherMonth, unselectable,
33574   tempDate = new Date(),
33575   today = this._daylightSavingAdjust(
33576    new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
33577   isRTL = this._get( inst, "isRTL" ),
33578   showButtonPanel = this._get( inst, "showButtonPanel" ),
33579   hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
33580   navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
33581   numMonths = this._getNumberOfMonths( inst ),
33582   showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
33583   stepMonths = this._get( inst, "stepMonths" ),
33584   isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
33585   currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
33586    new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
33587   minDate = this._getMinMaxDate( inst, "min" ),
33588   maxDate = this._getMinMaxDate( inst, "max" ),
vendor: 4,147 bytes, lines 33589-33657
33589   drawMonth = inst.drawMonth - showCurrentAtPos,
33590   drawYear = inst.drawYear;
33591  if ( drawMonth < 0 ) {
33592   drawMonth += 12;
33593   drawYear--;
33594  }
33595  if ( maxDate ) {
33596   maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
33597    maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
33598   maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
33599   while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
33600    drawMonth--;
33601    if ( drawMonth < 0 ) {
33602     drawMonth = 11;
33603     drawYear--;
33604    }
33605   }
33606  }
33607  inst.drawMonth = drawMonth;
33608  inst.drawYear = drawYear;
33609  prevText = this._get( inst, "prevText" );
33610  prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
33611   this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
33612   this._getFormatConfig( inst ) ) );
33613  prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
33614   "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
33615   " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
33616   ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) );
33617  nextText = this._get( inst, "nextText" );
33618  nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
33619   this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
33620   this._getFormatConfig( inst ) ) );
33621  next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
33622   "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
33623   " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
33624   ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) );
33625  currentText = this._get( inst, "currentText" );
33626  gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
33627  currentText = ( !navigationAsDateFormat ? currentText :
33628   this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
33629  controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
33630   this._get( inst, "closeText" ) + "</button>" : "" );
33631  buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
33632   ( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
33633   ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
33634  firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
33635  firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
33636  showWeek = this._get( inst, "showWeek" );
33637  dayNames = this._get( inst, "dayNames" );
33638  dayNamesMin = this._get( inst, "dayNamesMin" );
33639  monthNames = this._get( inst, "monthNames" );
33640  monthNamesShort = this._get( inst, "monthNamesShort" );
33641  beforeShowDay = this._get( inst, "beforeShowDay" );
33642  showOtherMonths = this._get( inst, "showOtherMonths" );
33643  selectOtherMonths = this._get( inst, "selectOtherMonths" );
33644  defaultDate = this._getDefaultDate( inst );
33645  html = "";
33646  for ( row = 0; row < numMonths[ 0 ]; row++ ) {
33647   group = "";
33648   this.maxRows = 4;
33649   for ( col = 0; col < numMonths[ 1 ]; col++ ) {
33650    selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
33651    cornerClass = " ui-corner-all";
33652    calender = "";
33653    if ( isMultiMonth ) {
33654     calender += "<div class='ui-datepicker-group";
33655     if ( numMonths[ 1 ] > 1 ) {
33656      switch ( col ) {
33657       case 0: calender += " ui-datepicker-group-first";
vendor: 5,221 bytes, lines 33658-33735
33658        cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
33659       case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
33660        cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
33661       default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
33662      }
33663     }
33664     calender += "'>";
33665    }
33666    calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
33667     ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
33668     ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
33669     this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
33670     row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
33671     "</div><table class='ui-datepicker-calendar'><thead>" +
33672     "<tr>";
33673    thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
33674    for ( dow = 0; dow < 7; dow++ ) { // days of the week
33675     day = ( dow + firstDay ) % 7;
33676     thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
33677      "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
33678    }
33679    calender += thead + "</tr></thead><tbody>";
33680    daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
33681    if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
33682     inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
33683    }
33684    leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
33685    curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
33686    numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
33687    this.maxRows = numRows;
33688    printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
33689    for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
33690     calender += "<tr>";
33691     tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
33692      this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
33693     for ( dow = 0; dow < 7; dow++ ) { // create date picker days
33694      daySettings = ( beforeShowDay ?
33695       beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
33696      otherMonth = ( printDate.getMonth() !== drawMonth );
33697      unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
33698       ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
33699      tbody += "<td class='" +
33700       ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
33701       ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
33702       ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
33703       ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
33704       // or defaultDate is current printedDate and defaultDate is selectedDate
33705       " " + this._dayOverClass : "" ) + // highlight selected day
33706       ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) +  // highlight unselectable days
33707       ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
33708       ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
33709       ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
33710       ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
33711       ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
33712       ( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
33713       ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
33714       ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
33715       ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
33716       ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
33717       "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
33718      printDate.setDate( printDate.getDate() + 1 );
33719      printDate = this._daylightSavingAdjust( printDate );
33720     }
33721     calender += tbody + "</tr>";
33722    }
33723    drawMonth++;
33724    if ( drawMonth > 11 ) {
33725     drawMonth = 0;
33726     drawYear++;
33727    }
33728    calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
33729       ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
33730    group += calender;
33731   }
33732   html += group;
33733  }
33734  html += buttonPanel;
33735  inst._keyEvent = false;
vendor: 4,316 bytes, lines 33736-33833
33736  return html;
33737 },
33738 /* Generate the month and year header. */
33739 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
33740   secondary, monthNames, monthNamesShort ) {
33741  var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
33742   changeMonth = this._get( inst, "changeMonth" ),
33743   changeYear = this._get( inst, "changeYear" ),
33744   showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
33745   html = "<div class='ui-datepicker-title'>",
33746   monthHtml = "";
33747  // Month selection
33748  if ( secondary || !changeMonth ) {
33749   monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
33750  } else {
33751   inMinYear = ( minDate && minDate.getFullYear() === drawYear );
33752   inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
33753   monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
33754   for ( month = 0; month < 12; month++ ) {
33755    if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
33756     monthHtml += "<option value='" + month + "'" +
33757      ( month === drawMonth ? " selected='selected'" : "" ) +
33758      ">" + monthNamesShort[ month ] + "</option>";
33759    }
33760   }
33761   monthHtml += "</select>";
33762  }
33763  if ( !showMonthAfterYear ) {
33764   html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
33765  }
33766  // Year selection
33767  if ( !inst.yearshtml ) {
33768   inst.yearshtml = "";
33769   if ( secondary || !changeYear ) {
33770    html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
33771   } else {
33772    // determine range of years to display
33773    years = this._get( inst, "yearRange" ).split( ":" );
33774    thisYear = new Date().getFullYear();
33775    determineYear = function( value ) {
33776     var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
33777      ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
33778      parseInt( value, 10 ) ) );
33779     return ( isNaN( year ) ? thisYear : year );
33780    };
33781    year = determineYear( years[ 0 ] );
33782    endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
33783    year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
33784    endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
33785    inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
33786    for ( ; year <= endYear; year++ ) {
33787     inst.yearshtml += "<option value='" + year + "'" +
33788      ( year === drawYear ? " selected='selected'" : "" ) +
33789      ">" + year + "</option>";
33790    }
33791    inst.yearshtml += "</select>";
33792    html += inst.yearshtml;
33793    inst.yearshtml = null;
33794   }
33795  }
33796  html += this._get( inst, "yearSuffix" );
33797  if ( showMonthAfterYear ) {
33798   html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
33799  }
33800  html += "</div>"; // Close datepicker_header
33801  return html;
33802 },
33803 /* Adjust one of the date sub-fields. */
33804 _adjustInstDate: function( inst, offset, period ) {
33805  var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
33806   month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
33807   day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
33808   date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
33809  inst.selectedDay = date.getDate();
33810  inst.drawMonth = inst.selectedMonth = date.getMonth();
33811  inst.drawYear = inst.selectedYear = date.getFullYear();
33812  if ( period === "M" || period === "Y" ) {
33813   this._notifyChange( inst );
33814  }
33815 },
33816 /* Ensure a date is within any min/max bounds. */
33817 _restrictMinMax: function( inst, date ) {
33818  var minDate = this._getMinMaxDate( inst, "min" ),
33819   maxDate = this._getMinMaxDate( inst, "max" ),
33820   newDate = ( minDate && date < minDate ? minDate : date );
33821  return ( maxDate && newDate > maxDate ? maxDate : newDate );
33822 },
33823 /* Notify change of month/year. */
33824 _notifyChange: function( inst ) {
33825  var onChange = this._get( inst, "onChangeMonthYear" );
33826  if ( onChange ) {
33827   onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
33828    [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
33829  }
33830 },
33831 /* Determine the number of months to show. */
33832 _getNumberOfMonths: function( inst ) {
33833  var numMonths = this._get( inst, "numberOfMonths" );
vendor: 6,339 bytes, lines 33834-33980
33834  return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
33835 },
33836 /* Determine the current maximum date - ensure no time components are set. */
33837 _getMinMaxDate: function( inst, minMax ) {
33838  return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
33839 },
33840 /* Find the number of days in a given month. */
33841 _getDaysInMonth: function( year, month ) {
33842  return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
33843 },
33844 /* Find the day of the week of the first of a month. */
33845 _getFirstDayOfMonth: function( year, month ) {
33846  return new Date( year, month, 1 ).getDay();
33847 },
33848 /* Determines if we should allow a "next/prev" month display change. */
33849 _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
33850  var numMonths = this._getNumberOfMonths( inst ),
33851   date = this._daylightSavingAdjust( new Date( curYear,
33852   curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
33853  if ( offset < 0 ) {
33854   date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
33855  }
33856  return this._isInRange( inst, date );
33857 },
33858 /* Is the given date in the accepted range? */
33859 _isInRange: function( inst, date ) {
33860  var yearSplit, currentYear,
33861   minDate = this._getMinMaxDate( inst, "min" ),
33862   maxDate = this._getMinMaxDate( inst, "max" ),
33863   minYear = null,
33864   maxYear = null,
33865   years = this._get( inst, "yearRange" );
33866   if ( years ) {
33867    yearSplit = years.split( ":" );
33868    currentYear = new Date().getFullYear();
33869    minYear = parseInt( yearSplit[ 0 ], 10 );
33870    maxYear = parseInt( yearSplit[ 1 ], 10 );
33871    if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
33872     minYear += currentYear;
33873    }
33874    if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
33875     maxYear += currentYear;
33876    }
33877   }
33878  return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
33879   ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
33880   ( !minYear || date.getFullYear() >= minYear ) &&
33881   ( !maxYear || date.getFullYear() <= maxYear ) );
33882 },
33883 /* Provide the configuration settings for formatting/parsing. */
33884 _getFormatConfig: function( inst ) {
33885  var shortYearCutoff = this._get( inst, "shortYearCutoff" );
33886  shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
33887   new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
33888  return { shortYearCutoff: shortYearCutoff,
33889   dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
33890   monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
33891 },
33892 /* Format the given date for display. */
33893 _formatDate: function( inst, day, month, year ) {
33894  if ( !day ) {
33895   inst.currentDay = inst.selectedDay;
33896   inst.currentMonth = inst.selectedMonth;
33897   inst.currentYear = inst.selectedYear;
33898  }
33899  var date = ( day ? ( typeof day === "object" ? day :
33900   this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
33901   this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
33902  return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
33903 }
33904} );
33905/*
33906 * Bind hover events for datepicker elements.
33907 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
33908 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
33909 */
33910function datepicker_bindHover( dpDiv ) {
33911 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
33912 return dpDiv.on( "mouseout", selector, function() {
33913   $( this ).removeClass( "ui-state-hover" );
33914   if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
33915    $( this ).removeClass( "ui-datepicker-prev-hover" );
33916   }
33917   if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
33918    $( this ).removeClass( "ui-datepicker-next-hover" );
33919   }
33920  } )
33921  .on( "mouseover", selector, datepicker_handleMouseover );
33922}
33923function datepicker_handleMouseover() {
33924 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
33925  $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
33926  $( this ).addClass( "ui-state-hover" );
33927  if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
33928   $( this ).addClass( "ui-datepicker-prev-hover" );
33929  }
33930  if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
33931   $( this ).addClass( "ui-datepicker-next-hover" );
33932  }
33933 }
33934}
33935/* jQuery extend now ignores nulls! */
33936function datepicker_extendRemove( target, props ) {
33937 $.extend( target, props );
33938 for ( var name in props ) {
33939  if ( props[ name ] == null ) {
33940   target[ name ] = props[ name ];
33941  }
33942 }
33943 return target;
33944}
33945/* Invoke the datepicker functionality.
33946   @param  options  string - a command, optionally followed by additional parameters or
33947     Object - settings for attaching new datepicker functionality
33948   @return  jQuery object */
33949$.fn.datepicker = function( options ) {
33950 /* Verify an empty collection wasn't passed - Fixes #6976 */
33951 if ( !this.length ) {
33952  return this;
33953 }
33954 /* Initialise the date picker. */
33955 if ( !$.datepicker.initialized ) {
33956  $( document ).on( "mousedown", $.datepicker._checkExternalClick );
33957  $.datepicker.initialized = true;
33958 }
33959 /* Append datepicker main container to body if not exist. */
33960 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
33961  $( "body" ).append( $.datepicker.dpDiv );
33962 }
33963 var otherArgs = Array.prototype.slice.call( arguments, 1 );
33964 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
33965  return $.datepicker[ "_" + options + "Datepicker" ].
33966   apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
33967 }
33968 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
33969  return $.datepicker[ "_" + options + "Datepicker" ].
33970   apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
33971 }
33972 return this.each( function() {
33973  typeof options === "string" ?
33974   $.datepicker[ "_" + options + "Datepicker" ].
33975    apply( $.datepicker, [ this ].concat( otherArgs ) ) :
33976   $.datepicker._attachDatepicker( this, options );
33977 } );
33978};
33979$.datepicker = new Datepicker(); // singleton instance
33980$.datepicker.initialized = false;
vendor: 69,710 bytes, lines 33981-36002
33981$.datepicker.uuid = new Date().getTime();
33982$.datepicker.version = "1.12.1";
33983var widgetsDatepicker = $.datepicker;
33984}));
33985
33986   /* Ende jqueryUI */
33987   /* Start slick */
33988   /*
33989 _ _      _       _
33990 ___| (_) ___| | __  (_)___
33991 / __| | |/ __| |/ /  | / __|
33992 \__ \ | | (__|   < _ | \__ \
33993 |___/_|_|\___|_|\_(_)/ |___/
33994 |__/
33995 Version: 1.6.0
33996 Author: Ken Wheeler
33997 Website: http://kenwheeler.github.io
33998 Docs: http://kenwheeler.github.io/slick
33999 Repo: http://github.com/kenwheeler/slick
34000 Issues: http://github.com/kenwheeler/slick/issues
34001 */
34002/* global window, document, define, jQuery, setInterval, clearInterval */
34003(function(factory) {
34004  'use strict';
34005  if (typeof define === 'function' && define.amd) {
34006    define(['jquery'], factory);
34007  } else if (typeof exports !== 'undefined') {
34008    module.exports = factory(require('jquery'));
34009  } else {
34010    factory(jQuery);
34011  }
34012}(function($) {
34013  'use strict';
34014  var Slick = window.Slick || {};
34015  Slick = (function() {
34016    var instanceUid = 0;
34017    function Slick(element, settings) {
34018      var _ = this, dataSettings;
34019      _.defaults = {
34020        accessibility: true,
34021        adaptiveHeight: false,
34022        appendArrows: $(element),
34023        appendDots: $(element),
34024        arrows: true,
34025        asNavFor: null,
34026        prevArrow: '<button type="button" data-role="none" class="slick-prev" aria-label="Previous" tabindex="0" role="button">Previous</button>',
34027        nextArrow: '<button type="button" data-role="none" class="slick-next" aria-label="Next" tabindex="0" role="button">Next</button>',
34028        autoplay: false,
34029        autoplaySpeed: 3000,
34030        centerMode: false,
34031        centerPadding: '50px',
34032        cssEase: 'ease',
34033        customPaging: function(slider, i) {
34034          return $('<button type="button" data-role="none" role="button" tabindex="0" />').text(i + 1);
34035        },
34036        dots: false,
34037        dotsClass: 'slick-dots',
34038        draggable: true,
34039        easing: 'linear',
34040        edgeFriction: 0.35,
34041        fade: false,
34042        focusOnSelect: false,
34043        infinite: true,
34044        initialSlide: 0,
34045        lazyLoad: 'ondemand',
34046        mobileFirst: false,
34047        pauseOnHover: true,
34048        pauseOnFocus: true,
34049        pauseOnDotsHover: false,
34050        respondTo: 'window',
34051        responsive: null,
34052        rows: 1,
34053        rtl: false,
34054        slide: '',
34055        slidesPerRow: 1,
34056        slidesToShow: 1,
34057        slidesToScroll: 1,
34058        speed: 500,
34059        swipe: true,
34060        swipeToSlide: false,
34061        touchMove: true,
34062        touchThreshold: 5,
34063        useCSS: true,
34064        useTransform: true,
34065        variableWidth: false,
34066        vertical: false,
34067        verticalSwiping: false,
34068        waitForAnimate: true,
34069        zIndex: 1000
34070      };
34071      _.initials = {
34072        animating: false,
34073        dragging: false,
34074        autoPlayTimer: null,
34075        currentDirection: 0,
34076        currentLeft: null,
34077        currentSlide: 0,
34078        direction: 1,
34079        $dots: null,
34080        listWidth: null,
34081        listHeight: null,
34082        loadIndex: 0,
34083        $nextArrow: null,
34084        $prevArrow: null,
34085        slideCount: null,
34086        slideWidth: null,
34087        $slideTrack: null,
34088        $slides: null,
34089        sliding: false,
34090        slideOffset: 0,
34091        swipeLeft: null,
34092        $list: null,
34093        touchObject: {},
34094        transformsEnabled: false,
34095        unslicked: false
34096      };
34097      $.extend(_, _.initials);
34098      _.activeBreakpoint = null;
34099      _.animType = null;
34100      _.animProp = null;
34101      _.breakpoints = [];
34102      _.breakpointSettings = [];
34103      _.cssTransitions = false;
34104      _.focussed = false;
34105      _.interrupted = false;
34106      _.hidden = 'hidden';
34107      _.paused = true;
34108      _.positionProp = null;
34109      _.respondTo = null;
34110      _.rowCount = 1;
34111      _.shouldClick = true;
34112      _.$slider = $(element);
34113      _.$slidesCache = null;
34114      _.transformType = null;
34115      _.transitionType = null;
34116      _.visibilityChange = 'visibilitychange';
34117      _.windowWidth = 0;
34118      _.windowTimer = null;
34119      dataSettings = $(element).data('slick') || {};
34120      _.options = $.extend({}, _.defaults, settings, dataSettings);
34121      _.currentSlide = _.options.initialSlide;
34122      _.originalSettings = _.options;
34123      if (typeof document.mozHidden !== 'undefined') {
34124        _.hidden = 'mozHidden';
34125        _.visibilityChange = 'mozvisibilitychange';
34126      } else if (typeof document.webkitHidden !== 'undefined') {
34127        _.hidden = 'webkitHidden';
34128        _.visibilityChange = 'webkitvisibilitychange';
34129      }
34130      _.autoPlay = $.proxy(_.autoPlay, _);
34131      _.autoPlayClear = $.proxy(_.autoPlayClear, _);
34132      _.autoPlayIterator = $.proxy(_.autoPlayIterator, _);
34133      _.changeSlide = $.proxy(_.changeSlide, _);
34134      _.clickHandler = $.proxy(_.clickHandler, _);
34135      _.selectHandler = $.proxy(_.selectHandler, _);
34136      _.setPosition = $.proxy(_.setPosition, _);
34137      _.swipeHandler = $.proxy(_.swipeHandler, _);
34138      _.dragHandler = $.proxy(_.dragHandler, _);
34139      _.keyHandler = $.proxy(_.keyHandler, _);
34140      _.instanceUid = instanceUid++;
34141      // A simple way to check for HTML strings
34142      // Strict HTML recognition (must start with <)
34143      // Extracted from jQuery v1.11 source
34144      _.htmlExpr = /^(?:\s*(<[\w\W]+>)[^>]*)$/;
34145      _.registerBreakpoints();
34146      _.init(true);
34147    }
34148    return Slick;
34149  }());
34150  Slick.prototype.activateADA = function() {
34151    var _ = this;
34152    _.$slideTrack.find('.slick-active').attr({
34153      'aria-hidden': 'false'
34154    }).find('a, input, button, select').attr({
34155      'tabindex': '0'
34156    });
34157  };
34158  Slick.prototype.addSlide = Slick.prototype.slickAdd = function(markup, index, addBefore) {
34159    var _ = this;
34160    if (typeof(index) === 'boolean') {
34161      addBefore = index;
34162      index = null;
34163    } else if (index < 0 || (index >= _.slideCount)) {
34164      return false;
34165    }
34166    _.unload();
34167    if (typeof(index) === 'number') {
34168      if (index === 0 && _.$slides.length === 0) {
34169        $(markup).appendTo(_.$slideTrack);
34170      } else if (addBefore) {
34171        $(markup).insertBefore(_.$slides.eq(index));
34172      } else {
34173        $(markup).insertAfter(_.$slides.eq(index));
34174      }
34175    } else {
34176      if (addBefore === true) {
34177        $(markup).prependTo(_.$slideTrack);
34178      } else {
34179        $(markup).appendTo(_.$slideTrack);
34180      }
34181    }
34182    _.$slides = _.$slideTrack.children(this.options.slide);
34183    _.$slideTrack.children(this.options.slide).detach();
34184    _.$slideTrack.append(_.$slides);
34185    _.$slides.each(function(index, element) {
34186      $(element).attr('data-slick-index', index);
34187    });
34188    _.$slidesCache = _.$slides;
34189    _.reinit();
34190  };
34191  Slick.prototype.animateHeight = function() {
34192    var _ = this;
34193    if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {
34194      var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);
34195      _.$list.animate({
34196        height: targetHeight
34197      }, _.options.speed);
34198    }
34199  };
34200  Slick.prototype.animateSlide = function(targetLeft, callback) {
34201    var animProps = {},
34202      _ = this;
34203    _.animateHeight();
34204    if (_.options.rtl === true && _.options.vertical === false) {
34205      targetLeft = -targetLeft;
34206    }
34207    if (_.transformsEnabled === false) {
34208      if (_.options.vertical === false) {
34209        _.$slideTrack.animate({
34210          left: targetLeft
34211        }, _.options.speed, _.options.easing, callback);
34212      } else {
34213        _.$slideTrack.animate({
34214          top: targetLeft
34215        }, _.options.speed, _.options.easing, callback);
34216      }
34217    } else {
34218      if (_.cssTransitions === false) {
34219        if (_.options.rtl === true) {
34220          _.currentLeft = -(_.currentLeft);
34221        }
34222        $({
34223          animStart: _.currentLeft
34224        }).animate({
34225          animStart: targetLeft
34226        }, {
34227          duration: _.options.speed,
34228          easing: _.options.easing,
34229          step: function(now) {
34230            now = Math.ceil(now);
34231            if (_.options.vertical === false) {
34232              animProps[_.animType] = 'translate(' +
34233                now + 'px, 0px)';
34234              _.$slideTrack.css(animProps);
34235            } else {
34236              animProps[_.animType] = 'translate(0px,' +
34237                now + 'px)';
34238              _.$slideTrack.css(animProps);
34239            }
34240          },
34241          complete: function() {
34242            if (callback) {
34243              callback.call();
34244            }
34245          }
34246        });
34247      } else {
34248        _.applyTransition();
34249        targetLeft = Math.ceil(targetLeft);
34250        if (_.options.vertical === false) {
34251          animProps[_.animType] = 'translate3d(' + targetLeft + 'px, 0px, 0px)';
34252        } else {
34253          animProps[_.animType] = 'translate3d(0px,' + targetLeft + 'px, 0px)';
34254        }
34255        _.$slideTrack.css(animProps);
34256        if (callback) {
34257          setTimeout(function() {
34258            _.disableTransition();
34259            callback.call();
34260          }, _.options.speed);
34261        }
34262      }
34263    }
34264  };
34265  Slick.prototype.getNavTarget = function() {
34266    var _ = this,
34267      asNavFor = _.options.asNavFor;
34268    if ( asNavFor && asNavFor !== null ) {
34269      asNavFor = $(asNavFor).not(_.$slider);
34270    }
34271    return asNavFor;
34272  };
34273  Slick.prototype.asNavFor = function(index) {
34274    var _ = this,
34275      asNavFor = _.getNavTarget();
34276    if ( asNavFor !== null && typeof asNavFor === 'object' ) {
34277      asNavFor.each(function() {
34278        var target = $(this).slick('getSlick');
34279        if(!target.unslicked) {
34280          target.slideHandler(index, true);
34281        }
34282      });
34283    }
34284  };
34285  Slick.prototype.applyTransition = function(slide) {
34286    var _ = this,
34287      transition = {};
34288    if (_.options.fade === false) {
34289      transition[_.transitionType] = _.transformType + ' ' + _.options.speed + 'ms ' + _.options.cssEase;
34290    } else {
34291      transition[_.transitionType] = 'opacity ' + _.options.speed + 'ms ' + _.options.cssEase;
34292    }
34293    if (_.options.fade === false) {
34294      _.$slideTrack.css(transition);
34295    } else {
34296      _.$slides.eq(slide).css(transition);
34297    }
34298  };
34299  Slick.prototype.autoPlay = function() {
34300    var _ = this;
34301    _.autoPlayClear();
34302    if ( _.slideCount > _.options.slidesToShow ) {
34303      _.autoPlayTimer = setInterval( _.autoPlayIterator, _.options.autoplaySpeed );
34304    }
34305  };
34306  Slick.prototype.autoPlayClear = function() {
34307    var _ = this;
34308    if (_.autoPlayTimer) {
34309      clearInterval(_.autoPlayTimer);
34310    }
34311  };
34312  Slick.prototype.autoPlayIterator = function() {
34313    var _ = this,
34314      slideTo = _.currentSlide + _.options.slidesToScroll;
34315    if ( !_.paused && !_.interrupted && !_.focussed ) {
34316      if ( _.options.infinite === false ) {
34317        if ( _.direction === 1 && ( _.currentSlide + 1 ) === ( _.slideCount - 1 )) {
34318          _.direction = 0;
34319        }
34320        else if ( _.direction === 0 ) {
34321          slideTo = _.currentSlide - _.options.slidesToScroll;
34322          if ( _.currentSlide - 1 === 0 ) {
34323            _.direction = 1;
34324          }
34325        }
34326      }
34327      _.slideHandler( slideTo );
34328    }
34329  };
34330  Slick.prototype.buildArrows = function() {
34331    var _ = this;
34332    if (_.options.arrows === true ) {
34333      _.$prevArrow = $(_.options.prevArrow).addClass('slick-arrow');
34334      _.$nextArrow = $(_.options.nextArrow).addClass('slick-arrow');
34335      if( _.slideCount > _.options.slidesToShow ) {
34336        _.$prevArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex');
34337        _.$nextArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex');
34338        if (_.htmlExpr.test(_.options.prevArrow)) {
34339          _.$prevArrow.prependTo(_.options.appendArrows);
34340        }
34341        if (_.htmlExpr.test(_.options.nextArrow)) {
34342          _.$nextArrow.appendTo(_.options.appendArrows);
34343        }
34344        if (_.options.infinite !== true) {
34345          _.$prevArrow
34346            .addClass('slick-disabled')
34347            .attr('aria-disabled', 'true');
34348        }
34349      } else {
34350        _.$prevArrow.add( _.$nextArrow )
34351          .addClass('slick-hidden')
34352          .attr({
34353            'aria-disabled': 'true',
34354            'tabindex': '-1'
34355          });
34356      }
34357    }
34358  };
34359  Slick.prototype.buildDots = function() {
34360    var _ = this,
34361      i, dot;
34362    if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
34363      _.$slider.addClass('slick-dotted');
34364      dot = $('<ul />').addClass(_.options.dotsClass);
34365      for (i = 0; i <= _.getDotCount(); i += 1) {
34366        dot.append($('<li />').append(_.options.customPaging.call(this, _, i)));
34367      }
34368      _.$dots = dot.appendTo(_.options.appendDots);
34369      _.$dots.find('li').first().addClass('slick-active').attr('aria-hidden', 'false');
34370    }
34371  };
34372  Slick.prototype.buildOut = function() {
34373    var _ = this;
34374    _.$slides =
34375      _.$slider
34376        .children( _.options.slide + ':not(.slick-cloned)')
34377        .addClass('slick-slide');
34378    _.slideCount = _.$slides.length;
34379    _.$slides.each(function(index, element) {
34380      $(element)
34381        .attr('data-slick-index', index)
34382        .data('originalStyling', $(element).attr('style') || '');
34383    });
34384    _.$slider.addClass('slick-slider');
34385    _.$slideTrack = (_.slideCount === 0) ?
34386      $('<div class="slick-track"/>').appendTo(_.$slider) :
34387      _.$slides.wrapAll('<div class="slick-track"/>').parent();
34388    _.$list = _.$slideTrack.wrap(
34389      '<div aria-live="polite" class="slick-list"/>').parent();
34390    _.$slideTrack.css('opacity', 0);
34391    if (_.options.centerMode === true || _.options.swipeToSlide === true) {
34392      _.options.slidesToScroll = 1;
34393    }
34394    $('img[data-lazy]', _.$slider).not('[src]').addClass('slick-loading');
34395    _.setupInfinite();
34396    _.buildArrows();
34397    _.buildDots();
34398    _.updateDots();
34399    _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0);
34400    if (_.options.draggable === true) {
34401      _.$list.addClass('draggable');
34402    }
34403  };
34404  Slick.prototype.buildRows = function() {
34405    var _ = this, a, b, c, newSlides, numOfSlides, originalSlides,slidesPerSection;
34406    newSlides = document.createDocumentFragment();
34407    originalSlides = _.$slider.children();
34408    if(_.options.rows > 1) {
34409      slidesPerSection = _.options.slidesPerRow * _.options.rows;
34410      numOfSlides = Math.ceil(
34411          originalSlides.length / slidesPerSection
34412      );
34413      for(a = 0; a < numOfSlides; a++){
34414        var slide = document.createElement('div');
34415        for(b = 0; b < _.options.rows; b++) {
34416          var row = document.createElement('div');
34417          for(c = 0; c < _.options.slidesPerRow; c++) {
34418            var target = (a * slidesPerSection + ((b * _.options.slidesPerRow) + c));
34419            if (originalSlides.get(target)) {
34420              row.appendChild(originalSlides.get(target));
34421            }
34422          }
34423          slide.appendChild(row);
34424        }
34425        newSlides.appendChild(slide);
34426      }
34427      _.$slider.empty().append(newSlides);
34428      _.$slider.children().children().children()
34429        .css({
34430          'width':(100 / _.options.slidesPerRow) + '%',
34431          'display': 'inline-block'
34432        });
34433    }
34434  };
34435  Slick.prototype.checkResponsive = function(initial, forceUpdate) {
34436    var _ = this,
34437      breakpoint, targetBreakpoint, respondToWidth, triggerBreakpoint = false;
34438    var sliderWidth = _.$slider.width();
34439    var windowWidth = window.innerWidth || $(window).width();
34440    if (_.respondTo === 'window') {
34441      respondToWidth = windowWidth;
34442    } else if (_.respondTo === 'slider') {
34443      respondToWidth = sliderWidth;
34444    } else if (_.respondTo === 'min') {
34445      respondToWidth = Math.min(windowWidth, sliderWidth);
34446    }
34447    if ( _.options.responsive &&
34448      _.options.responsive.length &&
34449      _.options.responsive !== null) {
34450      targetBreakpoint = null;
34451      for (breakpoint in _.breakpoints) {
34452        if (_.breakpoints.hasOwnProperty(breakpoint)) {
34453          if (_.originalSettings.mobileFirst === false) {
34454            if (respondToWidth < _.breakpoints[breakpoint]) {
34455              targetBreakpoint = _.breakpoints[breakpoint];
34456            }
34457          } else {
34458            if (respondToWidth > _.breakpoints[breakpoint]) {
34459              targetBreakpoint = _.breakpoints[breakpoint];
34460            }
34461          }
34462        }
34463      }
34464      if (targetBreakpoint !== null) {
34465        if (_.activeBreakpoint !== null) {
34466          if (targetBreakpoint !== _.activeBreakpoint || forceUpdate) {
34467            _.activeBreakpoint =
34468              targetBreakpoint;
34469            if (_.breakpointSettings[targetBreakpoint] === 'unslick') {
34470              _.unslick(targetBreakpoint);
34471            } else {
34472              _.options = $.extend({}, _.originalSettings,
34473                _.breakpointSettings[
34474                  targetBreakpoint]);
34475              if (initial === true) {
34476                _.currentSlide = _.options.initialSlide;
34477              }
34478              _.refresh(initial);
34479            }
34480            triggerBreakpoint = targetBreakpoint;
34481          }
34482        } else {
34483          _.activeBreakpoint = targetBreakpoint;
34484          if (_.breakpointSettings[targetBreakpoint] === 'unslick') {
34485            _.unslick(targetBreakpoint);
34486          } else {
34487            _.options = $.extend({}, _.originalSettings,
34488              _.breakpointSettings[
34489                targetBreakpoint]);
34490            if (initial === true) {
34491              _.currentSlide = _.options.initialSlide;
34492            }
34493            _.refresh(initial);
34494          }
34495          triggerBreakpoint = targetBreakpoint;
34496        }
34497      } else {
34498        if (_.activeBreakpoint !== null) {
34499          _.activeBreakpoint = null;
34500          _.options = _.originalSettings;
34501          if (initial === true) {
34502            _.currentSlide = _.options.initialSlide;
34503          }
34504          _.refresh(initial);
34505          triggerBreakpoint = targetBreakpoint;
34506        }
34507      }
34508      // only trigger breakpoints during an actual break. not on initialize.
34509      if( !initial && triggerBreakpoint !== false ) {
34510        _.$slider.trigger('breakpoint', [_, triggerBreakpoint]);
34511      }
34512    }
34513  };
34514  Slick.prototype.changeSlide = function(event, dontAnimate) {
34515    var _ = this,
34516      $target = $(event.currentTarget),
34517      indexOffset, slideOffset, unevenOffset;
34518    // If target is a link, prevent default action.
34519    if($target.is('a')) {
34520      event.preventDefault();
34521    }
34522    // If target is not the <li> element (ie: a child), find the <li>.
34523    if(!$target.is('li')) {
34524      $target = $target.closest('li');
34525    }
34526    unevenOffset = (_.slideCount % _.options.slidesToScroll !== 0);
34527    indexOffset = unevenOffset ? 0 : (_.slideCount - _.currentSlide) % _.options.slidesToScroll;
34528    switch (event.data.message) {
34529      case 'previous':
34530        slideOffset = indexOffset === 0 ? _.options.slidesToScroll : _.options.slidesToShow - indexOffset;
34531        if (_.slideCount > _.options.slidesToShow) {
34532          _.slideHandler(_.currentSlide - slideOffset, false, dontAnimate);
34533        }
34534        break;
34535      case 'next':
34536        slideOffset = indexOffset === 0 ? _.options.slidesToScroll : indexOffset;
34537        if (_.slideCount > _.options.slidesToShow) {
34538          _.slideHandler(_.currentSlide + slideOffset, false, dontAnimate);
34539        }
34540        break;
34541      case 'index':
34542        var index = event.data.index === 0 ? 0 :
34543          event.data.index || $target.index() * _.options.slidesToScroll;
34544        _.slideHandler(_.checkNavigable(index), false, dontAnimate);
34545        $target.children().trigger('focus');
34546        break;
34547      default:
34548        return;
34549    }
34550  };
34551  Slick.prototype.checkNavigable = function(index) {
34552    var _ = this,
34553      navigables, prevNavigable;
34554    navigables = _.getNavigableIndexes();
34555    prevNavigable = 0;
34556    if (index > navigables[navigables.length - 1]) {
34557      index = navigables[navigables.length - 1];
34558    } else {
34559      for (var n in navigables) {
34560        if (index < navigables[n]) {
34561          index = prevNavigable;
34562          break;
34563        }
34564        prevNavigable = navigables[n];
34565      }
34566    }
34567    return index;
34568  };
34569  Slick.prototype.cleanUpEvents = function() {
34570    var _ = this;
34571    if (_.options.dots && _.$dots !== null) {
34572      $('li', _.$dots)
34573        .off('click.slick', _.changeSlide)
34574        .off('mouseenter.slick', $.proxy(_.interrupt, _, true))
34575        .off('mouseleave.slick', $.proxy(_.interrupt, _, false));
34576    }
34577    _.$slider.off('focus.slick blur.slick');
34578    if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
34579      _.$prevArrow && _.$prevArrow.off('click.slick', _.changeSlide);
34580      _.$nextArrow && _.$nextArrow.off('click.slick', _.changeSlide);
34581    }
34582    _.$list.off('touchstart.slick mousedown.slick', _.swipeHandler);
34583    _.$list.off('touchmove.slick mousemove.slick', _.swipeHandler);
34584    _.$list.off('touchend.slick mouseup.slick', _.swipeHandler);
34585    _.$list.off('touchcancel.slick mouseleave.slick', _.swipeHandler);
34586    _.$list.off('click.slick', _.clickHandler);
34587    $(document).off(_.visibilityChange, _.visibility);
34588    _.cleanUpSlideEvents();
34589    if (_.options.accessibility === true) {
34590      _.$list.off('keydown.slick', _.keyHandler);
34591    }
34592    if (_.options.focusOnSelect === true) {
34593      $(_.$slideTrack).children().off('click.slick', _.selectHandler);
34594    }
34595    $(window).off('orientationchange.slick.slick-' + _.instanceUid, _.orientationChange);
34596    $(window).off('resize.slick.slick-' + _.instanceUid, _.resize);
34597    $('[draggable!=true]', _.$slideTrack).off('dragstart', _.preventDefault);
34598    $(window).off('load.slick.slick-' + _.instanceUid, _.setPosition);
34599    $(document).off('ready.slick.slick-' + _.instanceUid, _.setPosition);
34600  };
34601  Slick.prototype.cleanUpSlideEvents = function() {
34602    var _ = this;
34603    _.$list.off('mouseenter.slick', $.proxy(_.interrupt, _, true));
34604    _.$list.off('mouseleave.slick', $.proxy(_.interrupt, _, false));
34605  };
34606  Slick.prototype.cleanUpRows = function() {
34607    var _ = this, originalSlides;
34608    if(_.options.rows > 1) {
34609      originalSlides = _.$slides.children().children();
34610      originalSlides.removeAttr('style');
34611      _.$slider.empty().append(originalSlides);
34612    }
34613  };
34614  Slick.prototype.clickHandler = function(event) {
34615    var _ = this;
34616    if (_.shouldClick === false) {
34617      event.stopImmediatePropagation();
34618      event.stopPropagation();
34619      event.preventDefault();
34620    }
34621  };
34622  Slick.prototype.destroy = function(refresh) {
34623    var _ = this;
34624    _.autoPlayClear();
34625    _.touchObject = {};
34626    _.cleanUpEvents();
34627    $('.slick-cloned', _.$slider).detach();
34628    if (_.$dots) {
34629      _.$dots.remove();
34630    }
34631    if ( _.$prevArrow && _.$prevArrow.length ) {
34632      _.$prevArrow
34633        .removeClass('slick-disabled slick-arrow slick-hidden')
34634        .removeAttr('aria-hidden aria-disabled tabindex')
34635        .css('display','');
34636      if ( _.htmlExpr.test( _.options.prevArrow )) {
34637        _.$prevArrow.remove();
34638      }
34639    }
34640    if ( _.$nextArrow && _.$nextArrow.length ) {
34641      _.$nextArrow
34642        .removeClass('slick-disabled slick-arrow slick-hidden')
34643        .removeAttr('aria-hidden aria-disabled tabindex')
34644        .css('display','');
34645      if ( _.htmlExpr.test( _.options.nextArrow )) {
34646        _.$nextArrow.remove();
34647      }
34648    }
34649    if (_.$slides) {
34650      _.$slides
34651        .removeClass('slick-slide slick-active slick-center slick-visible slick-current')
34652        .removeAttr('aria-hidden')
34653        .removeAttr('data-slick-index')
34654        .each(function(){
34655          $(this).attr('style', $(this).data('originalStyling'));
34656        });
34657      _.$slideTrack.children(this.options.slide).detach();
34658      _.$slideTrack.detach();
34659      _.$list.detach();
34660      _.$slider.append(_.$slides);
34661    }
34662    _.cleanUpRows();
34663    _.$slider.removeClass('slick-slider');
34664    _.$slider.removeClass('slick-initialized');
34665    _.$slider.removeClass('slick-dotted');
34666    _.unslicked = true;
34667    if(!refresh) {
34668      _.$slider.trigger('destroy', [_]);
34669    }
34670  };
34671  Slick.prototype.disableTransition = function(slide) {
34672    var _ = this,
34673      transition = {};
34674    transition[_.transitionType] = '';
34675    if (_.options.fade === false) {
34676      _.$slideTrack.css(transition);
34677    } else {
34678      _.$slides.eq(slide).css(transition);
34679    }
34680  };
34681  Slick.prototype.fadeSlide = function(slideIndex, callback) {
34682    var _ = this;
34683    if (_.cssTransitions === false) {
34684      _.$slides.eq(slideIndex).css({
34685        zIndex: _.options.zIndex
34686      });
34687      _.$slides.eq(slideIndex).animate({
34688        opacity: 1
34689      }, _.options.speed, _.options.easing, callback);
34690    } else {
34691      _.applyTransition(slideIndex);
34692      _.$slides.eq(slideIndex).css({
34693        opacity: 1,
34694        zIndex: _.options.zIndex
34695      });
34696      if (callback) {
34697        setTimeout(function() {
34698          _.disableTransition(slideIndex);
34699          callback.call();
34700        }, _.options.speed);
34701      }
34702    }
34703  };
34704  Slick.prototype.fadeSlideOut = function(slideIndex) {
34705    var _ = this;
34706    if (_.cssTransitions === false) {
34707      _.$slides.eq(slideIndex).animate({
34708        opacity: 0,
34709        zIndex: _.options.zIndex - 2
34710      }, _.options.speed, _.options.easing);
34711    } else {
34712      _.applyTransition(slideIndex);
34713      _.$slides.eq(slideIndex).css({
34714        opacity: 0,
34715        zIndex: _.options.zIndex - 2
34716      });
34717    }
34718  };
34719  Slick.prototype.filterSlides = Slick.prototype.slickFilter = function(filter) {
34720    var _ = this;
34721    if (filter !== null) {
34722      _.$slidesCache = _.$slides;
34723      _.unload();
34724      _.$slideTrack.children(this.options.slide).detach();
34725      _.$slidesCache.filter(filter).appendTo(_.$slideTrack);
34726      _.reinit();
34727    }
34728  };
34729  Slick.prototype.focusHandler = function() {
34730    var _ = this;
34731    _.$slider
34732      .off('focus.slick blur.slick')
34733      .on('focus.slick blur.slick',
34734      '*:not(.slick-arrow)', function(event) {
34735        event.stopImmediatePropagation();
34736        var $sf = $(this);
34737        setTimeout(function() {
34738          if( _.options.pauseOnFocus ) {
34739            _.focussed = $sf.is(':focus');
34740            _.autoPlay();
34741          }
34742        }, 0);
34743      });
34744  };
34745  Slick.prototype.getCurrent = Slick.prototype.slickCurrentSlide = function() {
34746    var _ = this;
34747    return _.currentSlide;
34748  };
34749  Slick.prototype.getDotCount = function() {
34750    var _ = this;
34751    var breakPoint = 0;
34752    var counter = 0;
34753    var pagerQty = 0;
34754    if (_.options.infinite === true) {
34755      while (breakPoint < _.slideCount) {
34756        ++pagerQty;
34757        breakPoint = counter + _.options.slidesToScroll;
34758        counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
34759      }
34760    } else if (_.options.centerMode === true) {
34761      pagerQty = _.slideCount;
34762    } else if(!_.options.asNavFor) {
34763      pagerQty = 1 + Math.ceil((_.slideCount - _.options.slidesToShow) / _.options.slidesToScroll);
34764    }else {
34765      while (breakPoint < _.slideCount) {
34766        ++pagerQty;
34767        breakPoint = counter + _.options.slidesToScroll;
34768        counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
34769      }
34770    }
34771    return pagerQty - 1;
34772  };
34773  Slick.prototype.getLeft = function(slideIndex) {
34774    var _ = this,
34775      targetLeft,
34776      verticalHeight,
34777      verticalOffset = 0,
34778      targetSlide;
34779    _.slideOffset = 0;
34780    verticalHeight = _.$slides.first().outerHeight(true);
34781    if (_.options.infinite === true) {
34782      if (_.slideCount > _.options.slidesToShow) {
34783        _.slideOffset = (_.slideWidth * _.options.slidesToShow) * -1;
34784        verticalOffset = (verticalHeight * _.options.slidesToShow) * -1;
34785      }
34786      if (_.slideCount % _.options.slidesToScroll !== 0) {
34787        if (slideIndex + _.options.slidesToScroll > _.slideCount && _.slideCount > _.options.slidesToShow) {
34788          if (slideIndex > _.slideCount) {
34789            _.slideOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * _.slideWidth) * -1;
34790            verticalOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * verticalHeight) * -1;
34791          } else {
34792            _.slideOffset = ((_.slideCount % _.options.slidesToScroll) * _.slideWidth) * -1;
34793            verticalOffset = ((_.slideCount % _.options.slidesToScroll) * verticalHeight) * -1;
34794          }
34795        }
34796      }
34797    } else {
34798      if (slideIndex + _.options.slidesToShow > _.slideCount) {
34799        _.slideOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * _.slideWidth;
34800        verticalOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * verticalHeight;
34801      }
34802    }
34803    if (_.slideCount <= _.options.slidesToShow) {
34804      _.slideOffset = 0;
34805      verticalOffset = 0;
34806    }
34807    if (_.options.centerMode === true && _.options.infinite === true) {
34808      _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2) - _.slideWidth;
34809    } else if (_.options.centerMode === true) {
34810      _.slideOffset = 0;
34811      _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2);
34812    }
34813    if (_.options.vertical === false) {
34814      targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
34815    } else {
34816      targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset;
34817    }
34818    if (_.options.variableWidth === true) {
34819      if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) {
34820        targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex);
34821      } else {
34822        targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow);
34823      }
34824      if (_.options.rtl === true) {
34825        if (targetSlide[0]) {
34826          targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1;
34827        } else {
34828          targetLeft =  0;
34829        }
34830      } else {
34831        targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0;
34832      }
34833      if (_.options.centerMode === true) {
34834        if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) {
34835          targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex);
34836        } else {
34837          targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow + 1);
34838        }
34839        if (_.options.rtl === true) {
34840          if (targetSlide[0]) {
34841            targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1;
34842          } else {
34843            targetLeft =  0;
34844          }
34845        } else {
34846          targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0;
34847        }
34848        targetLeft += (_.$list.width() - targetSlide.outerWidth()) / 2;
34849      }
34850    }
34851    return targetLeft;
34852  };
34853  Slick.prototype.getOption = Slick.prototype.slickGetOption = function(option) {
34854    var _ = this;
34855    return _.options[option];
34856  };
34857  Slick.prototype.getNavigableIndexes = function() {
34858    var _ = this,
34859      breakPoint = 0,
34860      counter = 0,
34861      indexes = [],
34862      max;
34863    if (_.options.infinite === false) {
34864      max = _.slideCount;
34865    } else {
34866      breakPoint = _.options.slidesToScroll * -1;
34867      counter = _.options.slidesToScroll * -1;
34868      max = _.slideCount * 2;
34869    }
34870    while (breakPoint < max) {
34871      indexes.push(breakPoint);
34872      breakPoint = counter + _.options.slidesToScroll;
34873      counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
34874    }
34875    return indexes;
34876  };
34877  Slick.prototype.getSlick = function() {
34878    return this;
34879  };
34880  Slick.prototype.getSlideCount = function() {
34881    var _ = this,
34882      slidesTraversed, swipedSlide, centerOffset;
34883    centerOffset = _.options.centerMode === true ? _.slideWidth * Math.floor(_.options.slidesToShow / 2) : 0;
34884    if (_.options.swipeToSlide === true) {
34885      _.$slideTrack.find('.slick-slide').each(function(index, slide) {
34886        if (slide.offsetLeft - centerOffset + ($(slide).outerWidth() / 2) > (_.swipeLeft * -1)) {
34887          swipedSlide = slide;
34888          return false;
34889        }
34890      });
34891      slidesTraversed = Math.abs($(swipedSlide).attr('data-slick-index') - _.currentSlide) || 1;
34892      return slidesTraversed;
34893    } else {
34894      return _.options.slidesToScroll;
34895    }
34896  };
34897  Slick.prototype.goTo = Slick.prototype.slickGoTo = function(slide, dontAnimate) {
34898    var _ = this;
34899    _.changeSlide({
34900      data: {
34901        message: 'index',
34902        index: parseInt(slide)
34903      }
34904    }, dontAnimate);
34905  };
34906  Slick.prototype.init = function(creation) {
34907    var _ = this;
34908    if (!$(_.$slider).hasClass('slick-initialized')) {
34909      $(_.$slider).addClass('slick-initialized');
34910      _.buildRows();
34911      _.buildOut();
34912      _.setProps();
34913      _.startLoad();
34914      _.loadSlider();
34915      _.initializeEvents();
34916      _.updateArrows();
34917      _.updateDots();
34918      _.checkResponsive(true);
34919      _.focusHandler();
34920    }
34921    if (creation) {
34922      _.$slider.trigger('init', [_]);
34923    }
34924    if (_.options.accessibility === true) {
34925      _.initADA();
34926    }
34927    if ( _.options.autoplay ) {
34928      _.paused = false;
34929      _.autoPlay();
34930    }
34931  };
34932  Slick.prototype.initADA = function() {
34933    var _ = this;
34934    _.$slides.add(_.$slideTrack.find('.slick-cloned')).attr({
34935      'aria-hidden': 'true',
34936      'tabindex': '-1'
34937    }).find('a, input, button, select').attr({
34938      'tabindex': '-1'
34939    });
34940    _.$slideTrack.attr('role', 'listbox');
34941    _.$slides.not(_.$slideTrack.find('.slick-cloned')).each(function(i) {
34942      $(this).attr({
34943        'role': 'option',
34944        'aria-describedby': 'slick-slide' + _.instanceUid + i + ''
34945      });
34946    });
34947    if (_.$dots !== null) {
34948      _.$dots.attr('role', 'tablist').find('li').each(function(i) {
34949        $(this).attr({
34950          'role': 'presentation',
34951          'aria-selected': 'false',
34952          'aria-controls': 'navigation' + _.instanceUid + i + '',
34953          'id': 'slick-slide' + _.instanceUid + i + ''
34954        });
34955      })
34956        .first().attr('aria-selected', 'true').end()
34957        .find('button').attr('role', 'button').end()
34958        .closest('div').attr('role', 'toolbar');
34959    }
34960    _.activateADA();
34961  };
34962  Slick.prototype.initArrowEvents = function() {
34963    var _ = this;
34964    if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
34965      _.$prevArrow
34966        .off('click.slick')
34967        .on('click.slick', {
34968          message: 'previous'
34969        }, _.changeSlide);
34970      _.$nextArrow
34971        .off('click.slick')
34972        .on('click.slick', {
34973          message: 'next'
34974        }, _.changeSlide);
34975    }
34976  };
34977  Slick.prototype.initDotEvents = function() {
34978    var _ = this;
34979    if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
34980      $('li', _.$dots).on('click.slick', {
34981        message: 'index'
34982      }, _.changeSlide);
34983    }
34984    if ( _.options.dots === true && _.options.pauseOnDotsHover === true ) {
34985      $('li', _.$dots)
34986        .on('mouseenter.slick', $.proxy(_.interrupt, _, true))
34987        .on('mouseleave.slick', $.proxy(_.interrupt, _, false));
34988    }
34989  };
34990  Slick.prototype.initSlideEvents = function() {
34991    var _ = this;
34992    if ( _.options.pauseOnHover ) {
34993      _.$list.on('mouseenter.slick', $.proxy(_.interrupt, _, true));
34994      _.$list.on('mouseleave.slick', $.proxy(_.interrupt, _, false));
34995    }
34996  };
34997  Slick.prototype.initializeEvents = function() {
34998    var _ = this;
34999    _.initArrowEvents();
35000    _.initDotEvents();
35001    _.initSlideEvents();
35002    _.$list.on('touchstart.slick mousedown.slick', {
35003      action: 'start'
35004    }, _.swipeHandler);
35005    _.$list.on('touchmove.slick mousemove.slick', {
35006      action: 'move'
35007    }, _.swipeHandler);
35008    _.$list.on('touchend.slick mouseup.slick', {
35009      action: 'end'
35010    }, _.swipeHandler);
35011    _.$list.on('touchcancel.slick mouseleave.slick', {
35012      action: 'end'
35013    }, _.swipeHandler);
35014    _.$list.on('click.slick', _.clickHandler);
35015    $(document).on(_.visibilityChange, $.proxy(_.visibility, _));
35016    if (_.options.accessibility === true) {
35017      _.$list.on('keydown.slick', _.keyHandler);
35018    }
35019    if (_.options.focusOnSelect === true) {
35020      $(_.$slideTrack).children().on('click.slick', _.selectHandler);
35021    }
35022    $(window).on('orientationchange.slick.slick-' + _.instanceUid, $.proxy(_.orientationChange, _));
35023    $(window).on('resize.slick.slick-' + _.instanceUid, $.proxy(_.resize, _));
35024    $('[draggable!=true]', _.$slideTrack).on('dragstart', _.preventDefault);
35025    $(window).on('load.slick.slick-' + _.instanceUid, _.setPosition);
35026    $(document).on('ready.slick.slick-' + _.instanceUid, _.setPosition);
35027  };
35028  Slick.prototype.initUI = function() {
35029    var _ = this;
35030    if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
35031      _.$prevArrow.show();
35032      _.$nextArrow.show();
35033    }
35034    if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
35035      _.$dots.show();
35036    }
35037  };
35038  Slick.prototype.keyHandler = function(event) {
35039    var _ = this;
35040    //Dont slide if the cursor is inside the form fields and arrow keys are pressed
35041    if(!event.target.tagName.match('TEXTAREA|INPUT|SELECT')) {
35042      if (event.keyCode === 37 && _.options.accessibility === true) {
35043        _.changeSlide({
35044          data: {
35045            message: _.options.rtl === true ? 'next' :  'previous'
35046          }
35047        });
35048      } else if (event.keyCode === 39 && _.options.accessibility === true) {
35049        _.changeSlide({
35050          data: {
35051            message: _.options.rtl === true ? 'previous' : 'next'
35052          }
35053        });
35054      }
35055    }
35056  };
35057  Slick.prototype.lazyLoad = function() {
35058    var _ = this,
35059      loadRange, cloneRange, rangeStart, rangeEnd;
35060    function loadImages(imagesScope) {
35061      $('img[data-lazy]', imagesScope).each(function() {
35062        var image = $(this),
35063          imageSource = $(this).attr('data-lazy'),
35064          imageToLoad = document.createElement('img');
35065        imageToLoad.onload = function() {
35066          image
35067            .animate({ opacity: 0 }, 100, function() {
35068              image
35069                .attr('src', imageSource)
35070                .animate({ opacity: 1 }, 200, function() {
35071                  image
35072                    .removeAttr('data-lazy')
35073                    .removeClass('slick-loading');
35074                });
35075              _.$slider.trigger('lazyLoaded', [_, image, imageSource]);
35076            });
35077        };
35078        imageToLoad.onerror = function() {
35079          image
35080            .removeAttr( 'data-lazy' )
35081            .removeClass( 'slick-loading' )
35082            .addClass( 'slick-lazyload-error' );
35083          _.$slider.trigger('lazyLoadError', [ _, image, imageSource ]);
35084        };
35085        imageToLoad.src = imageSource;
35086      });
35087    }
35088    if (_.options.centerMode === true) {
35089      if (_.options.infinite === true) {
35090        rangeStart = _.currentSlide + (_.options.slidesToShow / 2 + 1);
35091        rangeEnd = rangeStart + _.options.slidesToShow + 2;
35092      } else {
35093        rangeStart = Math.max(0, _.currentSlide - (_.options.slidesToShow / 2 + 1));
35094        rangeEnd = 2 + (_.options.slidesToShow / 2 + 1) + _.currentSlide;
35095      }
35096    } else {
35097      rangeStart = _.options.infinite ? _.options.slidesToShow + _.currentSlide : _.currentSlide;
35098      rangeEnd = Math.ceil(rangeStart + _.options.slidesToShow);
35099      if (_.options.fade === true) {
35100        if (rangeStart > 0) rangeStart--;
35101        if (rangeEnd <= _.slideCount) rangeEnd++;
35102      }
35103    }
35104    loadRange = _.$slider.find('.slick-slide').slice(rangeStart, rangeEnd);
35105    loadImages(loadRange);
35106    if (_.slideCount <= _.options.slidesToShow) {
35107      cloneRange = _.$slider.find('.slick-slide');
35108      loadImages(cloneRange);
35109    } else
35110    if (_.currentSlide >= _.slideCount - _.options.slidesToShow) {
35111      cloneRange = _.$slider.find('.slick-cloned').slice(0, _.options.slidesToShow);
35112      loadImages(cloneRange);
35113    } else if (_.currentSlide === 0) {
35114      cloneRange = _.$slider.find('.slick-cloned').slice(_.options.slidesToShow * -1);
35115      loadImages(cloneRange);
35116    }
35117  };
35118  Slick.prototype.loadSlider = function() {
35119    var _ = this;
35120    _.setPosition();
35121    _.$slideTrack.css({
35122      opacity: 1
35123    });
35124    _.$slider.removeClass('slick-loading');
35125    _.initUI();
35126    if (_.options.lazyLoad === 'progressive') {
35127      _.progressiveLazyLoad();
35128    }
35129  };
35130  Slick.prototype.next = Slick.prototype.slickNext = function() {
35131    var _ = this;
35132    _.changeSlide({
35133      data: {
35134        message: 'next'
35135      }
35136    });
35137  };
35138  Slick.prototype.orientationChange = function() {
35139    var _ = this;
35140    _.checkResponsive();
35141    _.setPosition();
35142  };
35143  Slick.prototype.pause = Slick.prototype.slickPause = function() {
35144    var _ = this;
35145    _.autoPlayClear();
35146    _.paused = true;
35147  };
35148  Slick.prototype.play = Slick.prototype.slickPlay = function() {
35149    var _ = this;
35150    _.autoPlay();
35151    _.options.autoplay = true;
35152    _.paused = false;
35153    _.focussed = false;
35154    _.interrupted = false;
35155  };
35156  Slick.prototype.postSlide = function(index) {
35157    var _ = this;
35158    if( !_.unslicked ) {
35159      _.$slider.trigger('afterChange', [_, index]);
35160      _.animating = false;
35161      _.setPosition();
35162      _.swipeLeft = null;
35163      if ( _.options.autoplay ) {
35164        _.autoPlay();
35165      }
35166      if (_.options.accessibility === true) {
35167        _.initADA();
35168      }
35169    }
35170  };
35171  Slick.prototype.prev = Slick.prototype.slickPrev = function() {
35172    var _ = this;
35173    _.changeSlide({
35174      data: {
35175        message: 'previous'
35176      }
35177    });
35178  };
35179  Slick.prototype.preventDefault = function(event) {
35180    event.preventDefault();
35181  };
35182  Slick.prototype.progressiveLazyLoad = function( tryCount ) {
35183    tryCount = tryCount || 1;
35184    var _ = this,
35185      $imgsToLoad = $( 'img[data-lazy]', _.$slider ),
35186      image,
35187      imageSource,
35188      imageToLoad;
35189    if ( $imgsToLoad.length ) {
35190      image = $imgsToLoad.first();
35191      imageSource = image.attr('data-lazy');
35192      imageToLoad = document.createElement('img');
35193      imageToLoad.onload = function() {
35194        image
35195          .attr( 'src', imageSource )
35196          .removeAttr('data-lazy')
35197          .removeClass('slick-loading');
35198        if ( _.options.adaptiveHeight === true ) {
35199          _.setPosition();
35200        }
35201        _.$slider.trigger('lazyLoaded', [ _, image, imageSource ]);
35202        _.progressiveLazyLoad();
35203      };
35204      imageToLoad.onerror = function() {
35205        if ( tryCount < 3 ) {
35206          /**
35207           * try to load the image 3 times,
35208           * leave a slight delay so we don't get
35209           * servers blocking the request.
35210           */
35211          setTimeout( function() {
35212            _.progressiveLazyLoad( tryCount + 1 );
35213          }, 500 );
35214        } else {
35215          image
35216            .removeAttr( 'data-lazy' )
35217            .removeClass( 'slick-loading' )
35218            .addClass( 'slick-lazyload-error' );
35219          _.$slider.trigger('lazyLoadError', [ _, image, imageSource ]);
35220          _.progressiveLazyLoad();
35221        }
35222      };
35223      imageToLoad.src = imageSource;
35224    } else {
35225      _.$slider.trigger('allImagesLoaded', [ _ ]);
35226    }
35227  };
35228  Slick.prototype.refresh = function( initializing ) {
35229    var _ = this, currentSlide, lastVisibleIndex;
35230    lastVisibleIndex = _.slideCount - _.options.slidesToShow;
35231    // in non-infinite sliders, we don't want to go past the
35232    // last visible index.
35233    if( !_.options.infinite && ( _.currentSlide > lastVisibleIndex )) {
35234      _.currentSlide = lastVisibleIndex;
35235    }
35236    // if less slides than to show, go to start.
35237    if ( _.slideCount <= _.options.slidesToShow ) {
35238      _.currentSlide = 0;
35239    }
35240    currentSlide = _.currentSlide;
35241    _.destroy(true);
35242    $.extend(_, _.initials, { currentSlide: currentSlide });
35243    _.init();
35244    if( !initializing ) {
35245      _.changeSlide({
35246        data: {
35247          message: 'index',
35248          index: currentSlide
35249        }
35250      }, false);
35251    }
35252  };
35253  Slick.prototype.registerBreakpoints = function() {
35254    var _ = this, breakpoint, currentBreakpoint, l,
35255      responsiveSettings = _.options.responsive || null;
35256    if ( $.type(responsiveSettings) === 'array' && responsiveSettings.length ) {
35257      _.respondTo = _.options.respondTo || 'window';
35258      for ( breakpoint in responsiveSettings ) {
35259        l = _.breakpoints.length-1;
35260        currentBreakpoint = responsiveSettings[breakpoint].breakpoint;
35261        if (responsiveSettings.hasOwnProperty(breakpoint)) {
35262          // loop through the breakpoints and cut out any existing
35263          // ones with the same breakpoint number, we don't want dupes.
35264          while( l >= 0 ) {
35265            if( _.breakpoints[l] && _.breakpoints[l] === currentBreakpoint ) {
35266              _.breakpoints.splice(l,1);
35267            }
35268            l--;
35269          }
35270          _.breakpoints.push(currentBreakpoint);
35271          _.breakpointSettings[currentBreakpoint] = responsiveSettings[breakpoint].settings;
35272        }
35273      }
35274      _.breakpoints.sort(function(a, b) {
35275        return ( _.options.mobileFirst ) ? a-b : b-a;
35276      });
35277    }
35278  };
35279  Slick.prototype.reinit = function() {
35280    var _ = this;
35281    _.$slides =
35282      _.$slideTrack
35283        .children(_.options.slide)
35284        .addClass('slick-slide');
35285    _.slideCount = _.$slides.length;
35286    if (_.currentSlide >= _.slideCount && _.currentSlide !== 0) {
35287      _.currentSlide = _.currentSlide - _.options.slidesToScroll;
35288    }
35289    if (_.slideCount <= _.options.slidesToShow) {
35290      _.currentSlide = 0;
35291    }
35292    _.registerBreakpoints();
35293    _.setProps();
35294    _.setupInfinite();
35295    _.buildArrows();
35296    _.updateArrows();
35297    _.initArrowEvents();
35298    _.buildDots();
35299    _.updateDots();
35300    _.initDotEvents();
35301    _.cleanUpSlideEvents();
35302    _.initSlideEvents();
35303    _.checkResponsive(false, true);
35304    if (_.options.focusOnSelect === true) {
35305      $(_.$slideTrack).children().on('click.slick', _.selectHandler);
35306    }
35307    _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0);
35308    _.setPosition();
35309    _.focusHandler();
35310    _.paused = !_.options.autoplay;
35311    _.autoPlay();
35312    _.$slider.trigger('reInit', [_]);
35313  };
35314  Slick.prototype.resize = function() {
35315    var _ = this;
35316    if ($(window).width() !== _.windowWidth) {
35317      clearTimeout(_.windowDelay);
35318      _.windowDelay = window.setTimeout(function() {
35319        _.windowWidth = $(window).width();
35320        _.checkResponsive();
35321        if( !_.unslicked ) { _.setPosition(); }
35322      }, 50);
35323    }
35324  };
35325  Slick.prototype.removeSlide = Slick.prototype.slickRemove = function(index, removeBefore, removeAll) {
35326    var _ = this;
35327    if (typeof(index) === 'boolean') {
35328      removeBefore = index;
35329      index = removeBefore === true ? 0 : _.slideCount - 1;
35330    } else {
35331      index = removeBefore === true ? --index : index;
35332    }
35333    if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) {
35334      return false;
35335    }
35336    _.unload();
35337    if (removeAll === true) {
35338      _.$slideTrack.children().remove();
35339    } else {
35340      _.$slideTrack.children(this.options.slide).eq(index).remove();
35341    }
35342    _.$slides = _.$slideTrack.children(this.options.slide);
35343    _.$slideTrack.children(this.options.slide).detach();
35344    _.$slideTrack.append(_.$slides);
35345    _.$slidesCache = _.$slides;
35346    _.reinit();
35347  };
35348  Slick.prototype.setCSS = function(position) {
35349    var _ = this,
35350      positionProps = {},
35351      x, y;
35352    if (_.options.rtl === true) {
35353      position = -position;
35354    }
35355    x = _.positionProp == 'left' ? Math.ceil(position) + 'px' : '0px';
35356    y = _.positionProp == 'top' ? Math.ceil(position) + 'px' : '0px';
35357    positionProps[_.positionProp] = position;
35358    if (_.transformsEnabled === false) {
35359      _.$slideTrack.css(positionProps);
35360    } else {
35361      positionProps = {};
35362      if (_.cssTransitions === false) {
35363        positionProps[_.animType] = 'translate(' + x + ', ' + y + ')';
35364        _.$slideTrack.css(positionProps);
35365      } else {
35366        positionProps[_.animType] = 'translate3d(' + x + ', ' + y + ', 0px)';
35367        _.$slideTrack.css(positionProps);
35368      }
35369    }
35370  };
35371  Slick.prototype.setDimensions = function() {
35372    var _ = this;
35373    if (_.options.vertical === false) {
35374      if (_.options.centerMode === true) {
35375        _.$list.css({
35376          padding: ('0px ' + _.options.centerPadding)
35377        });
35378      }
35379    } else {
35380      _.$list.height(_.$slides.first().outerHeight(true) * _.options.slidesToShow);
35381      if (_.options.centerMode === true) {
35382        _.$list.css({
35383          padding: (_.options.centerPadding + ' 0px')
35384        });
35385      }
35386    }
35387    _.listWidth = _.$list.width();
35388    _.listHeight = _.$list.height();
35389    if (_.options.vertical === false && _.options.variableWidth === false) {
35390      _.slideWidth = Math.ceil(_.listWidth / _.options.slidesToShow);
35391      _.$slideTrack.width(Math.ceil((_.slideWidth * _.$slideTrack.children('.slick-slide').length)));
35392    } else if (_.options.variableWidth === true) {
35393      _.$slideTrack.width(5000 * _.slideCount);
35394    } else {
35395      _.slideWidth = Math.ceil(_.listWidth);
35396      _.$slideTrack.height(Math.ceil((_.$slides.first().outerHeight(true) * _.$slideTrack.children('.slick-slide').length)));
35397    }
35398    var offset = _.$slides.first().outerWidth(true) - _.$slides.first().width();
35399    if (_.options.variableWidth === false) _.$slideTrack.children('.slick-slide').width(_.slideWidth - offset);
35400  };
35401  Slick.prototype.setFade = function() {
35402    var _ = this,
35403      targetLeft;
35404    _.$slides.each(function(index, element) {
35405      targetLeft = (_.slideWidth * index) * -1;
35406      if (_.options.rtl === true) {
35407        $(element).css({
35408          position: 'relative',
35409          right: targetLeft,
35410          top: 0,
35411          zIndex: _.options.zIndex - 2,
35412          opacity: 0
35413        });
35414      } else {
35415        $(element).css({
35416          position: 'relative',
35417          left: targetLeft,
35418          top: 0,
35419          zIndex: _.options.zIndex - 2,
35420          opacity: 0
35421        });
35422      }
35423    });
35424    _.$slides.eq(_.currentSlide).css({
35425      zIndex: _.options.zIndex - 1,
35426      opacity: 1
35427    });
35428  };
35429  Slick.prototype.setHeight = function() {
35430    var _ = this;
35431    if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {
35432      var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);
35433      _.$list.css('height', targetHeight);
35434    }
35435  };
35436  Slick.prototype.setOption =
35437    Slick.prototype.slickSetOption = function() {
35438      /**
35439       * accepts arguments in format of:
35440       *
35441       *  - for changing a single option's value:
35442       *     .slick("setOption", option, value, refresh )
35443       *
35444       *  - for changing a set of responsive options:
35445       *     .slick("setOption", 'responsive', [{}, ...], refresh )
35446       *
35447       *  - for updating multiple values at once (not responsive)
35448       *     .slick("setOption", { 'option': value, ... }, refresh )
35449       */
35450      var _ = this, l, item, option, value, refresh = false, type;
35451      if( $.type( arguments[0] ) === 'object' ) {
35452        option =  arguments[0];
35453        refresh = arguments[1];
35454        type = 'multiple';
35455      } else if ( $.type( arguments[0] ) === 'string' ) {
35456        option =  arguments[0];
35457        value = arguments[1];
35458        refresh = arguments[2];
35459        if ( arguments[0] === 'responsive' && $.type( arguments[1] ) === 'array' ) {
35460          type = 'responsive';
35461        } else if ( typeof arguments[1] !== 'undefined' ) {
35462          type = 'single';
35463        }
35464      }
35465      if ( type === 'single' ) {
35466        _.options[option] = value;
35467      } else if ( type === 'multiple' ) {
35468        $.each( option , function( opt, val ) {
35469          _.options[opt] = val;
35470        });
35471      } else if ( type === 'responsive' ) {
35472        for ( item in value ) {
35473          if( $.type( _.options.responsive ) !== 'array' ) {
35474            _.options.responsive = [ value[item] ];
35475          } else {
35476            l = _.options.responsive.length-1;
35477            // loop through the responsive object and splice out duplicates.
35478            while( l >= 0 ) {
35479              if( _.options.responsive[l].breakpoint === value[item].breakpoint ) {
35480                _.options.responsive.splice(l,1);
35481              }
35482              l--;
35483            }
35484            _.options.responsive.push( value[item] );
35485          }
35486        }
35487      }
35488      if ( refresh ) {
35489        _.unload();
35490        _.reinit();
35491      }
35492    };
35493  Slick.prototype.setPosition = function() {
35494    var _ = this;
35495    _.setDimensions();
35496    _.setHeight();
35497    if (_.options.fade === false) {
35498      _.setCSS(_.getLeft(_.currentSlide));
35499    } else {
35500      _.setFade();
35501    }
35502    _.$slider.trigger('setPosition', [_]);
35503  };
35504  Slick.prototype.setProps = function() {
35505    var _ = this,
35506      bodyStyle = document.body.style;
35507    _.positionProp = _.options.vertical === true ? 'top' : 'left';
35508    if (_.positionProp === 'top') {
35509      _.$slider.addClass('slick-vertical');
35510    } else {
35511      _.$slider.removeClass('slick-vertical');
35512    }
35513    if (bodyStyle.WebkitTransition !== undefined ||
35514      bodyStyle.MozTransition !== undefined ||
35515      bodyStyle.msTransition !== undefined) {
35516      if (_.options.useCSS === true) {
35517        _.cssTransitions = true;
35518      }
35519    }
35520    if ( _.options.fade ) {
35521      if ( typeof _.options.zIndex === 'number' ) {
35522        if( _.options.zIndex < 3 ) {
35523          _.options.zIndex = 3;
35524        }
35525      } else {
35526        _.options.zIndex = _.defaults.zIndex;
35527      }
35528    }
35529    if (bodyStyle.OTransform !== undefined) {
35530      _.animType = 'OTransform';
35531      _.transformType = '-o-transform';
35532      _.transitionType = 'OTransition';
35533      if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
35534    }
35535    if (bodyStyle.MozTransform !== undefined) {
35536      _.animType = 'MozTransform';
35537      _.transformType = '-moz-transform';
35538      _.transitionType = 'MozTransition';
35539      if (bodyStyle.perspectiveProperty === undefined && bodyStyle.MozPerspective === undefined) _.animType = false;
35540    }
35541    if (bodyStyle.webkitTransform !== undefined) {
35542      _.animType = 'webkitTransform';
35543      _.transformType = '-webkit-transform';
35544      _.transitionType = 'webkitTransition';
35545      if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
35546    }
35547    if (bodyStyle.msTransform !== undefined) {
35548      _.animType = 'msTransform';
35549      _.transformType = '-ms-transform';
35550      _.transitionType = 'msTransition';
35551      if (bodyStyle.msTransform === undefined) _.animType = false;
35552    }
35553    if (bodyStyle.transform !== undefined && _.animType !== false) {
35554      _.animType = 'transform';
35555      _.transformType = 'transform';
35556      _.transitionType = 'transition';
35557    }
35558    _.transformsEnabled = _.options.useTransform && (_.animType !== null && _.animType !== false);
35559  };
35560  Slick.prototype.setSlideClasses = function(index) {
35561    var _ = this,
35562      centerOffset, allSlides, indexOffset, remainder;
35563    allSlides = _.$slider
35564      .find('.slick-slide')
35565      .removeClass('slick-active slick-center slick-current')
35566      .attr('aria-hidden', 'true');
35567    _.$slides
35568      .eq(index)
35569      .addClass('slick-current');
35570    if (_.options.centerMode === true) {
35571      centerOffset = Math.floor(_.options.slidesToShow / 2);
35572      if (_.options.infinite === true) {
35573        if (index >= centerOffset && index <= (_.slideCount - 1) - centerOffset) {
35574          _.$slides
35575            .slice(index - centerOffset, index + centerOffset + 1)
35576            .addClass('slick-active')
35577            .attr('aria-hidden', 'false');
35578        } else {
35579          indexOffset = _.options.slidesToShow + index;
35580          allSlides
35581            .slice(indexOffset - centerOffset + 1, indexOffset + centerOffset + 2)
35582            .addClass('slick-active')
35583            .attr('aria-hidden', 'false');
35584        }
35585        if (index === 0) {
35586          allSlides
35587            .eq(allSlides.length - 1 - _.options.slidesToShow)
35588            .addClass('slick-center');
35589        } else if (index === _.slideCount - 1) {
35590          allSlides
35591            .eq(_.options.slidesToShow)
35592            .addClass('slick-center');
35593        }
35594      }
35595      _.$slides
35596        .eq(index)
35597        .addClass('slick-center');
35598    } else {
35599      if (index >= 0 && index <= (_.slideCount - _.options.slidesToShow)) {
35600        _.$slides
35601          .slice(index, index + _.options.slidesToShow)
35602          .addClass('slick-active')
35603          .attr('aria-hidden', 'false');
35604      } else if (allSlides.length <= _.options.slidesToShow) {
35605        allSlides
35606          .addClass('slick-active')
35607          .attr('aria-hidden', 'false');
35608      } else {
35609        remainder = _.slideCount % _.options.slidesToShow;
35610        indexOffset = _.options.infinite === true ? _.options.slidesToShow + index : index;
35611        if (_.options.slidesToShow == _.options.slidesToScroll && (_.slideCount - index) < _.options.slidesToShow) {
35612          allSlides
35613            .slice(indexOffset - (_.options.slidesToShow - remainder), indexOffset + remainder)
35614            .addClass('slick-active')
35615            .attr('aria-hidden', 'false');
35616        } else {
35617          allSlides
35618            .slice(indexOffset, indexOffset + _.options.slidesToShow)
35619            .addClass('slick-active')
35620            .attr('aria-hidden', 'false');
35621        }
35622      }
35623    }
35624    if (_.options.lazyLoad === 'ondemand') {
35625      _.lazyLoad();
35626    }
35627  };
35628  Slick.prototype.setupInfinite = function() {
35629    var _ = this,
35630      i, slideIndex, infiniteCount;
35631    if (_.options.fade === true) {
35632      _.options.centerMode = false;
35633    }
35634    if (_.options.infinite === true && _.options.fade === false) {
35635      slideIndex = null;
35636      if (_.slideCount > _.options.slidesToShow) {
35637        if (_.options.centerMode === true) {
35638          infiniteCount = _.options.slidesToShow + 1;
35639        } else {
35640          infiniteCount = _.options.slidesToShow;
35641        }
35642        for (i = _.slideCount; i > (_.slideCount -
35643          infiniteCount); i -= 1) {
35644          slideIndex = i - 1;
35645          $(_.$slides[slideIndex]).clone(true).attr('id', '')
35646            .attr('data-slick-index', slideIndex - _.slideCount)
35647            .prependTo(_.$slideTrack).addClass('slick-cloned');
35648        }
35649        for (i = 0; i < infiniteCount; i += 1) {
35650          slideIndex = i;
35651          $(_.$slides[slideIndex]).clone(true).attr('id', '')
35652            .attr('data-slick-index', slideIndex + _.slideCount)
35653            .appendTo(_.$slideTrack).addClass('slick-cloned');
35654        }
35655        _.$slideTrack.find('.slick-cloned').find('[id]').each(function() {
35656          $(this).attr('id', '');
35657        });
35658      }
35659    }
35660  };
35661  Slick.prototype.interrupt = function( toggle ) {
35662    var _ = this;
35663    if( !toggle ) {
35664      _.autoPlay();
35665    }
35666    _.interrupted = toggle;
35667  };
35668  Slick.prototype.selectHandler = function(event) {
35669    var _ = this;
35670    var targetElement =
35671      $(event.target).is('.slick-slide') ?
35672        $(event.target) :
35673        $(event.target).parents('.slick-slide');
35674    var index = parseInt(targetElement.attr('data-slick-index'));
35675    if (!index) index = 0;
35676    if (_.slideCount <= _.options.slidesToShow) {
35677      _.setSlideClasses(index);
35678      _.asNavFor(index);
35679      return;
35680    }
35681    _.slideHandler(index);
35682  };
35683  Slick.prototype.slideHandler = function(index, sync, dontAnimate) {
35684    var targetSlide, animSlide, oldSlide, slideLeft, targetLeft = null,
35685      _ = this, navTarget;
35686    sync = sync || false;
35687    if (_.animating === true && _.options.waitForAnimate === true) {
35688      return;
35689    }
35690    if (_.options.fade === true && _.currentSlide === index) {
35691      return;
35692    }
35693    if (_.slideCount <= _.options.slidesToShow) {
35694      return;
35695    }
35696    if (sync === false) {
35697      _.asNavFor(index);
35698    }
35699    targetSlide = index;
35700    targetLeft = _.getLeft(targetSlide);
35701    slideLeft = _.getLeft(_.currentSlide);
35702    _.currentLeft = _.swipeLeft === null ? slideLeft : _.swipeLeft;
35703    if (_.options.infinite === false && _.options.centerMode === false && (index < 0 || index > _.getDotCount() * _.options.slidesToScroll)) {
35704      if (_.options.fade === false) {
35705        targetSlide = _.currentSlide;
35706        if (dontAnimate !== true) {
35707          _.animateSlide(slideLeft, function() {
35708            _.postSlide(targetSlide);
35709          });
35710        } else {
35711          _.postSlide(targetSlide);
35712        }
35713      }
35714      return;
35715    } else if (_.options.infinite === false && _.options.centerMode === true && (index < 0 || index > (_.slideCount - _.options.slidesToScroll))) {
35716      if (_.options.fade === false) {
35717        targetSlide = _.currentSlide;
35718        if (dontAnimate !== true) {
35719          _.animateSlide(slideLeft, function() {
35720            _.postSlide(targetSlide);
35721          });
35722        } else {
35723          _.postSlide(targetSlide);
35724        }
35725      }
35726      return;
35727    }
35728    if ( _.options.autoplay ) {
35729      clearInterval(_.autoPlayTimer);
35730    }
35731    if (targetSlide < 0) {
35732      if (_.slideCount % _.options.slidesToScroll !== 0) {
35733        animSlide = _.slideCount - (_.slideCount % _.options.slidesToScroll);
35734      } else {
35735        animSlide = _.slideCount + targetSlide;
35736      }
35737    } else if (targetSlide >= _.slideCount) {
35738      if (_.slideCount % _.options.slidesToScroll !== 0) {
35739        animSlide = 0;
35740      } else {
35741        animSlide = targetSlide - _.slideCount;
35742      }
35743    } else {
35744      animSlide = targetSlide;
35745    }
35746    _.animating = true;
35747    _.$slider.trigger('beforeChange', [_, _.currentSlide, animSlide]);
35748    oldSlide = _.currentSlide;
35749    _.currentSlide = animSlide;
35750    _.setSlideClasses(_.currentSlide);
35751    if ( _.options.asNavFor ) {
35752      navTarget = _.getNavTarget();
35753      navTarget = navTarget.slick('getSlick');
35754      if ( navTarget.slideCount <= navTarget.options.slidesToShow ) {
35755        navTarget.setSlideClasses(_.currentSlide);
35756      }
35757    }
35758    _.updateDots();
35759    _.updateArrows();
35760    if (_.options.fade === true) {
35761      if (dontAnimate !== true) {
35762        _.fadeSlideOut(oldSlide);
35763        _.fadeSlide(animSlide, function() {
35764          _.postSlide(animSlide);
35765        });
35766      } else {
35767        _.postSlide(animSlide);
35768      }
35769      _.animateHeight();
35770      return;
35771    }
35772    if (dontAnimate !== true) {
35773      _.animateSlide(targetLeft, function() {
35774        _.postSlide(animSlide);
35775      });
35776    } else {
35777      _.postSlide(animSlide);
35778    }
35779  };
35780  Slick.prototype.startLoad = function() {
35781    var _ = this;
35782    if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
35783      _.$prevArrow.hide();
35784      _.$nextArrow.hide();
35785    }
35786    if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
35787      _.$dots.hide();
35788    }
35789    _.$slider.addClass('slick-loading');
35790  };
35791  Slick.prototype.swipeDirection = function() {
35792    var xDist, yDist, r, swipeAngle, _ = this;
35793    xDist = _.touchObject.startX - _.touchObject.curX;
35794    yDist = _.touchObject.startY - _.touchObject.curY;
35795    r = Math.atan2(yDist, xDist);
35796    swipeAngle = Math.round(r * 180 / Math.PI);
35797    if (swipeAngle < 0) {
35798      swipeAngle = 360 - Math.abs(swipeAngle);
35799    }
35800    if ((swipeAngle <= 45) && (swipeAngle >= 0)) {
35801      return (_.options.rtl === false ? 'left' : 'right');
35802    }
35803    if ((swipeAngle <= 360) && (swipeAngle >= 315)) {
35804      return (_.options.rtl === false ? 'left' : 'right');
35805    }
35806    if ((swipeAngle >= 135) && (swipeAngle <= 225)) {
35807      return (_.options.rtl === false ? 'right' : 'left');
35808    }
35809    if (_.options.verticalSwiping === true) {
35810      if ((swipeAngle >= 35) && (swipeAngle <= 135)) {
35811        return 'down';
35812      } else {
35813        return 'up';
35814      }
35815    }
35816    return 'vertical';
35817  };
35818  Slick.prototype.swipeEnd = function(event) {
35819    var _ = this,
35820      slideCount,
35821      direction;
35822    _.dragging = false;
35823    _.interrupted = false;
35824    _.shouldClick = ( _.touchObject.swipeLength > 10 ) ? false : true;
35825    if ( _.touchObject.curX === undefined ) {
35826      return false;
35827    }
35828    if ( _.touchObject.edgeHit === true ) {
35829      _.$slider.trigger('edge', [_, _.swipeDirection() ]);
35830    }
35831    if ( _.touchObject.swipeLength >= _.touchObject.minSwipe ) {
35832      direction = _.swipeDirection();
35833      switch ( direction ) {
35834        case 'left':
35835        case 'down':
35836          slideCount =
35837            _.options.swipeToSlide ?
35838              _.checkNavigable( _.currentSlide + _.getSlideCount() ) :
35839              _.currentSlide + _.getSlideCount();
35840          _.currentDirection = 0;
35841          break;
35842        case 'right':
35843        case 'up':
35844          slideCount =
35845            _.options.swipeToSlide ?
35846              _.checkNavigable( _.currentSlide - _.getSlideCount() ) :
35847              _.currentSlide - _.getSlideCount();
35848          _.currentDirection = 1;
35849          break;
35850        default:
35851      }
35852      if( direction != 'vertical' ) {
35853        _.slideHandler( slideCount );
35854        _.touchObject = {};
35855        _.$slider.trigger('swipe', [_, direction ]);
35856      }
35857    } else {
35858      if ( _.touchObject.startX !== _.touchObject.curX ) {
35859        _.slideHandler( _.currentSlide );
35860        _.touchObject = {};
35861      }
35862    }
35863  };
35864  Slick.prototype.swipeHandler = function(event) {
35865    var _ = this;
35866    if ((_.options.swipe === false) || ('ontouchend' in document && _.options.swipe === false)) {
35867      return;
35868    } else if (_.options.draggable === false && event.type.indexOf('mouse') !== -1) {
35869      return;
35870    }
35871    _.touchObject.fingerCount = event.originalEvent && event.originalEvent.touches !== undefined ?
35872      event.originalEvent.touches.length : 1;
35873    _.touchObject.minSwipe = _.listWidth / _.options
35874      .touchThreshold;
35875    if (_.options.verticalSwiping === true) {
35876      _.touchObject.minSwipe = _.listHeight / _.options
35877        .touchThreshold;
35878    }
35879    switch (event.data.action) {
35880      case 'start':
35881        _.swipeStart(event);
35882        break;
35883      case 'move':
35884        _.swipeMove(event);
35885        break;
35886      case 'end':
35887        _.swipeEnd(event);
35888        break;
35889    }
35890  };
35891  Slick.prototype.swipeMove = function(event) {
35892    var _ = this,
35893      edgeWasHit = false,
35894      curLeft, swipeDirection, swipeLength, positionOffset, touches;
35895    touches = event.originalEvent !== undefined ? event.originalEvent.touches : null;
35896    if (!_.dragging || touches && touches.length !== 1) {
35897      return false;
35898    }
35899    curLeft = _.getLeft(_.currentSlide);
35900    _.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX;
35901    _.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY;
35902    _.touchObject.swipeLength = Math.round(Math.sqrt(
35903      Math.pow(_.touchObject.curX - _.touchObject.startX, 2)));
35904    if (_.options.verticalSwiping === true) {
35905      _.touchObject.swipeLength = Math.round(Math.sqrt(
35906        Math.pow(_.touchObject.curY - _.touchObject.startY, 2)));
35907    }
35908    swipeDirection = _.swipeDirection();
35909    if (swipeDirection === 'vertical') {
35910      return;
35911    }
35912    if (event.originalEvent !== undefined && _.touchObject.swipeLength > 4) {
35913      event.preventDefault();
35914    }
35915    positionOffset = (_.options.rtl === false ? 1 : -1) * (_.touchObject.curX > _.touchObject.startX ? 1 : -1);
35916    if (_.options.verticalSwiping === true) {
35917      positionOffset = _.touchObject.curY > _.touchObject.startY ? 1 : -1;
35918    }
35919    swipeLength = _.touchObject.swipeLength;
35920    _.touchObject.edgeHit = false;
35921    if (_.options.infinite === false) {
35922      if ((_.currentSlide === 0 && swipeDirection === 'right') || (_.currentSlide >= _.getDotCount() && swipeDirection === 'left')) {
35923        swipeLength = _.touchObject.swipeLength * _.options.edgeFriction;
35924        _.touchObject.edgeHit = true;
35925      }
35926    }
35927    if (_.options.vertical === false) {
35928      _.swipeLeft = curLeft + swipeLength * positionOffset;
35929    } else {
35930      _.swipeLeft = curLeft + (swipeLength * (_.$list.height() / _.listWidth)) * positionOffset;
35931    }
35932    if (_.options.verticalSwiping === true) {
35933      _.swipeLeft = curLeft + swipeLength * positionOffset;
35934    }
35935    if (_.options.fade === true || _.options.touchMove === false) {
35936      return false;
35937    }
35938    if (_.animating === true) {
35939      _.swipeLeft = null;
35940      return false;
35941    }
35942    _.setCSS(_.swipeLeft);
35943  };
35944  Slick.prototype.swipeStart = function(event) {
35945    var _ = this,
35946      touches;
35947    _.interrupted = true;
35948    if (_.touchObject.fingerCount !== 1 || _.slideCount <= _.options.slidesToShow) {
35949      _.touchObject = {};
35950      return false;
35951    }
35952    if (event.originalEvent !== undefined && event.originalEvent.touches !== undefined) {
35953      touches = event.originalEvent.touches[0];
35954    }
35955    _.touchObject.startX = _.touchObject.curX = touches !== undefined ? touches.pageX : event.clientX;
35956    _.touchObject.startY = _.touchObject.curY = touches !== undefined ? touches.pageY : event.clientY;
35957    _.dragging = true;
35958  };
35959  Slick.prototype.unfilterSlides = Slick.prototype.slickUnfilter = function() {
35960    var _ = this;
35961    if (_.$slidesCache !== null) {
35962      _.unload();
35963      _.$slideTrack.children(this.options.slide).detach();
35964      _.$slidesCache.appendTo(_.$slideTrack);
35965      _.reinit();
35966    }
35967  };
35968  Slick.prototype.unload = function() {
35969    var _ = this;
35970    $('.slick-cloned', _.$slider).remove();
35971    if (_.$dots) {
35972      _.$dots.remove();
35973    }
35974    if (_.$prevArrow && _.htmlExpr.test(_.options.prevArrow)) {
35975      _.$prevArrow.remove();
35976    }
35977    if (_.$nextArrow && _.htmlExpr.test(_.options.nextArrow)) {
35978      _.$nextArrow.remove();
35979    }
35980    _.$slides
35981      .removeClass('slick-slide slick-active slick-visible slick-current')
35982      .attr('aria-hidden', 'true')
35983      .css('width', '');
35984  };
35985  Slick.prototype.unslick = function(fromBreakpoint) {
35986    var _ = this;
35987    _.$slider.trigger('unslick', [_, fromBreakpoint]);
35988    _.destroy();
35989  };
35990  Slick.prototype.updateArrows = function() {
35991    var _ = this,
35992      centerOffset;
35993    centerOffset = Math.floor(_.options.slidesToShow / 2);
35994    if ( _.options.arrows === true &&
35995      _.slideCount > _.options.slidesToShow &&
35996      !_.options.infinite ) {
35997      _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
35998      _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
35999      if (_.currentSlide === 0) {
36000        _.$prevArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
36001        _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
36002      } else if (_.currentSlide >
36002= _.slideCount - _.options.slidesToShow && _.options.centerMode === false) {
36003        _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
36004        _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
36005      } else if (_.currentSlide >= _.slideCount - 1 && _.options.centerMode === true) {
36006        _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
36007        _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
36008      }
36009    }
36010  };
36011  Slick.prototype.updateDots = function() {
36012    var _ = this;
36013    if (_.$dots !== null) {
36014      _.$dots
36015        .find('li')
36016        .removeClass('slick-active')
36017        .attr('aria-hidden', 'true');
36018      _.$dots
36019        .find('li')
36020        .eq(Math.floor(_.currentSlide / _.options.slidesToScroll))
36021        .addClass('slick-active')
36022        .attr('aria-hidden', 'false');
36023    }
36024  };
36025  Slick.prototype.visibility = function() {
36026    var _ = this;
36027    if ( _.options.autoplay ) {
36028      if ( document[_.hidden] ) {
36029        _.interrupted = true;
36030      } else {
36031        _.interrupted = false;
36032      }
36033    }
36034  };
36035  $.fn.slick = function() {
36036    var _ = this,
36037      opt = arguments[0],
36038      args = Array.prototype.slice.call(arguments, 1),
36039      l = _.length,
36040      i,
36041      ret;
36042    for (i = 0; i < l; i++) {
36043      if (typeof opt == 'object' || typeof opt == 'undefined')
36044        _[i].slick = new Slick(_[i], opt);
36045      else
36046        ret = _[i].slick[opt].apply(_[i].slick, args);
36047      if (typeof ret != 'undefined') return ret;
36048    }
36049    return _;
36050  };
36051}));
36052
36053   /* Ende slick */
36054   /* Start jquery.magnific-popup */
36055   /*! Magnific Popup - v0.9.9 - 2013-12-27
36056* http://dimsemenov.com/plugins/magnific-popup/
36057* Copyright (c) 2013 Dmitry Semenov; */
36058;(function($) {
36059
36060/*>>core*/
36061/**
36062 *
36063 * Magnific Popup Core JS file
36064 *
36065 */
36066
36067/**
36068 * Private static constants
36069 */
36070var CLOSE_EVENT = 'Close',
36071 BEFORE_CLOSE_EVENT = 'BeforeClose',
36072 AFTER_CLOSE_EVENT = 'AfterClose',
36073 BEFORE_APPEND_EVENT = 'BeforeAppend',
36074 MARKUP_PARSE_EVENT = 'MarkupParse',
36075 OPEN_EVENT = 'Open',
36076 CHANGE_EVENT = 'Change',
36077 NS = 'mfp',
36078 EVENT_NS = '.' + NS,
36079 READY_CLASS = 'mfp-ready',
36080 REMOVING_CLASS = 'mfp-removing',
36081 PREVENT_CLOSE_CLASS = 'mfp-prevent-close';
36082
36083/**
36084 * Private vars
36085 */
36086var mfp, // As we have only one instance of MagnificPopup object, we define it locally to not to use 'this'
36087 MagnificPopup = function(){},
36088 _isJQ = !!(window.jQuery),
36089 _prevStatus,
36090 _window = $(window),
36091 _body,
36092 _document,
36093 _prevContentType,
36094 _wrapClasses,
36095 _currPopupType;
36096
36097/**
36098 * Private functions
36099 */
36100var _mfpOn = function(name, f) {
36101  mfp.ev.on(NS + name + EVENT_NS, f);
36102 },
36103 _getEl = function(className, appendTo, html, raw) {
36104  var el = document.createElement('div');
36105  el.className = 'mfp-'+className;
36106  if(html) {
36107   el.innerHTML = html;
36108  }
36109  if(!raw) {
36110   el = $(el);
36111   if(appendTo) {
36112    el.appendTo(appendTo);
36113   }
36114  } else if(appendTo) {
36115   appendTo.appendChild(el);
36116  }
36117  return el;
36118 },
36119 _mfpTrigger = function(e, data) {
36120  mfp.ev.triggerHandler(NS + e, data);
36121
36122  if(mfp.st.callbacks) {
36123   // converts "mfpEventName" to "eventName" callback and triggers it if it's present
36124   e = e.charAt(0).toLowerCase() + e.slice(1);
36125   if(mfp.st.callbacks[e]) {
36126    mfp.st.callbacks[e].apply(mfp, $.isArray(data) ? data : [data]);
36127   }
36128  }
36129 },
36130 _getCloseBtn = function(type) {
36131  if(type !== _currPopupType || !mfp.currTemplate.closeBtn) {
36132   mfp.currTemplate.closeBtn = $( mfp.st.closeMarkup.replace('%title%', mfp.st.tClose ) );
36133   _currPopupType = type;
36134  }
36135  return mfp.currTemplate.closeBtn;
36136 },
36137 // Initialize Magnific Popup only when called at least once
36138 _checkInstance = function() {
36139  if(!$.magnificPopup.instance) {
36140   mfp = new MagnificPopup();
36141   mfp.init();
36142   $.magnificPopup.instance = mfp;
36143  }
36144 },
36145 // CSS transition detection, http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr
36146 supportsTransitions = function() {
36147  var s = document.createElement('p').style, // 's' for style. better to create an element if body yet to exist
36148   v = ['ms','O','Moz','Webkit']; // 'v' for vendor
36149
36150  if( s['transition'] !== undefined ) {
36151   return true;
36152  }
36153  
36154  while( v.length ) {
36155   if( v.pop() + 'Transition' in s ) {
36156    return true;
36157   }
36158  }
36159   
36160  return false;
vendor: 24,482 bytes, lines 36161-37265
36161 };
36162
36163/**
36164 * Public functions
36165 */
36166MagnificPopup.prototype = {
36167
36168 constructor: MagnificPopup,
36169
36170 /**
36171  * Initializes Magnific Popup plugin.
36172  * This function is triggered only once when $.fn.magnificPopup or $.magnificPopup is executed
36173  */
36174 init: function() {
36175  var appVersion = navigator.appVersion;
36176  mfp.isIE7 = appVersion.indexOf("MSIE 7.") !== -1;
36177  mfp.isIE8 = appVersion.indexOf("MSIE 8.") !== -1;
36178  mfp.isLowIE = mfp.isIE7 || mfp.isIE8;
36179  mfp.isAndroid = (/android/gi).test(appVersion);
36180  mfp.isIOS = (/iphone|ipad|ipod/gi).test(appVersion);
36181  mfp.supportsTransition = supportsTransitions();
36182
36183  // We disable fixed positioned lightbox on devices that don't handle it nicely.
36184  // If you know a better way of detecting this - let me know.
36185  mfp.probablyMobile = (mfp.isAndroid || mfp.isIOS || /(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent) );
36186  _document = $(document);
36187
36188  mfp.popupsCache = {};
36189 },
36190
36191 /**
36192  * Opens popup
36193  * @param  data [description]
36194  */
36195 open: function(data) {
36196
36197  if(!_body) {
36198   _body = $(document.body);
36199  }
36200
36201  var i;
36202
36203  if(data.isObj === false) {
36204   // convert jQuery collection to array to avoid conflicts later
36205   mfp.items = data.items.toArray();
36206
36207   mfp.index = 0;
36208   var items = data.items,
36209    item;
36210   for(i = 0; i < items.length; i++) {
36211    item = items[i];
36212    if(item.parsed) {
36213     item = item.el[0];
36214    }
36215    if(item === data.el[0]) {
36216     mfp.index = i;
36217     break;
36218    }
36219   }
36220  } else {
36221   mfp.items = $.isArray(data.items) ? data.items : [data.items];
36222   mfp.index = data.index || 0;
36223  }
36224
36225  // if popup is already opened - we just update the content
36226  if(mfp.isOpen) {
36227   mfp.updateItemHTML();
36228   return;
36229  }
36230 
36231  mfp.types = [];
36232  _wrapClasses = '';
36233  if(data.mainEl && data.mainEl.length) {
36234   mfp.ev = data.mainEl.eq(0);
36235  } else {
36236   mfp.ev = _document;
36237  }
36238
36239  if(data.key) {
36240   if(!mfp.popupsCache[data.key]) {
36241    mfp.popupsCache[data.key] = {};
36242   }
36243   mfp.currTemplate = mfp.popupsCache[data.key];
36244  } else {
36245   mfp.currTemplate = {};
36246  }
36247
36248  mfp.st = $.extend(true, {}, $.magnificPopup.defaults, data );
36249  mfp.fixedContentPos = mfp.st.fixedContentPos === 'auto' ? !mfp.probablyMobile : mfp.st.fixedContentPos;
36250
36251  if(mfp.st.modal) {
36252   mfp.st.closeOnContentClick = false;
36253   mfp.st.closeOnBgClick = false;
36254   mfp.st.showCloseBtn = false;
36255   mfp.st.enableEscapeKey = false;
36256  }
36257 
36258
36259  // Building markup
36260  // main containers are created only once
36261  if(!mfp.bgOverlay) {
36262
36263   // Dark overlay
36264   mfp.bgOverlay = _getEl('bg').on('click'+EVENT_NS, function() {
36265    mfp.close();
36266   });
36267
36268   mfp.wrap = _getEl('wrap').attr('tabindex', -1).on('click'+EVENT_NS, function(e) {
36269    if(mfp._checkIfClose(e.target)) {
36270     mfp.close();
36271    }
36272   });
36273
36274   mfp.container = _getEl('container', mfp.wrap);
36275  }
36276
36277  mfp.contentContainer = _getEl('content');
36278  if(mfp.st.preloader) {
36279   mfp.preloader = _getEl('preloader', mfp.container, mfp.st.tLoading);
36280  }
36281
36282  // Initializing modules
36283  var modules = $.magnificPopup.modules;
36284  for(i = 0; i < modules.length; i++) {
36285   var n = modules[i];
36286   n = n.charAt(0).toUpperCase() + n.slice(1);
36287   mfp['init'+n].call(mfp);
36288  }
36289  _mfpTrigger('BeforeOpen');
36290
36291  if(mfp.st.showCloseBtn) {
36292   // Close button
36293   if(!mfp.st.closeBtnInside) {
36294    mfp.wrap.append( _getCloseBtn() );
36295   } else {
36296    _mfpOn(MARKUP_PARSE_EVENT, function(e, template, values, item) {
36297     values.close_replaceWith = _getCloseBtn(item.type);
36298    });
36299    _wrapClasses += ' mfp-close-btn-in';
36300   }
36301  }
36302
36303  if(mfp.st.alignTop) {
36304   _wrapClasses += ' mfp-align-top';
36305  }
36306
36307  if(mfp.fixedContentPos) {
36308   mfp.wrap.css({
36309    overflow: mfp.st.overflowY,
36310    overflowX: 'hidden',
36311    overflowY: mfp.st.overflowY
36312   });
36313  } else {
36314   mfp.wrap.css({
36315    top: _window.scrollTop(),
36316    position: 'absolute'
36317   });
36318  }
36319  if( mfp.st.fixedBgPos === false || (mfp.st.fixedBgPos === 'auto' && !mfp.fixedContentPos) ) {
36320   mfp.bgOverlay.css({
36321    height: _document.height(),
36322    position: 'absolute'
36323   });
36324  }
36325
36326 
36327
36328  if(mfp.st.enableEscapeKey) {
36329   // Close on ESC key
36330   _document.on('keyup' + EVENT_NS, function(e) {
36331    if(e.keyCode === 27) {
36332     mfp.close();
36333    }
36334   });
36335  }
36336
36337  _window.on('resize' + EVENT_NS, function() {
36338   mfp.updateSize();
36339  });
36340
36341  if(!mfp.st.closeOnContentClick) {
36342   _wrapClasses += ' mfp-auto-cursor';
36343  }
36344 
36345  if(_wrapClasses)
36346   mfp.wrap.addClass(_wrapClasses);
36347
36348  // this triggers recalculation of layout, so we get it once to not to trigger twice
36349  var windowHeight = mfp.wH = _window.height();
36350
36351 
36352  var windowStyles = {};
36353
36354  if( mfp.fixedContentPos ) {
36355            if(mfp._hasScrollBar(windowHeight)){
36356                var s = mfp._getScrollbarSize();
36357                if(s) {
36358                    windowStyles.marginRight = s;
36359                }
36360            }
36361        }
36362
36363  if(mfp.fixedContentPos) {
36364   if(!mfp.isIE7) {
36365    windowStyles.overflow = 'hidden';
36366   } else {
36367    // ie7 double-scroll bug
36368    $('body, html').css('overflow', 'hidden');
36369   }
36370  }
36371
36372 
36373 
36374  var classesToadd = mfp.st.mainClass;
36375  if(mfp.isIE7) {
36376   classesToadd += ' mfp-ie7';
36377  }
36378  if(classesToadd) {
36379   mfp._addClassToMFP( classesToadd );
36380  }
36381
36382  // add content
36383  mfp.updateItemHTML();
36384
36385  _mfpTrigger('BuildControls');
36386
36387  // remove scrollbar, add margin e.t.c
36388  $('html').css(windowStyles);
36389 
36390  // add everything to DOM
36391  mfp.bgOverlay.add(mfp.wrap).prependTo( mfp.st.prependTo || _body );
36392
36393  // Save last focused element
36394  mfp._lastFocusedEl = document.activeElement;
36395 
36396  // Wait for next cycle to allow CSS transition
36397  setTimeout(function() {
36398  
36399   if(mfp.content) {
36400    mfp._addClassToMFP(READY_CLASS);
36401    mfp._setFocus();
36402   } else {
36403    // if content is not defined (not loaded e.t.c) we add class only for BG
36404    mfp.bgOverlay.addClass(READY_CLASS);
36405   }
36406  
36407   // Trap the focus in popup
36408   _document.on('focusin' + EVENT_NS, mfp._onFocusIn);
36409
36410  }, 16);
36411
36412  mfp.isOpen = true;
36413  mfp.updateSize(windowHeight);
36414  _mfpTrigger(OPEN_EVENT);
36415
36416  return data;
36417 },
36418
36419 /**
36420  * Closes the popup
36421  */
36422 close: function() {
36423  if(!mfp.isOpen) return;
36424  _mfpTrigger(BEFORE_CLOSE_EVENT);
36425
36426  mfp.isOpen = false;
36427  // for CSS3 animation
36428  if(mfp.st.removalDelay && !mfp.isLowIE && mfp.supportsTransition )  {
36429   mfp._addClassToMFP(REMOVING_CLASS);
36430   setTimeout(function() {
36431    mfp._close();
36432   }, mfp.st.removalDelay);
36433  } else {
36434   mfp._close();
36435  }
36436 },
36437
36438 /**
36439  * Helper for close() function
36440  */
36441 _close: function() {
36442  _mfpTrigger(CLOSE_EVENT);
36443
36444  var classesToRemove = REMOVING_CLASS + ' ' + READY_CLASS + ' ';
36445
36446  mfp.bgOverlay.detach();
36447  mfp.wrap.detach();
36448  mfp.container.empty();
36449
36450  if(mfp.st.mainClass) {
36451   classesToRemove += mfp.st.mainClass + ' ';
36452  }
36453
36454  mfp._removeClassFromMFP(classesToRemove);
36455
36456  if(mfp.fixedContentPos) {
36457   var windowStyles = {marginRight: ''};
36458   if(mfp.isIE7) {
36459    $('body, html').css('overflow', '');
36460   } else {
36461    windowStyles.overflow = '';
36462   }
36463   $('html').css(windowStyles);
36464  }
36465 
36466  _document.off('keyup' + EVENT_NS + ' focusin' + EVENT_NS);
36467  mfp.ev.off(EVENT_NS);
36468
36469  // clean up DOM elements that aren't removed
36470  mfp.wrap.attr('class', 'mfp-wrap').removeAttr('style');
36471  mfp.bgOverlay.attr('class', 'mfp-bg');
36472  mfp.container.attr('class', 'mfp-container');
36473
36474  // remove close button from target element
36475  if(mfp.st.showCloseBtn &&
36476  (!mfp.st.closeBtnInside || mfp.currTemplate[mfp.currItem.type] === true)) {
36477   if(mfp.currTemplate.closeBtn)
36478    mfp.currTemplate.closeBtn.detach();
36479  }
36480
36481  if(mfp._lastFocusedEl) {
36482   $(mfp._lastFocusedEl).focus(); // put tab focus back
36483  }
36484  mfp.currItem = null;
36485  mfp.content = null;
36486  mfp.currTemplate = null;
36487  mfp.prevHeight = 0;
36488
36489  _mfpTrigger(AFTER_CLOSE_EVENT);
36490 },
36491 updateSize: function(winHeight) {
36492
36493  if(mfp.isIOS) {
36494   // fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2
36495   var zoomLevel = document.documentElement.clientWidth / window.innerWidth;
36496   var height = window.innerHeight * zoomLevel;
36497   mfp.wrap.css('height', height);
36498   mfp.wH = height;
36499  } else {
36500   mfp.wH = winHeight || _window.height();
36501  }
36502  // Fixes #84: popup incorrectly positioned with position:relative on body
36503  if(!mfp.fixedContentPos) {
36504   mfp.wrap.css('height', mfp.wH);
36505  }
36506
36507  _mfpTrigger('Resize');
36508
36509 },
36510
36511 /**
36512  * Set content of popup based on current index
36513  */
36514 updateItemHTML: function() {
36515  var item = mfp.items[mfp.index];
36516
36517  // Detach and perform modifications
36518  mfp.contentContainer.detach();
36519
36520  if(mfp.content)
36521   mfp.content.detach();
36522
36523  if(!item.parsed) {
36524   item = mfp.parseEl( mfp.index );
36525  }
36526
36527  var type = item.type;
36528
36529  _mfpTrigger('BeforeChange', [mfp.currItem ? mfp.currItem.type : '', type]);
36530  // BeforeChange event works like so:
36531  // _mfpOn('BeforeChange', function(e, prevType, newType) { });
36532 
36533  mfp.currItem = item;
36534
36535 
36536
36537 
36538
36539  if(!mfp.currTemplate[type]) {
36540   var markup = mfp.st[type] ? mfp.st[type].markup : false;
36541
36542   // allows to modify markup
36543   _mfpTrigger('FirstMarkupParse', markup);
36544
36545   if(markup) {
36546    mfp.currTemplate[type] = $(markup);
36547   } else {
36548    // if there is no markup found we just define that template is parsed
36549    mfp.currTemplate[type] = true;
36550   }
36551  }
36552
36553  if(_prevContentType && _prevContentType !== item.type) {
36554   mfp.container.removeClass('mfp-'+_prevContentType+'-holder');
36555  }
36556 
36557  var newContent = mfp['get' + type.charAt(0).toUpperCase() + type.slice(1)](item, mfp.currTemplate[type]);
36558  mfp.appendContent(newContent, type);
36559
36560  item.preloaded = true;
36561
36562  _mfpTrigger(CHANGE_EVENT, item);
36563  _prevContentType = item.type;
36564 
36565  // Append container back after its content changed
36566  mfp.container.prepend(mfp.contentContainer);
36567
36568  _mfpTrigger('AfterChange');
36569 },
36570
36571 /**
36572  * Set HTML content of popup
36573  */
36574 appendContent: function(newContent, type) {
36575  mfp.content = newContent;
36576 
36577  if(newContent) {
36578   if(mfp.st.showCloseBtn && mfp.st.closeBtnInside &&
36579    mfp.currTemplate[type] === true) {
36580    // if there is no markup, we just append close button element inside
36581    if(!mfp.content.find('.mfp-close').length) {
36582     mfp.content.append(_getCloseBtn());
36583    }
36584   } else {
36585    mfp.content = newContent;
36586   }
36587  } else {
36588   mfp.content = '';
36589  }
36590
36591  _mfpTrigger(BEFORE_APPEND_EVENT);
36592  mfp.container.addClass('mfp-'+type+'-holder');
36593
36594  mfp.contentContainer.append(mfp.content);
36595 },
36596 /**
36597  * Creates Magnific Popup data object based on given data
36598  * @param  {int} index Index of item to parse
36599  */
36600 parseEl: function(index) {
36601  var item = mfp.items[index],
36602   type;
36603
36604  if(item.tagName) {
36605   item = { el: $(item) };
36606  } else {
36607   type = item.type;
36608   item = { data: item, src: item.src };
36609  }
36610
36611  if(item.el) {
36612   var types = mfp.types;
36613
36614   // check for 'mfp-TYPE' class
36615   for(var i = 0; i < types.length; i++) {
36616    if( item.el.hasClass('mfp-'+types[i]) ) {
36617     type = types[i];
36618     break;
36619    }
36620   }
36621
36622   item.src = item.el.attr('data-mfp-src');
36623   if(!item.src) {
36624    item.src = item.el.attr('href');
36625   }
36626  }
36627
36628  item.type = type || mfp.st.type || 'inline';
36629  item.index = index;
36630  item.parsed = true;
36631  mfp.items[index] = item;
36632  _mfpTrigger('ElementParse', item);
36633
36634  return mfp.items[index];
36635 },
36636
36637 /**
36638  * Initializes single popup or a group of popups
36639  */
36640 addGroup: function(el, options) {
36641  var eHandler = function(e) {
36642   e.mfpEl = this;
36643   mfp._openClick(e, el, options);
36644  };
36645
36646  if(!options) {
36647   options = {};
36648  }
36649
36650  var eName = 'click.magnificPopup';
36651  options.mainEl = el;
36652 
36653  if(options.items) {
36654   options.isObj = true;
36655   el.off(eName).on(eName, eHandler);
36656  } else {
36657   options.isObj = false;
36658   if(options.delegate) {
36659    el.off(eName).on(eName, options.delegate , eHandler);
36660   } else {
36661    options.items = el;
36662    el.off(eName).on(eName, eHandler);
36663   }
36664  }
36665 },
36666 _openClick: function(e, el, options) {
36667  var midClick = options.midClick !== undefined ? options.midClick : $.magnificPopup.defaults.midClick;
36668
36669  if(!midClick && ( e.which === 2 || e.ctrlKey || e.metaKey ) ) {
36670   return;
36671  }
36672
36673  var disableOn = options.disableOn !== undefined ? options.disableOn : $.magnificPopup.defaults.disableOn;
36674
36675  if(disableOn) {
36676   if($.isFunction(disableOn)) {
36677    if( !disableOn.call(mfp) ) {
36678     return true;
36679    }
36680   } else { // else it's number
36681    if( _window.width() < disableOn ) {
36682     return true;
36683    }
36684   }
36685  }
36686 
36687  if(e.type) {
36688   e.preventDefault();
36689
36690   // This will prevent popup from closing if element is inside and popup is already opened
36691   if(mfp.isOpen) {
36692    e.stopPropagation();
36693   }
36694  }
36695  
36696
36697  options.el = $(e.mfpEl);
36698  if(options.delegate) {
36699   options.items = el.find(options.delegate);
36700  }
36701  mfp.open(options);
36702 },
36703
36704 /**
36705  * Updates text on preloader
36706  */
36707 updateStatus: function(status, text) {
36708
36709  if(mfp.preloader) {
36710   if(_prevStatus !== status) {
36711    mfp.container.removeClass('mfp-s-'+_prevStatus);
36712   }
36713
36714   if(!text && status === 'loading') {
36715    text = mfp.st.tLoading;
36716   }
36717
36718   var data = {
36719    status: status,
36720    text: text
36721   };
36722   // allows to modify status
36723   _mfpTrigger('UpdateStatus', data);
36724
36725   status = data.status;
36726   text = data.text;
36727
36728   mfp.preloader.html(text);
36729
36730   mfp.preloader.find('a').on('click', function(e) {
36731    e.stopImmediatePropagation();
36732   });
36733
36734   mfp.container.addClass('mfp-s-'+status);
36735   _prevStatus = status;
36736  }
36737 },
36738
36739 /*
36740  "Private" helpers that aren't private at all
36741  */
36742 // Check to close popup or not
36743 // "target" is an element that was clicked
36744 _checkIfClose: function(target) {
36745
36746  if($(target).hasClass(PREVENT_CLOSE_CLASS)) {
36747   return;
36748  }
36749
36750  var closeOnContent = mfp.st.closeOnContentClick;
36751  var closeOnBg = mfp.st.closeOnBgClick;
36752
36753  if(closeOnContent && closeOnBg) {
36754   return true;
36755  } else {
36756
36757   // We close the popup if click is on close button or on preloader. Or if there is no content.
36758   if(!mfp.content || $(target).hasClass('mfp-close') || (mfp.preloader && target === mfp.preloader[0]) ) {
36759    return true;
36760   }
36761
36762   // if click is outside the content
36763   if( (target !== mfp.content[0] && !$.contains(mfp.content[0].parentElement, target)) ) {
36764    if(closeOnBg) {
36765     // last check, if the clicked element is in DOM, (in case it's removed onclick)
36766     if( $.contains(document, target) ) {
36767      return true;
36768     }
36769    }
36770   } else if(closeOnContent) {
36771    return true;
36772   }
36773
36774  }
36775  return false;
36776 },
36777 _addClassToMFP: function(cName) {
36778  mfp.bgOverlay.addClass(cName);
36779  mfp.wrap.addClass(cName);
36780 },
36781 _removeClassFromMFP: function(cName) {
36782  this.bgOverlay.removeClass(cName);
36783  mfp.wrap.removeClass(cName);
36784 },
36785 _hasScrollBar: function(winHeight) {
36786  return (  (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) );
36787 },
36788 _setFocus: function() {
36789  (mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).focus();
36790 },
36791 _onFocusIn: function(e) {
36792  if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) {
36793   mfp._setFocus();
36794   return false;
36795  }
36796 },
36797 _parseMarkup: function(template, values, item) {
36798  var arr;
36799  if(item.data) {
36800   values = $.extend(item.data, values);
36801  }
36802  _mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] );
36803
36804  $.each(values, function(key, value) {
36805   if(value === undefined || value === false) {
36806    return true;
36807   }
36808   arr = key.split('_');
36809   if(arr.length > 1) {
36810    var el = template.find(EVENT_NS + '-'+arr[0]);
36811
36812    if(el.length > 0) {
36813     var attr = arr[1];
36814     if(attr === 'replaceWith') {
36815      if(el[0] !== value[0]) {
36816       el.replaceWith(value);
36817      }
36818     } else if(attr === 'img') {
36819      if(el.is('img')) {
36820       el.attr('src', value);
36821      } else {
36822       el.replaceWith( '<img src="'+value+'" class="' + el.attr('class') + '" />' );
36823      }
36824     } else {
36825      el.attr(arr[1], value);
36826     }
36827    }
36828
36829   } else {
36830    template.find(EVENT_NS + '-'+key).html(value);
36831   }
36832  });
36833 },
36834
36835 _getScrollbarSize: function() {
36836  // thx David
36837  if(mfp.scrollbarSize === undefined) {
36838   var scrollDiv = document.createElement("div");
36839   scrollDiv.id = "mfp-sbm";
36840   scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
36841   document.body.appendChild(scrollDiv);
36842   mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
36843   document.body.removeChild(scrollDiv);
36844  }
36845  return mfp.scrollbarSize;
36846 }
36847
36848}; /* MagnificPopup core prototype end */
36849
36850/**
36851 * Public static functions
36852 */
36853$.magnificPopup = {
36854 instance: null,
36855 proto: MagnificPopup.prototype,
36856 modules: [],
36857
36858 open: function(options, index) {
36859  _checkInstance();
36860
36861  if(!options) {
36862   options = {};
36863  } else {
36864   options = $.extend(true, {}, options);
36865  }
36866  
36867
36868  options.isObj = true;
36869  options.index = index || 0;
36870  return this.instance.open(options);
36871 },
36872
36873 close: function() {
36874  return $.magnificPopup.instance && $.magnificPopup.instance.close();
36875 },
36876
36877 registerModule: function(name, module) {
36878  if(module.options) {
36879   $.magnificPopup.defaults[name] = module.options;
36880  }
36881  $.extend(this.proto, module.proto);  
36882  this.modules.push(name);
36883 },
36884
36885 defaults: {  
36886
36887  // Info about options is in docs:
36888  // http://dimsemenov.com/plugins/magnific-popup/documentation.html#options
36889 
36890  disableOn: 0,
36891
36892  key: null,
36893
36894  midClick: false,
36895
36896  mainClass: '',
36897
36898  preloader: true,
36899
36900  focus: '', // CSS selector of input to focus after popup is opened
36901 
36902  closeOnContentClick: false,
36903
36904  closeOnBgClick: true,
36905
36906  closeBtnInside: true,
36907
36908  showCloseBtn: true,
36909
36910  enableEscapeKey: true,
36911
36912  modal: false,
36913
36914  alignTop: false,
36915  removalDelay: 0,
36916
36917  prependTo: null,
36918 
36919  fixedContentPos: 'auto',
36920  fixedBgPos: 'auto',
36921
36922  overflowY: 'auto',
36923
36924  closeMarkup: '<button title="%title%" type="button" class="mfp-close">&times;</button>',
36925
36926  tClose: 'Close (Esc)',
36927
36928  tLoading: 'Loading...'
36929
36930 }
36931};
36932
36933$.fn.magnificPopup = function(options) {
36934 _checkInstance();
36935
36936 var jqEl = $(this);
36937
36938 // We call some API method of first param is a string
36939 if (typeof options === "string" ) {
36940
36941  if(options === 'open') {
36942   var items,
36943    itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup,
36944    index = parseInt(arguments[1], 10) || 0;
36945
36946   if(itemOpts.items) {
36947    items = itemOpts.items[index];
36948   } else {
36949    items = jqEl;
36950    if(itemOpts.delegate) {
36951     items = items.find(itemOpts.delegate);
36952    }
36953    items = items.eq( index );
36954   }
36955   mfp._openClick({mfpEl:items}, jqEl, itemOpts);
36956  } else {
36957   if(mfp.isOpen)
36958    mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1));
36959  }
36960
36961 } else {
36962  // clone options obj
36963  options = $.extend(true, {}, options);
36964 
36965  /*
36966   * As Zepto doesn't support .data() method for objects
36967   * and it works only in normal browsers
36968   * we assign "options" object directly to the DOM element. FTW!
36969   */
36970  if(_isJQ) {
36971   jqEl.data('magnificPopup', options);
36972  } else {
36973   jqEl[0].magnificPopup = options;
36974  }
36975
36976  mfp.addGroup(jqEl, options);
36977
36978 }
36979 return jqEl;
36980};
36981
36982//Quick benchmark
36983/*
36984var start = performance.now(),
36985 i,
36986 rounds = 1000;
36987
36988for(i = 0; i < rounds; i++) {
36989
36990}
36991console.log('Test #1:', performance.now() - start);
36992
36993start = performance.now();
36994for(i = 0; i < rounds; i++) {
36995
36996}
36997console.log('Test #2:', performance.now() - start);
36998*/
36999
37000/*>>core*/
37001
37002/*>>inline*/
37003
37004var INLINE_NS = 'inline',
37005 _hiddenClass,
37006 _inlinePlaceholder,
37007 _lastInlineElement,
37008 _putInlineElementsBack = function() {
37009  if(_lastInlineElement) {
37010   _inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach();
37011   _lastInlineElement = null;
37012  }
37013 };
37014
37015$.magnificPopup.registerModule(INLINE_NS, {
37016 options: {
37017  hiddenClass: 'hide', // will be appended with `mfp-` prefix
37018  markup: '',
37019  tNotFound: 'Content not found'
37020 },
37021 proto: {
37022
37023  initInline: function() {
37024   mfp.types.push(INLINE_NS);
37025
37026   _mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() {
37027    _putInlineElementsBack();
37028   });
37029  },
37030
37031  getInline: function(item, template) {
37032
37033   _putInlineElementsBack();
37034
37035   if(item.src) {
37036    var inlineSt = mfp.st.inline,
37037     el = $(item.src);
37038
37039    if(el.length) {
37040
37041     // If target element has parent - we replace it with placeholder and put it back after popup is closed
37042     var parent = el[0].parentNode;
37043     if(parent && parent.tagName) {
37044      if(!_inlinePlaceholder) {
37045       _hiddenClass = inlineSt.hiddenClass;
37046       _inlinePlaceholder = _getEl(_hiddenClass);
37047       _hiddenClass = 'mfp-'+_hiddenClass;
37048      }
37049      // replace target inline element with placeholder
37050      _lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass);
37051     }
37052
37053     mfp.updateStatus('ready');
37054    } else {
37055     mfp.updateStatus('error', inlineSt.tNotFound);
37056     el = $('<div>');
37057    }
37058
37059    item.inlineElement = el;
37060    return el;
37061   }
37062
37063   mfp.updateStatus('ready');
37064   mfp._parseMarkup(template, {}, item);
37065   return template;
37066  }
37067 }
37068});
37069
37070/*>>inline*/
37071
37072/*>>ajax*/
37073var AJAX_NS = 'ajax',
37074 _ajaxCur,
37075 _removeAjaxCursor = function() {
37076  if(_ajaxCur) {
37077   _body.removeClass(_ajaxCur);
37078  }
37079 },
37080 _destroyAjaxRequest = function() {
37081  _removeAjaxCursor();
37082  if(mfp.req) {
37083   mfp.req.abort();
37084  }
37085 };
37086
37087$.magnificPopup.registerModule(AJAX_NS, {
37088
37089 options: {
37090  settings: null,
37091  cursor: 'mfp-ajax-cur',
37092  tError: '<a href="%url%">The content</a> could not be loaded.'
37093 },
37094
37095 proto: {
37096  initAjax: function() {
37097   mfp.types.push(AJAX_NS);
37098   _ajaxCur = mfp.st.ajax.cursor;
37099
37100   _mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest);
37101   _mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest);
37102  },
37103  getAjax: function(item) {
37104
37105   if(_ajaxCur)
37106    _body.addClass(_ajaxCur);
37107
37108   mfp.updateStatus('loading');
37109
37110   var opts = $.extend({
37111    url: item.src,
37112    success: function(data, textStatus, jqXHR) {
37113     var temp = {
37114      data:data,
37115      xhr:jqXHR
37116     };
37117
37118     _mfpTrigger('ParseAjax', temp);
37119
37120     mfp.appendContent( $(temp.data), AJAX_NS );
37121
37122     item.finished = true;
37123
37124     _removeAjaxCursor();
37125
37126     mfp._setFocus();
37127
37128     setTimeout(function() {
37129      mfp.wrap.addClass(READY_CLASS);
37130     }, 16);
37131
37132     mfp.updateStatus('ready');
37133
37134     _mfpTrigger('AjaxContentAdded');
37135    },
37136    error: function() {
37137     _removeAjaxCursor();
37138     item.finished = item.loadError = true;
37139     mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src));
37140    }
37141   }, mfp.st.ajax.settings);
37142
37143   mfp.req = $.ajax(opts);
37144
37145   return '';
37146  }
37147 }
37148});
37149
37150/*>>ajax*/
37151
37152/*>>image*/
37153var _imgInterval,
37154 _getTitle = function(item) {
37155  if(item.data && item.data.title !== undefined)
37156   return item.data.title;
37157
37158  var src = mfp.st.image.titleSrc;
37159
37160  if(src) {
37161   if($.isFunction(src)) {
37162    return src.call(mfp, item);
37163   } else if(item.el) {
37164    return item.el.attr(src) || '';
37165   }
37166  }
37167  return '';
37168 };
37169
37170$.magnificPopup.registerModule('image', {
37171
37172 options: {
37173  markup: '<div class="mfp-figure">'+
37174     '<div class="mfp-close"></div>'+
37175     '<figure>'+
37176      '<div class="mfp-img"></div>'+
37177      '<figcaption>'+
37178       '<div class="mfp-bottom-bar">'+
37179        '<div class="mfp-title"></div>'+
37180        '<div class="mfp-counter"></div>'+
37181       '</div>'+
37182      '</figcaption>'+
37183     '</figure>'+
37184    '</div>',
37185  cursor: 'mfp-zoom-out-cur',
37186  titleSrc: 'title',
37187  verticalFit: true,
37188  tError: '<a href="%url%">The image</a> could not be loaded.'
37189 },
37190
37191 proto: {
37192  initImage: function() {
37193   var imgSt = mfp.st.image,
37194    ns = '.image';
37195
37196   mfp.types.push('image');
37197
37198   _mfpOn(OPEN_EVENT+ns, function() {
37199    if(mfp.currItem.type === 'image' && imgSt.cursor) {
37200     _body.addClass(imgSt.cursor);
37201    }
37202   });
37203
37204   _mfpOn(CLOSE_EVENT+ns, function() {
37205    if(imgSt.cursor) {
37206     _body.removeClass(imgSt.cursor);
37207    }
37208    _window.off('resize' + EVENT_NS);
37209   });
37210
37211   _mfpOn('Resize'+ns, mfp.resizeImage);
37212   if(mfp.isLowIE) {
37213    _mfpOn('AfterChange', mfp.resizeImage);
37214   }
37215  },
37216  resizeImage: function() {
37217   var item = mfp.currItem;
37218   if(!item || !item.img) return;
37219
37220   if(mfp.st.image.verticalFit) {
37221    var decr = 0;
37222    // fix box-sizing in ie7/8
37223    if(mfp.isLowIE) {
37224     decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10);
37225    }
37226    item.img.css('max-height', mfp.wH-decr);
37227   }
37228  },
37229  _onImageHasSize: function(item) {
37230   if(item.img) {
37231   
37232    item.hasSize = true;
37233
37234    if(_imgInterval) {
37235     clearInterval(_imgInterval);
37236    }
37237   
37238    item.isCheckingImgSize = false;
37239
37240    _mfpTrigger('ImageHasSize', item);
37241
37242    if(item.imgHidden) {
37243     if(mfp.content)
37244      mfp.content.removeClass('mfp-loading');
37245    
37246     item.imgHidden = false;
37247    }
37248
37249   }
37250  },
37251
37252  /**
37253   * Function that loops until the image has size to display elements that rely on it asap
37254   */
37255  findImageSize: function(item) {
37256
37257   var counter = 0,
37258    img = item.img[0],
37259    mfpSetInterval = function(delay) {
37260
37261     if(_imgInterval) {
37262      clearInterval(_imgInterval);
37263     }
37264     // decelerating interval that checks for size of an image
37265     _imgInterval = setInterval(function() {
37266      if(img.naturalWidth > 0) {
37267       mfp._onImageHasSize(item);
37268       return;
37269      }
37270
37271      if(counter > 200) {
37272       clearInterval(_imgInterval);
37273      }
37274
37275      counter++;
37276      if(counter === 3) {
37277       mfpSetInterval(10);
37278      } else if(counter === 40) {
37279       mfpSetInterval(50);
37280      } else if(counter === 100) {
37281       mfpSetInterval(500);
37282      }
37283     }, delay);
37284    };
37285
37286   mfpSetInterval(1);
37287  },
37288
37289  getImage: function(item, template) {
37290
37291   var guard = 0,
37292
37293    // image load complete handler
37294    onLoadComplete = function() {
37295     if(item) {
37296      if (item.img[0].complete) {
37297       item.img.off('.mfploader');
37298      
37299       if(item === mfp.currItem){
37300        mfp._onImageHasSize(item);
37301
37302        mfp.updateStatus('ready');
37303       }
37304
37305       item.hasSize = true;
37306       item.loaded = true;
37307
37308       _mfpTrigger('ImageLoadComplete');
37309      
37310      }
37311      else {
37312       // if image complete check fails 200 times (20 sec), we assume that there was an error.
37313       guard++;
37314       if(guard < 200) {
37315        setTimeout(onLoadComplete,100);
37316       } else {
37317        onLoadError();
37318       }
37319      }
37320     }
37321    },
37322
37323    // image error handler
37324    onLoadError = function() {
37325     if(item) {
37326      item.img.off('.mfploader');
37327      if(item === mfp.currItem){
37328       mfp._onImageHasSize(item);
37329       mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
37330      }
37331
37332      item.hasSize = true;
37333      item.loaded = true;
37334      item.loadError = true;
37335     }
37336    },
37337    imgSt = mfp.st.image;
37338
37339   var el = template.find('.mfp-img');
37340   if(el.length) {
37341    var img = document.createElement('img');
37342    img.className = 'mfp-img';
37343    item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError);
37344    img.src = item.src;
37345
37346    // without clone() "error" event is not firing when IMG is replaced by new IMG
vendor: 8,672 bytes, lines 37347-37725
37347    // TODO: find a way to avoid such cloning
37348    if(el.is('img')) {
37349     item.img = item.img.clone();
37350    }
37351
37352    img = item.img[0];
37353    if(img.naturalWidth > 0) {
37354     item.hasSize = true;
37355    } else if(!img.width) {         
37356     item.hasSize = false;
37357    }
37358   }
37359
37360   mfp._parseMarkup(template, {
37361    title: _getTitle(item),
37362    img_replaceWith: item.img
37363   }, item);
37364
37365   mfp.resizeImage();
37366
37367   if(item.hasSize) {
37368    if(_imgInterval) clearInterval(_imgInterval);
37369
37370    if(item.loadError) {
37371     template.addClass('mfp-loading');
37372     mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
37373    } else {
37374     template.removeClass('mfp-loading');
37375     mfp.updateStatus('ready');
37376    }
37377    return template;
37378   }
37379
37380   mfp.updateStatus('loading');
37381   item.loading = true;
37382
37383   if(!item.hasSize) {
37384    item.imgHidden = true;
37385    template.addClass('mfp-loading');
37386    mfp.findImageSize(item);
37387   }
37388
37389   return template;
37390  }
37391 }
37392});
37393
37394/*>>image*/
37395
37396/*>>zoom*/
37397var hasMozTransform,
37398 getHasMozTransform = function() {
37399  if(hasMozTransform === undefined) {
37400   hasMozTransform = document.createElement('p').style.MozTransform !== undefined;
37401  }
37402  return hasMozTransform; 
37403 };
37404
37405$.magnificPopup.registerModule('zoom', {
37406
37407 options: {
37408  enabled: false,
37409  easing: 'ease-in-out',
37410  duration: 300,
37411  opener: function(element) {
37412   return element.is('img') ? element : element.find('img');
37413  }
37414 },
37415
37416 proto: {
37417
37418  initZoom: function() {
37419   var zoomSt = mfp.st.zoom,
37420    ns = '.zoom',
37421    image;
37422   
37423   if(!zoomSt.enabled || !mfp.supportsTransition) {
37424    return;
37425   }
37426
37427   var duration = zoomSt.duration,
37428    getElToAnimate = function(image) {
37429     var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'),
37430      transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing,
37431      cssObj = {
37432       position: 'fixed',
37433       zIndex: 9999,
37434       left: 0,
37435       top: 0,
37436       '-webkit-backface-visibility': 'hidden'
37437      },
37438      t = 'transition';
37439
37440     cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition;
37441
37442     newImg.css(cssObj);
37443     return newImg;
37444    },
37445    showMainContent = function() {
37446     mfp.content.css('visibility', 'visible');
37447    },
37448    openTimeout,
37449    animatedImg;
37450
37451   _mfpOn('BuildControls'+ns, function() {
37452    if(mfp._allowZoom()) {
37453
37454     clearTimeout(openTimeout);
37455     mfp.content.css('visibility', 'hidden');
37456
37457     // Basically, all code below does is clones existing image, puts in on top of the current one and animated it
37458    
37459     image = mfp._getItemToZoom();
37460
37461     if(!image) {
37462      showMainContent();
37463      return;
37464     }
37465
37466     animatedImg = getElToAnimate(image);
37467    
37468     animatedImg.css( mfp._getOffset() );
37469
37470     mfp.wrap.append(animatedImg);
37471
37472     openTimeout = setTimeout(function() {
37473      animatedImg.css( mfp._getOffset( true ) );
37474      openTimeout = setTimeout(function() {
37475
37476       showMainContent();
37477
37478       setTimeout(function() {
37479        animatedImg.remove();
37480        image = animatedImg = null;
37481        _mfpTrigger('ZoomAnimationEnded');
37482       }, 16); // avoid blink when switching images
37483
37484      }, duration); // this timeout equals animation duration
37485
37486     }, 16); // by adding this timeout we avoid short glitch at the beginning of animation
37487
37488     // Lots of timeouts...
37489    }
37490   });
37491   _mfpOn(BEFORE_CLOSE_EVENT+ns, function() {
37492    if(mfp._allowZoom()) {
37493
37494     clearTimeout(openTimeout);
37495
37496     mfp.st.removalDelay = duration;
37497
37498     if(!image) {
37499      image = mfp._getItemToZoom();
37500      if(!image) {
37501       return;
37502      }
37503      animatedImg = getElToAnimate(image);
37504     }
37505    
37506    
37507     animatedImg.css( mfp._getOffset(true) );
37508     mfp.wrap.append(animatedImg);
37509     mfp.content.css('visibility', 'hidden');
37510    
37511     setTimeout(function() {
37512      animatedImg.css( mfp._getOffset() );
37513     }, 16);
37514    }
37515
37516   });
37517
37518   _mfpOn(CLOSE_EVENT+ns, function() {
37519    if(mfp._allowZoom()) {
37520     showMainContent();
37521     if(animatedImg) {
37522      animatedImg.remove();
37523     }
37524     image = null;
37525    }
37526   });
37527  },
37528
37529  _allowZoom: function() {
37530   return mfp.currItem.type === 'image';
37531  },
37532
37533  _getItemToZoom: function() {
37534   if(mfp.currItem.hasSize) {
37535    return mfp.currItem.img;
37536   } else {
37537    return false;
37538   }
37539  },
37540
37541  // Get element postion relative to viewport
37542  _getOffset: function(isLarge) {
37543   var el;
37544   if(isLarge) {
37545    el = mfp.currItem.img;
37546   } else {
37547    el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem);
37548   }
37549
37550   var offset = el.offset();
37551   var paddingTop = parseInt(el.css('padding-top'),10);
37552   var paddingBottom = parseInt(el.css('padding-bottom'),10);
37553   offset.top -= ( $(window).scrollTop() - paddingTop );
37554
37555   /*
37556  
37557   Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa.
37558
37559    */
37560   var obj = {
37561    width: el.width(),
37562    // fix Zepto height+padding issue
37563    height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop
37564   };
37565
37566   // I hate to do this, but there is no another option
37567   if( getHasMozTransform() ) {
37568    obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)';
37569   } else {
37570    obj.left = offset.left;
37571    obj.top = offset.top;
37572   }
37573   return obj;
37574  }
37575
37576 }
37577});
37578
37579/*>>zoom*/
37580
37581/*>>iframe*/
37582
37583var IFRAME_NS = 'iframe',
37584 _emptyPage = '//about:blank',
37585 _fixIframeBugs = function(isShowing) {
37586  if(mfp.currTemplate[IFRAME_NS]) {
37587   var el = mfp.currTemplate[IFRAME_NS].find('iframe');
37588   if(el.length) {
37589    // reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug
37590    if(!isShowing) {
37591     el[0].src = _emptyPage;
37592    }
37593
37594    // IE8 black screen bug fix
37595    if(mfp.isIE8) {
37596     el.css('display', isShowing ? 'block' : 'none');
37597    }
37598   }
37599  }
37600 };
37601
37602$.magnificPopup.registerModule(IFRAME_NS, {
37603
37604 options: {
37605  markup: '<div class="mfp-iframe-scaler">'+
37606     '<div class="mfp-close"></div>'+
37607     '<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+
37608    '</div>',
37609
37610  srcAction: 'iframe_src',
37611
37612  // we don't care and support only one default type of URL by default
37613  patterns: {
37614   youtube: {
37615    index: 'youtube.com',
37616    id: 'v=',
37617    src: '//www.youtube.com/embed/%id%?autoplay=1'
37618   },
37619   vimeo: {
37620    index: 'vimeo.com/',
37621    id: '/',
37622    src: '//player.vimeo.com/video/%id%?autoplay=1'
37623   },
37624   gmaps: {
37625    index: '//maps.google.',
37626    src: '%id%&output=embed'
37627   }
37628  }
37629 },
37630
37631 proto: {
37632  initIframe: function() {
37633   mfp.types.push(IFRAME_NS);
37634
37635   _mfpOn('BeforeChange', function(e, prevType, newType) {
37636    if(prevType !== newType) {
37637     if(prevType === IFRAME_NS) {
37638      _fixIframeBugs(); // iframe if removed
37639     } else if(newType === IFRAME_NS) {
37640      _fixIframeBugs(true); // iframe is showing
37641     }
37642    }// else {
37643     // iframe source is switched, don't do anything
37644    //}
37645   });
37646
37647   _mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() {
37648    _fixIframeBugs();
37649   });
37650  },
37651
37652  getIframe: function(item, template) {
37653   var embedSrc = item.src;
37654   var iframeSt = mfp.st.iframe;
37655   
37656   $.each(iframeSt.patterns, function() {
37657    if(embedSrc.indexOf( this.index ) > -1) {
37658     if(this.id) {
37659      if(typeof this.id === 'string') {
37660       embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length);
37661      } else {
37662       embedSrc = this.id.call( this, embedSrc );
37663      }
37664     }
37665     embedSrc = this.src.replace('%id%', embedSrc );
37666     return false; // break;
37667    }
37668   });
37669  
37670   var dataObj = {};
37671   if(iframeSt.srcAction) {
37672    dataObj[iframeSt.srcAction] = embedSrc;
37673   }
37674   mfp._parseMarkup(template, dataObj, item);
37675
37676   mfp.updateStatus('ready');
37677
37678   return template;
37679  }
37680 }
37681});
37682
37683/*>>iframe*/
37684
37685/*>>gallery*/
37686/**
37687 * Get looped index depending on number of slides
37688 */
37689var _getLoopedId = function(index) {
37690  var numSlides = mfp.items.length;
37691  if(index > numSlides - 1) {
37692   return index - numSlides;
37693  } else  if(index < 0) {
37694   return numSlides + index;
37695  }
37696  return index;
37697 },
37698 _replaceCurrTotal = function(text, curr, total) {
37699  return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total);
37700 };
37701
37702$.magnificPopup.registerModule('gallery', {
37703
37704 options: {
37705  enabled: false,
37706  arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',
37707  preload: [0,2],
37708  navigateByImgClick: true,
37709  arrows: true,
37710
37711  tPrev: 'Previous (Left arrow key)',
37712  tNext: 'Next (Right arrow key)',
37713  tCounter: '%curr% of %total%'
37714 },
37715
37716 proto: {
37717  initGallery: function() {
37718
37719   var gSt = mfp.st.gallery,
37720    ns = '.mfp-gallery',
37721    supportsFastClick = Boolean($.fn.mfpFastClick);
37722
37723   mfp.direction = true; // true - next, false - prev
37724  
37725   if(!gSt || !gSt.enabled ) return false;
37726
37727   _wrapClasses += ' mfp-gallery';
37728
37729   _mfpOn(OPEN_EVENT+ns, function() {
37730
37731    if(gSt.navigateByImgClick) {
37732     mfp.wrap.on('click'+ns, '.mfp-img', function() {
37733      if(mfp.items.length > 1) {
37734       mfp.next();
37735       return false;
37736      }
37737     });
37738    }
37739
37740    _document.on('keydown'+ns, function(e) {
37741     if (e.keyCode === 37) {
37742      mfp.prev();
37743     } else if (e.keyCode === 39) {
37744      mfp.next();
37745     }
37746    });
37747   });
37748
37749   _mfpOn('UpdateStatus'+ns, function(e, data) {
37750    if(data.text) {
37751     data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length);
37752    }
37753   });
37754
37755   _mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) {
37756    var l = mfp.items.length;
37757    values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : '';
37758   });
37759
37760   _mfpOn('BuildControls' + ns, function() {
37761    if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) {
37762     var markup = gSt.arrowMarkup,
37763      arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, gSt.tPrev).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS),  
37764      arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, gSt.tNext).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS);
37765
37766     var eName = supportsFastClick ? 'mfpFastClick' : 'click';
37767     arrowLeft[eName](function() {
37768      mfp.prev();
37769     });  
37770     arrowRight[eName](function() {
37771      mfp.next();
37772     });
37773
37774     // Polyfill for :before and :after (adds elements with classes mfp-a and mfp-b)
37775     if(mfp.isIE7) {
37776      _getEl('b', arrowLeft[0], false, true);
37777      _getEl('a', arrowLeft[0], false, true);
37778      _getEl('b', arrowRight[0], false, true);
37779      _getEl('a', arrowRight[0], false, true);
37780     }
37781
37782     mfp.container.append(arrowLeft.add(arrowRight));
37783    }
37784   });
37785
37786   _mfpOn(CHANGE_EVENT+ns, function() {
37787    if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout);
37788
37789    mfp._preloadTimeout = setTimeout(function() {
37790     mfp.preloadNearbyImages();
37791     mfp._preloadTimeout = null;
37792    }, 16); 
37793   });
37794
37795   _mfpOn(CLOSE_EVENT+ns, function() {
37796    _document.off(ns);
37797    mfp.wrap.off('click'+ns);
37798  
37799    if(mfp.arrowLeft && supportsFastClick) {
37800     mfp.arrowLeft.add(mfp.arrowRight).destroyMfpFastClick();
37801    }
37802    mfp.arrowRight = mfp.arrowLeft = null;
37803   });
37804
37805  },
37806  next: function() {
37807   mfp.direction = true;
37808   mfp.index = _getLoopedId(mfp.index + 1);
37809   mfp.updateItemHTML();
37810  },
37811  prev: function() {
37812   mfp.direction = false;
37813   mfp.index = _getLoopedId(mfp.index - 1);
37814   mfp.updateItemHTML();
37815  },
37816  goTo: function(newIndex) {
37817   mfp.direction = (newIndex >= mfp.index);
37818   mfp.index = newIndex;
37819   mfp.updateItemHTML();
37820  },
37821  preloadNearbyImages: function() {
37822   var p = mfp.st.gallery.preload,
37823    preloadBefore = Math.min(p[0], mfp.items.length),
37824    preloadAfter = Math.min(p[1], mfp.items.length),
37825    i;
37826
37827   for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) {
37828    mfp._preloadItem(mfp.index+i);
37829   }
37830   for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) {
37831    mfp._preloadItem(mfp.index-i);
37832   }
37833  },
37834  _preloadItem: function(index) {
37835   index = _getLoopedId(index);
37836
37837   if(mfp.items[index].preloaded) {
37838    return;
37839   }
37840
37841   var item = mfp.items[index];
37842   if(!item.parsed) {
37843    item = mfp.parseEl( index );
37844   }
37845
37846   _mfpTrigger('LazyLoad', item);
37847
37848   if(item.type === 'image') {
37849    item.img = $('<img class="mfp-img" />').on('load.mfploader', function() {
37850     item.hasSize = true;
37851    }).on('error.mfploader', function() {
37852     item.hasSize = true;
37853     item.loadError = true;
37854     _mfpTrigger('LazyLoadError', item);
37855    }).attr('src', item.src);
37856   }
37857
37858   item.preloaded = true;
37859  }
37860 }
37861});
37862
37863/*
37864Touch Support that might be implemented some day
37865
37866addSwipeGesture: function() {
37867 var startX,
37868  moved,
37869  multipleTouches;
37870
37871  return;
37872
37873 var namespace = '.mfp',
37874  addEventNames = function(pref, down, move, up, cancel) {
37875   mfp._tStart = pref + down + namespace;
37876   mfp._tMove = pref + move + namespace;
37877   mfp._tEnd = pref + up + namespace;
37878   mfp._tCancel = pref + cancel + namespace;
37879  };
37880
37881 if(window.navigator.msPointerEnabled) {
37882  addEventNames('MSPointer', 'Down', 'Move', 'Up', 'Cancel');
37883 } else if('ontouchstart' in window) {
37884  addEventNames('touch', 'start', 'move', 'end', 'cancel');
37885 } else {
37886  return;
37887 }
37888 _window.on(mfp._tStart, function(e) {
37889  var oE = e.originalEvent;
37890  multipleTouches = moved = false;
37891  startX = oE.pageX || oE.changedTouches[0].pageX;
37892 }).on(mfp._tMove, function(e) {
37893  if(e.originalEvent.touches.length > 1) {
37894   multipleTouches = e.originalEvent.touches.length;
37895  } else {
37896   //e.preventDefault();
37897   moved = true;
37898  }
37899 }).on(mfp._tEnd + ' ' + mfp._tCancel, function(e) {
37900  if(moved && !multipleTouches) {
37901   var oE = e.originalEvent,
37902    diff = startX - (oE.pageX || oE.changedTouches[0].pageX);
37903
37904   if(diff > 20) {
37905    mfp.next();
37906   } else if(diff < -20) {
37907    mfp.prev();
37908   }
37909  }
37910 });
37911},
37912*/
37913
37914/*>>gallery*/
37915
37916/*>>retina*/
37917
37918var RETINA_NS = 'retina';
37919
37920$.magnificPopup.registerModule(RETINA_NS, {
37921 options: {
37922  replaceSrc: function(item) {
37923   return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; });
37924  },
37925  ratio: 1 // Function or number.  Set to 1 to disable.
37926 },
37927 proto: {
37928  initRetina: function() {
37929   if(window.devicePixelRatio > 1) {
37930
37931    var st = mfp.st.retina,
37932     ratio = st.ratio;
37933
37934    ratio = !isNaN(ratio) ? ratio : ratio();
37935
37936    if(ratio > 1) {
37937     _mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) {
37938      item.img.css({
37939       'max-width': item.img[0].naturalWidth / ratio,
37940       'width': '100%'
37941      });
37942     });
37943     _mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) {
37944      item.src = st.replaceSrc(item, ratio);
37945     });
37946    }
37947   }
37948
37949  }
37950 }
37951});
37952
37953/*>>retina*/
37954
37955/*>>fastclick*/
37956/**
37957 * FastClick event implementation. (removes 300ms delay on touch devices)
37958 * Based on https://developers.google.com/mobile/articles/fast_buttons
37959 *
37960 * You may use it outside the Magnific Popup by calling just:
37961 *
37962 * $('.your-el').mfpFastClick(function() {
37963 *     console.log('Clicked!');
37964 * });
37965 *
37966 * To unbind:
37967 * $('.your-el').destroyMfpFastClick();
37968 *
37969 *
37970 * Note that it's a very basic and simple implementation, it blocks ghost click on the same element where it was bound.
37971 * If you need something more advanced, use plugin by FT Labs https://github.com/ftlabs/fastclick
37972 *
37973 */
37974
37975(function() {
37976 var ghostClickDelay = 1000,
37977  supportsTouch = 'ontouchstart' in window,
37978  unbindTouchMove = function() {
37979   _window.off('touchmove'+ns+' touchend'+ns);
37980  },
37981  eName = 'mfpFastClick',
37982  ns = '.'+eName;
37983
37984 // As Zepto.js doesn't have an easy way to add custom events (like jQuery), so we implement it in this way
37985 $.fn.mfpFastClick = function(callback) {
37986
37987  return $(this).each(function() {
37988
37989   var elem = $(this),
37990    lock;
37991
37992   if( supportsTouch ) {
37993
37994    var timeout,
37995     startX,
37996     startY,
37997     pointerMoved,
37998     point,
37999     numPointers;
38000
38001    elem.on('touchstart' + ns, function(e) {
38002     pointerMoved = false;
38003     numPointers = 1;
38004
38005     point = e.originalEvent ? e.originalEvent.touches[0] : e.touches[0];
38006     startX = point.clientX;
38007     startY = point.clientY;
38008
38009     _window.on('touchmove'+ns, function(e) {
38010      point = e.originalEvent ? e.originalEvent.touches : e.touches;
38011      numPointers = point.length;
38012      point = point[0];
38013      if (Math.abs(point.clientX - startX) > 10 ||
38014       Math.abs(point.clientY - startY) > 10) {
38015       pointerMoved = true;
38016       unbindTouchMove();
38017      }
38018     }).on('touchend'+ns, function(e) {
38019      unbindTouchMove();
38020      if(pointerMoved || numPointers > 1) {
38021       return;
38022      }
38023      lock = true;
38024      e.preventDefault();
38025      clearTimeout(timeout);
38026      timeout = setTimeout(function() {
38027       lock = false;
38028      }, ghostClickDelay);
38029      callback();
38030     });
38031    });
38032
38033   }
38034
38035   elem.on('click' + ns, function() {
38036    if(!lock) {
38037     callback();
38038    }
38039   });
38040  });
38041 };
38042
38043 $.fn.destroyMfpFastClick = function() {
38044  $(this).off('touchstart' + ns + ' click' + ns);
38045  if(supportsTouch) _window.off('touchmove'+ns+' touchend'+ns);
38046 };
38047})();
38048
38049/*>>fastclick*/
38050 _checkInstance(); })(window.jQuery || window.Zepto);
38051   /* Ende jquery.magnific-popup */
38052   /* Start picturefill */
38053   /*! Picturefill - v2.2.0 - 2014-10-30
38054 * http://scottjehl.github.io/picturefill
38055 * Copyright (c) 2014 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT */
38056/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
38057window.matchMedia || (window.matchMedia = function() {
38058    "use strict";
38059    // For browsers that support matchMedium api such as IE 9 and webkit
38060    var styleMedia = (window.styleMedia || window.media);
38061    // For those that don't support matchMedium
38062    if (!styleMedia) {
38063        var style = document.createElement('style'),
38064            script = document.getElementsByTagName('script')[0],
38065            info = null;
38066        style.type = 'text/css';
38067        style.id = 'matchmediajs-test';
38068        script.parentNode.insertBefore(style, script);
38069        // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
38070        info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;
38071        styleMedia = {
38072            matchMedium: function(media) {
38073                var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }';
38074                // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
38075                if (style.styleSheet) {
38076                    style.styleSheet.cssText = text;
38077                } else {
38078                    style.textContent = text;
38079                }
38080                // Test if media query is true or false
38081                return info.width === '1px';
38082            }
38083        };
38084    }
38085    return function(media) {
38086        return {
38087            matches: styleMedia.matchMedium(media || 'all'),
38088            media: media || 'all'
38089        };
38090    };
38091}());
38092/*! Picturefill - Responsive Images that work today.
38093 * Author: Scott Jehl, Filament Group, 2012 ( new proposal implemented by Shawn Jansepar )
38094 * License: MIT/GPLv2
38095 * Spec: http://picture.responsiveimages.org/
38096 */
38097(function(w, doc, image) {
38098    // Enable strict mode
38099    "use strict";
38100    // If picture is supported, well, that's awesome. Let's get outta here...
38101    if (w.HTMLPictureElement) {
38102        w.picturefill = function() {};
38103        return;
38104    }
38105    // HTML shim|v it for old IE (IE9 will still need the HTML video tag workaround)
38106    doc.createElement("picture");
38107    // local object for method references and testing exposure
38108    var pf = {};
38109    // namespace
38110    pf.ns = "picturefill";
38111    // srcset support test
38112    (function() {
38113        pf.srcsetSupported = "srcset" in image;
38114        pf.sizesSupported = "sizes" in image;
38115    })();
38116    // just a string trim workaround
38117    pf.trim = function(str) {
38118        return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
38119    };
38120    // just a string endsWith workaround
38121    pf.endsWith = function(str, suffix) {
38122        return str.endsWith ? str.endsWith(suffix) : str.indexOf(suffix, str.length - suffix.length) !== -1;
38123    };
38124    /**
38125     * Shortcut method for https://w3c.github.io/webappsec/specs/mixedcontent/#restricts-mixed-content ( for easy overriding in tests )
38126     */
38127    pf.restrictsMixedContent = function() {
38128        return w.location.protocol === "https:";
38129    };
38130    /**
38131     * Shortcut method for matchMedia ( for easy overriding in tests )
38132     */
38133    pf.matchesMedia = function(media) {
38134        return w.matchMedia && w.matchMedia(media).matches;
38135    };
38136    // Shortcut method for `devicePixelRatio` ( for easy overriding in tests )
38137    pf.getDpr = function() {
38138        return (w.devicePixelRatio || 1);
38139    };
38140    /**
38141     * Get width in css pixel value from a "length" value
38142     * http://dev.w3.org/csswg/css-values-3/#length-value
38143     */
38144    pf.getWidthFromLength = function(length) {
38145        // If a length is specified and doesn’t contain a percentage, and it is greater than 0 or using `calc`, use it. Else, use the `100vw` default.
38146        length = length && length.indexOf("%") > -1 === false && (parseFloat(length) > 0 || length.indexOf("calc(") > -1) ? length : "100vw";
38147        /**
38148         * If length is specified in `vw` units, use `%` instead since the div we’re measuring
38149         * is injected at the top of the document.
38150         *
38151         * TODO: maybe we should put this behind a feature test for `vw`?
38152         */
38153        length = length.replace("vw", "%");
38154        // Create a cached element for getting length value widths
38155        if (!pf.lengthEl) {
38156            pf.lengthEl = doc.createElement("div");
38157            // Positioning styles help prevent padding/margin/width on `html` or `body` from throwing calculations off.
38158            pf.lengthEl.style.cssText = "border:0;display:block;font-size:1em;
38158left:0;margin:0;padding:0;position:absolute;visibility:hidden";
38159        }
38160        pf.lengthEl.style.width = length;
38161        doc.body.appendChild(pf.lengthEl);
38162        // Add a class, so that everyone knows where this element comes from
38163        pf.lengthEl.className = "helper-from-picturefill-js";
38164        if (pf.lengthEl.offsetWidth <= 0) {
38165            // Something has gone wrong. `calc()` is in use and unsupported, most likely. Default to `100vw` (`100%`, for broader support.):
38166            pf.lengthEl.style.width = doc.documentElement.offsetWidth + "px";
38167        }
38168        var offsetWidth = pf.lengthEl.offsetWidth;
38169        doc.body.removeChild(pf.lengthEl);
38170        return offsetWidth;
38171    };
38172    // container of supported mime types that one might need to qualify before using
38173    pf.types = {};
38174    // Add support for standard mime types
38175    pf.types["image/jpeg"] = true;
38176    pf.types["image/gif"] = true;
38177    pf.types["image/png"] = true;
38178    // test svg support
38179    pf.types["image/svg+xml"] = doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image", "1.1");
38180    // test webp support, only when the markup calls for it
38181    pf.types["image/webp"] = function() {
38182        // based on Modernizr's lossless img-webp test
38183        // note: asynchronous
38184        var type = "image/webp";
38185        image.onerror = function() {
38186            pf.types[type] = false;
38187            picturefill();
38188        };
38189        image.onload = function() {
38190            pf.types[type] = image.width === 1;
38191            picturefill();
38192        };
38193        image.src = "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=";
38194    };
38195    /**
38196     * Takes a source element and checks if its type attribute is present and if so, supported
38197     * Note: for type tests that require a async logic,
38198     * you can define them as a function that'll run only if that type needs to be tested. Just make the test function call picturefill again when it is complete.
38199     * see the async webp test above for example
38200     */
38201    pf.verifyTypeSupport = function(source) {
38202        var type = source.getAttribute("type");
38203        // if type attribute exists, return test result, otherwise return true
38204        if (type === null || type === "") {
38205            return true;
38206        } else {
38207            // if the type test is a function, run it and return "pending" status. The function will rerun picturefill on pending elements once finished.
38208            if (typeof(pf.types[type]) === "function") {
38209                pf.types[type]();
38210                return "pending";
38211            } else {
38212                return pf.types[type];
38213            }
38214        }
38215    };
38216    // Parses an individual `size` and returns the length, and optional media query
38217    pf.parseSize = function(sourceSizeStr) {
38218        var match = /(\([^)]+\))?\s*(.+)/g.exec(sourceSizeStr);
38219        return {
38220            media: match && match[1],
38221            length: match && match[2]
38222        };
38223    };
38224    // Takes a string of sizes and returns the width in pixels as a number
38225    pf.findWidthFromSourceSize = function(sourceSizeListStr) {
38226        // Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33%
38227        // or (min-width:30em) calc(30% - 15px)
38228        var sourceSizeList = pf.trim(sourceSizeListStr).split(/\s*,\s*/),
38229            winningLength;
38230        for (var i = 0, len = sourceSizeList.length; i < len; i++) {
38231            // Match <media-condition>? length, ie ( min-width: 50em ) 100%
38232            var sourceSize = sourceSizeList[i],
38233                // Split "( min-width: 50em ) 100%" into separate strings
38234                parsedSize = pf.parseSize(sourceSize),
38235                length = parsedSize.length,
38236                media = parsedSize.media;
38237            if (!length) {
38238                continue;
38239            }
38240            if (!media || pf.matchesMedia(media)) {
38241                // if there is no media query or it matches, choose this as our winning length
38242                // and end algorithm
38243                winningLength = length;
38244                break;
38245            }
38246        }
38247        // pass the length to a method that can properly determine length
38248        // in pixels based on these formats: http://dev.w3.org/csswg/css-values-3/#length-value
38249        return pf.getWidthFromLength(winningLength);
38250    };
38251    pf.parseSrcset = function(srcset) {
38252        /**
38253         * A lot of this was pulled from Boris Smus’ parser for the now-defunct WHATWG `srcset`
38254         * https://github.com/borismus/srcset-polyfill/blob/master/js/sr
38254cset-info.js
38255         *
38256         * 1. Let input (`srcset`) be the value passed to this algorithm.
38257         * 2. Let position be a pointer into input, initially pointing at the start of the string.
38258         * 3. Let raw candidates be an initially empty ordered list of URLs with associated
38259         * unparsed descriptors. The order of entries in the list is the order in which entries
38260         * are added to the list.
38261         */
38262        var candidates = [];
38263        while (srcset !== "") {
38264            srcset = srcset.replace(/^\s+/g, "");
38265            // 5. Collect a sequence of characters that are not space characters, and let that be url.
38266            var pos = srcset.search(/\s/g),
38267                url, descriptor = null;
38268            if (pos !== -1) {
38269                url = srcset.slice(0, pos);
38270                var last = url.slice(-1);
38271                // 6. If url ends with a U+002C COMMA character (,), remove that character from url
38272                // and let descriptors be the empty string. Otherwise, follow these substeps
38273                // 6.1. If url is empty, then jump to the step labeled descriptor parser.
38274                if (last === "," || url === "") {
38275                    url = url.replace(/,+$/, "");
38276                    descriptor = "";
38277                }
38278                srcset = srcset.slice(pos + 1);
38279                // 6.2. Collect a sequence of characters that are not U+002C COMMA characters (,), and
38280                // let that be descriptors.
38281                if (descriptor === null) {
38282                    var descpos = srcset.indexOf(",");
38283                    if (descpos !== -1) {
38284                        descriptor = srcset.slice(0, descpos);
38285                        srcset = srcset.slice(descpos + 1);
38286                    } else {
38287                        descriptor = srcset;
38288                        srcset = "";
38289                    }
38290                }
38291            } else {
38292                url = srcset;
38293                srcset = "";
38294            }
38295            // 7. Add url to raw candidates, associated with descriptors.
38296            if (url || descriptor) {
38297                candidates.push({
38298                    url: url,
38299                    descriptor: descriptor
38300                });
38301            }
38302        }
38303        return candidates;
38304    };
38305    pf.parseDescriptor = function(descriptor, sizesattr) {
38306        // 11. Descriptor parser: Let candidates be an initially empty source set. The order of entries in the list
38307        // is the order in which entries are added to the list.
38308        var sizes = sizesattr || "100vw",
38309            sizeDescriptor = descriptor && descriptor.replace(/(^\s+|\s+$)/g, ""),
38310            widthInCssPixels = pf.findWidthFromSourceSize(sizes),
38311            resCandidate;
38312        if (sizeDescriptor) {
38313            var splitDescriptor = sizeDescriptor.split(" ");
38314            for (var i = splitDescriptor.length - 1; i >= 0; i--) {
38315                var curr = splitDescriptor[i],
38316                    lastchar = curr && curr.slice(curr.length - 1);
38317                if ((lastchar === "h" || lastchar === "w") && !pf.sizesSupported) {
38318                    resCandidate = parseFloat((parseInt(curr, 10) / widthInCssPixels));
38319                } else if (lastchar === "x") {
38320                    var res = curr && parseFloat(curr, 10);
38321                    resCandidate = res && !isNaN(res) ? res : 1;
38322                }
38323            }
38324        }
38325        return resCandidate || 1;
38326    };
38327    /**
38328     * Takes a srcset in the form of url/
38329     * ex. "images/pic-medium.png 1x, images/pic-medium-2x.png 2x" or
38330     * "images/pic-medium.png 400w, images/pic-medium-2x.png 800w" or
38331     * "images/pic-small.png"
38332     * Get an array of image candidates in the form of
38333     * {url: "/foo/bar.png", resolution: 1}
38334     * where resolution is http://dev.w3.org/csswg/css-values-3/#resolution-value
38335     * If sizes is specified, resolution is calculated
38336     */
38337    pf.getCandidatesFromSourceSet = function(srcset, sizes) {
38338        var candidates = pf.parseSrcset(srcset),
38339            formattedCandidates = [];
38340        for (var i = 0, len = candidates.length; i < len; i++) {
38341            var candidate = candidates[i];
38342            formattedCandidates.push({
38343                url: candidate.url,
38344                resolution: pf.parseDescriptor(candidate.descriptor, sizes)
38345            });
38346        }
38347        return formattedCandidates;
38348    };
38349    /**
38350     * if it's an img element and it has a srcset property,
38351     * we need to remove the attribute so we can manipulate src
38352     * (the property's existence infers native srcset support, and a srcset-supporting browser will prioritize srcset's value over our winning picture candidate)
38353     * this moves srcset's value to memory for later use and removes the attr
38354     */
38355    pf.dodgeSrcset = function(img) {
38356        if (img.srcset) {
38357            img[pf.ns].srcset = img.srcset;
38358            img.removeAttribute("srcset");
38359        }
38360    };
38361    // Accept a source or img element and process its srcset and sizes attrs
38362    pf.processSourceSet = function(el) {
38363        var srcset = el.getAttribute("srcset"),
38364            sizes = el.getAttribute("sizes"),
38365            candidates = [];
38366        // if it's an img element, use the cached srcset property (defined or not)
38367        if (el.nodeName.toUpperCase() === "IMG" && el[pf.ns] && el[pf.ns].srcset) {
38368            srcset = el[pf.ns].srcset;
38369        }
38370        if (srcset) {
38371            candidates = pf.getCandidatesFromSourceSet(srcset, sizes);
38372        }
38373        return candidates;
38374    };
38375    pf.applyBestCandidate = function(candidates, picImg) {
38376        var candidate,
38377            length,
38378            bestCandidate;
38379        candidates.sort(pf.ascendingSort);
38380        length = candidates.length;
38381        bestCandidate = candidates[length - 1];
38382        for (var i = 0; i < length; i++) {
38383            candidate = candidates[i];
38384            if (candidate.resolution >= pf.getDpr()) {
38385                bestCandidate = candidate;
38386                break;
38387            }
38388        }
38389        if (bestCandidate && !pf.endsWith(picImg.src, bestCandidate.url)) {
38390            if (pf.restrictsMixedContent() && bestCandidate.url.substr(0, "http:".length).toLowerCase() === "http:") {
38391                if (typeof console !== undefined) {
38392                    console.warn("Blocked mixed content image " + bestCandidate.url);
38393                }
38394            } else {
38395                picImg.src = bestCandidate.url;
38396                // currentSrc attribute and property to match
38397                // http://picture.responsiveimages.org/#the-img-element
38398                picImg.currentSrc = picImg.src;
38399                var style = picImg.style || {},
38400                    WebkitBackfaceVisibility = "webkitBackfaceVisibility" in style,
38401                    currentZoom = style.zoom;
38402                if (WebkitBackfaceVisibility) { // See: https://github.com/scottjehl/picturefill/issues/332
38403                    style.zoom = ".999";
38404                    WebkitBackfaceVisibility = picImg.offsetWidth;
38405                    style.zoom = currentZoom;
38406                }
38407            }
38408        }
38409    };
38410    pf.ascendingSort = function(a, b) {
38411        return a.resolution - b.resolution;
38412    };
38413    /**
38414     * In IE9, <source> elements get removed if they aren't children of
38415     * video elements. Thus, we conditionally wrap source elements
38416     * using <!--[if IE 9]><video style="display: none;"><![endif]-->
38417     * and must account for that here by moving those source elements
38418     * back into the picture element.
38419     */
38420    pf.removeVideoShim = function(picture) {
38421        var videos = picture.getElementsByTagName("video");
38422        if (videos.length) {
38423            var video = videos[0],
38424                vsources = video.getElementsByTagName("source");
38425            while (vsources.length) {
38426                picture.insertBefore(vsources[0], video);
38427            }
38428            // Remove the video element once we're finished removing its children
38429            video.parentNode.removeChild(video);
38430        }
38431    };
38432    /**
38433     * Find all `img` elements, and add them to the candidate list if they have
38434     * a `picture` parent, a `sizes` attribute in basic `srcset` supporting browsers,
38435     * a `srcset` attribute at all, and they haven’t been evaluated already.
38436     */
38437    pf.getAllElements = function() {
38438        var elems = [],
38439            imgs = doc.getElementsByTagName("img");
38440        for (var h = 0, len = imgs.length; h < len; h++) {
38441            var currImg = imgs[h];
38442            if (currImg.parentNode.nodeName.toUpperCase() === "PICTURE" ||
38443                (currImg.getAttribute("srcset") !== null) || currImg[pf.ns] && currImg[pf.ns].srcset !== null) {
38444                elems.push(currImg);
38445            }
38446        }
38447        return elems;
38448    };
38449    pf.getMatch = function(img, picture) {
38450        var sources = picture.childNodes,
38451            match;
38452        // Go through each child, and if they have media queries, evaluate them
38453        for (var j = 0, slen = sources.length; j < slen; j++) {
38454            var source = sources[j];
38455            // ignore non-element nodes
38456            if (source.nodeType !== 1) {
38457                continue;
38458            }
38459            // Hitting the `img` element that started everything stops the search for `sources`.
38460            // If no previous `source` matches, the `img` itself is evaluated later.
38461            if (source === img) {
38462                return match;
38463            }
38464            // ignore non-`source` nodes
38465            if (source.nodeName.toUpperCase() !== "SOURCE") {
38466                continue;
38467            }
38468            // if it's a source element that has the `src` property set, throw a warning in the console
38469            if (source.getAttribute("src") !== null && typeof console !== undefined) {
38470                console.warn("The `src` attribute is invalid on `picture` `source` element; instead, use `srcset`.");
38471            }
38472            var media = source.getAttribute("media");
38473            // if source does not have a srcset attribute, skip
38474            if (!source.getAttribute("srcset")) {
38475                continue;
38476            }
38477            // if there's no media specified, OR w.matchMedia is supported
38478            if ((!media || pf.matchesMedia(media))) {
38479                var typeSupported = pf.verifyTypeSupport(source);
38480                if (typeSupported === true) {
38481                    match = source;
38482                    break;
38483                } else if (typeSupported === "pending") {
38484                    return false;
38485                }
38486            }
38487        }
38488        return match;
38489    };
38490    function picturefill(opt) {
38491            var elements,
38492                element,
38493                parent,
38494                firstMatch,
38495                candidates,
38496                options = opt || {};
38497            elements = options.elements || pf.getAllElements();
38498            // Loop through all elements
38499            for (var i = 0, plen = elements.length; i < plen; i++) {
38500                element = elements[i];
38501                parent = element.parentNode;
38502                firstMatch = undefined;
38503                candidates = undefined;
38504                // immediately skip non-`img` nodes
38505                if (element.nodeName.toUpperCase() !== "IMG") {
38506                    continue;
38507                }
38508                // expando for caching data on the img
38509                if (!element[pf.ns]) {
38510                    element[pf.ns] = {};
38511                }
38512                // if the element has already been evaluated, skip it unless
38513                // `options.reevaluate` is set to true ( this, for example,
38514                // is set to true when running `picturefill` on `resize` ).
38515                if (!options.reevaluate && element[pf.ns].evaluated) {
38516                    continue;
38517                }
38518                // if `img` is in a `picture` element
38519                if (parent.nodeName.toUpperCase() === "PICTURE") {
38520                    // IE9 video workaround
38521                    pf.removeVideoShim(parent);
38522                    // return the first match which might undefined
38523                    // returns false if there is a pending source
38524                    // TODO the return type here is brutal, cleanup
38525                    firstMatch = pf.getMatch(element, parent);
38526                    // if any sources are pending in this picture due to async type test(s)
38527                    // remove the evaluated attr and skip for now ( the pending test will
38528                    // rerun picturefill on this element when complete)
38529                    if (firstMatch === false) {
38530                        continue;
38531                    }
38532                } else {
38533                    firstMatch = undefined;
38534                }
38535                // Cache and remove `srcset` if present and we’re going to be doing `picture`/`srcset`/`sizes` polyfilling to it.
38536                if (parent.nodeName.toUpperCase() === "PICTURE" ||
38537                    (element.srcset && !pf.srcsetSupported) ||
38538                    (!pf.sizesSupported && (element.srcset && element.srcset.indexOf("w") > -1))) {
38539                    pf.dodgeSrcset(element);
38540                }
38541                if (firstMatch) {
38542                    candidates = pf.processSourceSet(firstMatch);
38543                    pf.applyBestCandidate(candidates, element);
38544                } else {
38545                    // No sources matched, so we’re down to processing the inner `img` as a source.
38546                    candidates = pf.processSourceSet(element);
38547                    if (element.srcset === undefined || element[pf.ns].srcset) {
38548                        // Either `srcset` is completely unsupported, or we need to polyfill `sizes` functionality.
38549                        pf.applyBestCandidate(candidates, element);
38550                    } // Else, resolution-only `srcset` is supported natively.
38551                }
38552                // set evaluated to true to avoid unnecessary reparsing
38553                element[pf.ns].evaluated = true;
38554            }
38555        }
38556        /**
38557         * Sets up picture polyfill by polling the document and running
38558         * the polyfill every 250ms until the document is ready.
38559         * Also attaches picturefill on resize
38560         */
38561    function runPicturefill() {
38562        picturefill();
38563        var intervalId = setInterval(function() {
38564            // When the document has finished loading, stop checking for new images
38565            // https://github.com/ded/domready/blob/master/ready.js#L15
38566            picturefill();
38567            if (/^loaded|^i|^c/.test(doc.readyState)) {
38568                clearInterval(intervalId);
38569                return;
38570            }
38571        }, 250);
38572        function checkResize() {
38573            var resizeThrottle;
38574            if (!w._picturefillWorking) {
38575                w._picturefillWorking = true;
38576                w.clearTimeout(resizeThrottle);
38577                resizeThrottle = w.setTimeout(function() {
38578                    picturefill({
38579                        reevaluate: true
38580                    });
38581                    w._picturefillWorking = false;
38582                }, 60);
38583            }
38584        }
38585        if (w.addEventListener) {
38586            w.addEventListener("resize", checkResize, false);
38587        } else if (w.attachEvent) {
38588            w.attachEvent("onresize", checkResize);
38589        }
38590    }
38591    runPicturefill();
38592    /* expose methods for testing */
38593    picturefill._ = pf;
38594    /* expose picturefill */
38595    if (typeof module === "object" && typeof module.exports === "object") {
38596        // CommonJS, just export
38597        module.exports = picturefill;
38598    } else if (typeof define === "function" && define.amd) {
38599        // AMD support
38600        define(function() {
38601            return picturefill;
38602        });
38603    } else if (typeof w === "object") {
38604        // If no AMD and we are in the browser, attach to window
38605        w.picturefill = picturefill;
38606    }
38607})(this, this.document, new this.Image());
38608
38609   /* Ende picturefill */
38610   /* Start navigationUtils */
38611   function NavigationUtils() {
38612
38613  /**
38614   * HTML des overlays
38615   * @static
38616   */
38617  NavigationUtils.prototype.overlay;
38618
38619  /**
38620   * HTML der Suche
38621   * @static
38622   */
38623  NavigationUtils.prototype.search;
38624
38625  NavigationUtils.prototype.scrollingElements = function (menu, base) {
38626    menu.find(base.options.scrollLayer + ' a,' + base.options.scrollLayer + ' strong').not('.no-subnavigation a, .no-subnavigation strong').each(function () {
38627      var currentScrollNode = $(this);
38628
38629      if (currentScrollNode.parent().is('em')) {
38630        if (currentScrollNode.parent().parent().siblings('ul').length > 0) {
38631          currentScrollNode.addClass('has-childs');
38632        }
38633      } else if (currentScrollNode.parent().siblings('ul').length > 0) {
38634        currentScrollNode.addClass('has-childs');
38635      }
38636    });
38637  };
38638
38639  NavigationUtils.prototype.addScollingLinks = function (menu, base, device) {
38640    //Ab welcher Ebene kann gescrollt werden
38641    menu.find(base.options.scrollLayer).not('.no-subnavigation').addClass('scrollFunction');
38642
38643    //Seitenlinks einfügen
38644    menu.find(base.options.scrollLayer + ' ul').not('.no-subnavigation').each(function () {
38645
38646      var currentUl = $(this);
38647
38648      var image = '<img src="' + base.options.backButtonImage + '" alt="' + base.options.backButtonAlt + '"/>';
38649      currentUl.addClass('inactive');
38650
38651      var upToImage = '<img src="' + base.options.backToFirstImage + '" alt="' + base.options.backToFirstAlt + '"/>';
38652      if (device == 'desktop') {
38653        currentUl.prepend('<li class="back"><button>' + image + '<span>' + currentUl.closest('li').find('.has-childs').first().text() + '</span></button></li>');
38654        currentUl.prepend('<li class="backToFirst"><button>' + upToImage + '<span>' + $(this).closest('.menu').siblings('h3').find('a, strong').text() + '</span></button></li>');
38655      } else {
38656        currentUl.prepend('<li class="back"><button>' + image + '<span>' + currentUl.closest('li').find('.has-childs').first().text() + '</span></button></li>');
38657        currentUl.prepend('<li class="backToFirst"><button>' + upToImage + '<span>' + $(this).closest('.level-2').find('.has-childs').first().text() + '</span></button></li>');
38658      }
38659    });
38660  };
38661
38662  // Getter und setter
38663
38664  NavigationUtils.prototype.setOverlay = function (elem) {
38665    NavigationUtils.overlay = elem;
38666  };
38667
38668  NavigationUtils.prototype.getOverlay = function () {
38669    return NavigationUtils.overlay;
38670  };
38671
38672  NavigationUtils.prototype.setSearch = function (elem) {
38673    NavigationUtils.search = elem;
38674  };
38675
38676  NavigationUtils.prototype.getSearch = function () {
38677    return NavigationUtils.search;
38678  };
38679}
38680   /* Ende navigationUtils */
38681   /* Start gsb_autosuggest */
38682   /*!
38683 * GSB-Plugin zur Darstellung von Suchvorschlaegen
38684 *
38685 * Optionen:
38686 * minInputLength: Ab wieviel eingegebenen Zeichen werden Vorschlaege ausgegeben (optional (default: 2))
38687 *
38688 * Author: gsb
38689 */
38690
38691;(function ($) {
38692    if (!$.gsb) {
38693        $.gsb = {};
38694    }
38695    $.gsb.AutoSuggestBoxCounter = 1;
38696    $.gsb.AutoSuggest = function (el, actionUrl, options) {
38697        var base = this;
38698        // Access to jQuery and DOM versions of element
38699        base.$el = $(el);
38700        base.el = el;
38701
38702        // BoxCounter
38703        base.boxNumber = $.gsb.AutoSuggestBoxCounter++;
38704        // Such-Textfeld
38705        base.$input = base.$el.find('input[type=text]:first');
38706        base.$submit = base.$el.find('input[type=submit]:first');
38707        if (base.$submit.length == 0) {
38708            base.$submit = base.$el.find('input[type=image]:first');
38709        }
38710        // Add a reverse reference to the DOM object
38711        base.$el.data("gsb.AutoSuggest", base);
38712        // Aktuelle Anfrage
38713        base.reqQuery = false;
38714        // Anfragen Cachen
38715        base.queries = [];
38716
38717        // Aktuelle Position
38718        base.enterPos = -1;
38719
38720        // Debug-Mode
38721        base.debug = false;
38722
38723        /**
38724         * Intialisierung
38725         */
38726        base.init = function (options) {
38727            base.actionUrl = actionUrl;
38728            base.options = $.extend({}, $.gsb.AutoSuggest.defaultOptions, options);
38729
38730            // AutoSuggest-Box vorbereiten und positionieren
38731            var positions = base.$input.position();
38732            base.$box = $('<p id="searchAutoSuggestBox' + base.boxNumber + '" class="searchAutoSuggestBox"></p>');
38733            base.$box.css({
38734                'width': base.$input.outerWidth() - 2 + 'px', // 2px Border
38735                'top': positions.top + base.$input.outerHeight() + 'px',
38736                'left': positions.left + 'px'
38737            });
38738            base.$box.hide();
38739
38740            $(window).resize(function () {
38741                positions = base.$input.position();
38742                base.$box.css({
38743                    'top': positions.top + base.$input.outerHeight() + 'px',
38744                    'left': positions.left + 'px'
38745                });
38746            });
38747
38748            // Browser-Auto-Vervollständigung deaktivieren
38749            base.$input.attr('autocomplete', 'off');
38750
38751            // Tastaturbefehle abfangen
38752            // Nicht mit jQuery, da alte Version dies noch nicht kann
38753            base.$input.get(0).onkeydown = function (e) {
38754                e = e || window.event;
38755                if (e) {
38756                    var code = e.keyCode != undefined && null != e.keyCode ? e.keyCode : e.which;
38757                    if (code == 13) return base.keydownEnter(); // Enter
38758                    else if (code == 38) return base.keydownUp(); // UpArrow
38759                        else if (code == 40) return base.keydownDown(); // DownArrow
38760                }
38761            };
38762
38763            // Bei Eingabe von mehr als zwei Zeichen Liste abrufen
38764            // Nicht mit jQuery, da alte Version dies noch nicht kann
38765            base.$input.get(0).onkeyup = function (e) {
38766                var go = false;
38767                e = e || window.event;
38768                if (e) {
38769                    var code = e.keyCode != undefined && null != e.keyCode ? e.keyCode : e.which;
38770                    if (code != 13 && code != 38 && code != 40) {
38771                        go = true;
38772                    }
38773                } else {
38774                    go = true;
38775                }
38776
38777                if (go) {
38778                    if (base.$input.val().length >= base.options.minInputLength) {
38779                        base.query(base.$input.val());
38780                    } else {
38781                        base.showSuggestionBox(false);
38782                    }
38783                }
38784            };
38785
38786            //base.$input.parents('p:first').css('position', 'relative');
38787            base.$input.after(base.$box);
38788
38789            base.$box = base.$el.find('#searchAutoSuggestBox' + base.boxNumber);
38790
38791            // Beim Defokussieren AutoSuggestbox schließen
38792            base.$input.bind('blur', function () {
38793                base.showSuggestionBox(false);
38794            });
38795        };
38796
38797        /**
38798         * Anfrage stellen
38799         */
38800        base.query = function (value) {
38801            base.reqQuery = value;
38802            if (typeof base.queries[base.reqQuery] == "undefined") {
38803                if (base.debug && typeof console != "undefined" && console && console.log) console.log('AutoSuggest-AJAX-Anfrage für "' + base.reqQuery + '"');
38804                $.ajax({
38805                    url: base.actionUrl,
38806                    dataType: 'json',
38807                    data: { 'userQuery': value },
38808                    error: function error(jqXHR, textStatus, errorThrown) {
38809                        if (base.debug && typeof console != "undefined" && console && console.log) console.log('AJAX Fehler beim Abruf der JSON-Resource ' + base.actionUrl + ': ' + textStatus + ' :: ' + errorThrown);
38810                    },
38811                    success: function success(data) {
38812                        base.queries[value] = data.suggestions;
38813                        if (base.reqQuery == value) {
38814                            if (base.debug && typeof console != "undefined" && console && console.log) console.log('AJAX-Antwort für "' + base.reqQuery + '" wird nun verarbeitet...');
38815                            if (base.debug && typeof console != "undefined" && console && console.log) console.log(data);
38816                            base.showSuggestions(data.suggestions);
38817                        } else {
38818                            if (base.debug && typeof console != "undefined" && console && console.log) console.log('AJAX-Antwort für "' + base.reqQuery + '" ist nicht mehr relevant...');
38819                        }
38820                    }
38821                });
38822            } else {
38823                base.showSuggestions(base.queries[base.reqQuery]);
38824            }
38825        };
38826
38827        /**
38828         * Vorschläge anzeigen
38829         */
38830        base.showSuggestions = function (suggestions) {
38831            base.$box.empty();
38832            var count = 0;
38833            for (var s in suggestions) {
38834                if (suggestions.hasOwnProperty(s) && suggestions[s].name) {
38835                    var $link = $('<a href="#"></a>');
38836                    $link.html(suggestions[s].name + '<em>' + suggestions[s].count + '</em>');
38837                    $link.click(function (e) {
38838                        e.preventDefault();
38839                        $(this).find('em').remove();
38840                        base.$input.val($(this).text());
38841                        base.$submit.click();
38842                    });
38843                    $link.appendTo(base.$box);
38844                    count++;
38845                }
38846            }
38847            if (count > 0) base.showSuggestionBox(true);else base.showSuggestionBox(false);
38848        };
38849
38850        /**
38851         * Suggestionbox ein/ausblenden
38852         */
38853        base.showSuggestionBox = function (show) {
38854            base.enterPos = -1;
38855            if (show) {
38856                base.$box.fadeIn('fast');
38857            } else {
38858                base.$box.fadeOut('fast');
38859            }
38860        };
38861
38862        /**
38863         * KeyDown: Runter
38864         */
38865        base.keydownDown = function () {
38866            if (base.debug && typeof console != "undefined" && console && console.log) console.log('KEYDOWN down');
38867
38868            if (base.enterPos < 0 && base.$box.find('a').length > 0) {
38869                base.$box.find('a').removeClass('active');
38870                base.enterPos = 0;
38871                $(base.$box.find('a')[base.enterPos]).addClass('active');
38872            } else if (base.enterPos < base.$box.find('a').length - 1) {
38873                base.$box.find('a').removeClass('active');
38874                base.enterPos++;
38875                $(base.$box.find('a')[base.enterPos]).addClass('active');
38876            }
38877        };
38878
38879        /**
38880         * KeyDown: Hoch
38881         */
38882        base.keydownUp = function () {
38883            if (base.debug && typeof console != "undefined" && console && console.log) console.log('KEYDOWN up');
38884
38885            if (base.enterPos < 0 && base.$box.find('a').length > 0) {
38886                base.$box.find('a').removeClass('active');
38887                base.enterPos = base.$box.find('a').length - 1;
38888                $(base.$box.find('a')[base.enterPos]).addClass('active');
38889            } else if (base.enterPos > 0) {
38890                base.$box.find('a').removeClass('active');
38891                base.enterPos--;
38892                $(base.$box.find('a')[base.enterPos]).addClass('active');
38893            }
38894        };
38895
38896        /**
38897         * KeyDown: Enter
38898         */
38899        base.keydownEnter = function () {
38900            if (base.debug && typeof console != "undefined" && console && console.log) console.log('KEYDOWN enter');
38901            if (base.enterPos >= 0 && base.$box.find('a').length > base.enterPos) {
38902                base.$box.find('a')[base.enterPos].click();
38903                return false;
38904            }
38905        };
38906        // Run initializer
38907        base.init(options);
38908    };
38909
38910    /**
38911     * Die Standard-Optionen fuer das Plugin
38912     */
38913    $.gsb.AutoSuggest.defaultOptions = {
38914        minInputLength: 2
38915    };
38916
38917    $.fn.gsb_AutoSuggest = function (actionUrl, options) {
38918        return this.each(function () {
38919            new $.gsb.AutoSuggest(this, actionUrl, options);
38920        });
38921    };
38922})(jQuery);
38923   /* Ende gsb_autosuggest */
38924   /* Start gsb_banner */
38925   /**
38926 * --GSBDocStart
38927 * @module gsb_banner
38928 * @version 1.5.3
38929 * - 1.3.0 jelseber Hinzufügen der Option und Funktion positionRelative, wenn oben platziert werden Banner relativ platziert, wenn unten dann absolute mit Platzhalter
38930 * - 1.3.1 jelseber Bei positionRelative wird das Banner im DOM nach den Sprunglinks (ul.navSkip) eingebunden, damit die Sprunglinks als erstes angetabbt werden können
38931 * - 1.3.2 rkrusenb positionRelative-Animation für "bottom"-Fall gefixt
38932 * - 1.4.0 rkrusenb Option 'matomoButtons' hinzugefügt
38933 * - 1.5.0 rkrusenb Opt-In mit GSB-eigenem Cookie fuer Matomo Tracking
38934 * - 1.5.1 rkrusenb Ein/Ausschalter fuer die Datenschutz-Seite
38935 * - 1.5.2 rkrusenb Workaround - Mehrfach-Animationen auf mobilen Geräten abkürzen
38936 * - 1.5.3 rkrusenb Option 'scriptUrl' hinzugefügt
38937 *
38938 * @see {@link http://semver.org|Semantic Versioning}
38939 * @author boelenbe
38940 *
38941 * @desc Banner-Box - Dieses Modul ermöglicht die Darstellung einer Information in Form eines Popup-Banner,
38942 * welches sich animiert ein- und ausgeblendet. Dieser Banner stellt eine Überschrift, einen Linktext sowie ein Bild,
38943 * die aus einem Textbaustein (TextFragment) ausgelesen werden, dar. Beim erstmaligen Aufrufen der Seite mit
38944 * konfiguriertem Banner wird dieser animiert im unteren Bildschirmbereich eingeblendet.
38945 *
38946 * @example
38947 * <div id="cookiebanner" class="cookiebanner top" data-position="top" data-animation="true">
38948 *  <div class="cookiebannerbox">
38949 *   <div>
38950 *    <div class="text">
38951 *    </div>
38952 *   </div>
38953 *  </div>
38954 * </div>
38955 *
38956 * @init
38957 *   $('#cookiebanner').gsb_banner({
38958 *   animation: $('#cookiebanner').data('animation'),
38959 *   position: $('#cookiebanner').data('position'),
38960 *   cookieName: 'cookiebanner',
38961 *   cookieLifeTimeInDaysClosed: 30
38962 * });
38963 *--GSBDocEnd
38964 */
38965var _paq = _paq || [];
38966;(function ($) {
38967  'use strict';
38968
38969  if (!$.gsb) {
38970    $.gsb = {};
38971  }
38972  /**
38973   * Initialisiert die Banner-Box
38974   * @param {DOM} el DOM-Banner-Element
38975   * @param {options} options JSON-Objekt zum überschreiben der Default-Options
38976   */
38977  $.gsb.banner = function gsbBanner(el, options) {
38978    // To avoid scope issues, use 'base' instead of 'this'
38979    // to reference this class from internal events and functions.
38980    var base = Object.create(gsbBanner.prototype);
38981    // Access to $ and DOM versions of element
38982    base.$el = $(el);
38983    base.el = el;
38984    base.options = $.extend(true, {}, $.gsb.banner.defaultOptions, options);
38985    // Add a reverse reference to the DOM object
38986    base.$el.data('gsb.banner', base);
38987
38988    // Run initializer
38989    base.init();
38990  };
38991  $.gsb.banner.prototype = {
38992
38993    init: function init() {
38994      var base = this;
38995      gsb.log('gsb_banner.init()');
38996      base.addMatomo();
38997      base.createBanner();
38998      base.$el.gsb_responsiveListener(base);
38999    },
39000
39001    addMatomoFormListeners: function addMatomoFormListeners() {
39002      var base = this,
39003          container = $('#matomoTracking'),
39004          enable = container.find('[name=matomoTracking][value=true]'),
39005          disable = container.find('[name=matomoTracking][value=false]');
39006      if (Cookies.get('matomoTracking')) {
39007        enable.prop('checked', true);
39008      } else {
39009        disable.prop('checked', true);
39010      }
39011      enable.on('click', base, base.matomoConsent);
39012      disable.on('click', base, base.matomoReject);
39013    },
39014
39015    show: function show() {
39016      var base = this,
39017          animationSpeed = base.options.animationSpeed;
39018      gsb.log('show banner position=' + base.options.position);
39019      if (base.options.positionRelative) {
39020        base.showPositionRelative();
39021      } else if (base.options.animation) {
39022        if (base.options.position === 'top') {
39023          base.$el.animate({ top: 0 }, animationSpeed);
39024        } else {
39025          base.$el.animate({ bottom: 0 }, animationSpeed);
39026        }
39027      } else {
39028        base.$el.css(base.options.position, 0);
39029      }
39030      base.$el.promise().done(function () {
39031        $('body').addClass(base.options.bodyVisibleClass).removeClass(base.options.bodyHiddenClass);
39032      });
39033    },
39034
39035    showPositionRelative: function showPositionRelative() {
39036      var base = this;
39037      if (base.options.position === 'top') {
39038        base.$el.addClass(base.options.positionRelativeClass);
39039        var $navSkipList = $(base.options.navSkipListSelector);
39040        if ($navSkipList.length > 0) {
39041          $navSkipList.after(base.$el);
39042        } else {
39043          console.warn('Das Cookiebanner wird vor der navSkip Liste eingebunden weil \'' + base.options.selectors.navSkipList + '\' nicht gefunden werden konnte.');
39044          $('header').before(base.$el);
39045        }
39046      } else {
39047        $('footer').after(base.$el);
39048        $('.' + base.options.positionRelativePlaceholderClass).remove();
39049        $('footer').after($('<div>').addClass(base.options.positionRelativePlaceholderClass).css('height', base.bannerHeight));
39050      }
39051      if (base.options.animation) {
39052        base.$el.finish().css({
39053          paddingTop: 0,
39054          paddingBottom: 0,
39055          height: 0
39056        }).animate({
39057          height: base.bannerHeight - base.options.topOffset,
39058          paddingTop: base.bannerPadding.top,
39059          paddingBottom: base.bannerPadding.bottom
39060        }, {
39061          duration: base.options.animationSpeed,
39062          complete: function complete() {
39063            base.$el.css('height', '');
39064          }
39065        });
39066      }
39067    },
39068
39069    hide: function hide(ignoreAnimation) {
39070      var base = this;
39071      if (base.bannerHeight && base.options.animation && !ignoreAnimation) {
39072        if (base.options.position === 'top') {
39073          if (base.options.positionRelative) {
39074            base.$el.animate({ height: 0, paddingTop: 0, paddingBottom: 0 }, base.options.animationSpeed, function () {
39075              base.$el.css('display', 'none');
39076            });
39077          } else {
39078            base.$el.animate({ top: -base.bannerHeight }, base.options.animationSpeed, function () {
39079              base.$el.css('display', 'none');
39080            });
39081          }
39082        } else {
39083          base.$el.animate({ bottom: -base.bannerHeight }, base.options.animationSpeed, function () {
39084            base.$el.css('display', 'none');
39085            $('.' + base.options.positionRelativePlaceholderClass).remove();
39086          });
39087        }
39088      } else {
39089        base.$el.css('display', 'none');
39090      }
39091      base.$el.promise().done(function () {
39092        $('body').addClass(base.options.bodyHiddenClass).removeClass(base.options.bodyVisibleClass);
39093      });
39094    },
39095
39096    createBanner: function createBanner(triggeredByResponsiveListener) {
39097      var base = this,
39098          buttons,
39099          rejectButton;
39100
39101      buttons = base.$el.find(base.options.closeButton);
39102
39103      if (!triggeredByResponsiveListener && base.options.matomoButtons) {
39104        rejectButton = buttons.first().clone().insertAfter(buttons.first());
39105
39106        buttons.first().text(base.options.labels.consent).on('click', base, base.matomoConsent);
39107        rejectButton.text(base.options.labels.reject).on('click', base, base.matomoReject);
39108
39109        buttons = buttons.add(rejectButton);
39110        base.matomoDone = true;
39111      }
39112
39113      base.prepareState(triggeredByResponsiveListener);
39114      // hide banner
39115      base.$el.css(base.options.position, base.options.positionRelative ? 0 : -base.bannerHeight);
39116      // if no cookie
39117      if (!base.options.cookieName) {
39118        base.show();
39119      } else if (!Cookies.get(base.options.cookieName)) {
39120        gsb.log('gsb_banner.createBanner() > no cookie');
39121        // display banner with or without animation
39122        base.show();
39123      } else {
39124        gsb.log('gsb_banner.createBanner() > valid cookie > hide banner');
39125        // hide banner without animation
39126        base.hide(true);
39127      }
39128      // create close button
39129      buttons.click(function (e) {
39130        gsb.log('gsb_banner.click() > confirm');
39131        e.preventDefault();
39132        e.stopPropagation();
39133        // hide banner with or without animation
39134        base.hide();
39135        // set cookie with expiredate
39136        Cookies.set(base.options.cookieName, 'closed', {
39137          expires: base.options.cookieLifeTimeInDaysClosed,
39138          path: '/'
39139        });
39140      });
39141    },
39142
39143    prepareState: function prepareState(reset) {
39144      var base = this;
39145      if (reset) {
39146        base.$el.css({
39147          paddingTop: '',
39148          paddingBottom: '',
39149          height: ''
39150        });
39151      }
39152      base.bannerHeight = !reset && base.bannerHeight && base.options.position === 'top' ? base.bannerHeight : base.$el.outerHeight() + base.options.topOffset;
39153      base.bannerPadding = !reset && base.bannerPadding ? base.bannerPadding : {
39154        top: base.$el.css('padding-top'),
39155        bottom: base.$el.css('padding-bottom')
39156      };
39157    },
39158
39159    matomoConsent: function matomoConsent(ev) {
39160      var base = ev.data;
39161      base.addMatomo();
39162      _paq.push(['setConsentGiven']);
39163      Cookies.set('matomoTracking', true, {
39164        expires: base.options.matomoTrackingCookieLifeTimeInDays,
39165        path: '/'
39166      });
39167      gsb.log('matomoConsent called');
39168    },
39169
39170    matomoReject: function matomoReject(ev) {
39171      var base = ev.data;
39172      _paq.push(['forgetConsentGiven']);
39173      Cookies.remove('matomoTracking');
39174      gsb.log('matomoReject called');
39175    },
39176
39177    addMatomo: function addMatomo() {
39178      var base = this,
39179          siteId = $('body').attr('data-matomo-site-id');
39180
39181      if (/^\d+$/.test(siteId) && $('#gsbMatomoScript').length === 0) {
39182        console.log('Matomo loaded');
39183        _paq.push(['disableCookie']);
39184        _paq.push(['setDocumentTitle', document.domain + "/" + document.title]);
39185        _paq.push(['trackPageView']);
39186        _paq.push(['enableLinkTracking']);
39187        _paq.push(['setTrackerUrl', base.options.trackerUrl]);
39188        _paq.push(['setSiteId', Number(siteId)]);
39189        _paq.push(['setDownloadClasses', "download_stat"]);
39190        _paq.push(['setDocumentTitle', '404/URL = ' + encodeURIComponent(document.location.pathname + document.location.search) + '/From = ' + encodeURIComponent(document.referrer)]);
39191        $(document.createElement('script')).attr({
39192          id: 'gsbMatomoScript',
39193          type: 'text/javascript',
39194          async: true,
39195          defer: true,
39196          src: base.options.scriptUrl
39197        }).insertBefore($("script:first"));
39198      }
39199    }
39200
39201  };
39202  $.gsb.banner.defaultOptions = {
39203    animation: typeof animation === 'undefined' ? false : animation,
39204    animationSpeed: 1800,
39205    position: typeof position === 'undefined' ? 'bottom' : position,
39206    topOffset: 20,
39207    closeButton: '.close', // jquery selector
39208    bodyVisibleClass: 'banner-visible',
39209    bodyHiddenClass: 'banner-hidden',
39210    positionRelativeClass: 'cookiebanner__relative',
39211    positionRelativePlaceholderClass: 'cookiebanner__placeholder',
39212    cookieName: 'gsbbanner',
39213    cookieLifeTimeInDaysClosed: 5,
39214    respondToEvents: true,
39215    positionRelative: false, // make room for the cookiebanner in the dom to not overlay content
39216    navSkipListSelector: 'ul.navSkip', // used if positionRelative is true
39217    matomoButtons: false,
39218    matomoTrackingCookieLifeTimeInDays: 5,
39219    scriptUrl: '//piwik.itzbund.de/js/',
39220    trackerUrl: '//piwik.itzbund.de/js/',
39221    labels: {
39222      consent: typeof TRACKING_CONSENT !== "undefined" ? TRACKING_CONSENT : 'Consent',
39223      reject: typeof TRACKING_DISSENT !== "undefined" ? TRACKING_DISSENT : 'Reject'
39224    },
39225    onRefresh: function onRefresh() {
39226      this.createBanner(true);
39227    }
39228  };
39229  /**
39230   * Initialisiert den Aufruf der die Banner-Box
39231   * @param {options} options JSON-Objekt zum überschreiben der Default-Options
39232   */
39233  $.fn.gsb_banner = function (options) {
39234    return this.each(function () {
39235      $.gsb.banner(this, options);
39236    });
39237  };
39238})(jQuery);
39239   /* Ende gsb_banner */
39240   /* Start gsb_maxHeight */
39241   /*!
39242 * @name maxHeight
39243 * @author @pespeloe
39244 * Licensed under the MIT license
39245 *
39246 * Container per Javascript auf die Höhe des höchsten
39247 * Containers setzen
39248 * */
39249;
39250(function ($) {
39251  if (!$.gsb) {
39252    $.gsb = {};
39253  }
39254  ;
39255  $.gsb.maxHeight = function (el, options) {
39256    // To avoid scope issues, use 'base' instead of 'this'
39257    // to reference this class from internal events and functions.
39258    var base = this;
39259    // Access to jQuery and DOM versions of element
39260    base.$el = $(el);
39261    base.el = el;
39262    // Add a reverse reference to the DOM object
39263    base.$el.data("gsb.maxHeight", base);
39264    base.init = function () {
39265      base.options = $.extend({}, $.gsb.maxHeight.defaultOptions, options);
39266      if (base.options.triggerFromOutside) {
39267        base.checkOptions(base);
39268      }
39269      $(window).on('resize load', function () {
39270        // um sicher zu sein das alle Bilder und somit alle Container
39271        // die entgültige Höhe haben
39272        if (typeof base.options.beforeInit === 'function') {
39273          base.options.beforeInit.call($(this), base.$el);
39274        }
39275        base.checkOptions(base);
39276        if (typeof base.options.afterInit === 'function') {
39277          base.options.afterInit.call($(this), base.$el, $items);
39278        }
39279      });
39280    };
39281    $.gsb.maxHeight.prototype.checkOptions = function (base) {
39282      if (base.options.elementsPerRow == null) {
39283        var $items = base.$el.find(base.options.boxes);
39284        if ($items.length > 0) {
39285          $items.css('height', 'auto');
39286          base.setHeight($items);
39287        }
39288      } else if (base.options.elementsPerRow > 1) {
39289        var items = [];
39290        base.$el.find(base.options.boxes).each(function (index) {
39291          items.push(this);
39292          if ((index + 1) % base.options.elementsPerRow == 0) {
39293            base.setHeight($(items));
39294            items = [];
39295          }
39296        });
39297      }
39298    };
39299    $.gsb.maxHeight.prototype.setHeight = function ($items) {
39300      var maxHeight = 0,
39301          maxHeightAbsoluteContainer = 0,
39302          maxHeightAdjacentElement = 0;
39303      $items.each(function () {
39304        var itemHeight = parseInt($(this).outerHeight());
39305        var moreButton;
39306        if (base.options.absoluteElements !== undefined) {
39307          moreButton = parseInt($(this).find(base.options.absoluteElements).outerHeight(true));
39308          if (moreButton > maxHeightAbsoluteContainer) maxHeightAbsoluteContainer = moreButton;
39309        }
39310        if (base.options.adjacentElements !== undefined) {
39311          heightAdjacentElement = parseInt($(this).parent().find(base.options.adjacentElements).outerHeight(true));
39312          if (heightAdjacentElement > maxHeightAdjacentElement) maxHeightAdjacentElement = heightAdjacentElement;
39313        }
39314        if (itemHeight > maxHeight) maxHeight = itemHeight;
39315      });
39316      $items.each(function () {
39317        if (base.options.adjacentElements !== undefined && $(this).parent().find(base.options.adjacentElements).length == 0) {
39318          $(this).css("height", maxHeight + maxHeightAbsoluteContainer + maxHeightAdjacentElement);
39319        } else {
39320          $(this).css("height", maxHeight + maxHeightAbsoluteContainer);
39321        }
39322      });
39323    };
39324    // Run initializer
39325    base.init();
39326  };
39327  $.gsb.maxHeight.defaultOptions = {
39328    boxes: '.slick-slide',
39329    elementsPerRow: null,
39330    absoluteElements: undefined,
39331    triggerFromOutside: false,
39332    beforeInit: undefined,
39333    afterInit: undefined,
39334    adjacentElements: undefined
39335  };
39336  //Search Reset
39337  $.fn.gsb_maxHeight = function (options) {
39338    return this.each(function () {
39339      new $.gsb.maxHeight(this, options);
39340    });
39341  };
39342})(jQuery);
39343   /* Ende gsb_maxHeight */
39344   /* Start gsb_calendar */
39345   /*!
39346 * GSB-Plugin zur Animation und zum Nachladen von Kalender
39347 *
39348 * Author: pespeloer
39349 */
39350;
39351(function ($) {
39352  if (!$.gsb) {
39353    $.gsb = {};
39354  }
39355  ;
39356
39357  $.gsb.calendar = function (el, options) {
39358    // To avoid scope issues, use 'base' instead of 'this'
39359    // to reference this class from internal events and functions.
39360    var base = this;
39361
39362    // Access to jQuery and DOM versions of element
39363    base.$el = $(el);
39364    base.el = el;
39365
39366    // Add a reverse reference to the DOM object
39367    base.$el.data("gsb.calendar", base);
39368
39369    base.init = function () {
39370      base.options = $.extend({}, $.gsb.calendar.defaultOptions, options);
39371      options = base.options;
39372
39373      //Klick auf einzelnen Termin
39374      base.$el.on("click touchstart", "td > a", function (e) {
39375        e.preventDefault();
39376        e.stopPropagation();
39377        // --- Termine des Tages anzeigen
39378        //Schlie�en
39379        if ($(this).parent().hasClass(options.detailsOpenedClass)) {
39380          $(this).parent().removeClass(options.detailsOpenedClass).addClass(options.detailsClosedClass);
39381        } else {
39382          // Alle ge�ffneten Details schlie�en
39383          base.$el.find('.' + options.detailsOpenedClass).removeClass(options.detailsOpenedClass);
39384          $(this).parent().removeClass(options.detailsClosedClass).addClass(options.detailsOpenedClass);
39385        }
39386      });
39387
39388      //Klick auf Zur�ckbutton
39389      base.$el.on("click touchstart", options.prevButton, function (e) {
39390        e.preventDefault();
39391        e.stopPropagation();
39392        base.loadCalendar($(this).data('href'));
39393      });
39394
39395      //Klick auf Vorbutton
39396      base.$el.on("click touchstart", options.nextButton, function (e) {
39397        e.preventDefault();
39398        e.stopPropagation();
39399        base.loadCalendar($(this).data('href'));
39400      });
39401    };
39402
39403    // --- N�chsten Monat laden
39404    //1. Fadeout
39405    //2. Container leeren und wieder bef�llen
39406    //3. Fadein
39407    //4. Focus auf das erste zu fokussierende Element setzen
39408
39409    base.loadCalendar = function (href) {
39410      if (typeof options.beforeInit === 'function') {
39411        base.options.beforeInit.call($(this), base.$el);
39412      }
39413
39414      base.$el.fadeTo(options.duration, 0, function () {
39415        base.$el.load(href, function () {
39416          base.$el.fadeTo(options.duration, 1, function () {
39417            base.addA11y();
39418            if (typeof options.afterInit === 'function') {
39419              base.options.afterInit.call($(this), base.$el);
39420            }
39421          });
39422        });
39423      });
39424    };
39425
39426    //Focus setzen
39427    base.addA11y = function (elem) {
39428      elem = elem || base.$el;
39429      var focusElements = elem.find('input,textarea,select,a,button').not(':hidden');
39430      focusElements[0].focus();
39431    };
39432
39433    // Run initializer
39434    base.init();
39435  };
39436
39437  $.gsb.calendar.defaultOptions = {
39438    nextButton: '.next > a',
39439    prevButton: '.prev > a',
39440    fadeDuration: 400,
39441    detailsOpenedClass: 'opened',
39442    detailsClosedClass: 'closed',
39443    beforeInit: undefined, //Vor Monatswechsel
39444    afterInit: undefined //Nach Monatswechsel
39445  };
39446
39447  //gsb Calendar
39448  $.fn.gsb_calendar = function (options) {
39449    return this.each(function () {
39450      new $.gsb.calendar(this, options);
39451    });
39452  };
39453})(jQuery);
39454   /* Ende gsb_calendar */
39455   /* Start gsb_clearfields */
39456   /*!
39457 * GSB-Plugin zum autom. Leeren von Text-Input-Feldern
39458 *
39459 * Author: sbaecker
39460 */
39461(function ($) {
39462  jQuery.fn.attachToField = function (id, defaultValue) {
39463    var field = $('#' + id);
39464    var input_text = field.attr('value');
39465    return jQuery(field).bind('focus', function () {
39466      if (input_text == defaultValue) {
39467        field.attr('value', '');
39468      }
39469    }).bind('blur', function () {
39470      if (field.attr('value') == '') {
39471        field.attr('value', input_text);
39472      }
39473      input_text = field.attr('value');
39474    });
39475  };
39476
39477  jQuery.gsb_clearfields = function () {
39478    // attach events to search form input
39479
39480    //HINWEIS: Bitte folgenden Zeilen im GSB einkommentieren
39481    //
39482    //    //  
39483    //  
39484    //      //    
39485    //        //      
39486    //      
39487    //      
39488    //      jQuery('#f6942653c85ec843c18743efed6942653d85ec843c18743f3c').attachToField('f6942653c85ec843c18743efed6942653d85ec843c18743f3c','');
39489    //    
39490    //  
39491    //    //  
39492    //  
39493    //      //    
39494    //        //      
39495    //      
39496    //      
39497    //      jQuery('#f6942653c85ec843c18743f02d6942653d85ec843c18743f3c').attachToField('f6942653c85ec843c18743f02d6942653d85ec843c18743f3c','');
39498    //    
39499    //  
39500    //    //  
39501    //  
39502    //  
39503    //    //  
39504    //  
39505    //  
39506    //
39507
39508    // HINWEIS: Bitte folgenden zeilen im GSB auskommentieren
39509    jQuery('#f7610d7612').attachToField('f7610d7612', 'Suchbegriff');
39510
39511    return;
39512  };
39513})(jQuery);
39514   /* Ende gsb_clearfields */
39515   /* Start gsb_lightbox */
39516   /**
39517 * @module gsb_lightbox
39518 * @version 1.0.0
39519 * @see {@link http://semver.org|Semantic Versioning}
39520 * @desc GSB-Wrapper-Plugin fuer magnific popup
39521 *
39522 *
39523 * @requires {@link external:jQuery}
39524 * @requires {@link external:magnific-popup}
39525 * @requires {@link external:hammerjs}
39526 * @requires {@link external:jquery-hammerjs}
39527 *
39528 * @author rkrusenb
39529 */
39530
39531//will be prettified eventually
39532(function ($) {
39533  if (!$.gsb) {
39534    $.gsb = {};
39535  };
39536  $.gsb.lightbox = function (el, userOptions) {
39537    var lightbox = this,
39538        $el = lightbox.$el = $(el),
39539        options,
39540        disabled;
39541    function openerClickHandler(ev) {
39542      if (!disabled) {
39543        ev && typeof ev.preventDefault == "function" && ev.preventDefault();
39544        $el.data('magnificPopup').index = $(this).data('gsb.lightboxopener').index;
39545      }
39546      $el.magnificPopup('open');
39547    }
39548    function checkArrowState(mfp) {
39549      if (!options.cycle && mfp.arrowLeft && mfp.arrowRight) {
39550        if (mfp.index == 0) {
39551          mfp.arrowLeft.find('img').attr('src', options.imagePrevInactive);
39552        } else {
39553          mfp.arrowLeft.find('img').attr('src', options.imagePrev);
39554        }
39555        if (mfp.index == mfp.items.length - 1) {
39556          mfp.arrowRight.find('img').attr('src', options.imageNextInactive);
39557        } else {
39558          mfp.arrowRight.find('img').attr('src', options.imageNext);
39559        }
39560      }
39561    }
39562    function makeGallery() {
39563      options.reallyMagnificOptions.callbacks.open = function () {
39564        var mfp = this;
39565        mfp.wrap.find('.mfp-close').appendTo(mfp.contentContainer);
39566        if (options.imagePrev) {
39567          $('.mfp-arrow-left').append('<img alt="' + options.reallyMagnificOptions.gallery.tPrev + '" src="' + options.imagePrev + '">');
39568        }
39569        if (options.imageNext) {
39570          $('.mfp-arrow-right').append('<img alt="' + options.reallyMagnificOptions.gallery.tNext + '" src="' + options.imageNext + '">');
39571        }
39572        mfp.prev = function () {
39573          if (options.cycle || mfp.index != 0) {
39574            $.magnificPopup.proto.prev.call(this);
39575          }
39576        };
39577        mfp.next = function () {
39578          if (options.cycle || mfp.index != mfp.items.length - 1) {
39579            $.magnificPopup.proto.next.call(this);
39580          }
39581        };
39582
39583        checkArrowState(this);
39584        if (typeof mfp.contentContainer.hammer == "function" && !mfp.wrap.data('gsb.swipe')) {
39585          mfp.contentContainer.hammer({
39586            drag_block_horizontal: true,
39587            stop_browser_behavior: { touchAction: 'auto' },
39588            swipe_velocity: 0.3
39589          }).on('swiperight', function () {
39590            mfp.prev();
39591          }).on('swipeleft', function () {
39592            mfp.next();
39593          }).data('gsb.swipe', {});
39594        }
39595      }; //end callbacks.open
39596      options.reallyMagnificOptions.callbacks.change = function () {
39597        checkArrowState(this);
39598      }; //end callbacks.change
39599      $.extend(options.reallyMagnificOptions, {
39600        items: $.map($(this).find(options.element), function (item) {
39601          return {
39602            src: $(item).clone().find('.loupe').remove().end().removeClass('slick-slide').attr('style', null),
39603            type: 'inline'
39604          };
39605        })
39606      }, (userOptions || {}).magnificOptions);
39607      $el.magnificPopup(options.reallyMagnificOptions).unbind('click');
39608    } //end makeGallery
39609    lightbox.el = el;
39610    // Add a reverse reference to the DOM object
39611    lightbox.$el.data("gsb.lightbox", lightbox);
39612    lightbox.init = function () {
39613      var url, closeText, defer;
39614      options = lightbox.options = $.extend({}, $.gsb.lightbox.defaultOptions, userOptions);
39615
39616      //init code here
39617      options.reallyMagnificOptions = $.extend({}, $.gsb.lightbox.defaultOptions.magnificOptions);
39618      closeText = options.magnificOptions.tClose;
39619      $.extend(options.reallyMagnificOptions, {
39620        disableOn: function disableOn() {
39621          return !disabled;
39622        },
39623        closeMarkup: '<button class="mfp-close">%title%</button>'
39624      });
39625
39626      if (options.lightboxType == 'single') {
39627        url = $el.data('lightbox-href');
39628        if (url) {
39629          options.reallyMagnificOptions.type = 'ajax';
39630          options.reallyMagnificOptions.ajax.settings.url = url;
39631        } else if ($el.parents(options.element).length) {
39632          options.reallyMagnificOptions.type = 'image';
39633        }
39634        $.extend(options.reallyMagnificOptions, (userOptions || {}).magnificOptions);
39635        $el.magnificPopup(options.reallyMagnificOptions);
39636      } else if (options.lightboxType == 'multiple') {
39637        url = $el.data('lightbox-href');
39638        if (url) {
39639          $('<div />').load(url, makeGallery);
39640        } else {
39641          $el.on('init.slideshow.gsb', makeGallery);
39642        }
39643        $el.on('init.slideshow.gsb', function () {
39644          $el.find('.loupe').each(function (idx) {
39645            var opener = $(this),
39646                openerData = opener.data('gsb.lightboxopener') || {};
39647            openerData.index = idx;
39648            opener.data('gsb.lightboxopener', openerData);
39649            opener.click(openerClickHandler).keydown(function (e) {
39650              if (e.which == 23) {
39651                $(this).click();
39652              }
39653            });
39654          });
39655        });
39656        $.extend(true, options.reallyMagnificOptions, {
39657          gallery: {
39658            enabled: true
39659          }
39660        });
39661        $.extend(options.reallyMagnificOptions, (userOptions || {}).magnificOptions);
39662      }
39663
39664      //call addA11y here somewhere
39665    };
39666    lightbox.closeLightbox = function () {
39667      $el.magnificPopup('close');
39668    };
39669    lightbox.disable = function () {
39670      disabled = true;
39671    };
39672    lightbox.enable = function () {
39673      disabled = false;
39674    };
39675
39676    lightbox.addA11y = function () {
39677      //add a11y enhancements
39678    };
39679    // Run initializer
39680    lightbox.init();
39681  };
39682  /**
39683   * @typedef defaultOptions
39684   * @type {object}
39685   * @property {object}   options                                       - Default Options des Scripts
39686   * @property {string}   [options.lightboxType]      single oder multiple - multiple füer Bildergallerie
39687   * @property {boolean}  [options.cycle]      rotation an oder aus
39688   * @property {string}   [options.element]   Vermutlich der Container dessen Inhalt in der Lightbox angezeigt werden soll
39689   * @property {string}   [options.imagePrev]   Zurückblättern-Pfeil, zwingend notwendig wenn lightboxtype auf multiple steht
39690   * @property {string}   [options.imageNext]   Vorblättern-Pfeil, zwingend notwendig wenn lightboxtype auf multiple steht
39691   * @property {Object}   [options.magnificOptions]   Optionen des magnificPopups (muss aber eigentlich nichts gemacht werden)
39692   * [siehe Doku]{@link http://dimsemenov.com/plugins/magnific-popup/documentation.html#options}
39693   */
39694  $.gsb.lightbox.defaultOptions = {
39695    lightboxType: 'single', //this is NOT the same as e.g. magnificOptions.type,
39696    cycle: false,
39697    element: '.picture',
39698    imagePrev: '', //MUST be specified if lightboxType = 'multiple'
39699    imageNext: '', //MUST be specified if lightboxType = 'multiple'
39700    magnificOptions: {
39701      //general label options
39702      tClose: typeof CLOSE == 'undefined' ? 'Schließen (Esc)' : CLOSE,
39703      gallery: {
39704        //gallery label options
39705        tPrev: typeof PREV == 'undefined' ? 'Vorheriges (linke Pfeiltaste)' : PREV, // Alt text on left arrow
39706        tNext: typeof NEXT == 'undefined' ? 'Nächstes (rechte Pfeiltaste)' : NEXT, // Alt text on right arrow
39707        tCounter: typeof LIGHTBOX_X_OF_Y == 'undefined' ? '%curr% von %total%' : LIGHTBOX_X_OF_Y // Markup for "1 of 7" counter
39708      },
39709      //main options
39710      type: 'ajax',
39711      closeOnContentClick: false,
39712      closeBtnInside: false,
39713      image: {
39714        verticalFit: true,
39715        titleSrc: function titleSrc() {
39716          return $(this.currItem && this.currItem.el).find('img').attr('alt');
39717        }
39718      },
39719      ajax: {
39720        settings: {}
39721      },
39722      callbacks: {
39723        afterChange: function afterChange() {
39724          $(this.content).find('video, audio').each(function (_, el) {
39725            var data = $(el).data("gsb.Multimedia");
39726            if (!data) {
39727              data = $(el).gsb_Multimedia().data("gsb.Multimedia");
39728            }
39729            if (!data.workaround && typeof data.triggerRefresh == "function") {
39730              data.workaround = true;
39731              data.triggerRefresh(); //no idea why this fixes it, but nothing else will
39732            }
39733          });
39734        },
39735        buildControls: function buildControls() {
39736          // re-appends controls inside the main container
39737          if (this.contentContainer && this.arrowLeft && this.arrowRight) {
39738            this.contentContainer.append(this.arrowLeft.add(this.arrowRight));
39739          }
39740        },
39741        open: function open() {
39742          if (this.wrap && this.wrap.find) {
39743            this.wrap.find('.mfp-close').appendTo(this.contentContainer);
39744          }
39745        }
39746      }
39747    }
39748  };
39749  $.fn.gsb_lightbox = function (options) {
39750    return this.each(function () {
39751      new $.gsb.lightbox(this, options);
39752    });
39753  };
39754})(jQuery);
39755   /* Ende gsb_lightbox */
39756   /* Start gsb_serviceborder */
39757   /*!
39758 * GSB-Plugin fuer Serviceleiste unter der Buehne
39759 *
39760 * Dabei wird die folgende HTML-Struktur erwartet
39761 *
39762 * <div id="service-border">
39763 *   <div id="tab">
39764 *     <ul class="tab">
39765 *       <li class="t-entry-1">
39766 *         <a class="navServiceNewsletter" href="...">Newsletter</a>
39767 *       </li>
39768 *       ...
39769 *     </ul>
39770 *   </div>
39771 *   <div id="section-1" class="container">
39772 *     ...
39773 *   </div>
39774 *   ...
39775 * </div>
39776 *
39777 * Aufruf:
39778 *  $("#navContent").gsb_Serviceborder();
39779 *
39780 * Author: sbaecker
39781 *
39782 * @requires jQuery >= 1.11.1, gsb_responsiveListener
39783 *
39784 */
39785
39786;
39787(function ($) {
39788  if (!$.gsb) {
39789    $.gsb = {};
39790  }
39791  ;
39792  $.gsb.Serviceborder = function (el, options) {
39793    var base = this,
39794        closeclick;
39795    // Access to jQuery and DOM versions of element
39796    base.$el = $(el);
39797    base.el = el;
39798    // Add a reverse reference to the DOM object
39799    base.$el.data("gsb.Serviceborder", base);
39800    /**
39801     * Initialisierung
39802     */
39803    base.init = function () {
39804      base.options = $.extend({}, $.gsb.Serviceborder.defaultOptions, options);
39805      base.$el.gsb_responsiveListener(base);
39806    };
39807    base._configuration = function () {
39808      closeclick = false;
39809
39810      if (!base.$el.length) return;
39811      // Tab-Navigation einrichten
39812      if (base.$el.find(base.options.navnodes + ' span.aural').length == 0) {
39813        base.$el.find(base.options.navnodes).append('<span class="aural"> ' + base.options.show_more_text + '</span>');
39814      }
39815      base.$el.find(base.options.navnodes).each(function () {
39816        $(this).on('click', function (e) {
39817          e.preventDefault();
39818          e.stopPropagation();
39819          base.showTab($(this));
39820          return false;
39821        });
39822      });
39823      // Nummer des aktiven Tabs und des Tabs, der als nächstes angezeigt werden soll
39824      base.tabActive = false;
39825      base.tabToShow = false;
39826    };
39827    /**
39828     * Einen Tab anzeigen
39829     */
39830    base.showTab = function (obj, close) {
39831      // Objekt übergeben?
39832      if (typeof obj != 'undefined' && obj) {
39833        // Tab-Nummer aus Klassenname des li über Link parsen
39834        var regExpMatch = obj.parent('li:first').attr('class').match(/^.*\w+-(\w+)-(\d+)( .*)?$/);
39835        base.tabToShow = regExpMatch[2];
39836      } else {
39837        // Tabs schließen
39838        closeclick = true;
39839        base.tabToShow = false;
39840      }
39841      //Klick auf das Icon eines bereits geöffneten tabs
39842      if (base.tabActive == base.tabToShow) {
39843        var tabActiveId = base.options.container + base.tabActive;
39844        var $tabActive = base.$el.find(tabActiveId);
39845        $tabActive.stop(true, true).fadeOut({ duration: base.options.fadeDuration, easing: 'linear', queue: false }).slideUp({ duration: base.options.slideDuration, easing: 'linear' });
39846        base.tabActive = false;
39847        // Tab-Überschriften deaktivieren
39848        base.$el.find(' ul > li .aural').text(" " + base.options.show_more_text);
39849        base.$el.find(' ul > li').removeClass('active');
39850      } else {
39851        // Wenn Tab nicht bereits angezeigt wird
39852        if (base.tabToShow != base.tabActive && false !== base.tabToShow) {
39853          // Tab-Elemente abrufen
39854          var tabToShowId = base.options.container + base.tabToShow;
39855          var $tabToShow = base.$el.find(tabToShowId);
39856          if (!$tabToShow.length) {
39857            alert('Tab ' + tabToShowId + ' nicht vorhanden...');
39858            return;
39859          }
39860          // Wenn nicht vorhanden, Schließen-Button hinzufügen
39861          if (!$tabToShow.find('.containerinner .close').length) {
39862            var $closeButton;
39863            if (base.options.close_button_markup_mode === 'image') {
39864              $closeButton = $('<p><button tabindex="0" class="close" title="' + base.options.close + '" ><img src="' + image_url_close + '" alt="' + base.options.close + '" /></button></p>');
39865            } else {
39866              $closeButton = $('<p><button tabindex="0" class="close">' + base.options.close + '</button></p>');
39867            }
39868            $closeButton.appendTo(tabToShowId + ' > .containerinner:first').on('click', function () {
39869              base.showTab();
39870              return false;
39871            });
39872          }
39873          base.$el.find('> div .close').unbind('click').on('click', function (e) {
39874            e.preventDefault();
39875            e.stopPropagation();
39876            // Tab schließen
39877            var tabActiveId = base.options.container + base.tabActive;
39878            var $tabActive = base.$el.find(tabActiveId);
39879            $tabToShow.stop(true, true).fadeOut({ duration: base.options.fadeDuration, easing: 'linear', queue: false }).slideUp({ duration: base.options.slideDuration, easing: 'linear' });
39880            obj.focus();
39881            base.tabActive = false;
39882            // Tab-Überschriften deaktivieren
39883            base.$el.find(' ul > li span.aural').text(' ' + base.options.show_more_text);
39884            base.$el.find('ul > li').removeClass('active');
39885          });
39886          // Ist gerade ein Tab geöffnet? => Ausblenden
39887          if (false !== base.tabActive) {
39888            var tabActiveId = base.options.container + base.tabActive;
39889            var $tabActive = base.$el.find(tabActiveId);
39890            $tabActive.slideUp();
39891          } else {
39892            $tabToShow.stop(true, true).fadeIn({ duration: base.options.fadeDuration, easing: 'linear', queue: false }).css('display', 'none').slideDown({ duration: base.options.slideDuration, easing: 'linear' });
39893          }
39894
39895          // Neuen Tab einblenden
39896          $tabToShow.slideDown();
39897          base.tabActive = base.tabToShow;
39898          // Entsprechende Tab-Überschrift aktivieren
39899          base.$el.find(' ul > li span.aural').text(' ' + base.options.show_more_text);
39900          base.$el.find(' ul > li').removeClass('active');
39901          obj.parent(':first').addClass('active');
39902          base.$el.find(' ul > li.active .aural').text(' ' + base.options.show_less_text);
39903        } else if (false === base.tabToShow && false !== base.tabActive) {
39904          // Tab schließen
39905          var tabActiveId = base.options.container + base.tabActive;
39906          var $tabActive = base.$el.find(tabActiveId);
39907          if (closeclick = true) {
39908            $tabActive.slideUp('fast');
39909            closeclick = false;
39910          } else {
39911            $tabActive.hide();
39912          }
39913          base.tabActive = false;
39914          // Tab-Überschriften deaktivieren
39915          base.$el.find(' ul > li span.aural').text(' ' + base.options.show_more_text);
39916          base.$el.find(' ul > li').removeClass('active');
39917        }
39918      }
39919    }; //Ende showTab
39920    base._uninit = function () {
39921      //Deaktivieren der Tab-Schließen Links
39922      var closeLink = base.$el.find('a.close');
39923      if (closeLink.length > 0) {
39924        if (closeLink.closest('p').length > 0) {
39925          closeLink.closest('p').off();
39926        } else {
39927          closeLink.off();
39928        }
39929      }
39930      if (base.$el.find('div .close').length > 0) {
39931        base.$el.find('div .close').off();
39932      }
39933      //Deaktivieren der Tabs
39934      if (base.$el.find(base.options.navnodes).length > 0) {
39935        base.$el.find(base.options.navnodes).off();
39936      }
39937      //Falls noch Tabs geöffnet waren -> schließen
39938      base.$el.find('.container').hide();
39939      base.$el.find(' ul > li span.aural').text(' ' + base.options.show_more_text);
39940      base.$el.find('>ul>li').removeClass('active');
39941    };
39942    // Init
39943    base.init();
39944  };
39945  $.gsb.Serviceborder.defaultOptions = {
39946    close: typeof CLOSE == 'undefined' ? 'Schließen' : CLOSE,
39947    close_button_markup_mode: 'image',
39948    navnodes: ' > ul > li > a',
39949    container: '#section-',
39950    show_more_text: typeof SHOW_MORE == 'undefined' ? 'Mehr anzeigen' : SHOW_MORE,
39951    show_less_text: typeof SHOW_LESS == 'undefined' ? 'Weniger anzeigen' : SHOW_LESS,
39952    slideDuration: 400, //MUST be integer; 200 = fast, 400 = default, 600 = slow
39953    fadeDuration: 600,
39954    respondToEvents: true,
39955    onRefresh: function onRefresh() {
39956      this._configuration();
39957    },
39958    responsive: [{
39959      breakpoint: 600,
39960      onRefresh: function onRefresh() {
39961        this._uninit();
39962      }
39963    }]
39964  };
39965  $.fn.gsb_Serviceborder = function (options) {
39966    return this.each(function () {
39967      new $.gsb.Serviceborder(this, options);
39968    });
39969  };
39970})(jQuery);
39971   /* Ende gsb_serviceborder */
39972   /* Start gsb_print */
39973   /*!
39974 * GSB-Plugin zum autom. Leeren von Text-Input-Feldern
39975 *
39976 * Das Addon fügt einen Link "Seite drucken" in eine vorhandene Liste ein
39977 * Aufruf: $("#element").gsb_init_printlink();
39978 * #element muss dabei ein <ul> sein, damit das html valide bleibt.
39979 *
39980 * Author: sbaecker
39981 *
39982 * @requires jQuery >= 1.11.1, gsb_responsiveListener
39983 *
39984 */
39985;
39986(function ($) {
39987  if (!$.gsb) {
39988    $.gsb = {};
39989  }
39990  ;
39991  $.gsb.printlink = function (el, options) {
39992    // To avoid scope issues, use 'base' instead of 'this'
39993    // to reference this class from internal events and functions.
39994    var base = this;
39995    var printInited = false;
39996    // Access to $ and DOM versions of element
39997    base.$el = $(el);
39998    base.el = el;
39999    // Add a reverse reference to the DOM object
40000    base.$el.data("gsb.printlink", base);
40001    base.init = function () {
40002      base.options = $.extend({}, $.gsb.printlink.defaultOptions, options);
40003      //Initialization Code
40004      base.$el.gsb_responsiveListener(base);
40005    };
40006    base._printlink = function () {
40007      if (!base.$el.length) {
40008        return;
40009      }
40010      if ($('#' + base.options.printlink_id).length == 0) {
40011        pattern = $('<li id="' + base.options.printlink_id + '"><a href="#" title="' + base.options.tooltip + '">' + base.options.page_text + '</a></li>');
40012        base.$el.prepend(pattern);
40013      }
40014      base.$el.parent().find('#' + base.options.printlink_id + ' a').on("click", function (e) {
40015        e.preventDefault();
40016        e.stopPropagation();
40017        window.print();
40018      });
40019    };
40020    base._uninit = function () {
40021      if (base.$el.find('#' + base.options.printlink_id)) {
40022        base.$el.find('#' + base.options.printlink_id).off().remove();
40023      }
40024    };
40025    // Run initializer
40026    base.init();
40027  };
40028  $.gsb.printlink.defaultOptions = {
40029    tooltip: typeof PRINT_TOOLTIP == 'undefined' ? 'Drucken (öffnet Dialog)' : PRINT_TOOLTIP,
40030    page_text: typeof PRINT_PAGE_TEXT == 'undefined' ? 'drucken' : PRINT_PAGE_TEXT,
40031    printlink_id: 'navFunctionsPrint',
40032    respondToEvents: true,
40033    onRefresh: function onRefresh() {
40034      this._printlink();
40035    },
40036    responsive: [{
40037      breakpoint: 1024,
40038      onRefresh: function onRefresh() {
40039        this._uninit();
40040      }
40041    }]
40042  };
40043  $.fn.gsb_printlink = function (options) {
40044    return this.each(function () {
40045      new $.gsb.printlink(this, options);
40046    });
40047  };
40048  $.gsb.printbutton = function (el, options) {
40049    // To avoid scope issues, use 'base' instead of 'this'
40050    // to reference this class from internal events and functions.
40051    var base = this;
40052    var printInited = false;
40053    // Access to $ and DOM versions of element
40054    base.$el = $(el);
40055    base.el = el;
40056    // Add a reverse reference to the DOM object
40057    base.$el.data("gsb.printbutton", base);
40058    base.init = function () {
40059      base.options = $.extend({}, $.gsb.printbutton.defaultOptions, options);
40060      //Initialization Code
40061      base.$el.gsb_responsiveListener(base);
40062    };
40063    base._printbutton = function () {
40064      if (!base.$el.length) {
40065        return;
40066      }
40067      if ($('#' + base.options.printbutton_id).length == 0) {
40068        pattern = $('<span id="' + base.options.printbutton_id + '"><a class="button" href="#" title="' + base.options.tooltip + '">' + base.options.page_text + '</a></span>');
40069        base.$el.prepend(pattern);
40070      }
40071      base.$el.parent().find('#' + base.options.printbutton_id + ' a').on("click", function (e) {
40072        e.preventDefault();
40073        e.stopPropagation();
40074        window.print();
40075      });
40076    };
40077    base._uninit = function () {
40078      if (base.$el.find('#' + base.options.printbutton_id)) {
40079        base.$el.find('#' + base.options.printbutton_id).off().remove();
40080      }
40081    };
40082    // Run initializer
40083    base.init();
40084  };
40085  $.gsb.printbutton.defaultOptions = {
40086    tooltip: typeof PRINT_BUTTON_TOOLTIP == 'undefined' ? 'Datenblatt durcken (öffnet Dialog)' : PRINT_BUTTON_TOOLTIP,
40087    page_text: typeof PRINT_BUTTON_TEXT == 'undefined' ? 'drucken' : PRINT_BUTTON_TEXT,
40088    printbutton_id: 'navFunctionsPrint',
40089    respondToEvents: true,
40090    onRefresh: function onRefresh() {
40091      this._printbutton();
40092    },
40093    responsive: [{
40094      breakpoint: 1024,
40095      onRefresh: function onRefresh() {
40096        this._uninit();
40097      }
40098    }]
40099  };
40100  $.fn.gsb_printbutton = function (options) {
40101    return this.each(function () {
40102      new $.gsb.printbutton(this, options);
40103    });
40104  };
40105})(jQuery);
40106   /* Ende gsb_print */
40107   /* Start gsb_slideshow */
40108   /*!
40109 * GSB-Wrapper-Plugin fuer slick.js.
40110 *
40111 * s. auch http://kenwheeler.github.io/slick/
40112 *
40113 * Optionen:
40114 * nextButtonImage: Das Hintergrundbild fuer den aktiven weiter-Link der Navigation(default: null)
40115 * nextButtonInactiveImage: Das Hintergrundbild fuer den inaktiven weiter-Link der Navigation(default: null)
40116 * nextTitle: Das title-Attribut fuer den aktiven weiter-Link der Navigation
40117 * (default: SLIDER_NEXT bzw. 'Nächste Seite')
40118 * nextTitleInactive: Das title-Attribut fuer den inaktiven weiter-Link der Navigation
40119 * (default: SLIDER_NEXT_INACTIVE bzw. 'Keine nächste Seite')
40120 * prevButtonImage: Das Hintergrundbild fuer den aktiven zurueck-Link der Navigation(default: null)
40121 * prevButtonInactiveImage: Das Hintergrundbild fuer den aktiven zurueck-Link der Navigation(default: null)
40122 * prevTitle: Das title-Attribut fuer den aktiven zurueck-Link der Navigation
40123 * (default: SLIDER_BACK bzw. 'Vorherige Seite')
40124 * prevTitleInactive: Das title-Attribut fuer den aktiven zurueck-Link der Navigation
40125 * (default: SLIDER_BACK_INACTIVE bzw. 'Keine vorherige Seite')
40126 * playButtonImagePlaying: Das Hintergrundbild fuer den Playbutton im abspielenden Zustand(default: null)
40127 * playButtonImagePaused: Das Hintergrundbild fuer den Playbutton im pausierten Zustand(default: null)
40128 * playButtonAltTextPlaying: Das alt-Attribut fuer den Playbutton im abspielenden Zustand
40129 * (default: SLIDER_PLAY bzw. 'Animation starten')
40130 * playButtonAltTextPaused: Das alt-Attribut fuer den Playbutton im pausierten Zustand
40131 * (default: SLIDER_PAUSE bzw. 'Animation stoppen')
40132 * slickOptions: native Optionen fuer das Slick Plugin(default: null, siehe Doku oben)
40133 * slickOptions.gsb.playButton: Soll ein Playbutton angelegt werden(default: true), an dieser Stelle
40134 * hinterlegt, um responsiven Reinitialisierungmechanismus von Slick zu nutzen
40135 *
40136 * Author: anuebel
40137 */
40138
40139/*global jQuery, console, SLIDER_NEXT, SLIDER_NEXT_INACTIVE, SLIDER_BACK, SLIDER_BACK_INACTIVE */
40140
40141// Multimedia-Einbindung mit requireGSBComponent erweitert
40142;
40143var gsb;
40144gsb = gsb || {};
40145(function ($) {
40146  'use strict';
40147
40148  if (!$.gsb) {
40149    $.gsb = {};
40150  }
40151
40152  $.gsb.Slideshow = function (el, options) {
40153    var base = this;
40154
40155    base.$el = $(el);
40156    base.el = el;
40157    base.$el.data("gsb.Slideshow", base);
40158
40159    //noinspection JSUnusedGlobalSymbols
40160    base.defaultSlickOptions = {
40161      slide: '.slide',
40162      fade: true,
40163      infinite: false,
40164      draggable: false,
40165      adaptiveHeight: false,
40166      onBeforeChange: function onBeforeChange(slick) {
40167        //ohne diese Anweisung kann die Höhenberechnung fehlschlagen
40168        //die "falschen" Elemente werden in updateTabindex wieder verborgen
40169        slick.$slides.find('video, object').show();
40170      },
40171      onAfterChange: function onAfterChange(slick) {
40172        base.updateNavigation(slick);
40173        base.updateTabindex(slick);
40174      },
40175      onInit: function onInit(slick) {
40176        var slideshowPluginInstance = slick.$slider.data('gsb.Slideshow');
40177        var onSlickInit = slideshowPluginInstance.options.onSlickInit;
40178        if (typeof onSlickInit === 'function') {
40179          onSlickInit.call(slick, slick, base);
40180        }
40181        base.updateNavigation(slick);
40182        base.initMultimedia();
40183        base.updateTabindex(slick);
40184        base.$el.trigger('init.slideshow.gsb');
40185      },
40186      // gsb Namespace zur Nutzung des responsiven Reinitialisierungsmechanismus
40187      gsb: {
40188        playButton: true
40189      }
40190    };
40191    base.initMultimedia = function initMultimedia() {
40192      var base = this;
40193      if (base.$el.find('video, audio').length > 0) {
40194        var $video = base.$el.find('video, audio');
40195        gsb.requireGSBComponent('bundle_multimedia', $video).done(function ($video) {
40196          $video.gsb_Multimedia({
40197            externalApiRequiresConsent: !$('body').hasClass('js-youtube-consent-not-required')
40198          });
40199        });
40200      }
40201    };
40202    base.updateTabindex = function updateTabindex(slick) {
40203      //Barrierefreiheit/Tabbing workaround
40204      var focusableItems = 'a, [tabindex], textarea, input, select, button, video, object',
40205          buggedItems = 'video, object';
40206      slick.$slides.not('.slick-active').find(focusableItems).attr('tabindex', -1).end().find(buggedItems).hide();
40207      slick.$slides.filter('.slick-active').find(focusableItems).attr('tabindex', 0).end().find(buggedItems).show();
40208    };
40209
40210    base.updateNavigationArrow = function ($arrow, activeImage, inactiveImage, activeArrowButtonTitle, inactiveArrowButtonTitle) {
40211      if ($arrow) {
40212        var $arrowButton = $arrow.is('button') ? $arrow : $arrow.find('button'),
40213            $arrowImage = $arrow.find('img');
40214        if ($arrow.hasClass('slick-disabled')) {
40215          $arrowButton.attr('disabled', '');
40216          $arrowButton.attr('title', inactiveArrowButtonTitle);
40217          $arrowImage.attr('src', inactiveImage);
40218          $arrowImage.attr('alt', '');
40219        } else {
40220          $arrowButton.removeAttr('disabled');
40221          $arrowButton.attr('title', activeArrowButtonTitle);
40222          $arrowImage.attr('src', activeImage);
40223          $arrowImage.attr('alt', activeArrowButtonTitle);
40224        }
40225      }
40226    };
40227
40228    /**
40229     * Fuehrt Manipulationen an der HTML-Struktur der Navigation durch. Dazu gehoeren u.a. die Aktualisierung der
40230     * Bilder und die Nachruestung von Elementen, die fuer die Barrierefreiheit relevant sind.
40231     * @param slick das Slick-Objekt, das Informationen ueber den Zustand des Karussells enthaelt.
40232     */
40233    base.updateNavigation = function (slick) {
40234      if (base.options.hideArrowsIfPossible) {
40235        if (slick.$slides.length <= slick.options.slidesToShow) {
40236          base.$el.next().find('.next, .prev').hide();
40237        } else {
40238          base.$el.next().find('.next, .prev').show();
40239        }
40240      }
40241
40242      base.updateNavigationArrow(slick.$prevArrow, base.options.prevButtonImage, base.options.prevButtonInactiveImage, base.options.prevTitle, base.options.prevTitleInactive);
40243      base.updateNavigationArrow(slick.$nextArrow, base.options.nextButtonImage, base.options.nextButtonInactiveImage, base.options.nextTitle, base.options.nextTitleInactive);
40244    };
40245
40246    /**
40247     * Einige der fuer das alte Slideshow-Plugin definierten Optionen werden auf die korrespondierenden
40248     * Slick-Optionen gemapt. Beispiel: pagination->dots
40249     *
40250     * Wird eine Legacy-Option in options gefunden, so wird sie dort geloescht und unter dem gemappten Namen in den
40251     * slickOptions registriert.
40252     *
40253     * @param slickOptions die Optionen, die an Slick uebergeben werden
40254     * @param options die Optionen, die an dieses Plugin uebergeben wurden
40255     */
40256    base.handleLegacyOptions = function (slickOptions, options) {
40257      $.each($.gsb.Slideshow.slickOptionsForLegacyOptions, function (legacyOption, mappedSlickOption) {
40258        if (options.hasOwnProperty(legacyOption)) {
40259          var savedValue = options[legacyOption];
40260          delete options[legacyOption];
40261          slickOptions[mappedSlickOption] = savedValue;
40262        }
40263      });
40264    };
40265
40266    /**
40267     * Initialisiert die Dots. Wird ein Selektor angegeben, wird ausgehend von base.$el gesucht, andernfalls (also Object)
40268     * wird der Slick Standard ausgeführt.
40269     * Diese Funktion wird nur ausgeführt, wenn die Slick-Option appendDots gefüllt ist.
40270     * Sie ermöglicht es, die Postion im HTML der Dots zu bestimmen
40271     * @param slickOptions die Optionen, die an Slick uebergeben werden
40272     */
40273
40274    base.handleDots = function (slickOptions) {
40275      var dotOptions = {};
40276      if (typeof slickOptions.appendDots === "string") {
40277        dotOptions = { appendDots: base.$el.find(slickOptions.appendDots) };
40278      } else {
40279        dotOptions = { appendDots: slickOptions.appendDots };
40280      }
40281
40282      return $.extend({}, slickOptions, dotOptions);
40283    };
40284
40285    /**
40286     * Initialisiert die Navigationspfeile. Diese duerfen erst nach einem etwaigen Austausch des HTML ermittelt werden,
40287     * da sie ggf. mit ersetzt werden. In diesem Fall wuerden ansonsten die nachgeladene Pfeile nicht
40288     * initialisiert.
40289     * @param slickOptions die Optionen, die an Slick uebergeben werden
40290     */
40291    base.handleNavigationArrows = function (slickOptions) {
40292      var navigationArrowOptions = {
40293        nextArrow: base.$el.find('.next'),
40294        prevArrow: base.$el.find('.prev')
40295      };
40296      return $.extend({}, navigationArrowOptions, slickOptions);
40297    };
40298
40299    /**
40300     * Initialisiert den Playbutton, der zum Starten und Stoppen des Autoplay-Modus benutzt wird.
40301     *
40302     * Aufgrund des responsiven Reinitialisierungsmechanismus von Slick wird die Eigenschaft createPlayButton ueber
40303     * ein gsb-Objekt in den Slick-Options zur Verfuegung gestellt.
40304     * @param slickOptions die Optionen, die an Slick uebergeben werden
40305     */
40306    base.handlePlayButton = function (slickOptions) {
40307      (function (existingOnInit) {
40308        slickOptions.onInit = function (slick) {
40309          // das zuvor konfigurierte onInit-Callback aufrufen
40310          existingOnInit.call(slick, slick);
40311          var initializedSlickOptions = slick.options;
40312
40313          function shouldCreatePlayButton() {
40314            var playButtonImagesAreConfigured = base.options.playButtonImagePlaying !== null && base.options.playButtonImagePaused !== null,
40315                createPlayButton = initializedSlickOptions.gsb.playButton;
40316            return createPlayButton && playButtonImagesAreConfigured;
40317          }
40318
40319          function preventPlay() {
40320            slick.paused = true;
40321            slick.autoPlayClear();
40322          }
40323
40324          var $existingPlayButton = base.$el.parent().find('.navigation button.playbutton'),
40325              playButtonExists = $existingPlayButton.length;
40326          if (shouldCreatePlayButton() && !playButtonExists) {
40327            var slideshowStartsPlaying = initializedSlickOptions.autoplay,
40328                initialClassForPlayButton = slideshowStartsPlaying && 'playbutton-playing' || 'playbutton-paused',
40329                initialTitleAttrForPlayButton = slideshowStartsPlaying && base.options.playButtonAltTextPlaying || base.options.playButtonAltTextPaused,
40330                initialSrcAttrForPlayButtonImage = slideshowStartsPlaying && base.options.playButtonImagePlaying || base.options.playButtonImagePaused,
40331                initialAltAttrForPlayButtonImage = slideshowStartsPlaying && base.options.playButtonAltTextPlaying || base.options.playButtonAltTextPaused,
40332                $playButton = $('<button' + ' class="playbutton ' + initialClassForPlayButton + '"' + ' title="' + initialTitleAttrForPlayButton + '">' + '<img' + ' src="' + initialSrcAttrForPlayButtonImage + '"' + ' alt="' + initialAltAttrForPlayButtonImage + '">' + '</button>'),
40333                playButtonImage = $playButton.find('img');
40334            base.$el.parent().find('.navigation').append($playButton);
40335            $playButton.click(function () {
40336              if ($playButton.is('.playbutton-playing')) {
40337                $playButton.removeClass().addClass('playbutton-paused').attr('title', base.options.playButtonAltTextPaused);
40338                playButtonImage.attr('src', base.options.playButtonImagePaused).attr('alt', base.options.playButtonAltTextPaused);
40339                base.$el.slick('slickPause');
40340                slick.$list.on('mouseleave.slick', preventPlay);
40341              } else {
40342                $playButton.removeClass().addClass('playbutton-playing').attr('title', base.options.playButtonAltTextPlaying);
40343                playButtonImage.attr('src', base.options.playButtonImagePlaying).attr('alt', base.options.playButtonAltTextPlaying);
40344                base.$el.slick('slickPlay');
40345                slick.$list.off('mouseleave.slick', preventPlay);
40346              }
40347            });
40348          } else if (!shouldCreatePlayButton() && playButtonExists) {
40349            $existingPlayButton.remove();
40350          }
40351        };
40352      })(slickOptions.onInit);
40353      return slickOptions;
40354    };
40355    base.init = function () {
40356      base.options = $.extend({}, $.gsb.Slideshow.defaultOptions, options);
40357
40358      var allElementsUrl = base.$el.data('href'),
40359          initSlick = function initSlick() {
40360        var rawSlickOptions = base.options.slickOptions;
40361        delete rawSlickOptions.onInit;
40362        var slickOptions = $.extend({}, base.defaultSlickOptions, rawSlickOptions);
40363        base.handleLegacyOptions(slickOptions, base.options);
40364        slickOptions = base.handleNavigationArrows(slickOptions);
40365        slickOptions = base.handlePlayButton(slickOptions);
40366
40367        if (slickOptions.appendDots) {
40368          slickOptions = base.handleDots(slickOptions);
40369        }
40370
40371        var onSlickBeforeInit = slickOptions.onSlickBeforeInit;
40372        if (typeof onSlickBeforeInit === 'function') {
40373          onSlickBeforeInit.call(base, base);
40374        }
40375
40376        base.$el.on('init', function (e, slick) {
40377          slickOptions.onInit.call(base, slick);
40378        });
40379
40380        base.$el.on('afterChange', function (e, slick) {
40381          slickOptions.onAfterChange.call(base, slick);
40382        });
40383        base.$el.on('beforeChange', function (e, slick) {
40384          slickOptions.onBeforeChange.call(base, slick);
40385        });
40386
40387        base.$el.slick(slickOptions);
40388      },
40389          onReceiveAllElements = function onReceiveAllElements(data) {
40390        base.$el.html(data);
40391        setTimeout(function () {
40392          initSlick();
40393        }, 300);
40394      };
40395
40396      if (allElementsUrl) {
40397        $.get(allElementsUrl, onReceiveAllElements);
40398      } else {
40399        initSlick();
40400      }
40401    };
40402
40403    base.init();
40404  };
40405
40406  /**
40407   * Die Standard-Optionen fuer das Plugin
40408   */
40409  $.gsb.Slideshow.defaultOptions = {
40410    hideArrowsIfPossible: false,
40411    nextButtonImage: null,
40412    nextButtonInactiveImage: null,
40413    nextTitle: typeof NEXT === 'undefined' ? 'Nächste Seite' : NEXT,
40414    nextTitleInactive: typeof NEXT_INACTIVE === 'undefined' ? 'Keine nächste Seite' : NEXT_INACTIVE,
40415    prevButtonImage: null,
40416    prevButtonInactiveImage: null,
40417    prevTitle: typeof BACK === 'undefined' ? 'Vorherige Seite' : BACK,
40418    prevTitleInactive: typeof BACK_INACTIVE === 'undefined' ? 'Keine vorherige Seite' : BACK_INACTIVE,
40419    playButtonImagePaused: null,
40420    playButtonImagePlaying: null,
40421    playButtonAltTextPaused: typeof PLAY === 'undefined' ? 'Animation starten' : PLAY,
40422    playButtonAltTextPlaying: typeof PAUSE === 'undefined' ? 'Animation stoppen' : PAUSE,
40423    paginationTitle: typeof PAGE === 'undefined' ? 'Seite' : PAGE,
40424    slickOptions: null
40425  };
40426
40427  /**
40428   * Das Mapping von alten Optionen fuer das gsb_slideshow.js Plugin auf Slick-Optionen
40429   * @see #handleLegacyOptions
40430   */
40431  $.gsb.Slideshow.slickOptionsForLegacyOptions = {
40432    containerElement: 'slide',
40433    elementsToSlide: 'slidesToShow',
40434    autoplay: 'autoplay',
40435    autoSpeed: 'autoplaySpeed',
40436    pagination: 'dots',
40437    pauseOnHover: 'pauseOnHover'
40438  };
40439
40440  $.fn.gsb_Slideshow = function (options) {
40441    return this.each(function () {
40442      return new $.gsb.Slideshow(this, options);
40443    });
40444  };
40445})(jQuery);
40446   /* Ende gsb_slideshow */
40447   /* Start gsb_slideshow_rowAddon */
40448   /*!
40449 * @name slideshow_rowAddon
40450 * @author @
40451 * Licensed under the MIT license
40452 *
40453 * @requires slick < 1.5.0,
40454 * */
40455;
40456(function ($) {
40457  if (!$.gsb) {
40458    $.gsb = {};
40459  }
40460  ;
40461
40462  $.gsb.slideshow_rowAddon = function (el, options, slideshow) {
40463    // To avoid scope issues, use 'base' instead of 'this'
40464    // to reference this class from internal events and functions.
40465    var base = this;
40466
40467    // Access to jQuery and DOM versions of element
40468    base.$el = $(el);
40469    base.el = el;
40470    base.slideshow = slideshow;
40471
40472    // Add a reverse reference to the DOM object
40473    base.$el.data("gsb.slideshow_rowAddon", base);
40474
40475    base.init = function () {
40476      base.options = $.extend({}, $.gsb.slideshow_rowAddon.defaultOptions, options);
40477      base.$el.gsb_responsiveListener(base);
40478    };
40479
40480    $.gsb.slideshow_rowAddon.prototype.setRows = function () {
40481      var teaser = base.slideshow.$el.find('.slide');
40482      var html = '<div class="' + teaser.prop("class") + '">';
40483      if (base.options.slidesPerRow > 1) {
40484        teaser.each(function (index) {
40485          html += "<div>" + $(this).html() + "</div>";
40486          if ((index + 1) % base.options.slidesPerRow == 0 && index < teaser.length - 1) {
40487            html += '</div><div class="' + teaser.prop("class") + '">';
40488          }
40489        });
40490        html += "</div>";
40491        base.slideshow.$el.empty().html(html);
40492      }
40493    };
40494
40495    // Run initializer
40496    base.init();
40497  };
40498
40499  $.gsb.slideshow_rowAddon.defaultOptions = {
40500    respondToEvents: false,
40501    slidesPerRow: 2,
40502    onRefresh: function onRefresh() {
40503      this.setRows();
40504    },
40505    responsive: [{
40506      breakpoint: 640,
40507      slidesPerRow: 1,
40508      onRefresh: function onRefresh() {
40509        this.setRows();
40510      }
40511    }]
40512  };
40513
40514  $.fn.gsb_slideshow_rowAddon = function (options, slideshow) {
40515    return this.each(function () {
40516      new $.gsb.slideshow_rowAddon(this, options, slideshow);
40517    });
40518  };
40519})(jQuery);
40520   /* Ende gsb_slideshow_rowAddon */
40521   /* Start gsb_toggle */
40522   /**
40523 * @module gsb_toggle
40524 * @version 1.5.3
40525 * @see {@link http://semver.org|Semantic Versioning}
40526 * @author pespeloe
40527 *
40528 * @desc Dieses Modul erstellt in der Default-Konfiguration eine Accordion in small und ein Tab-Modul in large
40529 * Über die einzelnen Optionen kann auch nur ein Tab oder nur ein Accordion erstellt werden.  Mit der Klasse "active-control"
40530 * kann festgelegt werden, welcher Tab/Accordion bei der Initialisierung geöffnet sein soll.<br>
40531 * Wenn der Inhalt der Tabs nachgeladen werden soll, muss im Template ein data-href Attribut vorhanden sein. Gleiches Vorgehen
40532 * wie bei dem Modul gsb_Sldeshow.<br><br>
40533 * Fest definiert sind die Klassen<br>
40534 *   "tabs-container" -> Klasse für den Wrapper des einzelnen Tabs<br>
40535 *   "heading" ->  Element was für die Steuerung als Accordion dient<br>
40536 *   "tabs-list" -> Wrapper der Steuerelemente als Tab<br>
40537 *   "active-control" -> Aktuell ausgewählter Tab/Accordion<br>
40538 *   "inactive-control" -> inaktiver Tab/Accordion<br>
40539 *   "gsb-toggle" -> Klasse des "Gesamt-Wrappers"
40540 *
40541 * @requires  {@link external:jQuery}
40542 * @requires  gsb_responsiveListener
40543 *
40544 * @example
40545 * HTML: Velocity
40546 * <div class="tabaccordion">
40547 *  <ul class="tabs-list">
40548 *    <li class="active-control">
40549 *     <a href="#">Inhalt (Tab Control)</a>
40550 *    </li>
40551 *    <li>
40552 *     <a href="#">Inhalt 2 (Tab Control)</a>
40553 *    </li>
40554 *  </ul>
40555 *  <div class="tabs-container">
40556 *    <h2 class="heading active-control">Inhalt (Accordion Control)</h2>
40557 *    <div>
40558 *     Inhalt
40559 *    </div>
40560 *    <h2 class="heading">Inhalt 2 (Accordion Control)</h2>
40561 *    <div>
40562 *     Inhalt 2
40563 *    </div>
40564 *  </div>
40565 * </div>
40566 *
40567 * @example
40568 * JS: init
40569 * $('.tabaccordion').gsb_toggle({options});
40570 *
40571 * */
40572;
40573(function ($) {
40574  if (!$.gsb) {
40575    $.gsb = {};
40576  }
40577  ;
40578
40579  $.gsb.toggle = function (el, options) {
40580    // Access to $ and DOM versions of element
40581    var base = this;
40582    base.$el = $(el);
40583    base.el = el;
40584    this.base = base;
40585    // Add a reverse reference to the DOM object
40586    base.$el.data("gsb.toggle", base);
40587
40588    base.init = function () {
40589      this.base.options = $.extend({}, $.gsb.toggle.defaultOptions, options);
40590      var _ = this.base;
40591
40592      if (_.options.accordion && _.options.richTextAccordion) {
40593        _.addRichtextContainer();
40594      } else {
40595        if (base.$el.data('href')) {
40596          $.get(base.$el.data('href'), function (data) {
40597            base.$el.html(data);
40598            base.$el.gsb_responsiveListener(_);
40599          });
40600        } else {
40601          base.$el.gsb_responsiveListener(_);
40602        }
40603      }
40604    };
40605    // Run initializer
40606    base.init();
40607  };
40608
40609  /**
40610   * @typedef defaultOptions
40611   * @type {object}
40612   * @property {object}   options                                   - Default Options des Scripts
40613   * @property {boolean}  [options.tab=true]                        - Aktiviert / Deaktiviert die Tab-Funktion
40614   * @property {string}   [options.tabControls='.tabs-list > li a'] - Steuerungselemente fuer die Tab-Darstellung
40615   * @property {boolean}  [options.accordion=true]                  - Aktiviert / Deaktiviert die Accordion-Funktion
40616   * @property {boolean}  [options.richTextAccordion=false]         - Aktiviert / Deaktiviert die Richtext-Accordion-Funktion -> nur wenn Option accordion true ist. ACHTUNG: Es ist nur ein Richtext-Accordion pro Seite möglich!
40617   * @property {boolean}  [options.accordionCloseOther=true]        - Immer nur ein Accordion geöffnet lassen
40618   * @property {boolean}  [options.accordionPanelHeight=false]      - Berechnet die Höhe des aufzuklappenden Elements (das aufzuklappenden Element darf nicht per CSS auf display non gesetzt sein)
40619   * @property {jQuery}  [options.accordionElementToOpen=null]      - Öffnet ein Element welches nicht in der eigentlich vorgegebenen Struktur ist
40620   * @property {boolean}  [options.autoplay=false]                  - Autoplay für Tab aktivieren
40621   * @property {string}   [options.playButtonImagePaused=null]      - Icon welches im stop Zustand angezeigt werden soll (nur wenn autoplay true)
40622   * @property {string}   [options.playButtonImagePlaying=null]     - Icon welches im play Zustand angezeigt werden soll (nur wenn autoplay true)
40623   * @property {string}   [options.playButtonAltTextPaused=null]    - Alttext welcher im stop Zustand angezeigt werden soll (nur wenn autoplay true)
40624   * @property {string}   [options.playButtonAltTextPlaying=null]   - Alttext welcher im play Zustand angezeigt werden soll (nur wenn autoplay true)
40625   * @property {string}  [options.accordionHeadingTitleClosed=null] - Title welcher angezeigt werden soll, wenn ein AccordionElement geschlossen ist
40626   * @property {string}  [options.accordionHeadingTitleOpened=null] - Title welcher angezeigt werden soll, wenn ein AccordionElement geöffnet ist
40627   * @property {int}      [options.autoSpeed=5000]                  - Nach welcher Zeit soll der Tab gewechselt werden? (nur wenn autoplay true)
40628   * @property {boolean}  [options.playOnLoad=false]                - Direkt nach laden der Seite autoplay starten (nur wenn autoplay true)
40629   * @property {boolean}  [options.pauseOnHover=true]               - Wenn hover ueber Bild oder Tab autoplay stoppen (nur wenn autoplay true)
40630   * @property {boolean}  [options.changeOnHover=false]             - Wenn hover ueber Bild oder Tab autoplay stoppen (nur wenn autoplay true)
40631   * @property {boolean}  [options.allOpen=false]                   - Alle Accordion-Elemente direkt geöffnet
40632   * @property {boolean}  [options.animateTab=false]                - Animation für den wechsel der Tabs
40633   */
40634  $.gsb.toggle.defaultOptions = {
40635    tab: true,
40636    tabControls: "> .tabs-list > li a",
40637    elements: '> .tabs-container > div',
40638    accordionControls: '> .tabs-container > .heading',
40639    accordion: true,
40640    richTextAccordion: false,
40641    accordionCloseOther: true,
40642    accordionPanelHeight: false,
40643    accordionElementToOpen: null,
40644    accordionElementsStopPropagation: '',
40645    autoplay: false,
40646    playButtonImagePaused: null,
40647    playButtonImagePlaying: null,
40648    playButtonAltTextPaused: typeof PLAY == 'undefined' ? 'Animation starten' : PLAY,
40649    playButtonAltTextPlaying: typeof PAUSE == 'undefined' ? 'Animation stoppen' : PAUSE,
40650    accordionHeadingTitleClosed: null,
40651    accordionHeadingTitleOpened: null,
40652    autoSpeed: '5000',
40653    playOnLoad: false,
40654    pauseOnHover: true,
40655    changeOnHover: false,
40656    allOpen: false,
40657    animateTab: false,
40658    respondToEvents: true,
40659    onRefresh: function onRefresh() {
40660      this.initialize();
40661      this.refreshTab();
40662    },
40663    responsive: [{
40664      breakpoint: 600,
40665      onRefresh: function onRefresh() {
40666        this.initialize();
40667        this.autoplayStop();
40668        this.$el.off("mouseenter mouseleave");
40669        this.refreshAccordion();
40670      },
40671      autoplay: false
40672    }]
40673  };
40674
40675  /**
40676   * @method initialize
40677   * @desc Initialisierung des Scripts
40678   */
40679  $.gsb.toggle.prototype.initialize = function () {
40680    var _ = this.base;
40681
40682    if (!_.$el.hasClass('gsb-toggle')) {
40683      _.$el.addClass('gsb-toggle');
40684      _.addClasses();
40685      _.addClickfunction();
40686    }
40687
40688    if (_.options.autoplay) {
40689      _.autoplay();
40690    }
40691  };
40692
40693  /**
40694   * @method addClasses
40695   * @desc Zugehörigkeit der Überschriften festlegen
40696   */
40697  $.gsb.toggle.prototype.addClasses = function () {
40698    var _ = this.base;
40699
40700    if (_.options.tab === true) {
40701
40702      //Angabe welcher Tab aktiv gesetzt werden soll
40703      var activeTabIndex = $.inArray(_.$el.find(_.options.tabControls + '.active-control').get(0), _.$el.find(_.options.tabControls));
40704      if (activeTabIndex == -1) {
40705        activeTabIndex = 0;
40706      }
40707
40708      _.$el.find(_.options.tabControls).each(function (index) {
40709        var tabControls = $(this);
40710        if (!tabControls.is('a') || tabControls.find('>a').length == 0) {
40711          tabControls.prop("tabindex", 0);
40712        }
40713
40714        tabControls.addClass('switch-panel' + index);
40715        if (index === activeTabIndex) {
40716          tabControls.addClass("active-control");
40717        } else {
40718          tabControls.addClass("inactive-control");
40719        }
40720      });
40721
40722      _.$el.find(_.options.elements).each(function (index) {
40723        var elements = $(this);
40724        elements.addClass('switch-panel' + index);
40725        if (index === activeTabIndex) {
40726          elements.addClass("panel-opened");
40727        } else {
40728          elements.addClass("panel-closed");
40729        }
40730      });
40731    }
40732
40733    if (_.options.accordion === true) {
40734      // Accorion hat bei start geöffnete Elemente
40735      var hasOpendElements = false;
40736      if (_.$el.find(_.options.tabControls + ".active-control").length > 0) {
40737        hasOpendElements = true;
40738      }
40739      _.$el.find(_.options.accordionControls).each(function () {
40740        var heading = $(this);
40741
40742        if (!heading.is('button') || !heading.is('a')) {
40743          if (_.options.accordionPanelHeight) {
40744            var height = 0;
40745            heading.next().find(">").each(function () {
40746              height += heading.outerHeight(true);
40747            });
40748            heading.next().height(height);
40749          }
40750          heading.prop("tabindex", 0);
40751          if (_.options.allOpen && !_.options.tab) {
40752            heading.addClass('active-control').attr('aria-expanded', 'true').attr('aria-selected', 'true').next().attr('aria-hidden', 'false').show();
40753          } else if (hasOpendElements) {
40754            if (!heading.hasClass("active-control")) {
40755              heading.attr('aria-expanded', 'false').attr('aria-selected', 'false').addClass("inactive-control").next().attr('aria-hidden', 'true').hide();
40756            } else {
40757              heading.attr('aria-expanded', 'true').attr('aria-selected', 'true').next().attr('aria-hidden', 'false').show();
40758            }
40759          } else {
40760            heading.attr('aria-expanded', 'false').attr('aria-selected', 'false').addClass("inactive-control").next().attr('aria-hidden', 'false').hide();
40761          }
40762        }
40763
40764        _.changeAccordionHeadingTitle(heading);
40765      });
40766    }
40767  };
40768
40769  /**
40770   * @method addClickfunction
40771   * @desc Click Events hinzufügen
40772   */
40773  $.gsb.toggle.prototype.addClickfunction = function () {
40774    var _ = this.base;
40775
40776    // Accordion
40777    if (_.options.accordion === true) {
40778      _.$el.on('click keydown', _.options.accordionControls, function (e) {
40779        if (e.type === 'click' || e.which == 13) {
40780          e.preventDefault();
40781          e.stopPropagation();
40782          _.clickedElem = $(this);
40783          _.changeStateAccordion();
40784        }
40785      }).find(_.options.accordionElementsStopPropagation).on('click keydown', function (e) {
40786        e.stopPropagation();
40787      });
40788    }
40789    if (_.options.tab === true) {
40790
40791      // Autoplay muss deaktiviert sein, da die Events focusin und focusout im Firefox derzeit nocht nicht implementiert
40792      // sind bzw. noch bugs enthalten
40793      if (_.options.changeOnHover && !_.options.autoplay) {
40794        _.$el.on('mouseenter focus touchend', _.options.tabControls, function (e) {
40795          e.preventDefault();
40796          e.stopPropagation();
40797          _.clickedElem = $(this);
40798          _.changeStateTab();
40799        });
40800
40801        // Seitenwechsel für click unterdrücken
40802        _.$el.on('click', _.options.tabControls, function (e) {
40803          e.preventDefault();
40804          e.stopPropagation();
40805        });
40806      } else {
40807        _.$el.on('click keydown', _.options.tabControls, function (e) {
40808          if (e.type === 'click' || e.which == 13) {
40809            e.preventDefault();
40810            e.stopPropagation();
40811            _.clickedElem = $(this);
40812            _.changeStateTab();
40813          }
40814        });
40815      }
40816    }
40817  };
40818
40819  /**
40820   * @method changeStateAccordion
40821   * @param {Object} elem - Geklicktes Element
40822   * @desc Passt den title des headingElements je Status an (geöffnet/geschlossen)
40823   */
40824  $.gsb.toggle.prototype.changeAccordionHeadingTitle = function (elem) {
40825    var _ = this.base;
40826
40827    if (elem.hasClass('active-control') && _.options.accordionHeadingTitleOpened) {
40828      elem.attr('title', _.options.accordionHeadingTitleOpened);
40829    } else if (!elem.hasClass('active-control') && _.options.accordionHeadingTitleClosed) {
40830      elem.attr('title', _.options.accordionHeadingTitleClosed);
40831    }
40832  };
40833
40834  /**
40835   * @method changeStateAccordion
40836   * @desc Open-/Close-States Accordion
40837   */
40838  $.gsb.toggle.prototype.changeStateAccordion = function () {
40839    var _ = this.base;
40840
40841    var contentElement;
40842    if (_.options.accordionElementToOpen) {
40843      contentElement = $(_.options.accordionElementToOpen);
40844    } else {
40845      contentElement = _.clickedElem.next();
40846    }
40847
40848    if (_.clickedElem.hasClass('inactive-control')) {
40849      if (_.options.accordionCloseOther && !_.options.accordionElementToOpen) {
40850        _.animationAccordion(_.clickedElem.parent().find('> .active-control').next(), "close");
40851        _.$el.find('.tabs-container > .active-control').removeClass('active-control').addClass('inactive-control');
40852      }
40853
40854      _.clickedElem.attr('aria-expanded', 'true').attr('aria-selected', 'true').removeClass('inactive-control').addClass('active-control');
40855
40856      _.animationAccordion(contentElement, "open");
40857      contentElement.attr('aria-hidden', 'false');
40858    } else {
40859      _.clickedElem.attr('aria-expanded', 'false').attr('aria-selected', 'false').removeClass('active-control').addClass('inactive-control');
40860
40861      _.animationAccordion(contentElement, "close");
40862      contentElement.attr('aria-hidden', 'true');
40863    }
40864
40865    _.changeAccordionHeadingTitle(_.clickedElem);
40866  };
40867
40868  /**
40869   * @method changeStateTab
40870   * @desc Open-/Close-States Tab
40871   */
40872  $.gsb.toggle.prototype.changeStateTab = function () {
40873    var _ = this.base;
40874
40875    if (_.clickedElem.hasClass('inactive-control')) {
40876      var panelToClose = _.$el.find('.panel-opened');
40877
40878      // "Alles auf 0 zurücksetzen"
40879      _.$el.find('[aria-hidden=false]').attr('aria-hidden', 'true');
40880      _.$el.find('[aria-selected=true]').attr('aria-selected', 'false');
40881
40882      var ariaControl = _.clickedElem.attr('aria-controls');
40883      _.$el.find('#' + ariaControl).attr('aria-hidden', 'false');
40884      _.clickedElem.attr('aria-selected', 'true');
40885      panelToClose.removeClass('panel-opened').addClass('panel-closed');
40886      _.$el.find('> .tabs-container >.active-control,' + _.options.tabControls + '.active-control ').removeClass('active-control').addClass('inactive-control');
40887      _.clickedElem.removeClass('inactive-control');
40888      var panelToOpen = _.$el.find('> .tabs-container > .' + _.getSwitchPanelClass(_.clickedElem));
40889      panelToOpen.removeClass('panel-closed').addClass('panel-opened');
40890      _.clickedElem.addClass('active-control');
40891      _.animationTab(panelToClose, panelToOpen);
40892      _.addA11y(panelToOpen);
40893    }
40894  };
40895
40896  /**
40897   * @method animationAccordion
40898   * @desc Animation für OpenClose des Accordions
40899   *
40900   * @param elem {Object} Element welches animiert werden soll
40901   * @param type Art der Animation - {string} open / close
40902   */
40903  $.gsb.toggle.prototype.animationAccordion = function (elem, type) {
40904    var _ = this.base;
40905
40906    if (type === 'open') {
40907      elem.slideDown(400, function () {
40908        if (_.options.accordionElementToOpen) {
40909          _.addA11y(elem);
40910        }
40911      });
40912    } else {
40913      elem.slideUp();
40914    }
40915  };
40916
40917  /**
40918   * @method animationTab
40919   * @desc Animation für OpenClose des Tabs
40920   *
40921   * @param panelToClose {Object} Element welches animiert werden soll (ausblenden)
40922   * @param panelToOpen {Object} Element welches animiert werden soll (einblenden)
40923   */
40924  $.gsb.toggle.prototype.animationTab = function (panelToClose, panelToOpen) {
40925    var _ = this.base;
40926
40927    if (_.options.animateTab) {
40928      panelToClose.fadeOut("slow", function () {
40929        panelToOpen.fadeIn("slow");
40930      });
40931    } else {
40932      panelToClose.hide();
40933      panelToOpen.show();
40934    }
40935  };
40936
40937  /**
40938   * @method autoplay
40939   * @desc Autoplay
40940   */
40941  $.gsb.toggle.prototype.autoplay = function () {
40942    var _ = this.base;
40943
40944    if (_.$el.find('> button').length === 0) {
40945      var button = document.createElement('button');
40946      button.className = 'paused';
40947      var image = document.createElement('img');
40948      image.src = _.options.playButtonImagePlaying;
40949      image.alt = _.options.playButtonAltTextPlaying;
40950      playbutton = _.$el.append($(button).append(image));
40951    }
40952    _.playbutton = _.$el.find('button.paused');
40953    _.playbutton.on('click autoplayStart', function (e) {
40954      e.preventDefault();
40955      e.stopPropagation();
40956      if (_.playbutton.hasClass('paused')) {
40957        $(this).removeClass('paused').addClass('played');
40958        _.autoplayStart();
40959        _.changeStatePlayPause(_.options.playButtonImagePlaying, _.options.playButtonAltTextPlaying);
40960        _.isPaused = false;
40961        if (e.type != "autoplayStart") {
40962          //Damit nach Starten des Autoplays nicht nochmal autoplayStart von mouseleave aufgerufen wir
40963          _.isClicked = true;
40964        }
40965      } else {
40966        $(this).addClass('paused').removeClass('played');
40967        _.autoplayStop();
40968        _.changeStatePlayPause(_.options.playButtonImagePaused, _.options.playButtonAltTextPaused);
40969        _.isPaused = true;
40970      }
40971    });
40972
40973    // Stop bei Hover
40974    if (_.options.pauseOnHover) {
40975      _.$el.on("mouseenter mouseleave", function (e) {
40976        if (!_.isPaused) {
40977          if (e.type == 'mouseenter') {
40978            _.autoplayStop();
40979          } else {
40980            if (_.playbutton.hasClass('played') && !_.isClicked) {
40981              _.autoplayStart();
40982            }
40983            _.isClicked = false;
40984          }
40985        }
40986      });
40987    }
40988
40989    //play bei start
40990    if (_.options.playOnLoad) {
40991      _.playbutton.trigger("autoplayStart");
40992    }
40993  };
40994
40995  /**
40996   * @method autoplayStart
40997   * @desc Autoplay start
40998   */
40999  $.gsb.toggle.prototype.autoplayStart = function () {
41000    var _ = this.base;
41001
41002    _.rotation = setInterval(function () {
41003      var lastTab = _.getSwitchPanelClass(_.$el.find('.tabs-list > li').last());
41004      //Wenn letzter Tab, wieder beim ersten anfangen
41005      if (_.$el.find('.tabs-list .active-control').hasClass(lastTab[0])) {
41006        _.$el.find('.tabs-list > li').first().click();
41007      } else {
41008        _.$el.find('.tabs-list .active-control').next().click();
41009      }
41010    }, _.options.autoSpeed);
41011  };
41012
41013  /**
41014   * @method autoplayStop
41015   * @desc Autoplay stop
41016   */
41017  $.gsb.toggle.prototype.autoplayStop = function () {
41018    var _ = this.base;
41019
41020    clearInterval(_.rotation);
41021  };
41022
41023  /**
41024   * @method refreshTab
41025   * @desc Refresh Tab
41026   */
41027  $.gsb.toggle.prototype.refreshTab = function () {
41028    var _ = this.base;
41029
41030    if (_.options.tab) {
41031      _.$el.find('.tabs-container').removeAttr('multiselectable');
41032      _.$el.find('.tabs-container').removeAttr('role');
41033      _.$el.find('.heading').each(function () {
41034        $(this).removeAttr('aria-expanded');
41035      });
41036
41037      // Autoplay muss deaktiviert sein, da die Events focusin und focusout im Firefox derzeit nocht nicht implementiert
41038      // sind bzw. noch bugs enthalten
41039      if (_.options.changeOnHover && !_.options.autoplay) {
41040        _.$el.on('mouseenter focus', _.options.tabControls, function (e) {
41041          _.clickedElem = $(this);
41042          _.changeStateTab();
41043        });
41044      }
41045
41046      _.$el.find('.panel-closed').hide();
41047      _.$el.find('.panel-opened').show();
41048    }
41049  };
41050
41051  /**
41052   * @method refreshAccordion
41053   * @desc  Refresh Accordion
41054   */
41055  $.gsb.toggle.prototype.refreshAccordion = function () {
41056    var _ = this.base;
41057
41058    if (_.options.accordion) {
41059      _.$el.find('.tabs-container').attr('role', 'tablist');
41060      if (!_.options.accordionCloseOther) {
41061        _.$el.find('.tabs-container').attr('multiselectable', 'true');
41062      }
41063      _.$el.find('.heading').each(function () {
41064        $(this).attr('aria-expanded', 'false');
41065        $(this).hasClass('inactive-control') ? $(this).next().hide() : "";
41066      });
41067    }
41068  };
41069
41070  /**
41071   * @method changeStatePlayPause
41072   * @param {string} imgsrc - Imagesource-Link
41073   * @param {string} alt - Alt-Text des Images
41074   * @desc Bild tauschen für Play/Pausebutton
41075   */
41076  $.gsb.toggle.prototype.changeStatePlayPause = function (imgsrc, imgalt) {
41077    var _ = this.base;
41078
41079    var image = _.playbutton.find('img');
41080    image.prop("alt", imgalt).prop("src", imgsrc);
41081  };
41082
41083  /**
41084   * @method getSwitchPanelClass
41085   * @param {Object} elem - geklicktes Element (durchgereicht von changeState oder autoplayStart)
41086   * @desc Liefert die switch-panel Klasse des geklickten Elements
41087   */
41088  $.gsb.toggle.prototype.getSwitchPanelClass = function (elem) {
41089    var panelClass = $.grep(elem.prop('class').split(" "), function (value) {
41090      return value.indexOf('switch-panel') > -1;
41091    });
41092    return panelClass;
41093  };
41094
41095  /**
41096   * @method uninitAccordion
41097   * @desc Destroy Accordion
41098   */
41099  $.gsb.toggle.prototype.uninitAccordion = function () {
41100    var _ = this.base;
41101
41102    if (_.$el.hasClass('gsb-toggle')) {
41103      _.$el.off();
41104      _.$el.removeClass('gsb-toggle');
41105      _.$el.find('> .tabs-container > .heading').removeClass('active-control inactive-control').removeAttr("tabindex").next().removeAttr("style");
41106    }
41107  };
41108
41109  /**
41110   * @method addA11y
41111   * @desc  setzt den focus auf das erste fokussierbare Element
41112   * @param elem {jQuery} Element welches nach fokussierbaren Elementen durchsucht wird. Ist mindestens ein Element vorhanden,
41113   * wird der Fokus gesetzt
41114   * @param tabPanel {jQuery} Element auf welches gesprungen werden soll, wenn im TabContainer keiner fokussierbaren Element vorhanden sind
41115   */
41116  $.gsb.toggle.prototype.addA11y = function (elem, tabPanel) {
41117    var _ = this.base;
41118
41119    elem = elem || _.$el;
41120    var focusElements = elem.find('input,textarea,select,a,button').not(':hidden');
41121    if (focusElements.length) {
41122      focusElements[0].focus();
41123      focusElements.last().keydown(function (e) {});
41124    }
41125  };
41126
41127  /**
41128   * @method addRichtextContainer
41129   * @desc Sucht im z.B. Content nach Elementen mit den Klasse startaccordion, endaccordion und accordionheadline und
41130   * baut die für gsb_toggle benötigte Struktur um diese Elemente
41131   *
41132   * Wenn alle benötigten Elemente eingebaut wurden, ruft sich das Script auf '.richtext-accordion' mit der Option
41133   * richTextAccordion nochmal selbst auf
41134   */
41135  $.gsb.toggle.prototype.addRichtextContainer = function () {
41136    var _ = this.base;
41137
41138    _.$el.find('.startaccordion').each(function () {
41139      $(this).nextUntil('.endaccordion').addBack().add($(this).find('~.endaccordion').first()).wrapAll('<div class="tabs-container"/>');
41140      var wrapper = $(this).parent();
41141
41142      wrapper.find('.startaccordion, .accordionheadline').addClass('heading');
41143      wrapper.find('.heading').each(function () {
41144        $(this).nextUntil('.heading').wrapAll('<div/>');
41145      });
41146      wrapper.find('.heading').last().nextUntil('.accordionend').add(wrapper.find('.accordionend')).wrapAll('<div/>');
41147      wrapper.wrap('<div class="richtext-accordion"/>');
41148    });
41149
41150    _.$el.removeData('gsb.toggle');
41151    _.$el.find('.richtext-accordion').gsb_toggle($.extend({}, _.options, { richTextAccordion: false }));
41152  };
41153
41154  $.fn.gsb_toggle = function (options) {
41155    return this.each(function () {
41156      new $.gsb.toggle(this, options);
41157    });
41158  };
41159})(jQuery);
41160   /* Ende gsb_toggle */
41161   /* Start gsb_togglebar */
41162   /*!
41163 * GSB-Plugin zum Erstellung von Menue-Leiste fuer mobile Navigation
41164 *
41165 * Author: sbaecker
41166 *
41167 * @requires jQuery >= 1.11.1, gsb_responsiveListener
41168 */
41169
41170;
41171(function ($) {
41172  if (!$.gsb) {
41173    $.gsb = {};
41174  }
41175  ;
41176  $.gsb.togglebar = function (el, options) {
41177    // To avoid scope issues, use 'base' instead of 'this'
41178    // to reference this class from internal events and functions.
41179    var base = this;
41180    // Access to $ and DOM versions of element
41181    base.$el = $(el);
41182    base.el = el;
41183    // Add a reverse reference to the DOM object
41184    base.$el.data("gsb.togglebar", base);
41185
41186    base.init = function () {
41187      base.options = $.extend({}, $.gsb.togglebar.defaultOptions, options);
41188      base.$el.gsb_responsiveListener(base);
41189    };
41190    base.generate = function () {
41191      //Initialization Code
41192      if ($('#navServiceGS').length > 0 && $('#navServiceLS').length > 0) {
41193
41194        var gs_link = $('#navServiceGS');
41195        gs_link.find('a').attr("title", $('#navServiceGS a').text());
41196        var gs = '<li class="navServiceGS">' + gs_link.html() + '</li>';
41197
41198        var ls_link = $('#navServiceLS');
41199        ls_link.find('a').attr("title", $('#navServiceLS a').text());
41200        var ls = '<li class="navServiceLS">' + ls_link.html() + '</li>';
41201      } else {
41202
41203        var gs = "";
41204        var ls = "";
41205      }
41206      if ($('#togglenav').length == 0) {
41207        base.$el.prepend('<div id="togglenav">' + '<ul class="left">' + '<li id="navMobileMenu">' + '<a href="#">Menü</a>' + '</li>' + '<li id="navMobileSearch">' + '<a href="#">Suche</a>' + '</li>' + '</ul>' + '<ul class="right">' + gs + ls + '</ul></div>');
41208      }
41209    };
41210
41211    //Funktion falls das Skript zur Laufzeit deaktiviert werden muss
41212    base._uninit = function () {
41213      $('#togglenav').remove();
41214    };
41215
41216    // Run initializer
41217    base.init();
41218  };
41219  $.gsb.togglebar.defaultOptions = {
41220    respondToEvents: true,
41221    onRefresh: function onRefresh() {
41222      this._uninit();
41223    },
41224    responsive: [{
41225      breakpoint: 1024,
41226      onRefresh: function onRefresh() {
41227        this.generate();
41228      }
41229    }]
41230  };
41231  $.fn.gsb_togglebar = function (options) {
41232    return this.each(function () {
41233      new $.gsb.togglebar(this, options);
41234    });
41235  };
41236})(jQuery);
41237   /* Ende gsb_togglebar */
41238   /* Start gsb_navigation_mobile */
41239   /**
41240 * @module navigation_mobile --- Mandantenanpassung
41241 * @version 2.1.1
41242 * @see {@link http://semver.org|Semantic Versioning}
41243 * @author pespeloe
41244 *
41245 * @desc Dieses Modul fügt
41246 * 1. Wenn konfiguerte, eine "togglebar" mit den Menübutton zum Öffnen des MMenu hinzu (base.$el.prepend)
41247 * 2. Die Grundkonfiguration des MMenu hinzu - nur Angabe der Optionen templateNavBar und menuHtml = MMenu aus SL OHNE autosuggest
41248 * 3. WAI-ARIA Support hinzu
41249 * 4. Tastaturbedienbarkeit des MMenu, bei geöffnetem Menu hinzu
41250 * 5. Den Responsive Listener hinzu
41251 *
41252 * @requires  {@link external:jQuery}
41253 * @requires  gsb_responsiveListener
41254 * @requires  gsb_ariaSupport
41255 *
41256 *
41257 * @example
41258 * JS: init (Einfachster Aufruf)
41259 * $('#wrapperDivisions').gsb_navigation_mobile({
41260 *   menuHtml: json_url_...
41261 * });
41262 * */
41263;
41264(function ($) {
41265  if (!$.gsb) {
41266    $.gsb = {};
41267  }
41268  ;
41269
41270  $.gsb.navigation_mobile = function (el, options) {
41271    // To avoid scope issues, use 'base' instead of 'this'
41272    // to reference this class from internal events and functions.
41273    var base = this;
41274
41275    // Access to jQuery and DOM versions of element
41276    base.$el = $(el);
41277    base.el = el;
41278
41279    base.utils = new NavigationUtils();
41280
41281    // Add a reverse reference to the DOM object
41282    base.$el.data("gsb.navigation_mobile", base);
41283
41284    base.init = function () {
41285      base.options = $.extend({}, $.gsb.navigation_mobile.defaultOptions, options);
41286      $('body').gsb_responsiveListener(base);
41287    };
41288
41289    /**
41290     * @method initMenu
41291     * @desc Initialisierung des Menüs
41292     */
41293    $.gsb.navigation_mobile.prototype.initMenu = function () {
41294
41295      base.overlay = base.utils.getOverlay();
41296      base.searchUtil = base.utils.getSearch();
41297
41298      if (!base.overlay) {
41299        base.utils.setOverlay($('<div id="navigation-overlay"/>'));
41300        base.utils.getOverlay().insertAfter($(base.options.overlayPosition));
41301        base.overlay = base.utils.getOverlay();
41302      } else {
41303        base.overlay.detach().insertAfter($(base.options.overlayPosition));
41304      }
41305
41306      if (!base.searchUtil) {
41307        base.utils.setSearch($('#search'));
41308        base.searchUtil = base.utils.getSearch();
41309      }
41310
41311      if (typeof base.options.beforeInit === 'function') {
41312        base.options.beforeInit.call($(this), base);
41313      }
41314
41315      base.createMenuContainer();
41316
41317      if (base.options.menuHtml != null) {
41318        $.ajax({
41319          url: base.options.menuHtml,
41320          dataType: 'html',
41321          success: function success(data) {
41322
41323            base.menu = $('#menu');
41324            base.menu.html(data);
41325
41326            var activeNode = base.menu.find('#mm-' + $('body').data('nn') + ' a').first();
41327            $('<strong>' + activeNode.text() + '</strong>').addClass(activeNode.prop('class')).insertAfter(activeNode);
41328            activeNode.remove();
41329
41330            base.nav = base.menu.find('.nav');
41331            base.search = base.menu.find('.searchfieldWrapper');
41332
41333            base.search.append(base.searchUtil);
41334
41335            base.menu.find('.level-2').each(function () {
41336              var level2 = $(this);
41337
41338              if (level2.find('>.back').length == 0) {
41339                var backLink = $('<li class="back"/>');
41340                level2.prepend(backLink);
41341                var link = $('<button/>');
41342                var image = $('<img src="' + base.options.backButtonImage + '" alt="' + base.options.backButtonAlt + '"/>');
41343                link.append(image);
41344                link.append('<span>' + base.options.firstBackButtonText + '</span>');
41345                backLink.append(link);
41346              }
41347            });
41348
41349            base.menu.find('.level-1').addClass('active');
41350            base.menu.find('.forward').parent().parent().siblings('ul').addClass('inactive');
41351
41352            base.utils.scrollingElements(base.menu, base);
41353            base.utils.addScollingLinks(base.menu, base, 'mobile');
41354
41355            base.mainNavWrapper = base.menu.find('.mainNavWrapper');
41356            base.mainNavWrapper.css({ height: base.menu.find('.level-1').outerHeight() });
41357
41358            base.nav.addClass('closed');
41359            base.search.addClass('closed');
41360
41361            base.menu.on('click', '.forward', function (e) {
41362              e.preventDefault();
41363              e.stopPropagation();
41364
41365              var siblingUl = $(this).parent().parent().siblings('ul');
41366              base.mainNavWrapper.css({ height: siblingUl.outerHeight() });
41367              siblingUl.removeClass('inactive').addClass('active');
41368            });
41369
41370            base.menu.on('click', '.back button', function (e) {
41371              e.preventDefault();
41372              e.stopPropagation();
41373
41374              $(this).closest('.active').removeClass('active').addClass('inactive');
41375              base.mainNavWrapper.css({ height: $(this).closest('.active').outerHeight() });
41376            });
41377
41378            base.menu.on('click', '.backToFirst button', function (e) {
41379              e.preventDefault();
41380              e.stopPropagation();
41381
41382              base.setTransition($(this).parentsUntil('.level-2').filter('ul'), 'inactive');
41383            });
41384
41385            //Menü öffnen Button
41386            base.$el.on('click', base.options.navOpenButton, function (e) {
41387              e.stopImmediatePropagation();
41388              e.preventDefault();
41389              if (base.nav.hasClass('opened')) {
41390                base.changeStatus($(this), base.nav, 'close', true);
41391              } else {
41392                if (base.isOpened(base.search)) {
41393                  base.$el.find(base.options.navSearchButton).trigger('click');
41394                }
41395                base.changeStatus($(this), base.nav, 'open', true);
41396                base.setActive(base.menu);
41397              }
41398            });
41399
41400            //Lupe der Togglebar
41401            base.$el.on('click', base.options.navSearchButton, function (e) {
41402              e.stopImmediatePropagation();
41403              e.preventDefault();
41404
41405              if (base.search.hasClass('opened')) {
41406                base.changeStatus($(this), base.search, 'close');
41407              } else {
41408                if (base.isOpened(base.nav)) {
41409                  base.$el.find(base.options.navOpenButton).trigger('click');
41410                }
41411                base.changeStatus($(this), base.search, 'open');
41412
41413                //Autosuggest initialisieren
41414                if (base.options.autosuggestURL) {
41415                  base.search.gsb_AutoSuggest(base.options.autosuggestURL);
41416                }
41417              }
41418            });
41419
41420            if (typeof base.options.afterInit === 'function') {
41421              base.options.afterInit.call($(this), base);
41422            }
41423          }
41424        });
41425      }
41426    };
41427
41428    // Wird nur zum öffnen oder schließen mehrerer Ebenen verwendet
41429    $.gsb.navigation_mobile.prototype.setTransition = function (elementList, state) {
41430      elementList.get().reverse().forEach(function (el) {
41431        var element = $(el);
41432        if (state == 'active') {
41433          element.addClass('active').removeClass('inactive');
41434        } else {
41435          element.addClass('inactive').removeClass('active');
41436        }
41437      });
41438
41439      if (state == 'active') {
41440        base.mainNavWrapper.css({ height: elementList.first().outerHeight() });
41441      } else {
41442        base.mainNavWrapper.css({ height: elementList.last().closest('.active').outerHeight() });
41443      }
41444    };
41445
41446    $.gsb.navigation_mobile.prototype.setActive = function (menuBox) {
41447      var $body = $('body');
41448      if ($body.data('nn') && menuBox.find('.scrollingLevel ul #mm-' + $body.data('nn')).length > 0) {
41449        base.setTransition(menuBox.find('#mm-' + $body.data('nn')).parentsUntil('.level-1').filter('ul'), 'active');
41450      }
41451    };
41452
41453    /**
41454     * @method isOpened
41455     * @desc Überprüfung ob Element geöffnet ist oder nicht
41456     */
41457    $.gsb.navigation_mobile.prototype.isOpened = function (elem) {
41458      if (elem.hasClass('opened')) {
41459        return true;
41460      } else {
41461        return false;
41462      }
41463    };
41464
41465    /**
41466     * @method changeStatus
41467     * @desc ändert den Status des Element - öffnen oder schließen
41468     * @param button {Object} geklickter button
41469     * @param elem {Object} Element ein oder ausgeblendet werden soll
41470     * @param type {String} Erlaubte Werte: open | close - wird geöffnet oder geschlossen?
41471     * @param setTogglebarClass {boolean} Angabe ob Klasse active an toggleBar hinzugefuegt werden soll
41472     */
41473    $.gsb.navigation_mobile.prototype.changeStatus = function (button, elem, type, setTogglebarClass) {
41474
41475      setTogglebarClass = setTogglebarClass || false;
41476
41477      if (type == 'open') {
41478        base.overlay.addClass('active');
41479        button.removeClass('closed').addClass('opened');
41480        elem.removeClass('closed').addClass('opened');
41481        $('body').addClass('fixed');
41482        if (setTogglebarClass) {
41483          base.$el.find('.togglebar').addClass('active');
41484        }
41485      } else {
41486        base.overlay.removeClass('active');
41487        button.removeClass('opened').addClass('closed');
41488        elem.removeClass('opened').addClass('closed');
41489        $('body').removeClass('fixed');
41490        if (setTogglebarClass) {
41491          base.$el.find('.togglebar').removeClass('active');
41492        }
41493      }
41494    };
41495
41496    /**
41497     * @method createMenuContainer
41498     * @desc MMenücontainer erstellen, falls nicht vorhanden
41499     */
41500    $.gsb.navigation_mobile.prototype.createMenuContainer = function () {
41501      if (!$('#menu').length) {
41502        $('<div id="menu"/>').insertAfter('#header');
41503      }
41504    };
41505
41506    /**
41507     * @method uninit
41508     * @desc Destroy Menu
41509     */
41510    $.gsb.navigation_mobile.prototype.uninit = function () {
41511      if (base.menu) {
41512        base.menu.remove();
41513      }
41514    };
41515
41516    /**
41517     * @method addA11y
41518     * @desc MMenu tastaturbedienbar machen bzw. Fokus auf erste fokussierbares Element setzen
41519     */
41520
41521    $.gsb.navigation_mobile.prototype.addA11y = function (elem) {
41522      elem = elem || base.$el;
41523      var focusElements = elem.find('button,a,input,textarea,select');
41524      focusElements[0].focus();
41525      focusElements.last().keydown(function (e) {
41526        if (e.keyCode === 9) {
41527          e.preventDefault();
41528          focusElements[0].focus();
41529        } else if (e.keyCode === 13) {
41530          return true;
41531        }
41532      });
41533    };
41534
41535    // Run initializer
41536    base.init();
41537  };
41538
41539  /**
41540   * @typedef defaultOptions
41541   * @type {object}
41542   * @property {object}   options                                   - Default Options des Scripts
41543   * @property {String}   [options.menuHtml]                        - Pfad zum HTML des Mobilen Menüs
41544   * @property {String]   [options.navOpenButton]                   - Selektor Menübutton in der Navigationsbar
41545   * @property {String]   [options.navSearchButton]                 - Selektor Suche Button in der Navigationsbar
41546   * @property {function] [options.beforeInit]                      - Funktionen die vor dem eigentlichen Script ausgeführt werden sollen
41547   * @property {function] [options.afterInit]                       - Funktionen die nach dem eigentlichen Script ausgeführt werden sollen
41548   * @property {boolean]  [options.respondToEvents]                 - Responsive Listener "Default" ausführen wenn keine Breakpoint Angabe zutrifft
41549   * @property {function] [options.onRefresh]                       - Responsive  "Default"
41550   * @property {Array]    [options.responsive]                      - Angaben zu den verschiedenen Breakp
41550oints - hier können auch Funktionen des Scripts ausgeführt werden,
41551    *                                                                 da base übergeben wird
41552   */
41553
41554  $.gsb.navigation_mobile.defaultOptions = {
41555    menuHtml: 'modules/navigation_mobile/navigation_mobile.html',
41556    navOpenButton: '#navMobileMenu ',
41557    navSearchButton: '#navMobileSearch',
41558    scrollLayer: '.scrollingLevel',
41559    firstBackButtonText: FIRST_BACK,
41560    backButtonImage: image_url_mobile_back_button,
41561    backButtonAlt: BACK_BUTTON,
41562    backToFirstImage: image_url_mobile_backtofirst_button,
41563    backToFirstAlt: BACKTOFIRST_BUTTON,
41564    beforeInit: null,
41565    afterInit: null,
41566    overlayPosition: '#header',
41567    autosuggestURL: '../html/modules/autosuggest/json/autosuggest.json',
41568    respondToEvents: true,
41569    onRefresh: function onRefresh() {
41570      this.uninit();
41571    },
41572    responsive: [{
41573      breakpoint: 1025,
41574      onRefresh: function onRefresh() {
41575        this.uninit();
41576        this.initMenu();
41577      }
41578    }]
41579  };
41580
41581  $.fn.gsb_navigation_mobile = function (options) {
41582    return this.each(function () {
41583      new $.gsb.navigation_mobile(this, options);
41584    });
41585  };
41586})(jQuery);
41587   /* Ende gsb_navigation_mobile */
41588   /* Start gsb_responsivetables */
41589   /*!
41590 * GSB-Plugin zum wrappen von Tabellen fuer die mobile Darstellung
41591 *
41592 * Author: sbaecker
41593 */
41594
41595;(function ($) {
41596  if (!$.gsb) {
41597    $.gsb = {};
41598  }
41599  $.gsb.responsiveTables = function (el, options) {
41600    // To avoid scope issues, use 'base' instead of 'this'
41601    // to reference this class from internal events and functions.
41602    var base = this;
41603    // Access to $ and DOM versions of element
41604    base.$el = $(el);
41605    base.el = el;
41606    // Add a reverse reference to the DOM object
41607    base.$el.data("gsb.responsiveTables", base);
41608    base.init = function () {
41609      base.options = $.extend({}, $.gsb.responsiveTables.defaultOptions, options);
41610
41611      //Initialization Code
41612      if (base.$el.find('table').length > 0) {
41613        base.$el.find('table').each(function () {
41614          switch (base.options.way) {
41615            case 'scroll':
41616              $(this).wrap('<div class="responsiveTable"></div>');
41617              break;
41618            default:
41619              $(this).wrap('<div class="responsiveTable"></div>');
41620              break;
41621          }
41622        });
41623      }
41624    };
41625
41626    // Run initializer
41627    base.init();
41628  };
41629  $.gsb.responsiveTables.defaultOptions = {
41630    way: 'scroll'
41631  };
41632
41633  $.fn.gsb_responsiveTables = function (options) {
41634    return this.each(function () {
41635      new $.gsb.responsiveTables(this, options);
41636    });
41637  };
41638})(jQuery);
41639   /* Ende gsb_responsivetables */
41640   /* Start gsb_tooltip */
41641   /*!
41642 * GSB-Wrapper-Plugin fuer Foundation Tooltip-Plugin. Arbeitet als Polyfill, um von Foundation benoetigte
41643 * data-Attribute und Klassen hinzuzufuegen.
41644 *
41645 * s. auch http://foundation.zurb.com/docs/components/tooltips.html
41646 *
41647 * Optionen:
41648 * tooltipPosition: Die Position des Tooltips(top,bottom(default),left,right)
41649 * tooltipCorners: Layoutmodus des Tooltip(''(default), 'radius', 'round')
41650 * tooltipFoundationOptions: native Optionen fuer das Foundation Plugin(undefined(default), siehe Doku oben)
41651 *
41652 * Abhängigkeiten:
41653 *
41654 * - modernizr(wegen Foundation)
41655 * - foundation
41656 * - foundation-tooltip
41657 *
41658 * Author: anuebel
41659 */
41660
41661;(function ($) {
41662    'use strict';
41663
41664    if (!$.gsb) {
41665        $.gsb = {};
41666    }
41667
41668    $.gsb.tooltip = function (el, options) {
41669        var base = this;
41670        base.$el = $(el);
41671        base.el = el;
41672        base.$el.data("gsb.tooltip", base);
41673
41674        base.init = function () {
41675            base.options = $.extend({}, $.gsb.tooltip.defaultOptions, options);
41676            base.$el.addClass('has-tip tip-' + base.options.tooltipPosition + ' ' + base.options.tooltipCorners).attr('data-tooltip', '').attr('aria-haspopup', 'true');
41677            // native Optionen des Foundation Plugins durchreichen
41678            if (base.options.tooltipFoundationOptions) {
41679                var serializedFoundationOptions = JSON.stringify(base.options.tooltipFoundationOptions);
41680                base.$el.attr('data-options', serializedFoundationOptions);
41681            }
41682        };
41683        base.init();
41684    };
41685
41686    $.gsb.tooltip.defaultOptions = {
41687        tooltipPosition: 'bottom',
41688        tooltipCorners: '',
41689        tooltipFoundationOptions: undefined
41690    };
41691
41692    $.fn.gsb_tooltip = function (options) {
41693        return this.each(function () {
41694            new $.gsb.tooltip(this, options);
41695        });
41696    };
41697})(jQuery);
41698   /* Ende gsb_tooltip */
41699   /* Start gsb_twoclickshare */
41700   /*!
41701 * GSB-Wrapper-Plugin fuer Heise-2-Klickloesung
41702 *
41703 * s. auch http://www.heise.de/extras/socialshareprivacy/
41704 *
41705 * Author: rkrusenb
41706 */
41707(function($){
41708  if(!$ .gsb){
41709    $ .gsb = {};
41710  }
41711  $ .gsb.twoclickshare = function(el, userOptions){
41712    var state = {},
41713      options,
41714      wrapper,
41715      toggleElement,
41716      wrapperOuter;
41717    function init(){
41718      options = state.options = $ .extend(true, {}, $ .gsb.twoclickshare.defaultOptions, userOptions);
41719      //wrapperOuter = $('<' + options.wrapperTag + ' />').attr('id', options.wrapperId);
41720      //wrapper = state.wrapper = $('<div/>').addClass(options.wrapperInnerClass);
41721      //wrapperOuter.append(wrapper);
41722      wrapper = $('<' + options.wrapperTag + ' />').attr('id', options.wrapperId);
41723      wrapperInner = state.wrapper = $('<div/>').addClass(options.wrapperInnerClass);
41724      wrapper.append(wrapperInner);
41725      if(options.insert == 'prepend'){
41726        $(el).prepend(wrapper);
41727      } else if(options.insert == 'append'){
41728        $(el).append(wrapper);
41729      } else if(options.insert == 'before'){
41730        $(el).before(wrapper);
41731      } else if(options.insert == 'after'){
41732        $(el).after(wrapper);
41733      }
41734      wrapperInner.socialSharePrivacy(options.socialSharePrivacyOptions)
41735        .prepend('<h3>' + options.labelHeader + '</h3>')
41736        .find('.switch, .settings').attr('tabindex', 0).keydown(function(ev){
41737          if(ev.which == 13) {
41738            $(this).trigger('click');
41739          }
41740        });
41741      if(options.toggleElement) {
41742        toggleElement = $(options.toggleElement, el);
41743        wrapper.find('li:first').before($('<li class="email"><a>' + options.labelFormLink + '</a></li>').find('a').attr('href', toggleElement.attr('href')).end());
41744        wrapper.data('gsb.twoclickshare', {oldHeight: wrapper.height()}).css({top: 0, display: 'none'}).attr('aria-hidden', 'true');
41745        toggleElement.attr('aria-haspopup', true).attr('aria-owns', options.wrapperId).attr('title', options.toggleTitleClosed).click(function(ev){
41746          var oldHeight = wrapper.data('gsb.twoclickshare').oldHeight;
41747          ev.preventDefault();
41748          ev.stopPropagation();
41749          if(wrapper.is('[aria-hidden=true]')) {
41750            /* CSS sorgt dafür, dass es "hoch" slidet */
41751            wrapper.attr('aria-hidden', 'false').css({height: 0, display: 'block'}).animate({top: -oldHeight-2, height: oldHeight}, 'slow').promise().done(function(){$(this).css('height', '').css({top: -$(this).height()-2})});
41752            wrapper.find('.close').focus();
41753            toggleElement.attr("title",options.toggleTitleOpened);
41754          } else {
41755            /* CSS sorgt dafür, dass es "runter" slidet */
41756            wrapper.attr('aria-hidden', 'true').data('gsb.twoclickshare', {oldHeight: wrapper.height()}).animate({top: 0, height: 0}, 'slow').promise().done(function(){$(this).css({display: 'none'})});
41757            toggleElement.attr("title",options.toggleTitleClosed);
41758          }
41759        });
41760      }
41761      wrapperInner.prepend($('<button class="close" tabindex="0">' + options.labelCloseButton + '</button>').click(function(){
41762        toggleElement.trigger('click');
41763        toggleElement.focus();
41764      }));
41765    }
41766    init();
41767  };
41768  $ .gsb.twoclickshare.defaultOptions = {
41769    insert: 'after', //where the wrapper is inserted, in relation to el,
41770    wrapperId: 'share', //ID of the wrapper element,
41771    wrapperTag: 'div', //HTML tag of the wrapper element
41772    toggleElement: '',
41773    toggleTitleClosed: typeof SHOW_MORE != "undefined" ? SHOW_MORE : 'Mehr anzeigen',
41774    toggleTitleOpened: typeof SHOW_LESS != "undefined" ? SHOW_LESS : 'Schließen',
41775    wrapperInnerClass: 'wrapper-share',
41776    labelHeader: typeof TWOCLICKSHARE_TITLE != "undefined" ? TWOCLICKSHARE_TITLE : 'In sozialen Medien teilen',
41777    labelFormLink: typeof TWOCLICKSHARE_FORMLINKTEXT != "undefined" ? TWOCLICKSHARE_FORMLINKTEXT : 'E-Mail',
41778    labelCloseButton: typeof CLOSE != "undefined" ? CLOSE : 'Schließen',
41779    socialSharePrivacyOptions: { //see jquery.socialshareprivacy.js for all possible options
41780      css_path: '',
41781      services: {
41782        facebook: {
41783          dummy_img: typeof(image_url_share_facebook_inactive) != "undefined" ? image_url_share_facebook_inactive : ''
41784        },
41785        twitter: {
41786          dummy_img: typeof(image_url_share_twitter_inactive) != "undefined" ? image_url_share_twitter_inactive : ''
41787        },
41788        gplus: {
41789          dummy_img: typeof(image_url_share_gplus_inactive) != "undefined" ? image_url_share_gplus_inactive : ''
41790        }
41791      }
41792    }
41793  };
41794  $ .fn.gsb_twoclickshare = function(options){
41795    return $ (this).map(function(){
41796      return $ .gsb.twoclickshare(this, options);
41797    });
41798  };
41799}(jQuery));
41800
41801   /* Ende gsb_twoclickshare */
41802   /* Start gsb_slideNavigation */
41803   (function ($) {
41804  if (!$.gsb) {
41805    $.gsb = {};
41806  }
41807  $.gsb.gsb_slideNavigation = function (el, options) {
41808    // To avoid scope issues, use 'base' instead of 'this'
41809    // to reference this class from internal events and functions.
41810    var base = this;
41811    var menuBoxWidth;
41812    // Access to jQuery and DOM versions of element
41813    base.$el = $(el);
41814    base.el = el;
41815    base.maxHeight = 0;
41816    base.utils = new NavigationUtils();
41817    base.menuBox;
41818
41819    // Add a reverse reference to the DOM object
41820    base.$el.data("gsb.gsb_slideNavigation", base);
41821    base.init = function () {
41822      base.options = $.extend({}, $.gsb.gsb_slideNavigation.defaultOptions, options);
41823      base.$el.gsb_responsiveListener(base);
41824    };
41825    $.gsb.gsb_slideNavigation.prototype.addClickfunction = function () {
41826
41827      // Wenn Browser kein translate3d kann, translate verwenden
41828      var bodyStyle = document.body.style;
41829      base.cssTransitions = false;
41830      if (bodyStyle.WebkitTransition !== undefined || bodyStyle.MozTransition !== undefined || bodyStyle.msTransition !== undefined) {
41831        base.cssTransitions = true;
41832      }
41833
41834      //Overlay aus static Variable holen
41835      base.overlay = base.utils.getOverlay();
41836      base.searchUtil = base.utils.getSearch();
41837
41838      if (!base.overlay) {
41839        base.utils.setOverlay($('<div id="navigation-overlay"/>'));
41840        base.utils.getOverlay().insertAfter($(base.options.overlayPosition));
41841        base.overlay = base.utils.getOverlay();
41842      } else {
41843        base.overlay.detach().insertAfter($(base.options.overlayPosition));
41844      }
41845
41846      if (!base.searchUtil) {
41847        base.utils.setSearch($('#search'));
41848        base.searchUtil = base.utils.getSearch().detach();
41849      } else {
41850        base.searchUtil = base.searchUtil.detach();
41851      }
41852
41853      //------------ WAI-ARIA -------------------------------------------------
41854      // Alle Control und Contentpanel selektieren
41855      base.controlPanel = base.$el.find(base.options.hoverItem).filter(function () {
41856        if ($(this).parent().siblings('.menu').length > 0) {
41857          return $(this);
41858        }
41859      });
41860      base.contentPanel = base.$el.find('.menu-box');
41861
41862      // Initial alles auf "closed" setzen
41863      base.aria = base.$el.gsb_ariaSupport(base);
41864
41865      //Erste Ebene
41866      base.$el.on('click', base.options.hoverItem, function (e) {
41867        if ($(this).closest('h3').siblings('.menu').length > 0) {
41868
41869          e.preventDefault();
41870          e.stopPropagation();
41871          base.menuBox = $(this).closest('li').find('.menu-box');
41872
41873          if (base.menuBox.is(':visible')) {
41874            base.utils.getOverlay().removeClass('active');
41875            $('body').removeClass('fixedNavPrimary');
41876            $(this).closest('h3').removeClass('opened');
41877            base.menuBox.hide();
41878            $(base.options.overlayItem).removeClass("active");
41879            //Schließen
41880            base.aria.updateAria(this, true, true);
41881            base.maxHeight = 0;
41882          } else {
41883            $('body').addClass('fixedNavPrimary');
41884            base.overlay.addClass('active');
41885
41886            //oeffnen
41887            base.aria.updateAria(this, false, true);
41888
41889            //Geöffnete Flyouts schliessen
41890            base.$el.find('.search .opened').trigger('click');
41891
41892            base.$el.find('.opened').removeClass('opened');
41893            base.$el.find('.menu-box:visible').hide();
41894            base.$el.find('.active').removeClass('active');
41895
41896            if (base.menuBox.find('>.pageLink').length == 0) {
41897              var pageLink = $('<p class="pageLink"/>');
41898              pageLink.insertAfter(base.menuBox.find('.close'));
41899              var link = $(this).clone();
41900              pageLink.prepend(link);
41901              pageLink.find('a').text(base.options.pageLinkText + " " + link.text());
41902            }
41903
41904            $(base.options.overlayItem).addClass("active");
41905            $(this).closest('h3').addClass('opened');
41906            base.menuBox.show();
41907
41908            if (base.menuBox.find(base.options.scrollLayer + ' ul').length > 0 && base.menuBox.find('.animate').length == 0) {
41909              base.menuBox.find(base.options.scrollLayer + ' ul').each(function () {
41910                base.setTransition($(this), 'inactive', 'true');
41911              });
41912
41913              base.setActive(base.menuBox, base, 'desktop');
41914              base.menuBox.find(base.options.scrollLayer + ' ul').addClass('animate');
41915            }
41916
41917            //Höhe des Fylouts berechnen
41918            var windowHeight = $(window).height();
41919            var navPrimaryHeight = base.$el.outerHeight();
41920            var offset = base.$el.offset().top;
41921            base.maxHeight = windowHeight - offset - navPrimaryHeight + $(window).scrollTop();
41922            base.menuBox.height(base.maxHeight);
41923            base.menuBox.width(menuBoxWidth);
41924          }
41925        }
41926      });
41927
41928      base.utils.scrollingElements(base.$el, base);
41929      base.utils.addScollingLinks(base.$el, base, 'desktop');
41930      base.addScollingClickFunction();
41931
41932      //Schließen Button
41933      base.closeButton = base.$el.find('p.close:first').clone();
41934      base.$el.on('click', '.close button', function (e) {
41935        e.preventDefault();
41936        e.stopPropagation();
41937
41938        base.$el.find('.opened a, .opened strong').focus().trigger('click');
41939      });
41940
41941      //Suche Button
41942      base.$el.on('click', base.options.searchLink, function (e) {
41943        e.preventDefault();
41944        e.stopPropagation();
41945
41946        if ($(this).hasClass('opened')) {
41947          $(this).removeClass('opened').addClass('closed');
41948          base.overlay.removeClass('active search');
41949          base.overlay.empty();
41950        } else {
41951          base.$el.find('.opened a').trigger('click');
41952          base.overlay.append(base.searchUtil);
41953          $(this).addClass('opened').removeClass('closed');
41954          base.overlay.addClass('active search');
41955
41956          //Autosuggest initialisieren
41957          if (base.options.autosuggestURL) {
41958            base.searchUtil.gsb_AutoSuggest(base.options.autosuggestURL);
41959          }
41960        }
41961      });
41962    };
41963
41964    $.gsb.gsb_slideNavigation.prototype.addScollingClickFunction = function () {
41965      // Nächster Slide
41966      base.$el.on('click', base.options.scrollLayer + ' ' + base.options.scrollButton, function (e) {
41967        e.preventDefault();
41968        e.stopPropagation();
41969
41970        base.liVisibility($(this), 'next');
41971        var siblingUl = $(this).closest('li').find('ul').first();
41972        if (siblingUl.length > 0) {
41973          base.setTransition(siblingUl, 'active');
41974        }
41975      });
41976
41977      // Slide zurück
41978      base.$el.on('click', '.back > button', function (e) {
41979        e.preventDefault();
41980        e.stopPropagation();
41981
41982        base.liVisibility($(this), 'prev');
41983        base.setTransition($(this).parent().parent('ul'), 'inactive');
41984      });
41985
41986      // Zurück zum ersten Slide
41987      base.$el.on('click', '.backToFirst > button', function (e) {
41988        e.preventDefault();
41989        e.stopPropagation();
41990
41991        base.liVisibility($(this), 'prev', true);
41992        base.setTransition($(this).parentsUntil(base.options.scrollLayer).filter('ul'), 'inactive');
41993      });
41994    };
41995
41996    /**
41997     *
41998     * @param btn - button welcher geklickt wurde
41999     * @param direction - Wird vor ider zurück Navigiert? (next,prev)
42000     * @param fullRecursive -  Li´s der Übergeordneten Ebene ausblenden, oder rekursiv bis topLevel?
42001     */
42002    $.gsb.gsb_slideNavigation.prototype.liVisibility = function (btn, direction, fullRecursive) {
42003
42004      fullRecursive = fullRecursive || false;
42005      var siblingsLi;
42006      if (direction == 'prev') {
42007        siblingsLi = btn.parent().parent().closest('li').siblings();
42008      } else {
42009        siblingsLi = btn.closest('li').siblings();
42010      }
42011
42012      if (siblingsLi.is(':hidden')) {
42013        siblingsLi.show();
42014      } else {
42015        siblingsLi.hide();
42016      }
42017
42018      if (fullRecursive) {
42019        var parentBackButton = siblingsLi.filter('.back').find('button');
42020        if (parentBackButton.length > 0) {
42021          base.liVisibility(parentBackButton, 'prev', true);
42022        }
42023      }
42024    };
42025
42026    /**
42027     *
42028     * @param elem - element welches aktiv gesetzt werden soll
42029     * @param state
42030     */
42031    $.gsb.gsb_slideNavigation.prototype.setTransition = function (elementList, state, initialcall) {
42032
42033      initialcall = initialcall || false;
42034      elementList.get().reverse().forEach(function (el) {
42035        var element = $(el);
42036
42037        if (!initialcall) {
42038          if (elementList.find('.close').length == 0) {
42039            var closeBtnWrapper = $('<li class="closeButton"/>');
42040            closeBtnWrapper.append(base.closeButton);
42041            elementList.append(closeBtnWrapper);
42042
42043            //setTimeout(function () {
42044            base.addA11y(elementList);
42045            //},500);
42046          }
42047        }
42048
42049        if (state == 'active') {
42050
42051          if (base.maxHeight < base.menuBox.get(0).scrollHeight) {
42052            base.maxHeight = base.menuBox.get(0).scrollHeight;
42053          }
42054
42055          element.height(base.maxHeight);
42056          setTimeout(function () {
42057            element.find('a:first').focus();
42058          }, 500);
42059          element.addClass('active').removeClass('inactive');
42060          var parentLiOffset = 0,
42061              menuBoxOffset = 0,
42062              translatePosition = 0;
42063          parentLiOffset = element.closest('li').offset().left;
42064          menuBoxOffset = element.closest('.menu-box').offset().left;
42065          translatePosition = parentLiOffset - menuBoxOffset;
42066
42067          if (base.cssTransitions) {
42068            element.css('transform', 'translate3d(-' + translatePosition + 'px,0,0)');
42069          } else {
42070            element.css('transform', 'translate(-' + translatePosition + 'px,0)');
42071          }
42072        } else {
42073          element.css('height', 'auto');
42074          element.addClass('inactive').removeClass('active');
42075          //}, 500);
42076          var menuBoxWidth = element.closest('.menu-box').outerWidth(),
42077              parentLiPosition = element.closest('li').position().left,
42078              translatePosition = menuBoxWidth - parentLiPosition;
42079
42080          if (base.cssTransitions) {
42081
42082            element.css('transform', 'translate3d(' + translatePosition + 'px,0,0)');
42083          } else {
42084            element.css('transform', 'translate(' + translatePosition + 'px,0)');
42085          }
42086        }
42087      });
42088    };
42089
42090    $.gsb.gsb_slideNavigation.prototype.addA11y = function (elementList) {
42091
42092      var focusElements = elementList.find('a,button');
42093
42094      focusElements[0].focus();
42095      focusElements.last().keydown(function (e) {
42096        if (e.keyCode === 9) {
42097          e.preventDefault();
42098          focusElements[0].focus();
42099        } else if (e.keyCode === 13) {
42100          return true;
42101        }
42102      });
42103    };
42104
42105    $.gsb.gsb_slideNavigation.prototype.setActive = function (menuBox) {
42106      var $body = $('body');
42107      if ($body.data('nn') && menuBox.find('.scrollingLevel ul #mm-' + $body.data('nn')).length > 0) {
42108        var activeNode = base.$el.find('#mm-' + $body.data('nn'));
42109        base.setTransition(activeNode.parentsUntil(base.options.scrollLayer).filter('ul'), 'active');
42110        activeNode.addClass('active').removeClass('inactive');
42111
42112        base.liVisibility(activeNode.siblings('.back').find('button'), 'prev', true);
42113      }
42114    };
42115
42116    $.gsb.gsb_slideNavigation.prototype.uninit = function () {
42117      base.$el.find('li.back,li.backToFirst').remove();
42118      base.$el.off();
42119    };
42120
42121    // Run initializer
42122    base.init();
42123  };
42124  $.gsb.gsb_slideNavigation.defaultOptions = {
42125    hoverItem: 'h3  a, h3 strong',
42126    searchLink: '.search > a',
42127    scrollLayer: '.scrollingLevel',
42128    scrollButton: 'li .forward',
42129    pageLinkText: PAGELINK,
42130    autosuggestURL: '../html/modules/autosuggest/json/autosuggest.json',
42131    overlayItem: '#navigation-overlay',
42132    overlayPosition: '#header',
42133    backLinkAural: BACK_BUTTON,
42134    backLinkAuraltoFirst: BACKTOFIRST_BUTTON,
42135    backButtonImage: image_url_mobile_back_button,
42136    backButtonAlt: BACK_BUTTON,
42137    backToFirstImage: image_url_mobile_backtofirst_button,
42138    backToFirstAlt: BACKTOFIRST_BUTTON,
42139    ariaType: "SLIDENAV",
42140    ariaSupport: {
42141      SLIDENAV: {
42142        firstOpen: true,
42143        panel: {
42144          id: function id(base) {
42145            return base.generateID();
42146          },
42147          aria_expanded: ["false", "true"],
42148          aria_controls: function aria_controls(base) {
42149            return base.generateID();
42150          }
42151        },
42152        content: {
42153          aria_hidden: ["true", "false"],
42154          id: function id(base, index) {
42155            return base.getPanelAttribute(index, "aria-controls");
42156          },
42157          aria_labelledby: function aria_labelledby(base, index) {
42158            return base.getPanelAttribute(index, "id");
42159          }
42160        }
42161      }
42162    },
42163    respondToEvents: true,
42164    onRefresh: function onRefresh() {
42165      this.addClickfunction();
42166    },
42167    responsive: [{
42168      breakpoint: 1025,
42169      onRefresh: function onRefresh() {
42170        this.uninit();
42171      }
42172    }]
42173  };
42174  $.fn.gsb_slideNavigation = function (options) {
42175    return this.each(function () {
vendor: 30,605 bytes, lines 42176-42876
42176      new $.gsb.gsb_slideNavigation(this, options);
42177    });
42178  };
42179})(jQuery);
42180   /* Ende gsb_slideNavigation */
42181   /* Start jquery.tablesorter */
42182   (function ($) {
42183    $.extend({
42184        tablesorter: new
42185        function () {
42186            var parsers = [],
42187                widgets = [];
42188            this.defaults = {
42189                cssHeader: "header",
42190                cssAsc: "headerSortUp",
42191                cssDesc: "headerSortDown",
42192                cssChildRow: "expand-child",
42193                sortInitialOrder: "asc",
42194                sortMultiSortKey: "shiftKey",
42195                sortForce: null,
42196                sortAppend: null,
42197                sortLocaleCompare: true,
42198                textExtraction: "simple",
42199                parsers: {}, widgets: [],
42200                widgetZebra: {
42201                    css: ["even", "odd"]
42202                }, headers: {}, widthFixed: false,
42203                cancelSelection: true,
42204                sortList: [],
42205                headerList: [],
42206                dateFormat: "us",
42207                decimal: '/\.|\,/g',
42208                onRenderHeader: null,
42209                selectorHeaders: 'thead th',
42210                debug: false
42211            };
42212 
42213            function benchmark(s, d) {
42214                log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
42215            }
42216            this.benchmark = benchmark;
42217            function log(s) {
42218                if (typeof console != "undefined" && typeof console.debug != "undefined") {
42219                    console.log(s);
42220                } else {
42221                    alert(s);
42222                }
42223            }
42224            function buildParserCache(table, $headers) {
42225                if (table.config.debug) {
42226                    var parsersDebug = "";
42227                }
42228                if (table.tBodies.length == 0) return;
42229                var rows = table.tBodies[0].rows;
42230                if (rows[0]) {
42231                    var list = [],
42232                        cells = rows[0].cells,
42233                        l = cells.length;
42234                    for (var i = 0; i < l; i++) {
42235                        var p = false;
42236                        if ($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)) {
42237                            p = getParserById($($headers[i]).metadata().sorter);
42238                        } else if ((table.config.headers[i] && table.config.headers[i].sorter)) {
42239                            p = getParserById(table.config.headers[i].sorter);
42240                        }
42241                        if (!p) {
42242                            p = detectParserForColumn(table, rows, -1, i);
42243                        }
42244                        if (table.config.debug) {
42245                            parsersDebug += "column:" + i + " parser:" + p.id + "\n";
42246                        }
42247                        list.push(p);
42248                    }
42249                }
42250                if (table.config.debug) {
42251                    log(parsersDebug);
42252                }
42253                return list;
42254            };
42255            function detectParserForColumn(table, rows, rowIndex, cellIndex) {
42256                var l = parsers.length,
42257                    node = false,
42258                    nodeValue = false,
42259                    keepLooking = true;
42260                while (nodeValue == '' && keepLooking) {
42261                    rowIndex++;
42262                    if (rows[rowIndex]) {
42263                        node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex);
42264                        nodeValue = trimAndGetNodeText(table.config, node);
42265                        if (table.config.debug) {
42266                            log('Checking if value was empty on row:' + rowIndex);
42267                        }
42268                    } else {
42269                        keepLooking = false;
42270                    }
42271                }
42272                for (var i = 1; i < l; i++) {
42273                    if (parsers[i].is(nodeValue, table, node)) {
42274                        return parsers[i];
42275                    }
42276                }
42277                return parsers[0];
42278            }
42279            function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) {
42280                return rows[rowIndex].cells[cellIndex];
42281            }
42282            function trimAndGetNodeText(config, node) {
42283                return $.trim(getElementText(config, node));
42284            }
42285            function getParserById(name) {
42286                var l = parsers.length;
42287                for (var i = 0; i < l; i++) {
42288                    if (parsers[i].id.toLowerCase() == name.toLowerCase()) {
42289                        return parsers[i];
42290                    }
42291                }
42292                return false;
42293            }
42294            function buildCache(table) {
42295                if (table.config.debug) {
42296                    var cacheTime = new Date();
42297                }
42298                var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
42299                    totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0,
42300                    parsers = table.config.parsers,
42301                    cache = {
42302                        row: [],
42303                        normalized: []
42304                    };
42305                for (var i = 0; i < totalRows; ++i) {
42306                    var c = $(table.tBodies[0].rows[i]),
42307                        cols = [];
42308                    if (c.hasClass(table.config.cssChildRow)) {
42309                        cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c);
42310                        continue;
42311                    }
42312                    cache.row.push(c);
42313                    for (var j = 0; j < totalCells; ++j) {
42314                        cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j]));
42315                    }
42316                    cols.push(cache.normalized.length);
42317                    cache.normalized.push(cols);
42318                    cols = null;
42319                };
42320                if (table.config.debug) {
42321                    benchmark("Building cache for " + totalRows + " rows:", cacheTime);
42322                }
42323                return cache;
42324            };
42325            function getElementText(config, node) {
42326                var text = "";
42327                if (!node) return "";
42328                if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false;
42329                if (config.textExtraction == "simple") {
42330                    if (config.supportsTextContent) {
42331                        text = node.textContent;
42332                    } else {
42333                        if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
42334                            text = node.childNodes[0].innerHTML;
42335                        } else {
42336                            text = node.innerHTML;
42337                        }
42338                    }
42339                } else {
42340                    if (typeof(config.textExtraction) == "function") {
42341                        text = config.textExtraction(node);
42342                    } else {
42343                        text = $(node).text();
42344                    }
42345                }
42346                return text;
42347            }
42348            function appendToTable(table, cache) {
42349                if (table.config.debug) {
42350                    var appendTime = new Date()
42351                }
42352                var c = cache,
42353                    r = c.row,
42354                    n = c.normalized,
42355                    totalRows = n.length,
42356                    checkCell = (n[0].length - 1),
42357                    tableBody = $(table.tBodies[0]),
42358                    rows = [];
42359                for (var i = 0; i < totalRows; i++) {
42360                    var pos = n[i][checkCell];
42361                    rows.push(r[pos]);
42362                    if (!table.config.appender) {
42363                        var l = r[pos].length;
42364                        for (var j = 0; j < l; j++) {
42365                            tableBody[0].appendChild(r[pos][j]);
42366                        }
42367                    }
42368                }
42369                if (table.config.appender) {
42370                    table.config.appender(table, rows);
42371                }
42372                rows = null;
42373                if (table.config.debug) {
42374                    benchmark("Rebuilt table:", appendTime);
42375                }
42376                applyWidget(table);
42377                setTimeout(function () {
42378                    $(table).trigger("sortEnd");
42379                }, 0);
42380            };
42381            function buildHeaders(table) {
42382                if (table.config.debug) {
42383                    var time = new Date();
42384                }
42385                var meta = ($.metadata) ? true : false;
42386              
42387                var header_index = computeTableHeaderCellIndexes(table);
42388                $tableHeaders = $(table.config.selectorHeaders, table).each(function (index) {
42389                    this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];;
42390                    this.order = formatSortingOrder(table.config.sortInitialOrder);
42391                  
42392   
42393     this.count = this.order;
42394                    if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true;
42395     if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index);
42396                    if (!this.sortDisabled) {
42397                        var $th = $(this).addClass(table.config.cssHeader);
42398                        if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th);
42399                    }
42400                    table.config.headerList[index] = this;
42401                });
42402                if (table.config.debug) {
42403                    benchmark("Built headers:", time);
42404                    log($tableHeaders);
42405                }
42406                return $tableHeaders;
42407            };
42408            function computeTableHeaderCellIndexes(t) {
42409                var matrix = [];
42410                var lookup = {};
42411                var thead = t.getElementsByTagName('THEAD')[0];
42412                var trs = thead.getElementsByTagName('TR');
42413                for (var i = 0; i < trs.length; i++) {
42414                    var cells = trs[i].cells;
42415                    for (var j = 0; j < cells.length; j++) {
42416                        var c = cells[j];
42417                        var rowIndex = c.parentNode.rowIndex;
42418                        var cellId = rowIndex + "-" + c.cellIndex;
42419                        var rowSpan = c.rowSpan || 1;
42420                        var colSpan = c.colSpan || 1
42421                        var firstAvailCol;
42422                        if (typeof(matrix[rowIndex]) == "undefined") {
42423                            matrix[rowIndex] = [];
42424                        }
42425                        for (var k = 0; k < matrix[rowIndex].length + 1; k++) {
42426                            if (typeof(matrix[rowIndex][k]) == "undefined") {
42427                                firstAvailCol = k;
42428                                break;
42429                            }
42430                        }
42431                        lookup[cellId] = firstAvailCol;
42432                        for (var k = rowIndex; k < rowIndex + rowSpan; k++) {
42433                            if (typeof(matrix[k]) == "undefined") {
42434                                matrix[k] = [];
42435                            }
42436                            var matrixrow = matrix[k];
42437                            for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) {
42438                                matrixrow[l] = "x";
42439                            }
42440                        }
42441                    }
42442                }
42443                return lookup;
42444            }
42445            function checkCellColSpan(table, rows, row) {
42446                var arr = [],
42447                    r = table.tHead.rows,
42448                    c = r[row].cells;
42449                for (var i = 0; i < c.length; i++) {
42450                    var cell = c[i];
42451                    if (cell.colSpan > 1) {
42452                        arr = arr.concat(checkCellColSpan(table, headerArr, row++));
42453                    } else {
42454                        if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) {
42455                            arr.push(cell);
42456                        }
42457                    }
42458                }
42459                return arr;
42460            };
42461            function checkHeaderMetadata(cell) {
42462                if (($.metadata) && ($(cell).metadata().sorter === false)) {
42463                    return true;
42464                };
42465                return false;
42466            }
42467            function checkHeaderOptions(table, i) {
42468                if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) {
42469                    return true;
42470                };
42471                return false;
42472            }
42473 
42474    function checkHeaderOptionsSortingLocked(table, i) {
42475                if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder;
42476                return false;
42477            }
42478 
42479            function applyWidget(table) {
42480                var c = table.config.widgets;
42481                var l = c.length;
42482                for (var i = 0; i < l; i++) {
42483                    getWidgetById(c[i]).format(table);
42484                }
42485            }
42486            function getWidgetById(name) {
42487                var l = widgets.length;
42488                for (var i = 0; i < l; i++) {
42489                    if (widgets[i].id.toLowerCase() == name.toLowerCase()) {
42490                        return widgets[i];
42491                    }
42492                }
42493            };
42494            function formatSortingOrder(v) {
42495                if (typeof(v) != "Number") {
42496                    return (v.toLowerCase() == "desc") ? 1 : 0;
42497                } else {
42498                    return (v == 1) ? 1 : 0;
42499                }
42500            }
42501            function isValueInArray(v, a) {
42502                var l = a.length;
42503                for (var i = 0; i < l; i++) {
42504                    if (a[i][0] == v) {
42505                        return true;
42506                    }
42507                }
42508                return false;
42509            }
42510            function setHeadersCss(table, $headers, list, css) {
42511                $headers.removeClass(css[0]).removeClass(css[1]);
42512                var h = [];
42513                $headers.each(function (offset) {
42514                    if (!this.sortDisabled) {
42515                        h[this.column] = $(this);
42516                    }
42517                });
42518                var l = list.length;
42519                for (var i = 0; i < l; i++) {
42520                    h[list[i][0]].addClass(css[list[i][1]]);
42521     var header = h[list[i][0]];
42522     var lnk = header.children('a.sortUp');
42523     var lnkText = lnk.html();
42524var newText = ""
42525     if(header.attr('class') == 'header headerSortDown'){
42526      newText = lnkText.replace("+", "-");
42527     } else if(header.attr('class') == 'header headerSortUp'){
42528     newText = lnkText.replace("-", "+");
42529     }
42530lnk.text(newText);
42531                }
42532            }
42533            function fixColumnWidth(table, $headers) {
42534                var c = table.config;
42535                if (c.widthFixed) {
42536                    var colgroup = $('<colgroup>');
42537                    $("tr:first td", table.tBodies[0]).each(function () {
42538                        colgroup.append($('<col>').css('width', $(this).width()));
42539                    });
42540                    $(table).prepend(colgroup);
42541                };
42542            }
42543            function updateHeaderSortCount(table, sortList) {
42544                var c = table.config,
42545                    l = sortList.length;
42546                for (var i = 0; i < l; i++) {
42547                    var s = sortList[i],
42548                        o = c.headerList[s[0]];
42549                    o.count = s[1];
42550                    o.count++;
42551                }
42552            }
42553            function multisort(table, sortList, cache) {
42554                if (table.config.debug) {
42555                    var sortTime = new Date();
42556                }
42557                var dynamicExp = "var sortWrapper = function(a,b) {",
42558                    l = sortList.length;
42559                for (var i = 0; i < l; i++) {
42560                    var c = sortList[i][0];
42561                    var order = sortList[i][1];
42562                    var s = (table.config.parsers[c].type == "text") ? ((order == 0) ? makeSortFunction("text", "asc", c) : makeSortFunction("text", "desc", c)) : ((order == 0) ? makeSortFunction("numeric", "asc", c) : makeSortFunction("numeric", "desc", c));
42563                    var e = "e" + i;
42564                    dynamicExp += "var " + e + " = " + s;
42565                    dynamicExp += "if(" + e + ") { return " + e + "; } ";
42566                    dynamicExp += "else { ";
42567                }
42568                var orgOrderCol = cache.normalized[0].length - 1;
42569                dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
42570                for (var i = 0; i < l; i++) {
42571                    dynamicExp += "}; ";
42572                }
42573                dynamicExp += "return 0; ";
42574                dynamicExp += "}; ";
42575                if (table.config.debug) {
42576                    benchmark("Evaling expression:" + dynamicExp, new Date());
42577                }
42578                eval(dynamicExp);
42579                cache.normalized.sort(sortWrapper);
42580                if (table.config.debug) {
42581                    benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime);
42582                }
42583                return cache;
42584            };
42585            function makeSortFunction(type, direction, index) {
42586                var a = "a[" + index + "]",
42587                    b = "b[" + index + "]";
42588                if (type == 'text' && direction == 'asc') {
42589                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));";
42590                } else if (type == 'text' && direction == 'desc') {
42591                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));";
42592                } else if (type == 'numeric' && direction == 'asc') {
42593                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));";
42594                } else if (type == 'numeric' && direction == 'desc') {
42595                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));";
42596                }
42597            };
42598            function makeSortText(i) {
42599                return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));";
42600            };
42601            function makeSortTextDesc(i) {
42602                return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));";
42603            };
42604            function makeSortNumeric(i) {
42605                return "a[" + i + "]-b[" + i + "];";
42606            };
42607            function makeSortNumericDesc(i) {
42608                return "b[" + i + "]-a[" + i + "];";
42609            };
42610            function sortText(a, b) {
42611                if (table.config.sortLocaleCompare) return a.localeCompare(b);
42612                return ((a < b) ? -1 : ((a > b) ? 1 : 0));
42613            };
42614            function sortTextDesc(a, b) {
42615                if (table.config.sortLocaleCompare) return b.localeCompare(a);
42616                return ((b < a) ? -1 : ((b > a) ? 1 : 0));
42617            };
42618            function sortNumeric(a, b) {
42619                return a - b;
42620            };
42621            function sortNumericDesc(a, b) {
42622                return b - a;
42623            };
42624            function getCachedSortType(parsers, i) {
42625                return parsers[i].type;
42626            };
42627            this.construct = function (settings) {
42628                return this.each(function () {
42629                    if (!this.tHead || !this.tBodies) return;
42630                    var $this, $document, $headers, cache, config, shiftDown = 0,
42631                        sortOrder;
42632                    this.config = {};
42633                    config = $.extend(this.config, $.tablesorter.defaults, settings);
42634                    $this = $(this);
42635                    $.data(this, "tablesorter", config);
42636                    $headers = buildHeaders(this);
42637                    this.config.parsers = buildParserCache(this, $headers);
42638                    cache = buildCache(this);
42639                    var sortCSS = [config.cssDesc, config.cssAsc];
42640                    fixColumnWidth(this);
42641                    $headers.click(
42642                    function (e) {
42643                        var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;
42644                        if (!this.sortDisabled && totalRows > 0) {
42645                            $this.trigger("sortStart");
42646                            var $cell = $(this);
42647                            var i = this.column;
42648                            this.order = this.count++ % 2;
42649       if(this.lockedOrder) this.order = this.lockedOrder;
42650                            if (!e[config.sortMultiSortKey]) {
42651                                config.sortList = [];
42652                                if (config.sortForce != null) {
42653                                    var a = config.sortForce;
42654                                    for (var j = 0; j < a.length; j++) {
42655                                        if (a[j][0] != i) {
42656                                            config.sortList.push(a[j]);
42657                                        }
42658                                    }
42659                                }
42660                                config.sortList.push([i, this.order]);
42661                            } else {
42662                                if (isValueInArray(i, config.sortList)) {
42663                                    for (var j = 0; j < config.sortList.length; j++) {
42664                                        var s = config.sortList[j],
42665                                            o = config.headerList[s[0]];
42666                                        if (s[0] == i) {
42667                                            o.count = s[1];
42668                                            o.count++;
42669                                            s[1] = o.count % 2;
42670                                        }
42671                                    }
42672                                } else {
42673                                    config.sortList.push([i, this.order]);
42674                                }
42675                            };
42676                            setTimeout(function () {
42677                                setHeadersCss($this[0], $headers, config.sortList, sortCSS);
42678                                appendToTable(
42679                                 $this[0], multisort(
42680                                 $this[0], config.sortList, cache)
42681        );
42682                            }, 1);
42683                            return false;
42684                        }
42685                    }).mousedown(function () {
42686                        if (config.cancelSelection) {
42687                            this.onselectstart = function () {
42688                                return false
42689                            };
42690                            return false;
42691                        }
42692                    });
42693                    $this.bind("update", function () {
42694                        var me = this;
42695                        setTimeout(function () {
42696                            me.config.parsers = buildParserCache(
42697                            me, $headers);
42698                            cache = buildCache(me);
42699                        }, 1);
42700                    }).bind("updateCell", function (e, cell) {
42701                        var config = this.config;
42702                        var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex];
42703                        cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(
42704                        getElementText(config, cell), cell);
42705                    }).bind("sorton", function (e, list) {
42706                        $(this).trigger("sortStart");
42707                        config.sortList = list;
42708                        var sortList = config.sortList;
42709                        updateHeaderSortCount(this, sortList);
42710                        setHeadersCss(this, $headers, sortList, sortCSS);
42711                        appendToTable(this, multisort(this, sortList, cache));
42712                    }).bind("appendCache", function () {
42713                        appendToTable(this, cache);
42714                    }).bind("applyWidgetId", function (e, id) {
42715                        getWidgetById(id).format(this);
42716                    }).bind("applyWidgets", function () {
42717                        applyWidget(this);
42718                    });
42719                    if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) {
42720                        config.sortList = $(this).metadata().sortlist;
42721                    }
42722                    if (config.sortList.length > 0) {
42723                        $this.trigger("sorton", [config.sortList]);
42724                    }
42725                    applyWidget(this);
42726                });
42727            };
42728            this.addParser = function (parser) {
42729                var l = parsers.length,
42730                    a = true;
42731                for (var i = 0; i < l; i++) {
42732                    if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
42733                        a = false;
42734                    }
42735                }
42736                if (a) {
42737                    parsers.push(parser);
42738                };
42739            };
42740            this.addWidget = function (widget) {
42741                widgets.push(widget);
42742            };
42743            this.formatFloat = function (s) {
42744                var i = parseFloat(s);
42745                return (isNaN(i)) ? 0 : i;
42746            };
42747            this.formatInt = function (s) {
42748                var i = parseInt(s);
42749                return (isNaN(i)) ? 0 : i;
42750            };
42751            this.isDigit = function (s, config) {
42752                return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, '')));
42753            };
42754            this.clearTableBody = function (table) {
42755                if ($.browser.msie) {
42756                    function empty() {
42757                        while (this.firstChild)
42758                        this.removeChild(this.firstChild);
42759                    }
42760                    empty.apply(table.tBodies[0]);
42761                } else {
42762                    table.tBodies[0].innerHTML = "";
42763                }
42764            };
42765        }
42766    });
42767    $.fn.extend({
42768        tablesorter: $.tablesorter.construct
42769    });
42770    var ts = $.tablesorter;
42771    ts.addParser({
42772        id: "text",
42773        is: function (s) {
42774            return true;
42775        }, format: function (s) {
42776            return $.trim(s.toLocaleLowerCase());
42777        }, type: "text"
42778    });
42779    ts.addParser({
42780        id: "digit",
42781        is: function (s, table) {
42782            var c = table.config;
42783            return $.tablesorter.isDigit(s, c);
42784        }, format: function (s) {
42785            return $.tablesorter.formatFloat(s);
42786        }, type: "numeric"
42787    });
42788    ts.addParser({
42789        id: "currency",
42790        is: function (s) {
42791            return /^[£$€?.]/.test(s);
42792        }, format: function (s) {
42793            return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), ""));
42794        }, type: "numeric"
42795    });
42796    ts.addParser({
42797        id: "ipAddress",
42798        is: function (s) {
42799            return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
42800        }, format: function (s) {
42801            var a = s.split("."),
42802                r = "",
42803                l = a.length;
42804            for (var i = 0; i < l; i++) {
42805                var item = a[i];
42806                if (item.length == 2) {
42807                    r += "0" + item;
42808                } else {
42809                    r += item;
42810                }
42811            }
42812            return $.tablesorter.formatFloat(r);
42813        }, type: "numeric"
42814    });
42815    ts.addParser({
42816        id: "url",
42817        is: function (s) {
42818            return /^(https?|ftp|file):\/\/$/.test(s);
42819        }, format: function (s) {
42820            return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), ''));
42821        }, type: "text"
42822    });
42823    ts.addParser({
42824        id: "isoDate",
42825        is: function (s) {
42826            return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
42827        }, format: function (s) {
42828            return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(
42829            new RegExp(/-/g), "/")).getTime() : "0");
42830        }, type: "numeric"
42831    });
42832    ts.addParser({
42833        id: "percent",
42834        is: function (s) {
42835            return /\%$/.test($.trim(s));
42836        }, format: function (s) {
42837            return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), ""));
42838        }, type: "numeric"
42839    });
42840    ts.addParser({
42841        id: "usLongDate",
42842        is: function (s) {
42843            return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));
42844        }, format: function (s) {
42845            return $.tablesorter.formatFloat(new Date(s).getTime());
42846        }, type: "numeric"
42847    });
42848    ts.addParser({
42849        id: "shortDate",
42850        is: function (s) {
42851            return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
42852        }, format: function (s, table) {
42853            var c = table.config;
42854            s = s.replace(/\-/g, "/");
42855            if (c.dateFormat == "us") {
42856                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
42857            } else if (c.dateFormat == "uk") {
42858                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
42859            } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
42860                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");
42861            }
42862            return $.tablesorter.formatFloat(new Date(s).getTime());
42863        }, type: "numeric"
42864    });
42865    ts.addParser({
42866        id: "time",
42867        is: function (s) {
42868            return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
42869        }, format: function (s) {
42870            return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
42871        }, type: "numeric"
42872    });
42873    ts.addParser({
42874        id: "metadata",
42875        is: function (s) {
42876            return false;
42877        }, format: function (s, table, cell) {
42878            var c = table.config,
42879                p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
42880            return $(cell).metadata()[p];
42881        }, type: "numeric"
42882    });
42883    // add default widgets
42884    ts.addWidget({
42885        id: "zebra",
42886        format: function (table) {
42887            if (table.config.debug) {
42888                var time = new Date();
42889            }
42890            var $tr, row = -1,
42891                odd;
42892            // loop through the visible rows
42893            $("tr:visible", table.tBodies[0]).each(function (i) {
42894                $tr = $(this);
42895                // style children rows the same way the parent
42896                // row was styled
42897                if (!$tr.hasClass(table.config.cssChildRow)) row++;
42898                odd = (row % 2 == 0);
42899                $tr.removeClass(
42900                table.config.widgetZebra.css[odd ? 0 : 1]).addClass(
42901                table.config.widgetZebra.css[odd ? 1 : 0])
42902            });
42903            if (table.config.debug) {
42904                $.tablesorter.benchmark("Applying Zebra widget", time);
42905            }
42906        }
42907    });
42908})(jQuery);
42909
42910   /* Ende jquery.tablesorter */
42911   /* Start tables */
42912   /*
42913* @author jkuschel
42914* @author dsorge
42915*/
42916(function($){
42917 jQuery.fn.extend({
42918  deleteCols: function(){
42919   var table = $(this);
42920   $origTable = $('.baua-table, .bauatable').clone();
42921   var headers = table.find('th');
42922   var clickCount = 0;
42923   return headers.each(function(){
42924    $(this).append('<a class="col" href="#"><img src="' + image_url_hide_td + '"' +
42925                ' alt="' + HIDE_TD + '"></a>');
42926    $(this).find('.col').click(function(){
42927     headers = table.find('th');
42928     var col = headers.index($(this).parent());
42929     table.find('tr').each(function(){
42930  var colToDelete = $(this).find('td:eq('+col+')');
42931      colToDelete.hide();
42932     });
42933     $(this).parent().hide();
42934     clickCount++;
42935 if($('.responsiveTable').find('.reset').length == 0){
42936  $('.baua-table, .bauatable').before('<p><a class="reset" href="#">vollständige Tabelle laden</a></p>');
42937 }
42938   var lnkReset =  $('.responsiveTable').find('.reset');
42939   lnkReset.click(function(){
42940      $('.baua-table, .bauatable').remove();
42941      $('.responsiveTable').append($origTable);
42942      $('.reset').remove();
42943      $('.baua-table, .bauatable').deleteCols();
42944  return false;
42945     });
42946     return false;
42947    });
42948   });
42949  }
42950 });
42951 jQuery(document).ready(function(){
42952  $('.baua-table, .bauatable').deleteCols();
42953 })
42954})(jQuery);
42955
42956   /* Ende tables */
42957   /* Start gsb_infinitescrolling */
42958   /**
42959 * GSB-Plugin infinitescrolling
42960 *
42961 * Author: pespeloe
42962 */
42963;(function ($) {
42964  if (!$.gsb) {
42965    $.gsb = {};
42966  }
42967  $.gsb.infinitescrolling = function (el, instanceId, options) {
42968    // To avoid scope issues, use 'base' instead of 'this'
42969    // to reference this class from internal events and functions.
42970    var base = this;
42971    // Access to $ and DOM versions of element
42972    base.$el = $(el);
42973    base.el = el;
42974    // Add a reverse reference to the DOM object
42975    base.$el.data("gsb.infinitescrolling", base);
42976    base.init = function () {
42977      base.options = $.extend({}, $.gsb.infinitescrolling.defaultOptions, options);
42978
42979      if (typeof base.options.paginationElements == 'function') {
42980        base.pagination = base.options.paginationElements.call(this, base);
42981      } else {
42982        base.pagination = base.$el.find(base.options.paginationElements);
42983      }
42984
42985      $.get(base.$el.data('href'), function (data) {
42986        base.nextLink = base.getLink(data);
42987      });
42988
42989      if (base.pagination.length != 0) {
42990        base.addMoreButton();
42991        base.pagination.closest(base.options.paginationBoxClass).hide();
42992      }
42993    };
42994
42995    $.gsb.infinitescrolling.prototype.addMoreButton = function () {
42996      base.moreButton = $('<button class="loadmore"/>');
42997      base.moreButton.append(base.options.buttonText);
42998      base.moreButton.insertAfter(base.$el).on('click', function (e) {
42999        e.preventDefault();
43000        e.stopPropagation();
43001
43002        $.get(base.nextLink, function (data) {
43003          base.$el.append($(data).find(base.options.resultClass));
43004          base.nextLink = base.getLink(data);
43005          if ($(data).find(base.options.forwardButton).length == 0) {
43006            base.moreButton.remove();
43007          }
43008        });
43009      });
43010    };
43011
43012    $.gsb.infinitescrolling.prototype.getLink = function (data) {
43013      return $(data).find(base.options.forwardButton).attr('href');
43014    };
43015
43016    // Run initializer
43017    base.init();
43018  };
43019
43020  $.gsb.infinitescrolling.defaultOptions = {
43021    paginationElements: 'a.forward',
43022    forwardButton: 'a.forward',
43023    paginationBoxClass: '.navIndex',
43024    resultClass: '.section-results .row',
43025    buttonText: typeof SHOW_MORE == 'undefined' ? 'mehr anzeigen' : SHOW_MORE
43026  };
43027
43028  $.fn.gsb_infinitescrolling = function (options) {
43029    return this.each(function (index, value) {
43030      new $.gsb.infinitescrolling($(value), options);
43031    });
43032  };
43033})(jQuery);
43034   /* Ende gsb_infinitescrolling */
43035   /* Start gsb_baua_toggle_text */
43036   (function ($) {
43037  if (!$.gsb) {
43038    $.gsb = { baua: {} };
43039  } else if (!$.gsb.baua) {
43040    $.gsb.baua = {};
43041  };
43042  $.gsb.baua.toggleText = function (el, userOptions) {
43043    var base = this;
43044    base.$el = $(el);
43045    base.options = $.extend({}, $.gsb.baua.toggleText.defaultOptions, userOptions);
43046    base.$el.data("gsb.baua.toggleText", base);
43047    base.$el.gsb_responsiveListener(base);
43048  };
43049  $.gsb.baua.toggleText.prototype.init = function init() {
43050    var base = this;
43051    base.$el.addClass('defaultHidden-element hidden');
43052    base.$el.find('button,a,input').attr('tabindex', -1);
43053    base.$el.append('<div class="overlay"></div>');
43054    base.fullTextButton = $("<button class='defaultHidden-opener'>" + base.options.fullTextButtonText + "</button>").insertAfter(base.$el).addClass('shown').on('click', function () {
43055      base.$el.removeClass('hidden');
43056      if (base.$el.find('button,a,input').length > 0) {
43057        base.$el.find('button,a,input').attr('tabindex', 0);
43058        base.$el.find('button,a,input')[0].focus();
43059      }
43060      $(this).removeClass('shown');
43061      base.shortTextButton.addClass('shown');
43062    });
43063    base.shortTextButton = $("<button class='defaultHidden-closer'>" + base.options.shortTextButtonText + "</button>").insertAfter(base.$el).on('click', function () {
43064      base.$el.addClass('hidden');
43065      base.$el.find('button,a,input').attr('tabindex', -1);
43066      $(this).removeClass('shown');
43067      base.fullTextButton.addClass('shown').focus();
43068    });
43069  };
43070  $.gsb.baua.toggleText.prototype.remove = function remove() {
43071    var base = this;
43072    if (base.fullTextButton && base.shortTextButton) {
43073      base.shortTextButton.remove();
43074      base.fullTextButton.remove();
43075      base.$el.find('button,a,input').removeAttr('tabindex');
43076      base.$el.removeClass('defaultHidden-element hidden shown');
43077    }
43078  };
43079  $.gsb.baua.toggleText.defaultOptions = {
43080    fullTextButtonText: typeof SHOW_MORE_ARTICLE == 'undefined' ? 'Weiterlesen' : SHOW_MORE_ARTICLE,
43081    shortTextButtonText: typeof SHOW_LESS_ARTICLE == 'undefined' ? 'Schließen' : SHOW_LESS_ARTICLE,
43082    respondToEvents: true,
43083    onRefresh: function onRefresh() {
43084      this.init();
43085    }
43086  };
43087  $.fn.gsb_baua_toggleText = function (options) {
43088    return this.each(function () {
43089      if (!$(this).data('gsb.baua.toggleText')) {
43090        new $.gsb.baua.toggleText(this, options);
43091      }
43092    });
43093    return this;
43094  };
43095})(jQuery);
43096   /* Ende gsb_baua_toggle_text */
43097   /* Start gsb_baua_toggleFacet */
43098   /**
43099 * @name toggleFacet
43100 * @version 0.0.5
43101 * @see {@link http://semver.org|Semantic Versioning}
43102 * @author pespeloe
43103 *
43104 * @desc Modulbeschreibung
43105 *
43106 * @requires  {@link external:jQuery}
43107 *
43108 * @example
43109 * $('#supplement').find('.respTargetsWrapper .links').gsb_toggleFacet();
43110 * */
43111;
43112(function ($) {
43113  if (!$.gsb) {
43114    $.gsb = {};
43115  }
43116  ;
43117
43118  $.gsb.baua_toggleFacet = function (el, options) {
43119    // To avoid scope issues, use 'base' instead of 'this'
43120    // to reference this class from internal events and functions.
43121    var base = this;
43122
43123    // Access to jQuery and DOM versions of element
43124    base.$el = $(el);
43125    base.el = el;
43126
43127    // Add a reverse reference to the DOM object
43128    base.$el.data("gsb.toggleFacet", base);
43129
43130    base.init = function () {
43131      base.options = $.extend({}, $.gsb.baua_toggleFacet.defaultOptions, options);
43132      base.wrapLists();
43133
43134      if (base.$el.find('li > strong').length > 0) {
43135        base.toggleList.find('button').click();
43136      }
43137    };
43138
43139    /**
43140     * @method wrapLists
43141     * @desc wraped die Elemente die über initialShow hinausgehen in einem li, welches an das Ende von base.$el gehängt wird
43142     */
43143    $.gsb.baua_toggleFacet.prototype.wrapLists = function () {
43144      if (base.$el.find('li').length > base.options.initialShow) {
43145        base.$el.append('<li class="toggle"/>');
43146        base.toggleList = base.$el.find('.toggle');
43147        base.toggleList.prepend("<ul/>");
43148
43149        $.each(base.$el.find('li'), function (index) {
43150          if (index + 1 > base.options.initialShow && !$(this).hasClass('toggle')) {
43151            base.toggleList.find('ul').append($(this));
43152          }
43153        });
43154
43155        base.toggleList.append('<button class="hideContent">' + base.options.buttonTextClosed + '</button>');
43156        base.toggleList.find('ul').hide();
43157
43158        base.addClick();
43159      }
43160    };
43161
43162    /**
43163     * @method addClick
43164     * @desc fügt die Click-Funktion hinzu und blendet Container ein oder aus
43165     */
43166    $.gsb.baua_toggleFacet.prototype.addClick = function () {
43167
43168      base.$el.on("click", ".toggle > button", function () {
43169        var button = $(this);
43170        if (button.hasClass('hideContent')) {
43171          base.toggleList.find('> ul').slideDown();
43172          button.text(base.options.buttonTextOpened);
43173          button.removeClass('hideContent').addClass('showContent');
43174          button.closest('ul').find('> li:first-child a').focus();
43175        } else {
43176          base.toggleList.find('> ul').slideUp();
43177          button.text(base.options.buttonTextClosed);
43178          button.removeClass('showContent').addClass('hideContent');
43179        }
43180      });
43181    };
43182
43183    // Run initializer
43184    base.init();
43185  };
43186
43187  /**
43188   * @typedef defaultOptions
43189   * @type {object}
43190   * @property {object}   options                                   - Default Options des Scripts
43191   * @property {int} [options.initialShow]                          - Angabe wie viele Elemente angezeigt werden sollen
43192   * @property {String} [options.buttonTextOpened]                  - Text für geöffnetes Accordion
43193   * @property {String} [options.buttonTextClosed]                  - Text für geschlossenes Accordion
43194   *
43195   */
43196
43197  $.gsb.baua_toggleFacet.defaultOptions = {
43198    initialShow: 3,
43199    buttonTextOpened: typeof SHOW_LESS == 'undefined' ? 'Ausblenden' : SHOW_LESS,
43200    buttonTextClosed: typeof SHOW_MORE == 'undefined' ? 'Einblenden' : SHOW_MORE
43201  };
43202
43203  $.fn.gsb_baua_toggleFacet = function (options) {
43204    return this.each(function () {
43205      new $.gsb.baua_toggleFacet(this, options);
43206    });
43207  };
43208})(jQuery);
43209   /* Ende gsb_baua_toggleFacet */
43210   /* Start gsb_multimedia */
43211   var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
43212
43213/* --GSBDocStart
43214 * @name: @gsb/gsb_multimedia 
43215 * @version: 6.3.5 
43216 * @repository:  
43217 * @description: [//]: # (Diesen und folgende Kommentare auf keinen Fall löschen!) [//]: # (Nur so akzeptiert license-checker die Lizenz) [//]: # (SEE LICENSE IN LICENSE-INTERNAL.txt) [//]: # (https://license-internal.txt) 
43218 * --GSBDocEnd
43219*/
43220gsb.makeGSBModule('gsb.Multimedia', {
43221  /**
43222   * Führt die Initialisierung des GSB-Wrapper-Plugins durch.
43223   */
43224  init: function init() {
43225    var base = this;
43226    base.$elWrapper = base.$el.closest(base.options.selectors.wrapper);
43227    base.initializeMediaElement();
43228  },
43229
43230  /**
43231   * Führt die Initialisierung des Mediaelement.js Plugins durch.
43232   */
43233  initializeMediaElement: function initializeMediaElement() {
43234    var base = this;
43235    var mediaelementplayerOptions = $.extend({}, base.options.mediaelementplayerOptions, base.options.settings.mediaelementplayerOptions, base.mediaelementplayerOptionsFromDataAttribute());
43236    var $consentWrapper = void 0,
43237        $consentButton = void 0;
43238    if (mediaelementplayerOptions.hasOwnProperty('videoWidth') && !base.options.dontSetWidthAttribute) {
43239      base.$el.attr('width', mediaelementplayerOptions.videoWidth);
43240    }
43241    if (mediaelementplayerOptions.hasOwnProperty('videoHeight') && !base.options.dontSetHeightAttribute) {
43242      base.$el.attr('height', mediaelementplayerOptions.videoHeight);
43243    }
43244    base.centerVideoIfRequired();
43245    base.setLocale();
43246    base.$elWrapper.addClass('gsb-multimedia');
43247    base.isExternalApi = Boolean(base.$elWrapper.find(base.options.selectors.isExternalApi).length);
43248    if (base.options.externalApiRequiresConsent && base.isExternalApi && !base.consented) {
43249      var height = base.$el.height();
43250      var width = base.$el.width();
43251      if (height <= 0) {
43252        // Fallback, falls die Höhe des Elements nicht abgelesen werden kann.
43253        var originalHeight = Math.floor(Number(base.$el.attr('height')));
43254        var originalWidth = Math.floor(Number(base.$el.attr('width')));
43255        if (width > 0) {
43256          height = Math.floor(width * (originalHeight / originalWidth));
43257          base.$elWrapper.css({
43258            minHeight: height
43259          });
43260        } else {
43261          height = originalHeight;
43262          width = originalWidth;
43263          base.$elWrapper.css({
43264            minHeight: height,
43265            minWidth: width
43266          });
43267        }
43268      }
43269      base.$elWrapper.css({
43270        height: height,
43271        width: width,
43272        backgroundImage: 'url(' + base.$el.attr('poster') + ')',
43273        backgroundSize: 'contain'
43274      }).addClass('consent-required');
43275      base.$el.attr('tabindex', -1).hide();
43276      $consentWrapper = $(base.options.markup.consentWrapper);
43277      $consentButton = $(base.options.markup.consentButton).text(base.options.consentButtonText).on('click', base, base.onClickConsentButton);
43278      $consentWrapper.find(base.options.selectors.consentContent).attr('aria-label', base.options.consentLabel).attr('role', 'group').attr('aria-roledescription', base.options.consentDescription).html(base.options.markup.consentContent)[base.options.consentButtonInsertion]($consentButton);
43279      base.$elWrapper.prepend($consentWrapper);
43280      base.$consentWrapper = $consentWrapper;
43281
43282      if (base.options.consentSetMinHeight) {
43283        $consentWrapper.css({
43284          minHeight: height
43285        });
43286      }
43287
43288      return;
43289    }
43290
43291    base.$el.on('success.' + base.eventName, base, base.onMepSuccess);
43292    base.$el.mediaelementplayer($.extend({}, {
43293      success: function success(fakeNode, baseEl, mepInstance) {
43294        var base = $(baseEl).data('gsb.Multimedia');
43295        base.mep = mepInstance;
43296        base.$el.trigger('success.Multimedia.gsb', base);
43297        base.bitvTweaks();
43298        base.$elWrapper.find(base.options.selectors.volumeSlider).hide();
43299        base.$elWrapper.find(base.options.selectors.captionsSelect).find('label').on('click', base, base.onClickCaptionsLabel);
43300        base.$elWrapper.find(base.options.selectors.timeRail).on('dragstart touchstart mousedown', function (ev) {
43301          return ev.stopPropagation();
43302        });
43303        base.$el.trigger('init.Multimedia.gsb');
43304      }
43305    }, mediaelementplayerOptions));
43306  },
43307
43308  // triggers hlserror.Multimedia.gsb for gsb_streamPolling_muxCom (currently only used in Saarland)
43309  onMepSuccess: function onMepSuccess(ev, base) {
43310    // make sure exposing base to success-Event-Handlers as 2. arg works
43311    var fakeNode = base.mep.media;
43312    if (fakeNode && fakeNode.hlsPlayer) {
43313      fakeNode.hlsPlayer.on(Hls.Events.ERROR, function (hlsEvType, hlsEvData) {
43314        console.warn(base.moduleName + ': HLS-Error-Callback called. Triggering event now.', Array.from(arguments));
43315        $(fakeNode).trigger('hlserror.Multimedia.gsb', {
43316          base: base,
43317          hlsEvData: hlsEvData,
43318          hlsEvType: hlsEvType
43319        });
43320      });
43321    }
43322  },
43323
43324  onClickCaptionsLabel: function onClickCaptionsLabel(ev) {
43325    var base = ev.data;
43326    //this function prevents <label> Elements from blurring their <input>s
43327    ev.preventDefault();
43328    $(this.control).trigger('click');
43329  },
43330
43331  onClickConsentButton: function onClickConsentButton(ev) {
43332    var base = ev.data;
43333    base.consented = true;
43334    base.$consentWrapper.remove();
43335    base.$elWrapper.css({
43336      backgroundImage: '',
43337      height: '',
43338      width: '',
43339      backgroundSize: ''
43340    }).removeClass('consent-required');
43341    if (base.$el.attr('data-consent-autoplay') !== 'false') {
43342      base.$el.attr('autoplay', 'autoplay');
43343    }
43344    base.$el.show();
43345    base.initializeMediaElement();
43346  },
43347
43348  bitvTweaks: function bitvTweaks(ev) {
43349    var base = ev ? ev.data : this;
43350    var unique = Math.random().toString(36).substr(2, 9);
43351    var $container = base.$elWrapper.find('.mejs__container');
43352
43353    /* required for HTML validation of stringified DOM
43354     * see: https://testen.bitv-test.de/index.php?a=di&iid=99
43355     * yes, this is dumb
43356     */
43357    base.$el.filter('audio, video').find('source').remove();
43358
43359    base.$elWrapper.find('.mejs__volume-slider').removeAttr('href') // role=slider MUST NOT have href attribute
43360    .find('#mejs__volume-slider').attr('id', 'volume-slider-' + unique); // fix duplicate Ids
43361    base.$elWrapper.find('.mejs__volume-button button').attr('aria-describedby', 'volume-slider-' + unique);
43362    $container.attr('aria-roledescription', $container.attr('aria-label')).removeAttr('aria-label').attr('aria-labelledby', base.$el.attr('aria-labelledby')).removeAttr('tabindex').prev('.mejs__offscreen').remove(); // remove superseded aural-only label
43363
43364    base.$el.on('progress timeupdate', base, base.removeTabindex);
43365
43366    // pressable buttons: set aria-pressed
43367    base.$elWrapper.find(base.options.selectors.pressableButton).on('click updatePressedStatus.' + base.eventName, base, base.updateAriaPressed).trigger('updatePressedStatus.' + base.eventName);
43368    // exit fullscreen by pressing esc: set aria-pressed
43369    base.$elWrapper.find('.mejs__container').on('exitedfullscreen', base, base.onExitFullscreen).on('enteredfullscreen', base, base.onEnterFullscreen);
43370
43371    if (base.isExternalApi) {
43372      base.$el.attr('tabindex', '-1');
43373      setTimeout(function () {
43374        base.$elWrapper.find('iframe').attr('tabindex', '-1');
43375      }, 300);
43376    }
43377  },
43378
43379  removeTabindex: function removeTabindex(ev) {
43380    var base = ev.data;
43381    if (base.options.removeTabIndexOnHidden) {
43382      if (!base.$el.is(':visible')) {
43383        base.$elWrapper.find('[tabindex]').attr('tabindex', -1);
43384      }
43385    }
43386  },
43387
43388  updateAriaPressed: function updateAriaPressed(ev) {
43389    var base = ev.data,
43390        $parent = $(ev.currentTarget),
43391        $button = $parent.children('button'),
43392        isPressed = base.options.selectors.isPressed;
43393    if ($parent.is(isPressed)) {
43394      $button.attr('aria-pressed', 'true');
43395    } else {
43396      $button.attr('aria-pressed', 'false');
43397    }
43398  },
43399
43400  onExitFullscreen: function onExitFullscreen(ev) {
43401    var base = ev.data;
43402    setTimeout(function () {
43403      base.$elWrapper.find('.mejs__fullscreen-button').trigger('updatePressedStatus');
43404    });
43405    base.$elWrapper.off('keydown.' + base.eventName);
43406  },
43407
43408  onEnterFullscreen: function onEnterFullscreen(ev) {
43409    var base = ev.data;
43410
43411    base.$elWrapper.on("keydown." + base.eventName, base, base.focusControlOnKeyDown);
43412  },
43413
43414  focusControlOnKeyDown: function focusControlOnKeyDown(ev) {
43415    var base = ev.data,
43416        playBtn = base.$elWrapper.find('.mejs__overlay-button'),
43417        controls = base.$elWrapper.find('.mejs__controls').find('a, button').add(playBtn);
43418
43419    if (ev.target === controls.last()[0] && ev.keyCode === 9 && !ev.shiftKey) {
43420      ev.preventDefault();
43421      controls.first().focus();
43422    } else if (ev.target === controls.first()[0]) {
43423      ev.preventDefault();
43424      controls.last().focus();
43425    }
43426  },
43427
43428  /**
43429   * @method centerVideoIfRequired
43430   * @desc Zentriert das zugrunde liegende Multimedia-Element.
43431   */
43432  centerVideoIfRequired: function centerVideoIfRequired() {
43433    var base = this;
43434    var mediaelementplayerOptions = base.options.mediaelementplayerOptions;
43435    var videoWidth = mediaelementplayerOptions && mediaelementplayerOptions.videoWidth || base.$el.attr('width');
43436    if (base.options.center && videoWidth) {
43437      var centerContainer = void 0;
43438      var parent = base.$el.parent();
43439      if (!parent.is(base.options.selectors.center)) {
43440        centerContainer = $(base.options.markup.center);
43441        centerContainer.css({ width: videoWidth, margin: '0 auto' });
43442        base.$el.wrap(centerContainer);
43443      } else {
43444        centerContainer = parent;
43445        centerContainer.css({ width: videoWidth });
43446      }
43447    }
43448  },
43449
43450  /**
43451   * @method setLocale
43452   * @desc Setzt das Locale
43453   */
43454  setLocale: function setLocale() {
43455    var lang = $('html').attr('lang');
43456    if ((typeof mejs === 'undefined' ? 'undefined' : _typeof(mejs)) === 'object') {
43457      mejs.i18n.language(lang);
43458    }
43459  },
43460
43461  /**
43462   * Parst zusätzliche Optionen für das Mediaelement.js Plugin aus dem options data-Attribut.
43463   * Die Logik dieser Funktion ist von Foundation übernommen.
43464   */
43465  mediaelementplayerOptionsFromDataAttribute: function mediaelementplayerOptionsFromDataAttribute() {
43466    var base = this,
43467        optionsFromDataAttributeAsString = base.$el.data('options');
43468    var opts = {},
43469        ii = void 0,
43470        p = void 0,
43471        opts_arr = (optionsFromDataAttributeAsString || ':').split(';');
43472    ii = opts_arr.length;
43473
43474    function isNumber(o) {
43475      return !isNaN(o - 0) && o !== null && o !== '' && o !== false && o !== true;
43476    }
43477
43478    function trim(str) {
43479      if (typeof str === 'string') {
43480        return $.trim(str);
43481      }
43482      return str;
43483    }
43484
43485    while (ii--) {
43486      p = opts_arr[ii].split(':');
43487      p = [p[0], p.slice(1).join(':')];
43488
43489      if (/true/i.test(p[1])) {
43490        p[1] = true;
43491      }
43492      if (/false/i.test(p[1])) {
43493        p[1] = false;
43494      }
43495      if (isNumber(p[1])) {
43496        if (p[1].indexOf('.') === -1) {
43497          p[1] = parseInt(p[1], 10);
43498        } else {
43499          p[1] = parseFloat(p[1]);
43500        }
43501      }
43502
43503      if (p.length === 2 && p[0].length > 0) {
43504        opts[trim(p[0])] = trim(p[1]);
43505      }
43506    }
43507    return opts;
43508  },
43509
43510  defaultOptions: {
43511    center: false,
43512    /**
43513     * Die Standard-Optionen fuer das aufgerufene Mediaelement.js Plugin
43514     */
43515    mediaelementplayerOptions: {
43516      flashName: '/static/mediaElementPlayer/flashmediaelement.swf',
43517      showPosterWhenEnded: true,
43518      features: ['playpause', 'current', 'progress', 'duration', 'tracks', 'a11y', 'volume', 'fullscreen'],
43519      /* Bindestrich notwendig für Custom Elements
43520         siehe https://stackoverflow.com/questions/9845011/are-custom-elements-valid-html5#answer-9845124 */
43521      fakeNodeName: 'mediaelement-wrapper',
43522      iconSprite: typeof image_url_mejs_controls !== 'undefined' ? image_url_mejs_controls : undefined,
43523      classPrefix: 'mejs__'
43524    },
43525    settings: {},
43526    selectors: {
43527      captionsSelect: '.mejs__captions-selector',
43528      center: '.mejs__centered',
43529      consentContent: '.consent-container',
43530      isExternalApi: 'source[type="video/vimeo"], source[type="video/youtube"]',
43531      isPressed: '.audio-description-on, .video-description-on, .mejs__unfullscreen',
43532      pressableButton: '.mejs__audio-description-button, .mejs__video-description-button, .mejs__fullscreen-button',
43533      timeRail: '.mejs__time-rail',
43534      volumeSlider: '.mejs__volume-slider',
43535      wrapper: '.mejs__wrapper'
43536    },
43537    markup: {
43538      center: '<div class=\'mejs__centered\' />',
43539      consentWrapper: '<div class="consent-wrapper"><div class="consent-container" /></div>',
43540      consentContent: '<p>' + (typeof CONSENT_TEXT !== 'undefined' ? CONSENT_TEXT : 'FALLBACK') + '</p>',
43541      consentButton: '<button type="button" class="c-button c-button--xs" />'
43542    },
43543    externalApiRequiresConsent: true,
43544    consentLabel: typeof CONSENT_LABEL !== 'undefined' ? CONSENT_LABEL : 'FALLBACK',
43545    consentDescription: typeof CONSENT_DESCRIPTION !== 'undefined' ? CONSENT_DESCRIPTION : 'FALLBACK',
43546    consentButtonText: typeof CONSENT_BUTTON !== 'undefined' ? CONSENT_BUTTON : 'Ich akzeptiere',
43547    consentButtonInsertion: 'append',
43548    dontSetWidthAttribute: false,
43549    dontSetHeightAttribute: false,
43550    consentSetMinHeight: false,
43551    removeTabIndexOnHidden: true
43552  }
43553});
43554   /* Ende gsb_multimedia */
43555   /* Start init */
43556   $(document).ready(function () {
43557  'use strict';
43558
43559  var $body = $('body');
43560
43561  // set js class
43562  $body.addClass('js-on').removeClass('js-off');
43563  // carousel slider
43564
43565  var content = $('#content');
43566
43567  // small: 1; medium: 2 vertikal; xlarge: 2 horizontal
43568  var $js_slider_1 = content.find('.js-slider-1-2v-2h .karussell');
43569  $js_slider_1.each(function () {
43570    $(this).gsb_Slideshow({
43571      containerElement: '.slide',
43572      autoplay: false,
43573      pagination: true,
43574      slickOptions: {
43575        onSlickBeforeInit: function onSlickBeforeInit(baseEl) {
43576          baseEl.$el.gsb_slideshow_rowAddon({
43577            slidesPerRow: 1,
43578            responsive: [{
43579              breakpoint: 1024,
43580              slidesPerRow: 2,
43581              onRefresh: function onRefresh() {
43582                this.setRows();
43583              }
43584            }, {
43585              breakpoint: 640,
43586              slidesPerRow: 1,
43587              onRefresh: function onRefresh() {
43588                this.setRows();
43589              }
43590            }]
43591          }, baseEl);
43592        },
43593        slidesToShow: 2,
43594        slidesToScroll: 2,
43595        fade: false,
43596        responsive: [{
43597          breakpoint: 1024,
43598          settings: {
43599            vertical: false,
43600            slidesToShow: 1,
43601            slidesToScroll: 1
43602          }
43603        }]
43604      }
43605    });
43606  });
43607
43608  // small: 1; medium: 2 vertikal; xlarge: 2 vertikal
43609  var $js_slider_2 = content.find('.js-slider-1-2v-2v .karussell');
43610  $js_slider_2.each(function () {
43611    $(this).gsb_Slideshow({
43612      containerElement: '.slide',
43613      autoplay: false,
43614      pagination: true,
43615      slickOptions: {
43616        onSlickBeforeInit: function onSlickBeforeInit(baseEl) {
43617          baseEl.$el.gsb_slideshow_rowAddon({
43618            slidesPerRow: 2,
43619            responsive: [{
43620              breakpoint: 640,
43621              slidesPerRow: 1,
43622              onRefresh: function onRefresh() {
43623                this.setRows();
43624              }
43625            }]
43626          }, baseEl);
43627        },
43628        slidesToShow: 1,
43629        slidesToScroll: 1,
43630        fade: false
43631      }
43632    });
43633  });
43634
43635  // small: 1; medium: 4 vertikal; xlarge: 2x2
43636  var $js_slider_3 = content.find('.js-slider-1-4v-2x2 .karussell');
43637  $js_slider_3.each(function () {
43638    $(this).gsb_Slideshow({
43639      containerElement: '.slide',
43640      autoplay: false,
43641      pagination: true,
43642      slickOptions: {
43643        onSlickBeforeInit: function onSlickBeforeInit(baseEl) {
43644          baseEl.$el.gsb_slideshow_rowAddon({
43645            slidesPerRow: 2,
43646            responsive: [{
43647              breakpoint: 1024,
43648              slidesPerRow: 4,
43649              onRefresh: function onRefresh() {
43650                this.setRows();
43651              }
43652            }, {
43653              breakpoint: 640,
43654              slidesPerRow: 1,
43655              onRefresh: function onRefresh() {
43656                this.setRows();
43657              }
43658            }]
43659          }, baseEl);
43660        },
43661        slidesToShow: 2,
43662        slidesToScroll: 2,
43663        fade: false,
43664        responsive: [{
43665          breakpoint: 1024,
43666          settings: {
43667            vertical: false,
43668            slidesToShow: 1,
43669            slidesToScroll: 1
43670          }
43671        }]
43672      }
43673    });
43674  });
43675
43676  // small: 1; medium: 2x2; xlarge: 2x2
43677  var $js_slider_4 = content.find('.js-slider-1-2x2-2x2 .karussell');
43678  $js_slider_4.each(function () {
43679    $(this).gsb_Slideshow({
43680      containerElement: '.slide',
43681      autoplay: false,
43682      pagination: true,
43683      slickOptions: {
43684        onSlickBeforeInit: function onSlickBeforeInit(baseEl) {
43685          baseEl.$el.gsb_slideshow_rowAddon({
43686            slidesPerRow: 2,
43687            responsive: [{
43688              breakpoint: 640,
43689              slidesPerRow: 1,
43690              onRefresh: function onRefresh() {
43691                this.setRows();
43692              }
43693            }]
43694          }, baseEl);
43695        },
43696        slidesToShow: 2,
43697        slidesToScroll: 2,
43698        fade: false,
43699        responsive: [{
43700          breakpoint: 640,
43701          settings: {
43702            vertical: false,
43703            slidesToShow: 1,
43704            slidesToScroll: 1
43705          }
43706        }]
43707      }
43708    });
43709  });
43710
43711  // small: 1; medium: 3 vertikal; xlarge: 3 vertikal
43712  var $js_slider_5 = content.find('.js-slider-1-3v-3v .karussell');
43713  $js_slider_5.each(function () {
43714    $(this).gsb_Slideshow({
43715      containerElement: '.slide',
43716      autoplay: false,
43717      pagination: true,
43718      slickOptions: {
43719        onSlickBeforeInit: function onSlickBeforeInit(baseEl) {
43720          baseEl.$el.gsb_slideshow_rowAddon({
43721            slidesPerRow: 3,
43722            responsive: [{
43723              breakpoint: 640,
43724              slidesPerRow: 1,
43725              onRefresh: function onRefresh() {
43726                this.setRows();
43727              }
43728            }]
43729          }, baseEl);
43730        },
43731        slidesToShow: 1,
43732        slidesToScroll: 1,
43733        fade: false
43734      }
43735    });
43736  });
43737
43738  // Slider horizontal
43739  var $js_slider_6 = content.find('.js-slider .karussell');
43740  if ($js_slider_6.length > 0) {
43741    $js_slider_6.gsb_Slideshow({
43742      containerElement: '.slide',
43743      autoplay: false,
43744      pagination: true,
43745      slickOptions: {
43746        slidesToShow: $js_slider_6.data('horizontalelements'),
43747        slidesToScroll: 1,
43748        fade: false,
43749        responsive: [{
43750          breakpoint: 640,
43751          settings: {
43752            slidesToShow: 1,
43753            slidesToScroll: 1
43754          }
43755        }]
43756      }
43757    });
43758  }
43759
43760  // gallery slider
43761  var $galleryBox = $('.galleryBox');
43762  $galleryBox.gsb_Slideshow({
43763    slideshowControls: true,
43764    generateButtonContainer: false,
43765    autoplay: false,
43766    pagination: true,
43767    nextButtonImage: image_url_next,
43768    prevButtonImage: image_url_back,
43769    prevButtonInactiveImage: image_url_back_g,
43770    nextButtonInactiveImage: image_url_next_g,
43771    slickOptions: {
43772      adaptiveHeight: true,
43773      fade: false
43774    }
43775  });
43776  $galleryBox.gsb_lightbox({
43777    lightboxType: 'multiple',
43778    element: '.slide',
43779    imagePrev: image_url_back,
43780    imageNext: image_url_next,
43781    imagePrevInactive: image_url_back_g,
43782    imageNextInactive: image_url_next_g
43783  });
43784  // banner
43785  $.each($('#cookiebanner'), function () {
43786    var $el = $(this);
43787    $el.gsb_banner({
43788      animation: $el.data('animation'),
43789      cookieLifeTimeInDaysClosed: 30,
43790      cookieName: $el.data('cookie'),
43791      bodyHiddenClass: '',
43792      bodyVisibleClass: '',
43793      positionRelativeClass: 'c-banner__relative',
43794      positionRelativePlaceholderClass: 'c-banner__placeholder',
43795      position: $el.data('position'),
43796      positionRelative: true,
43797      matomoTrackingCookieLifeTimeInDays: 30,
43798      scriptUrl: '//www.reach-clp-biozid-helpdesk.de/piwik/matomo.js',
43799      trackerUrl: '//www.reach-clp-biozid-helpdesk.de/piwik/matomo.php',
43800      responsive: [{
43801        breakpoint: 1024,
43802        onRefresh: function onRefresh() {
43803          this.createBanner(true);
43804        }
43805      }, {
43806        breakpoint: 600,
43807        onRefresh: function onRefresh() {
43808          this.createBanner(true);
43809        }
43810      }]
43811    });
43812  });
43813
43814  //BMV: Datenblatt drucken
43815  $('.printButton').gsb_printbutton();
43816
43817  //Hier das richtige Input-Feld selektieren und den code einkommentieren
43818  $('.datepicker').find('[name=datepicker]').datepicker({
43819    showOn: "button",
43820    buttonImage: image_url_calendar,
43821    buttonImageOnly: true,
43822    buttonText: DATEPICKER_TEXT,
43823    dateFormat: "dd.mm.yy",
43824    monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
43825    monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
43826    dayNamesMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"]
43827  });
43828
43829  // calendar
43830  $('#supplement').find('.live-calendar').gsb_calendar({
43831    beforeInit: function beforeInit() {
43832      $('#supplement .live-calendar').find('.has-tip').each(function (_, el) {
43833        $('#' + $(el).attr('aria-describedby')).remove();
43834      });
43835    },
43836    afterInit: function afterInit() {
43837      $('#supplement .live-calendar').find('abbr, acronym').gsb_tooltip().foundation();
43838    }
43839  });
43840
43841  // flyout
43842  $('#navPrimary').gsb_slideNavigation({
43843    autosuggestURL: json_url_mobileSearch
43844  });
43845
43846  $('.togglebar').gsb_navigation_mobile({
43847    autosuggestURL: json_url_mobileSearch,
43848    menuHtml: json_url_mobileMenu
43849  });
43850
43851  // responsive table wrapper
43852  content.gsb_responsiveTables();
43853
43854  // lightboxes
43855  $('.GlossarEntry').gsb_lightbox();
43856  $('.picture .loupe').not('.galleryBox *').gsb_lightbox();
43857
43858  // toggle fuer Module
43859  $("#navServiceMeta").find('ul').gsb_toggle({
43860    tab: false,
43861    onRefresh: function onRefresh() {
43862      this.initialize();
43863      this.refreshAccordion();
43864    }
43865  });
43866  content.find('.acc').gsb_toggle({
43867    tab: false
43868  });
43869  $("#gb-facets").find('.facet-acc').gsb_toggle({
43870    tab: false
43871  });
43872
43873  content.find('.tabacc').gsb_toggle();
43874  content.gsb_toggle({
43875    tab: false,
43876    richTextAccordion: true
43877  });
43878  content.find('.researc').gsb_toggle({
43879    tabControls: '> .wrapper-tabs-list .tabs-list > li a'
43880  });
43881
43882  // tooltips for abbreviations
43883  $('abbr').gsb_tooltip();
43884  $('acronym').gsb_tooltip();
43885  if ($('#facets').find('ul').length) {
43886    $('#facets').find('ul').gsb_baua_toggleFacet();
43887  }
43888
43889  var bt_toggle = $('#facets').find('.bt-toggle');
43890  if (bt_toggle.length) {
43891    var aural = $('<span class="aural"/>');
43892    var image = bt_toggle.find('img');
43893    var tmpAlt, tmpSrc;
43894    aural.text(SHOW_MORE);
43895    bt_toggle.append(aural);
43896    bt_toggle.on('click', function (e) {
43897      e.preventDefault();
43898      e.stopPropagation();
43899      var button = $(this);
43900      if (button.hasClass('opened')) {
43901        button.removeClass('opened').addClass('closed');
43902        $('#facets').find('.showContent').trigger('click');
43903        aural.text(SHOW_MORE);
43904        changeImage(image);
43905      } else {
43906        button.removeClass('closed').addClass('opened');
43907        // Quickfix um nach dem öffnen die erste Facette zu selektieren
43908        var reveredFind = $('#facets').find('.hideContent').get().reverse();
43909        $(reveredFind).trigger('click');
43910        aural.text(SHOW_LESS);
43911        changeImage(image);
43912      }
43913    });
43914  }
43915
43916  var formBiozid = $('[name = ProduktMelden3]');
43917
43918  if (formBiozid.length) {
43919    var produktartHinweis = $("#ProduktartHinweis").text();
43920    if (produktartHinweis === "6") {
43921      formBiozid.find('[name=idProduktart]').not('[name=idProduktart][value=6]').attr('disabled', 'true');
43922    } else if (produktartHinweis === "7") {
43923      formBiozid.find('[name=idProduktart]').not('[name=idProduktart][value=7]').attr('disabled', 'true');
43924    } else if (produktartHinweis === "andere") {
43925      formBiozid.find('[name=idProduktart][value=6], [name=idProduktart][value=7]').attr('disabled', 'true');
43926    } else {
43927      formBiozid.on('click', '[name=idProduktart]', function () {
43928        var input = $(this);
43929
43930        var findOther = formBiozid.find('[name=idProduktart]').not('[name=idProduktart][value=6], [name=idProduktart][value=7]');
43931
43932        var changeOther = false;
43933        // noinspection EqualityComparisonWithCoercionJS
43934        if (input.val() == 6 || input.val() == 7) {
43935          changeOther = true;
43936        }
43937
43938        if (!$(this).is(':checked')) {
43939          if (changeOther) {
43940            formBiozid.find('[name=idProduktart]').not(input).removeAttr('disabled');
43941          } else {
43942            if (!findOther.is(':checked')) {
43943              formBiozid.find('[name=idProduktart][value=6], [name=idProduktart][value=7]').removeAttr('disabled');
43944            }
43945          }
43946        } else {
43947          if (changeOther) {
43948            formBiozid.find('[name=idProduktart]').not(input).attr('disabled', 'true');
43949          } else {
43950            formBiozid.find('[name=idProduktart][value=6], [name=idProduktart][value=7]').attr('disabled', 'true');
43951          }
43952        }
43953      });
43954    }
43955  }
43956
43957  function changeImage(image) {
43958    tmpAlt = image.attr('alt');
43959    tmpSrc = image.attr('src');
43960    image.attr('src', image.attr('data-src')).attr('alt', image.attr('data-alt'));
43961    image.attr('data-src', tmpSrc).attr('data-alt', tmpAlt);
43962  }
43963
43964  // player for multimedia content
43965  var $contentNotVimeo = $('.content video, .content audio').filter(function (index, el) {
43966    return $(el).find('source[type|="video/vimeo"]').length < 1;
43967  });
43968  var $contentVimeo = $('.content video, .content audio').filter(function (index, el) {
43969    return $(el).find('source[type|="video/vimeo"]').length > 0;
43970  });
43971
43972  var $supplementNotVimeo = $('.supplement video, .supplement audio').filter(function (index, el) {
43973    return $(el).find('source[type|="video/vimeo"]').length < 1;
43974  });
43975  var $supplementVimeo = $('.supplement video, .supplement audio').filter(function (index, el) {
43976    return $(el).find('source[type|="video/vimeo"]').length > 0;
43977  });
43978
43979  gsb.requireGSBComponent('bundle_multimedia', $contentNotVimeo).done(function ($contentMedia) {
43980    $contentMedia.gsb_Multimedia({
43981      externalApiRequiresConsent: !$body.hasClass('js-youtube-consent-not-required')
43982    });
43983  });
43984
43985  gsb.requireGSBComponent('bundle_multimedia', $supplementNotVimeo).done(function ($supplementMedia) {
43986    $supplementMedia.gsb_Multimedia({
43987      externalApiRequiresConsent: !$body.hasClass('js-youtube-consent-not-required'),
43988      settings: {
43989        mediaelementplayerOptions: {
43990          videoWidth: 280,
43991          videoHeight: 158
43992        }
43993      },
43994      responsive: [{
43995        breakpoint: 600,
43996        settings: {
43997          mediaelementplayerOptions: {
43998            videoWidth: 280,
43999            videoHeight: 158
44000          }
44001        }
44002      }]
44003    });
44004  });
44005
44006  // Vimeo Content
44007  gsb.requireGSBComponent('bundle_multimedia', $contentVimeo).done(function ($media) {
44008    $media.gsb_Multimedia({
44009      externalApiRequiresConsent: !$body.hasClass('js-external-video-api-consent-not-required'),
44010      settings: {
44011        mediaelementplayerOptions: {
44012          features: ''
44013        }
44014      }
44015    });
44016  });
44017
44018  gsb.requireGSBComponent('bundle_multimedia', $supplementVimeo).done(function ($media) {
44019    $media.gsb_Multimedia({
44020      externalApiRequiresConsent: !$body.hasClass('js-external-video-api-consent-not-required'),
44021      settings: {
44022        mediaelementplayerOptions: {
44023          features: '',
44024          videoWidth: 280,
44025          videoHeight: 158
44026        }
44027      },
44028      responsive: [{
44029        breakpoint: 600,
44030        settings: {
44031          mediaelementplayerOptions: {
44032            features: '',
44033            videoWidth: 280,
44034            videoHeight: 158
44035          }
44036        }
44037      }]
44038    });
44039  });
44040
44041  // gsb_infinitescrolling
44042  var sectionresults = $('#content').find('.section-results');
44043  if (sectionresults.length > 0) {
44044    sectionresults.gsb_infinitescrolling();
44045  }
44046
44047  $('.intro-toggle').gsb_baua_toggleText();
44048
44049  var searchTargetMarker = content.find('#searchTargetMarker');
44050  if (searchTargetMarker.length > 0) {
44051    searchTargetMarker.parent().find('input.image').on('click', function (e) {
44052      e.preventDefault();
44053      var action = $(this).closest('form').attr('action');
44054      $(this).closest('form').attr('action', action + '#searchTargetMarker').submit();
44055    });
44056  }
44057
44058  $('.child-grp-anchor a').click(function (e) {
44059    e.preventDefault();
44060    var dest = $(this).attr('href');
44061    var parts = dest.split("#");
44062    var trgt = parts[1];
44063    $('html,body').animate({
44064      scrollTop: $("#" + trgt).offset().top
44065    }, 'slow');
44066  });
44067  (function () {
44068    var hash = location.hash || location.href.match(/#.*$/),
44069        target;
44070    if (hash) {
44071      target = document.getElementById(hash.toString().replace('#', ''));
44072      if (target) {
44073        $('html,body').animate({
44074          scrollTop: $(target).offset().top
44075        }, 0);
44076      }
44077    }
44078  })();
44079
44080  (function () {
44081    var $body = $('body'),
44082        $logo = $('.logo').first().find('img'),
44083        scrolledClassValue = 'js-scrolled',
44084        defaultLogoSrc = $logo.attr('src'),
44085        $togglebar = $('.togglebar'),
44086        mobileNavigation = $togglebar.data('gsb.navigation_mobile'),
44087        handleScrolledPage = function handleScrolledPage() {
44088      function activateScrolledStateForPageIfNotAlreadyDone() {
44089        function closeTogglebarIfOpen() {
44090          if (mobileNavigation.nav && mobileNavigation.isOpened(mobileNavigation.nav)) {
44091            $(mobileNavigation.options.navOpenButton).click();
44092          }
44093
44094          if (mobileNavigation.search && mobileNavigation.isOpened(mobileNavigation.search)) {
44095            $(mobileNavigation.options.navSearchButton).click();
44096          }
44097        }
44098
44099        if (!$body.hasClass(scrolledClassValue)) {
44100          $body.addClass(scrolledClassValue);
44101          if (image_url_logo_scrolled) {
44102            $logo.attr('src', image_url_logo_scrolled);
44103          }
44104          closeTogglebarIfOpen();
44105          $('body').trigger('stickyheader.scrolled');
44106        }
44107      }
44108
44109      function deactivateScrolledStateForPage() {
44110        $body.removeClass(scrolledClassValue);
44111        $logo.attr('src', defaultLogoSrc);
44112      }
44113
44114      function scrolledStateNeedsToBeActivated() {
44115        var $openNavigation = $('.nav.opened'),
44116            userHasScrolled = $(window).scrollTop() > 0,
44117            scrolledPositionIsWithinOpenNavigation = $openNavigation.length && $(window).scrollTop() < $openNavigation.offset().top + $openNavigation.outerHeight(),
44118            mobileSearchTextfieldHasFocus = typeof mobileNavigation.search !== "undefined" && mobileNavigation.search.find('input[type="text"]:focus').length === 1;
44119        return userHasScrolled && !scrolledPositionIsWithinOpenNavigation && !mobileSearchTextfieldHasFocus;
44120      }
44121
44122      if (scrolledStateNeedsToBeActivated()) {
44123        activateScrolledStateForPageIfNotAlreadyDone();
44124      } else {
44125        deactivateScrolledStateForPage();
44126      }
44127    },
44128        scrollToTopIfPageHasBeenScrolled = function scrollToTopIfPageHasBeenScrolled(e) {
44129      if ($(window).scrollTop() > 0) {
44130        e.preventDefault();
44131        $('html,body').animate({
44132          scrollTop: 0
44133        }, 0);
44134      }
44135    },
44136        gotoElement = function gotoElement($jumpToElement) {
44137      if ($jumpToElement.length) {
44138        var jumpToScrollTop = $jumpToElement.offset().top - $('#header').outerHeight(true);
44139        if (!$body.hasClass('js-scrolled')) {
44140          jumpToScrollTop -= 70;
44141        }
44142        $('html,body').animate({
44143          scrollTop: jumpToScrollTop
44144        }, 100);
44145      }
44146    },
44147        gotoHashOnInitialPageLoad = function gotoHashOnInitialPageLoad() {
44148      $body.one('stickyheader.scrolled', function () {
44149        if (window.location.hash) {
44150          var $jumpToElement = $(window.location.hash);
44151          gotoElement($jumpToElement);
44152        }
44153      });
44154    },
44155        handleTocJumpLinks = function handleTocJumpLinks() {
44156      $('.toc a').click(function (e) {
44157        e.preventDefault();
44158        var hrefOfTocLink = $(this).attr('href'),
44159            hash = hrefOfTocLink.substr(hrefOfTocLink.indexOf('#'));
44160        gotoElement($(hash));
44161      });
44162    };
44163    $(window).scroll(handleScrolledPage);
44164    $('#header').find('a').click(scrollToTopIfPageHasBeenScrolled);
44165    gotoHashOnInitialPageLoad();
44166    handleTocJumpLinks();
44167  })();
44168
44169  // Foundation initialisieren
44170  $(document).foundation();
44171});
44172   /* Ende init */
44173
44174jQuery(document).ready(function (jQuery){
44175  // Autosuggest
44176  var searchforms = [];
44177  searchforms[1] = {
44178    id : 'searchService',
44179    action : 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Forms/Suche/DE/Servicesuche_Autosuggest_Formular?nn=6942652c85ec843c18743a51'
44180  };
44181  searchforms[2] = {
44182    id : 'searchExpert',
44183    action : 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Forms/Suche/DE/Expertensuche_Autosuggest_Formular?nn=6942652c85ec843c18743a51'
44184  };
44185  if(searchforms.length > 0){
44186    $(searchforms).each(function(index){
44187      var valueObj = searchforms[index],form;
44188      if(valueObj !== undefined){
44189        form = jQuery('form[name="'+ valueObj.id +'"]');
44190        if(form.length > 0){
44191          form.gsb_AutoSuggest(valueObj.action);
44192        }
44193      }
44194    });
44195  }
44196});
44197

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.